From c06b804b0c155982a1034fef4b333298a758ccfa Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 21 Oct 2022 19:40:22 +0300 Subject: [PATCH 001/212] map builder commit v1 --- 3rdparty/casclib | 2 +- src/minimapGenerator/minimapGenerator.cpp | 16 ++++- wowViewerLib/3rdparty/oneTbb | 2 +- .../shaders/glsl/vulkan/m2ParticleShader.frag | 1 + .../shaders/glsl/vulkan/wmoShader.frag | 2 +- .../src/engine/managers/CRibbonEmitter.cpp | 4 +- .../src/gapi/UniformBufferStructures.h | 13 ++++ .../src/gapi/ogl3.3/GFrameBufferGL33.cpp | 59 ++++++++++++------- .../src/gapi/ogl3.3/GFrameBufferGL33.h | 3 + 9 files changed, 76 insertions(+), 26 deletions(-) diff --git a/3rdparty/casclib b/3rdparty/casclib index 8ac182b2f..6ff3b6762 160000 --- a/3rdparty/casclib +++ b/3rdparty/casclib @@ -1 +1 @@ -Subproject commit 8ac182b2fe1197bd979b6a08cf001508bb460d6f +Subproject commit 6ff3b6762dc7598a278af83dd2ffe5f91817fce4 diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 9742f7409..7785e8249 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -542,6 +542,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; + if (objBB.max.z > 2000) { + continue; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -559,6 +563,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; + if (objBB.max.z > 2000) { + continue; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -575,6 +583,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor for (auto &adtObjectRes: cullStage->adtArray) { auto adtObj = adtObjectRes->adtObject; + if (applyAdtChecks && (adtObj->getAdtX() != adt_x || adtObj->getAdtY() != adt_y)) { // std::cout << "skipping adtObj( " << // adtObj->getAdtX() << "," << adtObj->getAdtY() << " " @@ -585,6 +594,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor auto objBB = adtObj->calcAABB(); + if (objBB.max.z > 2000) { + continue; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -598,7 +611,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor } } -const int waitQueueLen = 3; +const int waitQueueLen = 5; void MinimapGenerator::process() { if (m_processor->completedAllJobs()) { framesReady++; @@ -625,6 +638,7 @@ void MinimapGenerator::process() { } if (m_candidateDS == nullptr) { + resetCandidate(); prepearCandidate = true; return; } diff --git a/wowViewerLib/3rdparty/oneTbb b/wowViewerLib/3rdparty/oneTbb index a927a6bba..549f03220 160000 --- a/wowViewerLib/3rdparty/oneTbb +++ b/wowViewerLib/3rdparty/oneTbb @@ -1 +1 @@ -Subproject commit a927a6bba93b77037b8377ddef025047d0270650 +Subproject commit 549f032201ecd3dad8925d776394afafa021fe3a diff --git a/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag index 34a5e34e4..8e4d74677 100644 --- a/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag @@ -72,6 +72,7 @@ void main() { vec3 matDiffuse = vColor.xyz * textureMod.rgb; finalColor = vec4(matDiffuse.rgb, opacity); } else if (uNonOptPixelShader == 4) { //Refraction + discard; float t0_973 = tex.x; float t1_978 = tex2.y; float t2_983 = tex3.z; diff --git a/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag b/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag index de5b8795e..471dcf825 100644 --- a/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag @@ -159,7 +159,7 @@ void main() { finalOpacity = tex.a; } else if (uPixelShader == 7) { //MapObjTwoLayerEnvMetal - vec4 colorMix = mix(tex, tex2, vColor2.a); + vec4 colorMix = mix(tex2, tex, vColor2.a); matDiffuse = colorMix.rgb ; emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 9b47409d5..90cbac774 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -144,12 +144,12 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat meshTemplate.ubo[2] = nullptr; meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(Particle::meshParticleWideBlockPS)); + meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(Ribbon::meshRibbonWideBlockPS)); auto blendMode = meshTemplate.blendMode; auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; meshTemplate.ubo[4]->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { - Particle::meshParticleWideBlockPS& blockPS = self->getObject(); + Ribbon::meshRibbonWideBlockPS& blockPS = self->getObject(); blockPS.uAlphaTest = -1.0f; blockPS.uPixelShader = 0; diff --git a/wowViewerLib/src/gapi/UniformBufferStructures.h b/wowViewerLib/src/gapi/UniformBufferStructures.h index 4270bb8bf..03239ba2f 100644 --- a/wowViewerLib/src/gapi/UniformBufferStructures.h +++ b/wowViewerLib/src/gapi/UniformBufferStructures.h @@ -117,6 +117,19 @@ namespace Particle { int uBlendMode; int padding2; // according to std140 int padding3; // according to std140 + }; +} + +namespace Ribbon { + struct meshRibbonWideBlockPS { + float uAlphaTest; + float textureScale0; + float textureScale1; + float textureScale2; + int uPixelShader; + int uBlendMode; + int padding2; // according to std140 + int padding3; // according to std140 float textureTranslate0; float textureTranslate1; float textureTranslate2; diff --git a/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.cpp index 6aa6c3077..99acfac1b 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.cpp @@ -48,6 +48,7 @@ GFrameBufferGL33::GFrameBufferGL33 ( } else if (textureAttachments[i] == ITextureFormat::itRGBAFloat32) { glRenderbufferStorageMultisample(GL_RENDERBUFFER, device->getMaxSamplesCnt(), GL_RGBA32F, width, height); } + glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, renderBufferAttachments[i]); } @@ -58,6 +59,7 @@ GFrameBufferGL33::GFrameBufferGL33 ( if (depthAttachment == ITextureFormat::itDepth32) { glRenderbufferStorageMultisample(GL_RENDERBUFFER, device->getMaxSamplesCnt(), GL_DEPTH32F_STENCIL8, width, height); } + glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBufferAttachment); } @@ -78,12 +80,15 @@ GFrameBufferGL33::GFrameBufferGL33 ( } else { } - // { -// auto frameBuffStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); -// if (frameBuffStatus != GL_FRAMEBUFFER_COMPLETE) -// std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete! error = " << frameBuffStatus << std::endl; -// } - } + { + auto frameBuffStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (frameBuffStatus != GL_FRAMEBUFFER_COMPLETE) + std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete! error = " << frameBuffStatus << std::endl; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + frame_created = device->getFrameNumber(); +} GFrameBufferGL33::~GFrameBufferGL33() { // glBindFramebuffer(GL_FRAMEBUFFER, m_renderBufFbo); @@ -97,23 +102,34 @@ GFrameBufferGL33::~GFrameBufferGL33() { // } // glDiscardFramebufferEXT(GL_FRAMEBUFFER,discards.size(),discards.data()); - glDeleteFramebuffers(1, &m_textureFbo); - glBindFramebuffer(GL_FRAMEBUFFER, m_renderBufFbo); - for (int i = 0; i < renderBufferAttachments.size(); i++) { - glBindRenderbuffer(GL_RENDERBUFFER, renderBufferAttachments[i]); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, 0, 0); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glDeleteRenderbuffers(1, &renderBufferAttachments[i]); + frame_destroyed = mdevice->getFrameNumber(); + +// std::cout << "m_textureFbo = " << m_textureFbo << " frame_created = " << frame_created << " " << +// "frame_destroyed = " << frame_destroyed << std::endl; + + auto l_textureFbo = m_textureFbo; + auto l_renderBufferAttachments = renderBufferAttachments; + auto l_depthBufferAttachment = depthBufferAttachment; + auto l_renderBufFbo = depthBufferAttachment; + mdevice->addDeallocationRecord([l_textureFbo, l_renderBufferAttachments, l_depthBufferAttachment, l_renderBufFbo]() { + glDeleteFramebuffers(1, &l_textureFbo); + glBindFramebuffer(GL_FRAMEBUFFER, l_renderBufFbo); + for (int i = 0; i < l_renderBufferAttachments.size(); i++) { + glBindRenderbuffer(GL_RENDERBUFFER, l_renderBufferAttachments[i]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, 0, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glDeleteRenderbuffers(1, &l_renderBufferAttachments[i]); } - if (depthBufferAttachment > 0) { - glBindRenderbuffer(GL_RENDERBUFFER, depthBufferAttachment); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_DEPTH32F_STENCIL8, 0, 0); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glDeleteRenderbuffers(1, &depthBufferAttachment); + if (l_depthBufferAttachment > 0) { + glBindRenderbuffer(GL_RENDERBUFFER, l_depthBufferAttachment); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_DEPTH32F_STENCIL8, 0, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glDeleteRenderbuffers(1, &l_depthBufferAttachment); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &m_renderBufFbo); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &l_renderBufFbo); + }); } HGTexture GFrameBufferGL33::getAttachment(int index){ @@ -129,6 +145,9 @@ void GFrameBufferGL33::bindFrameBuffer(){ } void GFrameBufferGL33::copyRenderBufferToTexture(){ +// std::cout << "m_textureFbo = " << m_textureFbo << " called on " << mdevice->getFrameNumber() +// << std::endl; + logGLError glBindFramebuffer(GL_READ_FRAMEBUFFER, m_renderBufFbo); logGLError diff --git a/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.h b/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.h index 6d053ab29..4ac1f3eb5 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/GFrameBufferGL33.h @@ -41,6 +41,9 @@ class GFrameBufferGL33 : public IFrameBuffer { int m_width = 0; int m_height = 0; + + int frame_created = -1; + int frame_destroyed = -1; }; From 92ee7a8203bc0303c4a9be004a73959c21682208 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 25 Oct 2022 22:30:13 +0300 Subject: [PATCH 002/212] changes for minimap generation part 1 --- src/database/CSqliteDB.h | 1 - src/main.cpp | 4 +- src/minimapGenerator/entities.h | 28 +- src/minimapGenerator/minimapGenerator.cpp | 382 +++++----- src/minimapGenerator/minimapGenerator.h | 22 +- .../storage/CMinimapDataDB.cpp | 686 ++++++++++-------- src/minimapGenerator/storage/CMinimapDataDB.h | 56 +- .../shaders/glsl/common/commonFunctions.glsl | 6 +- .../shaders/glsl/vulkan/wmoShader.vert | 5 +- wowViewerLib/src/engine/SceneComposer.cpp | 2 +- wowViewerLib/src/engine/SceneScenario.cpp | 4 +- wowViewerLib/src/engine/SceneScenario.h | 4 +- .../src/engine/objects/adt/adtObject.cpp | 13 +- .../src/engine/objects/adt/adtObject.h | 2 - wowViewerLib/src/engine/objects/iScene.h | 4 +- .../src/engine/objects/scenes/map.cpp | 15 +- wowViewerLib/src/engine/objects/scenes/map.h | 8 +- .../src/engine/shader/ShaderDefinitions.h | 124 ++-- wowViewerLib/src/include/config.h | 40 +- 19 files changed, 822 insertions(+), 584 deletions(-) diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index 64c0492ab..29bc78daf 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -47,7 +47,6 @@ class CSqliteDB : public IClientDatabase { private: SQLite::Statement m_query; std::unordered_map fieldToIndex; - }; SQLite::Database m_sqliteDatabase; diff --git a/src/main.cpp b/src/main.cpp index af4129d9b..796c6d428 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -352,8 +352,8 @@ int main(){ #endif // std::string rendererName = "ogl2"; - std::string rendererName = "ogl3"; -// std::string rendererName = "vulkan"; +// std::string rendererName = "ogl3"; + std::string rendererName = "vulkan"; //FOR OGL diff --git a/src/minimapGenerator/entities.h b/src/minimapGenerator/entities.h index b3696d063..d387d13a4 100644 --- a/src/minimapGenerator/entities.h +++ b/src/minimapGenerator/entities.h @@ -6,10 +6,15 @@ #define AWEBWOWVIEWERCPP_ENTITIES_H #include +#include +#include +#include +#include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #include +#include "../../wowViewerLib/src/include/config.h" enum class ScenarioOrientation { soTopDownOrtho, @@ -25,10 +30,26 @@ enum class EMGMode { ePreview, }; -struct ScenarioDef { - int id; +struct MapRenderDef { + int id = -1; + int mapId; + + double deltaX; + double deltaY; + double deltaZ; + + HADTRenderConfigDataHolder adtConfigHolder = std::make_shared(); +}; + +struct ScenarioDef { + std::vector maps; + + int id = -1; std::string name; + ScenarioOrientation orientation = ScenarioOrientation::so45DegreeTick0; + + std::unordered_map> activatePhasePerMap; mathfu::vec4 closeOceanColor; @@ -36,12 +57,11 @@ struct ScenarioDef { mathfu::vec2 maxWowWorldCoord; int imageHeight; + int imageWidth; float zoom = 1.0f; - ScenarioOrientation orientation = ScenarioOrientation::so45DegreeTick0; - std::string folderToSave; }; diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 7785e8249..f9fd01daf 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -14,8 +14,7 @@ MinimapGenerator::MinimapGenerator(HWoWFilesCacheStorage cacheStorage, const HGDevice &hDevice, - HRequestProcessor processor, std::shared_ptr dbhandler, - HADTBoundingBoxHolder boundingBoxHolder) { + HRequestProcessor processor, std::shared_ptr dbhandler) { m_apiContainer = std::make_shared(); m_apiContainer->hDevice = hDevice; @@ -24,7 +23,6 @@ MinimapGenerator::MinimapGenerator(HWoWFilesCacheStorage cacheStorage, const HGD m_apiContainer->databaseHandler = dbhandler; m_processor = processor; - m_boundingBoxHolder = boundingBoxHolder; auto config = m_apiContainer->getConfig(); config->glowSource = EParameterSource::eConfig; @@ -129,7 +127,9 @@ void MinimapGenerator::startNextScenario() { void MinimapGenerator::setupScenarioData() { m_zoom = currentScenario.zoom; - mandatoryADTMap.resize(0); + for (auto &mapData : mapRuntimeInfo) { + mapData.mandatoryADTMap.resize(0); + } stackOfCullStages = {nullptr, nullptr, nullptr, nullptr}; @@ -139,23 +139,29 @@ void MinimapGenerator::setupScenarioData() { m_apiContainer->camera = std::make_shared(); } - MapRecord mapRecord; - if (!m_apiContainer->databaseHandler->getMapById(currentScenario.mapId, mapRecord)) { - std::cout << "Couldnt get data for mapId " << currentScenario.mapId << std::endl; - startNextScenario(); - return; - } + for ( int i = 0; i < currentScenario.maps.size(); i++) { + auto &mapDef = currentScenario.maps[i]; + MapRecord mapRecord; + if (!m_apiContainer->databaseHandler->getMapById(mapDef.mapId, mapRecord)) { + std::cout << "Couldnt get data for mapId " << mapDef.mapId << std::endl; + startNextScenario(); + return; + } - m_currentScene = std::make_shared(m_apiContainer, mapRecord.ID, mapRecord.WdtFileID); - if (m_mgMode == EMGMode::eScreenshotGeneration) { - m_currentScene->setAdtBoundingBoxHolder(m_boundingBoxHolder); + auto &mapRuntime = mapRuntimeInfo.emplace_back(); + mapRuntime.mapIndex = i; + mapRuntime.scene = std::make_shared(m_apiContainer, mapRecord.ID, mapRecord.WdtFileID); + + if (m_mgMode == EMGMode::eScreenshotGeneration) { + mapRuntime.scene->setAdtConfig(mapDef.adtConfigHolder); + } } auto config = m_apiContainer->getConfig(); config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; config->closeRiverColor = {0.345206976, 0.329288304, 0.270450264, 0}; - setMinMaxXYWidhtHeight(currentScenario.minWowWorldCoord, currentScenario.maxWowWorldCoord); + setMinMaxXYWidthHeight(currentScenario.minWowWorldCoord, currentScenario.maxWowWorldCoord); m_x = 0; //To make AABB work for sure! @@ -165,72 +171,79 @@ void MinimapGenerator::setupScenarioData() { m_height = currentScenario.imageHeight; //Assign mandatory adt for every cell on the screen - if (m_mgMode == EMGMode::eScreenshotGeneration && m_boundingBoxHolder != nullptr) { + if (m_mgMode == EMGMode::eScreenshotGeneration ) { //currentScenario.boundingBoxHolder - mandatoryADTMap.resize(m_chunkWidth); - for (int i = 0; i < m_chunkWidth; i++) { - mandatoryADTMap[i].resize(m_chunkHeight); - } + for (auto &mapData : mapRuntimeInfo) { + mapData.mandatoryADTMap.resize(m_chunkWidth); + for (int i = 0; i < m_chunkWidth; i++) { + mapData.mandatoryADTMap[i].resize(m_chunkHeight); + } - for (int adt_x = 0; adt_x < 64; adt_x++) { - for (int adt_y = 0; adt_y < 64; adt_y++) { - auto aaBB = (*m_boundingBoxHolder)[adt_x][adt_y]; - //Project aaBB into screenSpace coordinates - std::array minMaxX = {aaBB.min.x, aaBB.min.x}; - std::array minMaxY = {aaBB.min.y, aaBB.min.y}; - std::array minMaxZ = {aaBB.min.z, aaBB.min.z}; - std::vector corners; - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - corners.push_back( - mathfu::vec4( - minMaxX[i], - minMaxY[j], - minMaxZ[k], - 1.0f - ) - ); + for (int adt_x = 0; adt_x < 64; adt_x++) { + for (int adt_y = 0; adt_y < 64; adt_y++) { + float minZ = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMinZ[adt_x][adt_y]; + float maxZ = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMaxZ[adt_x][adt_y]; + //Project aaBB into screenSpace coordinates + + std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1) , AdtIndexToWorldCoordinate(adt_x + 1)}; + std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y) , AdtIndexToWorldCoordinate(adt_x)}; + std::array minMaxZ = {minZ, maxZ}; + std::vector corners; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + corners.push_back( + mathfu::vec4( + minMaxX[i], + minMaxY[j], + minMaxZ[k], + 1.0f + ) + ); + } } } - } - mathfu::mat4 viewProj = genTempProjectMatrix(); - for (int i = 0; i < corners.size(); i++) { - corners[i] = viewProj * corners[i]; - corners[i] = corners[i] * (1.0f / corners[i].w); - } + mathfu::mat4 viewProj = genTempProjectMatrix(); + for (int i = 0; i < corners.size(); i++) { + corners[i] = viewProj * corners[i]; + corners[i] = corners[i] * (1.0f / corners[i].w); + } - std::array minMaxScreenX = {20000, -20000}; - std::array minMaxScreenY = {20000, -20000}; - std::array minMaxScreenZ = {20000, -20000}; + std::array minMaxScreenX = {20000, -20000}; + std::array minMaxScreenY = {20000, -20000}; + std::array minMaxScreenZ = {20000, -20000}; - for (int i = 0; i < corners.size(); i++) { - minMaxScreenX[0] = std::min(corners[i].x, minMaxScreenX[0]); - minMaxScreenX[1] = std::max(corners[i].x, minMaxScreenX[1]); + for (int i = 0; i < corners.size(); i++) { + minMaxScreenX[0] = std::min(corners[i].x, minMaxScreenX[0]); + minMaxScreenX[1] = std::max(corners[i].x, minMaxScreenX[1]); - minMaxScreenY[0] = std::min(corners[i].y, minMaxScreenY[0]); - minMaxScreenY[1] = std::max(corners[i].y, minMaxScreenY[1]); + minMaxScreenY[0] = std::min(corners[i].y, minMaxScreenY[0]); + minMaxScreenY[1] = std::max(corners[i].y, minMaxScreenY[1]); - minMaxScreenZ[0] = std::min(corners[i].z, minMaxScreenZ[0]); - minMaxScreenZ[1] = std::max(corners[i].z, minMaxScreenZ[1]); - } + minMaxScreenZ[0] = std::min(corners[i].z, minMaxScreenZ[0]); + minMaxScreenZ[1] = std::max(corners[i].z, minMaxScreenZ[1]); + } - //Add adt to all occupied cells - for (int i = std::floor(minMaxScreenX[0]); i < std::ceil((minMaxScreenX[1] - minMaxScreenX[0]) / 2.0f); i++) { - for (int j = std::floor(minMaxScreenY[0]); j < std::ceil((minMaxScreenY[1] - minMaxScreenY[0]) / 2.0f); j++) { - if (i < m_chunkStartX) - return; - if (j < m_chunkStartY) - return; - if (i > m_chunkStartX + m_chunkWidth) - return; - if (i > m_chunkStartY + m_chunkHeight) - return; - - std::array adtCoord = {static_cast(adt_x), static_cast(adt_y)}; - mandatoryADTMap[i - m_chunkStartX][j - m_chunkStartY].push_back(adtCoord); + //Add adt to all occupied cells + for (int i = std::floor(minMaxScreenX[0]); + i < std::ceil((minMaxScreenX[1] - minMaxScreenX[0]) / 2.0f); i++) { + for (int j = std::floor(minMaxScreenY[0]); + j < std::ceil((minMaxScreenY[1] - minMaxScreenY[0]) / 2.0f); j++) { + if (i < m_chunkStartX) + return; + if (j < m_chunkStartY) + return; + if (i > m_chunkStartX + m_chunkWidth) + return; + if (i > m_chunkStartY + m_chunkHeight) + return; + + std::array adtCoord = {static_cast(adt_x), + static_cast(adt_y)}; + mapData.mandatoryADTMap[i - m_chunkStartX][j - m_chunkStartY].push_back(adtCoord); + } } } } @@ -243,87 +256,73 @@ void MinimapGenerator::setupScenarioData() { void -MinimapGenerator::setMinMaxXYWidhtHeight(const mathfu::vec2 &minWowWorldCoord, const mathfu::vec2 &maxWowWorldCoord) { +MinimapGenerator::setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, const mathfu::vec2 &maxWowWorldCoord) { calcXtoYCoef(); bool useZCoord = false; - float minZ = 20000; float maxZ = -20000; - if (m_boundingBoxHolder && m_mgMode != EMGMode::eBoundingBoxCalculation) { + mathfu::mat4 viewProj = genTempProjectMatrix(); + + std::array minMaxScreenX = {20000, -20000}; + std::array minMaxScreenY = {20000, -20000}; + + if (m_mgMode != EMGMode::eBoundingBoxCalculation) { std::cout << "Using bounding box data to calc minMax Z" << std::endl; useZCoord = true; - for (int adt_y = worldCoordinateToAdtIndex(minWowWorldCoord.x); - adt_y < worldCoordinateToAdtIndex(maxWowWorldCoord.x); adt_y++) { + for (auto &mapData : mapRuntimeInfo) { + auto &mapDef = currentScenario.maps[mapData.mapIndex]; - for (int adt_x = worldCoordinateToAdtIndex(minWowWorldCoord.y); - adt_x < worldCoordinateToAdtIndex(maxWowWorldCoord.y); adt_x++) { + for (int adt_y = worldCoordinateToAdtIndex(minWowWorldCoord.x + mapDef.deltaX); + adt_y < worldCoordinateToAdtIndex(maxWowWorldCoord.x+ mapDef.deltaX); adt_y++) { - auto adtMinZ = (*m_boundingBoxHolder)[adt_x][adt_y].min.z; - if (adtMinZ < 32*MathHelper::TILESIZE) - minZ = std::min(adtMinZ, minZ); + for (int adt_x = worldCoordinateToAdtIndex(minWowWorldCoord.y + mapDef.deltaY); + adt_x < worldCoordinateToAdtIndex(maxWowWorldCoord.y + mapDef.deltaY); adt_x++) { - auto adtMaxZ = (*m_boundingBoxHolder)[adt_x][adt_y].max.z; - if (adtMaxZ > -32*MathHelper::TILESIZE) { - maxZ = std::max((*m_boundingBoxHolder)[adt_x][adt_y].max.z, maxZ); - } - } - } - } - std::array minMaxX = {minWowWorldCoord.x, maxWowWorldCoord.x}; - std::array minMaxY = {minWowWorldCoord.y, maxWowWorldCoord.y}; - std::array minMaxZ = {minZ, maxZ}; + auto adtMinZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; + auto adtMaxZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; - mathfu::mat4 viewProj = genTempProjectMatrix(); + if (adtMinZ > adtMaxZ) + continue; - std::vector corners; - if (useZCoord) { - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - corners.push_back( - mathfu::vec4( - minMaxX[i], - minMaxY[j], - minMaxZ[k], - 1.0f - ) - ); - } - } - } - } else { - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - corners.push_back( - mathfu::vec4( - minMaxX[i], - minMaxY[j], - 0, - 1.0f - ) - ); - } - } - } + adtMinZ += mapDef.deltaZ; + adtMaxZ += mapDef.deltaZ; - for (int i = 0; i < corners.size(); i++) { - corners[i] = viewProj * corners[i]; - corners[i] = corners[i] * (1.0f / corners[i].w); - } + std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1), AdtIndexToWorldCoordinate(adt_x + 1)}; + std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y), AdtIndexToWorldCoordinate(adt_x)}; + std::array minMaxZ = {adtMinZ, adtMaxZ}; - std::array minMaxScreenX = {20000, -20000}; - std::array minMaxScreenY = {20000, -20000}; - std::array minMaxScreenZ = {20000, -20000}; + std::vector corners; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) { + corners.push_back( + mathfu::vec4( + minMaxX[i], + minMaxY[j], + minMaxZ[k], + 1.0f + ) + ); + } - for (int i = 0; i < corners.size(); i++) { - minMaxScreenX[0] = std::min(corners[i].x, minMaxScreenX[0]); - minMaxScreenX[1] = std::max(corners[i].x, minMaxScreenX[1]); + for (int i = 0; i < corners.size(); i++) { + corners[i] = viewProj * corners[i]; + corners[i] = corners[i] * (1.0f / corners[i].w); + } - minMaxScreenY[0] = std::min(corners[i].y, minMaxScreenY[0]); - minMaxScreenY[1] = std::max(corners[i].y, minMaxScreenY[1]); + for (int i = 0; i < corners.size(); i++) { + minMaxScreenX[0] = std::min(corners[i].x, minMaxScreenX[0]); + minMaxScreenX[1] = std::max(corners[i].x, minMaxScreenX[1]); - minMaxScreenZ[0] = std::min(corners[i].z, minMaxScreenZ[0]); - minMaxScreenZ[1] = std::max(corners[i].z, minMaxScreenZ[1]); + minMaxScreenY[0] = std::min(corners[i].y, minMaxScreenY[0]); + minMaxScreenY[1] = std::max(corners[i].y, minMaxScreenY[1]); + } + } + } + } + } else { + minMaxScreenX = {-64, -64}; + minMaxScreenY = {64, 64}; } @@ -351,13 +350,6 @@ mathfu::mat4 MinimapGenerator::genTempProjectMatrix() { auto orthoProjection = getOrthoMatrix(); mathfu::vec3 lookAtPoint = mathfu::vec3(0, 0, 0); - lookAtPoint = lookAtPoint; - //std::cout << "lookAtPoint = (" << lookAtPoint.x << ", " << lookAtPoint.y << ", " << lookAtPoint.z << ") " << std::endl; - - mathfu::vec3 lookAtVec3 = getLookAtVec3(); - lookAtPoint -= (4000.0f*lookAtVec3); - - mathfu::vec3 cameraPos = lookAtPoint-(2000.0f*lookAtVec3); std::shared_ptr tempCamera; if (currentScenario.orientation == ScenarioOrientation::soTopDownOrtho) { @@ -366,8 +358,8 @@ mathfu::mat4 MinimapGenerator::genTempProjectMatrix() { tempCamera = std::make_shared(); } - tempCamera->setCameraPos(cameraPos.x, cameraPos.y, cameraPos.z); - tempCamera->setCameraLookAt(lookAtPoint.x, lookAtPoint.y, lookAtPoint.z); + setupCamera(lookAtPoint, tempCamera); + tempCamera->tick(0); float nearPlane = 1.0; @@ -484,10 +476,11 @@ void MinimapGenerator::setupCameraData() { float alphaMax = -max2.z / (max1.z - max2.z); auto max = (max1 - max2) * alphaMax + max2; - - if (mandatoryADTMap.size() > 0) { - auto adtVec = mandatoryADTMap[m_x][m_y]; - m_currentScene->setMandatoryADTs(adtVec); + for (auto &mapRuntime : mapRuntimeInfo) { + if (mapRuntime.mandatoryADTMap.size() > 0) { + auto adtVec = mapRuntime.mandatoryADTMap[m_x][m_y]; + mapRuntime.scene->setMandatoryADTs(adtVec); + } } // std::cout << "(Debug) m_x = " << m_x << " m_y = " << m_y << @@ -507,26 +500,31 @@ void MinimapGenerator::setZoom(float zoom) { void MinimapGenerator::setLookAtPoint(float x, float y) { mathfu::vec3 lookAtPoint2D = mathfu::vec3(x, y, 0); + setupCamera(lookAtPoint2D, m_apiContainer->camera); + + m_apiContainer->camera->tick(0); +} + +void +MinimapGenerator::setupCamera(const mathfu::vec3 &lookAtPoint2D, std::shared_ptr &camera) { mathfu::vec3 lookAtVec3 = getLookAtVec3(); - mathfu::vec3 lookAtPoint = lookAtPoint2D - ((m_minZ - 10) * lookAtVec3); - mathfu::vec3 cameraPos = lookAtPoint2D - ((m_maxZ + 10)*lookAtVec3); -// std::cout << "cameraPos = (" << cameraPos.x << ", " << cameraPos.y << ", " << cameraPos.z << ") " << std::endl; + mathfu::vec3 lookAtPoint = lookAtPoint2D - ((m_minZ - 10) * lookAtVec3); + mathfu::vec3 cameraPos = lookAtPoint2D - ((m_maxZ + 10) * lookAtVec3); - m_apiContainer->camera->setCameraPos( + camera->setCameraPos( cameraPos.x, cameraPos.y, cameraPos.z ); - m_apiContainer->camera->setCameraLookAt( + camera->setCameraLookAt( lookAtPoint.x, lookAtPoint.y, lookAtPoint.z ); - m_apiContainer->camera->tick(0); } void MinimapGenerator::resetCandidate() { prepearCandidate = false; m_candidateDS = nullptr; - m_candidateCS = nullptr; - m_candidateUS = nullptr; + m_candidateCS = {}; + m_candidateUS = {}; framesReady = 0; } @@ -624,19 +622,29 @@ void MinimapGenerator::process() { return; } - if ( - (m_candidateCS != nullptr && ( - (m_candidateCS->m2Array.getToLoadGeom().size() != 0) || - (m_candidateCS->m2Array.getToLoadMain().size() != 0) || - (m_candidateCS->wmoGroupArray.getToLoad().size() != 0) - ) - ) || - (m_candidateUS != nullptr && m_candidateUS->texturesForUpload.size() > 0) - ) { - resetCandidate(); - return; + if (!m_candidateCS.empty()) { + for (auto &cullStage : m_candidateCS) { + if (cullStage != nullptr && ( + (cullStage->m2Array.getToLoadGeom().size() != 0) || + (cullStage->m2Array.getToLoadMain().size() != 0) || + (cullStage->wmoGroupArray.getToLoad().size() != 0) + )) { + resetCandidate(); + return; + } + } } + if (!m_candidateUS.empty()) { + for (auto &updateStage : m_candidateUS) { + if (updateStage != nullptr && updateStage->texturesForUpload.size() > 0) { + resetCandidate(); + return; + } + } + } + + if (m_candidateDS == nullptr) { resetCandidate(); prepearCandidate = true; @@ -662,7 +670,6 @@ void MinimapGenerator::process() { mathfu::vec3 minCoord = mathfu::vec3(20000, 20000, 20000); mathfu::vec3 maxCoord = mathfu::vec3(-20000, -20000, -20000); { - CAaBox adtBox2d = { mathfu::vec3_packed(mathfu::vec3(minAdt.x, minAdt.y, 0)), mathfu::vec3_packed(mathfu::vec3(maxAdt.x, maxAdt.y, 0)) @@ -700,12 +707,8 @@ void MinimapGenerator::process() { maxAdt.y, maxCoord.z); - if (m_boundingBoxHolder != nullptr) { - (*m_boundingBoxHolder)[adt_x][adt_y] = CAaBox( - C3Vector(minCoord), - C3Vector(maxCoord) - ); - } + currentScenario.maps[m_mapIndex].adtConfigHolder->adtMinZ[adt_x][adt_y] = minCoord.z; + currentScenario.maps[m_mapIndex].adtConfigHolder->adtMaxZ[adt_x][adt_y] = maxCoord.z; saveDrawStageToFile(currentScenario.folderToSave+"/minimap", lastFrameIt); } else if (m_mgMode == EMGMode::eScreenshotGeneration) { @@ -786,7 +789,8 @@ HDrawStage MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) mathfu::vec4 clearColor = m_apiContainer->getConfig()->clearColor; m_lastDraw = nullptr; - if (m_currentScene != nullptr) { + + if (!mapRuntimeInfo.empty()) { ViewPortDimensions dimensions = {{0, 0}, {m_width, m_height}}; HFrameBuffer fb = nullptr; @@ -801,20 +805,36 @@ HDrawStage MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) std::vector drawStageDependencies = {}; - auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, m_currentScene); - std::shared_ptr updateStage = sceneScenario->addUpdateStage(cullStage, 0, cameraMatricesRendering); + auto &&mainMap = mapRuntimeInfo[m_mapIndex]; + std::vector cullStages; + std::vector updateStages; + + if (m_mgMode != EMGMode::eBoundingBoxCalculation) { + for (auto &mapData: mapRuntimeInfo) { + auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mapData.scene); + HUpdateStage updateStage = sceneScenario->addUpdateStage(cullStage, 0, + cameraMatricesRendering); + cullStages.push_back(cullStage); + updateStages.push_back(updateStage); + } + } else { + auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mainMap.scene); + std::shared_ptr updateStage = sceneScenario->addUpdateStage(cullStage, 0, + cameraMatricesRendering); + } + HDrawStage sceneDrawStage = sceneScenario->addDrawStage( - updateStage, m_currentScene, cameraMatricesRendering, + updateStages, mainMap.scene, cameraMatricesRendering, drawStageDependencies, true, dimensions, true, false, clearColor, fb); m_lastDraw = sceneDrawStage; //We dont need stack in preview mode if (prepearCandidate && m_candidateDS == nullptr) { m_candidateDS = sceneDrawStage; - m_candidateCS = cullStage; - m_candidateUS = updateStage; + m_candidateCS = cullStages; + m_candidateUS = updateStages; } - stackOfCullStages[m_apiContainer->hDevice->getDrawFrameNumber()] = cullStage; + stackOfCullStages[m_apiContainer->hDevice->getDrawFrameNumber()] = cullStages[0]; return sceneDrawStage; } diff --git a/src/minimapGenerator/minimapGenerator.h b/src/minimapGenerator/minimapGenerator.h index cb89af231..633edf24c 100644 --- a/src/minimapGenerator/minimapGenerator.h +++ b/src/minimapGenerator/minimapGenerator.h @@ -19,10 +19,11 @@ class MinimapGenerator { std::vector scenarioListToProcess; ScenarioDef currentScenario; - HScene m_currentScene = nullptr; int m_width = 1024; int m_height = 1024; + int m_mapIndex = 0; + //Position that's being rendered int m_x = 0; int m_y = 0; @@ -38,16 +39,20 @@ class MinimapGenerator { HDrawStage m_lastDraw = nullptr; - HADTBoundingBoxHolder m_boundingBoxHolder = nullptr; + struct PerSceneData { + int mapIndex = -1; + HScene scene; + //Per X dimension, per Y dimension, vector of mandatory adt {x, y} coordinates + std::vector>>> mandatoryADTMap; + }; - //Per X dimension, per Y dimension, vector of mandatory adt {x, y} coordinates - std::vector>>> mandatoryADTMap; + std::vector mapRuntimeInfo; std::array stackOfCullStages; - HUpdateStage m_candidateUS = nullptr; + std::vector m_candidateUS = {}; HDrawStage m_candidateDS = nullptr; - HCullStage m_candidateCS = nullptr; + std::vector m_candidateCS = {}; float m_zFar = 3000.0f; float m_maxZ = 1000.0f; @@ -72,7 +77,7 @@ class MinimapGenerator { MinimapGenerator(HWoWFilesCacheStorage cacheStorage, const HGDevice &hDevice, HRequestProcessor processor, - std::shared_ptr dbhandler, HADTBoundingBoxHolder boundingBoxHolder); + std::shared_ptr dbhandler); void startScenarios(std::vector &scenarioListToProcess); void process(); @@ -95,7 +100,7 @@ class MinimapGenerator { void calcXtoYCoef(); - void setMinMaxXYWidhtHeight(const mathfu::vec2 &minWowWorldCoord, const mathfu::vec2 &maxWowWorldCoord); + void setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, const mathfu::vec2 &maxWowWorldCoord); void setupScenarioData(); @@ -112,6 +117,7 @@ class MinimapGenerator { void saveDrawStageToFile(std::string folderToSave, const std::shared_ptr &lastFrameIt); + void setupCamera(const mathfu::vec3 &lookAtPoint2D, std::shared_ptr &camera); }; typedef std::shared_ptr HMinimapGenerator; diff --git a/src/minimapGenerator/storage/CMinimapDataDB.cpp b/src/minimapGenerator/storage/CMinimapDataDB.cpp index 744acd495..0a34a8bb8 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.cpp +++ b/src/minimapGenerator/storage/CMinimapDataDB.cpp @@ -7,23 +7,361 @@ #include #include -CMinimapDataDB::CMinimapDataDB(std::string fileName) : m_sqliteDatabase(fileName, SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE) { + +CMinimapDataDB::StatementFieldHolder::StatementFieldHolder(SQLite::Database &database, const std::string &query) : + m_query(database, query) { + + for (int i = 0; i < m_query.getColumnCount(); i++) { + fieldToIndex[CalculateFNV(m_query.getColumnName(i))] = i; + } +} + +void CMinimapDataDB::StatementFieldHolder::setInputs() { + this->m_query.reset(); +} + +template +void CMinimapDataDB::StatementFieldHolder::setInputs(Ts &&... inputs) { + int i = 1; + this->m_query.reset(); + ((this->m_query.bind(i++, inputs)), ...); +} + +bool CMinimapDataDB::StatementFieldHolder::execute() { + return m_query.executeStep(); +} +SQLite::Column CMinimapDataDB::StatementFieldHolder::getField(const HashedString fieldName) { + int index = getFieldIndex(fieldName); + + if (index >= 0) { + return m_query.getColumn(index); + } else { + throw SQLite::Exception("Field was not found in query"); + } +} + +const std::string getAllScenariosSQL = +R"===( + select s.id, s.orientation, s.name, + s.ocean_color_0, s.ocean_color_1, s.ocean_color_2, s.ocean_color_3, + s.world_coord_min_x, s.world_coord_min_y, s.world_coord_max_x, s.world_coord_max_y, + s.image_width, s.image_height, s.zoom, s.folderToSave from scenarios s; +)==="; + +const std::string insertNewScenariosSQL = +R"===( + insert into scenarios (orientation, + ocean_color_0, ocean_color_1, ocean_color_2, ocean_color_3, + world_coord_min_x, world_coord_min_y, world_coord_max_x, world_coord_max_y, + image_width, image_height, zoom, folderToSave) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +)==="; + +const std::string updateScenarioSQL = +R"===( + update scenarios set map_id = ?, orientation = ?, + ocean_color_0 = ?, ocean_color_1 = ?, ocean_color_2 = ?, ocean_color_3 = ?, + world_coord_min_x = ?, world_coord_min_y = ?, world_coord_max_x = ?, world_coord_max_y = ?, + image_width = ?, image_height = ?, zoom = ?, folderToSave = ? + where id = ?; +)==="; + +const std::string getADTBoundingBoxSQL = +R"===( +select abb.adt_x, abb.adt_y, + abb.min_z, + abb.max_z from adt_bounding_boxes abb + where map_id = ? +)==="; + +const std::string insertADTBoundingBoxesSQL = + R"===( + insert into adt_bounding_boxes(map_id, + adt_x, adt_y, + min_z, max_z) + values (?, ?, ?, ?, ?) +)==="; + +const std::string getMapDefSQL = + R"===( + select + smd.map_id, + smd.deltaX, smd.deltaY, smd.deltaZ + from scenario_map_def smd + where smd.scenario_id = ? +)==="; + +const std::string insertMapDefSQL = + R"===( + insert into scenario_map_def( + scenario_id, + map_id, + deltaX, deltaY, deltaZ) + values (?, ?, ?, ?, ?) +)==="; + +const std::string updateMapDefSQL = + R"===( + update scenario_map_def set map_id = ?, + deltaX = ?, deltaY = ?, deltaZ = ? + where scenario_id = ? +)==="; + +const std::string getAdtExcludedSQL = +R"===( + select + exl.adt_x, exl.adt_y, + exl.chunk_x, exl.chunk_y + from scenario_map_def_excluded_adt exl + where exl.map_definition_id = ? +)==="; + +const std::string insertAdtExcludedSQL = + R"===( + insert into scenario_map_def_excluded_adt(map_definition_id, + adt_x, adt_y, + min_z, max_z) + values (?, ?, ?, ?, ?) +)==="; + +CMinimapDataDB::CMinimapDataDB(const std::string &fileName) : + m_sqliteDatabase(fileName, SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE), + getAllScenarios(InitDB(m_sqliteDatabase), getAllScenariosSQL), + insertNewScenario(InitDB(m_sqliteDatabase), insertNewScenariosSQL), + updateScenario(InitDB(m_sqliteDatabase), updateScenarioSQL), + getADTBoundingBoxes(InitDB(m_sqliteDatabase), getADTBoundingBoxSQL), + insertADTBoundingBoxes(InitDB(m_sqliteDatabase), insertADTBoundingBoxesSQL), + + getMapDef(InitDB(m_sqliteDatabase), getMapDefSQL), + insertMapDef(InitDB(m_sqliteDatabase), insertMapDefSQL), + updateMapDef(InitDB(m_sqliteDatabase), updateMapDefSQL), + + getADTExcluded(InitDB(m_sqliteDatabase), getAdtExcludedSQL), + insertADTExcluded(InitDB(m_sqliteDatabase), insertAdtExcludedSQL) +{ char *sErrMsg = ""; // sqlite3_exec(m_sqliteDatabase.getHandle(), "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg); // sqlite3_exec(m_sqliteDatabase.getHandle(), "PRAGMA schema.journal_mode = MEMORY", NULL, NULL, &sErrMsg); +} + +void CMinimapDataDB::getScenarios(std::vector &scenarioList) { + if (!m_sqliteDatabase.tableExists("scenarios")) + return; + + getAllScenarios.setInputs(); + + while (getAllScenarios.execute()) + { + ScenarioDef scenarioDef; + + scenarioDef.id = getAllScenarios.getField("id").getInt(); + + scenarioDef.orientation = static_cast(getAllScenarios.getField("orientation").getInt()); + scenarioDef.name = getAllScenarios.getField("name").getString(); + scenarioDef.closeOceanColor = mathfu::vec4( + getAllScenarios.getField("ocean_color_0").getDouble(), + getAllScenarios.getField("ocean_color_1").getDouble(), + getAllScenarios.getField("ocean_color_2").getDouble(), + getAllScenarios.getField("ocean_color_3").getDouble() + ); + scenarioDef.minWowWorldCoord = mathfu::vec2(getAllScenarios.getField("world_coord_min_x").getDouble(), + getAllScenarios.getField("world_coord_min_y").getDouble()); + scenarioDef.maxWowWorldCoord = mathfu::vec2(getAllScenarios.getField("world_coord_max_x").getDouble(), + getAllScenarios.getField("world_coord_max_y").getDouble()); + + scenarioDef.imageWidth = getAllScenarios.getField("image_width").getInt(); + scenarioDef.imageHeight = getAllScenarios.getField("image_height").getInt(); + + scenarioDef.zoom = getAllScenarios.getField("zoom").getDouble(); + scenarioDef.folderToSave = getAllScenarios.getField("folderToSave").getDouble(); + + scenarioList.push_back(scenarioDef); + } + + for (auto &scenario : scenarioList) { + this->getMapRenderDef(scenario.id, scenario.maps); + } +} + +void CMinimapDataDB::saveScenarios(std::vector &scenarios) { + SQLite::Transaction transaction(m_sqliteDatabase); + + for (auto &scenario : scenarios) { + if (scenario.id == -1) { + insertNewScenario.setInputs( + (int) scenario.orientation, + scenario.closeOceanColor.x, + scenario.closeOceanColor.y, + scenario.closeOceanColor.z, + scenario.closeOceanColor.w, + scenario.minWowWorldCoord.x, + scenario.minWowWorldCoord.y, + scenario.maxWowWorldCoord.x, + scenario.maxWowWorldCoord.y, + scenario.imageWidth, + scenario.imageHeight, + scenario.zoom, + scenario.folderToSave.c_str() + ); + + if (insertNewScenario.execute()) { + scenario.id = m_sqliteDatabase.getLastInsertRowid(); + } + } else { + updateScenario.setInputs( + (int) scenario.orientation, + scenario.closeOceanColor.x, + scenario.closeOceanColor.y, + scenario.closeOceanColor.z, + scenario.closeOceanColor.w, + scenario.minWowWorldCoord.x, + scenario.minWowWorldCoord.y, + scenario.maxWowWorldCoord.x, + scenario.maxWowWorldCoord.y, + scenario.imageWidth, + scenario.imageHeight, + scenario.zoom, + scenario.folderToSave.c_str(), + scenario.id + ); + + updateScenario.execute(); + } + } + + // Commit transaction + transaction.commit(); +} + +void CMinimapDataDB::getAdtBoundingBoxes(MapRenderDef& mapRenderDef) { + getADTBoundingBoxes.setInputs(mapRenderDef.mapId); + + while (getADTBoundingBoxes.execute()) + { + int adt_x = getADTBoundingBoxes.getField("adt_x").getInt(); + int adt_y = getADTBoundingBoxes.getField("adt_y").getInt(); + + mapRenderDef.adtConfigHolder->adtMinZ[adt_x][adt_y] = getADTBoundingBoxes.getField("min_z").getDouble(); + mapRenderDef.adtConfigHolder->adtMaxZ[adt_x][adt_y] = getADTBoundingBoxes.getField("max_z").getDouble(); + } +} + +void CMinimapDataDB::saveAdtBoundingBoxes(MapRenderDef& mapRenderDef) { + SQLite::Transaction transaction(m_sqliteDatabase); + + //1. Clear all records for that mapId from DB + { + SQLite::Statement cleanABB(m_sqliteDatabase, + "delete from adt_bounding_boxes where map_id = ?" + ); + cleanABB.exec(); + } + + //2. Insert into database + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + insertADTBoundingBoxes.setInputs(mapRenderDef.mapId, i, j, + mapRenderDef.adtConfigHolder->adtMinZ[i][j], + mapRenderDef.adtConfigHolder->adtMaxZ[i][j]); + insertADTBoundingBoxes.execute(); + } + } + + //3. Commit transaction + transaction.commit(); +} + +void CMinimapDataDB::getAdtExcluded(MapRenderDef& mapRenderDef) { + getADTExcluded.setInputs(mapRenderDef.id); + + while (getADTExcluded.execute()) + { + int adt_x = getADTExcluded.getField("adt_x").getInt(); + int adt_y = getADTExcluded.getField("adt_y").getInt(); + int chunk_x = getADTExcluded.getField("chunk_x").getInt(); + int chunk_y = getADTExcluded.getField("chunk_y").getInt(); + + AdtCell adtCell = {adt_x, adt_y}; + AdtCell chunkCell = {chunk_x, chunk_y}; + if (chunk_x == -1 || chunk_y == -1) {\ + + mapRenderDef.adtConfigHolder->excludedADTs.insert(adtCell); + } else { + mapRenderDef.adtConfigHolder->excludedChunksPerADTs[adtCell].insert(chunkCell); + } + } +} +void CMinimapDataDB::saveAdtExcluded(MapRenderDef& mapRenderDef){ + +} + +void CMinimapDataDB::getRiverColorOverrides(int mapId, std::vector &riverOverrides) { +// SQLite::Statement getRiverColor(m_sqliteDatabase, +// "select rco.liquid_id, rco.color_0, rco.color_1, rco.color_2, rco.color_3 " +// " from river_color_overrides rco where rco.map_id = ?;" +// ); +// getRiverColor.reset(); +// getRiverColor.bind(1, mapId); +// +// while (getRiverColor.executeStep()) +// { +// RiverColorOverride colorOverride; +// colorOverride.liquidId = getRiverColor.getColumn(0).getInt(); +// colorOverride.color = mathfu::vec4( +// getRiverColor.getColumn(1).getDouble(), +// getRiverColor.getColumn(2).getDouble(), +// getRiverColor.getColumn(3).getDouble(), +// getRiverColor.getColumn(4).getDouble() +// ); +// riverOverrides.push_back(colorOverride); +// } +} + +void CMinimapDataDB::saveRiverColorOverrides(int mapId, std::vector &riverOverrides) { +// SQLite::Transaction transaction(m_sqliteDatabase); +// +// //1. Clear all records for that mapId from DB +// { +// SQLite::Statement cleanRiverColor(m_sqliteDatabase, +// "delete from river_color_overrides where map_id = ?" +// ); +// cleanRiverColor.bind(1, mapId); +// cleanRiverColor.exec(); +// } +// +// SQLite::Statement saveRiverColor(m_sqliteDatabase, "insert into river_color_overrides(map_id, liquid_id, " +// "color_0, color_1, color_2, color_3) \n" +// "values (?, ?, ?, ?, ?, ?);"); +// +// for (int j = 0; j < riverOverrides.size(); j++) { +// auto &roRec = riverOverrides[j]; +// saveRiverColor.reset(); +// +// saveRiverColor.bind(1, mapId); +// saveRiverColor.bind(2, roRec.liquidId); +// saveRiverColor.bind(3, roRec.color.x); +// saveRiverColor.bind(4, roRec.color.y); +// saveRiverColor.bind(5, roRec.color.z); +// saveRiverColor.bind(6, roRec.color.w); +// +// saveRiverColor.exec(); +// } +// transaction.commit(); +} + +SQLite::Database &CMinimapDataDB::InitDB(SQLite::Database &database) { //------------------------------- // Create Scenario table // ------------------------------ { - SQLite::Transaction transaction(m_sqliteDatabase); + SQLite::Transaction transaction(database); - m_sqliteDatabase.exec("CREATE TABLE IF NOT EXISTS scenarios\n" + database.exec("CREATE TABLE IF NOT EXISTS scenarios\n" "(\n" " id INTEGER PRIMARY KEY,\n" - " map_id INTEGER,\n" - " orientation INTEGER,\n" " name VARCHAR(256),\n" + " orientation INTEGER,\n" " ocean_color_0 FLOAT,\n" " ocean_color_1 FLOAT,\n" " ocean_color_2 FLOAT,\n" @@ -45,18 +383,14 @@ CMinimapDataDB::CMinimapDataDB(std::string fileName) : m_sqliteDatabase(fileName // Create Bounding boxes table // ------------------------------ { - SQLite::Transaction transaction(m_sqliteDatabase); + SQLite::Transaction transaction(database); - m_sqliteDatabase.exec("CREATE TABLE IF NOT EXISTS adt_bounding_boxes (\n" + database.exec("CREATE TABLE IF NOT EXISTS adt_bounding_boxes (\n" " id INTEGER PRIMARY KEY,\n" " map_id INTEGER,\n" " adt_x INTEGER,\n" " adt_y INTEGER,\n" - " min_x FLOAT,\n" - " min_y FLOAT,\n" " min_z FLOAT,\n" - " max_x FLOAT,\n" - " max_y FLOAT,\n" " max_z FLOAT\n" ")"); @@ -64,315 +398,97 @@ CMinimapDataDB::CMinimapDataDB(std::string fileName) : m_sqliteDatabase(fileName } //------------------------------- - // Create river color overrides + // Create map definition per scenario // ------------------------------ - { - SQLite::Transaction transaction(m_sqliteDatabase); + SQLite::Transaction transaction(database); - m_sqliteDatabase.exec("CREATE TABLE IF NOT EXISTS river_color_overrides\n" - "(\n" - " id INTEGER PRIMARY KEY,\n" - " map_id INTEGER,\n" - " area_id INTEGER,\n" - " color_0 FLOAT,\n" - " color_1 FLOAT,\n" - " color_2 FLOAT,\n" - " color_3 FLOAT\n" + database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def (\n" + " scenario_id INTEGER,\n" + " map_id INTEGER,\n" + " deltaX DOUBLE,\n" + " deltaY DOUBLE,\n" + " deltaZ DOUBLE\n" ")"); transaction.commit(); } //------------------------------- - // Create WMO aabb overrides + // Create excluded ADTs per map_def // ------------------------------ { - SQLite::Transaction transaction(m_sqliteDatabase); + SQLite::Transaction transaction(database); - m_sqliteDatabase.exec("CREATE TABLE IF NOT EXISTS wmo_aabb_overrides\n" - "(\n" - " id INTEGER PRIMARY KEY,\n" - " map_id INTEGER,\n" - " unique_id INTEGER,\n" - " min_x FLOAT,\n" - " min_y FLOAT,\n" - " min_z FLOAT,\n" - " max_x FLOAT,\n" - " max_y FLOAT,\n" - " max_z FLOAT\n" + database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def (\n" + " id INTEGER PRIMARY KEY,\n" + " map_definition_id INTEGER,\n" + " adt_x INTEGER,\n" + " adt_y INTEGER\n" ")"); transaction.commit(); } -} - -void CMinimapDataDB::getScenarios(std::vector &scenarioList) { - if (!m_sqliteDatabase.tableExists("scenarios")) - return; - - SQLite::Statement getScenarioList(m_sqliteDatabase, - "select s.id, s.map_id, s.orientation, s.name, \n" - " s.ocean_color_0, s.ocean_color_1, s.ocean_color_2, s.ocean_color_3,\n" - " s.world_coord_min_x, s.world_coord_min_y, s.world_coord_max_x, s.world_coord_max_y,\n" - " s.image_width, s.image_height, s.zoom, s.folderToSave from scenarios s;" - ); - getScenarioList.reset(); - - while (getScenarioList.executeStep()) - { - ScenarioDef scenarioDef; - - scenarioDef.id = getScenarioList.getColumn(0).getInt(); - scenarioDef.mapId = getScenarioList.getColumn(1).getInt(); - scenarioDef.orientation = static_cast(getScenarioList.getColumn(2).getInt()); - scenarioDef.name = getScenarioList.getColumn(3).getString(); - scenarioDef.closeOceanColor = mathfu::vec4( - getScenarioList.getColumn(4).getDouble(), - getScenarioList.getColumn(5).getDouble(), - getScenarioList.getColumn(6).getDouble(), - getScenarioList.getColumn(7).getDouble() - ); - scenarioDef.minWowWorldCoord = mathfu::vec2(getScenarioList.getColumn(8).getDouble(), - getScenarioList.getColumn(9).getDouble()); - scenarioDef.maxWowWorldCoord = mathfu::vec2(getScenarioList.getColumn(10).getDouble(), - getScenarioList.getColumn(11).getDouble()); - - scenarioDef.imageWidth = getScenarioList.getColumn(12).getInt(); - scenarioDef.imageHeight = getScenarioList.getColumn(13).getInt(); - - scenarioDef.zoom = getScenarioList.getColumn(14).getDouble(); - scenarioDef.folderToSave = getScenarioList.getColumn(15).getDouble(); - - scenarioList.push_back(scenarioDef); - } -} -void CMinimapDataDB::getScenario(int id, ScenarioDef &scenario) { - SQLite::Statement getScenarioById(m_sqliteDatabase, - "select s.id, s.map_id, s.orientation,\n" - " s.ocean_color_0, s.ocean_color_1, s.ocean_color_2, s.ocean_color_3,\n" - " s.world_coord_min_x, s.world_coord_min_y, s.world_coord_max_x, s.world_coord_max_y,\n" - " s.image_width, s.image_height, s.zoom, s.folderToSave from scenarios s" - " where s.id = ?;" - ); - getScenarioById.reset(); - getScenarioById.bind(1, id); - - while (getScenarioById.executeStep()) + //------------------------------- + // Create excluded ADT CELLS/chunks per map_def + // ------------------------------ { - ScenarioDef scenarioDef; - - scenarioDef.id = getScenarioById.getColumn(0).getInt(); - scenarioDef.mapId = getScenarioById.getColumn(1).getInt(); - scenarioDef.orientation = static_cast(getScenarioById.getColumn(3).getInt()); - scenarioDef.closeOceanColor = mathfu::vec4( - getScenarioById.getColumn(4).getDouble(), - getScenarioById.getColumn(5).getDouble(), - getScenarioById.getColumn(6).getDouble(), - getScenarioById.getColumn(7).getDouble() - ); - scenarioDef.minWowWorldCoord = mathfu::vec2(getScenarioById.getColumn(8).getDouble(), - getScenarioById.getColumn(9).getDouble()); - scenarioDef.maxWowWorldCoord = mathfu::vec2(getScenarioById.getColumn(10).getDouble(), - getScenarioById.getColumn(11).getDouble()); + SQLite::Transaction transaction(database); - scenarioDef.imageWidth = getScenarioById.getColumn(12).getInt(); - scenarioDef.imageHeight = getScenarioById.getColumn(13).getInt(); + database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def_excluded_adt (\n" + " map_definition_id INTEGER,\n" + " adt_x INTEGER,\n" + " adt_y INTEGER,\n" + " chunk_x INTEGER,\n" + " chunk_y INTEGER\n" + ")"); - scenarioDef.zoom = getScenarioById.getColumn(14).getDouble(); - scenarioDef.folderToSave = getScenarioById.getColumn(15).getString(); + transaction.commit(); } -} -void CMinimapDataDB::saveScenario(ScenarioDef &scenario) { - SQLite::Transaction transaction(m_sqliteDatabase); - if (scenario.id == -1) { - SQLite::Statement insertScenario(m_sqliteDatabase, - "insert into scenarios (map_id, orientation, \n" - " ocean_color_0, ocean_color_1, ocean_color_2, ocean_color_3, \n" - " world_coord_min_x, world_coord_min_y, world_coord_max_x, world_coord_max_y, \n" - " image_width, image_height, zoom, folderToSave) \n" - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" - ); - - insertScenario.bind(1, scenario.mapId); - insertScenario.bind(2, (int)scenario.orientation); - insertScenario.bind(3, scenario.closeOceanColor.x); - insertScenario.bind(4, scenario.closeOceanColor.y); - insertScenario.bind(5, scenario.closeOceanColor.z); - insertScenario.bind(6, scenario.closeOceanColor.w); - insertScenario.bind(7, scenario.minWowWorldCoord.x); - insertScenario.bind(8, scenario.minWowWorldCoord.y); - insertScenario.bind(9, scenario.maxWowWorldCoord.x); - insertScenario.bind(10, scenario.maxWowWorldCoord.y); - insertScenario.bind(11, scenario.imageWidth); - insertScenario.bind(12, scenario.imageHeight); - insertScenario.bind(13, scenario.zoom); - insertScenario.bind(14, scenario.folderToSave.c_str()); - insertScenario.exec(); - } else { - SQLite::Transaction transaction(m_sqliteDatabase); - - SQLite::Statement updateScenario(m_sqliteDatabase, - "update scenarios set map_id = ?, orientation = ?,\n" - " ocean_color_0 = ?, ocean_color_1 = ?, ocean_color_2 = ?, ocean_color_3 = ?,\n" - " world_coord_min_x = ?, world_coord_min_y = ?, world_coord_max_x = ?, world_coord_max_y = ?,\n" - " image_width = ?, image_height = ?, zoom = ?, folderToSave = ?\n" - " where id = ?;" - ); - - updateScenario.bind(1, scenario.mapId); - updateScenario.bind(2, (int)scenario.orientation); - updateScenario.bind(3, scenario.closeOceanColor.x); - updateScenario.bind(4, scenario.closeOceanColor.y); - updateScenario.bind(5, scenario.closeOceanColor.z); - updateScenario.bind(6, scenario.closeOceanColor.w); - updateScenario.bind(7, scenario.minWowWorldCoord.x); - updateScenario.bind(8, scenario.minWowWorldCoord.y); - updateScenario.bind(9, scenario.maxWowWorldCoord.x); - updateScenario.bind(10, scenario.maxWowWorldCoord.y); - updateScenario.bind(11, scenario.imageWidth); - updateScenario.bind(12, scenario.imageHeight); - updateScenario.bind(13, scenario.zoom); - updateScenario.bind(14, scenario.folderToSave.c_str()); - updateScenario.bind(15, scenario.id); - updateScenario.exec(); - } - - // Commit transaction - transaction.commit(); -} + //------------------------------- + // Create river color overrides + // ------------------------------ -void CMinimapDataDB::getAdtBoundingBoxes(int mapId, ADTBoundingBoxHolder &boundingBoxHolder) { - SQLite::Statement getAdtBB(m_sqliteDatabase, - "select abb.adt_x, abb.adt_y, \n" - " abb.min_x, abb.min_y, abb.min_z, \n" - " abb.max_x, abb.max_y, abb.max_z from adt_bounding_boxes abb \n" - " where map_id = ?" - ); - getAdtBB.reset(); - getAdtBB.bind(1, mapId); - - while (getAdtBB.executeStep()) { - int adt_x = getAdtBB.getColumn(0).getInt(); - int adt_y = getAdtBB.getColumn(1).getInt(); - CAaBox aaBox = CAaBox( - C3Vector(mathfu::vec3( - getAdtBB.getColumn(2).getDouble(), - getAdtBB.getColumn(3).getDouble(), - getAdtBB.getColumn(4).getDouble() - )), - C3Vector(mathfu::vec3( - getAdtBB.getColumn(5).getDouble(), - getAdtBB.getColumn(6).getDouble(), - getAdtBB.getColumn(7).getDouble() - )) - ); - - boundingBoxHolder[adt_x][adt_y] = aaBox; - } -} - -void CMinimapDataDB::saveAdtBoundingBoxes(int mapId, ADTBoundingBoxHolder &boundingBoxHolder) { - SQLite::Transaction transaction(m_sqliteDatabase); + SQLite::Transaction transaction(database); - //1. Clear all records for that mapId from DB - { - SQLite::Statement cleanABB(m_sqliteDatabase, - "delete from adt_bounding_boxes where map_id = ?" - ); - cleanABB.exec(); - } + database.exec("CREATE TABLE IF NOT EXISTS river_color_overrides\n" + "(\n" + " id INTEGER PRIMARY KEY,\n" + " map_id INTEGER,\n" + " liquid_id INTEGER,\n" + " color_0 FLOAT,\n" + " color_1 FLOAT,\n" + " color_2 FLOAT,\n" + " color_3 FLOAT\n" + ")"); - //2. Insert into database - SQLite::Statement insertBB(m_sqliteDatabase, "insert into adt_bounding_boxes(map_id, adt_x, adt_y, min_x, min_y, min_z, max_x, max_y, max_z) " - "values (?, ?, ?, ?, ?, ?, ?, ?, ?)"); - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - auto aabb = boundingBoxHolder[i][j]; - insertBB.reset(); - - insertBB.bind(1, mapId); - insertBB.bind(2, i); - insertBB.bind(3, j); - insertBB.bind(4, aabb.min.x); - insertBB.bind(5, aabb.min.y); - insertBB.bind(6, aabb.min.z); - insertBB.bind(7, aabb.max.x); - insertBB.bind(8, aabb.max.y); - insertBB.bind(9, aabb.max.z); - - insertBB.exec(); - } + transaction.commit(); } - //3. Commit transaction - transaction.commit(); -} - -void CMinimapDataDB::getRiverColorOverrides(int mapId, std::vector &riverOverrides) { - SQLite::Statement getRiverColor(m_sqliteDatabase, - "select rco.area_id, rco.color_0, rco.color_1, rco.color_2, rco.color_3 " - " from river_color_overrides rco where rco.map_id = ?;" - ); - getRiverColor.reset(); - getRiverColor.bind(1, mapId); - - while (getRiverColor.executeStep()) - { - RiverColorOverride colorOverride; - colorOverride.areaId = getRiverColor.getColumn(0).getInt(); - colorOverride.color = mathfu::vec4( - getRiverColor.getColumn(1).getDouble(), - getRiverColor.getColumn(2).getDouble(), - getRiverColor.getColumn(3).getDouble(), - getRiverColor.getColumn(4).getDouble() - ); - riverOverrides.push_back(colorOverride); - } + return database; } -void CMinimapDataDB::saveRiverColorOverrides(int mapId, std::vector &riverOverrides) { - SQLite::Transaction transaction(m_sqliteDatabase); +void CMinimapDataDB::getMapRenderDef(int scenarioId, std::vector &mapRenderDefs) { + getMapDef.setInputs(scenarioId); - //1. Clear all records for that mapId from DB - { - SQLite::Statement cleanRiverColor(m_sqliteDatabase, - "delete from river_color_overrides where map_id = ?" - ); - cleanRiverColor.bind(1, mapId); - cleanRiverColor.exec(); + while (getMapDef.execute()) { + auto &mapRenderDef = mapRenderDefs.emplace_back(); + mapRenderDef.mapId = getMapDef.getField("map_id").getInt(); + mapRenderDef.deltaX = getMapDef.getField("deltaX").getDouble(); + mapRenderDef.deltaY = getMapDef.getField("deltaY").getDouble(); + mapRenderDef.deltaZ = getMapDef.getField("deltaZ").getDouble(); } - SQLite::Statement saveRiverColor(m_sqliteDatabase, "insert into river_color_overrides(map_id, area_id, " - "color_0, color_1, color_2, color_3) \n" - "values (?, ?, ?, ?, ?, ?);"); - - for (int j = 0; j < riverOverrides.size(); j++) { - auto &roRec = riverOverrides[j]; - saveRiverColor.reset(); - - saveRiverColor.bind(1, mapId); - saveRiverColor.bind(2, roRec.areaId); - saveRiverColor.bind(3, roRec.color.x); - saveRiverColor.bind(4, roRec.color.y); - saveRiverColor.bind(5, roRec.color.z); - saveRiverColor.bind(6, roRec.color.w); - - saveRiverColor.exec(); + for (auto &mapRenderDef : mapRenderDefs) { + this->getAdtBoundingBoxes(mapRenderDef); + this->getAdtExcluded(mapRenderDef); } - transaction.commit(); -} - -bool CMinimapDataDB::getWmoAABBOverride(int mapId, int uniqueId, CAaBox &aaBox) { - return false; -} - -void CMinimapDataDB::saveWmoAABBOverride(int mapId, int uniqueId, const CAaBox &aaBox) { - } +void CMinimapDataDB::saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef) { +} \ No newline at end of file diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index 6763e1636..618fdf049 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -8,23 +8,28 @@ #include #include "../entities.h" #include "../minimapGenerator.h" +#include "../../../wowViewerLib/src/engine/algorithms/hashString.h" class CMinimapDataDB { private: SQLite::Database m_sqliteDatabase; - public: - explicit CMinimapDataDB(std::string fileName); + explicit CMinimapDataDB(const std::string &fileName); //Scenarios void getScenarios(std::vector &scenarioList); - void getScenario(int id, ScenarioDef &scenario); - void saveScenario(ScenarioDef &scenario); + void saveScenarios(std::vector &scenarios); //ADT Bounding boxes - void getAdtBoundingBoxes(int mapId, ADTBoundingBoxHolder &boundingBoxHolder); - void saveAdtBoundingBoxes(int mapId, ADTBoundingBoxHolder &boundingBoxHolder); + void getMapRenderDef(int scenarioId, std::vector &mapRenderDef); + void saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef); + + void getAdtBoundingBoxes(MapRenderDef& mapRenderDef); + void saveAdtBoundingBoxes(MapRenderDef& mapRenderDef); + + void getAdtExcluded(MapRenderDef& mapRenderDef); + void saveAdtExcluded(MapRenderDef& mapRenderDef); //River color overrides void getRiverColorOverrides(int mapId, std::vector &riverOverrides); @@ -33,6 +38,45 @@ class CMinimapDataDB { //Get WMO ADT aabb override bool getWmoAABBOverride(int mapId, int uniqueId, CAaBox &aaBox); void saveWmoAABBOverride(int mapId, int uniqueId, const CAaBox &aaBox); + +private: + class StatementFieldHolder { + public: + StatementFieldHolder(SQLite::Database &database, const std::string &query); + + template + void setInputs(Ts && ... inputs); + + void setInputs(); + bool execute(); + SQLite::Column getField(HashedString fieldName); + inline int getFieldIndex(HashedString fieldName) { + auto it = fieldToIndex.find(fieldName.Hash()); + if(it != fieldToIndex.end()) { + return it->second; + } else { + return -1; + } + } + private: + SQLite::Statement m_query; + std::unordered_map fieldToIndex; + }; + + SQLite::Database &InitDB(SQLite::Database &database); + + StatementFieldHolder getAllScenarios; + StatementFieldHolder insertNewScenario; + StatementFieldHolder updateScenario; + StatementFieldHolder getADTBoundingBoxes; + StatementFieldHolder insertADTBoundingBoxes; + + StatementFieldHolder getMapDef; + StatementFieldHolder insertMapDef; + StatementFieldHolder updateMapDef; + + StatementFieldHolder getADTExcluded; + StatementFieldHolder insertADTExcluded; }; diff --git a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl index e1a27ae16..51c7bb313 100644 --- a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl @@ -4,9 +4,9 @@ vec2 posToTexCoord(vec3 cameraPoint, vec3 normal){ // vec3 reflection = reflect(normPos, normal); // return (normalize(vec3(reflection.r, reflection.g, reflection.b + 1.0)).rg * 0.5) + vec2(0.5); - vec3 normPos_495 = normalize(cameraPoint.xyz); - vec3 temp_500 = (normPos_495 - (normal * (2.0 * dot(normPos_495, normal)))); - vec3 temp_657 = vec3(temp_500.x, temp_500.y, (temp_500.z + 1.0)); + vec3 viewVecNormalized = -normalize(cameraPoint.xyz); + vec3 reflection = reflect(viewVecNormalized, normal); + vec3 temp_657 = vec3(reflection.x, reflection.y, (reflection.z + 1.0)); return ((normalize(temp_657).xy * 0.5) + vec2(0.5)); } diff --git a/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert b/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert index 631c58bfc..d0eab8879 100644 --- a/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert @@ -48,16 +48,13 @@ void main() { vec4 cameraPoint = scene.uLookAtMat * worldPoint; - mat4 viewModelMat = scene.uLookAtMat * uPlacementMat; mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); - gl_Position = scene.uPMatrix * cameraPoint; vPosition = vec4(cameraPoint.xyz, 0); vNormal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; - vColor = aColor.bgra; vColor2 = aColor2; vColorSecond = aColorSecond; @@ -99,7 +96,7 @@ void main() { vTexCoord3 = aTexCoord3; //not used } else if (uVertexShader == 7) { //MapObjDiffuse_CompAlpha vTexCoord = aTexCoord; - vTexCoord2 = vPosition.xy * -0.239999995; + vTexCoord2 = aTexCoord2; vTexCoord3 = aTexCoord3; //not used } else if (uVertexShader == 8) { //MapObjParallax vTexCoord = aTexCoord; diff --git a/wowViewerLib/src/engine/SceneComposer.cpp b/wowViewerLib/src/engine/SceneComposer.cpp index 510c48232..e22d7009f 100644 --- a/wowViewerLib/src/engine/SceneComposer.cpp +++ b/wowViewerLib/src/engine/SceneComposer.cpp @@ -188,7 +188,7 @@ void SceneComposer::DoUpdate() { logExecution for (auto &link : frameScenario->drawStageLinks) { logExecution - link.scene->produceDrawStage(link.drawStage, link.updateStage, additionalChunks); + link.scene->produceDrawStage(link.drawStage, link.updateStages, additionalChunks); logExecution } produceDrawStage.endMeasurement(); diff --git a/wowViewerLib/src/engine/SceneScenario.cpp b/wowViewerLib/src/engine/SceneScenario.cpp index 4eca64623..ba43fe013 100644 --- a/wowViewerLib/src/engine/SceneScenario.cpp +++ b/wowViewerLib/src/engine/SceneScenario.cpp @@ -33,7 +33,7 @@ HDrawStage FrameScenario::getDrawStage() { //FrameScenario::addDrawStage(std::shared_ptr, std::shared_ptr, std::shared_ptr, std::vector, std::allocator>> const&, bool, ViewPortDimensions const&, bool, mathfu::Vector const&, std::shared_ptr) //FrameScenario::addDrawStage(std::shared_ptr, std::shared_ptr, std::shared_ptr, std::__debug::vector, std::allocator>> const&, bool, ViewPortDimensions const&, bool, mathfu::Vector const&, std::shared_ptr) -HDrawStage FrameScenario::addDrawStage(HUpdateStage updateStage, HScene scene, HCameraMatrices matricesForDrawing, +HDrawStage FrameScenario::addDrawStage(std::vector &updateStages, HScene scene, HCameraMatrices matricesForDrawing, std::vector const &drawStageDependencies, bool setViewPort, ViewPortDimensions const &viewPortDimensions, bool clearScreen, bool invertedZ, mathfu::vec4 const &clearColor, HFrameBuffer fbTarget) { @@ -50,7 +50,7 @@ HDrawStage FrameScenario::addDrawStage(HUpdateStage updateStage, HScene scene, H // drawStage->sceneWideBlockVSPSChunk; - drawStageLinks.push_back({scene, updateStage, drawStage}); + drawStageLinks.push_back({scene, updateStages, drawStage}); this->lastDrawStage = drawStage; diff --git a/wowViewerLib/src/engine/SceneScenario.h b/wowViewerLib/src/engine/SceneScenario.h index c757747fa..2ce4c72cf 100644 --- a/wowViewerLib/src/engine/SceneScenario.h +++ b/wowViewerLib/src/engine/SceneScenario.h @@ -78,7 +78,7 @@ class FrameScenario { friend class SceneComposer; struct DrawStageLinkage { HScene scene; - HUpdateStage updateStage; + std::vector updateStages; HDrawStage drawStage; }; private: @@ -92,7 +92,7 @@ class FrameScenario { HCullStage addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene); HUpdateStage addUpdateStage(HCullStage cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate); - HDrawStage addDrawStage(HUpdateStage updateStage, + HDrawStage addDrawStage(std::vector &updateStage, HScene scene, HCameraMatrices matricesForDrawing, std::vector const &drawStageDependencies, diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index d35f4c45e..8ae412313 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -180,7 +180,6 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid } } } else { - std::vector liquidTypeData; m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liquidTypeData); for (auto ltd: liquidTypeData) { @@ -289,13 +288,13 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid bool waterColorFound = true; if (m_api->getConfig()->colorOverrideHolder != nullptr) { waterColorFound = false; - int adt_global_x = worldCoordinateToGlobalAdtChunk(waterPos.y) % 16; - int adt_global_y = worldCoordinateToGlobalAdtChunk(waterPos.x) % 16; - - auto areaId = getAreaId(adt_global_x, adt_global_y); +// int adt_global_x = worldCoordinateToGlobalAdtChunk(waterPos.y) % 16; +// int adt_global_y = worldCoordinateToGlobalAdtChunk(waterPos.x) % 16; +// +// auto areaId = getAreaId(adt_global_x, adt_global_y); for (auto &riverOverride : *m_api->getConfig()->colorOverrideHolder) { - if (riverOverride.areaId == areaId) { + if (riverOverride.liquidObjectId == liquidInstance.liquid_object_or_lvf) { closeRiverColor = riverOverride.color.xyz(); waterColorFound = true; break; @@ -1273,8 +1272,6 @@ bool AdtObject::checkReferences( bool AdtObject::checkFrustumCulling(ADTObjRenderRes &adtFrustRes, const mathfu::vec4 &cameraPos, - int adt_glob_x, - int adt_glob_y, const MathHelper::FrustumCullingData &frustumData, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index a7a5b0d72..f4f59acd6 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -59,8 +59,6 @@ class AdtObject { bool checkFrustumCulling( ADTObjRenderRes &adtFrustRes, const mathfu::vec4 &cameraPos, - int adt_glob_x, - int adt_glob_y, const MathHelper::FrustumCullingData &frustumData, M2ObjectListContainer&m2ObjectsCandidates, diff --git a/wowViewerLib/src/engine/objects/iScene.h b/wowViewerLib/src/engine/objects/iScene.h index f0fc83c25..575dc7e2c 100644 --- a/wowViewerLib/src/engine/objects/iScene.h +++ b/wowViewerLib/src/engine/objects/iScene.h @@ -23,7 +23,7 @@ class IScene { virtual void setMeshIds(std::vector &meshIds) = 0; virtual void resetAnimation() = 0; - virtual void produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) = 0; + virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStage, std::vector &additionalChunks) = 0; virtual void produceUpdateStage(HUpdateStage &updateStage) = 0; virtual void checkCulling(HCullStage &cullStage) = 0; @@ -36,7 +36,7 @@ class IScene { virtual void exportScene(IExporter * exporter) {}; - virtual void setAdtBoundingBoxHolder(HADTBoundingBoxHolder &bbHolder) {}; + virtual void setAdtConfig(HADTRenderConfigDataHolder &adtConfig) {}; virtual void setMandatoryADTs(std::vector> &mandatoryADTs) {}; virtual void getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAreaId) {}; }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index c75cceba2..d91d5d834 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1232,11 +1232,16 @@ void Map::checkADTCulling(int i, int j, if ((i < 0) || (i > 64)) return; if ((j < 0) || (j > 64)) return; - int adt_global_x = worldCoordinateToGlobalAdtChunk(cameraPos.y); - int adt_global_y = worldCoordinateToGlobalAdtChunk(cameraPos.x); + if (this->m_adtConfigHolder != nullptr) { + float maxZ = m_adtConfigHolder->adtMaxZ[i][j]; + float minZ = m_adtConfigHolder->adtMinZ[i][j]; - if (this->m_adtBBHolder != nullptr) { - bool bbCheck = MathHelper::checkFrustum( frustumData, (*this->m_adtBBHolder)[i][j]); + CAaBox box = { + C3Vector({AdtIndexToWorldCoordinate(j + 1) , AdtIndexToWorldCoordinate(i + 1), minZ}), + C3Vector({AdtIndexToWorldCoordinate(j) , AdtIndexToWorldCoordinate(j), maxZ}) + }; + + bool bbCheck = MathHelper::checkFrustum( frustumData, box); if (!bbCheck) return; @@ -1251,8 +1256,6 @@ void Map::checkADTCulling(int i, int j, bool result = adtObject->checkFrustumCulling( *adtFrustRes.get(), cameraPos, - adt_global_x, - adt_global_y, frustumData, m2ObjectsCandidates, wmoCandidates); // if (this->m_adtBBHolder != nullptr) { diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 17144739e..c3db53f67 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -156,7 +156,7 @@ class Map : public IScene, public IMapApi { FreeStrategy adtFreeLambda; FreeStrategy zeroStateLambda; - HADTBoundingBoxHolder m_adtBBHolder = nullptr; + HADTRenderConfigDataHolder m_adtConfigHolder = nullptr; protected: explicit Map() { @@ -234,8 +234,8 @@ class Map : public IScene, public IMapApi { void resetAnimation() override { } - void setAdtBoundingBoxHolder(HADTBoundingBoxHolder &bbHolder) override { - m_adtBBHolder = bbHolder; + virtual void setAdtConfig(HADTRenderConfigDataHolder &adtConfig) override { + m_adtConfigHolder = adtConfig; } @@ -245,7 +245,7 @@ class Map : public IScene, public IMapApi { void update(HUpdateStage &updateStage); void updateBuffers(HUpdateStage &updateStage) override; void produceUpdateStage(HUpdateStage &updateStage) override; - void produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) override; + void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override; private: void checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 707282043..9edda338a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -625,36 +625,36 @@ const std::unordered_map +#include +#include #include #include struct RiverColorOverride { - int areaId = -1; + int liquidObjectId; mathfu::vec4 color = {0,0,0,0}; }; @@ -190,5 +192,41 @@ class Config { HRiverColorOverrideHolder colorOverrideHolder = nullptr; }; +//ADT STUFF FOR MAP GENERATION +typedef std::array AdtCell; + +struct AdtCellCompare +{ + bool operator()(const AdtCell &a, const AdtCell &b) const { + return a[0] == b[0] && a[1] == b[1]; + } +}; + +struct AdtCellHasher { + std::size_t operator()(const AdtCell &k) const { + using std::hash; + return hash{}(k[0]) ^ (hash{}(k[1]) << 16); + }; +}; + +struct ADTRenderConfigData { + ADTRenderConfigData() { + std::array defaultMaxZ = {}; + std::array defaultMinZ = {}; + defaultMaxZ.fill(-200000); + defaultMinZ.fill(200000); + + adtMaxZ.fill(defaultMaxZ); + adtMinZ.fill(defaultMinZ); + } + std::array, 64> adtMaxZ; + std::array, 64> adtMinZ; + std::unordered_set excludedADTs; + std::unordered_map, AdtCellHasher> excludedChunksPerADTs; +}; + +typedef std::shared_ptr HADTRenderConfigDataHolder; + + #endif //WOWVIEWERLIB_CONFIG_H From 4250ef4b03c834c5732186d9ca5c1f4133b61640 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Oct 2022 02:59:05 +0300 Subject: [PATCH 003/212] the app is compilable --- CMakeLists.txt | 2 +- src/minimapGenerator/entities.h | 8 +- src/minimapGenerator/minimapGenerator.cpp | 157 +++-- src/minimapGenerator/minimapGenerator.h | 1 + .../storage/CMinimapDataDB.cpp | 24 +- src/ui/FrontendUI.cpp | 524 +---------------- src/ui/FrontendUI.h | 19 +- .../MinimapGenerationWindow.cpp | 545 ++++++++++++++++++ .../MinimapGenerationWindow.h | 57 ++ wowViewerLib/src/engine/SceneScenario.cpp | 7 +- wowViewerLib/src/engine/SceneScenario.h | 9 +- .../src/engine/objects/scenes/NullScene.h | 2 +- .../src/engine/objects/scenes/map.cpp | 159 ++--- wowViewerLib/src/engine/objects/scenes/map.h | 2 +- 14 files changed, 842 insertions(+), 674 deletions(-) create mode 100644 src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp create mode 100644 src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0811c8ae..5012a1bc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,7 +225,7 @@ set(SOURCE_FILES src/database/product_db_parser/productDbParser.cpp src/database/product_db_parser/productDbParser.h src/database/buildInfoParser/buildInfoParser.cpp - src/database/buildInfoParser/buildInfoParser.h) + src/database/buildInfoParser/buildInfoParser.h src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h) diff --git a/src/minimapGenerator/entities.h b/src/minimapGenerator/entities.h index d387d13a4..77ac7f81e 100644 --- a/src/minimapGenerator/entities.h +++ b/src/minimapGenerator/entities.h @@ -33,11 +33,11 @@ enum class EMGMode { struct MapRenderDef { int id = -1; - int mapId; + int mapId = -1; - double deltaX; - double deltaY; - double deltaZ; + double deltaX = 0.0f; + double deltaY = 0.0f; + double deltaZ = 0.0f; HADTRenderConfigDataHolder adtConfigHolder = std::make_shared(); }; diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index f9fd01daf..b422ab9a1 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -123,29 +123,14 @@ void MinimapGenerator::startNextScenario() { setupScenarioData(); } - -void MinimapGenerator::setupScenarioData() { - m_zoom = currentScenario.zoom; - - for (auto &mapData : mapRuntimeInfo) { - mapData.mandatoryADTMap.resize(0); - } - - stackOfCullStages = {nullptr, nullptr, nullptr, nullptr}; - - if (currentScenario.orientation == ScenarioOrientation::soTopDownOrtho) { - m_apiContainer->camera = std::make_shared(); - } else { - m_apiContainer->camera = std::make_shared(); - } - +bool MinimapGenerator::loadMaps() { for ( int i = 0; i < currentScenario.maps.size(); i++) { auto &mapDef = currentScenario.maps[i]; MapRecord mapRecord; if (!m_apiContainer->databaseHandler->getMapById(mapDef.mapId, mapRecord)) { std::cout << "Couldnt get data for mapId " << mapDef.mapId << std::endl; startNextScenario(); - return; + return false; } auto &mapRuntime = mapRuntimeInfo.emplace_back(); @@ -156,20 +141,11 @@ void MinimapGenerator::setupScenarioData() { mapRuntime.scene->setAdtConfig(mapDef.adtConfigHolder); } } - - auto config = m_apiContainer->getConfig(); - config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; - config->closeRiverColor = {0.345206976, 0.329288304, 0.270450264, 0}; - setMinMaxXYWidthHeight(currentScenario.minWowWorldCoord, currentScenario.maxWowWorldCoord); - m_x = 0; - //To make AABB work for sure! - m_y = m_chunkHeight - 1; - - m_width = currentScenario.imageWidth; - m_height = currentScenario.imageHeight; - + for (auto &mapData : mapRuntimeInfo) { + mapData.mandatoryADTMap.resize(0); + } //Assign mandatory adt for every cell on the screen if (m_mgMode == EMGMode::eScreenshotGeneration ) { //currentScenario.boundingBoxHolder @@ -206,24 +182,24 @@ void MinimapGenerator::setupScenarioData() { } mathfu::mat4 viewProj = genTempProjectMatrix(); - for (int i = 0; i < corners.size(); i++) { - corners[i] = viewProj * corners[i]; - corners[i] = corners[i] * (1.0f / corners[i].w); + for (auto & corner : corners) { + corner = viewProj * corner; + corner = corner * (1.0f / corner.w); } std::array minMaxScreenX = {20000, -20000}; std::array minMaxScreenY = {20000, -20000}; std::array minMaxScreenZ = {20000, -20000}; - for (int i = 0; i < corners.size(); i++) { - minMaxScreenX[0] = std::min(corners[i].x, minMaxScreenX[0]); - minMaxScreenX[1] = std::max(corners[i].x, minMaxScreenX[1]); + for (auto & corner : corners) { + minMaxScreenX[0] = std::min(corner.x, minMaxScreenX[0]); + minMaxScreenX[1] = std::max(corner.x, minMaxScreenX[1]); - minMaxScreenY[0] = std::min(corners[i].y, minMaxScreenY[0]); - minMaxScreenY[1] = std::max(corners[i].y, minMaxScreenY[1]); + minMaxScreenY[0] = std::min(corner.y, minMaxScreenY[0]); + minMaxScreenY[1] = std::max(corner.y, minMaxScreenY[1]); - minMaxScreenZ[0] = std::min(corners[i].z, minMaxScreenZ[0]); - minMaxScreenZ[1] = std::max(corners[i].z, minMaxScreenZ[1]); + minMaxScreenZ[0] = std::min(corner.z, minMaxScreenZ[0]); + minMaxScreenZ[1] = std::max(corner.z, minMaxScreenZ[1]); } //Add adt to all occupied cells @@ -232,13 +208,13 @@ void MinimapGenerator::setupScenarioData() { for (int j = std::floor(minMaxScreenY[0]); j < std::ceil((minMaxScreenY[1] - minMaxScreenY[0]) / 2.0f); j++) { if (i < m_chunkStartX) - return; + continue; if (j < m_chunkStartY) - return; + continue; if (i > m_chunkStartX + m_chunkWidth) - return; + continue; if (i > m_chunkStartY + m_chunkHeight) - return; + continue; std::array adtCoord = {static_cast(adt_x), static_cast(adt_y)}; @@ -250,6 +226,35 @@ void MinimapGenerator::setupScenarioData() { } } + return true; +} + +void MinimapGenerator::setupScenarioData() { + m_zoom = currentScenario.zoom; + + stackOfCullStages = {nullptr, nullptr, nullptr, nullptr}; + + auto config = m_apiContainer->getConfig(); + config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; + config->closeRiverColor = {0.345206976, 0.329288304, 0.270450264, 0}; + + + m_width = currentScenario.imageWidth; + m_height = currentScenario.imageHeight; + + if (currentScenario.orientation == ScenarioOrientation::soTopDownOrtho) { + m_apiContainer->camera = std::make_shared(); + } else { + m_apiContainer->camera = std::make_shared(); + } + + if (!loadMaps()) + return; + + m_x = 0; + //To make AABB work for sure! + m_y = m_chunkHeight - 1; + prepearCandidate = false; setupCameraData(); } @@ -284,12 +289,9 @@ MinimapGenerator::setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, c if (adtMinZ > adtMaxZ) continue; - adtMinZ += mapDef.deltaZ; - adtMaxZ += mapDef.deltaZ; - - std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1), AdtIndexToWorldCoordinate(adt_x + 1)}; - std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y), AdtIndexToWorldCoordinate(adt_x)}; - std::array minMaxZ = {adtMinZ, adtMaxZ}; + std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1) + mapDef.deltaX, AdtIndexToWorldCoordinate(adt_x + 1) + mapDef.deltaX}; + std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y) + mapDef.deltaY, AdtIndexToWorldCoordinate(adt_x) + mapDef.deltaY}; + std::array minMaxZ = {adtMinZ + mapDef.deltaZ, adtMaxZ + mapDef.deltaZ}; std::vector corners; for (int i = 0; i < 2; i++) @@ -540,7 +542,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; - if (objBB.max.z > 2000) { + if (objBB.max.x > 17000) { continue; } @@ -561,7 +563,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; - if (objBB.max.z > 2000) { + if (objBB.max.x > 17000) { continue; } @@ -592,7 +594,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor auto objBB = adtObj->calcAABB(); - if (objBB.max.z > 2000) { + if (objBB.max.x > 17000) { continue; } @@ -675,24 +677,31 @@ void MinimapGenerator::process() { mathfu::vec3_packed(mathfu::vec3(maxAdt.x, maxAdt.y, 0)) }; - this->calcBB(lastFrameCull, minCoord, maxCoord, adtBox2d, adt_x, adt_y, m_mgMode == EMGMode::eBoundingBoxCalculation); - float zFar = (minCoord - maxCoord).Length(); - float maxZ = maxCoord.z; - float minZ = minCoord.z; - - if (!lastFrameCull->m2Array.getDrawn().empty() || !lastFrameCull->adtArray.empty() || - !lastFrameCull->wmoGroupArray.getToDraw().empty()) { - if (minCoord.x < 20000 && maxCoord.x > -20000) { - if (zFar > m_zFar || maxZ > m_maxZ || minZ < m_minZ) { - m_zFar = std::max(zFar, m_zFar); - m_maxZ = std::max(maxZ, m_maxZ); - m_minZ = std::min(minZ, m_minZ); - resetCandidate(); - setupCameraData(); - return; + bool needRestart = false; + for (auto &cullStage: lastFrameCull) { + this->calcBB(cullStage, minCoord, maxCoord, adtBox2d, adt_x, adt_y, + m_mgMode == EMGMode::eBoundingBoxCalculation); + float zFar = (minCoord - maxCoord).Length(); + float maxZ = maxCoord.z + cullStage->deltaZ; + float minZ = minCoord.z + cullStage->deltaZ; + + if (!cullStage->m2Array.getDrawn().empty() || !cullStage->adtArray.empty() || + !cullStage->wmoGroupArray.getToDraw().empty()) { + if (minCoord.x < 20000 && maxCoord.x > -20000) { + if (zFar > m_zFar || maxZ > m_maxZ || minZ < m_minZ) { + m_zFar = std::max(zFar, m_zFar); + m_maxZ = std::max(maxZ, m_maxZ); + m_minZ = std::min(minZ, m_minZ); + needRestart = true; + } } } } + if (needRestart) { + resetCandidate(); + setupCameraData(); + return; + } } //Conditional mode stuff @@ -883,19 +892,7 @@ Config *MinimapGenerator::getConfig() { } void MinimapGenerator::reload() { - m_currentScene = nullptr; - - MapRecord mapRecord; - if (!m_apiContainer->databaseHandler->getMapById(currentScenario.mapId, mapRecord)) { - std::cout << "Couldnt get data for mapId " << currentScenario.mapId << std::endl; - startNextScenario(); - return; - } - - m_currentScene = std::make_shared(m_apiContainer, mapRecord.ID, mapRecord.WdtFileID); - if (m_mgMode == EMGMode::eScreenshotGeneration) { - m_currentScene->setAdtBoundingBoxHolder(m_boundingBoxHolder); - } + loadMaps(); } void MinimapGenerator::getCurrentFDData(int &areaId, int &parentAreaId, mathfu::vec4 &riverColor) { diff --git a/src/minimapGenerator/minimapGenerator.h b/src/minimapGenerator/minimapGenerator.h index 633edf24c..9e6cab74d 100644 --- a/src/minimapGenerator/minimapGenerator.h +++ b/src/minimapGenerator/minimapGenerator.h @@ -65,6 +65,7 @@ class MinimapGenerator { mathfu::mat4 getOrthoMatrix(); mathfu::vec3 getLookAtVec3(); void startNextScenario(); + bool loadMaps(); void resetCandidate(); void calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoord, diff --git a/src/minimapGenerator/storage/CMinimapDataDB.cpp b/src/minimapGenerator/storage/CMinimapDataDB.cpp index 0a34a8bb8..d1acd771a 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.cpp +++ b/src/minimapGenerator/storage/CMinimapDataDB.cpp @@ -120,7 +120,7 @@ const std::string insertAdtExcludedSQL = R"===( insert into scenario_map_def_excluded_adt(map_definition_id, adt_x, adt_y, - min_z, max_z) + chunk_x, chunk_y) values (?, ?, ?, ?, ?) )==="; @@ -284,7 +284,6 @@ void CMinimapDataDB::getAdtExcluded(MapRenderDef& mapRenderDef) { AdtCell adtCell = {adt_x, adt_y}; AdtCell chunkCell = {chunk_x, chunk_y}; if (chunk_x == -1 || chunk_y == -1) {\ - mapRenderDef.adtConfigHolder->excludedADTs.insert(adtCell); } else { mapRenderDef.adtConfigHolder->excludedChunksPerADTs[adtCell].insert(chunkCell); @@ -292,7 +291,28 @@ void CMinimapDataDB::getAdtExcluded(MapRenderDef& mapRenderDef) { } } void CMinimapDataDB::saveAdtExcluded(MapRenderDef& mapRenderDef){ + SQLite::Transaction transaction(m_sqliteDatabase); + + //1. Clear all records for that mapId from DB + { + SQLite::Statement cleanABB(m_sqliteDatabase, + "delete from adt_bounding_boxes where map_id = ?" + ); + cleanABB.exec(); + } + + //2. Insert into database + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + insertADTBoundingBoxes.setInputs(mapRenderDef.mapId, i, j, + mapRenderDef.adtConfigHolder->adtMinZ[i][j], + mapRenderDef.adtConfigHolder->adtMaxZ[i][j]); + insertADTBoundingBoxes.execute(); + } + } + //3. Commit transaction + transaction.commit(); } void CMinimapDataDB::getRiverColorOverrides(int mapId, std::vector &riverOverrides) { diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index ef19c3a4d..f62ba6b76 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -355,6 +355,7 @@ void FrontendUI::showMapSelectionDialog() { } //The table ImGui::BeginChild("Map Select Dialog Left panel"); + ImGui::Columns(5, "mycolumns"); // 5-ways, with border ImGui::Separator(); ImGui::Text("ID"); @@ -368,6 +369,7 @@ void FrontendUI::showMapSelectionDialog() { ImGui::Text("MapType"); ImGui::NextColumn(); ImGui::Separator(); + static int selected = -1; for (int i = 0; i < filteredMapList.size(); i++) { auto mapRec = filteredMapList[i]; @@ -1288,7 +1290,7 @@ void FrontendUI::showSettingsDialog() { //#define logExecution { \ // std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ //} -void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) { +void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) { auto m_device = m_api->hDevice; logExecution @@ -1458,7 +1460,7 @@ void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &upd } //1. Collect buffers - auto &bufferChunks = updateStage->uniformBufferChunks; + auto &bufferChunks = updateStages[0]->uniformBufferChunks; int renderIndex = 0; for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { for (int i = 0; i < 5; i++ ) { @@ -1566,7 +1568,7 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int height, double deltaTime, bool isScreenshot, bool produceDoubleCamera, bool swapDebugCamera, - ApiContainer &apiContainer, const std::shared_ptr ¤tScene, HCullStage &cullStage) { + ApiContainer &apiContainer, std::shared_ptr ¤tScene, HCullStage &cullStage) { static const mathfu::mat4 vulkanMatrixFix2 = mathfu::mat4(1, 0, 0, 0, @@ -1627,10 +1629,13 @@ HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int hei cullStage = sceneScenario->addCullStage(cameraMatricesCulling, currentScene); auto updateStage = sceneScenario->addUpdateStage(cullStage, deltaTime*(1000.0f), cameraMatricesUpdate); + std::vector updateStages = {updateStage}; + std::vector drawStageDependencies = {}; if (produceDoubleCamera) { std::vector drawStageDependencies__ = {}; - HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStage, currentScene, cameraMatricesRenderingDebug, drawStageDependencies__, + + HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRenderingDebug, drawStageDependencies__, true, dimensions, true, isInfZSupported, clearColor, fb); @@ -1645,7 +1650,7 @@ HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int hei dimensions = {{newX, newY}, {newWidth, newHeight}}; } - HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStage, currentScene, cameraMatricesRendering, drawStageDependencies, + HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRendering, drawStageDependencies, true, dimensions, true, isInfZSupported, clearColor, fb); @@ -1658,8 +1663,8 @@ HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int hei } HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, double deltaTime) { - if (minimapGenerator != nullptr && minimapGenerator->getCurrentMode() != EMGMode::eNone) { - minimapGenerator->process(); + if (m_minimapGenerationWindow != nullptr) { + m_minimapGenerationWindow->process(); } if (dataExporter != nullptr) { @@ -1697,8 +1702,11 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do } needToMakeScreenshot = false; } - if (minimapGenerator != nullptr && minimapGenerator->getCurrentMode() != EMGMode::eNone) { - uiDependecies.push_back(minimapGenerator->createSceneDrawStage(sceneScenario)); + if (m_minimapGenerationWindow != nullptr) { + auto drawStage = m_minimapGenerationWindow->getDrawStage(sceneScenario); + if (drawStage != nullptr) { + uiDependecies.push_back(drawStage); + } } //DrawStage for current frame @@ -1732,7 +1740,8 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); - HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(uiUpdateStage, getShared(), nullptr, uiDependecies, + std::vector updateStages = {uiUpdateStage}; + HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, true, dimension, clearOnUi, false, clearColor, nullptr); } @@ -1894,498 +1903,17 @@ void FrontendUI::createDefaultprocessor() { overrideCascOpened(true); } -auto FrontendUI::createMinimapGenerator() { - boundingBoxHolder = std::make_shared(); - riverColorOverrides = std::make_shared(); - - if (sceneDef != nullptr) { - m_minimapDB->getAdtBoundingBoxes(sceneDef->mapId, *boundingBoxHolder); - m_minimapDB->getRiverColorOverrides(sceneDef->mapId, *riverColorOverrides); - } - - minimapGenerator = std::make_shared( - m_api->cacheStorage, - m_api->hDevice, - m_processor, - m_api->databaseHandler, - boundingBoxHolder - ); - - minimapGenerator->getConfig()->colorOverrideHolder = riverColorOverrides; - - minimapGenerator->setZoom(previewZoom); - minimapGenerator->setLookAtPoint(previewX, previewY); - - -// sceneDef = { -// EMGMode::eScreenshotGeneration, -// 0, -// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -// mathfu::vec2(0, 0), -// mathfu::vec2(MathHelper::TILESIZE*2, MathHelper::TILESIZE*2), -// 1024, -// 1024, -// 1.0f, -// false, -// ScenarioOrientation::so45DegreeTick3, -// "azeroth/topDown1" -// }; - - sceneDefList = { - { - -1, - 530, - "Netherstorm", - mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), - mathfu::vec2(1627, -1175), - mathfu::vec2(6654 , 4689 ), - 1024, - 1024, - 1.0f, - ScenarioOrientation::so45DegreeTick0, - "outland/netherstorm" - }, - { - -1, - 1, - "Kalimdor, rot 0", - mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), - mathfu::vec2(-12182, -8803 ), - mathfu::vec2(12058, 4291), - 1024, - 1024, - 1.0f, - ScenarioOrientation::so45DegreeTick0, - "kalimdor/rotation0" - } - }; - - return minimapGenerator; - -// std::vector scenarios = { -//// { -//// 2222, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-9750, -8001 ), -//// mathfu::vec2(8333, 9500 ), -//// ScenarioOrientation::so45DegreeTick0, -//// "shadowlands/orient0" -//// } -// { -// 1643, -// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -// mathfu::vec2(291 , 647 ), -// mathfu::vec2(2550, 2895), -// 256, -// 256, -// 4.0f, -// ScenarioOrientation::so45DegreeTick0, -// "kultiras/orient0" -// }, -//// { -//// 530, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-5817, -1175), -//// mathfu::vec2(1758, 10491), -//// ScenarioOrientation::so45DegreeTick0, -//// "outland/topDown1" -//// } -//// { -//// 0, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-9081, -20), -//// mathfu::vec2(-8507, 1296), -//// ScenarioOrientation::soTopDownOrtho, -//// "azeroth/topDown" -//// } -//// }; -// -//// std::vector scenarios = { -//// { -//// 1, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-12182, -8803 ), -//// mathfu::vec2(12058, 4291), -//// ScenarioOrientation::so45DegreeTick0, -//// "kalimdor/rotation0" -//// }, -// { -// 1, -// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -// mathfu::vec2(-12182, -8803), -// mathfu::vec2(12058, 4291), -// 256, -// 256, -// 4.0f, -// ScenarioOrientation::so45DegreeTick1, -// "kalimdor/rotation1_new" -// } -// }; -//// { -//// 1, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-12182, -8803 ), -//// mathfu::vec2(12058, 4291), -//// ScenarioOrientation::so45DegreeTick2, -//// "kalimdor/rotation2" -//// }, -//// { -//// 1, -//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), -//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), -//// mathfu::vec2(-12182, -8803 ), -//// mathfu::vec2(12058, 4291), -//// ScenarioOrientation::so45DegreeTick3, -//// "kalimdor/rotation3" -//// }, -//// }; -} - -void FrontendUI::editComponentsForConfig(Config * config) { - if (config == nullptr) return; - - ImGui::BeginGroupPanel("Exterior Lighting"); - - { - ImGui::CompactColorPicker("Exterior Ambient", config->exteriorAmbientColor); - ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorHorizontAmbientColor); - ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorGroundAmbientColor); - ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorDirectColor); - } - - ImGui::EndGroupPanel(); -} - -void FrontendUI::restartMinimapGenPreview() { - minimapGenerator->stopPreview(); - minimapGenerator->startPreview(*sceneDef); - minimapGenerator->setZoom(previewZoom); - minimapGenerator->setLookAtPoint(previewX, previewY); -} - void FrontendUI::showMinimapGenerationSettingsDialog() { if(showMinimapGeneratorSettings) { - if (m_minimapDB == nullptr) { - m_minimapDB = std::make_shared("minimapdb.sqlite"); - m_minimapDB->getScenarios(sceneDefList); - } - if (minimapGenerator == nullptr) { - createMinimapGenerator(); - } - - - ImGui::Begin("Minimap Generator settings", &showMinimapGeneratorSettings); - ImGui::Columns(2, NULL, true); - //Left panel - ImGui::BeginTabBar("MinimapGenTabs"); - { - bool listOpened = this->sceneDef == nullptr; - bool staticAlwaysTrue = true; - if (ImGui::BeginTabItem("List")) - { - //The table - ImGui::BeginChild("Scenario List"); - ImGui::Columns(3, "scenarioListcolumns"); // 3-ways, with border - ImGui::Separator(); - ImGui::Text(""); - ImGui::NextColumn(); - ImGui::Text("Name"); - ImGui::NextColumn(); - ImGui::Text("Actions"); - ImGui::NextColumn(); - ImGui::Separator(); - - for (int i = 0; i < this->sceneDefList.size(); i++) { - auto &l_sceneDef = sceneDefList[i]; - bool checked = true; - ImGui::Checkbox("", &checked); - ImGui::NextColumn(); - ImGui::Text("%s", l_sceneDef.name.c_str()); - ImGui::NextColumn(); - if (ImGui::Button(("Edit##" + std::to_string(i)).c_str())) { - this->sceneDef = &l_sceneDef; - editTabOpened = true; - createMinimapGenerator(); - } - ImGui::NextColumn(); - } - ImGui::Columns(1); - ImGui::Separator(); - ImGui::EndChild(); - - ImGui::EndTabItem(); - } - - if (sceneDef != nullptr) { - if (editTabOpened && ImGui::BeginTabItem("Edit", &editTabOpened, ImGuiTabItemFlags_SetSelected)) { - { - ImGui::InputInt("Map Id", &sceneDef->mapId); - auto scenarioName = std::array(); - if (sceneDef->name.size() > 128) sceneDef->name.resize(128); - std::copy(sceneDef->name.begin(), sceneDef->name.end(), scenarioName.data()); - if (ImGui::InputText("Scenario name", scenarioName.data(), 128)) { - sceneDef->name = std::string(std::begin(scenarioName), std::end(scenarioName)); - } - ImGui::BeginGroupPanel("Orientation"); - { - if (ImGui::RadioButton("Ortho projection", &sceneDef->orientation, ScenarioOrientation::soTopDownOrtho)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - restartMinimapGenPreview(); - } - } - if (ImGui::RadioButton("At 45° tick 0", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick0)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - restartMinimapGenPreview(); - } - } - if (ImGui::RadioButton("At 45° tick 1", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick1)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - restartMinimapGenPreview(); - } - } - if (ImGui::RadioButton("At 45° tick 2", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick2)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - restartMinimapGenPreview(); - } - } - if (ImGui::RadioButton("At 45° tick 3", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick3)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - restartMinimapGenPreview(); - } - } - } - ImGui::EndGroupPanel(); - ImGui::SameLine(); - ImGui::BeginGroupPanel("Generation boundaries"); - { - ImGui::Text("In world coordinates"); - ImGui::InputFloat("Min x", &sceneDef->minWowWorldCoord.x); - ImGui::InputFloat("Min y", &sceneDef->minWowWorldCoord.y); - ImGui::InputFloat("Max x", &sceneDef->maxWowWorldCoord.x); - ImGui::InputFloat("Max y", &sceneDef->maxWowWorldCoord.y); - ImGui::EndGroupPanel(); - } - ImGui::BeginGroupPanel("Ocean color override"); - { - ImGui::CompactColorPicker("Close Ocean Color", sceneDef->closeOceanColor); - ImGui::EndGroupPanel(); - } - ImGui::BeginGroupPanel("Image settings"); - { - ImGui::PushItemWidth(100); - ImGui::InputInt("Image Width", &sceneDef->imageWidth); - ImGui::InputInt("Image Height", &sceneDef->imageHeight); - ImGui::PopItemWidth(); - ImGui::EndGroupPanel(); - } - - - - ImGui::BeginGroupPanel("Global map settings"); - { - ImGui::BeginGroupPanel("River color overrides"); - { - for (int i = 0; i < riverColorOverrides->size(); i++) { - auto &riverColorOverride = riverColorOverrides->operator[](i); - - ImGui::PushID(i); - if (ImGui::Button("Copy from current")) { - int areaId, parentAreaId; - mathfu::vec4 riverColor; - - minimapGenerator->getCurrentFDData(areaId, parentAreaId, riverColor); - riverColorOverride.areaId = areaId; - riverColorOverride.color = riverColor; - } - ImGui::SameLine(); - ImGui::CompactColorPicker("River Color Override", riverColorOverride.color); - ImGui::SameLine(); - ImGui::PushItemWidth(100); - ImGui::InputInt("Area Id", &riverColorOverride.areaId); - ImGui::PopItemWidth(); + if (m_minimapGenerationWindow == nullptr) + m_minimapGenerationWindow = std::make_shared(m_api, + m_processor, + showMinimapGeneratorSettings); - - ImGui::PopID(); - } - - if (ImGui::Button("Add override")) { - riverColorOverrides->push_back({}); - } - } - ImGui::EndGroupPanel(); - } - ImGui::EndGroupPanel(); - - ImGui::BeginGroupPanel("Current stats"); - { - int areaId, parentAreaId; - mathfu::vec4 riverColor; - - minimapGenerator->getCurrentFDData(areaId, parentAreaId, riverColor); - ImGui::Text("Current areaId %d", areaId); - ImGui::Text("Current parent areaId %d", parentAreaId); - ImGui::CompactColorPicker("Current River Color", riverColor); - - ImGui::EndGroupPanel(); - } - - auto currentTime = minimapGenerator->getConfig()->currentTime; - ImGui::Text("Time: %02d:%02d", (int)(currentTime/120), (int)((currentTime/2) % 60)); - if (ImGui::SliderInt("Current time", ¤tTime, 0, 2880)) { - minimapGenerator->getConfig()->currentTime = currentTime; - } - - editComponentsForConfig(minimapGenerator->getConfig()); - - if (minimapGenerator->getCurrentMode() != EMGMode::eScreenshotGeneration) { - bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; - if (ImGui::ButtonDisablable("Start Screenshot Gen", isDisabled)) { - std::vector list = {*sceneDef}; - - minimapGenerator->startScenarios(list); - } - } else { - if (ImGui::Button("Stop Screenshot Gen")) { - minimapGenerator->stopPreview(); - } - } - ImGui::SameLine(); - if (minimapGenerator->getCurrentMode() != EMGMode::ePreview) { - bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; - if (ImGui::ButtonDisablable("Start Preview", isDisabled)) { - minimapGenerator->startPreview(*sceneDef); - minimapGenerator->setZoom(previewZoom); - minimapGenerator->setLookAtPoint(previewX, previewY); - } - } else { - if (ImGui::Button("Stop Preview")) { - minimapGenerator->stopPreview(); - } - } - ImGui::SameLine(); - if (minimapGenerator->getCurrentMode() != EMGMode::eBoundingBoxCalculation) { - bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; - if (ImGui::ButtonDisablable("Start BBox calc", isDisabled)) { - minimapGenerator->startBoundingBoxCalc(*sceneDef); - } - } else { - if (ImGui::Button("Stop BBox calc")) { - minimapGenerator->stopBoundingBoxCalc(); - } - } - - if (minimapGenerator->getCurrentMode() != EMGMode::eNone && minimapGenerator->getCurrentMode() != EMGMode::ePreview) { - int x, y, maxX, maxY; - minimapGenerator->getCurrentTileCoordinates(x, y, maxX, maxY); - - ImGui::Text("X: % 03d out of % 03d", x, maxX); - ImGui::Text("Y: % 03d out of % 03d", y, maxY); - - } - - if (ImGui::Button("Save")) { - m_minimapDB->saveScenario(*sceneDef); - m_minimapDB->saveRiverColorOverrides(sceneDef->mapId, *riverColorOverrides); - m_minimapDB->saveAdtBoundingBoxes(sceneDef->mapId, *boundingBoxHolder); - } - } - - ImGui::EndTabItem(); - - } else { - //sceneDef = nullptr; - } - } - - - ImGui::EndTabBar(); - } - - //Right panel - ImGui::NextColumn(); - { - ImGui::BeginChild("Minimap Gen Preview", ImVec2(0, 0)); - { - bool changed = false; - bool readOnly = minimapGenerator->getCurrentMode() != EMGMode::ePreview; - - const char * fmt = "%.3f"; - changed |= ImGui::InputFloat("x", &previewX, 0.0f, 0.0f, fmt, readOnly ? ImGuiInputTextFlags_::ImGuiInputTextFlags_ReadOnly: 0); - changed |= ImGui::InputFloat("y", &previewY, 0.0f, 0.0f, fmt, readOnly ? ImGuiInputTextFlags_::ImGuiInputTextFlags_ReadOnly: 0); - - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - minimapGenerator->setLookAtPoint(previewX, previewY); - } - if (ImGui::SliderFloat("Zoom", &previewZoom, 0.1, 10)) { - if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { - minimapGenerator->setZoom(previewZoom); - } - } - if (ImGui::Button("Reload")) { - minimapGenerator->reload(); - } - - ImGui::BeginChild("Minimap Gen Preview image", ImVec2(0, 0), - true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | - ImGuiWindowFlags_AlwaysVerticalScrollbar); - - auto drawStage = minimapGenerator->getLastDrawStage(); - if (drawStage != nullptr) { - auto texture = drawStage->target->getAttachment(0); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,1.0)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0,0,0,1.0)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0,0,0,1.0)); - - const int imageSize = 512; - - if (ImGui::ImageButton2(texture, "previewImage", - ImVec2(imageSize, imageSize), - ImVec2(0,1), - ImVec2(1,0))) - { - auto mousePos = ImGui::GetMousePos(); - ImGuiStyle &style = ImGui::GetStyle(); - - mousePos.x += -ImGui::GetWindowPos().x - style.WindowPadding.x; - mousePos.y += -ImGui::GetWindowPos().y - style.WindowPadding.y; - - - previewX = ((0.5f - (mousePos.y / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewX; - previewY = ((0.5f - (mousePos.x / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewY; - - - - minimapGenerator->setLookAtPoint(previewX, previewY); - }; - - ImGui::PopStyleColor(3); - ImGui::PopStyleVar(3); - } - - ImGui::EndChild(); - - } - ImGui::EndChild(); - - - } - ImGui::Columns(1); - - ImGui::End(); + m_minimapGenerationWindow->render(); } else { - if (minimapGenerator != nullptr && minimapGenerator->getCurrentMode() == EMGMode::eNone) { - minimapGenerator = nullptr; + if (m_minimapGenerationWindow != nullptr) { + m_minimapGenerationWindow = nullptr; } } } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index e257cd7fd..2629cf55b 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -21,6 +21,7 @@ #include "../minimapGenerator/storage/CMinimapDataDB.h" #include "../exporters/dataExporter/DataExporterClass.h" #include "childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h" +#include "childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -38,6 +39,8 @@ class FrontendUI : public IScene, public std::enable_shared_from_thisimguiContext); }; std::shared_ptr getShared() @@ -54,7 +57,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &meshIds) override {}; - void produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) override; + void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override; void produceUpdateStage(HUpdateStage &updateStage) override; void checkCulling(HCullStage &cullStage) override {}; @@ -90,21 +93,8 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_cullstages = {}; - std::shared_ptr m_minimapDB; - - HMinimapGenerator minimapGenerator; - HADTBoundingBoxHolder boundingBoxHolder; - std::vector sceneDefList; - HRiverColorOverrideHolder riverColorOverrides; - ScenarioDef *sceneDef = nullptr; - bool editTabOpened; - float previewX = 0; - float previewY = 0; - float previewZoom = 1; - float uiScale = 1; - std::shared_ptr currentScene = nullptr; bool tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef); @@ -223,6 +213,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_mapConstructionWindow = nullptr; + std::shared_ptr m_minimapGenerationWindow = nullptr; //Test export diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp new file mode 100644 index 000000000..7ac721af9 --- /dev/null +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -0,0 +1,545 @@ +// +// Created by Deamon on 10/29/2022. +// + +#include "MinimapGenerationWindow.h" +#include "imgui.h" +#include "imageButton2/imageButton2.h" +#include "groupPanel/groupPanel.h" +#include "compactColorPicker/compactColorPicker.h" +#include "disablableButton/disablableButton.h" + +void MinimapGenerationWindow::restartMinimapGenPreview() { + minimapGenerator->stopPreview(); + minimapGenerator->startPreview(*sceneDef); + minimapGenerator->setZoom(previewZoom); + minimapGenerator->setLookAtPoint(previewX, previewY); +} + +void MinimapGenerationWindow::render() { + ImGui::Begin("Minimap Generator settings", &m_showMinimapGeneratorSettings); + ImGui::Columns(2, NULL, true); + //Left panel + ImGui::BeginTabBar("MinimapGenTabs"); + { + renderListTab(); + if (sceneDef != nullptr) { + if (editTabOpened) { + renderEditTab(); + } else { + //sceneDef = nullptr; + } + } + + ImGui::EndTabBar(); + } + + //Right panel + ImGui::NextColumn(); + { + ImGui::BeginChild("Minimap Gen Preview", ImVec2(0, 0)); + { + bool changed = false; + bool readOnly = minimapGenerator->getCurrentMode() != EMGMode::ePreview; + + const char * fmt = "%.3f"; + changed |= ImGui::InputFloat("x", &previewX, 0.0f, 0.0f, fmt, readOnly ? ImGuiInputTextFlags_::ImGuiInputTextFlags_ReadOnly: 0); + changed |= ImGui::InputFloat("y", &previewY, 0.0f, 0.0f, fmt, readOnly ? ImGuiInputTextFlags_::ImGuiInputTextFlags_ReadOnly: 0); + + if (changed && minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + minimapGenerator->setLookAtPoint(previewX, previewY); + } + if (ImGui::SliderFloat("Zoom", &previewZoom, 0.1, 10)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + minimapGenerator->setZoom(previewZoom); + } + } + if (ImGui::Button("Reload")) { + minimapGenerator->reload(); + } + + ImGui::BeginChild("Minimap Gen Preview image", ImVec2(0, 0), + true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | + ImGuiWindowFlags_AlwaysVerticalScrollbar); + + auto drawStage = minimapGenerator->getLastDrawStage(); + if (drawStage != nullptr) { + auto texture = drawStage->target->getAttachment(0); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,1.0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0,0,0,1.0)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0,0,0,1.0)); + + const int imageSize = 512; + + if (ImGui::ImageButton2(texture, "previewImage", + ImVec2(imageSize, imageSize), + ImVec2(0,1), + ImVec2(1,0))) + { + auto mousePos = ImGui::GetMousePos(); + ImGuiStyle &style = ImGui::GetStyle(); + + mousePos.x += -ImGui::GetWindowPos().x - style.WindowPadding.x; + mousePos.y += -ImGui::GetWindowPos().y - style.WindowPadding.y; + + + previewX = ((0.5f - (mousePos.y / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewX; + previewY = ((0.5f - (mousePos.x / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewY; + + + + minimapGenerator->setLookAtPoint(previewX, previewY); + }; + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(3); + } + + ImGui::EndChild(); + + } + ImGui::EndChild(); + + + } + ImGui::Columns(1); + + ImGui::End(); +} + +void MinimapGenerationWindow::renderMapConfigSubWindow(int mapIndex) { + auto &mapRenderDef = sceneDef->maps[mapIndex]; + ImGui::BeginGroupPanel(("Map##" + std::to_string(mapIndex)).c_str()); + + ImGui::InputInt(("Map Id##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.mapId); + ImGui::InputDouble(("Delta X##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaX); + ImGui::InputDouble(("Delta Y##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaY); + ImGui::InputDouble(("Delta Z##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaZ); + + ImGui::PushStyleColor(ImGuiCol_Button, 0x0000FF); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0x0000FF); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0x0000FF); + if (ImGui::Button("Delete")) { + sceneDef->maps.erase(std::next(sceneDef->maps.begin(), mapIndex-1)); + } + ImGui::PopStyleColor(ImGuiCol_Button); + ImGui::PopStyleColor(ImGuiCol_ButtonActive); + ImGui::PopStyleColor(ImGuiCol_ButtonActive); + + ImGui::EndGroupPanel(); +} + +void MinimapGenerationWindow::editComponentsForConfig(Config * config) { + if (config == nullptr) return; + + ImGui::BeginGroupPanel("Exterior Lighting"); + + { + ImGui::CompactColorPicker("Exterior Ambient", config->exteriorAmbientColor); + ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorHorizontAmbientColor); + ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorGroundAmbientColor); + ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorDirectColor); + } + + ImGui::EndGroupPanel(); +} + +void MinimapGenerationWindow::createMinimapGenerator() { + riverColorOverrides = std::make_shared(); + + minimapGenerator = std::make_shared( + m_api->cacheStorage, + m_api->hDevice, + m_processor, + m_api->databaseHandler + ); + + minimapGenerator->getConfig()->colorOverrideHolder = riverColorOverrides; + + minimapGenerator->setZoom(previewZoom); + minimapGenerator->setLookAtPoint(previewX, previewY); + + +// sceneDef = { +// EMGMode::eScreenshotGeneration, +// 0, +// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +// mathfu::vec2(0, 0), +// mathfu::vec2(MathHelper::TILESIZE*2, MathHelper::TILESIZE*2), +// 1024, +// 1024, +// 1.0f, +// false, +// ScenarioOrientation::so45DegreeTick3, +// "azeroth/topDown1" +// }; + +// sceneDefList = { +// { +// -1, +// 530, +// "Netherstorm", +// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +// mathfu::vec2(1627, -1175), +// mathfu::vec2(6654 , 4689 ), +// 1024, +// 1024, +// 1.0f, +// ScenarioOrientation::so45DegreeTick0, +// "outland/netherstorm" +// }, +// { +// -1, +// 1, +// "Kalimdor, rot 0", +// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +// mathfu::vec2(-12182, -8803 ), +// mathfu::vec2(12058, 4291), +// 1024, +// 1024, +// 1.0f, +// ScenarioOrientation::so45DegreeTick0, +// "kalimdor/rotation0" +// } +// }; + +// std::vector scenarios = { +//// { +//// 2222, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-9750, -8001 ), +//// mathfu::vec2(8333, 9500 ), +//// ScenarioOrientation::so45DegreeTick0, +//// "shadowlands/orient0" +//// } +// { +// 1643, +// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +// mathfu::vec2(291 , 647 ), +// mathfu::vec2(2550, 2895), +// 256, +// 256, +// 4.0f, +// ScenarioOrientation::so45DegreeTick0, +// "kultiras/orient0" +// }, +//// { +//// 530, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-5817, -1175), +//// mathfu::vec2(1758, 10491), +//// ScenarioOrientation::so45DegreeTick0, +//// "outland/topDown1" +//// } +//// { +//// 0, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-9081, -20), +//// mathfu::vec2(-8507, 1296), +//// ScenarioOrientation::soTopDownOrtho, +//// "azeroth/topDown" +//// } +//// }; +// +//// std::vector scenarios = { +//// { +//// 1, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-12182, -8803 ), +//// mathfu::vec2(12058, 4291), +//// ScenarioOrientation::so45DegreeTick0, +//// "kalimdor/rotation0" +//// }, +// { +// 1, +// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +// mathfu::vec2(-12182, -8803), +// mathfu::vec2(12058, 4291), +// 256, +// 256, +// 4.0f, +// ScenarioOrientation::so45DegreeTick1, +// "kalimdor/rotation1_new" +// } +// }; +//// { +//// 1, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-12182, -8803 ), +//// mathfu::vec2(12058, 4291), +//// ScenarioOrientation::so45DegreeTick2, +//// "kalimdor/rotation2" +//// }, +//// { +//// 1, +//// mathfu::vec4(0.0671968088, 0.294095874, 0.348881632, 0), +//// mathfu::vec4(0.345206976, 0.329288304, 0.270450264, 0), +//// mathfu::vec2(-12182, -8803 ), +//// mathfu::vec2(12058, 4291), +//// ScenarioOrientation::so45DegreeTick3, +//// "kalimdor/rotation3" +//// }, +//// }; +} + +void MinimapGenerationWindow::process() { + if (minimapGenerator != nullptr && minimapGenerator->getCurrentMode() != EMGMode::eNone) + minimapGenerator->process(); +} + +HDrawStage MinimapGenerationWindow::getDrawStage(HFrameScenario sceneScenario) { + if (minimapGenerator->getCurrentMode() != EMGMode::eNone) { + return minimapGenerator->createSceneDrawStage(sceneScenario); + } else { + return nullptr; + } +} + +void MinimapGenerationWindow::renderEditTab() { + if (ImGui::BeginTabItem("Edit", &editTabOpened, ImGuiTabItemFlags_SetSelected)) { + { + auto scenarioName = std::array(); + if (sceneDef->name.size() > 128) sceneDef->name.resize(128); + std::copy(sceneDef->name.begin(), sceneDef->name.end(), scenarioName.data()); + if (ImGui::InputText("Scenario name", scenarioName.data(), 128)) { + sceneDef->name = std::string(std::begin(scenarioName), std::end(scenarioName)); + } + { + ImGui::BeginGroupPanel("Maps"); + + for (int i = 0; i < sceneDef->maps.size(); i++) { + renderMapConfigSubWindow(i); + } + + if (ImGui::Button("Add Map")) { + sceneDef->maps.emplace_back(); + } + ImGui::EndGroupPanel(); + } + + + + ImGui::BeginGroupPanel("Orientation"); + { + if (ImGui::RadioButton("Ortho projection", &sceneDef->orientation, ScenarioOrientation::soTopDownOrtho)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + restartMinimapGenPreview(); + } + } + if (ImGui::RadioButton("At 45° tick 0", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick0)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + restartMinimapGenPreview(); + } + } + if (ImGui::RadioButton("At 45° tick 1", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick1)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + restartMinimapGenPreview(); + } + } + if (ImGui::RadioButton("At 45° tick 2", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick2)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + restartMinimapGenPreview(); + } + } + if (ImGui::RadioButton("At 45° tick 3", &sceneDef->orientation, ScenarioOrientation::so45DegreeTick3)) { + if (minimapGenerator->getCurrentMode() == EMGMode::ePreview) { + restartMinimapGenPreview(); + } + } + } + ImGui::EndGroupPanel(); + ImGui::SameLine(); + ImGui::BeginGroupPanel("Generation boundaries"); + { + ImGui::Text("In world coordinates"); + ImGui::InputFloat("Min x", &sceneDef->minWowWorldCoord.x); + ImGui::InputFloat("Min y", &sceneDef->minWowWorldCoord.y); + ImGui::InputFloat("Max x", &sceneDef->maxWowWorldCoord.x); + ImGui::InputFloat("Max y", &sceneDef->maxWowWorldCoord.y); + ImGui::EndGroupPanel(); + } + ImGui::BeginGroupPanel("Ocean color override"); + { + ImGui::CompactColorPicker("Close Ocean Color", sceneDef->closeOceanColor); + ImGui::EndGroupPanel(); + } + ImGui::BeginGroupPanel("Image settings"); + { + ImGui::PushItemWidth(100); + ImGui::InputInt("Image Width", &sceneDef->imageWidth); + ImGui::InputInt("Image Height", &sceneDef->imageHeight); + ImGui::PopItemWidth(); + ImGui::EndGroupPanel(); + } + + + + ImGui::BeginGroupPanel("Global map settings"); + { +// ImGui::BeginGroupPanel("River color overrides"); +// { +// for (int i = 0; i < riverColorOverrides->size(); i++) { +// auto &riverColorOverride = riverColorOverrides->operator[](i); +// +// ImGui::PushID(i); +// if (ImGui::Button("Copy from current")) { +// int areaId, parentAreaId; +// mathfu::vec4 riverColor; +// +// minimapGenerator->getCurrentFDData(areaId, parentAreaId, riverColor); +// riverColorOverride.areaId = areaId; +// riverColorOverride.color = riverColor; +// } +// ImGui::SameLine(); +// ImGui::CompactColorPicker("River Color Override", riverColorOverride.color); +// ImGui::SameLine(); +// ImGui::PushItemWidth(100); +// ImGui::InputInt("Area Id", &riverColorOverride.areaId); +// ImGui::PopItemWidth(); +// +// +// ImGui::PopID(); +// } +// +// if (ImGui::Button("Add override")) { +// riverColorOverrides->push_back({}); +// } +// } +// ImGui::EndGroupPanel(); + } + ImGui::EndGroupPanel(); + + ImGui::BeginGroupPanel("Current stats"); + { + int areaId, parentAreaId; + mathfu::vec4 riverColor; + + minimapGenerator->getCurrentFDData(areaId, parentAreaId, riverColor); + ImGui::Text("Current areaId %d", areaId); + ImGui::Text("Current parent areaId %d", parentAreaId); + ImGui::CompactColorPicker("Current River Color", riverColor); + + ImGui::EndGroupPanel(); + } + + auto currentTime = minimapGenerator->getConfig()->currentTime; + ImGui::Text("Time: %02d:%02d", (int)(currentTime/120), (int)((currentTime/2) % 60)); + if (ImGui::SliderInt("Current time", ¤tTime, 0, 2880)) { + minimapGenerator->getConfig()->currentTime = currentTime; + } + + editComponentsForConfig(minimapGenerator->getConfig()); + + if (minimapGenerator->getCurrentMode() != EMGMode::eScreenshotGeneration) { + bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; + if (ImGui::ButtonDisablable("Start Screenshot Gen", isDisabled)) { + std::vector list = {*sceneDef}; + + minimapGenerator->startScenarios(list); + } + } else { + if (ImGui::Button("Stop Screenshot Gen")) { + minimapGenerator->stopPreview(); + } + } + ImGui::SameLine(); + if (minimapGenerator->getCurrentMode() != EMGMode::ePreview) { + bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; + if (ImGui::ButtonDisablable("Start Preview", isDisabled)) { + minimapGenerator->startPreview(*sceneDef); + minimapGenerator->setZoom(previewZoom); + minimapGenerator->setLookAtPoint(previewX, previewY); + } + } else { + if (ImGui::Button("Stop Preview")) { + minimapGenerator->stopPreview(); + } + } + ImGui::SameLine(); + if (minimapGenerator->getCurrentMode() != EMGMode::eBoundingBoxCalculation) { + bool isDisabled = minimapGenerator->getCurrentMode() != EMGMode::eNone; + if (ImGui::ButtonDisablable("Start BBox calc", isDisabled)) { + minimapGenerator->startBoundingBoxCalc(*sceneDef); + } + } else { + if (ImGui::Button("Stop BBox calc")) { + minimapGenerator->stopBoundingBoxCalc(); + } + } + + if (minimapGenerator->getCurrentMode() != EMGMode::eNone && minimapGenerator->getCurrentMode() != EMGMode::ePreview) { + int x, y, maxX, maxY; + minimapGenerator->getCurrentTileCoordinates(x, y, maxX, maxY); + + ImGui::Text("X: % 03d out of % 03d", x, maxX); + ImGui::Text("Y: % 03d out of % 03d", y, maxY); + + } + + if (ImGui::Button("Save")) { + m_minimapDB->saveScenarios(sceneDefList); + } + } + + ImGui::EndTabItem(); + } +} + +void MinimapGenerationWindow::renderListTab() { + if (ImGui::BeginTabItem("List")) + { + //The table + { + ImGui::BeginChild("Scenario List", ImVec2(0, -(100 + ImGui::GetStyle().ItemSpacing.y)), false, + 0); // Use avail width, use 100 for height + ImGui::Columns(3, "scenarioListcolumns"); // 3-ways, with border + ImGui::Separator(); + ImGui::Text(""); + ImGui::NextColumn(); + ImGui::Text("Name"); + ImGui::NextColumn(); + ImGui::Text("Actions"); + ImGui::NextColumn(); + ImGui::Separator(); + for (int i = 0; i < this->sceneDefList.size(); i++) { + auto &l_sceneDef = sceneDefList[i]; + bool checked = true; + ImGui::Checkbox("", &checked); + ImGui::NextColumn(); + ImGui::Text("%s", l_sceneDef.name.c_str()); + ImGui::NextColumn(); + if (ImGui::Button(("Edit##" + std::to_string(i)).c_str())) { + this->sceneDef = &l_sceneDef; + editTabOpened = true; + } + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + ImGui::EndChild(); + } + + { + ImGui::BeginChild("BottomBar", ImVec2(0, 0), false, 0); // Use avail width/height + if (ImGui::Button("Add new scenario")) { + this->sceneDef = &sceneDefList.emplace_back(); + editTabOpened = true; + } + ImGui::Button("Render selected"); + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } +} diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h new file mode 100644 index 000000000..935ae3e9f --- /dev/null +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -0,0 +1,57 @@ +// +// Created by Deamon on 10/29/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MINIMAPGENERATIONWINDOW_H +#define AWEBWOWVIEWERCPP_MINIMAPGENERATIONWINDOW_H + + +#include "../../../minimapGenerator/entities.h" +#include "../../../minimapGenerator/minimapGenerator.h" +#include "../../../minimapGenerator/storage/CMinimapDataDB.h" + +class MinimapGenerationWindow { +public: + MinimapGenerationWindow(HApiContainer api, HRequestProcessor processor, bool &showMinimapGeneratorSettings) : + m_showMinimapGeneratorSettings(showMinimapGeneratorSettings) { + m_api = api; + m_processor = processor; + + m_minimapDB = std::make_shared("minimapdb.sqlite"); + m_minimapDB->getScenarios(sceneDefList); + + createMinimapGenerator(); + } + + void render(); + void process(); + HDrawStage getDrawStage(HFrameScenario sceneScenario); + +private: + HApiContainer m_api; + HRequestProcessor m_processor; + + bool &m_showMinimapGeneratorSettings; + + std::shared_ptr m_minimapDB; + + HMinimapGenerator minimapGenerator; + std::vector sceneDefList; + HRiverColorOverrideHolder riverColorOverrides; + ScenarioDef *sceneDef = nullptr; + bool editTabOpened; + float previewX = 0; + float previewY = 0; + float previewZoom = 1; + + void restartMinimapGenPreview(); + void createMinimapGenerator(); + void editComponentsForConfig(Config * config); + void renderMapConfigSubWindow(int mapIndex); + void renderEditTab(); + + void renderListTab(); +}; + + +#endif //AWEBWOWVIEWERCPP_MINIMAPGENERATIONWINDOW_H diff --git a/wowViewerLib/src/engine/SceneScenario.cpp b/wowViewerLib/src/engine/SceneScenario.cpp index ba43fe013..c07b80ad9 100644 --- a/wowViewerLib/src/engine/SceneScenario.cpp +++ b/wowViewerLib/src/engine/SceneScenario.cpp @@ -4,10 +4,13 @@ #include "SceneScenario.h" -HCullStage FrameScenario::addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene) { +HCullStage FrameScenario::addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene, mathfu::vec3 deltas) { HCullStage newCullStage = std::make_shared(); newCullStage->matricesForCulling = matricesForCulling; newCullStage->scene = scene; + newCullStage->deltaX = deltas[0]; + newCullStage->deltaY = deltas[1]; + newCullStage->deltaZ = deltas[2]; cullStages.push_back(newCullStage); @@ -15,7 +18,7 @@ HCullStage FrameScenario::addCullStage(HCameraMatrices matricesForCulling, std:: } HUpdateStage -FrameScenario::addUpdateStage(HCullStage cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate) { +FrameScenario::addUpdateStage(HCullStage &cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate) { HUpdateStage newUpdateStage = std::make_shared(); newUpdateStage->cullResult = cullStage; diff --git a/wowViewerLib/src/engine/SceneScenario.h b/wowViewerLib/src/engine/SceneScenario.h index 2ce4c72cf..8f31600d6 100644 --- a/wowViewerLib/src/engine/SceneScenario.h +++ b/wowViewerLib/src/engine/SceneScenario.h @@ -30,6 +30,11 @@ struct CullStage { HCameraMatrices matricesForCulling; HScene scene; + //Just for proper BoundingBox calculus + float deltaX = 0.0f; + float deltaY = 0.0f; + float deltaZ = 0.0f; + //Output: int adtAreadId = -1; @@ -89,8 +94,8 @@ class FrameScenario { HDrawStage lastDrawStage; public: - HCullStage addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene); - HUpdateStage addUpdateStage(HCullStage cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate); + HCullStage addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene, mathfu::vec3 deltas = {0,0,0}); + HUpdateStage addUpdateStage(HCullStage &cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate); HDrawStage addDrawStage(std::vector &updateStage, HScene scene, diff --git a/wowViewerLib/src/engine/objects/scenes/NullScene.h b/wowViewerLib/src/engine/objects/scenes/NullScene.h index 5643e3172..c99e2742f 100644 --- a/wowViewerLib/src/engine/objects/scenes/NullScene.h +++ b/wowViewerLib/src/engine/objects/scenes/NullScene.h @@ -16,7 +16,7 @@ class NullScene : public IScene { virtual void setMeshIds(std::vector &meshIds) override {}; virtual void produceUpdateStage(HUpdateStage &updateStage) override {}; - virtual void produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) override { + virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override { resultDrawStage->transparentMeshes = std::make_shared(); resultDrawStage->opaqueMeshes = std::make_shared(); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index d91d5d834..e37d81923 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1748,80 +1748,100 @@ void Map::produceUpdateStage(HUpdateStage &updateStage) { m_api->getConfig()->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); m_api->getConfig()->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); } -void Map::produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStage, std::vector &additionalChunks) { - auto cullStage = updateStage->cullResult; - - //Create scenewide uniform - resultDrawStage->frameDepedantData = updateStage->cullResult->frameDepedantData; - auto renderMats = resultDrawStage->matricesForRendering; +void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) { + //Smash all meshes into one array + + auto opaqueMeshes = std::make_shared(); + auto transparentMeshes = std::make_shared(); + for (auto &updateStage : updateStages) { + auto cullStage = updateStage->cullResult; + + //Create scenewide uniform + resultDrawStage->frameDepedantData = updateStage->cullResult->frameDepedantData; + + opaqueMeshes->meshes.insert(std::end(opaqueMeshes->meshes), + std::begin(updateStage->opaqueMeshes->meshes), + std::end(updateStage->opaqueMeshes->meshes)); + transparentMeshes->meshes.insert(std::end(transparentMeshes->meshes), + std::begin(updateStage->transparentMeshes->meshes), + std::end(updateStage->transparentMeshes->meshes)); + } - resultDrawStage->opaqueMeshes = updateStage->opaqueMeshes; - resultDrawStage->transparentMeshes = updateStage->transparentMeshes; + //Sort transparent meshes. Again + tbb::parallel_sort(transparentMeshes->meshes.begin(), transparentMeshes->meshes.end(), +#include "../../../gapi/interface/sortLambda.h" + ); HDrawStage origResultDrawStage = resultDrawStage; bool frameBufferSupported = m_api->hDevice->getIsRenderbufferSupported(); auto config = m_api->getConfig(); - resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); - resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler([renderMats, config](IUniformBufferChunk *chunk, const HFrameDepedantData &fdd) -> void { - auto *blockPSVS = &chunk->getObject(); - - blockPSVS->uLookAtMat = renderMats->lookAtMat; - blockPSVS->uPMatrix = renderMats->perspectiveMat; - blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; - blockPSVS->uViewUp = renderMats->viewUp; - - blockPSVS->extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; - blockPSVS->extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; - blockPSVS->extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; - blockPSVS->extLight.uExteriorDirectColor = fdd->exteriorDirectColor; - blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); - blockPSVS->extLight.uAdtSpecMult = mathfu::vec4(config->adtSpecMult, 0,0,1.0); + + auto renderMats = resultDrawStage->matricesForRendering; + if (renderMats != nullptr) { + resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); + resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler( + [renderMats, config](IUniformBufferChunk *chunk, const HFrameDepedantData &fdd) -> void { + auto *blockPSVS = &chunk->getObject(); + + blockPSVS->uLookAtMat = renderMats->lookAtMat; + blockPSVS->uPMatrix = renderMats->perspectiveMat; + blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; + blockPSVS->uViewUp = renderMats->viewUp; + + blockPSVS->extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; + blockPSVS->extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; + blockPSVS->extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; + blockPSVS->extLight.uExteriorDirectColor = fdd->exteriorDirectColor; + blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); + blockPSVS->extLight.uAdtSpecMult = mathfu::vec4(config->adtSpecMult, 0, 0, 1.0); // float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); - float fogEnd = config->farPlane; - if (config->disableFog || !fdd->FogDataFound) { - fogEnd = 100000000.0f; - fdd->FogScaler = 0; - fdd->FogDensity = 0; - } + float fogEnd = config->farPlane; + if (config->disableFog || !fdd->FogDataFound) { + fogEnd = 100000000.0f; + fdd->FogScaler = 0; + fdd->FogDensity = 0; + } - float fogStart = std::max(config->farPlane - 250, 0); - fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); - - - blockPSVS->fogData.densityParams = mathfu::vec4( - fogStart, - fogEnd , - fdd->FogDensity / 1000, - 0); - blockPSVS->fogData.heightPlane = mathfu::vec4(0,0,0,0); - blockPSVS->fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor,fdd->FogHeightScaler); - blockPSVS->fogData.heightDensity_and_endColor = mathfu::vec4( - fdd->FogHeightDensity, - fdd->EndFogColor.x, - fdd->EndFogColor.y, - fdd->EndFogColor.z - ); - blockPSVS->fogData.sunAngle_and_sunColor = mathfu::vec4( - fdd->SunFogAngle, - fdd->SunFogColor.x * fdd->SunFogStrength, - fdd->SunFogColor.y * fdd->SunFogStrength, - fdd->SunFogColor.z * fdd->SunFogStrength - ); - blockPSVS->fogData.heightColor_and_endFogDistance = mathfu::vec4( - fdd->FogHeightColor, - (fdd->EndFogColorDistance > 0) ? - fdd->EndFogColorDistance : - 1000.0f + float fogStart = std::max(config->farPlane - 250, 0); + fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); + + + blockPSVS->fogData.densityParams = mathfu::vec4( + fogStart, + fogEnd, + fdd->FogDensity / 1000, + 0); + blockPSVS->fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); + blockPSVS->fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); + blockPSVS->fogData.heightDensity_and_endColor = mathfu::vec4( + fdd->FogHeightDensity, + fdd->EndFogColor.x, + fdd->EndFogColor.y, + fdd->EndFogColor.z + ); + blockPSVS->fogData.sunAngle_and_sunColor = mathfu::vec4( + fdd->SunFogAngle, + fdd->SunFogColor.x * fdd->SunFogStrength, + fdd->SunFogColor.y * fdd->SunFogStrength, + fdd->SunFogColor.z * fdd->SunFogStrength + ); + blockPSVS->fogData.heightColor_and_endFogDistance = mathfu::vec4( + fdd->FogHeightColor, + (fdd->EndFogColorDistance > 0) ? + fdd->EndFogColorDistance : + 1000.0f + ); + blockPSVS->fogData.sunPercentage = mathfu::vec4( + (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); + + } ); - blockPSVS->fogData.sunPercentage = mathfu::vec4( - (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f - , 0, 0, 0); + additionalChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); + } - }); - updateStage->uniformBufferChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); if (frameBufferSupported ) { //Create a copy of exiting resultDrawStage @@ -1842,7 +1862,7 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStag HDrawStage prevDrawStage = resultDrawStageCpy; if (!config->disableGlow) { - lastDrawStage = doGaussBlur(prevDrawStage, updateStage); + lastDrawStage = doGaussBlur(prevDrawStage, additionalChunks); if (lastDrawStage != nullptr) prevDrawStage = lastDrawStage; } @@ -1856,9 +1876,10 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, HUpdateStage &updateStag } + } -HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &updateStage) const { +HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const { if (quadBindings == nullptr) return nullptr; @@ -1886,7 +1907,7 @@ HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &upd ); auto vertexChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); - updateStage->uniformBufferChunks.push_back(vertexChunk); + uniformBufferChunks.push_back(vertexChunk); vertexChunk->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); meshblockVS.x = 1; @@ -1897,7 +1918,7 @@ HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &upd auto ffxGaussFrag = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - updateStage->uniformBufferChunks.push_back(ffxGaussFrag); + uniformBufferChunks.push_back(ffxGaussFrag); ffxGaussFrag->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); static const float s_texOffsetX[4] = {-1, 0, 0, -1}; @@ -1911,7 +1932,7 @@ HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &upd auto ffxGaussFrag2 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - updateStage->uniformBufferChunks.push_back(ffxGaussFrag2); + uniformBufferChunks.push_back(ffxGaussFrag2); ffxGaussFrag2->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); static const float s_texOffsetX[4] = {-6, -1, 1, 6}; @@ -1923,7 +1944,7 @@ HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &upd } }); auto ffxGaussFrag3 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - updateStage->uniformBufferChunks.push_back(ffxGaussFrag3); + uniformBufferChunks.push_back(ffxGaussFrag3); ffxGaussFrag3->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); static const float s_texOffsetX[4] = {0, 0, 0, 0}; @@ -1990,7 +2011,7 @@ HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &upd auto glow = parentDrawStage->frameDepedantData->currentGlow; auto ffxGlowfragmentChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); - updateStage->uniformBufferChunks.push_back(ffxGlowfragmentChunk); + uniformBufferChunks.push_back(ffxGlowfragmentChunk); ffxGlowfragmentChunk->setUpdateHandler([glow, config](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); meshblockVS.x = 1; diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index c3db53f67..636c73496 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -252,7 +252,7 @@ class Map : public IScene, public IMapApi { int viewRenderOrder, HCullStage cullStage); - HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, HUpdateStage &updateStage) const; + HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) override; From b278ca936267e9359254fa066480b1944a8f0d5c Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Oct 2022 03:50:43 +0300 Subject: [PATCH 004/212] commit before trying sqlite_orm --- src/minimapGenerator/entities.h | 7 +- .../storage/CMinimapDataDB.cpp | 131 ++++++++++++------ src/minimapGenerator/storage/CMinimapDataDB.h | 4 +- .../MinimapGenerationWindow.cpp | 39 ++++-- .../MinimapGenerationWindow.h | 3 + 5 files changed, 126 insertions(+), 58 deletions(-) diff --git a/src/minimapGenerator/entities.h b/src/minimapGenerator/entities.h index 77ac7f81e..a36759c6f 100644 --- a/src/minimapGenerator/entities.h +++ b/src/minimapGenerator/entities.h @@ -43,26 +43,25 @@ struct MapRenderDef { }; struct ScenarioDef { - std::vector maps; int id = -1; std::string name; ScenarioOrientation orientation = ScenarioOrientation::so45DegreeTick0; - std::unordered_map> activatePhasePerMap; - mathfu::vec4 closeOceanColor; mathfu::vec2 minWowWorldCoord; mathfu::vec2 maxWowWorldCoord; int imageHeight; - int imageWidth; float zoom = 1.0f; std::string folderToSave; + + std::unordered_map> activatePhasePerMap; + std::vector maps; }; diff --git a/src/minimapGenerator/storage/CMinimapDataDB.cpp b/src/minimapGenerator/storage/CMinimapDataDB.cpp index d1acd771a..6b18b86ed 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.cpp +++ b/src/minimapGenerator/storage/CMinimapDataDB.cpp @@ -50,7 +50,8 @@ R"===( const std::string insertNewScenariosSQL = R"===( - insert into scenarios (orientation, + insert into scenarios (name, + orientation, ocean_color_0, ocean_color_1, ocean_color_2, ocean_color_3, world_coord_min_x, world_coord_min_y, world_coord_max_x, world_coord_max_y, image_width, image_height, zoom, folderToSave) @@ -59,7 +60,7 @@ R"===( const std::string updateScenarioSQL = R"===( - update scenarios set map_id = ?, orientation = ?, + update scenarios set name = ?, map_id = ?, orientation = ?, ocean_color_0 = ?, ocean_color_1 = ?, ocean_color_2 = ?, ocean_color_3 = ?, world_coord_min_x = ?, world_coord_min_y = ?, world_coord_max_x = ?, world_coord_max_y = ?, image_width = ?, image_height = ?, zoom = ?, folderToSave = ? @@ -133,7 +134,7 @@ CMinimapDataDB::CMinimapDataDB(const std::string &fileName) : insertADTBoundingBoxes(InitDB(m_sqliteDatabase), insertADTBoundingBoxesSQL), getMapDef(InitDB(m_sqliteDatabase), getMapDefSQL), - insertMapDef(InitDB(m_sqliteDatabase), insertMapDefSQL), + insertNewMapDef(InitDB(m_sqliteDatabase), insertMapDefSQL), updateMapDef(InitDB(m_sqliteDatabase), updateMapDefSQL), getADTExcluded(InitDB(m_sqliteDatabase), getAdtExcludedSQL), @@ -187,52 +188,67 @@ void CMinimapDataDB::saveScenarios(std::vector &scenarios) { SQLite::Transaction transaction(m_sqliteDatabase); for (auto &scenario : scenarios) { - if (scenario.id == -1) { - insertNewScenario.setInputs( - (int) scenario.orientation, - scenario.closeOceanColor.x, - scenario.closeOceanColor.y, - scenario.closeOceanColor.z, - scenario.closeOceanColor.w, - scenario.minWowWorldCoord.x, - scenario.minWowWorldCoord.y, - scenario.maxWowWorldCoord.x, - scenario.maxWowWorldCoord.y, - scenario.imageWidth, - scenario.imageHeight, - scenario.zoom, - scenario.folderToSave.c_str() - ); - - if (insertNewScenario.execute()) { - scenario.id = m_sqliteDatabase.getLastInsertRowid(); - } - } else { - updateScenario.setInputs( - (int) scenario.orientation, - scenario.closeOceanColor.x, - scenario.closeOceanColor.y, - scenario.closeOceanColor.z, - scenario.closeOceanColor.w, - scenario.minWowWorldCoord.x, - scenario.minWowWorldCoord.y, - scenario.maxWowWorldCoord.x, - scenario.maxWowWorldCoord.y, - scenario.imageWidth, - scenario.imageHeight, - scenario.zoom, - scenario.folderToSave.c_str(), - scenario.id - ); - - updateScenario.execute(); - } + saveScenario(scenario); } // Commit transaction transaction.commit(); } +void CMinimapDataDB::saveScenario(ScenarioDef &scenario) { + SQLite::Transaction transaction(m_sqliteDatabase); + + if (scenario.id == -1) { + insertNewScenario.setInputs( + scenario.name, + (int) scenario.orientation, + scenario.closeOceanColor.x, + scenario.closeOceanColor.y, + scenario.closeOceanColor.z, + scenario.closeOceanColor.w, + scenario.minWowWorldCoord.x, + scenario.minWowWorldCoord.y, + scenario.maxWowWorldCoord.x, + scenario.maxWowWorldCoord.y, + scenario.imageWidth, + scenario.imageHeight, + scenario.zoom, + scenario.folderToSave.c_str() + ); + + if (insertNewScenario.execute()) { + scenario.id = m_sqliteDatabase.getLastInsertRowid(); + } + } else { + updateScenario.setInputs( + scenario.name, + (int) scenario.orientation, + scenario.closeOceanColor.x, + scenario.closeOceanColor.y, + scenario.closeOceanColor.z, + scenario.closeOceanColor.w, + scenario.minWowWorldCoord.x, + scenario.minWowWorldCoord.y, + scenario.maxWowWorldCoord.x, + scenario.maxWowWorldCoord.y, + scenario.imageWidth, + scenario.imageHeight, + scenario.zoom, + scenario.folderToSave.c_str(), + scenario.id + ); + + updateScenario.execute(); + } + // Commit transaction + transaction.commit(); + + //Save arrays + for (auto &mapDef : scenario.maps) { + saveMapRenderDef(scenario.id, mapDef); + } +} + void CMinimapDataDB::getAdtBoundingBoxes(MapRenderDef& mapRenderDef) { getADTBoundingBoxes.setInputs(mapRenderDef.mapId); @@ -276,7 +292,7 @@ void CMinimapDataDB::getAdtExcluded(MapRenderDef& mapRenderDef) { while (getADTExcluded.execute()) { - int adt_x = getADTExcluded.getField("adt_x").getInt(); + int adt_x = c.getField("adt_x").getInt(); int adt_y = getADTExcluded.getField("adt_y").getInt(); int chunk_x = getADTExcluded.getField("chunk_x").getInt(); int chunk_y = getADTExcluded.getField("chunk_y").getInt(); @@ -510,5 +526,32 @@ void CMinimapDataDB::getMapRenderDef(int scenarioId, std::vector & } void CMinimapDataDB::saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef) { + SQLite::Transaction transaction(m_sqliteDatabase); + + if (mapRenderDef.id == -1) { + insertNewMapDef.setInputs( + scenarioId, + mapRenderDef.mapId, + mapRenderDef.deltaX, + mapRenderDef.deltaY, + mapRenderDef.deltaZ + ); + + if (insertNewMapDef.execute()) { + mapRenderDef.id = m_sqliteDatabase.getLastInsertRowid(); + } + } else { + updateMapDef.setInputs( + mapRenderDef.mapId, + mapRenderDef.deltaX, + mapRenderDef.deltaY, + mapRenderDef.deltaZ + ); + + updateScenario.execute(); + } + // Commit transaction + transaction.commit(); + saveAdtExcluded(mapRenderDef); } \ No newline at end of file diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index 618fdf049..061daf41a 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -72,11 +72,13 @@ class CMinimapDataDB { StatementFieldHolder insertADTBoundingBoxes; StatementFieldHolder getMapDef; - StatementFieldHolder insertMapDef; + StatementFieldHolder insertNewMapDef; StatementFieldHolder updateMapDef; StatementFieldHolder getADTExcluded; StatementFieldHolder insertADTExcluded; + + void saveScenario(ScenarioDef &scenario); }; diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 7ac721af9..4ade69ec5 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -112,23 +112,40 @@ void MinimapGenerationWindow::render() { void MinimapGenerationWindow::renderMapConfigSubWindow(int mapIndex) { auto &mapRenderDef = sceneDef->maps[mapIndex]; - ImGui::BeginGroupPanel(("Map##" + std::to_string(mapIndex)).c_str()); + ImGui::BeginGroupPanel(("Map" + std::to_string(mapIndex)).c_str()); ImGui::InputInt(("Map Id##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.mapId); ImGui::InputDouble(("Delta X##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaX); ImGui::InputDouble(("Delta Y##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaY); ImGui::InputDouble(("Delta Z##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaZ); - ImGui::PushStyleColor(ImGuiCol_Button, 0x0000FF); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0x0000FF); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0x0000FF); - if (ImGui::Button("Delete")) { - sceneDef->maps.erase(std::next(sceneDef->maps.begin(), mapIndex-1)); + const auto redColor = ImVec4{1.0f, 0.f, 0.f, 1.0f}; + ImGui::PushStyleColor(ImGuiCol_Button, redColor); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, redColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, redColor); + if (ImGui::Button(("Delete##"+ std::to_string(mapIndex)).c_str())) { + if (mapIndex > 0) { + sceneDef->maps.erase(std::next(sceneDef->maps.begin(), mapIndex - 1)); + } else { + sceneDef->maps.erase(sceneDef->maps.begin()); + } } - ImGui::PopStyleColor(ImGuiCol_Button); - ImGui::PopStyleColor(ImGuiCol_ButtonActive); - ImGui::PopStyleColor(ImGuiCol_ButtonActive); + ImGui::PopStyleColor(3); + ImGui::EndGroupPanel(); + + ImGui::SameLine(); + ImGui::BeginGroupPanel(""); + bool active = mapIndexExcludeADT == mapIndex; + if (ImGui::RadioButton(("Exclude ADT##" + std::to_string(mapIndex)).c_str(), active)) { + mapIndexExcludeADT = mapIndex; + mapIndexExcludeADTChunk = -1; + } + bool active2 = mapIndexExcludeADTChunk == mapIndex; + if (ImGui::RadioButton(("Exclude ADT Chunk##" + std::to_string(mapIndex)).c_str(), active2)) { + mapIndexExcludeADT = -1; + mapIndexExcludeADTChunk = mapIndex; + } ImGui::EndGroupPanel(); } @@ -325,6 +342,10 @@ void MinimapGenerationWindow::renderEditTab() { if (ImGui::Button("Add Map")) { sceneDef->maps.emplace_back(); } + if (ImGui::Button("Reset Exclude")) { + mapIndexExcludeADT = -1; + mapIndexExcludeADTChunk = -1; + } ImGui::EndGroupPanel(); } diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h index 935ae3e9f..2f7c1179e 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -44,6 +44,9 @@ class MinimapGenerationWindow { float previewY = 0; float previewZoom = 1; + int mapIndexExcludeADT = -1; + int mapIndexExcludeADTChunk = -1; + void restartMinimapGenPreview(); void createMinimapGenerator(); void editComponentsForConfig(Config * config); From 95faa8f2805597f74f7745741b0a709dc9437635 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 2 Nov 2022 02:43:57 +0200 Subject: [PATCH 005/212] first stage completed. The pngs are generated properly --- CMakeLists.txt | 3 +- src/minimapGenerator/entities.h | 26 +- src/minimapGenerator/minimapGenerator.cpp | 72 ++- .../storage/CMinimapDataDB.cpp | 568 +++--------------- src/minimapGenerator/storage/CMinimapDataDB.h | 151 +++-- src/ui/FrontendUI.cpp | 10 +- src/ui/FrontendUI.h | 2 +- .../MinimapGenerationWindow.cpp | 28 +- .../MinimapGenerationWindow.h | 4 +- wowViewerLib/src/engine/SceneComposer.cpp | 14 +- .../src/engine/algorithms/mathHelper.h | 6 +- .../src/engine/objects/adt/adtObject.cpp | 29 +- .../src/engine/objects/adt/adtObject.h | 2 + wowViewerLib/src/engine/objects/iScene.h | 2 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../src/engine/objects/scenes/NullScene.h | 2 +- .../src/engine/objects/scenes/m2Scene.cpp | 8 +- .../src/engine/objects/scenes/m2Scene.h | 4 +- .../src/engine/objects/scenes/map.cpp | 193 +++--- wowViewerLib/src/engine/objects/scenes/map.h | 25 +- .../src/engine/objects/scenes/wmoScene.cpp | 86 +-- .../src/engine/objects/wmo/wmoObject.h | 2 +- 22 files changed, 444 insertions(+), 795 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5012a1bc3..ec1ad6b7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ endif() if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) - +cmake_policy(SET CMP0079 NEW) set(USE_NEON 0) if (CMAKE_NDK_BUILD MATCHES 1) @@ -331,6 +331,7 @@ target_link_libraries(AWebWoWViewerCpp libprotobuf-lite) target_link_libraries(AWebWoWViewerCpp SQLiteCpp sqlite3) +target_link_libraries(DBImporterLib SQLiteCpp) if (NOT MSVC) find_library(DL_EXISTS dl) message("DL_EXISTS = ${DL_EXISTS}") diff --git a/src/minimapGenerator/entities.h b/src/minimapGenerator/entities.h index a36759c6f..d90c6916e 100644 --- a/src/minimapGenerator/entities.h +++ b/src/minimapGenerator/entities.h @@ -53,8 +53,9 @@ struct ScenarioDef { mathfu::vec2 minWowWorldCoord; mathfu::vec2 maxWowWorldCoord; - int imageHeight; - int imageWidth; + //TODO: add check + int imageHeight = 1024; + int imageWidth = 1024; float zoom = 1.0f; @@ -62,6 +63,27 @@ struct ScenarioDef { std::unordered_map> activatePhasePerMap; std::vector maps; +public: + int getOrientation() const {return (int) orientation;} + void setOrientation(int value) { orientation = static_cast(value); }; + + float getCloseOceanColor_R() const {return closeOceanColor[0];} + float getCloseOceanColor_G() const {return closeOceanColor[1];} + float getCloseOceanColor_B() const {return closeOceanColor[2];} + + void setCloseOceanColor_R(float value) {closeOceanColor[0] = value;} + void setCloseOceanColor_G(float value) {closeOceanColor[1] = value;} + void setCloseOceanColor_B(float value) {closeOceanColor[2] = value;} + + float getMinWowWorldCoordX() const {return minWowWorldCoord.x;} + float getMinWowWorldCoordY() const {return minWowWorldCoord.y;} + float getMaxWowWorldCoordX() const {return maxWowWorldCoord.x;} + float getMaxWowWorldCoordY() const {return maxWowWorldCoord.y;} + + void setMinWowWorldCoordX(float value){minWowWorldCoord.x = value;} + void setMinWowWorldCoordY(float value){minWowWorldCoord.y = value;} + void setMaxWowWorldCoordX(float value){maxWowWorldCoord.x = value;} + void setMaxWowWorldCoordY(float value){maxWowWorldCoord.y = value;} }; diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index b422ab9a1..9ccae0b95 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -166,6 +166,8 @@ bool MinimapGenerator::loadMaps() { std::array minMaxZ = {minZ, maxZ}; std::vector corners; + if (minZ > maxZ) continue; + for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { @@ -211,9 +213,9 @@ bool MinimapGenerator::loadMaps() { continue; if (j < m_chunkStartY) continue; - if (i > m_chunkStartX + m_chunkWidth) + if (i >= m_chunkStartX + m_chunkWidth) continue; - if (i > m_chunkStartY + m_chunkHeight) + if (i >= m_chunkStartY + m_chunkHeight) continue; std::array adtCoord = {static_cast(adt_x), @@ -230,6 +232,7 @@ bool MinimapGenerator::loadMaps() { } void MinimapGenerator::setupScenarioData() { + m_mapIndex = 0; m_zoom = currentScenario.zoom; stackOfCullStages = {nullptr, nullptr, nullptr, nullptr}; @@ -238,7 +241,6 @@ void MinimapGenerator::setupScenarioData() { config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; config->closeRiverColor = {0.345206976, 0.329288304, 0.270450264, 0}; - m_width = currentScenario.imageWidth; m_height = currentScenario.imageHeight; @@ -277,11 +279,15 @@ MinimapGenerator::setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, c for (auto &mapData : mapRuntimeInfo) { auto &mapDef = currentScenario.maps[mapData.mapIndex]; - for (int adt_y = worldCoordinateToAdtIndex(minWowWorldCoord.x + mapDef.deltaX); - adt_y < worldCoordinateToAdtIndex(maxWowWorldCoord.x+ mapDef.deltaX); adt_y++) { + for (int adt_y = worldCoordinateToAdtIndex(maxWowWorldCoord.x + mapDef.deltaX); + adt_y <= worldCoordinateToAdtIndex(minWowWorldCoord.x+ mapDef.deltaX); adt_y++) { + + if (adt_y < 0 || adt_y > 63) continue; - for (int adt_x = worldCoordinateToAdtIndex(minWowWorldCoord.y + mapDef.deltaY); - adt_x < worldCoordinateToAdtIndex(maxWowWorldCoord.y + mapDef.deltaY); adt_x++) { + for (int adt_x = worldCoordinateToAdtIndex(maxWowWorldCoord.y + mapDef.deltaY); + adt_x <= worldCoordinateToAdtIndex(minWowWorldCoord.y + mapDef.deltaY); adt_x++) { + + if (adt_x < 0 || adt_x > 63) continue; auto adtMinZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; auto adtMaxZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; @@ -323,10 +329,17 @@ MinimapGenerator::setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, c } } } else { - minMaxScreenX = {-64, -64}; - minMaxScreenY = {64, 64}; + minMaxScreenX = {-64, 64}; + minMaxScreenY = {-64, 64}; } + if (minMaxScreenX[0] > minMaxScreenX[1]) { + std::cout << "apparently BB were not calculated. exiting" << std::endl; + m_chunkStartX = 0; + m_chunkStartY = 0; + m_chunkWidth = 0; + m_chunkHeight = 0; + } mathfu::vec2 minOrthoMapCoord = mathfu::vec2( minMaxScreenX[0], @@ -431,14 +444,14 @@ void MinimapGenerator::setupCameraData() { //Do reverse transform here auto min1 = mathfu::vec4( (m_chunkStartX + m_x) * 2.0f, - (m_chunkStartY + m_chunkHeight - (m_y - 1)) * 2.0f, + (m_chunkStartY + m_chunkHeight - (m_y + 1)) * 2.0f, 0, 1 ); auto min2 = mathfu::vec4( (m_chunkStartX + m_x) * 2.0f, - (m_chunkStartY + m_chunkHeight - (m_y - 1)) * 2.0f, + (m_chunkStartY + m_chunkHeight - (m_y + 1)) * 2.0f, 1, 1 ); @@ -620,17 +633,23 @@ void MinimapGenerator::process() { return; } - if (framesReady < waitQueueLen) { - return; - } - if (!m_candidateCS.empty()) { for (auto &cullStage : m_candidateCS) { - if (cullStage != nullptr && ( + if (cullStage == nullptr) continue; + + for (const auto &adtCullRes : cullStage->adtArray) { + if (adtCullRes->adtObject == nullptr) continue; + if (adtCullRes->adtObject->getLoadedStatus() == FileStatus::FSNotLoaded) { + resetCandidate(); + return; + } + } + + if ( (cullStage->m2Array.getToLoadGeom().size() != 0) || (cullStage->m2Array.getToLoadMain().size() != 0) || (cullStage->wmoGroupArray.getToLoad().size() != 0) - )) { + ) { resetCandidate(); return; } @@ -646,6 +665,9 @@ void MinimapGenerator::process() { } } + if (framesReady < waitQueueLen) { + return; + } if (m_candidateDS == nullptr) { resetCandidate(); @@ -719,7 +741,7 @@ void MinimapGenerator::process() { currentScenario.maps[m_mapIndex].adtConfigHolder->adtMinZ[adt_x][adt_y] = minCoord.z; currentScenario.maps[m_mapIndex].adtConfigHolder->adtMaxZ[adt_x][adt_y] = maxCoord.z; - saveDrawStageToFile(currentScenario.folderToSave+"/minimap", lastFrameIt); + saveDrawStageToFile(currentScenario.folderToSave+"/minimap/"+std::to_string(currentScenario.maps[m_mapIndex].mapId), lastFrameIt); } else if (m_mgMode == EMGMode::eScreenshotGeneration) { //Make screenshot out of this drawStage saveDrawStageToFile(currentScenario.folderToSave, lastFrameIt); @@ -735,7 +757,17 @@ void MinimapGenerator::process() { // std::cout << "m_x = " << m_x << " out of (" << m_chunkStartX+m_chunkWidth << ") m_y = " << m_y << " out of (" << m_chunkStartY+m_chunkHeight << ")" << std::endl; if (m_x >= m_chunkWidth) { - startNextScenario(); + if (m_mgMode == EMGMode::eBoundingBoxCalculation && (m_mapIndex+1) < currentScenario.maps.size()) { + m_mapIndex++; + m_x = 0; + m_y = 0; + m_zFar = 10000.0f; + m_maxZ = 1000.0f; + m_minZ = -1000.0f; + setupCameraData(); + } else { + startNextScenario(); + } } else { //reset m_zFar = 10000.0f; @@ -830,6 +862,8 @@ HDrawStage MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mainMap.scene); std::shared_ptr updateStage = sceneScenario->addUpdateStage(cullStage, 0, cameraMatricesRendering); + cullStages.push_back(cullStage); + updateStages.push_back(updateStage); } HDrawStage sceneDrawStage = sceneScenario->addDrawStage( diff --git a/src/minimapGenerator/storage/CMinimapDataDB.cpp b/src/minimapGenerator/storage/CMinimapDataDB.cpp index 6b18b86ed..6b633b3d9 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.cpp +++ b/src/minimapGenerator/storage/CMinimapDataDB.cpp @@ -7,516 +7,131 @@ #include #include - -CMinimapDataDB::StatementFieldHolder::StatementFieldHolder(SQLite::Database &database, const std::string &query) : - m_query(database, query) { - - for (int i = 0; i < m_query.getColumnCount(); i++) { - fieldToIndex[CalculateFNV(m_query.getColumnName(i))] = i; - } -} - -void CMinimapDataDB::StatementFieldHolder::setInputs() { - this->m_query.reset(); -} - -template -void CMinimapDataDB::StatementFieldHolder::setInputs(Ts &&... inputs) { - int i = 1; - this->m_query.reset(); - ((this->m_query.bind(i++, inputs)), ...); -} - -bool CMinimapDataDB::StatementFieldHolder::execute() { - return m_query.executeStep(); -} -SQLite::Column CMinimapDataDB::StatementFieldHolder::getField(const HashedString fieldName) { - int index = getFieldIndex(fieldName); - - if (index >= 0) { - return m_query.getColumn(index); - } else { - throw SQLite::Exception("Field was not found in query"); - } -} - -const std::string getAllScenariosSQL = -R"===( - select s.id, s.orientation, s.name, - s.ocean_color_0, s.ocean_color_1, s.ocean_color_2, s.ocean_color_3, - s.world_coord_min_x, s.world_coord_min_y, s.world_coord_max_x, s.world_coord_max_y, - s.image_width, s.image_height, s.zoom, s.folderToSave from scenarios s; -)==="; - -const std::string insertNewScenariosSQL = -R"===( - insert into scenarios (name, - orientation, - ocean_color_0, ocean_color_1, ocean_color_2, ocean_color_3, - world_coord_min_x, world_coord_min_y, world_coord_max_x, world_coord_max_y, - image_width, image_height, zoom, folderToSave) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); -)==="; - -const std::string updateScenarioSQL = -R"===( - update scenarios set name = ?, map_id = ?, orientation = ?, - ocean_color_0 = ?, ocean_color_1 = ?, ocean_color_2 = ?, ocean_color_3 = ?, - world_coord_min_x = ?, world_coord_min_y = ?, world_coord_max_x = ?, world_coord_max_y = ?, - image_width = ?, image_height = ?, zoom = ?, folderToSave = ? - where id = ?; -)==="; - -const std::string getADTBoundingBoxSQL = -R"===( -select abb.adt_x, abb.adt_y, - abb.min_z, - abb.max_z from adt_bounding_boxes abb - where map_id = ? -)==="; - -const std::string insertADTBoundingBoxesSQL = - R"===( - insert into adt_bounding_boxes(map_id, - adt_x, adt_y, - min_z, max_z) - values (?, ?, ?, ?, ?) -)==="; - -const std::string getMapDefSQL = - R"===( - select - smd.map_id, - smd.deltaX, smd.deltaY, smd.deltaZ - from scenario_map_def smd - where smd.scenario_id = ? -)==="; - -const std::string insertMapDefSQL = - R"===( - insert into scenario_map_def( - scenario_id, - map_id, - deltaX, deltaY, deltaZ) - values (?, ?, ?, ?, ?) -)==="; - -const std::string updateMapDefSQL = - R"===( - update scenario_map_def set map_id = ?, - deltaX = ?, deltaY = ?, deltaZ = ? - where scenario_id = ? -)==="; - -const std::string getAdtExcludedSQL = -R"===( - select - exl.adt_x, exl.adt_y, - exl.chunk_x, exl.chunk_y - from scenario_map_def_excluded_adt exl - where exl.map_definition_id = ? -)==="; - -const std::string insertAdtExcludedSQL = - R"===( - insert into scenario_map_def_excluded_adt(map_definition_id, - adt_x, adt_y, - chunk_x, chunk_y) - values (?, ?, ?, ?, ?) -)==="; - -CMinimapDataDB::CMinimapDataDB(const std::string &fileName) : - m_sqliteDatabase(fileName, SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE), - getAllScenarios(InitDB(m_sqliteDatabase), getAllScenariosSQL), - insertNewScenario(InitDB(m_sqliteDatabase), insertNewScenariosSQL), - updateScenario(InitDB(m_sqliteDatabase), updateScenarioSQL), - getADTBoundingBoxes(InitDB(m_sqliteDatabase), getADTBoundingBoxSQL), - insertADTBoundingBoxes(InitDB(m_sqliteDatabase), insertADTBoundingBoxesSQL), - - getMapDef(InitDB(m_sqliteDatabase), getMapDefSQL), - insertNewMapDef(InitDB(m_sqliteDatabase), insertMapDefSQL), - updateMapDef(InitDB(m_sqliteDatabase), updateMapDefSQL), - - getADTExcluded(InitDB(m_sqliteDatabase), getAdtExcludedSQL), - insertADTExcluded(InitDB(m_sqliteDatabase), insertAdtExcludedSQL) -{ +CMinimapDataDB::DataBaseClass::DataBaseClass(const std::string &fileName) : m_storage(makeStorage(fileName)) { char *sErrMsg = ""; // sqlite3_exec(m_sqliteDatabase.getHandle(), "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg); // sqlite3_exec(m_sqliteDatabase.getHandle(), "PRAGMA schema.journal_mode = MEMORY", NULL, NULL, &sErrMsg); -} - -void CMinimapDataDB::getScenarios(std::vector &scenarioList) { - if (!m_sqliteDatabase.tableExists("scenarios")) - return; - - getAllScenarios.setInputs(); - while (getAllScenarios.execute()) - { - ScenarioDef scenarioDef; - - scenarioDef.id = getAllScenarios.getField("id").getInt(); - - scenarioDef.orientation = static_cast(getAllScenarios.getField("orientation").getInt()); - scenarioDef.name = getAllScenarios.getField("name").getString(); - scenarioDef.closeOceanColor = mathfu::vec4( - getAllScenarios.getField("ocean_color_0").getDouble(), - getAllScenarios.getField("ocean_color_1").getDouble(), - getAllScenarios.getField("ocean_color_2").getDouble(), - getAllScenarios.getField("ocean_color_3").getDouble() - ); - scenarioDef.minWowWorldCoord = mathfu::vec2(getAllScenarios.getField("world_coord_min_x").getDouble(), - getAllScenarios.getField("world_coord_min_y").getDouble()); - scenarioDef.maxWowWorldCoord = mathfu::vec2(getAllScenarios.getField("world_coord_max_x").getDouble(), - getAllScenarios.getField("world_coord_max_y").getDouble()); - - scenarioDef.imageWidth = getAllScenarios.getField("image_width").getInt(); - scenarioDef.imageHeight = getAllScenarios.getField("image_height").getInt(); - - scenarioDef.zoom = getAllScenarios.getField("zoom").getDouble(); - scenarioDef.folderToSave = getAllScenarios.getField("folderToSave").getDouble(); + m_storage.sync_schema(true); +} - scenarioList.push_back(scenarioDef); - } +void CMinimapDataDB::DataBaseClass::getScenarios(std::vector &scenarioList) { + scenarioList = m_storage.get_all(); for (auto &scenario : scenarioList) { this->getMapRenderDef(scenario.id, scenario.maps); } } -void CMinimapDataDB::saveScenarios(std::vector &scenarios) { - SQLite::Transaction transaction(m_sqliteDatabase); - +void CMinimapDataDB::DataBaseClass::saveScenarios(std::vector &scenarios) { for (auto &scenario : scenarios) { saveScenario(scenario); } - - // Commit transaction - transaction.commit(); } -void CMinimapDataDB::saveScenario(ScenarioDef &scenario) { - SQLite::Transaction transaction(m_sqliteDatabase); - - if (scenario.id == -1) { - insertNewScenario.setInputs( - scenario.name, - (int) scenario.orientation, - scenario.closeOceanColor.x, - scenario.closeOceanColor.y, - scenario.closeOceanColor.z, - scenario.closeOceanColor.w, - scenario.minWowWorldCoord.x, - scenario.minWowWorldCoord.y, - scenario.maxWowWorldCoord.x, - scenario.maxWowWorldCoord.y, - scenario.imageWidth, - scenario.imageHeight, - scenario.zoom, - scenario.folderToSave.c_str() - ); +void CMinimapDataDB::DataBaseClass::saveScenario(ScenarioDef &scenario) { + using namespace sqlite_orm; - if (insertNewScenario.execute()) { - scenario.id = m_sqliteDatabase.getLastInsertRowid(); - } + auto &scenarioId = scenario.id; + if(m_storage.count(where(c(&ScenarioDef::id) == scenarioId))) { + m_storage.update(scenario); } else { - updateScenario.setInputs( - scenario.name, - (int) scenario.orientation, - scenario.closeOceanColor.x, - scenario.closeOceanColor.y, - scenario.closeOceanColor.z, - scenario.closeOceanColor.w, - scenario.minWowWorldCoord.x, - scenario.minWowWorldCoord.y, - scenario.maxWowWorldCoord.x, - scenario.maxWowWorldCoord.y, - scenario.imageWidth, - scenario.imageHeight, - scenario.zoom, - scenario.folderToSave.c_str(), - scenario.id - ); - - updateScenario.execute(); + scenarioId = m_storage.insert(scenario); } - // Commit transaction - transaction.commit(); //Save arrays for (auto &mapDef : scenario.maps) { - saveMapRenderDef(scenario.id, mapDef); + saveMapRenderDef(scenarioId, mapDef); } } -void CMinimapDataDB::getAdtBoundingBoxes(MapRenderDef& mapRenderDef) { - getADTBoundingBoxes.setInputs(mapRenderDef.mapId); - - while (getADTBoundingBoxes.execute()) - { - int adt_x = getADTBoundingBoxes.getField("adt_x").getInt(); - int adt_y = getADTBoundingBoxes.getField("adt_y").getInt(); +void CMinimapDataDB::DataBaseClass::getAdtBoundingBoxes(MapRenderDef& mapRenderDef) { + using namespace sqlite_orm; + auto adtBoundingBoxesDB = m_storage.get_all(where(c(&ADTBoundingBoxDB::map_id) == mapRenderDef.mapId)); - mapRenderDef.adtConfigHolder->adtMinZ[adt_x][adt_y] = getADTBoundingBoxes.getField("min_z").getDouble(); - mapRenderDef.adtConfigHolder->adtMaxZ[adt_x][adt_y] = getADTBoundingBoxes.getField("max_z").getDouble(); + for (auto &adtBoundingBoxeDB : adtBoundingBoxesDB) { + mapRenderDef.adtConfigHolder->adtMinZ[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = adtBoundingBoxeDB.adtMin_z; + mapRenderDef.adtConfigHolder->adtMaxZ[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = adtBoundingBoxeDB.adtMax_z; } } -void CMinimapDataDB::saveAdtBoundingBoxes(MapRenderDef& mapRenderDef) { - SQLite::Transaction transaction(m_sqliteDatabase); +void CMinimapDataDB::DataBaseClass::saveAdtBoundingBoxes(MapRenderDef& mapRenderDef) { + using namespace sqlite_orm; - //1. Clear all records for that mapId from DB - { - SQLite::Statement cleanABB(m_sqliteDatabase, - "delete from adt_bounding_boxes where map_id = ?" - ); - cleanABB.exec(); - } + m_storage.remove_all(where(c(&ADTBoundingBoxDB::map_id) == mapRenderDef.mapId)); //2. Insert into database for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { - insertADTBoundingBoxes.setInputs(mapRenderDef.mapId, i, j, - mapRenderDef.adtConfigHolder->adtMinZ[i][j], - mapRenderDef.adtConfigHolder->adtMaxZ[i][j]); - insertADTBoundingBoxes.execute(); + ADTBoundingBoxDB boxDb; + boxDb.map_id = mapRenderDef.mapId; + boxDb.adt_x = i; + boxDb.adt_y = j; + boxDb.adtMin_z = mapRenderDef.adtConfigHolder->adtMinZ[i][j]; + boxDb.adtMax_z = mapRenderDef.adtConfigHolder->adtMaxZ[i][j]; + + m_storage.insert(boxDb); } } - - //3. Commit transaction - transaction.commit(); } -void CMinimapDataDB::getAdtExcluded(MapRenderDef& mapRenderDef) { - getADTExcluded.setInputs(mapRenderDef.id); - - while (getADTExcluded.execute()) - { - int adt_x = c.getField("adt_x").getInt(); - int adt_y = getADTExcluded.getField("adt_y").getInt(); - int chunk_x = getADTExcluded.getField("chunk_x").getInt(); - int chunk_y = getADTExcluded.getField("chunk_y").getInt(); +void CMinimapDataDB::DataBaseClass::getAdtExcluded(MapRenderDef& mapRenderDef) { + using namespace sqlite_orm; + auto excludedADTAndChunks = m_storage.get_all( + where(c(&ExcludedADT_and_chunk_DB::map_definition_id) == mapRenderDef.id) + ); - AdtCell adtCell = {adt_x, adt_y}; - AdtCell chunkCell = {chunk_x, chunk_y}; - if (chunk_x == -1 || chunk_y == -1) {\ - mapRenderDef.adtConfigHolder->excludedADTs.insert(adtCell); + for (auto &excludedADTAndChunk : excludedADTAndChunks) { + if (excludedADTAndChunk.chunk_x == -1 && excludedADTAndChunk.chunk_y == -1) { + mapRenderDef.adtConfigHolder->excludedADTs.insert({excludedADTAndChunk.adt_x, excludedADTAndChunk.adt_y}); } else { - mapRenderDef.adtConfigHolder->excludedChunksPerADTs[adtCell].insert(chunkCell); + mapRenderDef.adtConfigHolder-> + excludedChunksPerADTs[{excludedADTAndChunk.adt_x, excludedADTAndChunk.adt_y}] + .insert({excludedADTAndChunk.chunk_x, excludedADTAndChunk.chunk_y}); } } } -void CMinimapDataDB::saveAdtExcluded(MapRenderDef& mapRenderDef){ - SQLite::Transaction transaction(m_sqliteDatabase); +void CMinimapDataDB::DataBaseClass::saveAdtExcluded(MapRenderDef& mapRenderDef){ + using namespace sqlite_orm; + m_storage.remove_all(where(c(&ExcludedADT_and_chunk_DB::map_definition_id) == mapRenderDef.id)); - //1. Clear all records for that mapId from DB - { - SQLite::Statement cleanABB(m_sqliteDatabase, - "delete from adt_bounding_boxes where map_id = ?" - ); - cleanABB.exec(); - } + for (auto &excludedADT : mapRenderDef.adtConfigHolder->excludedADTs) { + ExcludedADT_and_chunk_DB adtAndChunkDb; + adtAndChunkDb.map_definition_id = mapRenderDef.id; + adtAndChunkDb.adt_x = excludedADT[0]; + adtAndChunkDb.adt_y = excludedADT[1]; + adtAndChunkDb.chunk_x = -1; + adtAndChunkDb.chunk_y = -1; - //2. Insert into database - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - insertADTBoundingBoxes.setInputs(mapRenderDef.mapId, i, j, - mapRenderDef.adtConfigHolder->adtMinZ[i][j], - mapRenderDef.adtConfigHolder->adtMaxZ[i][j]); - insertADTBoundingBoxes.execute(); - } - } - - //3. Commit transaction - transaction.commit(); -} - -void CMinimapDataDB::getRiverColorOverrides(int mapId, std::vector &riverOverrides) { -// SQLite::Statement getRiverColor(m_sqliteDatabase, -// "select rco.liquid_id, rco.color_0, rco.color_1, rco.color_2, rco.color_3 " -// " from river_color_overrides rco where rco.map_id = ?;" -// ); -// getRiverColor.reset(); -// getRiverColor.bind(1, mapId); -// -// while (getRiverColor.executeStep()) -// { -// RiverColorOverride colorOverride; -// colorOverride.liquidId = getRiverColor.getColumn(0).getInt(); -// colorOverride.color = mathfu::vec4( -// getRiverColor.getColumn(1).getDouble(), -// getRiverColor.getColumn(2).getDouble(), -// getRiverColor.getColumn(3).getDouble(), -// getRiverColor.getColumn(4).getDouble() -// ); -// riverOverrides.push_back(colorOverride); -// } -} - -void CMinimapDataDB::saveRiverColorOverrides(int mapId, std::vector &riverOverrides) { -// SQLite::Transaction transaction(m_sqliteDatabase); -// -// //1. Clear all records for that mapId from DB -// { -// SQLite::Statement cleanRiverColor(m_sqliteDatabase, -// "delete from river_color_overrides where map_id = ?" -// ); -// cleanRiverColor.bind(1, mapId); -// cleanRiverColor.exec(); -// } -// -// SQLite::Statement saveRiverColor(m_sqliteDatabase, "insert into river_color_overrides(map_id, liquid_id, " -// "color_0, color_1, color_2, color_3) \n" -// "values (?, ?, ?, ?, ?, ?);"); -// -// for (int j = 0; j < riverOverrides.size(); j++) { -// auto &roRec = riverOverrides[j]; -// saveRiverColor.reset(); -// -// saveRiverColor.bind(1, mapId); -// saveRiverColor.bind(2, roRec.liquidId); -// saveRiverColor.bind(3, roRec.color.x); -// saveRiverColor.bind(4, roRec.color.y); -// saveRiverColor.bind(5, roRec.color.z); -// saveRiverColor.bind(6, roRec.color.w); -// -// saveRiverColor.exec(); -// } -// transaction.commit(); -} - -SQLite::Database &CMinimapDataDB::InitDB(SQLite::Database &database) { - - //------------------------------- - // Create Scenario table - // ------------------------------ - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS scenarios\n" - "(\n" - " id INTEGER PRIMARY KEY,\n" - " name VARCHAR(256),\n" - " orientation INTEGER,\n" - " ocean_color_0 FLOAT,\n" - " ocean_color_1 FLOAT,\n" - " ocean_color_2 FLOAT,\n" - " ocean_color_3 FLOAT,\n" - " world_coord_min_x FLOAT,\n" - " world_coord_min_y FLOAT,\n" - " world_coord_max_x FLOAT,\n" - " world_coord_max_y FLOAT,\n" - " image_height INTEGER,\n" - " image_width INTEGER,\n" - " zoom FLOAT,\n" - " folderToSave VARCHAR(256)\n" - ");"); - - transaction.commit(); - } - - //------------------------------- - // Create Bounding boxes table - // ------------------------------ - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS adt_bounding_boxes (\n" - " id INTEGER PRIMARY KEY,\n" - " map_id INTEGER,\n" - " adt_x INTEGER,\n" - " adt_y INTEGER,\n" - " min_z FLOAT,\n" - " max_z FLOAT\n" - ")"); - - transaction.commit(); - } - - //------------------------------- - // Create map definition per scenario - // ------------------------------ - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def (\n" - " scenario_id INTEGER,\n" - " map_id INTEGER,\n" - " deltaX DOUBLE,\n" - " deltaY DOUBLE,\n" - " deltaZ DOUBLE\n" - ")"); - - transaction.commit(); - } - - //------------------------------- - // Create excluded ADTs per map_def - // ------------------------------ - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def (\n" - " id INTEGER PRIMARY KEY,\n" - " map_definition_id INTEGER,\n" - " adt_x INTEGER,\n" - " adt_y INTEGER\n" - ")"); - - transaction.commit(); + m_storage.insert(adtAndChunkDb); } - //------------------------------- - // Create excluded ADT CELLS/chunks per map_def - // ------------------------------ - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS scenario_map_def_excluded_adt (\n" - " map_definition_id INTEGER,\n" - " adt_x INTEGER,\n" - " adt_y INTEGER,\n" - " chunk_x INTEGER,\n" - " chunk_y INTEGER\n" - ")"); - - transaction.commit(); - } + for (auto &excludedADTChunk : mapRenderDef.adtConfigHolder->excludedChunksPerADTs) { + ExcludedADT_and_chunk_DB adtAndChunkDb; + adtAndChunkDb.map_definition_id = mapRenderDef.id; + adtAndChunkDb.adt_x = excludedADTChunk.first[0]; + adtAndChunkDb.adt_y = excludedADTChunk.first[1]; + for (auto &chunk : excludedADTChunk.second) { + adtAndChunkDb.chunk_x = chunk[0]; + adtAndChunkDb.chunk_y = chunk[1]; - - //------------------------------- - // Create river color overrides - // ------------------------------ - - { - SQLite::Transaction transaction(database); - - database.exec("CREATE TABLE IF NOT EXISTS river_color_overrides\n" - "(\n" - " id INTEGER PRIMARY KEY,\n" - " map_id INTEGER,\n" - " liquid_id INTEGER,\n" - " color_0 FLOAT,\n" - " color_1 FLOAT,\n" - " color_2 FLOAT,\n" - " color_3 FLOAT\n" - ")"); - - transaction.commit(); + m_storage.insert(adtAndChunkDb); + } } - - return database; } -void CMinimapDataDB::getMapRenderDef(int scenarioId, std::vector &mapRenderDefs) { - getMapDef.setInputs(scenarioId); +void CMinimapDataDB::DataBaseClass::getMapRenderDef(int scenarioId, std::vector &mapRenderDefs) { + using namespace sqlite_orm; - while (getMapDef.execute()) { + mapRenderDefs.clear(); + auto mapRenderDefsDB = m_storage.get_all(where(c(&MapRenderDefDB::scenarioId) == scenarioId)); + for (auto const &mapRenderDefDB : mapRenderDefsDB) { auto &mapRenderDef = mapRenderDefs.emplace_back(); - mapRenderDef.mapId = getMapDef.getField("map_id").getInt(); - mapRenderDef.deltaX = getMapDef.getField("deltaX").getDouble(); - mapRenderDef.deltaY = getMapDef.getField("deltaY").getDouble(); - mapRenderDef.deltaZ = getMapDef.getField("deltaZ").getDouble(); + mapRenderDef.id = mapRenderDefDB.id; + mapRenderDef.mapId = mapRenderDefDB.mapId; + mapRenderDef.deltaX = mapRenderDefDB.deltaX; + mapRenderDef.deltaY = mapRenderDefDB.deltaY; + mapRenderDef.deltaZ = mapRenderDefDB.deltaZ; } for (auto &mapRenderDef : mapRenderDefs) { @@ -525,33 +140,22 @@ void CMinimapDataDB::getMapRenderDef(int scenarioId, std::vector & } } -void CMinimapDataDB::saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef) { - SQLite::Transaction transaction(m_sqliteDatabase); +void CMinimapDataDB::DataBaseClass::saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef) { + MapRenderDefDB defDb; + defDb.id = mapRenderDef.id; + defDb.mapId = mapRenderDef.mapId; + defDb.scenarioId = scenarioId; + defDb.deltaX = mapRenderDef.deltaX; + defDb.deltaY = mapRenderDef.deltaY; + defDb.deltaZ = mapRenderDef.deltaZ; - if (mapRenderDef.id == -1) { - insertNewMapDef.setInputs( - scenarioId, - mapRenderDef.mapId, - mapRenderDef.deltaX, - mapRenderDef.deltaY, - mapRenderDef.deltaZ - ); - - if (insertNewMapDef.execute()) { - mapRenderDef.id = m_sqliteDatabase.getLastInsertRowid(); - } + if(defDb.id >= 0) { + m_storage.update(defDb); } else { - updateMapDef.setInputs( - mapRenderDef.mapId, - mapRenderDef.deltaX, - mapRenderDef.deltaY, - mapRenderDef.deltaZ - ); - - updateScenario.execute(); + mapRenderDef.id = m_storage.insert(defDb); } - // Commit transaction - transaction.commit(); saveAdtExcluded(mapRenderDef); -} \ No newline at end of file + saveAdtBoundingBoxes(mapRenderDef); +} + diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index 061daf41a..e7fa66670 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -5,81 +5,114 @@ #ifndef AWEBWOWVIEWERCPP_CMINIMAPDATADB_H #define AWEBWOWVIEWERCPP_CMINIMAPDATADB_H -#include +#include "../../../3rdparty/sqlite_orm//sqlite_orm.h" #include "../entities.h" #include "../minimapGenerator.h" -#include "../../../wowViewerLib/src/engine/algorithms/hashString.h" - +namespace CMinimapDataDB { + //Intermediate structures for storing/loading data from/to DB + struct ADTBoundingBoxDB { + int map_id; + int adt_x; + int adt_y; + float adtMin_z; + float adtMax_z; + }; -class CMinimapDataDB { -private: - SQLite::Database m_sqliteDatabase; -public: - explicit CMinimapDataDB(const std::string &fileName); + struct MapRenderDefDB { + int id = -1; + int scenarioId = -1; - //Scenarios - void getScenarios(std::vector &scenarioList); - void saveScenarios(std::vector &scenarios); + int mapId = -1; - //ADT Bounding boxes - void getMapRenderDef(int scenarioId, std::vector &mapRenderDef); - void saveMapRenderDef(int scenarioId, MapRenderDef& mapRenderDef); + double deltaX = 0.0f; + double deltaY = 0.0f; + double deltaZ = 0.0f; + }; - void getAdtBoundingBoxes(MapRenderDef& mapRenderDef); - void saveAdtBoundingBoxes(MapRenderDef& mapRenderDef); + struct MapRenderDefPhases { + int mapRenderDefId = -1; + int mapId = -1; + }; - void getAdtExcluded(MapRenderDef& mapRenderDef); - void saveAdtExcluded(MapRenderDef& mapRenderDef); + struct ExcludedADT_and_chunk_DB { + int map_definition_id; + int adt_x; + int adt_y; + int chunk_x; + int chunk_y; + }; - //River color overrides - void getRiverColorOverrides(int mapId, std::vector &riverOverrides); - void saveRiverColorOverrides(int mapId, std::vector &riverOverrides); + //Function that creates storage + inline static auto makeStorage(const std::string &dataBaseFile) { + using namespace sqlite_orm; + return make_storage(dataBaseFile, + make_table("scenarios", + make_column("id", &ScenarioDef::id, autoincrement(), primary_key()), + make_column("name", &ScenarioDef::name), make_column("orientation", &ScenarioDef::getOrientation, &ScenarioDef::setOrientation), + make_column("close_ocean_color_r", &ScenarioDef::getCloseOceanColor_R, &ScenarioDef::setCloseOceanColor_R), + make_column("close_ocean_color_g", &ScenarioDef::getCloseOceanColor_G, &ScenarioDef::setCloseOceanColor_G), + make_column("close_ocean_color_b", &ScenarioDef::getCloseOceanColor_B, &ScenarioDef::setCloseOceanColor_B), + make_column("world_coord_min_x", &ScenarioDef::getMinWowWorldCoordX, &ScenarioDef::setMinWowWorldCoordX), + make_column("world_coord_min_y", &ScenarioDef::getMinWowWorldCoordY, &ScenarioDef::setMinWowWorldCoordY), + make_column("world_coord_max_x", &ScenarioDef::getMaxWowWorldCoordX, &ScenarioDef::setMaxWowWorldCoordX), + make_column("world_coord_max_y", &ScenarioDef::getMaxWowWorldCoordY, &ScenarioDef::setMaxWowWorldCoordY), + make_column("image_height", &ScenarioDef::imageHeight), + make_column("image_width", &ScenarioDef::imageWidth), + make_column("zoom", &ScenarioDef::zoom), + make_column("folder_to_save", &ScenarioDef::folderToSave) + ), + make_table("scenario_map_def", + make_column("id", &MapRenderDefDB::id, autoincrement(), primary_key()), + make_column("map_id", &MapRenderDefDB::mapId), + make_column("scenario_id", &MapRenderDefDB::scenarioId), + make_column("delta_x", &MapRenderDefDB::deltaX), + make_column("delta_y", &MapRenderDefDB::deltaY), + make_column("delta_z", &MapRenderDefDB::deltaZ) + ), + make_table("scenario_map_def_excluded_adt", + make_column("map_definition_id", &ExcludedADT_and_chunk_DB::map_definition_id), + make_column("adt_x", &ExcludedADT_and_chunk_DB::adt_x), + make_column("adt_y", &ExcludedADT_and_chunk_DB::adt_y), + make_column("chunk_x", &ExcludedADT_and_chunk_DB::chunk_x), + make_column("chunk_y", &ExcludedADT_and_chunk_DB::chunk_y) + ), + make_table("map_bounding_box", + make_column("map_id", &ADTBoundingBoxDB::map_id), + make_column("adt_x", &ADTBoundingBoxDB::adt_x), + make_column("adt_y", &ADTBoundingBoxDB::adt_y), + make_column("adt_min_z", &ADTBoundingBoxDB::adtMin_z), + make_column("adt_max_z", &ADTBoundingBoxDB::adtMax_z) + ) + ); + }; - //Get WMO ADT aabb override - bool getWmoAABBOverride(int mapId, int uniqueId, CAaBox &aaBox); - void saveWmoAABBOverride(int mapId, int uniqueId, const CAaBox &aaBox); -private: - class StatementFieldHolder { + class DataBaseClass { public: - StatementFieldHolder(SQLite::Database &database, const std::string &query); - - template - void setInputs(Ts && ... inputs); - - void setInputs(); - bool execute(); - SQLite::Column getField(HashedString fieldName); - inline int getFieldIndex(HashedString fieldName) { - auto it = fieldToIndex.find(fieldName.Hash()); - if(it != fieldToIndex.end()) { - return it->second; - } else { - return -1; - } - } - private: - SQLite::Statement m_query; - std::unordered_map fieldToIndex; - }; + explicit DataBaseClass(const std::string &fileName); + + //Scenarios + void getScenarios(std::vector &scenarioList); + void saveScenario(ScenarioDef &scenario); + void saveScenarios(std::vector &scenarios); - SQLite::Database &InitDB(SQLite::Database &database); + //Map defs + void getMapRenderDef(int scenarioId, std::vector &mapRenderDef); + void saveMapRenderDef(int scenarioId, MapRenderDef &mapRenderDef); - StatementFieldHolder getAllScenarios; - StatementFieldHolder insertNewScenario; - StatementFieldHolder updateScenario; - StatementFieldHolder getADTBoundingBoxes; - StatementFieldHolder insertADTBoundingBoxes; + //Active phase - StatementFieldHolder getMapDef; - StatementFieldHolder insertNewMapDef; - StatementFieldHolder updateMapDef; + //ADT Bounding Boxes + void getAdtBoundingBoxes(MapRenderDef &mapRenderDef); + void saveAdtBoundingBoxes(MapRenderDef &mapRenderDef); - StatementFieldHolder getADTExcluded; - StatementFieldHolder insertADTExcluded; + void getAdtExcluded(MapRenderDef &mapRenderDef); + void saveAdtExcluded(MapRenderDef &mapRenderDef); - void saveScenario(ScenarioDef &scenario); -}; + private: + decltype(makeStorage("")) m_storage; + }; +} #endif //AWEBWOWVIEWERCPP_CMINIMAPDATADB_H diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index f62ba6b76..c2431b937 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -552,7 +552,7 @@ void FrontendUI::showMainMenu() { if (ImGui::MenuItem("Open settings")) {showSettings = true;} if (ImGui::MenuItem("Open QuickLinks")) {showQuickLinks = true;} if (ImGui::MenuItem("Open MapConstruction")) {showMapConstruction = true;} - if (ImGui::MenuItem("Open minimap generator")) { + if (ImGui::MenuItem("Open minimap generator", "", false, cascOpened)) { showMinimapGeneratorSettings = true; } if (ImGui::MenuItem("Test export")) { @@ -679,7 +679,7 @@ std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneTyp // m_usePlanarCamera = cameraNum == -1; - return std::make_shared(apiContainer, name , cameraNum); + return std::make_shared(apiContainer, name); } else if (sceneType == 1) { return std::make_shared(apiContainer, name); } else if (sceneType == 2) { @@ -1290,7 +1290,7 @@ void FrontendUI::showSettingsDialog() { //#define logExecution { \ // std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ //} -void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) { +void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { auto m_device = m_api->hDevice; logExecution @@ -1787,7 +1787,7 @@ void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementTextureIds) { - currentScene = std::make_shared(m_api, m2Fdid, -1); + currentScene = std::make_shared(m_api, m2Fdid); currentScene->setReplaceTextureArray(replacementTextureIds); @@ -1798,7 +1798,7 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText m_api->camera->setCameraPos(0, 0, 0); } void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { - currentScene = std::make_shared(m_api, m2FileName, -1); + currentScene = std::make_shared(m_api, m2FileName); currentScene->setReplaceTextureArray(replacementTextureIds); m_api->camera = std::make_shared(); diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 2629cf55b..7006204b0 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -57,7 +57,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &meshIds) override {}; - void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override; + void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; void produceUpdateStage(HUpdateStage &updateStage) override; void checkCulling(HCullStage &cullStage) override {}; diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 4ade69ec5..47eb7f946 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -114,7 +114,9 @@ void MinimapGenerationWindow::renderMapConfigSubWindow(int mapIndex) { auto &mapRenderDef = sceneDef->maps[mapIndex]; ImGui::BeginGroupPanel(("Map" + std::to_string(mapIndex)).c_str()); - ImGui::InputInt(("Map Id##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.mapId); + if (ImGui::InputInt(("Map Id##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.mapId)) { + m_minimapDB->getAdtBoundingBoxes(mapRenderDef); + } ImGui::InputDouble(("Delta X##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaX); ImGui::InputDouble(("Delta Y##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaY); ImGui::InputDouble(("Delta Z##"+ std::to_string(mapIndex)).c_str(), &mapRenderDef.deltaZ); @@ -323,6 +325,16 @@ HDrawStage MinimapGenerationWindow::getDrawStage(HFrameScenario sceneScenario) { } } +template +inline std::array to_array(const V& v) +{ + assert(v.size() <= N); + std::array d = {0}; + using std::begin; using std::end; + std::copy( begin(v), end(v), begin(d) ); // this is the recommended way + return d; +} + void MinimapGenerationWindow::renderEditTab() { if (ImGui::BeginTabItem("Edit", &editTabOpened, ImGuiTabItemFlags_SetSelected)) { { @@ -330,7 +342,17 @@ void MinimapGenerationWindow::renderEditTab() { if (sceneDef->name.size() > 128) sceneDef->name.resize(128); std::copy(sceneDef->name.begin(), sceneDef->name.end(), scenarioName.data()); if (ImGui::InputText("Scenario name", scenarioName.data(), 128)) { - sceneDef->name = std::string(std::begin(scenarioName), std::end(scenarioName)); + scenarioName[127] = 0; + sceneDef->name = std::string(scenarioName.data()); + } + + if (sceneDef->folderToSave.size() > 128) sceneDef->folderToSave.resize(128); + std::array folderToSave = to_array(sceneDef->folderToSave); + + if (ImGui::InputText("Folder for saving", folderToSave.data(), 128)) { + folderToSave[127] = 0; + sceneDef->folderToSave = std::string(folderToSave.data()); + trim(sceneDef->folderToSave); } { ImGui::BeginGroupPanel("Maps"); @@ -349,8 +371,6 @@ void MinimapGenerationWindow::renderEditTab() { ImGui::EndGroupPanel(); } - - ImGui::BeginGroupPanel("Orientation"); { if (ImGui::RadioButton("Ortho projection", &sceneDef->orientation, ScenarioOrientation::soTopDownOrtho)) { diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h index 2f7c1179e..3c13a2b19 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -17,7 +17,7 @@ class MinimapGenerationWindow { m_api = api; m_processor = processor; - m_minimapDB = std::make_shared("minimapdb.sqlite"); + m_minimapDB = std::make_shared("minimapdb.sqlite"); m_minimapDB->getScenarios(sceneDefList); createMinimapGenerator(); @@ -33,7 +33,7 @@ class MinimapGenerationWindow { bool &m_showMinimapGeneratorSettings; - std::shared_ptr m_minimapDB; + std::shared_ptr m_minimapDB; HMinimapGenerator minimapGenerator; std::vector sceneDefList; diff --git a/wowViewerLib/src/engine/SceneComposer.cpp b/wowViewerLib/src/engine/SceneComposer.cpp index e22d7009f..d70e3ddcb 100644 --- a/wowViewerLib/src/engine/SceneComposer.cpp +++ b/wowViewerLib/src/engine/SceneComposer.cpp @@ -151,7 +151,7 @@ void collectMeshes(HDrawStage drawStage, std::vector &meshes) { std::back_inserter(meshes) ); } - for (auto deps : drawStage->drawStageDependencies) { + for (auto &deps : drawStage->drawStageDependencies) { collectMeshes(deps, meshes); } } @@ -184,11 +184,11 @@ void SceneComposer::DoUpdate() { logExecution produceDrawStage.beginMeasurement(); logExecution - std::vector additionalChunks; + logExecution for (auto &link : frameScenario->drawStageLinks) { logExecution - link.scene->produceDrawStage(link.drawStage, link.updateStages, additionalChunks); + link.scene->produceDrawStage(link.drawStage, link.updateStages); logExecution } produceDrawStage.endMeasurement(); @@ -213,11 +213,11 @@ void SceneComposer::DoUpdate() { updateBuffersDeviceCNT.beginMeasurement(); logExecution - std::vector frameDepDataVec = {}; - logExecution - std::vector*> uniformChunkVec = {}; + std::vector*> uniformChunkVec; + std::vector frameDepDataVec; logExecution - for (auto updateStage : frameScenario->updateStages) { +// uniformChunkVec.push_back(&additionalChunks); + for (auto &updateStage : frameScenario->updateStages) { frameDepDataVec.push_back(updateStage->cullResult->frameDepedantData); uniformChunkVec.push_back(&updateStage->uniformBufferChunks); } diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index da3f9e49e..72e69dd82 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -144,8 +144,12 @@ inline bool feq(const float a, const float b, const float tolerance = ROUNDING_E return (a + tolerance >= b) && (a - tolerance <= b); } +inline float worldCoordinateToAdtIndexF(float x) { + return (32.0f - (x / MathHelper::TILESIZE)); +} + inline int worldCoordinateToAdtIndex(float x) { - return floor((32.0f - (x / MathHelper::TILESIZE))); + return floor(worldCoordinateToAdtIndexF(x)); } inline int worldCoordinateToGlobalAdtChunk(float x) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 8ae412313..22383eee6 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -838,15 +838,28 @@ void AdtObject::collectMeshesLod(std::vector &renderedThisFrame) { */ } + +FileStatus AdtObject::getLoadedStatus() { + const std::array, 5> filesToCheck = { + m_adtFile, m_adtFileObj, m_adtFileObjLod, m_adtFileLod, m_adtFileTex + }; + + for (auto &fileToCheck : filesToCheck) { + if (fileToCheck == nullptr) continue; + if (fileToCheck->getStatus()==FileStatus::FSRejected) { + return FileStatus::FSRejected; + } + if (fileToCheck->getStatus()==FileStatus::FSNotLoaded) { + return FileStatus::FSNotLoaded; + } + } + return FileStatus::FSLoaded; +} + + void AdtObject::doPostLoad() { -// std::cout << "AdtObject::doPostLoad finished called" << std::endl; if (!m_loaded) { - if (m_adtFile->getStatus()==FileStatus::FSLoaded && - m_adtFileObj->getStatus()==FileStatus::FSLoaded && - m_adtFileObj->getStatus()==FileStatus::FSLoaded && - m_adtFileObjLod->getStatus()==FileStatus::FSLoaded && - ((m_adtFileLod != nullptr && m_adtFileLod->getStatus()==FileStatus::FSLoaded) || !m_wdtFile->mphd->flags.unk_0x0100) && - m_adtFileTex->getStatus()==FileStatus::FSLoaded) { + if (getLoadedStatus() == FileStatus::FSLoaded) { this->loadingFinished(); m_loaded = true; } @@ -1364,7 +1377,7 @@ AdtObject::AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDa m_adtFileTex = m_api->cacheStorage->getAdtGeomCache()->getFileId(fileDataIDs.tex0ADT); m_adtFileObj = m_api->cacheStorage->getAdtGeomCache()->getFileId(fileDataIDs.obj0ADT); m_adtFileObjLod = m_api->cacheStorage->getAdtGeomCache()->getFileId(fileDataIDs.obj1ADT); - if (fileDataIDs.lodADT != 0) { + if (fileDataIDs.lodADT != 0 && m_wdtFile->mphd->flags.unk_0x0100) { m_adtFileLod = m_api->cacheStorage->getAdtGeomCache()->getFileId(fileDataIDs.lodADT); } else { m_adtFileLod = nullptr; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index f4f59acd6..0b07c907a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -41,6 +41,8 @@ class AdtObject { m_mapApi = api; } + FileStatus getLoadedStatus(); + void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void collectMeshesLod(std::vector &renderedThisFrame); diff --git a/wowViewerLib/src/engine/objects/iScene.h b/wowViewerLib/src/engine/objects/iScene.h index 575dc7e2c..c41819bcb 100644 --- a/wowViewerLib/src/engine/objects/iScene.h +++ b/wowViewerLib/src/engine/objects/iScene.h @@ -23,7 +23,7 @@ class IScene { virtual void setMeshIds(std::vector &meshIds) = 0; virtual void resetAnimation() = 0; - virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStage, std::vector &additionalChunks) = 0; + virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStage) = 0; virtual void produceUpdateStage(HUpdateStage &updateStage) = 0; virtual void checkCulling(HCullStage &cullStage) = 0; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 5ce0cfa3d..a90defbcf 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -30,7 +30,7 @@ class M2Object { public: friend class IExporter; - M2Object(HApiContainer api, bool isSkybox = false, bool overrideSkyModelMat = true) : m_api(api), m_m2Geom(nullptr), + M2Object(HApiContainer &api, bool isSkybox = false, bool overrideSkyModelMat = true) : m_api(api), m_m2Geom(nullptr), m_skinGeom(nullptr), m_animationManager(nullptr), m_boolSkybox(isSkybox), m_overrideSkyModelMat(overrideSkyModelMat) { } diff --git a/wowViewerLib/src/engine/objects/scenes/NullScene.h b/wowViewerLib/src/engine/objects/scenes/NullScene.h index c99e2742f..1f01814fb 100644 --- a/wowViewerLib/src/engine/objects/scenes/NullScene.h +++ b/wowViewerLib/src/engine/objects/scenes/NullScene.h @@ -16,7 +16,7 @@ class NullScene : public IScene { virtual void setMeshIds(std::vector &meshIds) override {}; virtual void produceUpdateStage(HUpdateStage &updateStage) override {}; - virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override { + virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override { resultDrawStage->transparentMeshes = std::make_shared(); resultDrawStage->opaqueMeshes = std::make_shared(); }; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index e5d050c2a..43e14e897 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -139,8 +139,8 @@ void updateCameraPosOnLoad(const HApiContainer &m_api, const std::shared_ptrgetConfig()->globalFog = EParameterSource::eConfig; } -M2Scene::M2Scene(HApiContainer api, int fileDataId, int cameraView) { - m_api = api; m_cameraView = cameraView; +M2Scene::M2Scene(HApiContainer api, int fileDataId) { + m_api = api; m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index b0dfab187..f8ad2a5a1 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -30,8 +30,8 @@ class M2Scene : public Map { StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; public: - explicit M2Scene(HApiContainer api, std::string m2Model, int cameraView = - 1); - explicit M2Scene(HApiContainer api, int fileDataId, int cameraView = - 1); + explicit M2Scene(HApiContainer api, std::string m2Model); + explicit M2Scene(HApiContainer api, int fileDataId); ~M2Scene() override { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index e37d81923..0f35d152f 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -288,6 +288,25 @@ HGVertexBufferBindings createSkyBindings(IDevice *device) { return skyBindings; } +Map::Map(HApiContainer api, int mapId, std::string mapName) { + initMapTiles(); + + m_mapId = mapId; m_api = api; this->mapName = mapName; + m_sceneMode = SceneMode::smMap; + createAdtFreeLamdas(); + + std::string wdtFileName = "world/maps/"+mapName+"/"+mapName+".wdt"; + std::string wdlFileName = "world/maps/"+mapName+"/"+mapName+".wdl"; + + m_wdtfile = api->cacheStorage->getWdtFileCache()->get(wdtFileName); + m_wdlObject = std::make_shared(api, wdlFileName); + m_wdlObject->setMapApi(this); + + loadZoneLights(); + + m_sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); +} + HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config *config, bool conusFor0x4Sky) { auto skyVs = device->createUniformBufferChunk(sizeof(DnSky::meshWideBlockVS)); skyVs->setUpdateHandler([config, conusFor0x4Sky](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { @@ -364,27 +383,14 @@ void Map::checkCulling(HCullStage &cullStage) { cullStage->adtArray = {}; cullStage->adtArray.reserve(adtRenderedThisFramePrev); -// size_t m2RenderedThisFramePrev = cullStage->m2Array.gesize(); -// cullStage->m2Array = {}; -// cullStage->m2Array.reserve(m2RenderedThisFramePrev); - -// size_t wmoRenderedThisFramePrev = cullStage->wmoGroupArray.size(); -// cullStage->wmoGroupArray = {}; -// cullStage->wmoGroupArray.reserve(wmoRenderedThisFramePrev); - - mathfu::mat4 viewPerspectiveMat = frustumMat*lookAtMat4; - mathfu::vec4 &camera4 = cameraPos; - auto oldPlanes = MathHelper::getFrustumClipsFromMatrix(viewPerspectiveMat); - - - auto newPlanes = MathHelper::getFrustumClipsFromMatrix(frustumMat); - for (int i = 0; i < newPlanes.size(); i++) { - newPlanes[i] = (lookAtMat4.Transpose().Inverse()) * newPlanes[i]; - } - +// auto oldPlanes = MathHelper::getFrustumClipsFromMatrix(viewPerspectiveMat); +// auto newPlanes = MathHelper::getFrustumClipsFromMatrix(frustumMat); +// for (int i = 0; i < newPlanes.size(); i++) { +// newPlanes[i] = (lookAtMat4.Transpose().Inverse()) * newPlanes[i]; +// } MathHelper::PlanesUndPoints planesUndPoints; planesUndPoints.planes = MathHelper::getFrustumClipsFromMatrix(viewPerspectiveMat); @@ -660,7 +666,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca // m_skyConeAlpha -= _light.blendCoef; m_skyConeAlpha -= _light.blendCoef; } - + if (_light.skyBoxFlags & 1) { skyBox->setOverrideAnimationPerc(config->currentTime / 2880.0, true); } @@ -1002,7 +1008,6 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } } } - void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, HCullStage &cullStage, @@ -1051,6 +1056,8 @@ void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData } } } + + void Map::getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAreaId) { areaId = 0; parentAreaId = 0; @@ -1077,7 +1084,6 @@ void Map::getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAr } } - void Map::checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, int viewRenderOrder, @@ -1200,11 +1206,11 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat } } - int adt_x_min = std::max(worldCoordinateToAdtIndex(maxy), 0); - int adt_x_max = std::min(worldCoordinateToAdtIndex(miny), 63); + int adt_x_min = std::max(std::floor(worldCoordinateToAdtIndexF(maxy)), 0); + int adt_x_max = std::min(std::ceil(worldCoordinateToAdtIndexF(miny)), 63); - int adt_y_min = std::max(worldCoordinateToAdtIndex(maxx), 0); - int adt_y_max = std::min(worldCoordinateToAdtIndex(minx), 63); + int adt_y_min = std::max(std::floor(worldCoordinateToAdtIndexF(maxx)), 0); + int adt_y_max = std::min(std::ceil(worldCoordinateToAdtIndexF(minx)), 63); @@ -1238,7 +1244,7 @@ void Map::checkADTCulling(int i, int j, CAaBox box = { C3Vector({AdtIndexToWorldCoordinate(j + 1) , AdtIndexToWorldCoordinate(i + 1), minZ}), - C3Vector({AdtIndexToWorldCoordinate(j) , AdtIndexToWorldCoordinate(j), maxZ}) + C3Vector({AdtIndexToWorldCoordinate(j) , AdtIndexToWorldCoordinate(i), maxZ}) }; bool bbCheck = MathHelper::checkFrustum( frustumData, box); @@ -1324,6 +1330,8 @@ void Map::createAdtFreeLamdas() { } + + void Map::doPostLoad(HCullStage &cullStage) { int processedThisFrame = 0; int wmoProcessedThisFrame = 0; @@ -1400,8 +1408,6 @@ void Map::doPostLoad(HCullStage &cullStage) { } }; - - void Map::update(HUpdateStage &updateStage) { mapUpdateCounter.beginMeasurement(); mathfu::vec3 cameraVec3 = updateStage->cameraMatrices->cameraPos.xyz(); @@ -1520,6 +1526,7 @@ std::shared_ptr Map::getM2Object(std::string fileName, SMDoodadDef &do return nullptr; } + std::shared_ptr Map::getM2Object(int fileDataId, SMDoodadDef &doodadDef) { auto it = m_m2MapObjects[doodadDef.uniqueId]; if (!it.expired()) { @@ -1536,8 +1543,6 @@ std::shared_ptr Map::getM2Object(int fileDataId, SMDoodadDef &doodadDe } return nullptr; } - - std::shared_ptr Map::getWmoObject(std::string fileName, SMMapObjDef &mapObjDef) { auto it = m_wmoMapObjects[mapObjDef.uniqueId]; if (!it.expired()) { @@ -1552,6 +1557,7 @@ std::shared_ptr Map::getWmoObject(std::string fileName, SMMapObjDef & } return nullptr; } + std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDef &mapObjDef) { auto it = m_wmoMapObjects[mapObjDef.uniqueId]; if (!it.expired()) { @@ -1596,7 +1602,6 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDefObj1 &ma } return nullptr; } - animTime_t Map::getCurrentSceneTime() { return m_currentTime; } @@ -1748,7 +1753,8 @@ void Map::produceUpdateStage(HUpdateStage &updateStage) { m_api->getConfig()->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); m_api->getConfig()->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); } -void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) { + +void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { //Smash all meshes into one array auto opaqueMeshes = std::make_shared(); @@ -1772,6 +1778,9 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vectoropaqueMeshes = opaqueMeshes; + resultDrawStage->transparentMeshes = transparentMeshes; + HDrawStage origResultDrawStage = resultDrawStage; bool frameBufferSupported = m_api->hDevice->getIsRenderbufferSupported(); @@ -1781,64 +1790,9 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vectorsceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler( - [renderMats, config](IUniformBufferChunk *chunk, const HFrameDepedantData &fdd) -> void { - auto *blockPSVS = &chunk->getObject(); - - blockPSVS->uLookAtMat = renderMats->lookAtMat; - blockPSVS->uPMatrix = renderMats->perspectiveMat; - blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; - blockPSVS->uViewUp = renderMats->viewUp; - - blockPSVS->extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; - blockPSVS->extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; - blockPSVS->extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; - blockPSVS->extLight.uExteriorDirectColor = fdd->exteriorDirectColor; - blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); - blockPSVS->extLight.uAdtSpecMult = mathfu::vec4(config->adtSpecMult, 0, 0, 1.0); - -// float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); - float fogEnd = config->farPlane; - if (config->disableFog || !fdd->FogDataFound) { - fogEnd = 100000000.0f; - fdd->FogScaler = 0; - fdd->FogDensity = 0; - } - - float fogStart = std::max(config->farPlane - 250, 0); - fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); - - - blockPSVS->fogData.densityParams = mathfu::vec4( - fogStart, - fogEnd, - fdd->FogDensity / 1000, - 0); - blockPSVS->fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); - blockPSVS->fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); - blockPSVS->fogData.heightDensity_and_endColor = mathfu::vec4( - fdd->FogHeightDensity, - fdd->EndFogColor.x, - fdd->EndFogColor.y, - fdd->EndFogColor.z - ); - blockPSVS->fogData.sunAngle_and_sunColor = mathfu::vec4( - fdd->SunFogAngle, - fdd->SunFogColor.x * fdd->SunFogStrength, - fdd->SunFogColor.y * fdd->SunFogStrength, - fdd->SunFogColor.z * fdd->SunFogStrength - ); - blockPSVS->fogData.heightColor_and_endFogDistance = mathfu::vec4( - fdd->FogHeightColor, - (fdd->EndFogColorDistance > 0) ? - fdd->EndFogColorDistance : - 1000.0f - ); - blockPSVS->fogData.sunPercentage = mathfu::vec4( - (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); - - } + this->generateSceneWideChunk(renderMats, config) ); - additionalChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); + updateStages[0]->uniformBufferChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); } @@ -1862,7 +1816,7 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vectordisableGlow) { - lastDrawStage = doGaussBlur(prevDrawStage, additionalChunks); + lastDrawStage = doGaussBlur(prevDrawStage, updateStages[0]->uniformBufferChunks); if (lastDrawStage != nullptr) prevDrawStage = lastDrawStage; } @@ -2102,3 +2056,62 @@ void Map::loadZoneLights() { } } + +IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrices &renderMats, Config* config) { + return [renderMats, config](IUniformBufferChunk *chunk, const HFrameDepedantData &fdd) -> void { + auto *blockPSVS = &chunk->getObject(); + + blockPSVS->uLookAtMat = renderMats->lookAtMat; + blockPSVS->uPMatrix = renderMats->perspectiveMat; + blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; + blockPSVS->uViewUp = renderMats->viewUp; + + blockPSVS->extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; + blockPSVS->extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; + blockPSVS->extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; + blockPSVS->extLight.uExteriorDirectColor = fdd->exteriorDirectColor; + blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); + blockPSVS->extLight.uAdtSpecMult = mathfu::vec4(config->adtSpecMult, 0, 0, 1.0); + +// float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); + float fogEnd = config->farPlane; + if (config->disableFog || !fdd->FogDataFound) { + fogEnd = 100000000.0f; + fdd->FogScaler = 0; + fdd->FogDensity = 0; + } + + float fogStart = std::max(config->farPlane - 250, 0); + fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); + + + blockPSVS->fogData.densityParams = mathfu::vec4( + fogStart, + fogEnd, + fdd->FogDensity / 1000, + 0); + blockPSVS->fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); + blockPSVS->fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); + blockPSVS->fogData.heightDensity_and_endColor = mathfu::vec4( + fdd->FogHeightDensity, + fdd->EndFogColor.x, + fdd->EndFogColor.y, + fdd->EndFogColor.z + ); + blockPSVS->fogData.sunAngle_and_sunColor = mathfu::vec4( + fdd->SunFogAngle, + fdd->SunFogColor.x * fdd->SunFogStrength, + fdd->SunFogColor.y * fdd->SunFogStrength, + fdd->SunFogColor.z * fdd->SunFogStrength + ); + blockPSVS->fogData.heightColor_and_endFogDistance = mathfu::vec4( + fdd->FogHeightColor, + (fdd->EndFogColorDistance > 0) ? + fdd->EndFogColorDistance : + 1000.0f + ); + blockPSVS->fogData.sunPercentage = mathfu::vec4( + (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); + + }; +} diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 636c73496..516330e3b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -68,6 +68,8 @@ class Map : public IScene, public IMapApi { std::vector> m_mandatoryADT; std::string mapName; + HGUniformBufferChunk m_sceneWideBlockVSPSChunk; + SceneMode m_sceneMode = SceneMode::smMap; float m_currentTime = 0; @@ -97,7 +99,6 @@ class Map : public IScene, public IMapApi { //M2 mode std::shared_ptr m_m2Object = nullptr; std::string m_m2Model; - int m_cameraView; //Wmo mode std::shared_ptr m_wmoObject = nullptr; @@ -162,23 +163,7 @@ class Map : public IScene, public IMapApi { explicit Map() { } public: - explicit Map(HApiContainer api, int mapId, std::string mapName) { - initMapTiles(); - - m_mapId = mapId; m_api = api; this->mapName = mapName; - m_sceneMode = SceneMode::smMap; - createAdtFreeLamdas(); - - std::string wdtFileName = "world/maps/"+mapName+"/"+mapName+".wdt"; - std::string wdlFileName = "world/maps/"+mapName+"/"+mapName+".wdl"; - - m_wdtfile = api->cacheStorage->getWdtFileCache()->get(wdtFileName); - m_wdlObject = std::make_shared(api, wdlFileName); - m_wdlObject->setMapApi(this); - - loadZoneLights(); - - }; + explicit Map(HApiContainer api, int mapId, std::string mapName);; explicit Map(HApiContainer api, int mapId, int wdtFileDataId) { initMapTiles(); @@ -245,7 +230,7 @@ class Map : public IScene, public IMapApi { void update(HUpdateStage &updateStage); void updateBuffers(HUpdateStage &updateStage) override; void produceUpdateStage(HUpdateStage &updateStage) override; - void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages, std::vector &additionalChunks) override; + void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; private: void checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, @@ -258,6 +243,8 @@ class Map : public IScene, public IMapApi { void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) override; void createAdtFreeLamdas(); + + IChunkHandlerType generateSceneWideChunk(HCameraMatrices &renderMats, Config* config); }; #endif //WEBWOWVIEWERCPP_MAP_H diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index 0193e7077..d6ccdd138 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -44,88 +44,4 @@ void WmoScene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec cullStage->matricesForCulling->lookAtMat, m_api->getConfig()->currentTime ); -} - -/* -void WmoScene::doPostLoad(HCullStage cullStage) { - int processedThisFrame = 0; - int groupsProcessedThisFrame = 0; - - for (int i = 0; i < cullStage->m2Array.size(); i++) { - std::shared_ptr m2Object = cullStage->m2Array[i]; - if (m2Object == nullptr) continue; - if (m2Object->doPostLoad()) processedThisFrame++; - if (processedThisFrame > 3) return; - } -// } - - for (auto &wmoObject : cullStage->wmoGroupArray) { - if (wmoObject == nullptr) continue; - if (wmoObject->doPostLoad(groupsProcessedThisFrame)) processedThisFrame++; - - if (processedThisFrame > 3) return; - } -} -*/ -/* - -void WmoScene::produceDrawStage(HDrawStage resultDrawStage, HUpdateStage updateStage, std::vector &additionalChunks) { - auto cullStage = updateStage->cullResult; - auto renderedThisFramePreSort = std::vector(); - - //Create meshes - resultDrawStage->meshesToRender = std::make_shared(); - - //Create scenewide uniform - auto renderMats = resultDrawStage->matricesForRendering; - - auto config = m_api->getConfig(); - resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); - resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler([renderMats, config](IUniformBufferChunk *chunk) -> void { - auto *blockPSVS = &chunk->getObject(); - blockPSVS->uLookAtMat = renderMats->lookAtMat; - blockPSVS->uPMatrix = renderMats->perspectiveMat; - blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; - blockPSVS->uViewUp = renderMats->viewUp; - - blockPSVS->extLight.uExteriorAmbientColor = mathfu::vec4(0.8,0.8,0.8,0.8); - blockPSVS->extLight.uExteriorHorizontAmbientColor = mathfu::vec4(1.0,1.0,1.0,1.0); - blockPSVS->extLight.uExteriorGroundAmbientColor = mathfu::vec4(1.0,1.0,1.0,1.0); - blockPSVS->extLight.uExteriorDirectColor = mathfu::vec4(0.3,0.3,0.3,1.3); - blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(0.0,0.0,0.0,1.0); - }); - - - std::vector vector; - for (auto & interiorView : updateStage->cullResult->interiorViews) { - if (interiorView.viewCreated) { - vector.push_back(&interiorView); - } - } - if (updateStage->cullResult->exteriorView.viewCreated) { - vector.push_back(&updateStage->cullResult->exteriorView); - } - - for (auto &view : vector) { - view->collectMeshes(resultDrawStage->meshesToRender->meshes); - } - - std::vector> m2ObjectsRendered; - for (auto &view : vector) { - std::copy(view->drawnM2s.begin(),view->drawnM2s.end(), std::back_inserter(m2ObjectsRendered)); - } - std::sort( m2ObjectsRendered.begin(), m2ObjectsRendered.end() ); - m2ObjectsRendered.erase( unique( m2ObjectsRendered.begin(), m2ObjectsRendered.end() ), m2ObjectsRendered.end() ); - - for (auto &m2Object : m2ObjectsRendered) { - if (m2Object == nullptr) continue; - m2Object->collectMeshes(resultDrawStage->meshesToRender->meshes, m_viewRenderOrder); - m2Object->drawParticles(resultDrawStage->meshesToRender->meshes, m_viewRenderOrder); - } - - std::sort(resultDrawStage->meshesToRender->meshes.begin(), - resultDrawStage->meshesToRender->meshes.end(), - IDevice::sortMeshes - ); -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 2a60b153a..c15b11f39 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -25,7 +25,7 @@ class WmoGroupObject; class WmoObject : public IWmoApi { public: - WmoObject(HApiContainer api) : m_api(api) { + WmoObject(HApiContainer &api) : m_api(api) { } ~WmoObject(); From f29d81037239a52326bca13f33ff4bed4121c60e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 20 Nov 2022 18:08:36 +0200 Subject: [PATCH 006/212] big refactoring part one --- .gitmodules | 3 + src/minimapGenerator/entities.h | 2 + src/minimapGenerator/minimapGenerator.cpp | 77 +++- .../storage/CMinimapDataDB.cpp | 12 +- src/minimapGenerator/storage/CMinimapDataDB.h | 8 + src/ui/FrontendUI.cpp | 9 +- .../MinimapGenerationWindow.cpp | 7 +- .../MinimapGenerationWindow.h | 1 + wowViewerLib/3rdparty/mathfu | 2 +- wowViewerLib/shaders/CMakeLists.txt | 61 ++- .../shaders/glsl/common/commonFunctions.glsl | 53 ++- .../glsl/common/commonLightFunctions.glsl | 193 +++++---- .../shaders/glsl/common/commonM2Material.glsl | 344 ++++++++++++++++ .../glsl/common/commonWMOMaterial.glsl | 280 +++++++++++++ .../adtLodShader.frag | 0 .../adtLodShader.vert | 0 .../adtShader.frag | 0 .../adtShader.vert | 0 .../drawBBShader.frag | 0 .../drawBBShader.vert | 0 .../drawDepthShader.frag | 0 .../drawFrustumShader.frag | 0 .../drawFrustumShader.vert | 0 .../drawLinesShader.frag | 0 .../drawLinesShader.vert | 0 .../drawPoints.frag | 0 .../drawPoints.vert | 0 .../drawPortalShader.frag | 0 .../drawPortalShader.vert | 0 .../drawQuad.vert | 0 .../ffxgauss4.frag | 0 .../{vulkan => forwardRendering}/ffxglow.frag | 0 .../imguiShader.frag | 0 .../imguiShader.vert | 0 .../m2ParticleShader.frag | 0 .../m2ParticleShader.vert | 0 .../glsl/forwardRendering/m2Shader.frag | 168 ++++++++ .../glsl/forwardRendering/m2Shader.vert | 87 ++++ .../renderFrameBufferShader.frag | 0 .../renderFrameBufferShader.vert | 0 .../ribbonShader.frag | 0 .../ribbonShader.vert | 0 .../skyConus.frag | 0 .../skyConus.vert | 0 .../waterShader.frag | 0 .../waterShader.vert | 4 +- .../waterfallShader.frag | 0 .../waterfallShader.vert | 0 .../glsl/forwardRendering/wmoShader.frag | 96 +++++ .../wmoShader.vert | 46 +-- .../shaders/glsl/vulkan/m2Shader.frag | 352 ----------------- .../shaders/glsl/vulkan/m2Shader.vert | 174 -------- .../shaders/glsl/vulkan/wmoShader.frag | 335 ---------------- .../src/engine/objects/adt/adtObject.cpp | 2 + .../src/engine/objects/m2/m2Object.cpp | 67 +++- .../src/engine/objects/scenes/map.cpp | 18 +- .../src/engine/shader/ShaderDefinitions.h | 373 ++++++++---------- .../src/gapi/interface/meshes/IMesh.h | 2 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 1 - wowViewerLib/src/include/config.h | 16 +- 60 files changed, 1510 insertions(+), 1283 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonM2Material.glsl create mode 100644 wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/adtLodShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/adtLodShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/adtShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/adtShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawBBShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawBBShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawDepthShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawFrustumShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawFrustumShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawLinesShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawLinesShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawPoints.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawPoints.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawPortalShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawPortalShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/drawQuad.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/ffxgauss4.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/ffxglow.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/imguiShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/imguiShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/m2ParticleShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/m2ParticleShader.vert (100%) create mode 100644 wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag create mode 100644 wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/renderFrameBufferShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/renderFrameBufferShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/ribbonShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/ribbonShader.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/skyConus.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/skyConus.vert (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/waterShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/waterShader.vert (87%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/waterfallShader.frag (100%) rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/waterfallShader.vert (100%) create mode 100644 wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag rename wowViewerLib/shaders/glsl/{vulkan => forwardRendering}/wmoShader.vert (52%) delete mode 100644 wowViewerLib/shaders/glsl/vulkan/m2Shader.frag delete mode 100644 wowViewerLib/shaders/glsl/vulkan/m2Shader.vert delete mode 100644 wowViewerLib/shaders/glsl/vulkan/wmoShader.frag diff --git a/.gitmodules b/.gitmodules index bb9f4bbcd..4cdf8a8da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -44,3 +44,6 @@ [submodule "wowViewerLib/3rdparty/oneTbb"] path = wowViewerLib/3rdparty/oneTbb url = https://github.com/Deamon87/oneTBBWasm.git +[submodule "3rdparty/hiberlite"] + path = 3rdparty/hiberlite + url = https://github.com/paulftw/hiberlite.git diff --git a/src/minimapGenerator/entities.h b/src/minimapGenerator/entities.h index d90c6916e..802683a4d 100644 --- a/src/minimapGenerator/entities.h +++ b/src/minimapGenerator/entities.h @@ -59,6 +59,8 @@ struct ScenarioDef { float zoom = 1.0f; + int time = 0; + std::string folderToSave; std::unordered_map> activatePhasePerMap; diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 9ccae0b95..dcbeecea3 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -124,6 +124,8 @@ void MinimapGenerator::startNextScenario() { } bool MinimapGenerator::loadMaps() { + mapRuntimeInfo.clear(); + for ( int i = 0; i < currentScenario.maps.size(); i++) { auto &mapDef = currentScenario.maps[i]; MapRecord mapRecord; @@ -157,16 +159,25 @@ bool MinimapGenerator::loadMaps() { for (int adt_x = 0; adt_x < 64; adt_x++) { for (int adt_y = 0; adt_y < 64; adt_y++) { - float minZ = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMinZ[adt_x][adt_y]; - float maxZ = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMaxZ[adt_x][adt_y]; + mathfu::vec3 adtMin = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMin[adt_x][adt_y]; + mathfu::vec3 adtMax = currentScenario.maps[mapData.mapIndex].adtConfigHolder->adtMax[adt_x][adt_y]; //Project aaBB into screenSpace coordinates - std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1) , AdtIndexToWorldCoordinate(adt_x + 1)}; + std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1), AdtIndexToWorldCoordinate(adt_x + 1)}; std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y) , AdtIndexToWorldCoordinate(adt_x)}; - std::array minMaxZ = {minZ, maxZ}; + +// std::array minMaxX = {adtMin.x, adtMax.x}; +// std::array minMaxY = {adtMin.y, adtMax.y}; + std::array minMaxZ = {adtMin.z, adtMax.z}; std::vector corners; - if (minZ > maxZ) continue; + if (minMaxZ[0] > minMaxZ[1]) continue; + + minMaxX[0] = std::max(minMaxX[0] - (MathHelper::TILESIZE/2.0f), adtMin.x ); + minMaxX[1] = std::min(minMaxX[1] + (MathHelper::TILESIZE/2.0f), adtMax.x ); + minMaxY[0] = std::max(minMaxY[0] - (MathHelper::TILESIZE/2.0f), adtMin.y ); + minMaxY[1] = std::min(minMaxY[1] + (MathHelper::TILESIZE/2.0f), adtMax.y ); + for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { @@ -215,7 +226,7 @@ bool MinimapGenerator::loadMaps() { continue; if (i >= m_chunkStartX + m_chunkWidth) continue; - if (i >= m_chunkStartY + m_chunkHeight) + if (j >= m_chunkStartY + m_chunkHeight) continue; std::array adtCoord = {static_cast(adt_x), @@ -240,10 +251,12 @@ void MinimapGenerator::setupScenarioData() { auto config = m_apiContainer->getConfig(); config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; config->closeRiverColor = {0.345206976, 0.329288304, 0.270450264, 0}; + config->currentTime = currentScenario.time; m_width = currentScenario.imageWidth; m_height = currentScenario.imageHeight; + if (currentScenario.orientation == ScenarioOrientation::soTopDownOrtho) { m_apiContainer->camera = std::make_shared(); } else { @@ -289,15 +302,22 @@ MinimapGenerator::setMinMaxXYWidthHeight(const mathfu::vec2 &minWowWorldCoord, c if (adt_x < 0 || adt_x > 63) continue; - auto adtMinZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; - auto adtMaxZ = mapDef.adtConfigHolder->adtMinZ[adt_x][adt_y]; + auto adtMin = mapDef.adtConfigHolder->adtMin[adt_x][adt_y] + mathfu::vec3(mapDef.deltaX, mapDef.deltaY, mapDef.deltaZ); + auto adtMax = mapDef.adtConfigHolder->adtMin[adt_x][adt_y] + mathfu::vec3(mapDef.deltaX, mapDef.deltaY, mapDef.deltaZ);; - if (adtMinZ > adtMaxZ) + if (adtMin.z > adtMax.z) continue; - std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1) + mapDef.deltaX, AdtIndexToWorldCoordinate(adt_x + 1) + mapDef.deltaX}; - std::array minMaxY = {AdtIndexToWorldCoordinate(adt_y) + mapDef.deltaY, AdtIndexToWorldCoordinate(adt_x) + mapDef.deltaY}; - std::array minMaxZ = {adtMinZ + mapDef.deltaZ, adtMaxZ + mapDef.deltaZ}; + std::array minMaxX = {AdtIndexToWorldCoordinate(adt_y + 1) + mapDef.deltaX, AdtIndexToWorldCoordinate(adt_y) + mapDef.deltaX}; + std::array minMaxY = {AdtIndexToWorldCoordinate(adt_x + 1) + mapDef.deltaY, AdtIndexToWorldCoordinate(adt_x) + mapDef.deltaY}; + + minMaxX[0] = std::max(minMaxX[0] - (MathHelper::TILESIZE/2.0f), adtMin.x); + minMaxX[1] = std::min(minMaxX[1] + (MathHelper::TILESIZE/2.0f), adtMax.x); + + minMaxY[0] = std::max(minMaxY[0] - (MathHelper::TILESIZE/2.0f), adtMin.y); + minMaxY[1] = std::min(minMaxY[1] + (MathHelper::TILESIZE/2.0f), adtMax.y); + + std::array minMaxZ = {adtMin.z + mapDef.deltaZ, adtMax.z + mapDef.deltaZ}; std::vector corners; for (int i = 0; i < 2; i++) @@ -559,6 +579,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor continue; } + if (objBB.max.z > 10000) { + std::cout << "what" << std::endl; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -580,6 +604,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor continue; } + if (objBB.max.z > 10000) { + std::cout << "what" << std::endl; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -611,6 +639,10 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor continue; } + if (objBB.max.z > 10000) { + std::cout << "what" << std::endl; + } + minCoord = mathfu::vec3( std::min(minCoord.x, objBB.min.x), std::min(minCoord.y, objBB.min.y), @@ -703,10 +735,15 @@ void MinimapGenerator::process() { for (auto &cullStage: lastFrameCull) { this->calcBB(cullStage, minCoord, maxCoord, adtBox2d, adt_x, adt_y, m_mgMode == EMGMode::eBoundingBoxCalculation); + if (adt_y == 29 && adt_x == 15) { + std::cout << "what" << std::endl; + } + float zFar = (minCoord - maxCoord).Length(); float maxZ = maxCoord.z + cullStage->deltaZ; float minZ = minCoord.z + cullStage->deltaZ; + if (!cullStage->m2Array.getDrawn().empty() || !cullStage->adtArray.empty() || !cullStage->wmoGroupArray.getToDraw().empty()) { if (minCoord.x < 20000 && maxCoord.x > -20000) { @@ -724,10 +761,20 @@ void MinimapGenerator::process() { setupCameraData(); return; } + + if (minCoord.x < 20000 && maxCoord.x > -20000) { + minAdt.x = std::max(minCoord.x, minAdt.x - (MathHelper::TILESIZE/2.0f)); + maxAdt.x = std::min(maxCoord.x, maxAdt.x + (MathHelper::TILESIZE/2.0f)); + + minAdt.y = std::max(minCoord.y, minAdt.y - (MathHelper::TILESIZE/2.0f)); + maxAdt.y = std::min(maxCoord.y, maxAdt.y + (MathHelper::TILESIZE/2.0f)); + } } //Conditional mode stuff if (m_mgMode == EMGMode::eBoundingBoxCalculation) { + + minCoord = mathfu::vec3( minAdt.x, minAdt.y, @@ -738,8 +785,10 @@ void MinimapGenerator::process() { maxAdt.y, maxCoord.z); - currentScenario.maps[m_mapIndex].adtConfigHolder->adtMinZ[adt_x][adt_y] = minCoord.z; - currentScenario.maps[m_mapIndex].adtConfigHolder->adtMaxZ[adt_x][adt_y] = maxCoord.z; + currentScenario.maps[m_mapIndex].adtConfigHolder->adtMin[adt_x][adt_y] = minCoord; + currentScenario.maps[m_mapIndex].adtConfigHolder->adtMax[adt_x][adt_y] = maxCoord; + + saveDrawStageToFile(currentScenario.folderToSave+"/minimap/"+std::to_string(currentScenario.maps[m_mapIndex].mapId), lastFrameIt); } else if (m_mgMode == EMGMode::eScreenshotGeneration) { diff --git a/src/minimapGenerator/storage/CMinimapDataDB.cpp b/src/minimapGenerator/storage/CMinimapDataDB.cpp index 6b633b3d9..e1ad289e3 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.cpp +++ b/src/minimapGenerator/storage/CMinimapDataDB.cpp @@ -50,8 +50,8 @@ void CMinimapDataDB::DataBaseClass::getAdtBoundingBoxes(MapRenderDef& mapRenderD auto adtBoundingBoxesDB = m_storage.get_all(where(c(&ADTBoundingBoxDB::map_id) == mapRenderDef.mapId)); for (auto &adtBoundingBoxeDB : adtBoundingBoxesDB) { - mapRenderDef.adtConfigHolder->adtMinZ[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = adtBoundingBoxeDB.adtMin_z; - mapRenderDef.adtConfigHolder->adtMaxZ[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = adtBoundingBoxeDB.adtMax_z; + mapRenderDef.adtConfigHolder->adtMin[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = {adtBoundingBoxeDB.adtMin_x, adtBoundingBoxeDB.adtMin_y, adtBoundingBoxeDB.adtMin_z} ; + mapRenderDef.adtConfigHolder->adtMax[adtBoundingBoxeDB.adt_x][adtBoundingBoxeDB.adt_y] = {adtBoundingBoxeDB.adtMax_x, adtBoundingBoxeDB.adtMax_y, adtBoundingBoxeDB.adtMax_z}; } } @@ -67,8 +67,12 @@ void CMinimapDataDB::DataBaseClass::saveAdtBoundingBoxes(MapRenderDef& mapRender boxDb.map_id = mapRenderDef.mapId; boxDb.adt_x = i; boxDb.adt_y = j; - boxDb.adtMin_z = mapRenderDef.adtConfigHolder->adtMinZ[i][j]; - boxDb.adtMax_z = mapRenderDef.adtConfigHolder->adtMaxZ[i][j]; + boxDb.adtMin_x = mapRenderDef.adtConfigHolder->adtMin[i][j].x; + boxDb.adtMin_y = mapRenderDef.adtConfigHolder->adtMin[i][j].y; + boxDb.adtMin_z = mapRenderDef.adtConfigHolder->adtMin[i][j].z; + boxDb.adtMax_x = mapRenderDef.adtConfigHolder->adtMax[i][j].x; + boxDb.adtMax_y = mapRenderDef.adtConfigHolder->adtMax[i][j].y; + boxDb.adtMax_z = mapRenderDef.adtConfigHolder->adtMax[i][j].z; m_storage.insert(boxDb); } diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index e7fa66670..1e931e9a9 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -14,7 +14,11 @@ namespace CMinimapDataDB { int map_id; int adt_x; int adt_y; + float adtMin_x; + float adtMin_y; float adtMin_z; + float adtMax_x; + float adtMax_y; float adtMax_z; }; @@ -80,7 +84,11 @@ namespace CMinimapDataDB { make_column("map_id", &ADTBoundingBoxDB::map_id), make_column("adt_x", &ADTBoundingBoxDB::adt_x), make_column("adt_y", &ADTBoundingBoxDB::adt_y), + make_column("adt_min_x", &ADTBoundingBoxDB::adtMin_x), + make_column("adt_min_y", &ADTBoundingBoxDB::adtMin_y), make_column("adt_min_z", &ADTBoundingBoxDB::adtMin_z), + make_column("adt_max_x", &ADTBoundingBoxDB::adtMax_x), + make_column("adt_max_y", &ADTBoundingBoxDB::adtMax_y), make_column("adt_max_z", &ADTBoundingBoxDB::adtMax_z) ) ); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index c2431b937..1ba1a8159 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -723,6 +723,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("Tomb of sargares hall", ImVec2(-1, 0))) { openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); } + if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { + openWMOSceneByfdid(4419436); + } if (ImGui::Button("10.0 Raid WMO", ImVec2(-1, 0))) { openWMOSceneByfdid(4282557); } @@ -1919,19 +1922,19 @@ void FrontendUI::showMinimapGenerationSettingsDialog() { } void FrontendUI::createDatabaseHandler() { - bool forceEmptyDatabase = false; + bool useEmptyDatabase = false; if (fileExistsNotNull("./export.db3")) { try{ m_api->databaseHandler = std::make_shared("./export.db3"); } catch(std::exception const& e) { std::cout << "Failed to open database: " << e.what() << std::endl; - forceEmptyDatabase = true; + useEmptyDatabase = true; } catch(...) { std::cout << "Exception occurred" << std::endl; } } - if (forceEmptyDatabase) { + if (useEmptyDatabase) { m_api->databaseHandler = std::make_shared(); } diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 47eb7f946..8dbd55200 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -423,6 +423,7 @@ void MinimapGenerationWindow::renderEditTab() { ImGui::PopItemWidth(); ImGui::EndGroupPanel(); } + ImGui::InputFloat("Zoom", &sceneDef->zoom, 0.1); @@ -474,10 +475,10 @@ void MinimapGenerationWindow::renderEditTab() { ImGui::EndGroupPanel(); } - auto currentTime = minimapGenerator->getConfig()->currentTime; + auto currentTime = sceneDef->time; ImGui::Text("Time: %02d:%02d", (int)(currentTime/120), (int)((currentTime/2) % 60)); - if (ImGui::SliderInt("Current time", ¤tTime, 0, 2880)) { - minimapGenerator->getConfig()->currentTime = currentTime; + if (ImGui::SliderInt("Current time", &sceneDef->time, 0, 2880)) { +// sceneDef->time = sceneDef->time; } editComponentsForConfig(minimapGenerator->getConfig()); diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h index 3c13a2b19..06c974ae7 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -44,6 +44,7 @@ class MinimapGenerationWindow { float previewY = 0; float previewZoom = 1; + int mapIndexExcludeADT = -1; int mapIndexExcludeADTChunk = -1; diff --git a/wowViewerLib/3rdparty/mathfu b/wowViewerLib/3rdparty/mathfu index da23a1227..f3e7f0d22 160000 --- a/wowViewerLib/3rdparty/mathfu +++ b/wowViewerLib/3rdparty/mathfu @@ -1 +1 @@ -Subproject commit da23a1227bb65fbb7f2f5b6c504fbbdd1dfdab4b +Subproject commit f3e7f0d22fd1e2317c8fade8db5d85fac1fd0322 diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 92c8c11ab..cb1568d14 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -42,7 +42,11 @@ if(NOT ANDROID) # set(PATH_TO_NATIVE_GLSL_VALIDATOR "${CMAKE_BINARY_DIR}/glslangValidator${CMAKE_EXECUTABLE_SUFFIX}") # set(PATH_TO_NATIVE_SPIRV_REFLECTION "${CMAKE_BINARY_DIR}/spirv_reflection${CMAKE_EXECUTABLE_SUFFIX}") - set(PATH_TO_NATIVE_GLSL_VALIDATOR $) + if (NOT PATH_TO_NATIVE_GLSL_VALIDATOR) + set(PATH_TO_NATIVE_GLSL_VALIDATOR $) + else() + MESSAGE(WARNING "PATH_TO_NATIVE_GLSL_VALIDATOR = ${PATH_TO_NATIVE_GLSL_VALIDATOR}") + endif() set(PATH_TO_NATIVE_SPIRV_REFLECTION $) else() MESSAGE(WARNING "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}") @@ -61,13 +65,13 @@ else() add_custom_target(spirv_reflection) endif() - macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring directory ${destDir}") - make_directory(${destDir}) + set(spirvNonOptDir ${CMAKE_BINARY_DIR}/spriv_raw) + make_directory(${spirvNonOptDir}) - file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*.frag ${srcDir}/*.vert) - file(GLOB commonFilesRelative RELATIVE ${srcCommonDir} ${srcCommonDir}/*.glsl) + file(GLOB_RECURSE templateFiles RELATIVE ${srcDir} ${srcDir}/*.frag ${srcDir}/*.vert) + file(GLOB_RECURSE commonFilesRelative RELATIVE ${srcCommonDir} ${srcCommonDir}/*.glsl) foreach(commonFileRelative ${commonFilesRelative}) set(commonFileFullPath ${srcCommonDir}/${commonFileRelative}) @@ -82,8 +86,13 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring file ${templateFile}") get_filename_component(FILE_NAME_WO_EXT ${srcTemplatePath} NAME_WE) get_filename_component(FILE_NAME ${srcTemplatePath} NAME) - set(SPIRV_NonOpt "${destDir}/${FILE_NAME}.spv") -# set(SPIRVOpt "${destDir}/${FILE_NAME}.opt.spv") + if (NOT SPIRV_OPT_APP) + set(SPIRV_NonOpt "${destDir}/${FILE_NAME}.spv") + else() + set(SPIRV_NonOpt "${spirvNonOptDir}/${FILE_NAME}.spv") + set(SPIRVOpt "${destDir}/${FILE_NAME}.spv") + endif() + add_custom_command( OUTPUT ${SPIRV_NonOpt} @@ -91,25 +100,12 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_GLSL_VALIDATOR} -V ${srcTemplatePath} -o ${SPIRV_NonOpt} DEPENDS ${srcTemplatePath} glslangValidator ${commonFiles}) -# if(SPIRV_OPT_APP) -# add_custom_command( -# OUTPUT ${SPIRVOpt} -# COMMAND ${SPIRV_OPT_APP} --inline-entry-points-exhaustive -# --convert-local-access-chains -# --eliminate-local-single-block -# --eliminate-local-single-store -# --eliminate-insert-extract -# --eliminate-dead-code-aggressive -# --eliminate-dead-branches -# --merge-blocks -# --eliminate-local-single-block -# --eliminate-local-single-store -# --eliminate-local-multi-store -# --eliminate-insert-extract -# --eliminate-dead-code-aggressive -# -o ${SPIRVOpt} ${SPIRV_NonOpt} -# DEPENDS ${srcTemplatePath} ${SPIRV_NonOpt}) -# endif() + if(SPIRV_OPT_APP) + add_custom_command( + OUTPUT ${SPIRVOpt} + COMMAND ${SPIRV_OPT_APP} -O -o ${SPIRVOpt} ${SPIRV_NonOpt} + DEPENDS ${srcTemplatePath} ${SPIRV_NonOpt}) + endif() list(APPEND SPIRV_BINARY_FILES_NON_OPT ${SPIRV_NonOpt}) list(APPEND SPIRV_BINARY_FILES_OPT ${SPIRVOpt}) @@ -146,12 +142,9 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) list(APPEND GLSL20Files ${GLSL20_FILE}) - get_filename_component(GLSL30_FILE_FULLPATH "${GLSL33_FILE}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") - - add_custom_command( OUTPUT ${GLSL33_FILE} COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL33}" @@ -163,15 +156,15 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) endif(NOT IS_DIRECTORY ${srcTemplatePath}) endforeach(templateFile) -# if (NOT SPIRV_OPT_APP) + if (NOT SPIRV_OPT_APP) SET(SPIRV_BINARY_FILES ${SPIRV_BINARY_FILES_NON_OPT}) -# else() -# SET(SPIRV_BINARY_FILES ${SPIRV_BINARY_FILES_OPT}) -# endif() + else() + SET(SPIRV_BINARY_FILES ${SPIRV_BINARY_FILES_OPT}) + endif() endmacro(configure_filesVLK) configure_filesVLK( - ${PROJECT_SOURCE_DIR}/shaders/glsl/vulkan + ${PROJECT_SOURCE_DIR}/shaders/glsl/forwardRendering ${PROJECT_SOURCE_DIR}/shaders/glsl/common ${GLSL_TARGET_FOLDER}/spirv ${GLSL_TARGET_FOLDER}/glsl/glsl20/ diff --git a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl index 51c7bb313..858fe2ea5 100644 --- a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl @@ -1,22 +1,27 @@ -vec2 posToTexCoord(vec3 cameraPoint, vec3 normal){ -// vec3 normPos = -normalize(cameraPoint.xyz); -// vec3 normPos = cameraPoint.xyz; -// vec3 reflection = reflect(normPos, normal); -// return (normalize(vec3(reflection.r, reflection.g, reflection.b + 1.0)).rg * 0.5) + vec2(0.5); +#ifndef COMMON_FUNCTION_GLSL +#define COMMON_FUNCTION_GLSL - vec3 viewVecNormalized = -normalize(cameraPoint.xyz); +vec2 posToTexCoord(const vec3 cameraPoint, const vec3 normal){ + + //Blizz seems to have vertex in view space as vector from "vertex to eye", while in this implementation, it's + //vector from "eye to vertex". So the minus here is not needed + //vec3 viewVecNormalized = -normalize(cameraPoint.xyz); + vec3 viewVecNormalized = normalize(cameraPoint.xyz); vec3 reflection = reflect(viewVecNormalized, normal); vec3 temp_657 = vec3(reflection.x, reflection.y, (reflection.z + 1.0)); return ((normalize(temp_657).xy * 0.5) + vec2(0.5)); } -float edgeScan(vec3 position, vec3 normal){ - float dotProductClamped = clamp(dot(-normalize(position),normal), 0.000000, 1.000000); +float edgeScan(const vec3 position, const vec3 normal){ + //Blizz seems to have vertex in view space as vector from "vertex to eye", while in this implementation, it's + //vector from "eye to vertex". So the minus here is not needed +// float dotProductClamped = clamp(dot(-normalize(position),normal), 0.000000, 1.000000); + float dotProductClamped = clamp(dot(normalize(position),normal), 0.000000, 1.000000); return clamp(2.700000 * dotProductClamped * dotProductClamped - 0.400000, 0.000000, 1.000000); } -mat3 blizzTranspose(mat4 value) { +mat3 blizzTranspose(const mat4 value) { return mat3( value[0].xyz, value[1].xyz, @@ -24,3 +29,33 @@ mat3 blizzTranspose(mat4 value) { ); } +#ifdef FRAGMENT_SHADER +//From: https://pdfslide.tips/technology/shaderx5-26normalmappingwithoutprecomputedtangents-130318-1.html?page=14 +mat3 contangent_frame(vec3 N, vec3 p, vec2 uv) +{ + // Get edge vectors of the pixel triangle + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + // Solve the linear system + vec3 dp2perp = cross(dp2, N); + vec3 dp1perp = cross(N, dp1); + vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; + // Construct a scale-invariant frame + float invmax = inversesqrt(max(dot(T,T), dot(B,B))); + return mat3(T * invmax, B * invmax, N); +} +#else +//Temp implementation. +//TODO: add implementation for raytracing case +mat3 contangent_frame(vec3 N, vec3 p, vec2 uv) { + return mat3(1.0); +} + +#endif + + +#endif + diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 6d0b3ea17..2870ba3bb 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -1,3 +1,6 @@ +#ifndef COMMON_LIGHT_FUNCTIONS +#define COMMON_LIGHT_FUNCTIONS + struct SceneExteriorLight { vec4 uExteriorAmbientColor; vec4 uExteriorHorizontAmbientColor; @@ -21,103 +24,131 @@ struct InteriorLightParam { vec4 uInteriorDirectColorAndApplyExteriorLight; }; +vec3 Slerp(vec3 p0, vec3 p1, float t) +{ + float dotp = dot(normalize(p0), normalize(p1)); + if ((dotp > 0.9999) || (dotp<-0.9999)) + { + if (t<=0.5) + return p0; + + return p1; + } + float theta = acos(dotp); + vec3 P = ((p0*sin((1-t)*theta) + p1*sin(t*theta)) / sin(theta)); + + return P; +} + vec3 calcLight( - vec3 matDiffuse, - vec3 vNormal, - bool applyLight, - float interiorExteriorBlend, - readonly SceneWideParams sceneParams, - readonly InteriorLightParam intLight, - readonly vec3 accumLight, const vec3 precomputedLight, const vec3 specular, - readonly const vec3 emissive) { - - vec3 currColor; + const in vec3 matDiffuse, + const in vec3 vNormal, + const in bool applyLight, + const in float interiorExteriorBlend, + const in SceneWideParams sceneParams, + const in InteriorLightParam intLight, + const in vec3 accumLight, const in vec3 precomputedLight, const in vec3 specular, + const in vec3 emissive) { + vec3 localDiffuse = accumLight; + vec3 result = matDiffuse; + if (applyLight) { + vec3 currColor = vec3(0.0, 0.0, 0.0); + vec3 lDiffuse = vec3(0.0, 0.0, 0.0); + vec3 normalizedN = normalize(vNormal); - if (!applyLight) { - return matDiffuse; - } + if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { + float nDotL = clamp(dot(normalizedN, -(sceneParams.extLight.uExteriorDirectColorDir.xyz)), 0.0, 1.0); + float nDotUp = dot(normalizedN, sceneParams.uViewUp.xyz); - vec3 lDiffuse = vec3(0.0, 0.0, 0.0); - vec3 normalizedN = normalize(vNormal); + vec3 adjAmbient = (sceneParams.extLight.uExteriorAmbientColor.rgb + precomputedLight); + vec3 adjHorizAmbient = (sceneParams.extLight.uExteriorHorizontAmbientColor.rgb + precomputedLight); + vec3 adjGroundAmbient = (sceneParams.extLight.uExteriorGroundAmbientColor.rgb + precomputedLight); - if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { - float nDotL = clamp(dot(normalizedN, -(sceneParams.extLight.uExteriorDirectColorDir.xyz)), 0.0, 1.0); - float nDotUp = dot(normalizedN, sceneParams.uViewUp.xyz); + if ((nDotUp >= 0.0)) + { + currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp)); + } + else + { + currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp))); + } - vec3 adjAmbient = (sceneParams.extLight.uExteriorAmbientColor.rgb + precomputedLight); - vec3 adjHorizAmbient = (sceneParams.extLight.uExteriorHorizontAmbientColor.rgb + precomputedLight); - vec3 adjGroundAmbient = (sceneParams.extLight.uExteriorGroundAmbientColor.rgb + precomputedLight); + vec3 skyColor = (currColor * 1.10000002); + vec3 groundColor = (currColor* 0.699999988); - if ((nDotUp >= 0.0)) - { - currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp)); + + lDiffuse = (sceneParams.extLight.uExteriorDirectColor.xyz * nDotL); + currColor = mix(groundColor, skyColor, vec3(nDotL)); } - else - { - currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp))); + if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { + float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir.xyz)), 0.0, 1.0); + vec3 lDiffuseInterior = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz * nDotL; + vec3 interiorAmbient = intLight.uInteriorAmbientColorAndApplyInteriorLight.xyz + precomputedLight; + + if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { + lDiffuse = mix(lDiffuseInterior, lDiffuse, interiorExteriorBlend); + currColor = mix(interiorAmbient, currColor, interiorExteriorBlend); + } else { + lDiffuse = lDiffuseInterior; + currColor = interiorAmbient; + } } - vec3 skyColor = (currColor * 1.10000002); - vec3 groundColor = (currColor* 0.699999988); + vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse); + vec3 linearDiffTerm = (matDiffuse * matDiffuse) * localDiffuse; + + //Specular term + vec3 specTerm = specular; + //Emission term + const vec3 emTerm = emissive; + result = sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) + specTerm + emTerm; + } + + return result; +} +vec3 calcSpec(const in float texAlpha) { + return vec3(0.0f); +} - lDiffuse = (sceneParams.extLight.uExteriorDirectColor.xyz * nDotL); - currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL)))); +/* +//TODO: Restore this function some other time +vec3 calcSpec(const in float texAlpha, + const in vec3 vertexPosInView, + const in vec3 normalInView, + const in SceneWideParams sceneParams, + const in InteriorLightParam intLight, + float exteriorInteriorBlend + ) { + vec3 normal = normalize(normalInView); + + vec3 sunDir = vec3(0); + vec3 sunColor = vec3(0); + + if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { + sunDir = -(sceneParams.extLight.uExteriorDirectColorDir.xyz); + sunColor = sceneParams.extLight.uExteriorDirectColor.xyz; } + if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { - float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir.xyz)), 0.0, 1.0); - vec3 lDiffuseInterior = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz * nDotL; - vec3 interiorAmbient = intLight.uInteriorAmbientColorAndApplyInteriorLight.xyz + precomputedLight; + sunDir = -(sceneParams.uInteriorSunDir.xyz); + sunColor = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz; if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { - lDiffuse = mix(lDiffuseInterior, lDiffuse, interiorExteriorBlend); - currColor = mix(interiorAmbient, currColor, interiorExteriorBlend); - } else { - lDiffuse = lDiffuseInterior; - currColor = interiorAmbient; + sunDir = Slerp(sunDir, -(sceneParams.extLight.uExteriorDirectColorDir.xyz), exteriorInteriorBlend); + sunColor = mix(sunColor, sceneParams.extLight.uExteriorDirectColor.xyz, exteriorInteriorBlend); } } - vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse); - vec3 linearDiffTerm = (matDiffuse * matDiffuse) * localDiffuse; - - //Specular term - vec3 specTerm = specular; - //Emission term - vec3 emTerm = emissive; - - - return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) + specTerm + emTerm; - - -// vec3 normalDirection = normalize(vNormal); -// -// vec3 viewDirection = normalize(_WorldSpaceCameraPos - vec3(position)); -// vec3 lightDirection; -// float attenuation; -// -// if (0.0 == _WorldSpaceLightPos0.w) // directional light? -// { -// attenuation = 1.0; // no attenuation -// lightDirection = normalize(vec3(_WorldSpaceLightPos0)); -// } -// else // point or spot light -// { -// vec3 vertexToLightSource = -// vec3(_WorldSpaceLightPos0 - position); -// float distance = length(vertexToLightSource); -// attenuation = 1.0 / distance; // linear attenuation -// lightDirection = normalize(vertexToLightSource); -// } -// -// vec4 fragmentColor = vec4(0.0, 0.0, 0.0, 0.0); -// if (dot(normalDirection, lightDirection) > 0.0 -// // light source on the right side? -// && attenuation * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess) > 0.5) -// // more than half highlight intensity? -// { -// fragmentColor = vec4(_LightColor0.rgb, 1.0) * _SpecColor; -// } - -} \ No newline at end of file + vec3 t849 = normalize((sunDir + normalize(-(vertexPosInView.xyz)))); + float dirAtten_956 = clamp(dot(normal, sunDir), 0, 1); + float spec = (1.25 * pow(clamp(dot(normal, t849), 0, 1), 8.0)); + vec3 specTerm = ((((vec3(mix(pow((1.0 - clamp(dot(sunDir, t849), 0, 1)), 5.0), 1.0, texAlpha)) * spec) * sunColor) * dirAtten_956)); + // float distFade = clamp(((vPosition * pc_miscParams.z) + pc_miscParams.w), 0, 1); + float distFade = 1.0; + specTerm = (specTerm * distFade); + return specTerm; +} +*/ +#endif \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl new file mode 100644 index 000000000..1128d0477 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -0,0 +1,344 @@ +#include "commonFunctions.glsl" + +void calcM2FragMaterial(const in int uPixelShader, + in sampler2D texSampler1, + in sampler2D texSampler2, + in sampler2D texSampler3, + in sampler2D texSampler4, + const in vec2 inUv1, + const in vec2 inUv2, + const in vec2 inUv3, + const in vec3 meshColor, + const in float meshOpacity, + const in vec3 texSampleAlpha, + const in int blendMode, + + out vec3 matDiffuse, out vec3 specular, + out float finalOpacity, out bool discardThisFragment) +{ + vec4 genericParams[3]; + genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 ); + genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 ); + genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 ); + + vec2 uv1 = inUv1; + vec2 uv2 = inUv2; + vec2 uv3 = inUv3; + + if (uPixelShader == 26 || uPixelShader == 27 || uPixelShader == 28) { + uv2 = uv1; + uv3 = uv1; + } + + vec4 tex = texture(texSampler1, uv1).rgba; + vec4 tex2 = texture(texSampler2, uv2).rgba; + vec4 tex3 = texture(texSampler3, uv3).rgba; + + float discardAlpha = 1.0; + bool canDiscard = false; + matDiffuse = vec3(0.0, 0.0, 0.0); + specular = vec3(0.0, 0.0, 0.0); + + switch (uPixelShader) { + case (0): { //Combiners_Opaque + matDiffuse = meshColor * tex.rgb; + break; + } + case (1): { //Combiners_Mod + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (2): { //Combiners_Opaque_Mod + matDiffuse = meshColor * tex.rgb * tex2.rgb; + discardAlpha = tex2.a; + canDiscard = true; + break; + } + case (3): { //Combiners_Opaque_Mod2x + matDiffuse = meshColor * tex.rgb * tex2.rgb * 2.0; + discardAlpha = tex2.a * 2.0; + canDiscard = true; + break; + } + case (4): { //Combiners_Opaque_Mod2xNA + matDiffuse = meshColor * tex.rgb * tex2.rgb * 2.0; + break; + } + case (5): { //Combiners_Opaque_Opaque + matDiffuse = meshColor * tex.rgb * tex2.rgb; + break; + } + case (6): { //Combiners_Mod_Mod + matDiffuse = meshColor * tex.rgb * tex2.rgb; + discardAlpha = tex.a * tex2.a; + canDiscard = true; + break; + } + case (7): { //Combiners_Mod_Mod2x + matDiffuse = meshColor * tex.rgb * tex2.rgb * 2.0; + discardAlpha = tex.a * tex2.a * 2.0; + canDiscard = true; + break; + } + case (8): { //Combiners_Mod_Add + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a + tex2.a; + canDiscard = true; + specular = tex2.rgb; + break; + } + case (9): { //Combiners_Mod_Mod2xNA + matDiffuse = meshColor * tex.rgb * tex2.rgb * 2.0; + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (10): { //Combiners_Mod_AddNA + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a; + canDiscard = true; + specular = tex2.rgb; + break; + } + case (11): { //Combiners_Mod_Opaque + matDiffuse = meshColor * tex.rgb * tex2.rgb; + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (12): { //Combiners_Opaque_Mod2xNA_Alpha + matDiffuse = meshColor * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)); + break; + } + case (13): { //Combiners_Opaque_AddAlpha + matDiffuse = meshColor * tex.rgb; + specular = tex2.rgb * tex2.a; + break; + } + case (14): { //Combiners_Opaque_AddAlpha_Alpha + matDiffuse = meshColor * tex.rgb; + specular = tex2.rgb * tex2.a * (1.0 - tex.a); + break; + } + case (15): { //Combiners_Opaque_Mod2xNA_Alpha_Add + matDiffuse = meshColor * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)); + specular = tex3.rgb * tex3.a * texSampleAlpha.b; + break; + } + case (16): { //Combiners_Mod_AddAlpha + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a; + canDiscard = true; + specular = tex2.rgb * tex2.a; + break; + } + case (17): { //Combiners_Mod_AddAlpha_Alpha + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a + tex2.a * (0.3 * tex2.r + 0.59 * tex2.g + 0.11 * tex2.b); + canDiscard = true; + specular = tex2.rgb * tex2.a * (1.0 - tex.a); + break; + } + case (18): { //Combiners_Opaque_Alpha_Alpha + matDiffuse = meshColor * mix(mix(tex.rgb, tex2.rgb, vec3(tex2.a)), tex.rgb, vec3(tex.a)); + break; + } + case (19): { //Combiners_Opaque_Mod2xNA_Alpha_3s + matDiffuse = meshColor * mix(tex.rgb * tex2.rgb * 2.0, tex3.rgb, vec3(tex3.a)); + break; + } + case (20): { //Combiners_Opaque_AddAlpha_Wgt + matDiffuse = meshColor * tex.rgb; + specular = tex2.rgb * tex2.a * texSampleAlpha.g; + break; + } + case (21): { //Combiners_Mod_Add_Alpha + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a + tex2.a; + canDiscard = true; + specular = tex2.rgb * (1.0 - tex.a); + break; + } + case (22): { //Combiners_Opaque_ModNA_Alpha + matDiffuse = meshColor * mix(tex.rgb * tex2.rgb, tex.rgb, vec3(tex.a)); + break; + } + case (23): { //Combiners_Mod_AddAlpha_Wgt + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a; + canDiscard = true; + specular = tex2.rgb * tex2.a * texSampleAlpha.g; + break; + } + case (24): { //Combiners_Opaque_Mod_Add_Wgt + matDiffuse = meshColor * mix(tex.rgb, tex2.rgb, vec3(tex2.a)); + specular = tex.rgb * tex.a * texSampleAlpha.r; + break; + } + case (25): { //Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha + float glowOpacity = clamp(tex3.a * texSampleAlpha.b, 0.0, 1.0); + matDiffuse = meshColor * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)) * (1.0 - glowOpacity); + specular = tex3.rgb * glowOpacity; + break; + } + case (26): { //Combiners_Mod_Dual_Crossfade + matDiffuse = meshColor * mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).rgb; + discardAlpha = mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).a; + canDiscard = true; + break; + } + case (27): { //Combiners_Opaque_Mod2xNA_Alpha_Alpha + matDiffuse = meshColor * mix(mix(tex.rgb * tex2.rgb * 2.0, tex3.rgb, vec3(tex3.a)), tex.rgb, vec3(tex.a)); + break; + } + case (28): { //Combiners_Mod_Masked_Dual_Crossfade + vec4 tex4 = texture(texSampler4, uv2).rgba; + matDiffuse = meshColor * mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).rgb; + discardAlpha = mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).a * tex4.a; + canDiscard = true; + break; + } + case (29): { //Combiners_Opaque_Alpha + matDiffuse = meshColor * mix(tex.rgb, tex2.rgb, vec3(tex2.a)); + break; + } + case (30): { //Guild + matDiffuse = meshColor * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a)); + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (31): { //Guild_NoBorder + matDiffuse = meshColor * tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)); + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (32): { //Guild_Opaque + matDiffuse = meshColor * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a)); + break; + } + case (33): { //Combiners_Mod_Depth + matDiffuse = meshColor * tex.rgb; + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (34): { //Illum + discardAlpha = tex.a; + canDiscard = true; + break; + } + case (35): { //Combiners_Mod_Mod_Mod_Const + matDiffuse = meshColor * (tex * tex2 * tex3 * genericParams[0]).rgb; + discardAlpha = (tex * tex2 * tex3 * genericParams[0]).a; + canDiscard = true; + break; + } + case (36): { //unk shader combiner + matDiffuse = meshColor * tex.rgb * tex2.rgb; + discardAlpha = tex.a * tex2.a; + canDiscard = true; + } + } + + bool doDiscard = false; + + if (blendMode == 13) { + finalOpacity = discardAlpha * meshOpacity; + } else if (blendMode == 1) { + finalOpacity = meshOpacity; + if (canDiscard && discardAlpha < 0.501960814) + doDiscard = true; + } else if (blendMode == 0) { + finalOpacity = meshOpacity; + } else { + finalOpacity = discardAlpha * meshOpacity; + } + + discardThisFragment = doDiscard; +} + +void calcM2VertexMat(in int vertexShader, + in vec3 vertexPosInView, + in vec3 normal, + in vec2 texCoord, + in vec2 texCoord2, + in vec4 color_Transparency, + in mat4 textMat[2], + out vec4 vMeshColorAlpha, + out vec2 vTexCoord, + out vec2 vTexCoord2, + out vec2 vTexCoord3) { + vTexCoord2 = vec2(0.0); + vTexCoord3 = vec2(0.0); + + vec2 envCoord = posToTexCoord(vertexPosInView, normal); + float edgeScanVal = edgeScan(vertexPosInView, normal); + + vMeshColorAlpha = color_Transparency; + if ( vertexShader == 0 ) {//Diffuse_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 1 ) {//Diffuse_Env + vTexCoord = envCoord; + } else if ( vertexShader == 2 ) {//Diffuse_T1_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 3 ) {//Diffuse_T1_Env + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = envCoord; + } else if ( vertexShader == 4 ) {//Diffuse_Env_T1 + vTexCoord = envCoord; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 5 ) {//Diffuse_Env_Env + vTexCoord = envCoord; + vTexCoord2 = envCoord; + } else if ( vertexShader == 6 ) {//Diffuse_T1_Env_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000) ).xy; + vTexCoord2 = envCoord; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 7 ) {//Diffuse_T1_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 8 ) {//Diffuse_T1_T1_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 9 ) {//Diffuse_EdgeFade_T1 + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = ((textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy).xy; + } else if ( vertexShader == 10 ) {//Diffuse_T2 + vTexCoord = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 11 ) {//Diffuse_T1_Env_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = envCoord; + vTexCoord3 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 12 ) {//Diffuse_EdgeFade_T1_T2 + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 13 ) {//Diffuse_EdgeFade_Env + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = envCoord; + } else if ( vertexShader == 14 ) {//Diffuse_T1_T2_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 15 ) {//Diffuse_T1_T2_T3 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + vTexCoord3 = vTexCoord3; + } else if ( vertexShader == 16 ) {//Color_T1_T2_T3 + vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0); + vMeshColorAlpha = vec4((in_col0.rgb * 0.500000).r, (in_col0.rgb * 0.500000).g, (in_col0.rgb * 0.500000).b, in_col0.a); + vTexCoord = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; + vTexCoord2 = vec2(0.000000, 0.000000); + vTexCoord3 = vTexCoord3; + } else if ( vertexShader == 17 ) {//BW_Diffuse_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } else if ( vertexShader == 18 ) {//BW_Diffuse_T1_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + } +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl new file mode 100644 index 000000000..f996a30e7 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl @@ -0,0 +1,280 @@ +#ifndef COMMON_WMO_MATERIAL +#define COMMON_WMO_MATERIAL + +#include "commonLightFunctions.glsl" +#include "commonFunctions.glsl" + +void caclWMOFragMat(in int pixelShader, bool enableAlpha, + in sampler2D s_texture, in sampler2D s_texture2, in sampler2D s_texture3, in sampler2D s_texture4, in sampler2D s_texture5, + in sampler2D s_texture6, in sampler2D s_texture7, in sampler2D s_texture8, in sampler2D s_texture9, + in vec3 vertexPosInView, + in vec3 normalInView, + in vec2 vTexCoord, + in vec2 vTexCoord2, + in vec2 vTexCoord3, + in vec2 vTexCoord4, + in vec4 vColor2, + + in vec4 vColorSecond, + out vec3 matDiffuse, out vec3 specular, out vec3 emissive, out float finalOpacity, out bool doDiscard) +{ + matDiffuse = vec3(0.0); + specular = vec3(0.0); + emissive = vec3(0.0); + finalOpacity = 1.0; + + vec4 tex = texture(s_texture, vTexCoord).rgba ; + vec4 tex2 = texture(s_texture2, vTexCoord2).rgba; + vec4 tex3 = texture(s_texture3, vTexCoord3).rgba; + + doDiscard = false; + if (enableAlpha) { + if ((tex.a - 0.501960814) < 0.0) { + doDiscard = true; + return; + } + } + + + // float distFade_1070 = clamp(((in_vpos.z * pc_miscParams.z) + pc_miscParams.w), 0, 1); + float distFade = 1.0; + + if ( pixelShader == -1 ) { + matDiffuse = tex.rgb * tex2.rgb; + finalOpacity = tex.a; + } else if (pixelShader == 0) { //MapObjDiffuse + + matDiffuse = tex.rgb; + finalOpacity = tex.a; + + } else if (pixelShader == 1) { //MapObjSpecular + + matDiffuse = tex.rgb; + specular = calcSpec(tex.a); + + finalOpacity = tex.a; + } else if (pixelShader == 2) { //MapObjMetal + + matDiffuse = tex.rgb ; + specular = calcSpec(((tex * 4.0) * tex.a).x); + + finalOpacity = tex.a; + } else if (pixelShader == 3) { //MapObjEnv + matDiffuse = tex.rgb ; + + emissive = tex2.rgb * tex.a * distFade; + finalOpacity = 1.0; + + } else if (pixelShader == 4) { //MapObjOpaque + + matDiffuse = tex.rgb ; + finalOpacity = 1.0; + + } else if (pixelShader == 5) { //MapObjEnvMetal + + matDiffuse = tex.rgb ; + emissive = (((tex.rgb * tex.a) * tex2.rgb) * distFade); + + finalOpacity = 1.0; + + } else if (pixelShader == 6) { //MapObjTwoLayerDiffuse + + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, tex2.a); + matDiffuse = mix(layer2, layer1, vColor2.a); + + finalOpacity = tex.a; + } else if (pixelShader == 7) { //MapObjTwoLayerEnvMetal + + vec4 colorMix = mix(tex2, tex, vColor2.a); + + matDiffuse = colorMix.rgb ; + emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; + + finalOpacity = tex.a; + + } else if (pixelShader == 8) { //MapObjTwoLayerTerrain + + vec3 layer1 = tex.rgb; + vec3 layer2 = tex2.rgb; + + matDiffuse = mix(layer2, layer1, vColor2.a); + specular = calcSpec(tex2.a * (1.0 - vColor2.a)); + + finalOpacity = tex.a; + + } else if (pixelShader == 9) { //MapObjDiffuseEmissive + + matDiffuse = tex.rgb ; + emissive = tex2.rgb * tex2.a * vColor2.a; + + finalOpacity = tex.a; + + } else if (pixelShader == 10) { //MapObjMaskedEnvMetal + + float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0); + matDiffuse = + mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a); + + finalOpacity = tex.a; + + } else if (pixelShader == 11) { //MapObjEnvMetalEmissive + matDiffuse = tex.rgb ; + emissive = + ( + ((tex.rgb * tex.a) * tex2.rgb) + + ((tex3.rgb * tex3.a) * vColor2.a) + ); + finalOpacity = tex.a; + + } else if (pixelShader == 12) { //MapObjTwoLayerDiffuseOpaque + matDiffuse = mix(tex2.rgb, tex.rgb, vColor2.a); + + finalOpacity = 1.0; + } else if (pixelShader == 13) { //MapObjTwoLayerDiffuseEmissive + vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a)); + + matDiffuse = mix(t1diffuse, tex.rgb, vColor2.a); + + emissive = (tex2.rgb * tex2.a) * (1.0 - vColor2.a); + + finalOpacity = tex.a; + } else if (pixelShader == 14) { //MapObjAdditiveMaskedEnvMetal + matDiffuse = mix( + (tex.rgb * tex2.rgb * 2.0) + (tex3.rgb * clamp(tex3.a * vColor2.a, 0.0, 1.0)), + tex.rgb, + vec3(tex.a) + ); + finalOpacity = 1.0; + } else if (pixelShader == 15) { //MapObjTwoLayerDiffuseMod2x + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); + vec3 layer3 = mix(layer2, layer1, vec3(vColor2.a)); + + matDiffuse = layer3 * tex3.rgb * 2.0; + finalOpacity = tex.a; + } if (pixelShader == 16) { //MapObjTwoLayerDiffuseMod2xNA + vec3 layer1 = ((tex.rgb * tex2.rgb) * 2.0); + + matDiffuse = mix(tex.rgb, layer1, vec3(vColor2.a)) ; + finalOpacity = tex.a; + } if (pixelShader == 17) { //MapObjTwoLayerDiffuseAlpha + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); + vec3 layer3 = mix(layer2, layer1, vec3(tex3.a)); + + matDiffuse = ((layer3 * tex3.rgb) * 2.0); + finalOpacity = tex.a; + } if (pixelShader == 18) { //MapObjLod + matDiffuse = tex.rgb ; + finalOpacity = tex.a; + } if (pixelShader == 19) { //MapObjParallax + vec4 tex_6 = texture(s_texture6, vTexCoord2).rgba; + + mat3 TBN = contangent_frame(normalInView, -vertexPosInView, vTexCoord2); + + float cosAlpha = dot(normalize(vertexPosInView.xyz), normalInView); + vec2 dotResult = (TBN * (normalize(-vertexPosInView.xyz) / cosAlpha)).xy; + + vec4 tex_4 = texture(s_texture4, vTexCoord2 - (dotResult * tex_6.r * 0.25)).rgba; + vec4 tex_5 = texture(s_texture5, vTexCoord3 - (dotResult * tex_6.r * 0.25)).rgba; + vec4 tex_3 = texture(s_texture3, vTexCoord2).rgba; + + vec3 mix1 = tex_5.rgb + tex_4.rgb * tex_4.a; + vec3 mix2 = (tex_3.rgb - mix1) * tex_6.g + mix1; + vec3 mix3 = tex_3.rgb * tex_6.b + (tex_5.rgb * tex_5.a * (1.0 - tex3.b)); + + vec4 tex_2 = texture(s_texture3, vColorSecond.bg).rgba; + vec3 tex_2_mult = tex_2.rgb * tex_2.a; + + vec3 emissive_component; + if (vColor2.a> 0.0) + { + vec4 tex = texture(s_texture, vTexCoord).rgba; + matDiffuse = (tex.rgb - mix2 ) * vColor2.a + mix2; + emissive_component = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; + } else { + emissive_component = tex_2_mult; + matDiffuse = mix2; + } + + emissive = (mix3 - (mix3 * vColor2.a)) + (emissive_component * tex_2.rgb); + } if (pixelShader == 20) { //MapObjUnkShader + vec4 tex_1 = texture(s_texture, posToTexCoord(vertexPosInView.xyz, normalInView.xyz)); + vec4 tex_2 = texture(s_texture2, vTexCoord); + vec4 tex_3 = texture(s_texture3, vTexCoord2); + vec4 tex_4 = texture(s_texture4, vTexCoord3); + vec4 tex_5 = texture(s_texture5, vTexCoord4); + + vec4 tex_6 = texture(s_texture6, vTexCoord).rgba; + vec4 tex_7 = texture(s_texture7, vTexCoord2).rgba; + vec4 tex_8 = texture(s_texture8, vTexCoord3).rgba; + vec4 tex_9 = texture(s_texture9, vTexCoord4).rgba; + + float secondColorSum = dot(vColorSecond.bgr, vec3(1.0)); + vec4 alphaVec = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004) * vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); + float maxAlpha = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); + vec4 alphaVec2 = (1.0 - clamp(vec4(maxAlpha) - alphaVec, 0.0, 1.0)); + alphaVec2 = alphaVec2 * alphaVec; + + vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); + + vec4 texMixed = tex_2 * alphaVec2Normalized.r + + tex_3 * alphaVec2Normalized.g + + tex_4 * alphaVec2Normalized.b + + tex_5 * alphaVec2Normalized.a; + + emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; + vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk + matDiffuse = (diffuseColor - texMixed.rgb) * vColorSecond.a + texMixed.rgb; + } +} + +void calcWMOVertMat(in int vertexShader, + in vec3 vertexPosInView, + in vec3 normalInView, + in vec2 aTexCoord, in vec2 aTexCoord2, in vec2 aTexCoord3, + out vec2 vTexCoord, out vec2 vTexCoord2, out vec2 vTexCoord3) { + if ( vertexShader == -1 ) { + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = aTexCoord3; + } else if (vertexShader == 0) { //MapObjDiffuse_T1 + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; //not used + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 1) { //MapObjDiffuse_T1_Refl + vTexCoord = aTexCoord; + vTexCoord2 = reflect(normalize(vertexPosInView.xyz), normalInView).xy; + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 2) { //MapObjDiffuse_T1_Env_T2 + vTexCoord = aTexCoord; + vTexCoord2 = posToTexCoord(vertexPosInView.xyz, normalInView); + vTexCoord3 = aTexCoord3; + } else if (vertexShader == 3) { //MapObjSpecular_T1 + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; //not used + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 4) { //MapObjDiffuse_Comp + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; //not used + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 5) { //MapObjDiffuse_Comp_Refl + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = reflect(normalize(vertexPosInView.xyz), normalInView).xy; + } else if (vertexShader == 6) { //MapObjDiffuse_Comp_Terrain + vTexCoord = aTexCoord; + vTexCoord2 = vertexPosInView.xy * -0.239999995; + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 7) { //MapObjDiffuse_CompAlpha + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = aTexCoord3; //not used + } else if (vertexShader == 8) { //MapObjParallax + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = aTexCoord3; + } +} +#endif \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/vulkan/adtLodShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtLodShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/adtLodShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/adtLodShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/adtLodShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtLodShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/adtLodShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/adtLodShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/adtShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/adtShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawBBShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawBBShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawBBShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawBBShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawDepthShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawDepthShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawDepthShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawDepthShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawFrustumShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawFrustumShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawFrustumShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawFrustumShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawFrustumShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawFrustumShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawFrustumShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawFrustumShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawLinesShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawLinesShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawLinesShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawLinesShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawLinesShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawLinesShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawLinesShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawLinesShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawPoints.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawPoints.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawPoints.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawPoints.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawPoints.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPoints.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawPoints.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawPoints.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawPortalShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawPortalShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/drawPortalShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawPortalShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/drawQuad.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/drawQuad.vert rename to wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/ffxgauss4.frag b/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/ffxgauss4.frag rename to wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/ffxglow.frag b/wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/ffxglow.frag rename to wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/imguiShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/imguiShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/imguiShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/imguiShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/m2ParticleShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag new file mode 100644 index 000000000..76fb63f2d --- /dev/null +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -0,0 +1,168 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +#ifndef MAX_MATRIX_NUM +#define MAX_MATRIX_NUM 220 +#endif + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonM2Material.glsl" + +struct LocalLight +{ + vec4 color; + vec4 position; + vec4 attenuation; +}; + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec2 vTexCoord3; +layout(location=3) in vec3 vNormal; +layout(location=4) in vec3 vPosition; +layout(location=5) in vec4 vMeshColorAlpha; + +layout(location=0) out vec4 outputColor; + +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +layout(std140, set=0, binding=1) uniform modelWideBlockVS { + mat4 uPlacementMat; + mat4 uBoneMatrixes[MAX_MATRIX_NUM]; +}; + +//Whole model +layout(std140, set=0, binding=3) uniform modelWideBlockPS { + InteriorLightParam intLight; + LocalLight pc_lights[4]; + ivec4 lightCountAndBcHack; + vec4 interiorExteriorBlend; +}; + +//Individual meshes +layout(std140, set=0, binding=4) uniform meshWideBlockPS { + ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; + vec4 uFogColorAndAlphaTest; + vec4 uTexSampleAlpha; + + + vec4 uPcColor; +}; + +layout(set=1,binding=5) uniform sampler2D uTexture; +layout(set=1,binding=6) uniform sampler2D uTexture2; +layout(set=1,binding=7) uniform sampler2D uTexture3; +layout(set=1,binding=8) uniform sampler2D uTexture4; + +void main() { + /* Animation support */ + vec2 texCoord = vTexCoord.xy; + vec2 texCoord2 = vTexCoord2.xy; + vec2 texCoord3 = vTexCoord3.xy; + + vec4 finalColor = vec4(0); + vec3 meshResColor = vMeshColorAlpha.rgb; + + vec3 accumLight = vec3(0.0); + if ((PixelShader_UnFogged_IsAffectedByLight_blendMode.z == 1)) { + vec3 vPos3 = vPosition.xyz; + vec3 vNormal3 = normalize(vNormal.xyz); + vec3 lightColor = vec3(0.0); + int count = int(pc_lights[0].attenuation.w); + + for (int index = 0; index < 4; index++) + { + if (index >= lightCountAndBcHack.x) break; + + LocalLight lightRecord = pc_lights[index]; + vec3 vectorToLight = ((scene.uLookAtMat * (uPlacementMat * lightRecord.position)).xyz - vPos3); + float distanceToLightSqr = dot(vectorToLight, vectorToLight); + float distanceToLightInv = inversesqrt(distanceToLightSqr); + float distanceToLight = (distanceToLightSqr * distanceToLightInv); + float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); + vec4 attenuationRec = lightRecord.attenuation; + + float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); + + vec3 attenuatedColor = attenuation * lightRecord.color.xyz; + lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); + } + + meshResColor.rgb = clamp(lightColor , 0.0, 1.0); + accumLight = mix(lightColor.rgb, meshResColor.rgb, lightCountAndBcHack.y); + //finalColor.rgb = finalColor.rgb * lightColor; + } + + float finalOpacity = 0.0; + vec3 matDiffuse; + vec3 specular; + + int uPixelShader = PixelShader_UnFogged_IsAffectedByLight_blendMode.x; + int blendMode = PixelShader_UnFogged_IsAffectedByLight_blendMode.w; + + bool doDiscard = false; + + calcM2FragMaterial(uPixelShader, + uTexture, uTexture2, uTexture3, uTexture4, + texCoord, texCoord2, texCoord3, + vMeshColorAlpha.rgb, vMeshColorAlpha.a, + uTexSampleAlpha.rgb, + blendMode, + matDiffuse, specular, finalOpacity, doDiscard + ); + + if (doDiscard) + discard; + + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + PixelShader_UnFogged_IsAffectedByLight_blendMode.z > 0, + interiorExteriorBlend.x, + scene, + intLight, + accumLight, + vec3(0.0), + specular, + vec3(0.0) + ) , + finalOpacity + ); + + outputColor = finalColor; + + int uUnFogged = PixelShader_UnFogged_IsAffectedByLight_blendMode.y; + if (uUnFogged == 0) { + vec3 sunDir = + mix( + scene.uInteriorSunDir, + scene.extLight.uExteriorDirectColorDir, + interiorExteriorBlend.x + ) + .xyz; + + finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, PixelShader_UnFogged_IsAffectedByLight_blendMode.w); + } +// finalColor.rgb = finalColor.rgb; + + + //Forward rendering without lights + outputColor = finalColor; + + //Deferred rendering + //gl_FragColor = finalColor; +// gl_FragData[0] = vec4(vec3(fs_Depth), 1.0); +// gl_FragData[1] = vec4(vPosition.xyz,0); +// gl_FragData[2] = vec4(vNormal.xyz,0); +// gl_FragData[3] = finalColor; + +} diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert new file mode 100644 index 000000000..7267361f3 --- /dev/null +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -0,0 +1,87 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +#ifndef MAX_MATRIX_NUM +#define MAX_MATRIX_NUM 220 +#endif + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonM2Material.glsl" + +/* vertex shader code */ +layout(location=0) in vec3 aPosition; +layout(location=1) in vec3 aNormal; +layout(location=2) in uvec4 bones; +layout(location=3) in vec4 boneWeights; +layout(location=4) in vec2 aTexCoord; +layout(location=5) in vec2 aTexCoord2; + +//Whole scene +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +// Whole model +layout(std140, set=0, binding=1) uniform modelWideBlockVS { + mat4 uPlacementMat; + mat4 uBoneMatrixes[MAX_MATRIX_NUM]; +}; + +//Individual meshes +layout(std140, set=0, binding=2) uniform meshWideBlockVS { + ivec4 vertexShader_IsAffectedByLight; + vec4 color_Transparency; + mat4 uTextMat[2]; +}; + +//Shader output +layout(location=0) out vec2 vTexCoord; +layout(location=1) out vec2 vTexCoord2; +layout(location=2) out vec2 vTexCoord3; +layout(location=3) out vec3 vNormal; +layout(location=4) out vec3 vPosition; +layout(location=5) out vec4 vMeshColorAlpha; + + +void main() { + vec4 modelPoint = vec4(0,0,0,0); + + vec4 aPositionVec4 = vec4(aPosition, 1); + mat4 boneTransformMat = mat4(0.0); + +// + boneTransformMat += (boneWeights.x ) * uBoneMatrixes[bones.x]; + boneTransformMat += (boneWeights.y ) * uBoneMatrixes[bones.y]; + boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; + boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; + + + mat4 placementMat; + placementMat = uPlacementMat; + + mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; + vec4 vertexPosInView = viewModelMat * aPositionVec4; + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + + vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; + + int uVertexShader = vertexShader_IsAffectedByLight.x; + calcM2VertexMat(uVertexShader, + vertexPosInView.xyz, normal, + aTexCoord, aTexCoord2, + color_Transparency, uTextMat, + vMeshColorAlpha, vTexCoord, vTexCoord2, vTexCoord3); + + gl_Position = scene.uPMatrix * vertexPosInView; + vNormal = normal; + vPosition = vertexPosInView.xyz; +} + + diff --git a/wowViewerLib/shaders/glsl/vulkan/renderFrameBufferShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/renderFrameBufferShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/renderFrameBufferShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/renderFrameBufferShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/renderFrameBufferShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/renderFrameBufferShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/renderFrameBufferShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/renderFrameBufferShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/ribbonShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/ribbonShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/ribbonShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/skyConus.frag b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/skyConus.frag rename to wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/skyConus.vert rename to wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert diff --git a/wowViewerLib/shaders/glsl/vulkan/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/waterShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert similarity index 87% rename from wowViewerLib/shaders/glsl/vulkan/waterShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index 871ce363d..053376e95 100644 --- a/wowViewerLib/shaders/glsl/vulkan/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -31,8 +31,8 @@ void main() { vec4 cameraPoint = cameraMatrix * aPositionVec4; - const float posToTextPos = 1.0 / (1600.0/3.0/16.0); - vTextCoords = aPositionVec4.xy * posToTextPos; + //const float posToTextPos = 1.0 / (1600.0/3.0/16.0); + vTextCoords = aTexCoord;//aPositionVec4.xy * posToTextPos; gl_Position = scene.uPMatrix * cameraPoint; // vTexCoord = aTexCoord; diff --git a/wowViewerLib/shaders/glsl/vulkan/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/waterfallShader.frag rename to wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag diff --git a/wowViewerLib/shaders/glsl/vulkan/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/vulkan/waterfallShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag new file mode 100644 index 000000000..de71fb501 --- /dev/null +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -0,0 +1,96 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require + +#define FRAGMENT_SHADER 1 + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonWMOMaterial.glsl" + + + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec2 vTexCoord3; +layout(location=3) in vec2 vTexCoord4; +layout(location=4) in vec4 vColor; +layout(location=5) in vec4 vColor2; +layout(location=6) in vec4 vColorSecond; +layout(location=7) in vec4 vPosition; +layout(location=8) in vec3 vNormal; + +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +layout(std140, set=0, binding=3) uniform modelWideBlockPS { + InteriorLightParam intLight; + +}; + +layout(std140, set=0, binding=4) uniform meshWideBlockPS { + ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; + vec4 FogColor_AlphaTest; +}; + +layout(set=1, binding=5) uniform sampler2D uTexture; +layout(set=1, binding=6) uniform sampler2D uTexture2; +layout(set=1, binding=7) uniform sampler2D uTexture3; +layout(set=1, binding=8) uniform sampler2D uTexture4; +layout(set=1, binding=9) uniform sampler2D uTexture5; +layout(set=1, binding=10) uniform sampler2D uTexture6; +layout(set=1, binding=11) uniform sampler2D uTexture7; +layout(set=1, binding=12) uniform sampler2D uTexture8; +layout(set=1, binding=13) uniform sampler2D uTexture9; + +layout (location = 0) out vec4 outputColor; + +void main() { + int uPixelShader = UseLitColor_EnableAlpha_PixelShader_BlendMode.z; + + vec3 matDiffuse = vec3(0.0); + vec3 spec = vec3(0.0); + vec3 emissive = vec3(0.0); + float finalOpacity = 0.0; + bool doDiscard; + + caclWMOFragMat(uPixelShader, UseLitColor_EnableAlpha_PixelShader_BlendMode.y == 1, + uTexture, uTexture2, uTexture3, uTexture4, + uTexture5, uTexture6, uTexture7, uTexture8, uTexture9, + vPosition.xyz, vNormal, vTexCoord, vTexCoord2, vTexCoord3, vTexCoord4, + vColor2, + vColorSecond, + matDiffuse, spec, emissive, finalOpacity, + doDiscard + ); + + if (doDiscard) + discard; + + vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + vColor.w, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vColor.rgb, + spec, /* specular */ + emissive + ), + finalOpacity + ); + + finalColor = makeFog(fogData, finalColor, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); + finalColor.a = 1.0; + + outputColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert similarity index 52% rename from wowViewerLib/shaders/glsl/vulkan/wmoShader.vert rename to wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index d0eab8879..b34310236 100644 --- a/wowViewerLib/shaders/glsl/vulkan/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -7,6 +7,8 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonWMOMaterial.glsl" /* vertex shader code */ layout (location = 0) in vec3 aPosition; @@ -41,7 +43,6 @@ layout(location=6) out vec4 vColorSecond; layout(location=7) out vec4 vPosition; layout(location=8) out vec3 vNormal; -#include "../common/commonFunctions.glsl" void main() { vec4 worldPoint = uPlacementMat * vec4(aPosition, 1); @@ -61,47 +62,6 @@ void main() { vTexCoord4 = aTexCoord4; int uVertexShader = VertexShader_UseLitColor.x; - if ( uVertexShader == -1 ) { - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; - vTexCoord3 = aTexCoord3; - } else if (uVertexShader == 0) { //MapObjDiffuse_T1 - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; //not used - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 1) { //MapObjDiffuse_T1_Refl - vTexCoord = aTexCoord; - vTexCoord2 = reflect(normalize(cameraPoint.xyz), vNormal).xy; - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 2) { //MapObjDiffuse_T1_Env_T2 - vTexCoord = aTexCoord; - - vTexCoord2 = posToTexCoord(vPosition.xyz, vNormal);; - vTexCoord3 = aTexCoord3; - } else if (uVertexShader == 3) { //MapObjSpecular_T1 - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; //not used - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 4) { //MapObjDiffuse_Comp - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; //not used - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 5) { //MapObjDiffuse_Comp_Refl - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; - vTexCoord3 = reflect(normalize(cameraPoint.xyz), vNormal).xy; - } else if (uVertexShader == 6) { //MapObjDiffuse_Comp_Terrain - vTexCoord = aTexCoord; - vTexCoord2 = vPosition.xy * -0.239999995; - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 7) { //MapObjDiffuse_CompAlpha - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; - vTexCoord3 = aTexCoord3; //not used - } else if (uVertexShader == 8) { //MapObjParallax - vTexCoord = aTexCoord; - vTexCoord2 = aTexCoord2; - vTexCoord3 = aTexCoord3; - } + calcWMOVertMat(uVertexShader, vPosition.xyz, vNormal, aTexCoord, aTexCoord2, aTexCoord3, vTexCoord, vTexCoord2, vTexCoord3); } diff --git a/wowViewerLib/shaders/glsl/vulkan/m2Shader.frag b/wowViewerLib/shaders/glsl/vulkan/m2Shader.frag deleted file mode 100644 index 7f03decac..000000000 --- a/wowViewerLib/shaders/glsl/vulkan/m2Shader.frag +++ /dev/null @@ -1,352 +0,0 @@ -#version 450 - -#extension GL_GOOGLE_include_directive: require - -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 -#endif - -precision highp float; -precision highp int; - -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" - -struct LocalLight -{ - vec4 color; - vec4 position; - vec4 attenuation; -}; - -layout(location=0) in vec2 vTexCoord; -layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec2 vTexCoord3; -layout(location=3) in vec3 vNormal; -layout(location=4) in vec3 vPosition; -layout(location=5) in vec4 vDiffuseColor; - -layout(location=0) out vec4 outputColor; - -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData; -}; - -layout(std140, set=0, binding=1) uniform modelWideBlockVS { - mat4 uPlacementMat; - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; -}; - -//Whole model -layout(std140, set=0, binding=3) uniform modelWideBlockPS { - InteriorLightParam intLight; - LocalLight pc_lights[4]; - ivec4 lightCountAndBcHack; - vec4 interiorExteriorBlend; -}; - -//Individual meshes -layout(std140, set=0, binding=4) uniform meshWideBlockPS { - ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; - vec4 uFogColorAndAlphaTest; - vec4 uTexSampleAlpha; - - - vec4 uPcColor; -}; - -layout(set=1,binding=5) uniform sampler2D uTexture; -layout(set=1,binding=6) uniform sampler2D uTexture2; -layout(set=1,binding=7) uniform sampler2D uTexture3; -layout(set=1,binding=8) uniform sampler2D uTexture4; - - - - -void main() { - /* Animation support */ - vec2 texCoord = vTexCoord.xy; - vec2 texCoord2 = vTexCoord2.xy; - vec2 texCoord3 = vTexCoord3.xy; - - /* Get color from texture */ - vec4 tex = texture(uTexture, texCoord).rgba; - vec4 tex2 = texture(uTexture2, texCoord2).rgba; - vec4 tex3 = texture(uTexture3, texCoord3).rgba; - - vec4 tex2WithTextCoord1 = texture(uTexture2,texCoord); - vec4 tex3WithTextCoord1 = texture(uTexture3,texCoord); - vec4 tex4WithTextCoord2 = texture(uTexture4,texCoord2); - -// vec4 tex = vec4(1.0, 1.0, 1.0, 1.0); -// vec4 tex2 = vec4(1.0, 1.0, 1.0, 1.0); -// vec4 tex3 = vec4(1.0, 1.0, 1.0, 1.0); - -// vec4 tex2WithTextCoord1 = vec4(1.0, 1.0, 1.0, 1.0); -// vec4 tex3WithTextCoord1 = vec4(1.0, 1.0, 1.0, 1.0); -// vec4 tex4WithTextCoord2 = vec4(1.0, 1.0, 1.0, 1.0); - - vec4 finalColor = vec4(0); - vec4 meshResColor = vDiffuseColor; - - vec3 accumLight; - if ((PixelShader_UnFogged_IsAffectedByLight_blendMode.z == 1)) { - vec3 vPos3 = vPosition.xyz; - vec3 vNormal3 = normalize(vNormal.xyz); - vec3 lightColor = vec3(0.0); - int count = int(pc_lights[0].attenuation.w); - - for (int index = 0; index < 4; index++) - { - if (index >= lightCountAndBcHack.x) break; - - LocalLight lightRecord = pc_lights[index]; - vec3 vectorToLight = ((scene.uLookAtMat * (uPlacementMat * lightRecord.position)).xyz - vPos3); - float distanceToLightSqr = dot(vectorToLight, vectorToLight); - float distanceToLightInv = inversesqrt(distanceToLightSqr); - float distanceToLight = (distanceToLightSqr * distanceToLightInv); - float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); - vec4 attenuationRec = lightRecord.attenuation; - - float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); - - vec3 attenuatedColor = attenuation * lightRecord.color.xyz; - lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); - } - - meshResColor.rgb = clamp(lightColor , 0.0, 1.0); - accumLight = mix(lightColor.rgb, meshResColor.rgb, lightCountAndBcHack.y); - //finalColor.rgb = finalColor.rgb * lightColor; - } - - float opacity; - float finalOpacity = 0.0; - vec3 matDiffuse; - vec3 specular = vec3(0.0, 0.0, 0.0); - vec3 visParams = vec3(1.0, 1.0, 1.0); - vec4 genericParams[3]; - genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 ); - genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 ); - genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 ); - bool canDiscard = false; - float discardAlpha = 1.0; - - int uPixelShader = PixelShader_UnFogged_IsAffectedByLight_blendMode.x; - - if ( uPixelShader == 0 ) { //Combiners_Opaque - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - } else if ( uPixelShader == 1 ) { //Combiners_Mod - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 2 ) { //Combiners_Opaque_Mod - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb; - discardAlpha = tex2.a; - canDiscard = true; - } else if ( uPixelShader == 3 ) { //Combiners_Opaque_Mod2x - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb * 2.0; - discardAlpha = tex2.a * 2.0; - canDiscard = true; - } else if ( uPixelShader == 4 ) { //Combiners_Opaque_Mod2xNA - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb * 2.0; - } else if ( uPixelShader == 5 ) { //Combiners_Opaque_Opaque - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb; - } else if ( uPixelShader == 6 ) { //Combiners_Mod_Mod - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb; - discardAlpha = tex.a * tex2.a; - canDiscard = true; - } else if ( uPixelShader == 7 ) { //Combiners_Mod_Mod2x - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb * 2.0; - discardAlpha = tex.a * tex2.a * 2.0; - canDiscard = true; - } else if ( uPixelShader == 8 ) { //Combiners_Mod_Add - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a + tex2.a; - canDiscard = true; - specular = tex2.rgb; - } else if ( uPixelShader == 9 ) { //Combiners_Mod_Mod2xNA - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb * 2.0; - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 10 ) { //Combiners_Mod_AddNA - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a; - canDiscard = true; - specular = tex2.rgb; - } else if ( uPixelShader == 11 ) { //Combiners_Mod_Opaque - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb; - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 12 ) { //Combiners_Opaque_Mod2xNA_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)); - } else if ( uPixelShader == 13 ) { //Combiners_Opaque_AddAlpha - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - specular = tex2.rgb * tex2.a; - } else if ( uPixelShader == 14 ) { //Combiners_Opaque_AddAlpha_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - specular = tex2.rgb * tex2.a * (1.0 - tex.a); - } else if ( uPixelShader == 15 ) { //Combiners_Opaque_Mod2xNA_Alpha_Add - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)); - specular = tex3.rgb * tex3.a * uTexSampleAlpha.b; - } else if ( uPixelShader == 16 ) { //Combiners_Mod_AddAlpha - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a; - canDiscard = true; - specular = tex2.rgb * tex2.a; - } else if ( uPixelShader == 17 ) { //Combiners_Mod_AddAlpha_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a + tex2.a * (0.3 * tex2.r + 0.59 * tex2.g + 0.11 * tex2.b); - canDiscard = true; - specular = tex2.rgb * tex2.a * (1.0 - tex.a); - } else if ( uPixelShader == 18 ) { //Combiners_Opaque_Alpha_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(mix(tex.rgb, tex2.rgb, vec3(tex2.a)), tex.rgb, vec3(tex.a)); - } else if ( uPixelShader == 19 ) { //Combiners_Opaque_Mod2xNA_Alpha_3s - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * tex2.rgb * 2.0, tex3.rgb, vec3(tex3.a)); - } else if ( uPixelShader == 20 ) { //Combiners_Opaque_AddAlpha_Wgt - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - specular = tex2.rgb * tex2.a * uTexSampleAlpha.g; - } else if ( uPixelShader == 21 ) { //Combiners_Mod_Add_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a + tex2.a; - canDiscard = true; - specular = tex2.rgb * (1.0 - tex.a); - } else if ( uPixelShader == 22 ) { //Combiners_Opaque_ModNA_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * tex2.rgb, tex.rgb, vec3(tex.a)); - } else if ( uPixelShader == 23 ) { //Combiners_Mod_AddAlpha_Wgt - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a; - canDiscard = true; - specular = tex2.rgb * tex2.a * uTexSampleAlpha.g; - } else if ( uPixelShader == 24 ) { //Combiners_Opaque_Mod_Add_Wgt - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb, tex2.rgb, vec3(tex2.a)); - specular = tex.rgb * tex.a * uTexSampleAlpha.r; - } else if ( uPixelShader == 25 ) { //Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha - float glowOpacity = clamp(tex3.a * uTexSampleAlpha.b, 0.0, 1.0); - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * tex2.rgb * 2.0, tex.rgb, vec3(tex.a)) * (1.0 - glowOpacity); - specular = tex3.rgb * glowOpacity; - } else if ( uPixelShader == 26 ) { //Combiners_Mod_Dual_Crossfade - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(uTexSampleAlpha.g, 0.0, 1.0))), tex3WithTextCoord1, vec4(clamp(uTexSampleAlpha.b, 0.0, 1.0))).rgb; - discardAlpha = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(uTexSampleAlpha.g, 0.0, 1.0))), tex3WithTextCoord1, vec4(clamp(uTexSampleAlpha.b, 0.0, 1.0))).a; - canDiscard = true; - } else if ( uPixelShader == 27 ) { //Combiners_Opaque_Mod2xNA_Alpha_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(mix(tex.rgb * tex2.rgb * 2.0, tex3.rgb, vec3(tex3.a)), tex.rgb, vec3(tex.a)); - } else if ( uPixelShader == 28 ) { //Combiners_Mod_Masked_Dual_Crossfade - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(uTexSampleAlpha.g, 0.0, 1.0))), tex3WithTextCoord1, vec4(clamp(uTexSampleAlpha.b, 0.0, 1.0))).rgb; - discardAlpha = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(uTexSampleAlpha.g, 0.0, 1.0))), tex3WithTextCoord1, vec4(clamp(uTexSampleAlpha.b, 0.0, 1.0))).a * tex4WithTextCoord2.a; - canDiscard = true; - } else if ( uPixelShader == 29 ) { //Combiners_Opaque_Alpha - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb, tex2.rgb, vec3(tex2.a)); - } else if ( uPixelShader == 30 ) { //Guild - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a)); - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 31 ) { //Guild_NoBorder - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)); - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 32 ) { //Guild_Opaque - matDiffuse = vDiffuseColor.rgb * 2.0 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a)); - } else if ( uPixelShader == 33 ) { //Combiners_Mod_Depth - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb; - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 34 ) { //Illum - discardAlpha = tex.a; - canDiscard = true; - } else if ( uPixelShader == 35 ) { //Combiners_Mod_Mod_Mod_Const - matDiffuse = vDiffuseColor.rgb * 2.0 * (tex * tex2 * tex3 * genericParams[0]).rgb; - discardAlpha = (tex * tex2 * tex3 * genericParams[0]).a; - canDiscard = true; - } else if ( uPixelShader == 36 ) { //unk shader combiner - matDiffuse = vDiffuseColor.rgb * 2.0 * tex.rgb * tex2.rgb; - discardAlpha = tex.a * tex2.a; - canDiscard = true; - - /* - WOTLK DEPRECATED SHADERS! - */ - /* - } else if (uPixelShader == -1) { // Combiners_Decal - finalColor.rgb = (meshResColor.rgb - tex.rgb) * meshResColor.a + tex.rgb; - finalColor.a = meshResColor.a; - } else if (uPixelShader == -2) { // Combiners_Add - finalColor.rgba = tex.rgba + meshResColor.rgba; - } else if (uPixelShader == -3) { // Combiners_Mod2x - finalColor.rgb = tex.rgb * meshResColor.rgb * vec3(2.0); - finalColor.a = tex.a * meshResColor.a * 2.0; - } else if (uPixelShader == -4) { // Combiners_Fade - finalColor.rgb = (tex.rgb - meshResColor.rgb) * meshResColor.a + meshResColor.rgb; - finalColor.a = meshResColor.a; - } else if (uPixelShader == -5) { // Combiners_Opaque_Add - finalColor.rgb = tex2.rgb + tex.rgb * meshResColor.rgb; - finalColor.a = meshResColor.a + tex.a; - } else if (uPixelShader == -6) { // Combiners_Opaque_AddNA - finalColor.rgb = tex2.rgb + tex.rgb * meshResColor.rgb; - finalColor.a = meshResColor.a; - } else if (uPixelShader == -7) { // Combiners_Add_Mod - finalColor.rgb = (tex.rgb + meshResColor.rgb) * tex2.a; - finalColor.a = (tex.a + meshResColor.a) * tex2.a; - } else if (uPixelShader == -8) { // Combiners_Mod2x_Mod2x - finalColor.rgba = tex.rgba * tex2.rgba * meshResColor.rgba * vec4(4.0); - */ - } - - int blendMode = PixelShader_UnFogged_IsAffectedByLight_blendMode.w; - - if (blendMode == 13) { - finalOpacity = discardAlpha * vDiffuseColor.a; - } else if (blendMode == 1) { - finalOpacity = vDiffuseColor.a; - if (canDiscard && discardAlpha < 0.501960814) - discard; - - finalOpacity = vDiffuseColor.a; - } else if (blendMode == 0) { - finalOpacity = vDiffuseColor.a; - } else { - finalOpacity = discardAlpha * vDiffuseColor.a; - } - - - finalColor = vec4( - calcLight( - matDiffuse, - vNormal, - PixelShader_UnFogged_IsAffectedByLight_blendMode.z > 0, - interiorExteriorBlend.x, - scene, - intLight, - accumLight, vec3(0.0), - specular, - vec3(0.0) /* emissive */ - ) , - finalOpacity - ); - - int uUnFogged = PixelShader_UnFogged_IsAffectedByLight_blendMode.y; - if (uUnFogged == 0) { - vec3 sunDir = - mix( - scene.uInteriorSunDir, - scene.extLight.uExteriorDirectColorDir, - interiorExteriorBlend.x - ) - .xyz; - - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, PixelShader_UnFogged_IsAffectedByLight_blendMode.w); - } -// finalColor.rgb = finalColor.rgb; - - - //Forward rendering without lights - outputColor = finalColor; - - //Deferred rendering - //gl_FragColor = finalColor; -// gl_FragData[0] = vec4(vec3(fs_Depth), 1.0); -// gl_FragData[1] = vec4(vPosition.xyz,0); -// gl_FragData[2] = vec4(vNormal.xyz,0); -// gl_FragData[3] = finalColor; - -} diff --git a/wowViewerLib/shaders/glsl/vulkan/m2Shader.vert b/wowViewerLib/shaders/glsl/vulkan/m2Shader.vert deleted file mode 100644 index b9772379c..000000000 --- a/wowViewerLib/shaders/glsl/vulkan/m2Shader.vert +++ /dev/null @@ -1,174 +0,0 @@ -#version 450 - -#extension GL_GOOGLE_include_directive: require - -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 -#endif - -precision highp float; -precision highp int; - -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" - -/* vertex shader code */ -layout(location=0) in vec3 aPosition; -layout(location=1) in vec3 aNormal; -layout(location=2) in uvec4 bones; -layout(location=3) in vec4 boneWeights; -layout(location=4) in vec2 aTexCoord; -layout(location=5) in vec2 aTexCoord2; - -//Whole scene -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData; -}; - -// Whole model -layout(std140, set=0, binding=1) uniform modelWideBlockVS { - mat4 uPlacementMat; - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; -}; - -//Individual meshes -layout(std140, set=0, binding=2) uniform meshWideBlockVS { - ivec4 vertexShader_IsAffectedByLight; - vec4 color_Transparency; - mat4 uTextMat[2]; -}; - -//Shader output -layout(location=0) out vec2 vTexCoord; -layout(location=1) out vec2 vTexCoord2; -layout(location=2) out vec2 vTexCoord3; -layout(location=3) out vec3 vNormal; -layout(location=4) out vec3 vPosition; -layout(location=5) out vec4 vDiffuseColor; - -#include "../common/commonFunctions.glsl" - -void main() { - vec4 modelPoint = vec4(0,0,0,0); - - vec4 aPositionVec4 = vec4(aPosition, 1); - mat4 boneTransformMat = mat4(0.0); - -// - boneTransformMat += (boneWeights.x ) * uBoneMatrixes[bones.x]; - boneTransformMat += (boneWeights.y ) * uBoneMatrixes[bones.y]; - boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; - boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; - - - mat4 placementMat; - placementMat = uPlacementMat; - - vec4 lDiffuseColor = color_Transparency; - - mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; - vec4 cameraPoint = viewModelMat * aPositionVec4; - mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); - -// vec3 normal = normalize(mat3(cameraMatrix) * aNormal); - vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; - vec4 combinedColor = clamp(lDiffuseColor /*+ vc_matEmissive*/, 0.000000, 1.000000); - vec4 combinedColorHalved = combinedColor * 0.5; - - vec2 envCoord = posToTexCoord(cameraPoint.xyz, normal); - float edgeScanVal = edgeScan(cameraPoint.xyz, normal); - - vTexCoord2 = vec2(0.0); - vTexCoord3 = vec2(0.0); - - int uVertexShader = vertexShader_IsAffectedByLight.x; - - if ( uVertexShader == 0 ) {//Diffuse_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 1 ) {//Diffuse_Env - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = envCoord; - } else if ( uVertexShader == 2 ) {//Diffuse_T1_T2 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 3 ) {//Diffuse_T1_Env - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = envCoord; - } else if ( uVertexShader == 4 ) {//Diffuse_Env_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = envCoord; - vTexCoord2 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 5 ) {//Diffuse_Env_Env - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = envCoord; - vTexCoord2 = envCoord; - } else if ( uVertexShader == 6 ) {//Diffuse_T1_Env_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000) ).xy; - vTexCoord2 = envCoord; - vTexCoord3 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 7 ) {//Diffuse_T1_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 8 ) {//Diffuse_T1_T1_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord3 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 9 ) {//Diffuse_EdgeFade_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal); - vTexCoord = ((uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy).xy; - } else if ( uVertexShader == 10 ) {//Diffuse_T2 - - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 11 ) {//Diffuse_T1_Env_T2 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = envCoord; - vTexCoord3 = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 12 ) {//Diffuse_EdgeFade_T1_T2 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 13 ) {//Diffuse_EdgeFade_Env - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal); - vTexCoord = envCoord; - } else if ( uVertexShader == 14 ) {//Diffuse_T1_T2_T1 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - vTexCoord3 = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 15 ) {//Diffuse_T1_T2_T3 - vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - vTexCoord3 = vTexCoord3; - } else if ( uVertexShader == 16 ) {//Color_T1_T2_T3 - vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0); - vDiffuseColor = vec4((in_col0.rgb * 0.500000).r, (in_col0.rgb * 0.500000).g, (in_col0.rgb * 0.500000).b, in_col0.a); - vTexCoord = (uTextMat[1] * vec4(aTexCoord2, 0.000000, 1.000000)).xy; - vTexCoord2 = vec2(0.000000, 0.000000); - vTexCoord3 = vTexCoord3; - } else if ( uVertexShader == 17 ) {//BW_Diffuse_T1 - vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } else if ( uVertexShader == 18 ) {//BW_Diffuse_T1_T2 - vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a); - vTexCoord = (uTextMat[0] * vec4(aTexCoord, 0.000000, 1.000000)).xy; - } - - - gl_Position = scene.uPMatrix * cameraPoint; - vNormal = normal; - vPosition = cameraPoint.xyz; - - -} - - diff --git a/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag b/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag deleted file mode 100644 index 471dcf825..000000000 --- a/wowViewerLib/shaders/glsl/vulkan/wmoShader.frag +++ /dev/null @@ -1,335 +0,0 @@ -#version 450 -#extension GL_GOOGLE_include_directive: require - -precision highp float; -precision highp int; - -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonFunctions.glsl" - -layout(location=0) in vec2 vTexCoord; -layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec2 vTexCoord3; -layout(location=3) in vec2 vTexCoord4; -layout(location=4) in vec4 vColor; -layout(location=5) in vec4 vColor2; -layout(location=6) in vec4 vColorSecond; -layout(location=7) in vec4 vPosition; -layout(location=8) in vec3 vNormal; - -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData; -}; - -layout(std140, set=0, binding=3) uniform modelWideBlockPS { - InteriorLightParam intLight; - -}; - -layout(std140, set=0, binding=4) uniform meshWideBlockPS { - ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; - vec4 FogColor_AlphaTest; -}; - -vec3 Slerp(vec3 p0, vec3 p1, float t) -{ - float dotp = dot(normalize(p0), normalize(p1)); - if ((dotp > 0.9999) || (dotp<-0.9999)) - { - if (t<=0.5) - return p0; - return p1; - } - float theta = acos(dotp); - vec3 P = ((p0*sin((1-t)*theta) + p1*sin(t*theta)) / sin(theta)); - - return P; -} - -vec3 calcSpec(float texAlpha) { - vec3 normal = normalize(vNormal); - - vec3 sunDir = vec3(0); - vec3 sunColor = vec3(0); - - if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { - sunDir = -(scene.extLight.uExteriorDirectColorDir.xyz); - sunColor = scene.extLight.uExteriorDirectColor.xyz; - } - - if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { - sunDir = -(scene.uInteriorSunDir.xyz); - sunColor = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz; - - if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { - sunDir = Slerp(sunDir, -(scene.extLight.uExteriorDirectColorDir.xyz), vColor.a); - sunColor = mix(sunColor, scene.extLight.uExteriorDirectColor.xyz, vColor.a); - } - } - - vec3 t849 = normalize((sunDir + normalize(-(vPosition.xyz)))); - float dirAtten_956 = clamp(dot(normal, sunDir), 0, 1); - float spec = (1.25 * pow(clamp(dot(normal, t849), 0, 1), 8.0)); - vec3 specTerm = ((((vec3(mix(pow((1.0 - clamp(dot(sunDir, t849), 0, 1)), 5.0), 1.0, texAlpha)) * spec) * sunColor) * dirAtten_956)); -// float distFade = clamp(((vPosition * pc_miscParams.z) + pc_miscParams.w), 0, 1); - float distFade = 1.0; - specTerm = (specTerm * distFade); - return specTerm; -} - -layout(set=1, binding=5) uniform sampler2D uTexture; -layout(set=1, binding=6) uniform sampler2D uTexture2; -layout(set=1, binding=7) uniform sampler2D uTexture3; -layout(set=1, binding=8) uniform sampler2D uTexture4; -layout(set=1, binding=9) uniform sampler2D uTexture5; -layout(set=1, binding=10) uniform sampler2D uTexture6; -layout(set=1, binding=11) uniform sampler2D uTexture7; -layout(set=1, binding=12) uniform sampler2D uTexture8; -layout(set=1, binding=13) uniform sampler2D uTexture9; - -layout (location = 0) out vec4 outputColor; - -void main() { - vec4 tex = texture(uTexture, vTexCoord).rgba ; - vec4 tex2 = texture(uTexture2, vTexCoord2).rgba; - vec4 tex3 = texture(uTexture3, vTexCoord3).rgba; - - if (UseLitColor_EnableAlpha_PixelShader_BlendMode.y == 1) { - if ((tex.a - 0.501960814) < 0.0) { - discard; - } - } - - int uPixelShader = UseLitColor_EnableAlpha_PixelShader_BlendMode.z; - vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); - vec3 matDiffuse = vec3(0.0); - vec3 spec = vec3(0.0); - vec3 emissive = vec3(0.0); - float finalOpacity = 0.0; - - // float distFade_1070 = clamp(((in_vpos.z * pc_miscParams.z) + pc_miscParams.w), 0, 1); - float distFade = 1.0; - - if ( uPixelShader == -1 ) { - matDiffuse = tex.rgb * tex2.rgb; - finalOpacity = tex.a; - } else if (uPixelShader == 0) { //MapObjDiffuse - - matDiffuse = tex.rgb; - finalOpacity = tex.a; - - } else if (uPixelShader == 1) { //MapObjSpecular - - matDiffuse = tex.rgb; - spec = calcSpec(tex.a); - - finalOpacity = tex.a; - } else if (uPixelShader == 2) { //MapObjMetal - - matDiffuse = tex.rgb ; - spec = calcSpec(((tex * 4.0) * tex.a).x); - - finalOpacity = tex.a; - } else if (uPixelShader == 3) { //MapObjEnv - matDiffuse = tex.rgb ; - - emissive = tex2.rgb * tex.a * distFade; - finalOpacity = 1.0; - - } else if (uPixelShader == 4) { //MapObjOpaque - - matDiffuse = tex.rgb ; - finalOpacity = 1.0; - - } else if (uPixelShader == 5) { //MapObjEnvMetal - - matDiffuse = tex.rgb ; - emissive = (((tex.rgb * tex.a) * tex2.rgb) * distFade); - - finalOpacity = 1.0; - - } else if (uPixelShader == 6) { //MapObjTwoLayerDiffuse - - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, tex2.a); - matDiffuse = mix(layer2, layer1, vColor2.a); - - finalOpacity = tex.a; - } else if (uPixelShader == 7) { //MapObjTwoLayerEnvMetal - - vec4 colorMix = mix(tex2, tex, vColor2.a); - - matDiffuse = colorMix.rgb ; - emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; - - finalOpacity = tex.a; - - } else if (uPixelShader == 8) { //MapObjTwoLayerTerrain - - vec3 layer1 = tex.rgb; - vec3 layer2 = tex2.rgb; - - matDiffuse = mix(layer2, layer1, vColor2.a); - spec = calcSpec(tex2.a * (1.0 - vColor2.a)); - - finalOpacity = tex.a; - - } else if (uPixelShader == 9) { //MapObjDiffuseEmissive - - matDiffuse = tex.rgb ; - emissive = tex2.rgb * tex2.a * vColor2.a; - - finalOpacity = tex.a; - - } else if (uPixelShader == 10) { //MapObjMaskedEnvMetal - - float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0); - matDiffuse = - mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a); - - finalOpacity = tex.a; - - } else if (uPixelShader == 11) { //MapObjEnvMetalEmissive - matDiffuse = tex.rgb ; - emissive = - ( - ((tex.rgb * tex.a) * tex2.rgb) + - ((tex3.rgb * tex3.a) * vColor2.a) - ); - finalOpacity = tex.a; - - } else if (uPixelShader == 12) { //MapObjTwoLayerDiffuseOpaque - matDiffuse = mix(tex2.rgb, tex.rgb, vColor2.a); - - finalOpacity = 1.0; - } else if (uPixelShader == 13) { //MapObjTwoLayerDiffuseEmissive - vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a)); - - matDiffuse = mix(t1diffuse, tex.rgb, vColor2.a); - - emissive = (tex2.rgb * tex2.a) * (1.0 - vColor2.a); - - finalOpacity = tex.a; - } else if (uPixelShader == 14) { //MapObjAdditiveMaskedEnvMetal - matDiffuse = mix( - (tex.rgb * tex2.rgb * 2.0) + (tex3.rgb * clamp(tex3.a * vColor2.a, 0.0, 1.0)), - tex.rgb, - vec3(tex.a) - ); - finalOpacity = 1.0; - } else if (uPixelShader == 15) { //MapObjTwoLayerDiffuseMod2x - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); - vec3 layer3 = mix(layer2, layer1, vec3(vColor2.a)); - - matDiffuse = layer3 * tex3.rgb * 2.0; - finalOpacity = tex.a; - } if (uPixelShader == 16) { //MapObjTwoLayerDiffuseMod2xNA - vec3 layer1 = ((tex.rgb * tex2.rgb) * 2.0); - - matDiffuse = mix(tex.rgb, layer1, vec3(vColor2.a)) ; - finalOpacity = tex.a; - } if (uPixelShader == 17) { //MapObjTwoLayerDiffuseAlpha - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); - vec3 layer3 = mix(layer2, layer1, vec3(tex3.a)); - - matDiffuse = ((layer3 * tex3.rgb) * 2.0); - finalOpacity = tex.a; - } if (uPixelShader == 18) { //MapObjLod - matDiffuse = tex.rgb ; - finalOpacity = tex.a; - } if (uPixelShader == 19) { //MapObjParallax - vec4 tex_6 = texture(uTexture6, vTexCoord2).rgba; - vec3 crossDy = cross(dFdy(vPosition.xyz), vNormal); - vec3 crossDx = cross(vNormal, dFdx(vPosition.xyz)); - vec2 dTexCoord2Dx = dFdx(vTexCoord2); - vec2 dTexCoord2Dy = dFdy(vTexCoord2); - - vec3 sum1 = dTexCoord2Dy.x * crossDx + dTexCoord2Dx.x * crossDy; - vec3 sum2 = dTexCoord2Dy.y * crossDx + dTexCoord2Dx.y * crossDy; - - float maxInverseDot = inversesqrt(max(dot(sum1,sum1), dot(sum2, sum2))); - float cosAlpha = dot(normalize(vPosition.xyz), vNormal); - - float dot1 = dot(maxInverseDot * sum1, normalize(vPosition.xyz)) / cosAlpha; - float dot2 = dot(maxInverseDot * sum2, normalize(vPosition.xyz)) / cosAlpha; - - vec4 tex_4 = texture(uTexture4, vTexCoord2 - (vec2(dot1, dot2)* tex_6.r * 0.25)).rgba; - vec4 tex_5 = texture(uTexture5, vTexCoord3 - (vec2(dot1, dot2)* tex_6.r * 0.25)).rgba; - vec4 tex_3 = texture(uTexture3, vTexCoord2).rgba; - - vec3 mix1 = tex_5.rgb + tex_4.rgb * tex_4.a; - vec3 mix2 = (tex_3.rgb - mix1) * tex_6.g + mix1; - vec3 mix3 = tex_3.rgb * tex_6.b + (tex_5.rgb * tex_5.a * (1.0 - tex3.b)); - - vec4 tex_2 = texture(uTexture3, vColorSecond.bg).rgba; - vec3 tex_2_mult = tex_2.rgb * tex_2.a; - - vec3 emissive_component; - if (vColor2.a> 0.0) - { - vec4 tex = texture(uTexture, vTexCoord).rgba; - matDiffuse = (tex.rgb - mix2 ) * vColor2.a + mix2; - emissive_component = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; - } else { - emissive_component = tex_2_mult; - matDiffuse = mix2; - } - - emissive = (mix3 - (mix3 * vColor2.a)) + (emissive_component * tex_2.rgb); - - } if (uPixelShader == 20) { //MapObjUnkShader - vec4 tex_1 = texture(uTexture, posToTexCoord(vPosition.xyz, vNormal.xyz)); - vec4 tex_2 = texture(uTexture2, vTexCoord); - vec4 tex_3 = texture(uTexture3, vTexCoord2); - vec4 tex_4 = texture(uTexture4, vTexCoord3); - vec4 tex_5 = texture(uTexture5, vTexCoord4); - - vec4 tex_6 = texture(uTexture6, vTexCoord).rgba; - vec4 tex_7 = texture(uTexture7, vTexCoord2).rgba; - vec4 tex_8 = texture(uTexture8, vTexCoord3).rgba; - vec4 tex_9 = texture(uTexture9, vTexCoord4).rgba; - - float secondColorSum = dot(vColorSecond.bgr, vec3(1.0)); - vec4 alphaVec = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004) * vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); - float maxAlpha = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); - vec4 alphaVec2 = (1.0 - clamp(vec4(maxAlpha) - alphaVec, 0.0, 1.0)); - alphaVec2 = alphaVec2 * alphaVec; - - vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); - - vec4 texMixed = tex_2 * alphaVec2Normalized.r + - tex_3 * alphaVec2Normalized.g + - tex_4 * alphaVec2Normalized.b + - tex_5 * alphaVec2Normalized.a; - - emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; - vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk - matDiffuse = (diffuseColor - texMixed.rgb) * vColorSecond.a + texMixed.rgb; - } - - finalColor = vec4( - calcLight( - matDiffuse, - vNormal, - true, - vColor.w, - scene, - intLight, - vec3(0.0) /*accumLight*/, - vColor.rgb, - spec, /* specular */ - emissive - ), - finalOpacity - ); - - finalColor = makeFog(fogData, finalColor, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); - -// finalColor.a = 1.0; //do I really need it now? - - outputColor = finalColor; -} diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 22383eee6..e1ab87828 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -1388,6 +1388,8 @@ AdtObject::AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDa } bool AdtObject::getWaterColorFromDB(mathfu::vec4 cameraPos, mathfu::vec3 &closeRiverColor) { + if (!m_loaded) return false; + auto adt_x = worldCoordinateToAdtIndex(cameraPos.y); auto adt_y = worldCoordinateToAdtIndex(cameraPos.x); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 3a2f17573..019d60f62 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -475,24 +475,69 @@ void M2Object::createAABB() { auto min = mathfu::vec3(9999, 9999, 9999); auto max = mathfu::vec3(-9999, -9999, -9999); +// auto indexBuffer = m_skinGeom->generateIndexBuffer(); +// auto m2SkinProfile = m_skinGeom->getSkinData(); +// for (int batchIndex = 0; batchIndex < m2SkinProfile->batches.size; batchIndex++) { +// M2Batch *textMaterial = m2SkinProfile->batches.getElement(batchIndex); +// M2SkinSection *skinSection = m2SkinProfile->skinSections.getElement(textMaterial->skinSectionIndex); +// +// int vertexIndexStart = skinSection->indexStart + (skinSection->Level << 16); +// +// for (int i = 0; i < skinSection->indexCount; i++) { +// auto *vertex = m2Data->vertices.getElement(vertexIndexStart+i); +// +// min = mathfu::vec3( +// mathfu::vec3( +// std::min(min.x, vertex->pos.x), +// std::min(min.y, vertex->pos.y), +// std::min(min.z, vertex->pos.z) +// ) +// ); +// +// max = mathfu::vec3( +// mathfu::vec3( +// std::max(max.x, vertex->pos.x), +// std::max(max.y, vertex->pos.y), +// std::max(max.z, vertex->pos.z) +// ) +// ); +// } +// } for (int i = 0; i < m2Data->vertices.size; i++) { auto *vertex = m2Data->vertices.getElement(i); + min = mathfu::vec3( + mathfu::vec3( + std::min(min.x, vertex->pos.x), + std::min(min.y, vertex->pos.y), + std::min(min.z, vertex->pos.z) + ) + ); + + max = mathfu::vec3( + mathfu::vec3( + std::max(max.x, vertex->pos.x), + std::max(max.y, vertex->pos.y), + std::max(max.z, vertex->pos.z) + ) + ); + } - min = mathfu::vec3(mathfu::vec3(std::min(min.x, vertex->pos.x), - std::min(min.y, vertex->pos.y), - std::min(min.z, vertex->pos.z))); + //TODO: undo this :D - max = mathfu::vec3(mathfu::vec3(std::max(max.x, vertex->pos.x), - std::max(max.y, vertex->pos.y), - std::max(max.z, vertex->pos.z))); + mathfu::vec4 minVec = mathfu::vec4(min.x - 10, min.y - 10, min.z - 10, 1); + mathfu::vec4 maxVec = mathfu::vec4(max.x + 10, max.y + 10, max.z + 10, 1); + if (min.x > max.x) { + minVec = {0,0,0,1}; + maxVec = {0,0,0,1}; } -// std::cout << "calculated min = (" << min.x << ", " << min.y << ", " << min.z << ")" << std::endl; -// std::cout << "calculated max = (" << max.x << ", " << max.y << ", " << max.z << ")" << std::endl; - } + CAaBox worldAABB = MathHelper::transformAABBWithMat4(m_placementMatrix, minVec, maxVec); + this->aabb = worldAABB; + } + if (false) { C3Vector min = m2Data->bounding_box.min; C3Vector max = m2Data->bounding_box.max; @@ -1531,8 +1576,8 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti meshTemplate.skybox = m_boolSkybox; HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; - meshTemplate.texture.resize(m2Batch->textureCount); - meshTemplate.textureCount = m2Batch->textureCount; + meshTemplate.texture.resize(4); + meshTemplate.textureCount = 4; for (int j = 0; j < material.textureCount; j++) { meshTemplate.texture[j] = material.textures[j]; } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 0f35d152f..15f7e8954 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1239,12 +1239,15 @@ void Map::checkADTCulling(int i, int j, if ((j < 0) || (j > 64)) return; if (this->m_adtConfigHolder != nullptr) { - float maxZ = m_adtConfigHolder->adtMaxZ[i][j]; - float minZ = m_adtConfigHolder->adtMinZ[i][j]; + mathfu::vec3 min = m_adtConfigHolder->adtMin[i][j]; + mathfu::vec3 max = m_adtConfigHolder->adtMax[i][j]; CAaBox box = { - C3Vector({AdtIndexToWorldCoordinate(j + 1) , AdtIndexToWorldCoordinate(i + 1), minZ}), - C3Vector({AdtIndexToWorldCoordinate(j) , AdtIndexToWorldCoordinate(i), maxZ}) + C3Vector(min), + C3Vector(max) + +// C3Vector({AdtIndexToWorldCoordinate(j + 1) , AdtIndexToWorldCoordinate(i + 1), minZ}), +// C3Vector({AdtIndexToWorldCoordinate(j) , AdtIndexToWorldCoordinate(i), maxZ}) }; bool bbCheck = MathHelper::checkFrustum( frustumData, box); @@ -1409,7 +1412,6 @@ void Map::doPostLoad(HCullStage &cullStage) { }; void Map::update(HUpdateStage &updateStage) { - mapUpdateCounter.beginMeasurement(); mathfu::vec3 cameraVec3 = updateStage->cameraMatrices->cameraPos.xyz(); mathfu::mat4 &frustumMat = updateStage->cameraMatrices->perspectiveMat; mathfu::mat4 &lookAtMat = updateStage->cameraMatrices->lookAtMat; @@ -1478,9 +1480,6 @@ void Map::update(HUpdateStage &updateStage) { adtCleanupCounter.endMeasurement(); this->m_currentTime += updateStage->delta; - mapUpdateCounter.endMeasurement(); - - m_api->getConfig()->mapUpdateTime = mapUpdateCounter.getTimePerFrame(); m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); @@ -1607,7 +1606,9 @@ animTime_t Map::getCurrentSceneTime() { } void Map::produceUpdateStage(HUpdateStage &updateStage) { mapProduceUpdateCounter.beginMeasurement(); + mapUpdateCounter.beginMeasurement(); this->update(updateStage); + mapUpdateCounter.endMeasurement(); //Create meshes updateStage->opaqueMeshes = std::make_shared(); @@ -1746,6 +1747,7 @@ void Map::produceUpdateStage(HUpdateStage &updateStage) { m_api->getConfig()->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); + m_api->getConfig()->mapUpdateTime = mapUpdateCounter.getTimePerFrame(); m_api->getConfig()->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); m_api->getConfig()->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); m_api->getConfig()->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 9edda338a..347007ea0 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -218,9 +218,9 @@ const std::unordered_map shaderMetaInfo = {{ "wmoSh } },{ "wmoShader.frag.spv", { { -{0,3,32}, -{0,0,368}, {0,4,32}, +{0,0,368}, +{0,3,32}, } } },{ "waterShader.frag.spv", { @@ -233,13 +233,11 @@ const std::unordered_map shaderMetaInfo = {{ "wmoSh { {0,4,96}, {0,0,368}, -{0,1,14144}, } } },{ "adtShader.vert.spv", { { {0,0,368}, -{0,2,16}, } } },{ "adtLodShader.vert.spv", { @@ -285,7 +283,6 @@ const std::unordered_map shaderMetaInfo = {{ "wmoSh } },{ "drawFrustumShader.frag.spv", { { -{0,2,12}, } } },{ "drawDepthShader.frag.spv", { @@ -310,7 +307,6 @@ const std::unordered_map shaderMetaInfo = {{ "wmoSh } },{ "drawLinesShader.frag.spv", { { -{0,1,12}, } } },{ "skyConus.frag.spv", { @@ -399,8 +395,8 @@ const std::unordered_map shaderMetaInfo = {{ "wmoSh },{ "m2Shader.vert.spv", { { {0,1,14144}, -{0,2,160}, {0,0,368}, +{0,2,160}, } } },{ "ribbonShader.frag.spv", { @@ -415,35 +411,35 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 1, { - {"_818_uPlacementMat", true, 0, 4, 4, 0}, - {"_818_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, { 0, { - {"_709_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_709_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_709_scene_uViewUp", true, 128, 1, 4, 0}, - {"_709_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_709_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_709_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_709_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_709_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_709_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_709_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_709_fogData_densityParams", true, 256, 1, 4, 0}, - {"_709_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_709_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_709_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_709_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_709_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_709_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_686_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_686_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_686_scene_uViewUp", true, 128, 1, 4, 0}, + {"_686_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_686_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_686_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_686_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_686_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_686_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_686_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_686_fogData_densityParams", true, 256, 1, 4, 0}, + {"_686_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_686_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_686_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_686_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_686_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_686_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, { 4, { - {"_445_values0", true, 0, 1, 4, 0}, - {"_445_values1", true, 16, 1, 4, 0}, - {"_445_values2", true, 32, 1, 4, 0}, - {"_445_values3", true, 48, 1, 4, 0}, - {"_445_values4", true, 64, 1, 4, 0}, - {"_445_baseColor", true, 80, 1, 4, 0}, + {"_419_values0", true, 0, 1, 4, 0}, + {"_419_values1", true, 16, 1, 4, 0}, + {"_419_values2", true, 32, 1, 4, 0}, + {"_419_values3", true, 48, 1, 4, 0}, + {"_419_values4", true, 64, 1, 4, 0}, + {"_419_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -812,35 +797,35 @@ const std::unordered_map(device)) { - uniformsAvailable = 5*4096; imageAvailable = 4096 * 4; setsAvailable = 4096; diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index a0f17bc2c..bbbbe4b2a 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -211,16 +211,16 @@ struct AdtCellHasher { struct ADTRenderConfigData { ADTRenderConfigData() { - std::array defaultMaxZ = {}; - std::array defaultMinZ = {}; - defaultMaxZ.fill(-200000); - defaultMinZ.fill(200000); + std::array defaultMax = {}; + std::array defaultMin = {}; + defaultMax.fill({-200000, -200000, -200000}); + defaultMin.fill({200000, 200000, 200000}); - adtMaxZ.fill(defaultMaxZ); - adtMinZ.fill(defaultMinZ); + adtMax.fill(defaultMax); + adtMin.fill(defaultMin); } - std::array, 64> adtMaxZ; - std::array, 64> adtMinZ; + std::array, 64> adtMin; + std::array, 64> adtMax; std::unordered_set excludedADTs; std::unordered_map, AdtCellHasher> excludedChunksPerADTs; }; From 692c7f89145599fb40fecc9c598a4a827ce33201 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 20 Nov 2022 18:31:10 +0200 Subject: [PATCH 007/212] env mapping finally working correctly --- .../shaders/glsl/common/commonFunctions.glsl | 6 +- .../src/engine/shader/ShaderDefinitions.h | 124 +++++++++--------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl index 858fe2ea5..edb7a119b 100644 --- a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl @@ -1,13 +1,13 @@ #ifndef COMMON_FUNCTION_GLSL #define COMMON_FUNCTION_GLSL -vec2 posToTexCoord(const vec3 cameraPoint, const vec3 normal){ +vec2 posToTexCoord(const vec3 vertexPosInView, const vec3 normal){ //Blizz seems to have vertex in view space as vector from "vertex to eye", while in this implementation, it's //vector from "eye to vertex". So the minus here is not needed //vec3 viewVecNormalized = -normalize(cameraPoint.xyz); - vec3 viewVecNormalized = normalize(cameraPoint.xyz); - vec3 reflection = reflect(viewVecNormalized, normal); + vec3 viewVecNormalized = normalize(vertexPosInView.xyz); + vec3 reflection = reflect(viewVecNormalized, normalize(normal)); vec3 temp_657 = vec3(reflection.x, reflection.y, (reflection.z + 1.0)); return ((normalize(temp_657).xy * 0.5) + vec2(0.5)); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 347007ea0..066cab727 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -616,36 +616,36 @@ const std::unordered_map Date: Thu, 24 Nov 2022 21:04:47 +0200 Subject: [PATCH 008/212] refactoring and fixing m2 for vulkan --- src/ui/FrontendUI.cpp | 3 + .../glsl/common/commonWMOMaterial.glsl | 2 +- .../glsl/forwardRendering/adtShader.vert | 11 +- .../glsl/forwardRendering/waterShader.frag | 2 +- .../forwardRendering/waterfallShader.frag | 2 +- .../forwardRendering/waterfallShader.vert | 10 +- .../src/engine/camera/m2TiedCamera.cpp | 9 +- wowViewerLib/src/engine/camera/m2TiedCamera.h | 2 + .../src/engine/geometry/wmoGroupGeom.cpp | 39 ++---- .../src/engine/geometry/wmoGroupGeom.h | 23 ++-- .../src/engine/managers/animationManager.cpp | 27 ++-- .../src/engine/objects/adt/adtObject.cpp | 125 +++++++++--------- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/wmo/wmoObject.cpp | 3 +- .../src/engine/shader/ShaderDefinitions.h | 114 ++++++++-------- .../gapi/ogl2.0/GVertexBufferBindingsGL20.cpp | 2 +- .../gapi/ogl4.x/GVertexBufferBindingsGL4x.cpp | 2 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 6 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 3 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 1 + 20 files changed, 197 insertions(+), 193 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 1ba1a8159..eeb5649cd 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -726,6 +726,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { openWMOSceneByfdid(4419436); } + if (ImGui::Button("14654.wmo (parallax)", ImVec2(-1, 0))) { + openWMOSceneByfdid(4222547); + } if (ImGui::Button("10.0 Raid WMO", ImVec2(-1, 0))) { openWMOSceneByfdid(4282557); } diff --git a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl index f996a30e7..06a292f84 100644 --- a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl @@ -265,7 +265,7 @@ void calcWMOVertMat(in int vertexShader, vTexCoord3 = reflect(normalize(vertexPosInView.xyz), normalInView).xy; } else if (vertexShader == 6) { //MapObjDiffuse_Comp_Terrain vTexCoord = aTexCoord; - vTexCoord2 = vertexPosInView.xy * -0.239999995; + vTexCoord2 = vertexPosInView.xy * 0.239999995; vTexCoord3 = aTexCoord3; //not used } else if (vertexShader == 7) { //MapObjDiffuse_CompAlpha vTexCoord = aTexCoord; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 72266831e..8bb322838 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -9,7 +9,7 @@ precision highp int; #include "../common/commonFogFunctions.glsl" /* vertex shader code */ -layout(location = 0) in vec3 aHeight; +layout(location = 0) in vec3 aPos; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; @@ -61,16 +61,17 @@ void main() { // uPos.z + aHeight, // 1); - vec4 worldPoint = vec4( - aHeight, - 1); + vec4 worldPoint = vec4(aPos, 1); vChunkCoords = vec2(iX, iY); vPosition = (scene.uLookAtMat * worldPoint).xyz; vColor = aColor; vVertexLighting = aVertexLighting.rgb; - vNormal = blizzTranspose(scene.uLookAtMat) * aNormal; + mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); + vec3 normal = normalize(viewMatForNormal * vec4(aNormal, 0.0)).xyz; + + vNormal = normal; gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 486aa3afa..e9e4e9b4c 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -29,7 +29,7 @@ layout(std140, binding=4) uniform meshWideBlockPS { void main() { vec3 matDiffuse = color.rgb+texture(uTexture, vTextCoords).rgb; - vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; //BlendMode is always GxBlend_Alpha vec3 finalColor = makeFog(fogData, vec4(matDiffuse, 1.0), vPosition.xyz, sunDir.xyz, 2).rgb; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index 48ac322be..ef30eeb62 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -75,7 +75,7 @@ vec3 PerturbNormal ( vec3 surf_pos, vec3 surf_norm ) } void main() { - vec3 perturbedNormal = PerturbNormal(vPosition, normalize(vNormal)); + vec3 perturbedNormal = PerturbNormal(-vPosition, normalize(vNormal)); vec2 vTexCoordNorm = vTexCoord / values1.x; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index b0da765fb..3197eb7ff 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -65,13 +65,11 @@ void main() { boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; - mat4 cameraMatrix = scene.uLookAtMat * uPlacementMat * boneTransformMat ; - vec4 cameraPoint = cameraMatrix * vec4(pos, 1.0); + mat4 viewModelMat = scene.uLookAtMat * uPlacementMat * boneTransformMat ; + vec4 cameraPoint = viewModelMat * vec4(pos, 1.0); - mat3 viewModelMatTransposed = - blizzTranspose(scene.uLookAtMat) * - blizzTranspose(uPlacementMat) * - blizzTranspose(boneTransformMat); + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; vNormal = (scene.uLookAtMat * uPlacementMat * vec4(aNormal, 0)).xyz; vPosition = pos; diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp index dc287777b..d82a0691e 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp @@ -5,9 +5,9 @@ #include "m2TiedCamera.h" void m2TiedCamera::getCameraPosition(float *position) { - position[0] = m_lastCameraResult.target_position.x; - position[1] = m_lastCameraResult.target_position.y; - position[2] = m_lastCameraResult.target_position.z; + position[0] = lastCameraPos.x; + position[1] = lastCameraPos.y; + position[2] = lastCameraPos.z; } void m2TiedCamera::tick(animTime_t timeDelta) { @@ -44,7 +44,8 @@ HCameraMatrices m2TiedCamera::getCameraMatrices(float fov, float canvasAspect, f farPlane); cameraMatrices->lookAtMat = lookAtMat4; - cameraMatrices->cameraPos = mathfu::vec4(m_lastCameraResult.position.xyz(), 1.0); + lastCameraPos = lookAtMat4.Inverse() * mathfu::vec4(0,0,0,1); + cameraMatrices->cameraPos = lastCameraPos; cameraMatrices->viewUp = mathfu::vec4(upVectorTranformed, 0); cameraMatrices->interiorDirectLightDir = mathfu::vec4(0,0,0,0); diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.h b/wowViewerLib/src/engine/camera/m2TiedCamera.h index 604573e74..023f44e4a 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.h +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.h @@ -20,6 +20,8 @@ class m2TiedCamera : public ICamera { int m_cameraNum = -1; M2CameraResult m_lastCameraResult; + mathfu::vec4 lastCameraPos = mathfu::vec4(0,0,0,1.0); + mathfu::vec4 lastCameraDir = mathfu::vec4(0,0,0,1.0); public: void startMovingForward() override {}; void stopMovingForward() override {}; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 4793a575a..f6dd6c896 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -308,25 +308,12 @@ HGVertexBuffer WmoGroupGeom::getVBO(const HGDevice &device) { if (combinedVBO == nullptr) { combinedVBO = device->createVertexBuffer(); - PACK( - struct VboFormat { - C3Vector pos; - C3Vector normal; - C2Vector textCoordinate; - C2Vector textCoordinate2; - C2Vector textCoordinate3; - C2Vector textCoordinate4; - CImVector color; - CImVector color2; - CImVector colorSecond; - }); - static const C2Vector c2ones = C2Vector(mathfu::vec2(1.0, 1.0)); static const C3Vector c3zeros = C3Vector(mathfu::vec3(0, 0, 0)); - std::vector buffer (verticesLen); + std::vector buffer (verticesLen); for (int i = 0; i < verticesLen; i++) { - VboFormat &format = buffer[i]; + WMOVertex &format = buffer[i]; format.pos = verticles[i]; if (normalsLen > 0) { format.normal = normals[i]; @@ -379,7 +366,7 @@ HGVertexBuffer WmoGroupGeom::getVBO(const HGDevice &device) { } } - combinedVBO->uploadData(&buffer[0], (int)(verticesLen * sizeof(VboFormat))); + combinedVBO->uploadData(&buffer[0], (int)(verticesLen * sizeof(WMOVertex))); } return combinedVBO; @@ -397,15 +384,15 @@ HGIndexBuffer WmoGroupGeom::getIBO(const HGDevice &device) { } static const std::array staticWMOBindings = {{ - {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 68 , 0 }, - {+wmoShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, 68, 12}, - {+wmoShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 68, 24}, - {+wmoShader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, 68, 32}, - {+wmoShader::Attribute::aTexCoord3, 2, GBindingType::GFLOAT, false, 68, 40}, - {+wmoShader::Attribute::aTexCoord4, 2, GBindingType::GFLOAT, false, 68, 48}, - {+wmoShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, 68, 56}, - {+wmoShader::Attribute::aColor2, 4, GBindingType::GUNSIGNED_BYTE, true, 68, 60}, - {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true, 68, 64} + {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, pos) }, + {+wmoShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, normal)}, + {+wmoShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate)}, + {+wmoShader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate2)}, + {+wmoShader::Attribute::aTexCoord3, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate3)}, + {+wmoShader::Attribute::aTexCoord4, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate4)}, + {+wmoShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color)}, + {+wmoShader::Attribute::aColor2, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color2)}, + {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; static GBufferBinding staticWMOWaterBindings[2] = { @@ -491,7 +478,7 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi } } - std::vector vboBuffer; + std::vector iboBuffer; for (int j = 0; j < m_mliq->ytiles; j++) diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index ae96848fb..255663bce 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -12,9 +12,23 @@ #include "../../include/sharedFile.h" #include "../../gapi/interface/IDevice.h" +PACK( + struct WMOVertex { + C3Vector pos; + C3Vector normal; + C2Vector textCoordinate; + C2Vector textCoordinate2; + C2Vector textCoordinate3; + C2Vector textCoordinate4; + CImVector color; + CImVector color2; + CImVector colorSecond; + } +); + class WmoGroupGeom : public PersistentFile { public: - WmoGroupGeom(std::string fileName){m_fileName = fileName;}; + WmoGroupGeom(std::string fileName){ m_fileName = fileName; }; WmoGroupGeom(int fileDataId){ m_fileDataId = fileDataId;}; void process(HFileContent wmoGroupFile, const std::string &fileName) override; @@ -32,13 +46,6 @@ class WmoGroupGeom : public PersistentFile { int getFileDataId() const {return m_fileDataId;} const std::string &getFileName() const {return m_fileName;} private: - int normalOffset = 0; - int textOffset = 0; - int textOffset2 = 0; - int textOffset3 = 0; - int colorOffset = 0; - int colorOffset2 = 0; - std::function m_attenuateFunc; int getLegacyWaterType(int a); diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index f15f46c6d..dd65f5971 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -182,13 +182,10 @@ void blendMatrices(std::vector &origMat, std::vector template inline void calcAnimationTransform( mathfu::mat4 &tranformMat, - mathfu::mat4 *billboardMatrix, mathfu::vec4 &pivotPoint, mathfu::vec4 &negatePivotPoint, M2Array &global_loops, std::vector &globalSequenceTimes, - - bool &isAnimated, M2Track &translationTrack, M2Track &rotationTrack, M2Track &scaleTrack, @@ -207,12 +204,9 @@ inline void calcAnimationTransform( ); tranformMat = tranformMat * mathfu::mat4::FromTranslationVector(transVec.xyz()); - isAnimated = true; } - if (billboardMatrix != nullptr) { - tranformMat = tranformMat * *billboardMatrix; - } else if (rotationTrack.values.size > 0) { + if (rotationTrack.values.size > 0) { mathfu::quat defaultValue = mathfu::quat(1,0,0,0); mathfu::quat quaternionResult = animateTrackWithBlend( animationInfo, @@ -222,7 +216,6 @@ inline void calcAnimationTransform( defaultValue); tranformMat = tranformMat * quaternionResult.ToMatrix4(); - isAnimated = true; } if (scaleTrack.values.size > 0) { @@ -235,7 +228,6 @@ inline void calcAnimationTransform( defaultValue); tranformMat = tranformMat * mathfu::mat4::FromScaleVector(scaleResult.xyz()); - isAnimated = true; } tranformMat = tranformMat * mathfu::mat4::FromTranslationVector(negatePivotPoint.xyz()); } @@ -489,15 +481,13 @@ AnimationManager::calcBoneMatrix( mathfu::mat4 *billboardMatrix = nullptr; /* 3. Calculate matrix */ - bool isAnimated = (boneDefinition->flags_raw & 0x280) > 0; + const bool isAnimated = (boneDefinition->flags_raw & 0x280) > 0; mathfu::mat4 animatedMatrix = mathfu::mat4::Identity(); if (isAnimated) { calcAnimationTransform(animatedMatrix, - billboardMatrix, pivotPoint, negatePivotPoint, *globalSequences, *globalSequenceTimes, - isAnimated, boneDefinition->translation, boneDefinition->rotation, boneDefinition->scaling, @@ -918,6 +908,18 @@ void AnimationManager::update( for (int i = 0; i < bones.size; i++) { this->bonesIsCalculated[i] = false; } + +// //NOT WORKING +// //Feed modelViewMatrix that would transform to "from vertex to eye", instead of "from eye to vertex", like normally +// //This is intended +// auto blizzModelViewMat = mathfu::mat4::FromScaleVector(mathfu::vec3(-1, -1, -1)) * modelViewMatrix; +// this->calcBones(bonesMatrices, blizzModelViewMat); +// +// mathfu::mat4 invBlizzModelViewMat = blizzModelViewMat.Inverse(); +// for (int i = 0; i < bones.size; i++) { +// bonesMatrices[i] = invBlizzModelViewMat * bonesMatrices[i]; +// } +// this->calcBones(bonesMatrices, modelViewMatrix); mathfu::mat4 invModelViewMatrix = modelViewMatrix.Inverse(); @@ -925,6 +927,7 @@ void AnimationManager::update( bonesMatrices[i] = invModelViewMatrix * bonesMatrices[i]; } + this->calcSubMeshColors(subMeshColors); this->calcTransparencies(transparencies); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index e1ab87828..b9eff05ca 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -14,17 +14,34 @@ #include "tbb/parallel_for.h" #include "tbb/blocked_range2d.h" -static GBufferBinding bufferBinding[5] = { - {(uint32_t)adtShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 60, 0}, - {(uint32_t)adtShader::Attribute::aHeight, 3, GBindingType::GFLOAT, false, 60, 4}, - {(uint32_t)adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, 60, 16 }, - {(uint32_t)adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, 60, 28}, - {(uint32_t)adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, 60, 44}, -}; +PACK( + struct AdtVertex { + mathfu::vec3_packed pos; + float helpIndex = 0.0f; + mathfu::vec3_packed normal; + mathfu::vec4_packed mccv; + mathfu::vec4_packed mclv; + } +); +PACK( + struct LiquidVertexFormat { + mathfu::vec4_packed pos_transp; + mathfu::vec2_packed uv; + } +); + + +static std::array adtVertexBufferBinding = {{ + {+adtShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, helpIndex)}, + {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, + {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, + {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, + {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, +}}; static GBufferBinding staticWaterBindings[2] = { - {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, 24, 0}, - {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 24, 16}, + {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, + {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)}, // {+waterShader::Attribute::aDepth, 1, GBindingType::GFLOAT, false, 24, 0 }, // {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 24, 4}, @@ -142,7 +159,6 @@ void AdtObject::loadWmos() { } HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { - uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water if (liquidInstance.offset_exists_bitmap > 0 && liquidInstance.height > 0) { @@ -204,13 +220,6 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid int i = this->m_adtFile->mcnkMap[x_chunk][y_chunk]; auto &waterAaBB = waterTileAabb[i]; SMChunk *mcnkChunk = &m_adtFile->mapTile[i]; -// - -// -// float minX = mcnkChunk->position.x - (MathHelper::CHUNKSIZE); -// float maxX = mcnkChunk->position.x; -// float minY = mcnkChunk->position.y - (MathHelper::CHUNKSIZE); -// float maxY = mcnkChunk->position.y; float minX = 999999; float maxX = -999999; float minY = 999999; float maxY = -999999; @@ -221,11 +230,6 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid minZ = std::min(minZ, waterAaBB.min.z); maxZ = std::max(maxZ, waterAaBB.max.z); //Parse the blob - PACK( - struct LiquidVertexFormat { - mathfu::vec4_packed pos_transp; - mathfu::vec2_packed uv; - }); std::vector vertexBuffer; std::vector indexBuffer; @@ -433,7 +437,8 @@ void AdtObject::loadWater() { void AdtObject::createVBO() { /* 1. help index + Heights + texCoords + */ - std::vector vboArray ; + + std::vector vboArray ; //DEBUG // //Interate MLLL @@ -462,66 +467,57 @@ void AdtObject::createVBO() { // } // std::cout<< "mlsi: min_index = "<< min_index << " max_index = " << max_index<< std::endl << std::flush; + const float UNITSIZE = (1600.0 / 3.0) / 16.0 / 8.0; for (int i = 0; i <= m_adtFile->mcnkRead; i++) { for (int j = 0; j < 9 * 9 + 8 * 8; j++) { + AdtVertex &adtVertex = vboArray.emplace_back(); /* 1.1 help index */ - vboArray.push_back((float)j); + adtVertex.helpIndex = j; /* 1.2 Heights */ - float iX = fmod(j, 17.0); - float iY = floor(j/17.0); + float iX = fmod(j, 17.0f); + float iY = floor(j/17.0f); if (iX > 8.01f) { - iY = iY + 0.5; - iX = iX - 8.5; + iY = iY + 0.5f; + iX = iX - 8.5f; } - mathfu::vec3 pos = mathfu::vec3( - m_adtFile->mapTile[i].position.x - iY * UNITSIZE, - m_adtFile->mapTile[i].position.y - iX * UNITSIZE, - m_adtFile->mapTile[i].position.z + m_adtFile->mcnkStructs[i].mcvt->height[j] ); - - vboArray.push_back(pos.x); - vboArray.push_back(pos.y); - vboArray.push_back(pos.z); - -// std::cout << " i = " << i << " j = " << j << " pos = " << pos.x << ", " << pos.y << ", " << pos.z << std::endl; + adtVertex.pos = { m_adtFile->mapTile[i].position.x - iY * UNITSIZE, + m_adtFile->mapTile[i].position.y - iX * UNITSIZE, + m_adtFile->mapTile[i].position.z + m_adtFile->mcnkStructs[i].mcvt->height[j] }; /* 1.3 Normals */ if (m_adtFile->mcnkStructs[i].mcnr != nullptr) { for (int k = 0; k < 3; k++) { - vboArray.push_back(m_adtFile->mcnkStructs[i].mcnr->entries[j].normal[k] / 127.0f); + adtVertex.normal.data_[k] = m_adtFile->mcnkStructs[i].mcnr->entries[j].normal[k] / 127.0f; } } else { - vboArray.push_back(0.0); - vboArray.push_back(0.0); - vboArray.push_back(1.0); + adtVertex.normal = { 0, 0, 1.0 }; } /* 1.4 MCCV */ //Color vertex if (m_adtFile->mcnkStructs[i].mccv != nullptr) { auto &mccv = m_adtFile->mcnkStructs[i].mccv; - vboArray.push_back(mccv->entries[j].red / 255.0f); - vboArray.push_back(mccv->entries[j].green / 255.0f); - vboArray.push_back(mccv->entries[j].blue / 255.0f); - vboArray.push_back(mccv->entries[j].alpha / 255.0f); + adtVertex.mccv = { + mccv->entries[j].red / 255.0f, + mccv->entries[j].green / 255.0f, + mccv->entries[j].blue / 255.0f, + mccv->entries[j].alpha / 255.0f, + }; } else { - vboArray.push_back(0.5f); - vboArray.push_back(0.5f); - vboArray.push_back(0.5f); - vboArray.push_back(0.5f); + adtVertex.mccv = { 0.5f, 0.5f, 0.5f, 0.5f}; } /* 1.4 MCLV */ //Lightning Vertex if (m_adtFile->mcnkStructs[i].mclv != nullptr) { auto &mclv = m_adtFile->mcnkStructs[i].mclv; - vboArray.push_back(mclv->values[j].b / 255.0f); - vboArray.push_back(mclv->values[j].g / 255.0f); - vboArray.push_back(mclv->values[j].r / 255.0f); - vboArray.push_back(mclv->values[j].a / 255.0f); + adtVertex.mclv = { + mclv->values[j].b / 255.0f, + mclv->values[j].g / 255.0f, + mclv->values[j].r / 255.0f, + mclv->values[j].a / 255.0f + }; } else { //If MCLV is empty, localDiffuse doesnt exist in shader - vboArray.push_back(0.0f); - vboArray.push_back(0.0f); - vboArray.push_back(0.0f); - vboArray.push_back(0.0f); + adtVertex.mclv = { 0.0f, 0.0f, 0.0f, 0.0f }; } } } @@ -529,7 +525,7 @@ void AdtObject::createVBO() { /* 1.3 Make combinedVbo */ HGDevice device = m_api->hDevice; combinedVbo = device->createVertexBuffer(); - combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(float)); + combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(AdtVertex)); /* 2. Strips */ @@ -542,7 +538,8 @@ void AdtObject::createVBO() { GVertexBufferBinding vertexBinding; vertexBinding.vertexBuffer = combinedVbo; - vertexBinding.bindings = std::vector(&bufferBinding[0], &bufferBinding[5]); + vertexBinding.bindings = std::vector(adtVertexBufferBinding.begin(), + adtVertexBufferBinding.end()); adtVertexBindings->addVertexBufferBinding(vertexBinding); adtVertexBindings->save(); @@ -581,10 +578,10 @@ void AdtObject::createVBO() { GVertexBufferBinding vertexBinding; vertexBinding.vertexBuffer = combinedVbo; - GBufferBinding bufferBinding = { +adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 4, 0 }; - vertexBinding.bindings.push_back(bufferBinding); - bufferBinding = { +adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 4, static_cast(indexVBOLodOffset * sizeof(float))}; - vertexBinding.bindings.push_back(bufferBinding); + GBufferBinding adtLodBufferBinding = { +adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 4, 0 }; + vertexBinding.bindings.push_back(adtLodBufferBinding); + GBufferBinding adtLodBufferBinding2 = {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 4, static_cast(indexVBOLodOffset * sizeof(float))}; + vertexBinding.bindings.push_back(adtLodBufferBinding2); lodVertexBindings->addVertexBufferBinding(vertexBinding); lodVertexBindings->save(); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index a90defbcf..fe0fdfba3 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -248,7 +248,9 @@ class M2Object { if (m_useLocalDiffuseColor == -1) { m_useLocalDiffuseColor = value ? 1 : 0; } - m_useLocalDiffuseColor = ( m_useLocalDiffuseColor == 0 ? m_useLocalDiffuseColor : (value ? 1 : 0) ); + if (value && m_useLocalDiffuseColor == 0) { + m_useLocalDiffuseColor = 1; + } return m_useLocalDiffuseColor == 1; }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 252539604..b60fa68d5 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -838,6 +838,7 @@ bool WmoObject::startTraversingWMOGroup( if (interiorView == nullptr) { interiorView = viewsHolder.createInterior(frustumDataGlobal); ivPerWMOGroup[groupId] = interiorView; + interiorView->ownerGroupWMO = groupObjects[groupId]; interiorView->wmoGroupArray.addToDraw(nextGroupObject); interiorView->wmoGroupArray.addToCheckM2(nextGroupObject); } @@ -892,7 +893,7 @@ bool WmoObject::startTraversingWMOGroup( } } - //Add all ALAWAYSRENDER to Exterior + //Add all ALWAYSRENDER to Exterior for (int i = 0; i< mainGeom->groupsLen; i++) { if ((mainGeom->groups[i].flags.ALWAYSDRAW) > 0) { //exterior auto exteriorView = viewsHolder.getOrCreateExterior(frustumDataGlobal); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 066cab727..a4c27cf22 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -50,7 +50,7 @@ struct adtLodShader { struct adtShader { enum class Attribute { - aHeight = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd }; }; @@ -152,7 +152,7 @@ const std::unordered_map> attributesPe {"aHeight", 0}, {"aIndex", 1}, }},{"adtShader", { -{"aHeight", 0}, +{"aPos", 0}, {"aColor", 1}, {"aVertexLighting", 2}, {"aNormal", 3}, @@ -411,35 +411,35 @@ const std::unordered_map{}(k.triCCW) << 4) ^ (hash{}(k.depthCulling) << 8) ^ (hash{}(k.depthWrite) << 10) ^ - (hash{}(k.blendMode) << 16) ^ - (hash{}(k.element) << 24); + (hash{}(k.invertZ) << 12) ^ + (hash{}(k.blendMode) << 14) ^ + (hash{}(k.element) << 16); }; }; std::unordered_map, PipelineCacheRecordHasher> loadedPipeLines; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index f19984ad4..58c808c7c 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -85,13 +85,14 @@ GMeshVLK::GMeshVLK(IDevice &device, //Works under assumption that meshes do not often change the renderpass on which they are rendered std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ) { - if (m_lastRenderPass != renderPass) { + if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, m_shader, renderPass, m_element, m_backFaceCulling, m_triCCW, m_blendMode, m_depthCulling, m_depthWrite, invertedZ); m_lastRenderPass = renderPass; + m_lastInvertedZ = invertedZ; } return m_lastPipelineForRenderPass; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index b55737871..0e8750f4f 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -70,6 +70,7 @@ class GMeshVLK : public IMesh { VkDescriptorPool m_descriptorPool; std::shared_ptr m_lastRenderPass = nullptr; + bool m_lastInvertedZ = false; std::shared_ptr m_lastPipelineForRenderPass; From df2922779869646185c8a425826995a449c90f45 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 3 Dec 2022 16:02:12 +0200 Subject: [PATCH 009/212] temp commit --- src/main.cpp | 2 - src/minimapGenerator/minimapGenerator.cpp | 2 +- src/ui/FrontendUI.cpp | 54 +++++++++---------- wowViewerLib/CMakeLists.txt | 7 ++- .../glsl/forwardRendering/wmoShader.frag | 2 +- wowViewerLib/src/engine/DrawStage.h | 17 ------ wowViewerLib/src/engine/SceneComposer.cpp | 2 +- wowViewerLib/src/engine/SceneScenario.h | 50 +++++++---------- .../src/engine/camera/m2TiedCamera.cpp | 6 +-- .../src/engine/objects/ViewsObjects.h | 8 +-- .../src/engine/objects/adt/adtObject.cpp | 1 - .../src/engine/objects/m2/m2Object.cpp | 5 +- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 24 ++++----- .../src/engine/objects/scenes/wmoScene.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 6 +-- .../src/engine/persistance/adtFile.cpp | 1 - .../src/engine/shader/ShaderDefinitions.h | 38 ++++++------- wowViewerLib/src/gapi/interface/IDevice.h | 11 ++-- .../src/gapi/interface/textures/IBlpTexture.h | 9 ---- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h | 2 + .../gapi/ogl2.0/GVertexBufferBindingsGL20.cpp | 14 ----- .../gapi/ogl2.0/textures/GBlpTextureGL20.h | 1 - wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h | 2 + .../gapi/ogl3.3/textures/GBlpTextureGL33.h | 1 - .../gapi/ogl4.x/textures/GBlpTextureGL4x.h | 1 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 4 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 16 +++--- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- .../src/renderer/MapSceneRenderer.cpp | 5 ++ wowViewerLib/src/renderer/MapSceneRenderer.h | 21 ++++++++ .../src/renderer/MapSceneRendererFactory.cpp | 18 +++++++ .../src/renderer/MapSceneRendererFactory.h | 17 ++++++ .../vulkan/MapSceneRenderForwardVLK.cpp | 13 +++++ .../vulkan/MapSceneRenderForwardVLK.h | 25 +++++++++ 35 files changed, 219 insertions(+), 174 deletions(-) delete mode 100644 wowViewerLib/src/gapi/interface/textures/IBlpTexture.h create mode 100644 wowViewerLib/src/renderer/MapSceneRenderer.cpp create mode 100644 wowViewerLib/src/renderer/MapSceneRenderer.h create mode 100644 wowViewerLib/src/renderer/MapSceneRendererFactory.cpp create mode 100644 wowViewerLib/src/renderer/MapSceneRendererFactory.h create mode 100644 wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp create mode 100644 wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h diff --git a/src/main.cpp b/src/main.cpp index 796c6d428..e3ebf40d0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -426,8 +426,6 @@ int main(){ SceneComposer sceneComposer = SceneComposer(apiContainer); - // WoWScene *scene = createWoWScene(testConf, storage, sqliteDB, device, canvWidth, canvHeight); - frontendUI = std::make_shared(apiContainer, nullptr); glfwSetWindowUserPointer(window, &apiContainer); diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index dcbeecea3..2b16d9e00 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -988,7 +988,7 @@ void MinimapGenerator::getCurrentFDData(int &areaId, int &parentAreaId, mathfu:: areaId = cullStage->adtAreadId; parentAreaId = cullStage->parentAreaId; - riverColor = cullStage->frameDepedantData->closeRiverColor; + riverColor = cullStage->frameDependentData->closeRiverColor; mathfu::vec4 cameraPos = {0,0,0,1}; this->m_apiContainer->camera->getCameraPosition(cameraPos.data_); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index eeb5649cd..7d19d85b3 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -232,42 +232,42 @@ void FrontendUI::showCurrentStatsDialog() { } if (ImGui::CollapsingHeader("Current fog params")) { - if (cullStageData != nullptr && cullStageData->frameDepedantData != nullptr) { - ImGui::Text("Fog end: %.3f", cullStageData->frameDepedantData->FogEnd); - ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDepedantData->FogScaler); - ImGui::Text("Fog Density: %.3f", cullStageData->frameDepedantData->FogDensity); - ImGui::Text("Fog Height: %.3f", cullStageData->frameDepedantData->FogHeight); - ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDepedantData->FogHeightScaler); - ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDepedantData->FogHeightDensity); - ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDepedantData->SunFogAngle); + if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { + ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); + ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); + ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); + ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); + ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); + ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); + ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDepedantData->FogColor.x, - cullStageData->frameDepedantData->FogColor.y, - cullStageData->frameDepedantData->FogColor.z); + cullStageData->frameDependentData->FogColor.x, + cullStageData->frameDependentData->FogColor.y, + cullStageData->frameDependentData->FogColor.z); ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDepedantData->EndFogColor.x, - cullStageData->frameDepedantData->EndFogColor.y, - cullStageData->frameDepedantData->EndFogColor.z); - ImGui::Text("End Fog Color Distance: %.3f", cullStageData->frameDepedantData->EndFogColorDistance); + cullStageData->frameDependentData->EndFogColor.x, + cullStageData->frameDependentData->EndFogColor.y, + cullStageData->frameDependentData->EndFogColor.z); + ImGui::Text("End Fog Color Distance: %.3f", cullStageData->frameDependentData->EndFogColorDistance); ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDepedantData->SunFogColor.x, - cullStageData->frameDepedantData->SunFogColor.y, - cullStageData->frameDepedantData->SunFogColor.z); - ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDepedantData->SunFogStrength); + cullStageData->frameDependentData->SunFogColor.x, + cullStageData->frameDependentData->SunFogColor.y, + cullStageData->frameDependentData->SunFogColor.z); + ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDepedantData->FogHeightColor.x, - cullStageData->frameDepedantData->FogHeightColor.y, - cullStageData->frameDepedantData->FogHeightColor.z); + cullStageData->frameDependentData->FogHeightColor.x, + cullStageData->frameDependentData->FogHeightColor.y, + cullStageData->frameDependentData->FogHeightColor.z); ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", - cullStageData->frameDepedantData->FogHeightCoefficients.x, - cullStageData->frameDepedantData->FogHeightCoefficients.y, - cullStageData->frameDepedantData->FogHeightCoefficients.z); + cullStageData->frameDependentData->FogHeightCoefficients.x, + cullStageData->frameDependentData->FogHeightCoefficients.y, + cullStageData->frameDependentData->FogHeightCoefficients.z); ImGui::Separator(); } } if (ImGui::CollapsingHeader("Current light params")) { - if (cullStageData->frameDepedantData != nullptr) { - ImGui::Text("Glow: %.3f", cullStageData->frameDepedantData->currentGlow); + if (cullStageData->frameDependentData != nullptr) { + ImGui::Text("Glow: %.3f", cullStageData->frameDependentData->currentGlow); } } diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index b127ed579..ed79477d8 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -320,7 +320,10 @@ set(SOURCE_FILES src/engine/algorithms/mathHelper_culling_sse.cpp src/engine/algorithms/mathHelper_culling_sse.h src/engine/algorithms/mathHelper_culling.cpp - src/engine/algorithms/mathHelper_culling.h) + src/engine/algorithms/mathHelper_culling.h + src/renderer/MapSceneRenderer.cpp + src/renderer/MapSceneRenderer.h + src/renderer/MapSceneRendererFactory.cpp src/renderer/MapSceneRendererFactory.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -494,7 +497,7 @@ if (LINK_VULKAN) src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp - src/gapi/vulkan/shaders/GWaterfallShaderVLK.h) + src/gapi/vulkan/shaders/GWaterfallShaderVLK.h src/renderer/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/vulkan/MapSceneRenderForwardVLK.h) set(Vulkan_INCLUDE_DIR $ENV{VULKAN_SDK}/Include) IF(WIN32) IF (NOT Vulkan_FOUND) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index de71fb501..9407bc6b6 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -77,7 +77,7 @@ void main() { calcLight( matDiffuse, vNormal, - true, + UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, vColor.w, scene, intLight, diff --git a/wowViewerLib/src/engine/DrawStage.h b/wowViewerLib/src/engine/DrawStage.h index a85aa9c98..e96695cbb 100644 --- a/wowViewerLib/src/engine/DrawStage.h +++ b/wowViewerLib/src/engine/DrawStage.h @@ -44,10 +44,6 @@ struct FrameDepedantData { mathfu::vec4 exteriorDirectColor = {0.3,0.3,0.3, 0.3}; mathfu::vec3 exteriorDirectColorDir; - mathfu::vec4 interiorAmbientColor; - mathfu::vec4 interiorSunColor; - mathfu::vec3 interiorSunDir; - //Sky params bool overrideValuesWithFinalFog = false; @@ -88,23 +84,10 @@ struct FrameDepedantData { struct DrawStage { - HCameraMatrices matricesForRendering; - HGUniformBufferChunk sceneWideBlockVSPSChunk; - - HFrameDepedantData frameDepedantData; - HMeshesToRender opaqueMeshes; - HMeshesToRender transparentMeshes = nullptr; std::vector drawStageDependencies; - bool invertedZ = false; - - bool setViewPort = false; - ViewPortDimensions viewPortDimensions; - - bool clearScreen = false; mathfu::vec4 clearColor; - HFrameBuffer target = nullptr; }; typedef std::shared_ptr HDrawStage; diff --git a/wowViewerLib/src/engine/SceneComposer.cpp b/wowViewerLib/src/engine/SceneComposer.cpp index d70e3ddcb..2b3911735 100644 --- a/wowViewerLib/src/engine/SceneComposer.cpp +++ b/wowViewerLib/src/engine/SceneComposer.cpp @@ -218,7 +218,7 @@ void SceneComposer::DoUpdate() { logExecution // uniformChunkVec.push_back(&additionalChunks); for (auto &updateStage : frameScenario->updateStages) { - frameDepDataVec.push_back(updateStage->cullResult->frameDepedantData); + frameDepDataVec.push_back(updateStage->cullResult->frameDependentData); uniformChunkVec.push_back(&updateStage->uniformBufferChunks); } logExecution diff --git a/wowViewerLib/src/engine/SceneScenario.h b/wowViewerLib/src/engine/SceneScenario.h index 8f31600d6..571c1577e 100644 --- a/wowViewerLib/src/engine/SceneScenario.h +++ b/wowViewerLib/src/engine/SceneScenario.h @@ -25,9 +25,11 @@ class FrameScenario; #include "DrawStage.h" #include "objects/wmo/wmoObject.h" -struct CullStage { -//Input: + +struct FrameInputParams { HCameraMatrices matricesForCulling; + HCameraMatrices cameraMatricesForRendering; + HCameraMatrices cameraMatricesForDebugCamera; HScene scene; //Just for proper BoundingBox calculus @@ -35,12 +37,21 @@ struct CullStage { float deltaY = 0.0f; float deltaZ = 0.0f; -//Output: - int adtAreadId = -1; + //Time advance + animTime_t delta; + //Parameters for framebuffer + ViewPortDimensions viewPortDimensions; + bool invertedZ = false; + bool clearScreen = false; +}; + +struct MapRenderPlan { + int adtAreadId = -1; int areaId = -1; int parentAreaId = -1; + //Result of culling test std::vector m_currentInteriorGroups = {}; bool currentWmoGroupIsExtLit = false; bool currentWmoGroupShowExtSkybox = false; @@ -49,31 +60,16 @@ struct CullStage { FrameViewsHolder viewsHolder; - HFrameDepedantData frameDepedantData = std::make_shared(); + HFrameDepedantData frameDependentData = std::make_shared(); + //Objects for update and rendering std::vector> adtArray = {}; M2ObjectListContainer m2Array; WMOListContainer wmoArray; WMOGroupListContainer wmoGroupArray; -}; -typedef std::shared_ptr HCullStage; - -struct UpdateStage { -//input - HCullStage cullResult; - animTime_t delta; - HCameraMatrices cameraMatrices; -//Output - HMeshesToRender opaqueMeshes; - HMeshesToRender transparentMeshes; - - std::vector uniformBufferChunks; - std::vector texturesForUpload; - // + //Settings for the frame }; -typedef std::shared_ptr HUpdateStage; - class SceneComposer; @@ -81,18 +77,8 @@ class SceneComposer; class FrameScenario { friend class SceneComposer; - struct DrawStageLinkage { - HScene scene; - std::vector updateStages; - HDrawStage drawStage; - }; private: - std::vector cullStages; - std::vector updateStages; - - std::vector drawStageLinks; - HDrawStage lastDrawStage; public: HCullStage addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene, mathfu::vec3 deltas = {0,0,0}); HUpdateStage addUpdateStage(HCullStage &cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate); diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp index d82a0691e..f3a072388 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp @@ -19,9 +19,9 @@ void m2TiedCamera::tick(animTime_t timeDelta) { HCameraMatrices m2TiedCamera::getCameraMatrices(float fov, float canvasAspect, float nearPlane, float farPlane) { mathfu::mat4 lookAtMat4 = mathfu::mat4::LookAt( - -m_lastCameraResult.target_position.xyz()+m_lastCameraResult.position.xyz(), - mathfu::vec3(0,0,0), - mathfu::vec3(0,0,1)) * mathfu::mat4::FromTranslationVector(-m_lastCameraResult.position.xyz()); + m_lastCameraResult.target_position.xyz(), + m_lastCameraResult.position.xyz(), + mathfu::vec3(0,0,1), 1); mathfu::mat4 rotateMat = MathHelper::RotationY(m_lastCameraResult.roll); lookAtMat4 = rotateMat * lookAtMat4; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 17387032f..4904813a6 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -25,9 +25,9 @@ class ADTObjRenderRes { public: std::shared_ptr adtObject; bool wasLoaded = false; - bool drawChunk[256] = {false}; - bool drawWaterChunk[256] = {false}; - bool checkRefs[256] = {false}; + std::array drawChunk = {false}; + std::array drawWaterChunk = {false}; + std::array checkRefs = {false}; }; class GeneralView { @@ -77,7 +77,7 @@ class FrameViewsHolder { public: HExteriorView getOrCreateExterior(const MathHelper::FrustumCullingData &frustumData); HExteriorView getExterior(); - HInteriorView createInterior(const MathHelper::FrustumCullingData &frustumData); + HInteriorView createInterior(const MathHelper::FrustumCullingData &frustumData); const std::vector &getInteriorViews() { return interiorViews; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index b9eff05ca..051f56000 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -744,7 +744,6 @@ void AdtObject::createMeshes() { } void AdtObject::loadAlphaTextures() { - //int chunkCount = m_adtFile->mcnkRead+1; int chunkCount = m_adtFileTex->mcnkRead+1; int maxAlphaTexPerChunk = 4; int alphaTexSize = 64; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 019d60f62..10c76c7ce 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -918,7 +918,10 @@ void M2Object:: doLoadGeom(){ m_skelGeom = skelCache->getFileId(m_m2Geom->m_skid); return; } - if (m_skelGeom->getStatus() == FileStatus::FSLoaded && m_parentSkelGeom == nullptr) { + if (m_skelGeom->getStatus() != FileStatus::FSLoaded ) { + return; + } + if (m_parentSkelGeom == nullptr) { if (m_skelGeom->m_skpd != nullptr && m_skelGeom->m_skpd->parent_skel_file_id != 0) { m_parentSkelGeom = skelCache->getFileId(m_skelGeom->m_skpd->parent_skel_file_id); return; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 43e14e897..67618deca 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -35,7 +35,7 @@ void M2Scene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 if (ambient.Length() < 0.0001) ambient = mathfu::vec4(1.0,1.0,1.0,1.0); - auto frameDepedantData = cullStage->frameDepedantData; + auto frameDepedantData = cullStage->frameDependentData; frameDepedantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); frameDepedantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); @@ -43,7 +43,7 @@ void M2Scene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 frameDepedantData->exteriorDirectColor = mathfu::vec4(0.0,0.0,0.0,0.0); frameDepedantData->exteriorDirectColorDir = mathfu::vec3(0.0,0.0,0.0); } - auto frameDepedantData = cullStage->frameDepedantData; + auto frameDepedantData = cullStage->frameDependentData; frameDepedantData->FogDataFound = false; } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 15f7e8954..f8c2fda23 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -658,7 +658,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca skyBox->setAlpha(_light.blendCoef); if ((_light.skyBoxFlags & 4) > 0 ) { //In this case conus is still rendered been, but all values are final fog values. - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->overrideValuesWithFinalFog = true; } @@ -718,16 +718,16 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca // horizontAmbientColor *= ambientMult; if (config->glowSource == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->currentGlow = currentGlow; } else if (config->glowSource == EParameterSource::eConfig) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->currentGlow = config->currentGlow; } if (config->globalLighting == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->exteriorAmbientColor = mathfu::vec4(ambientColor[2], ambientColor[1], ambientColor[0], 0); fdd->exteriorGroundAmbientColor = mathfu::vec4(groundAmbientColor[2], groundAmbientColor[1], groundAmbientColor[0], @@ -741,7 +741,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca ); fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; } else if (config->globalLighting == EParameterSource::eConfig) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->exteriorAmbientColor = config->exteriorAmbientColor; fdd->exteriorGroundAmbientColor = config->exteriorGroundAmbientColor; @@ -755,26 +755,26 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca } { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->useMinimapWaterColor = config->useMinimapWaterColor; fdd->useCloseRiverColorForDB = config->useCloseRiverColorForDB; } if (config->waterColorParams == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->closeRiverColor = mathfu::vec4(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0], 0); fdd->farRiverColor = mathfu::vec4(farRiverColor[2], farRiverColor[1], farRiverColor[0], 0); fdd->closeOceanColor = mathfu::vec4(closeOceanColor[2], closeOceanColor[1], closeOceanColor[0], 0); fdd->farOceanColor = mathfu::vec4(farOceanColor[2], farOceanColor[1], farOceanColor[0], 0); } else if (config->waterColorParams == EParameterSource::eConfig) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->closeRiverColor = config->closeRiverColor; fdd->farRiverColor = config->farRiverColor; fdd->closeOceanColor = config->closeOceanColor; fdd->farOceanColor = config->farOceanColor; } if (config->skyParams == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->SkyTopColor = mathfu::vec4(SkyTopColor[2], SkyTopColor[1], SkyTopColor[0], 1.0); fdd->SkyMiddleColor = mathfu::vec4(SkyMiddleColor[2], SkyMiddleColor[1], SkyMiddleColor[0], 1.0); fdd->SkyBand1Color = mathfu::vec4(SkyBand1Color[2], SkyBand1Color[1], SkyBand1Color[0], 1.0); @@ -909,7 +909,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca //In case of no data -> disable the fog { - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; fdd->FogDataFound = !combinedResults.empty(); // std::cout << "combinedResults.empty() = " << combinedResults.empty() << std::endl; // std::cout << "combinedResults.size() = " << combinedResults.size() << std::endl; @@ -1621,7 +1621,7 @@ void Map::produceUpdateStage(HUpdateStage &updateStage) { transparentMeshes.reserve(30000); auto cullStage = updateStage->cullResult; - auto fdd = cullStage->frameDepedantData; + auto fdd = cullStage->frameDependentData; if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { @@ -1765,7 +1765,7 @@ void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vectorcullResult; //Create scenewide uniform - resultDrawStage->frameDepedantData = updateStage->cullResult->frameDepedantData; + resultDrawStage->frameDepedantData = updateStage->cullResult->frameDependentData; opaqueMeshes->meshes.insert(std::end(opaqueMeshes->meshes), std::begin(updateStage->opaqueMeshes->meshes), diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index d6ccdd138..f685e6ac3 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -34,7 +34,7 @@ void WmoScene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec mathfu::vec4 ambient = mathfu::vec4(1.0,1.0,1.0,1.0); - auto frameDepedantData = cullStage->frameDepedantData; + auto frameDepedantData = cullStage->frameDependentData; frameDepedantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); frameDepedantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index b60fa68d5..616e9a736 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -285,16 +285,16 @@ void WmoObject::createWorldPortals() { mathfu::vec3 lookAt = center + mathfu::vec3(portalInfo->plane.planeGeneral.normal); mathfu::vec3 upVector = portalVecs[0] - center; - mathfu::mat4 projMat = mathfu::mat4::LookAt( + mathfu::mat4 viewMat = mathfu::mat4::LookAt( lookAt, center, upVector ); - mathfu::mat4 projMatInv = projMat.Inverse(); + mathfu::mat4 projMatInv = viewMat.Inverse(); std::vector portalTransformed(portalVecs.size()); for (int k = 0; k < portalVecs.size(); k++) { - portalTransformed[k] = (projMat * mathfu::vec4(portalVecs[k], 1.0)).xyz(); + portalTransformed[k] = (viewMat * mathfu::vec4(portalVecs[k], 1.0)).xyz(); } std::vector hulled = MathHelper::getHullPoints(portalTransformed); diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 0570b4e32..19781b1a0 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -495,7 +495,6 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, std::vector((64*4) * 64, 0); if (layers == nullptr || alphaArray == nullptr) return; -// for (int j = 0; j < mapTile[i].nLayers; j++ ) { for (int j = 0; j HGMesh; typedef std::shared_ptr HGM2Mesh; typedef std::shared_ptr HGParticleMesh; typedef std::shared_ptr HGOcclusionQuery; -typedef std::shared_ptr HGBlpTexture; typedef std::shared_ptr HGTexture; typedef std::shared_ptr HGPUFence; typedef std::shared_ptr HFrameBuffer; @@ -143,10 +138,16 @@ struct FramebufAvalabilityStruct { int frame; }; +enum class GDeviceType { + GOpenGL2, GOpenGL3, GVulkan, +}; + class IDevice { public: virtual ~IDevice() {}; + virtual GDeviceType getDeviceType() = 0; + virtual void initialize() = 0; virtual void reset() = 0; virtual unsigned int getFrameNumber() = 0; diff --git a/wowViewerLib/src/gapi/interface/textures/IBlpTexture.h b/wowViewerLib/src/gapi/interface/textures/IBlpTexture.h deleted file mode 100644 index 14cd118f6..000000000 --- a/wowViewerLib/src/gapi/interface/textures/IBlpTexture.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by Deamon on 8/27/2018. -// - -#ifndef AWEBWOWVIEWERCPP_IBLPTEXTURE_H -#define AWEBWOWVIEWERCPP_IBLPTEXTURE_H - - -#endif //AWEBWOWVIEWERCPP_IBLPTEXTURE_H diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h index c5bbf7df8..b7d83ef3e 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h @@ -45,6 +45,8 @@ class GDeviceGL20 : public IDevice { GDeviceGL20(); ~GDeviceGL20() override = default;; + GDeviceType getDeviceType() override {return GDeviceType::GOpenGL2; }; + void initialize() override; void reset() override; diff --git a/wowViewerLib/src/gapi/ogl2.0/GVertexBufferBindingsGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/GVertexBufferBindingsGL20.cpp index 89d2bb091..d6ab11811 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GVertexBufferBindingsGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/GVertexBufferBindingsGL20.cpp @@ -80,20 +80,6 @@ void GVertexBufferBindingsGL20::addVertexBufferBinding(GVertexBufferBinding bind static int VAO_updated = 0; void GVertexBufferBindingsGL20::save() { -// std::cout << "VAO_updated = " << VAO_updated++ << std::endl; - -// m_device.bindVertexBufferBindings(this); -// for (GVertexBufferBinding &binding : m_bindings) { -// for (GBufferBinding &adtVertexBufferBinding : binding.bindings) { -// -// } -// } -// m_device.bindIndexBuffer(nullptr); -// m_device.bindVertexBuffer(nullptr); - - - -// m_device.bindVertexBufferBindings(nullptr); } diff --git a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h index 2c73b134a..447614d82 100644 --- a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h @@ -5,7 +5,6 @@ #ifndef WEBWOWVIEWERCPP_GBLPTEXTURE20_H #define WEBWOWVIEWERCPP_GBLPTEXTURE20_H -#include "../../../gapi/interface/textures/IBlpTexture.h" #include "GTextureGL20.h" #include "../GDeviceGL20.h" diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h index 5e1b2faaf..13c91dc47 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h @@ -62,6 +62,8 @@ class GDeviceGL33 : public IDevice, public std::enable_shared_from_this{}(k.texture) ^ (hash{}(k.wrapX) << 8) ^ (hash{}(k.wrapY) << 16); + return hash{}(k.texture); }; }; std::unordered_map, BlpCacheRecordHasher> loadedTextureCache; @@ -469,7 +465,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_createdRenderPasses; }; - +typedef std::shared_ptr HGDeviceVLK; #endif //AWEBWOWVIEWERCPP_GDEVICEVULKAN_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 0cf9d8593..d0954adcf 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -52,7 +52,7 @@ void GBlpTextureVLK::createGlTexture(TextureFormat textureFormat, const HMipmaps /* S3TC is not supported on mobile platforms */ bool compressedTextSupported = m_device.getIsCompressedTexturesSupported(); - if (!compressedTextSupported && textureFormat != TextureFormat::BGRA) { + if (!compressedTextSupported && textureFormat != TextureFormat::BGRA) { this->decompressAndUpload(textureFormat, hmipmaps); return; } diff --git a/wowViewerLib/src/renderer/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/MapSceneRenderer.cpp new file mode 100644 index 000000000..f70b05b9a --- /dev/null +++ b/wowViewerLib/src/renderer/MapSceneRenderer.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 11/26/2022. +// + +#include "MapSceneRenderer.h" diff --git a/wowViewerLib/src/renderer/MapSceneRenderer.h b/wowViewerLib/src/renderer/MapSceneRenderer.h new file mode 100644 index 000000000..cb73606b6 --- /dev/null +++ b/wowViewerLib/src/renderer/MapSceneRenderer.h @@ -0,0 +1,21 @@ +// +// Created by Deamon on 11/26/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERER_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERER_H + + +#include "../engine/objects/scenes/map.h" + +class MapSceneRenderer { +public: + MapSceneRenderer() = default; + virtual ~MapSceneRenderer() = 0; + + virtual HFrameBuffer putIntoQueue(HCullStage &cullStage) = 0; + +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERER_H diff --git a/wowViewerLib/src/renderer/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/MapSceneRendererFactory.cpp new file mode 100644 index 000000000..afd83afb4 --- /dev/null +++ b/wowViewerLib/src/renderer/MapSceneRendererFactory.cpp @@ -0,0 +1,18 @@ +// +// Created by Deamon on 12/1/2022. +// + +#include "MapSceneRendererFactory.h" +#include "vulkan/MapSceneRenderForwardVLK.h" + +std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device) { + + switch (device->getDeviceType()) { + case GDeviceType::GVulkan: + return std::make_shared(); + default: + return nullptr; + } + + return nullptr; +} diff --git a/wowViewerLib/src/renderer/MapSceneRendererFactory.h b/wowViewerLib/src/renderer/MapSceneRendererFactory.h new file mode 100644 index 000000000..a3af0f81d --- /dev/null +++ b/wowViewerLib/src/renderer/MapSceneRendererFactory.h @@ -0,0 +1,17 @@ +// +// Created by Deamon on 12/1/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERERFACTORY_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERERFACTORY_H + + +#include +#include "MapSceneRenderer.h" + +class MapSceneRendererFactory { + static std::shared_ptr createForwardRenderer(HGDevice const &device); +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERERFACTORY_H diff --git a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp new file mode 100644 index 000000000..3ff3e5070 --- /dev/null +++ b/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp @@ -0,0 +1,13 @@ +// +// Created by Deamon on 12/1/2022. +// + +#include "MapSceneRenderForwardVLK.h" + +MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { + +} + +HFrameBuffer MapSceneRenderForwardVLK::putIntoQueue(HCullStage &cullStage) { + +} diff --git a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h new file mode 100644 index 000000000..447822a94 --- /dev/null +++ b/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h @@ -0,0 +1,25 @@ +// +// Created by Deamon on 12/1/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H + + +#include "../MapSceneRenderer.h" +#include "../../gapi/vulkan/GDeviceVulkan.h" + +class MapSceneRenderForwardVLK : public MapSceneRenderer { +public: + MapSceneRenderForwardVLK(HGDeviceVLK hDevice); + + HFrameBuffer putIntoQueue(HCullStage &cullStage) override; + +private: + HGDeviceVLK m_device; + + +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H From 0ef7c50072f1e83fc434a345793113a98c1d5c90 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 15 Dec 2022 02:55:48 +0200 Subject: [PATCH 010/212] temp commit --- CMakeLists.txt | 34 +- src/exporters/gltfExporter/GLTFExporter.cpp | 2 +- src/main.cpp | 13 +- src/minimapGenerator/minimapGenerator.cpp | 272 +- src/minimapGenerator/minimapGenerator.h | 25 +- src/ui/FrontendUI.cpp | 698 +- src/ui/FrontendUI.h | 29 +- .../MinimapGenerationWindow.cpp | 15 +- .../MinimapGenerationWindow.h | 2 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 5 + src/ui/renderer/uiScene/FrontendUIRenderer.h | 22 + .../uiScene/FrontendUIRendererFactory.cpp | 16 + .../uiScene/FrontendUIRendererFactory.h | 18 + src/ui/renderer/uiScene/ImGUIPlan.cpp | 5 + src/ui/renderer/uiScene/ImGUIPlan.h | 29 + .../buffers/IVertexBufferDynamicImgui.cpp | 5 + .../buffers/IVertexBufferDynamicImgui.h | 18 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 267 + .../vulkan/FrontendUIRenderForwardVLK.h | 58 + .../buffers/IVertexBufferDynamicImguiVLK.cpp | 15 + .../buffers/IVertexBufferDynamicImguiVLK.h | 33 + wowViewerLib/CMakeLists.txt | 41 +- wowViewerLib/src/engine/ApiContainer.h | 4 +- wowViewerLib/src/engine/SceneComposer.cpp | 369 - wowViewerLib/src/engine/SceneComposer.h | 95 - wowViewerLib/src/engine/SceneScenario.cpp | 62 - wowViewerLib/src/engine/SceneScenario.h | 100 - .../src/engine/algorithms/mathHelper.h | 6 +- wowViewerLib/src/engine/engineClassList.h | 1 + .../src/engine/managers/CRibbonEmitter.cpp | 62 +- .../managers/particles/particleEmitter.cpp | 60 +- .../src/engine/objects/ViewsObjects.cpp | 2 +- .../src/engine/objects/adt/adtObject.cpp | 10 +- wowViewerLib/src/engine/objects/iScene.cpp | 1 - wowViewerLib/src/engine/objects/iScene.h | 33 +- wowViewerLib/src/engine/objects/iWmoApi.h | 2 - .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 4 +- .../src/engine/objects/m2/m2Object.cpp | 22 +- .../src/engine/objects/scenes/NullScene.h | 17 - .../src/engine/objects/scenes/m2Scene.cpp | 19 +- .../src/engine/objects/scenes/m2Scene.h | 35 +- .../src/engine/objects/scenes/map.cpp | 1164 +- wowViewerLib/src/engine/objects/scenes/map.h | 47 +- .../src/engine/objects/scenes/wmoScene.cpp | 24 +- .../src/engine/objects/scenes/wmoScene.h | 8 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 10 +- wowViewerLib/src/gapi/IDeviceFactory.cpp | 5 + wowViewerLib/src/gapi/interface/IDevice.h | 10 +- .../interface/buffers/IUniformBufferChunk.h | 6 +- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp | 2 +- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h | 12 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp | 4 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h | 2 +- .../gapi/ogl3.3/GVertexBufferBindingsGL33.cpp | 1 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 663 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 30 +- wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h | 31181 ++++++++-------- wowViewerLib/src/renderer/IRenderParameters.h | 16 + wowViewerLib/src/renderer/IRenderer.h | 17 + wowViewerLib/src/renderer/MapSceneRenderer.h | 21 - .../buffers/IVertexBufferDynamicTemplate.cpp | 5 + .../buffers/IVertexBufferDynamicTemplate.h | 20 + .../src/renderer/frame/FrameInputParams.h | 39 + .../src/renderer/frame/SceneComposer.cpp | 123 + .../src/renderer/frame/SceneComposer.h | 66 + .../src/renderer/frame/SceneScenario.cpp | 6 + .../src/renderer/frame/SceneScenario.h | 45 + .../mapScene/FrameDependentData.h} | 49 +- .../src/renderer/mapScene/MapScenePlan.h | 41 + .../{ => mapScene}/MapSceneRenderer.cpp | 0 .../src/renderer/mapScene/MapSceneRenderer.h | 22 + .../MapSceneRendererFactory.cpp | 5 +- .../{ => mapScene}/MapSceneRendererFactory.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.h | 7 +- 75 files changed, 18623 insertions(+), 17558 deletions(-) create mode 100644 src/ui/renderer/uiScene/FrontendUIRenderer.cpp create mode 100644 src/ui/renderer/uiScene/FrontendUIRenderer.h create mode 100644 src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp create mode 100644 src/ui/renderer/uiScene/FrontendUIRendererFactory.h create mode 100644 src/ui/renderer/uiScene/ImGUIPlan.cpp create mode 100644 src/ui/renderer/uiScene/ImGUIPlan.h create mode 100644 src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp create mode 100644 src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h create mode 100644 src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp create mode 100644 src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h create mode 100644 src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp create mode 100644 src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h delete mode 100644 wowViewerLib/src/engine/SceneComposer.cpp delete mode 100644 wowViewerLib/src/engine/SceneComposer.h delete mode 100644 wowViewerLib/src/engine/SceneScenario.cpp delete mode 100644 wowViewerLib/src/engine/SceneScenario.h create mode 100644 wowViewerLib/src/renderer/IRenderParameters.h create mode 100644 wowViewerLib/src/renderer/IRenderer.h delete mode 100644 wowViewerLib/src/renderer/MapSceneRenderer.h create mode 100644 wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.cpp create mode 100644 wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h create mode 100644 wowViewerLib/src/renderer/frame/FrameInputParams.h create mode 100644 wowViewerLib/src/renderer/frame/SceneComposer.cpp create mode 100644 wowViewerLib/src/renderer/frame/SceneComposer.h create mode 100644 wowViewerLib/src/renderer/frame/SceneScenario.cpp create mode 100644 wowViewerLib/src/renderer/frame/SceneScenario.h rename wowViewerLib/src/{engine/DrawStage.h => renderer/mapScene/FrameDependentData.h} (61%) create mode 100644 wowViewerLib/src/renderer/mapScene/MapScenePlan.h rename wowViewerLib/src/renderer/{ => mapScene}/MapSceneRenderer.cpp (100%) create mode 100644 wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h rename wowViewerLib/src/renderer/{ => mapScene}/MapSceneRendererFactory.cpp (69%) rename wowViewerLib/src/renderer/{ => mapScene}/MapSceneRendererFactory.h (92%) rename wowViewerLib/src/renderer/{ => mapScene}/vulkan/MapSceneRenderForwardVLK.cpp (65%) rename wowViewerLib/src/renderer/{ => mapScene}/vulkan/MapSceneRenderForwardVLK.h (64%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec1ad6b7a..c89685483 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,6 @@ if (LINK_EGL) add_definitions(-DWITH_GLESv2) endif() - include_directories(${GLEW_INCLUDE_DIRS}) @@ -225,9 +224,24 @@ set(SOURCE_FILES src/database/product_db_parser/productDbParser.cpp src/database/product_db_parser/productDbParser.h src/database/buildInfoParser/buildInfoParser.cpp - src/database/buildInfoParser/buildInfoParser.h src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h) - - + src/database/buildInfoParser/buildInfoParser.h + src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp + src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h + src/ui/renderer/uiScene/FrontendUIRenderer.cpp + src/ui/renderer/uiScene/FrontendUIRenderer.h + src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp + src/ui/renderer/uiScene/FrontendUIRendererFactory.h + src/ui/renderer/uiScene/ImGUIPlan.cpp + src/ui/renderer/uiScene/ImGUIPlan.h + src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp + src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h) + + +set(SOURCE_FILES_VULKAN + src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp + src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h + src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp + src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h) ######################################################### # FIND OPENGL @@ -260,13 +274,15 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package( Threads REQUIRED ) -#if(CMAKE_USE_PTHREADS_INIT) -# set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-pthread") -#endif() - add_subdirectory(${PROJECT_SOURCE_DIR}/3rdparty/SQLiteCpp EXCLUDE_FROM_ALL) -add_executable(AWebWoWViewerCpp ${SOURCE_FILES}) + +if (NOT Vulkan_FOUND) + set(SOURCE_FILES_VULKAN "") +endif() + +add_executable(AWebWoWViewerCpp ${SOURCE_FILES} ${SOURCE_FILES_VULKAN}) + if (Vulkan_FOUND) add_definitions(-DLINK_VULKAN) endif() diff --git a/src/exporters/gltfExporter/GLTFExporter.cpp b/src/exporters/gltfExporter/GLTFExporter.cpp index 8b000a71a..e1844c920 100644 --- a/src/exporters/gltfExporter/GLTFExporter.cpp +++ b/src/exporters/gltfExporter/GLTFExporter.cpp @@ -155,7 +155,7 @@ void GLTFExporter::createTextures(GLTFExporter::M2ModelData &m2ModelData, std::s sampler.minFilter = TINYGLTF_TEXTURE_FILTER_LINEAR; sampler.magFilter = TINYGLTF_TEXTURE_FILTER_LINEAR; sampler.wrapS = wrapX ? TINYGLTF_TEXTURE_WRAP_REPEAT : TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE; - sampler.wrapT = wrapX ? TINYGLTF_TEXTURE_WRAP_REPEAT : TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE; + sampler.wrapT = wrapY ? TINYGLTF_TEXTURE_WRAP_REPEAT : TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE; model.samplers.push_back(sampler); } diff --git a/src/main.cpp b/src/main.cpp index e3ebf40d0..08efab23d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ #include "../wowViewerLib/src/gapi/interface/IDevice.h" #include "../wowViewerLib/src/gapi/IDeviceFactory.h" #include "ui/FrontendUI.h" -#include "../wowViewerLib/src/engine/SceneComposer.h" +#include "../wowViewerLib/src/renderer/frame/SceneComposer.h" #include "../wowViewerLib/src/engine/camera/firstPersonCamera.h" #include "../wowViewerLib/src/engine/objects/scenes/map.h" #include "screenshots/screenshotMaker.h" @@ -336,8 +336,6 @@ int main(){ const bool SET_TERMINATE_UNEXP = std::set_unexpected(beforeCrash); #endif #endif - - signal(SIGABRT, &my_function_to_handle_aborts); signal(SIGSEGV, &my_function_to_handle_aborts); @@ -475,8 +473,6 @@ int main(){ glfwSetWindowSize(window, width, height); glfwGetFramebufferSize(window, &canvWidth, &canvHeight); } - -// frontendUI->createDefaultprocessor(); glfwSwapInterval(0); //try { @@ -486,15 +482,12 @@ int main(){ stopKeyboard = frontendUI->getStopKeyboard(); glfwPollEvents(); - frontendUI->composeUI(); - // Render scene currentFrame = glfwGetTime(); // seconds double deltaTime = currentFrame - lastFrame; { auto processor = frontendUI->getProcessor(); if (frontendUI->getProcessor()) { - if (!processor->getThreaded()) { processor->processRequests(false); } @@ -506,11 +499,11 @@ int main(){ apiContainer->debugCamera->tick(deltaTime * (1000.0f)); } - //DrawStage for screenshot -// needToMakeScreenshot = true; if (apiContainer->getConfig()->pauseAnimation) { deltaTime = 0.0; } + + frontendUI->composeUI(); auto sceneScenario = frontendUI->createFrameScenario(canvWidth, canvHeight, deltaTime); sceneComposer.draw(sceneScenario); diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 2b16d9e00..ef1ad315c 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -246,7 +246,6 @@ void MinimapGenerator::setupScenarioData() { m_mapIndex = 0; m_zoom = currentScenario.zoom; - stackOfCullStages = {nullptr, nullptr, nullptr, nullptr}; auto config = m_apiContainer->getConfig(); config->closeOceanColor = currentScenario.closeOceanColor;//{0.0671968088, 0.294095874, 0.348881632, 0}; @@ -557,20 +556,18 @@ MinimapGenerator::setupCamera(const mathfu::vec3 &lookAtPoint2D, std::shared_ptr void MinimapGenerator::resetCandidate() { prepearCandidate = false; - m_candidateDS = nullptr; m_candidateCS = {}; - m_candidateUS = {}; framesReady = 0; } -void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoord, +void MinimapGenerator::calcBB(const HMapRenderPlan &mapRenderPlan, mathfu::vec3 &minCoord, mathfu::vec3 &maxCoord, const CAaBox &adtBox2d, int adt_x, int adt_y, bool applyAdtChecks) { minCoord = mathfu::vec3(20000, 20000, 20000); maxCoord = mathfu::vec3(-20000, -20000, -20000); - for (auto &m2Object: cullStage->m2Array.getDrawn()) { + for (auto &m2Object: mapRenderPlan->m2Array.getDrawn()) { auto objBB = m2Object->getAABB(); if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; @@ -595,7 +592,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor ); } - for (auto &wmoObject: cullStage->wmoGroupArray.getToDraw()) { + for (auto &wmoObject: mapRenderPlan->wmoGroupArray.getToDraw()) { auto objBB = wmoObject->getWorldAABB(); if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; @@ -621,7 +618,7 @@ void MinimapGenerator::calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoor } - for (auto &adtObjectRes: cullStage->adtArray) { + for (auto &adtObjectRes: mapRenderPlan->adtArray) { auto adtObj = adtObjectRes->adtObject; @@ -688,27 +685,27 @@ void MinimapGenerator::process() { } } - if (!m_candidateUS.empty()) { - for (auto &updateStage : m_candidateUS) { - if (updateStage != nullptr && updateStage->texturesForUpload.size() > 0) { - resetCandidate(); - return; - } - } - } - - if (framesReady < waitQueueLen) { - return; - } - - if (m_candidateDS == nullptr) { - resetCandidate(); - prepearCandidate = true; - return; - } +// if (!m_candidateUS.empty()) { +// for (auto &updateStage : m_candidateUS) { +// if (updateStage != nullptr && updateStage->texturesForUpload.size() > 0) { +// resetCandidate(); +// return; +// } +// } +// } +// +// if (framesReady < waitQueueLen) { +// return; +// } +// +// if (m_candidateDS == nullptr) { +// resetCandidate(); +// prepearCandidate = true; +// return; +// } - auto lastFrameIt = m_candidateDS; auto lastFrameCull = m_candidateCS; + auto lastFrameParams = m_candidateCS; resetCandidate(); //Check the BB and adjust minZ-maxZ @@ -740,8 +737,8 @@ void MinimapGenerator::process() { } float zFar = (minCoord - maxCoord).Length(); - float maxZ = maxCoord.z + cullStage->deltaZ; - float minZ = minCoord.z + cullStage->deltaZ; + float maxZ = maxCoord.z; + float minZ = minCoord.z; if (!cullStage->m2Array.getDrawn().empty() || !cullStage->adtArray.empty() || @@ -790,10 +787,10 @@ void MinimapGenerator::process() { - saveDrawStageToFile(currentScenario.folderToSave+"/minimap/"+std::to_string(currentScenario.maps[m_mapIndex].mapId), lastFrameIt); + saveDrawStageToFile(currentScenario.folderToSave+"/minimap/"+std::to_string(currentScenario.maps[m_mapIndex].mapId), m_lastFrameBuffer); } else if (m_mgMode == EMGMode::eScreenshotGeneration) { //Make screenshot out of this drawStage - saveDrawStageToFile(currentScenario.folderToSave, lastFrameIt); + saveDrawStageToFile(currentScenario.folderToSave, m_lastFrameBuffer); } //Apply this logic only if it's not a preview mode @@ -827,7 +824,7 @@ void MinimapGenerator::process() { } } -void MinimapGenerator::saveDrawStageToFile(std::string folderToSave, const std::shared_ptr &lastFrameIt) { +void MinimapGenerator::saveDrawStageToFile(std::string folderToSave, const HFrameBuffer lastFrameBuffer) { if (!ghc::filesystem::is_directory(folderToSave) || !ghc::filesystem::exists(folderToSave)) { // Check if src folder exists ghc::filesystem::create_directories(folderToSave); // create src folder @@ -840,98 +837,83 @@ void MinimapGenerator::saveDrawStageToFile(std::string folderToSave, const std:: ) + ".png"; std::vector buffer = std::vector(m_width * m_height * 4 + 1); - saveDataFromDrawStage(lastFrameIt->target, fileName, m_width, m_height, buffer); - if (lastFrameIt->opaqueMeshes != nullptr) { -// std::cout << "Saved " << fileName << ": opaqueMeshes (" << lastFrameIt->opaqueMeshes->meshes.size() << ") " -// << std::endl; - } + saveDataFromDrawStage(lastFrameBuffer, fileName, m_width, m_height, buffer); } -HDrawStage MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) { - float farPlaneRendering = m_apiContainer->getConfig()->farPlane; - float farPlaneCulling = m_apiContainer->getConfig()->farPlaneForCulling; - - float nearPlane = 1.0; - float fov = toRadian(45.0); - - float canvasAspect = (float)m_width / (float)m_height; - - HCameraMatrices cameraMatricesCulling = m_apiContainer->camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); - HCameraMatrices cameraMatricesRendering = m_apiContainer->camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); - //Frustum matrix with reversed Z - - { - float f = 1.0f / tan(fov / 2.0f); - cameraMatricesCulling->perspectiveMat = getOrthoMatrix(); - cameraMatricesRendering->perspectiveMat = getOrthoMatrix(); - } - - if (m_apiContainer->hDevice->getIsVulkanAxisSystem() ) { - auto &perspectiveMatrix = cameraMatricesRendering->perspectiveMat; - - static const mathfu::mat4 vulkanMatrixFix2 = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1/2.0, - 0, 0, 0, 1).Transpose(); - - perspectiveMatrix = vulkanMatrixFix2 * perspectiveMatrix; - } - - mathfu::vec4 clearColor = m_apiContainer->getConfig()->clearColor; - m_lastDraw = nullptr; - - if (!mapRuntimeInfo.empty()) { - ViewPortDimensions dimensions = {{0, 0}, {m_width, m_height}}; - - HFrameBuffer fb = nullptr; - int frameWait = 4; - if (prepearCandidate && m_candidateDS == nullptr ) { - frameWait = waitQueueLen+4; - } - - fb = m_apiContainer->hDevice->createFrameBuffer(m_width, m_height, - {ITextureFormat::itRGBA}, ITextureFormat::itDepth32, - m_apiContainer->hDevice->getMaxSamplesCnt(), frameWait); - - std::vector drawStageDependencies = {}; - - auto &&mainMap = mapRuntimeInfo[m_mapIndex]; - std::vector cullStages; - std::vector updateStages; - - if (m_mgMode != EMGMode::eBoundingBoxCalculation) { - for (auto &mapData: mapRuntimeInfo) { - auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mapData.scene); - HUpdateStage updateStage = sceneScenario->addUpdateStage(cullStage, 0, - cameraMatricesRendering); - cullStages.push_back(cullStage); - updateStages.push_back(updateStage); - } - } else { - auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mainMap.scene); - std::shared_ptr updateStage = sceneScenario->addUpdateStage(cullStage, 0, - cameraMatricesRendering); - cullStages.push_back(cullStage); - updateStages.push_back(updateStage); - } - - HDrawStage sceneDrawStage = sceneScenario->addDrawStage( - updateStages, mainMap.scene, cameraMatricesRendering, - drawStageDependencies, true, dimensions, true, false, clearColor, fb); - - m_lastDraw = sceneDrawStage; - //We dont need stack in preview mode - if (prepearCandidate && m_candidateDS == nullptr) { - m_candidateDS = sceneDrawStage; - m_candidateCS = cullStages; - m_candidateUS = updateStages; - } - stackOfCullStages[m_apiContainer->hDevice->getDrawFrameNumber()] = cullStages[0]; - - return sceneDrawStage; - } +void MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) { +// float farPlaneRendering = m_apiContainer->getConfig()->farPlane; +// float farPlaneCulling = m_apiContainer->getConfig()->farPlaneForCulling; +// +// float nearPlane = 1.0f; +// float fov = toRadian(45.0f); +// +// float canvasAspect = (float)m_width / (float)m_height; +// +// HCameraMatrices cameraMatricesCulling = m_apiContainer->camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); +// HCameraMatrices cameraMatricesRendering = m_apiContainer->camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); +// //Frustum matrix with reversed Z +// +// { +// float f = 1.0f / tan(fov / 2.0f); +// cameraMatricesCulling->perspectiveMat = getOrthoMatrix(); +// cameraMatricesRendering->perspectiveMat = getOrthoMatrix(); +// } +// +// mathfu::vec4 clearColor = m_apiContainer->getConfig()->clearColor; +// m_lastDraw = nullptr; +// +// if (!mapRuntimeInfo.empty()) { +// ViewPortDimensions dimensions = {{0, 0}, {m_width, m_height}}; +// +// HFrameBuffer fb = nullptr; +// int frameWait = 4; +// if (prepearCandidate && m_candidateFrameBuffer == nullptr ) { +// frameWait = waitQueueLen+4; +// } +// +// fb = m_apiContainer->hDevice->createFrameBuffer(m_width, m_height, +// {ITextureFormat::itRGBA}, ITextureFormat::itDepth32, +// m_apiContainer->hDevice->getMaxSamplesCnt(), frameWait); +// +// std::vector drawStageDependencies = {}; +// +// auto &&mainMap = mapRuntimeInfo[m_mapIndex]; +// std::vector cullStages; +// std::vector updateStages; +// +// if (m_mgMode != EMGMode::eBoundingBoxCalculation) { +// for (auto &mapData: mapRuntimeInfo) { +// auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mapData.scene); +// HUpdateStage updateStage = sceneScenario->addUpdateStage(cullStage, 0, +// cameraMatricesRendering); +// cullStages.push_back(cullStage); +// updateStages.push_back(updateStage); +// } +// } else { +// auto cullStage = sceneScenario->addCullStage(cameraMatricesCulling, mainMap.scene); +// std::shared_ptr updateStage = sceneScenario->addUpdateStage(cullStage, 0, +// cameraMatricesRendering); +// cullStages.push_back(cullStage); +// updateStages.push_back(updateStage); +// } +// +// HDrawStage sceneDrawStage = sceneScenario->addDrawStage( +// updateStages, mainMap.scene, cameraMatricesRendering, +// drawStageDependencies, true, dimensions, true, false, clearColor, fb); +// +// m_lastDraw = sceneDrawStage; +// //We dont need stack in preview mode +// if (prepearCandidate && m_candidateDS == nullptr) { +// m_candidateDS = sceneDrawStage; +// m_candidateCS = cullStages; +// m_candidateUS = updateStages; +// } +// stackOfCullStages[m_apiContainer->hDevice->getDrawFrameNumber()] = cullStages[0]; +// +// return sceneDrawStage; +// } - return nullptr; + return; } float MinimapGenerator::GetOrthoDimension() { @@ -966,8 +948,8 @@ mathfu::vec3 MinimapGenerator::getLookAtVec3() { return mathfu::vec3(0,0,0); } -HDrawStage MinimapGenerator::getLastDrawStage() { - return m_lastDraw; +HFrameBuffer MinimapGenerator::getLastFrameBuffer() { + return m_lastFrameBuffer; } Config *MinimapGenerator::getConfig() { @@ -983,29 +965,27 @@ void MinimapGenerator::getCurrentFDData(int &areaId, int &parentAreaId, mathfu:: parentAreaId = 0; riverColor = mathfu::vec4(0,0,0,0); - auto cullStage = stackOfCullStages[m_apiContainer->hDevice->getUpdateFrameNumber()]; - if (cullStage == nullptr) return; - - areaId = cullStage->adtAreadId; - parentAreaId = cullStage->parentAreaId; - riverColor = cullStage->frameDependentData->closeRiverColor; - - mathfu::vec4 cameraPos = {0,0,0,1}; - this->m_apiContainer->camera->getCameraPosition(cameraPos.data_); - - for (auto &adtCullObj : cullStage->adtArray) { - auto adt_x = worldCoordinateToAdtIndex(cameraPos.y); - auto adt_y = worldCoordinateToAdtIndex(cameraPos.x); - - if (adt_x != adtCullObj->adtObject->getAdtX() || adt_y != adtCullObj->adtObject->getAdtY()) - continue; - - mathfu::vec3 riverColorV3; - adtCullObj->adtObject->getWaterColorFromDB(cameraPos, riverColorV3); - riverColor = mathfu::vec4(riverColorV3, 0); - break; - - - } +// auto cullStage = stackOfCullStages[m_apiContainer->hDevice->getUpdateFrameNumber()]; +// if (cullStage == nullptr) return; +// +// areaId = cullStage->adtAreadId; +// parentAreaId = cullStage->parentAreaId; +// riverColor = cullStage->frameDependentData->closeRiverColor; +// +// mathfu::vec4 cameraPos = {0,0,0,1}; +// this->m_apiContainer->camera->getCameraPosition(cameraPos.data_); +// +// for (auto &adtCullObj : cullStage->adtArray) { +// auto adt_x = worldCoordinateToAdtIndex(cameraPos.y); +// auto adt_y = worldCoordinateToAdtIndex(cameraPos.x); +// +// if (adt_x != adtCullObj->adtObject->getAdtX() || adt_y != adtCullObj->adtObject->getAdtY()) +// continue; +// +// mathfu::vec3 riverColorV3; +// adtCullObj->adtObject->getWaterColorFromDB(cameraPos, riverColorV3); +// riverColor = mathfu::vec4(riverColorV3, 0); +// break; +// } } diff --git a/src/minimapGenerator/minimapGenerator.h b/src/minimapGenerator/minimapGenerator.h index 9e6cab74d..56ee14287 100644 --- a/src/minimapGenerator/minimapGenerator.h +++ b/src/minimapGenerator/minimapGenerator.h @@ -6,9 +6,12 @@ #define AWEBWOWVIEWERCPP_MINIMAPGENERATOR_H #include "../../wowViewerLib/src/engine/ApiContainer.h" -#include "../../wowViewerLib/src/engine/SceneScenario.h" #include "../persistance/RequestProcessor.h" #include "entities.h" +#include "../../wowViewerLib/src/engine/objects/iScene.h" +#include "../../wowViewerLib/src/renderer/mapScene/MapScenePlan.h" +#include "../../wowViewerLib/src/renderer/frame/SceneScenario.h" +#include "../../wowViewerLib/src/engine/objects/scenes/map.h" class MinimapGenerator { @@ -37,22 +40,18 @@ class MinimapGenerator { EMGMode m_mgMode = EMGMode::eNone; - HDrawStage m_lastDraw = nullptr; + HFrameBuffer m_lastFrameBuffer = nullptr; struct PerSceneData { int mapIndex = -1; - HScene scene; + HMapScene scene; //Per X dimension, per Y dimension, vector of mandatory adt {x, y} coordinates std::vector>>> mandatoryADTMap; }; std::vector mapRuntimeInfo; - - std::array stackOfCullStages; - - std::vector m_candidateUS = {}; - HDrawStage m_candidateDS = nullptr; - std::vector m_candidateCS = {}; + HFrameBuffer m_candidateFrameBuffer = nullptr; + std::vector m_candidateCS = {}; float m_zFar = 3000.0f; float m_maxZ = 1000.0f; @@ -68,7 +67,7 @@ class MinimapGenerator { bool loadMaps(); void resetCandidate(); - void calcBB(const HCullStage &cullStage, mathfu::vec3 &minCoord, + void calcBB(const HMapRenderPlan &mapRenderPlan, mathfu::vec3 &minCoord, mathfu::vec3 &maxCoord, const CAaBox &adtBox2d, int adt_x, int adt_y, bool applyAdtChecks); @@ -84,8 +83,8 @@ class MinimapGenerator { void process(); EMGMode getCurrentMode() { return m_mgMode;} void setupCameraData(); - HDrawStage createSceneDrawStage(HFrameScenario sceneScenario); - HDrawStage getLastDrawStage(); + void createSceneDrawStage(HFrameScenario sceneScenario); + HFrameBuffer getLastFrameBuffer(); Config *getConfig(); void getCurrentTileCoordinates(int &x, int &y, int &maxX, int &maxY) { @@ -116,7 +115,7 @@ class MinimapGenerator { void startBoundingBoxCalc(ScenarioDef &scenarioDef); void stopBoundingBoxCalc(); - void saveDrawStageToFile(std::string folderToSave, const std::shared_ptr &lastFrameIt); + void saveDrawStageToFile(std::string folderToSave, const HFrameBuffer lastFrameBuffer); void setupCamera(const mathfu::vec3 &lookAtPoint2D, std::shared_ptr &camera); }; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 7d19d85b3..a91e8f256 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -205,71 +205,70 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Separator(); } - int currentFrame = m_api->hDevice->getDrawFrameNumber(); - auto &cullStageData = m_cullstages[currentFrame]; - - if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { - int m2ObjectsBeforeCullingExterior = 0; - if (cullStageData->viewsHolder.getExterior() != nullptr) { - m2ObjectsBeforeCullingExterior = cullStageData->viewsHolder.getExterior()->m2List.getCandidates().size(); - } - - int wmoGroupsInExterior = 0; - if (cullStageData->viewsHolder.getExterior() != nullptr) { - wmoGroupsInExterior = cullStageData->viewsHolder.getExterior()->wmoGroupArray.getToDraw().size(); - } - - int m2ObjectsDrawn = cullStageData!= nullptr ? cullStageData->m2Array.getDrawn().size() : 0; - int wmoObjectsBeforeCull = cullStageData!= nullptr ? cullStageData->wmoArray.getCandidates().size() : 0; - - ImGui::Text("M2 objects drawn: %s", std::to_string(m2ObjectsDrawn).c_str()); - ImGui::Text("WMO Groups in Exterior: %s", std::to_string(wmoGroupsInExterior).c_str()); - ImGui::Text("Interiors (aka group WMOs): %s", std::to_string(cullStageData->viewsHolder.getInteriorViews().size()).c_str()); - ImGui::Text("M2 Objects Before Culling in Exterior: %s", std::to_string(m2ObjectsBeforeCullingExterior).c_str()); - ImGui::Text("WMO objects before culling: %s", std::to_string(wmoObjectsBeforeCull).c_str()); - - ImGui::Separator(); - } - - if (ImGui::CollapsingHeader("Current fog params")) { - if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { - ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); - ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); - ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); - ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); - ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); - ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); - ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); - ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogColor.x, - cullStageData->frameDependentData->FogColor.y, - cullStageData->frameDependentData->FogColor.z); - ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->EndFogColor.x, - cullStageData->frameDependentData->EndFogColor.y, - cullStageData->frameDependentData->EndFogColor.z); - ImGui::Text("End Fog Color Distance: %.3f", cullStageData->frameDependentData->EndFogColorDistance); - ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->SunFogColor.x, - cullStageData->frameDependentData->SunFogColor.y, - cullStageData->frameDependentData->SunFogColor.z); - ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); - ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogHeightColor.x, - cullStageData->frameDependentData->FogHeightColor.y, - cullStageData->frameDependentData->FogHeightColor.z); - ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogHeightCoefficients.x, - cullStageData->frameDependentData->FogHeightCoefficients.y, - cullStageData->frameDependentData->FogHeightCoefficients.z); - ImGui::Separator(); - } - } - if (ImGui::CollapsingHeader("Current light params")) { - if (cullStageData->frameDependentData != nullptr) { - ImGui::Text("Glow: %.3f", cullStageData->frameDependentData->currentGlow); - } - } +// auto &cullStageData = m_cullstages[currentFrame]; +// +// if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { +// int m2ObjectsBeforeCullingExterior = 0; +// if (cullStageData->viewsHolder.getExterior() != nullptr) { +// m2ObjectsBeforeCullingExterior = cullStageData->viewsHolder.getExterior()->m2List.getCandidates().size(); +// } +// +// int wmoGroupsInExterior = 0; +// if (cullStageData->viewsHolder.getExterior() != nullptr) { +// wmoGroupsInExterior = cullStageData->viewsHolder.getExterior()->wmoGroupArray.getToDraw().size(); +// } +// +// int m2ObjectsDrawn = cullStageData!= nullptr ? cullStageData->m2Array.getDrawn().size() : 0; +// int wmoObjectsBeforeCull = cullStageData!= nullptr ? cullStageData->wmoArray.getCandidates().size() : 0; +// +// ImGui::Text("M2 objects drawn: %s", std::to_string(m2ObjectsDrawn).c_str()); +// ImGui::Text("WMO Groups in Exterior: %s", std::to_string(wmoGroupsInExterior).c_str()); +// ImGui::Text("Interiors (aka group WMOs): %s", std::to_string(cullStageData->viewsHolder.getInteriorViews().size()).c_str()); +// ImGui::Text("M2 Objects Before Culling in Exterior: %s", std::to_string(m2ObjectsBeforeCullingExterior).c_str()); +// ImGui::Text("WMO objects before culling: %s", std::to_string(wmoObjectsBeforeCull).c_str()); +// +// ImGui::Separator(); +// } +// +// if (ImGui::CollapsingHeader("Current fog params")) { +// if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { +// ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); +// ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); +// ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); +// ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); +// ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); +// ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); +// ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); +// ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogColor.x, +// cullStageData->frameDependentData->FogColor.y, +// cullStageData->frameDependentData->FogColor.z); +// ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->EndFogColor.x, +// cullStageData->frameDependentData->EndFogColor.y, +// cullStageData->frameDependentData->EndFogColor.z); +// ImGui::Text("End Fog Color Distance: %.3f", cullStageData->frameDependentData->EndFogColorDistance); +// ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->SunFogColor.x, +// cullStageData->frameDependentData->SunFogColor.y, +// cullStageData->frameDependentData->SunFogColor.z); +// ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); +// ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogHeightColor.x, +// cullStageData->frameDependentData->FogHeightColor.y, +// cullStageData->frameDependentData->FogHeightColor.z); +// ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogHeightCoefficients.x, +// cullStageData->frameDependentData->FogHeightCoefficients.y, +// cullStageData->frameDependentData->FogHeightCoefficients.z); +// ImGui::Separator(); +// } +// } +// if (ImGui::CollapsingHeader("Current light params")) { +// if (cullStageData->frameDependentData != nullptr) { +// ImGui::Text("Glow: %.3f", cullStageData->frameDependentData->currentGlow); +// } +// } ImGui::End(); } @@ -558,7 +557,7 @@ void FrontendUI::showMainMenu() { if (ImGui::MenuItem("Test export")) { if (currentScene != nullptr) { exporter = std::make_shared("./gltf/"); - currentScene->exportScene(exporter.get()); +// currentScene->exportScene(exporter.get()); exporterFramesReady = 0; } } @@ -1292,195 +1291,10 @@ void FrontendUI::showSettingsDialog() { ImGui::End(); } } -#define logExecution {} -//#define logExecution { \ -// std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ -//} -void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { - auto m_device = m_api->hDevice; - - logExecution - if (this->fontTexture == nullptr) { - logExecution - ImGuiIO& io = ImGui::GetIO(); - logExecution - unsigned char* pixels; - int width, height; - logExecution - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - logExecution - // Upload texture to graphics system - logExecution - this->fontTexture = m_device->createTexture(false, false); - this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); - logExecution - // Store our identifier - logExecution - io.Fonts->TexID = this->fontTexture; - logExecution - return; - } - logExecution - if (exporter != nullptr) { - if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { - exporterFramesReady++; - } - if (exporterFramesReady > 5) { - exporter->saveToFile("model.gltf"); - exporter = nullptr; - } - } - logExecution - lastWidth = resultDrawStage->viewPortDimensions.maxs[0]; - lastHeight = resultDrawStage->viewPortDimensions.maxs[1]; - - resultDrawStage->opaqueMeshes = std::make_shared(); - logExecution - auto *draw_data = ImGui::GetDrawData(); - logExecution - if (draw_data == nullptr) - return; - - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) { - return; - } - logExecution - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - logExecution - //Create projection matrix: - auto uiScale = ImGui::GetIO().uiScale; - float L = draw_data->DisplayPos.x * uiScale; - float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; - float T = draw_data->DisplayPos.y * uiScale; - float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; - logExecution - mathfu::mat4 ortho_projection = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, -1.0f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, - }; - - logExecution - if (m_device->getIsVulkanAxisSystem()) { - static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1/2.0, - 0, 0, 0, 1).Transpose(); - ortho_projection = vulkanMatrixFix1 * ortho_projection; - } - logExecution - auto uboPart = m_device->createUniformBufferChunk(sizeof(ImgUI::modelWideBlockVS)); - - - uboPart->setUpdateHandler([ortho_projection,uiScale](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData) { - auto &uni = self->getObject(); - uni.projectionMat = ortho_projection; - uni.scale[0] = uiScale; - }); - - logExecution - auto shaderPermute = m_device->getShader("imguiShader", nullptr); - logExecution - // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - - // Upload vertex/index buffers - auto vertexBufferBindings = m_device->createVertexBufferBindings(); - auto vboBuffer = m_device->createVertexBuffer(); - auto iboBuffer = m_device->createIndexBuffer(); - - vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - //Create vao - GVertexBufferBinding vertexBufferBinding; - vertexBufferBinding.bindings = std::vector(&imguiBindings[0], &imguiBindings[3]); - vertexBufferBinding.vertexBuffer = vboBuffer; +//void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { - vertexBufferBindings->setIndexBuffer(iboBuffer); - vertexBufferBindings->addVertexBufferBinding(vertexBufferBinding); - vertexBufferBindings->save(); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - - - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != NULL) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) -// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) -// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); -// else -// pcmd->UserCallback(cmd_list, pcmd); - assert(pcmd->UserCallback == NULL); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec4 clip_rect; - clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { - // Apply scissor/clipping rectangle - // Create mesh add add it to collected meshes - gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); - meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.backFaceCulling = false; - meshTemplate.depthCulling = false; - - meshTemplate.scissorEnabled = true; - //Vulkan has different clip offset compared to OGL - if (!m_device->getIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } else { - meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } - - meshTemplate.ubo[1] = uboPart; - meshTemplate.textureCount = 1; - meshTemplate.texture[0] = pcmd->TextureId; - - meshTemplate.start = pcmd->IdxOffset * 2; - meshTemplate.end = pcmd->ElemCount; - - resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); - } - } - } - } - - //1. Collect buffers - auto &bufferChunks = updateStages[0]->uniformBufferChunks; - int renderIndex = 0; - for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { - for (int i = 0; i < 5; i++ ) { - auto bufferChunk = mesh->getUniformBuffer(i); - - if (bufferChunk != nullptr) { - bufferChunks.push_back(bufferChunk); - } - } - } - - std::sort( bufferChunks.begin(), bufferChunks.end()); - bufferChunks.erase( unique( bufferChunks.begin(), bufferChunks.end() ), bufferChunks.end() ); -} +//} void FrontendUI::getAdtSelectionMinimap(int wdtFileDataId) { m_wdtFile = m_api->cacheStorage->getWdtFileCache()->getFileId(wdtFileDataId); @@ -1558,12 +1372,6 @@ void FrontendUI::showMakeScreenshotDialog() { } } -void FrontendUI::produceUpdateStage(HUpdateStage &updateStage) { - this->update(updateStage); - - -} - mathfu::mat4 getInfZMatrix(float f, float aspect) { return mathfu::mat4( f / aspect, 0.0f, 0.0f, 0.0f, @@ -1572,186 +1380,169 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { 0.0f, 0.0f, 1, 0.0f); } -HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int height, double deltaTime, bool isScreenshot, - bool produceDoubleCamera, bool swapDebugCamera, - ApiContainer &apiContainer, std::shared_ptr ¤tScene, HCullStage &cullStage) { - - - static const mathfu::mat4 vulkanMatrixFix2 = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1.0/2.0, - 0, 0, 0, 1).Transpose(); - - float farPlaneRendering = apiContainer.getConfig()->farPlane; - float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; - - float nearPlane = 1.0; - float fov = toRadian(45.0); - - float canvasAspect = (float)width / (float)height; - - HCameraMatrices cameraMatricesCulling = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); - HCameraMatrices cameraMatricesUpdate = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); - HCameraMatrices cameraMatricesRendering = cameraMatricesUpdate; - HCameraMatrices cameraMatricesRenderingDebug = nullptr; - - if (produceDoubleCamera && apiContainer.debugCamera != nullptr) - cameraMatricesRenderingDebug = apiContainer.debugCamera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); - - - //Frustum matrix with reversed Z - bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); - if (isInfZSupported) - { - float f = 1.0f / tan(fov / 2.0f); - cameraMatricesRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); - if (cameraMatricesRenderingDebug != nullptr) { - cameraMatricesRenderingDebug->perspectiveMat = cameraMatricesRendering->perspectiveMat; - } - } - - if (apiContainer.hDevice->getIsVulkanAxisSystem() ) { - auto &perspectiveMatrix = cameraMatricesRendering->perspectiveMat; - - perspectiveMatrix = vulkanMatrixFix2 * perspectiveMatrix; - } - - auto clearColor = apiContainer.getConfig()->clearColor; - - if (cameraMatricesRenderingDebug && swapDebugCamera) { - std::swap(cameraMatricesRendering, cameraMatricesRenderingDebug); - } - - if (currentScene != nullptr) { - ViewPortDimensions dimensions = {{0, 0}, {width, height}}; - - HFrameBuffer fb = nullptr; - if (isScreenshot) { - fb = apiContainer.hDevice->createFrameBuffer(width, height, - {ITextureFormat::itRGBA}, - ITextureFormat::itDepth32, - apiContainer.hDevice->getMaxSamplesCnt(), 4); - } - - cullStage = sceneScenario->addCullStage(cameraMatricesCulling, currentScene); - auto updateStage = sceneScenario->addUpdateStage(cullStage, deltaTime*(1000.0f), cameraMatricesUpdate); - std::vector updateStages = {updateStage}; - - std::vector drawStageDependencies = {}; - if (produceDoubleCamera) { - std::vector drawStageDependencies__ = {}; - - HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRenderingDebug, drawStageDependencies__, - true, - dimensions, - true, isInfZSupported, clearColor, fb); - drawStageDependencies.push_back(sceneDrawStage); - - int newWidth = floor(dimensions.maxs[0]*0.25f); - int newHeight = floor((float)newWidth / canvasAspect); - - int newX = dimensions.maxs[0] - newWidth; - int newY = dimensions.maxs[1] - newHeight; - - dimensions = {{newX, newY}, {newWidth, newHeight}}; - } - - HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRendering, drawStageDependencies, - true, - dimensions, - true, isInfZSupported, clearColor, fb); - - - return sceneDrawStage; - } - - return nullptr; -} +//HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int height, double deltaTime, bool isScreenshot, +// bool produceDoubleCamera, bool swapDebugCamera, +// ApiContainer &apiContainer, std::shared_ptr ¤tScene, HCullStage &cullStage) { +// +// +// static const mathfu::mat4 vulkanMatrixFix2 = mathfu::mat4(1, 0, 0, 0, +// 0, -1, 0, 0, +// 0, 0, 1.0/2.0, 1.0/2.0, +// 0, 0, 0, 1).Transpose(); +// +// float farPlaneRendering = apiContainer.getConfig()->farPlane; +// float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; +// +// float nearPlane = 1.0; +// float fov = toRadian(45.0); +// +// float canvasAspect = (float)width / (float)height; +// +// HCameraMatrices cameraMatricesCulling = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); +// HCameraMatrices cameraMatricesUpdate = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); +// HCameraMatrices cameraMatricesRendering = cameraMatricesUpdate; +// HCameraMatrices cameraMatricesRenderingDebug = nullptr; +// +// if (produceDoubleCamera && apiContainer.debugCamera != nullptr) +// cameraMatricesRenderingDebug = apiContainer.debugCamera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); +// +// +// //Frustum matrix with reversed Z +// bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); +// if (isInfZSupported) +// { +// float f = 1.0f / tan(fov / 2.0f); +// cameraMatricesRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); +// if (cameraMatricesRenderingDebug != nullptr) { +// cameraMatricesRenderingDebug->perspectiveMat = cameraMatricesRendering->perspectiveMat; +// } +// } +// +// if (apiContainer.hDevice->getIsVulkanAxisSystem() ) { +// auto &perspectiveMatrix = cameraMatricesRendering->perspectiveMat; +// +// perspectiveMatrix = vulkanMatrixFix2 * perspectiveMatrix; +// } +// +// auto clearColor = apiContainer.getConfig()->clearColor; +// +// if (cameraMatricesRenderingDebug && swapDebugCamera) { +// std::swap(cameraMatricesRendering, cameraMatricesRenderingDebug); +// } +// +// if (currentScene != nullptr) { +// ViewPortDimensions dimensions = {{0, 0}, {width, height}}; +// +// HFrameBuffer fb = nullptr; +// if (isScreenshot) { +// fb = apiContainer.hDevice->createFrameBuffer(width, height, +// {ITextureFormat::itRGBA}, +// ITextureFormat::itDepth32, +// apiContainer.hDevice->getMaxSamplesCnt(), 4); +// } +// +// cullStage = sceneScenario->addCullStage(cameraMatricesCulling, currentScene); +// auto updateStage = sceneScenario->addUpdateStage(cullStage, deltaTime*(1000.0f), cameraMatricesUpdate); +// std::vector updateStages = {updateStage}; +// +// std::vector drawStageDependencies = {}; +// if (produceDoubleCamera) { +// std::vector drawStageDependencies__ = {}; +// +// HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRenderingDebug, drawStageDependencies__, +// true, +// dimensions, +// true, isInfZSupported, clearColor, fb); +// drawStageDependencies.push_back(sceneDrawStage); +// +// int newWidth = floor(dimensions.maxs[0]*0.25f); +// int newHeight = floor((float)newWidth / canvasAspect); +// +// int newX = dimensions.maxs[0] - newWidth; +// int newY = dimensions.maxs[1] - newHeight; +// +// dimensions = {{newX, newY}, {newWidth, newHeight}}; +// } +// +// HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRendering, drawStageDependencies, +// true, +// dimensions, +// true, isInfZSupported, clearColor, fb); +// +// +// return sceneDrawStage; +// } +// +// return nullptr; +//} HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, double deltaTime) { if (m_minimapGenerationWindow != nullptr) { m_minimapGenerationWindow->process(); } - if (dataExporter != nullptr) { - dataExporter->process(); - if (dataExporter->isDone()) { - delete dataExporter; - dataExporter = nullptr; - } - } - - if (screenshotDS != nullptr) { - if (screenshotFrame + 5 <= m_api->hDevice->getFrameNumber()) { - std::vector buffer = std::vector(screenShotWidth*screenShotHeight*4+1); - - saveDataFromDrawStage(screenshotDS->target, screenshotFilename, screenShotWidth, screenShotHeight, buffer); - - screenshotDS = nullptr; - } - } - - - HFrameScenario sceneScenario = std::make_shared(); - std::vector uiDependecies = {}; - - if (needToMakeScreenshot) - { - HCullStage tempCullStage = nullptr; - auto drawStage = createSceneDrawStage(sceneScenario, screenShotWidth, screenShotHeight, deltaTime, true, - false, false, *m_api, - currentScene,tempCullStage); - if (drawStage != nullptr) { - uiDependecies.push_back(drawStage); - screenshotDS = drawStage; - screenshotFrame = m_api->hDevice->getFrameNumber(); - } - needToMakeScreenshot = false; - } - if (m_minimapGenerationWindow != nullptr) { - auto drawStage = m_minimapGenerationWindow->getDrawStage(sceneScenario); - if (drawStage != nullptr) { - uiDependecies.push_back(drawStage); - } - } - - //DrawStage for current frame - bool clearOnUi = true; - if (currentScene != nullptr && m_api->camera != nullptr) - { - int currentFrame = m_api->hDevice->getDrawFrameNumber(); - auto &cullStageData = m_cullstages[currentFrame]; - cullStageData = nullptr; - - - - auto drawStage = createSceneDrawStage(sceneScenario, canvWidth, canvHeight, deltaTime, - false, - m_api->getConfig()->doubleCameraDebug, - m_api->getConfig()->swapMainAndDebug, - *m_api, - currentScene, cullStageData); - if (drawStage != nullptr) { - uiDependecies.push_back(drawStage); - clearOnUi = false; - } - } - //DrawStage for UI - { - ViewPortDimensions dimension = { - {0, 0}, - {canvWidth, canvHeight} - }; - auto clearColor = m_api->getConfig()->clearColor; - - auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); - auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); - std::vector updateStages = {uiUpdateStage}; - HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, - true, dimension, clearOnUi, false, clearColor, nullptr); - } - - return sceneScenario; + return nullptr; +// +// HFrameScenario sceneScenario = std::make_shared(); +// std::vector uiDependecies = {}; +// +// if (needToMakeScreenshot) +// { +// HCullStage tempCullStage = nullptr; +// auto drawStage = createSceneDrawStage(sceneScenario, screenShotWidth, screenShotHeight, deltaTime, true, +// false, false, *m_api, +// currentScene,tempCullStage); +// if (drawStage != nullptr) { +// uiDependecies.push_back(drawStage); +// screenshotDS = drawStage; +// screenshotFrame = m_api->hDevice->getFrameNumber(); +// } +// needToMakeScreenshot = false; +// } +// if (m_minimapGenerationWindow != nullptr) { +// auto drawStage = m_minimapGenerationWindow->getDrawStage(sceneScenario); +// if (drawStage != nullptr) { +// uiDependecies.push_back(drawStage); +// } +// } +// +// //DrawStage for current frame +// bool clearOnUi = true; +// if (currentScene != nullptr && m_api->camera != nullptr) +// { +// int currentFrame = m_api->hDevice->getDrawFrameNumber(); +// auto &cullStageData = m_cullstages[currentFrame]; +// cullStageData = nullptr; +// +// +// +// auto drawStage = createSceneDrawStage(sceneScenario, canvWidth, canvHeight, deltaTime, +// false, +// m_api->getConfig()->doubleCameraDebug, +// m_api->getConfig()->swapMainAndDebug, +// *m_api, +// currentScene, cullStageData); +// if (drawStage != nullptr) { +// uiDependecies.push_back(drawStage); +// clearOnUi = false; +// } +// } +// //DrawStage for UI +// { +// ViewPortDimensions dimension = { +// {0, 0}, +// {canvWidth, canvHeight} +// }; +// auto clearColor = m_api->getConfig()->clearColor; +// +// auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); +// auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); +// std::vector updateStages = {uiUpdateStage}; +// HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, +// true, dimension, clearOnUi, false, clearColor, nullptr); +// } +// +// return sceneScenario; } bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { @@ -1793,8 +1584,9 @@ void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementTextureIds) { - currentScene = std::make_shared(m_api, m2Fdid); - currentScene->setReplaceTextureArray(replacementTextureIds); + auto m2Scene = std::make_shared(m_api, m2Fdid); + currentScene = m2Scene; + m2Scene->setReplaceTextureArray(replacementTextureIds); m_api->camera = std::make_shared(); @@ -1804,8 +1596,9 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText m_api->camera->setCameraPos(0, 0, 0); } void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { - currentScene = std::make_shared(m_api, m2FileName); - currentScene->setReplaceTextureArray(replacementTextureIds); + auto m2Scene = std::make_shared(m_api, m2FileName); + currentScene = m2Scene; + m2Scene->setReplaceTextureArray(replacementTextureIds); m_api->camera = std::make_shared(); m_api->camera->setCameraPos(0, 0, 0); @@ -1820,9 +1613,9 @@ void FrontendUI::unloadScene() { } int FrontendUI::getCameraNumCallback() { - if (currentScene != nullptr) { - return currentScene->getCameraNum(); - } +// if (currentScene != nullptr) { +// return currentScene->getCameraNum(); +// } return 0; } @@ -1830,21 +1623,22 @@ int FrontendUI::getCameraNumCallback() { bool FrontendUI::setNewCameraCallback(int cameraNum) { - if (currentScene == nullptr) return false; - - auto newCamera = currentScene->createCamera(cameraNum); - if (newCamera == nullptr) { - m_api->camera = std::make_shared(); - m_api->camera->setMovementSpeed(movementSpeed); - return false; - } - - m_api->camera = newCamera; - return true; + return false; +// if (currentScene == nullptr) return false; +// +// auto newCamera = currentScene->createCamera(cameraNum); +// if (newCamera == nullptr) { +// m_api->camera = std::make_shared(); +// m_api->camera->setMovementSpeed(movementSpeed); +// return false; +// } +// +// m_api->camera = newCamera; +// return true; } void FrontendUI::resetAnimationCallback() { - currentScene->resetAnimation(); +// currentScene->resetAnimation(); } void FrontendUI::getCameraPos(float &cameraX, float &cameraY, float &cameraZ) { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 7006204b0..83e70c60b 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -22,6 +22,7 @@ #include "../exporters/dataExporter/DataExporterClass.h" #include "childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h" #include "childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h" +#include "../../wowViewerLib/src/exporters/IExporter.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -52,27 +53,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &replaceTextureArray) override {}; - void setMeshIdArray(std::vector &meshIds) override {}; - void setAnimationId(int animationId) override {}; - void setMeshIds(std::vector &meshIds) override {}; - - void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; - void produceUpdateStage(HUpdateStage &updateStage) override; - - void checkCulling(HCullStage &cullStage) override {}; - - - void doPostLoad(HCullStage &cullStage) override {}; - - void update(HUpdateStage &updateStage) {}; - void updateBuffers(HUpdateStage &updateStage) override {}; - - - int getCameraNum() override {return 0;}; - std::shared_ptr createCamera(int cameraNum) override {return nullptr;}; - void resetAnimation() override {}; - +// void produceDrawStage(HDrawStage &resultDrawStage); HFrameScenario createFrameScenario(int canvWidth, int canvHeight, double deltaTime); void setUIScale(float scale) { @@ -91,7 +72,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_cullstages = {}; +// HCullStage m_lastCullstage = {}; float uiScale = 1; @@ -138,8 +119,6 @@ class FrontendUI : public IScene, public std::enable_shared_from_thisgetLastDrawStage(); - if (drawStage != nullptr) { - auto texture = drawStage->target->getAttachment(0); + auto lastFrameBuffer = minimapGenerator->getLastFrameBuffer(); + if (lastFrameBuffer != nullptr) { + auto texture = lastFrameBuffer->getAttachment(0); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); @@ -97,13 +97,10 @@ void MinimapGenerationWindow::render() { ImGui::PopStyleColor(3); ImGui::PopStyleVar(3); } - ImGui::EndChild(); } ImGui::EndChild(); - - } ImGui::Columns(1); @@ -125,7 +122,7 @@ void MinimapGenerationWindow::renderMapConfigSubWindow(int mapIndex) { ImGui::PushStyleColor(ImGuiCol_Button, redColor); ImGui::PushStyleColor(ImGuiCol_ButtonActive, redColor); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, redColor); - if (ImGui::Button(("Delete##"+ std::to_string(mapIndex)).c_str())) { + if (ImGui::Button(("Delete##"+std::to_string(mapIndex)).c_str())) { if (mapIndex > 0) { sceneDef->maps.erase(std::next(sceneDef->maps.begin(), mapIndex - 1)); } else { @@ -317,11 +314,9 @@ void MinimapGenerationWindow::process() { minimapGenerator->process(); } -HDrawStage MinimapGenerationWindow::getDrawStage(HFrameScenario sceneScenario) { +void MinimapGenerationWindow::getDrawStage(HFrameScenario sceneScenario) { if (minimapGenerator->getCurrentMode() != EMGMode::eNone) { return minimapGenerator->createSceneDrawStage(sceneScenario); - } else { - return nullptr; } } diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h index 06c974ae7..5742fda70 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -25,7 +25,7 @@ class MinimapGenerationWindow { void render(); void process(); - HDrawStage getDrawStage(HFrameScenario sceneScenario); + void getDrawStage(HFrameScenario sceneScenario); private: HApiContainer m_api; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp new file mode 100644 index 000000000..007ecddb7 --- /dev/null +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 12.12.22. +// + +#include "FrontendUIRenderer.h" diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h new file mode 100644 index 000000000..a693a6e4c --- /dev/null +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -0,0 +1,22 @@ +// +// Created by Deamon on 12.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_FRONTENDUIRENDERER_H +#define AWEBWOWVIEWERCPP_FRONTENDUIRENDERER_H + +#include "../../../../wowViewerLib/src/renderer/IRenderParameters.h" +#include "ImGUIPlan.h" +#include "buffers/IVertexBufferDynamicImgui.h" + +class FrontendUIRenderer : public IRendererParameters { +public: + virtual HIVertexBufferDynamicImgui allocateDynamicVertexBuffer(int size) = 0; + virtual HIVertexBufferDynamicImgui allocateDynamicIndexBuffer(int size) = 0; + +// virtual HGMesh allocateImguiMesh(eshTemplate) +}; + +typedef FrameInputParams FrontendUIInputParams; + +#endif //AWEBWOWVIEWERCPP_FRONTENDUIRENDERER_H diff --git a/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp b/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp new file mode 100644 index 000000000..15406d8ad --- /dev/null +++ b/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp @@ -0,0 +1,16 @@ +// +// Created by Deamon on 12.12.22. +// + +#include "FrontendUIRendererFactory.h" +#include "vulkan/FrontendUIRenderForwardVLK.h" + +std::shared_ptr FrontendUIRendererFactory::createForwardRenderer(HGDevice &device) { + switch (device->getDeviceType()) { + case GDeviceType::GVulkan: + return std::make_shared(std::dynamic_pointer_cast(device)); + default: + return nullptr; + } + +} diff --git a/src/ui/renderer/uiScene/FrontendUIRendererFactory.h b/src/ui/renderer/uiScene/FrontendUIRendererFactory.h new file mode 100644 index 000000000..4d3e2a310 --- /dev/null +++ b/src/ui/renderer/uiScene/FrontendUIRendererFactory.h @@ -0,0 +1,18 @@ +// +// Created by Deamon on 12.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_FRONTENDUIRENDERERFACTORY_H +#define AWEBWOWVIEWERCPP_FRONTENDUIRENDERERFACTORY_H + +#include +#include +#include "FrontendUIRenderer.h" +#include "../../../../wowViewerLib/src/gapi/interface/IDevice.h" + +class FrontendUIRendererFactory { + static std::shared_ptr createForwardRenderer(HGDevice &device); +}; + + +#endif //AWEBWOWVIEWERCPP_FRONTENDUIRENDERERFACTORY_H diff --git a/src/ui/renderer/uiScene/ImGUIPlan.cpp b/src/ui/renderer/uiScene/ImGUIPlan.cpp new file mode 100644 index 000000000..42b75b1c4 --- /dev/null +++ b/src/ui/renderer/uiScene/ImGUIPlan.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 12.12.22. +// + +#include "ImGUIPlan.h" diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h new file mode 100644 index 000000000..3288951ef --- /dev/null +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -0,0 +1,29 @@ +// +// Created by Deamon on 12.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IMGUIPLAN_H +#define AWEBWOWVIEWERCPP_IMGUIPLAN_H + +#include "imgui.h" + +namespace ImGuiFramePlan { + class EmptyPlan { + }; + + class ImGUIParam { + public: + ~ImGUIParam() { + if (imData != nullptr) { + for (int i = 0; i < imData->CmdListsCount; i++ ) { + IM_FREE(imData->CmdLists[i]); + } + } + } + + public: + ImDrawData *imData = nullptr; + }; +} + +#endif //AWEBWOWVIEWERCPP_IMGUIPLAN_H diff --git a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp new file mode 100644 index 000000000..1480caa9d --- /dev/null +++ b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 14.12.22. +// + +#include "IVertexBufferDynamicImgui.h" diff --git a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h new file mode 100644 index 000000000..0b8349c66 --- /dev/null +++ b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h @@ -0,0 +1,18 @@ +// +// Created by Deamon on 14.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H +#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H + + +#include "imgui.h" +#include "../../../../../wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h" + +class IVertexBufferDynamicImgui : public IVertexBufferDynamicTemplate{ +public: + ~IVertexBufferDynamicImgui() override = default ; +}; +typedef std::shared_ptr HIVertexBufferDynamicImgui; + +#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp new file mode 100644 index 000000000..6c1145cc6 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -0,0 +1,267 @@ +// +// Created by Deamon on 12.12.22. +// + +#include "FrontendUIRenderForwardVLK.h" +#include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" +#include "buffers/IVertexBufferDynamicImguiVLK.h" + +FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + createBuffer(vertexBuffers[i], 1024*1024*1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + createBuffer(indexBuffers[i], 1024*1024*1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); +} + +void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptr &frameInputParams) { + std::lock_guard guard(m_inputParamsMtx); + + m_inputParams.push(frameInputParams); +} + +void FrontendUIRenderForwardVLK::render() { + +} + +void FrontendUIRenderForwardVLK::createBuffer(Buffer &buffer, int bufferSize, VkBufferUsageFlags bufferUsageFlags) { +//Create new buffer for VBO + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = bufferSize; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo ibAllocCreateInfo = {}; + ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, + &buffer.stagingBuffer, + &buffer.stagingBufferAlloc, + &buffer.stagingBufferAllocInfo)); + + // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT. + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | bufferUsageFlags; + ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + ibAllocCreateInfo.flags = 0; + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, + &buffer.g_hBuffer, + &buffer.g_hBufferAlloc, nullptr)); + + //Create virtual buffer off this native buffer + VmaVirtualBlockCreateInfo blockCreateInfo = {}; + blockCreateInfo.size = bufferSize; + + VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &buffer.virtualBlock); + if(res != VK_SUCCESS) + { + std::cerr << "Failed to create virtual buffer" << std::endl; + } + //memcpy(bufferInfo.stagingVertexBufferAllocInfo.pMappedData, data, length); +} + +void FrontendUIRenderForwardVLK::destroyBuffer(FrontendUIRenderForwardVLK::Buffer &buffer) { + auto l_device = m_device; + + m_device->addDeallocationRecord( + [buffer, l_device]() { + vmaClearVirtualBlock(buffer.virtualBlock); + vmaDestroyVirtualBlock(buffer.virtualBlock); + + vmaDestroyBuffer(l_device->getVMAAllocator(), buffer.stagingBuffer, buffer.stagingBufferAlloc); + vmaDestroyBuffer(l_device->getVMAAllocator(), buffer.g_hBuffer, buffer.g_hBufferAlloc); + + } + ); +} + +HIVertexBufferDynamicImgui FrontendUIRenderForwardVLK::allocateDynamicVertexBuffer(int maxSize) { + VmaVirtualAllocationCreateInfo allocCreateInfo = {}; + allocCreateInfo.size = maxSize; //Size in bytes + + VmaVirtualAllocation alloc; + VkDeviceSize offset; + + VkResult res = vmaVirtualAllocate(vertexBuffers[0].virtualBlock, &allocCreateInfo, &alloc, &offset); + if(res == VK_SUCCESS) + { + return std::make_shared(this, maxSize, alloc, offset); + } + else + { + // Allocation failed - no space for it could be found. Handle this error! + return nullptr; + } +} + +void FrontendUIRenderForwardVLK::update() { + + std::unique_lock guard(m_inputParamsMtx); + + guard.lock(); + auto frameParams = m_inputParams.front(); + m_inputParams.pop(); + guard.unlock(); + +// if (this->fontTexture == nullptr) { +// ImGuiIO& io = ImGui::GetIO(); +// unsigned char* pixels; +// int width, height; +// io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. +// // Upload texture to graphics system +// this->fontTexture = m_device->createTexture(false, false); +// this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); +// // Store our identifier +// io.Fonts->TexID = this->fontTexture; +// return; +// } +// if (exporter != nullptr) { +// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { +// exporterFramesReady++; +// } +// if (exporterFramesReady > 5) { +// exporter->saveToFile("model.gltf"); +// exporter = nullptr; +// } +// } + int lastWidth = frameParams->viewPortDimensions.maxs[0]; + int lastHeight = frameParams->viewPortDimensions.maxs[1]; + + auto *draw_data = frameParams->additionalData->imData; + if (draw_data == nullptr) + return; + + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) { + return; + } + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + //Create projection matrix: + auto uiScale = ImGui::GetIO().uiScale; + float L = draw_data->DisplayPos.x * uiScale; + float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; + float T = draw_data->DisplayPos.y * uiScale; + float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; + mathfu::mat4 ortho_projection = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + + if (m_device->getIsVulkanAxisSystem()) { + static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1.0/2.0, 1/2.0, + 0, 0, 0, 1).Transpose(); + ortho_projection = vulkanMatrixFix1 * ortho_projection; + } + + auto uboPart = m_device->createUniformBufferChunk(sizeof(ImgUI::modelWideBlockVS)); + + + uboPart->setUpdateHandler([ortho_projection,uiScale](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) { + auto &uni = self->getObject(); + uni.projectionMat = ortho_projection; + uni.scale[0] = uiScale; + }); + + auto shaderPermute = m_device->getShader("imguiShader", nullptr); + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + + // Upload vertex/index buffers + auto vertexBufferBindings = m_device->createVertexBufferBindings(); + auto vboBuffer = m_device->createVertexBuffer(); + auto iboBuffer = m_device->createIndexBuffer(); + + vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + + //Create vao + GVertexBufferBinding vertexBufferBinding; + vertexBufferBinding.bindings = std::vector(&imguiBindings[0], &imguiBindings[3]); + vertexBufferBinding.vertexBuffer = vboBuffer; + + vertexBufferBindings->setIndexBuffer(iboBuffer); + vertexBufferBindings->addVertexBufferBinding(vertexBufferBinding); + vertexBufferBindings->save(); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + + + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) +// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) +// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); +// else +// pcmd->UserCallback(cmd_list, pcmd); + assert(pcmd->UserCallback == NULL); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + // Create mesh, add it to collected meshes + gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); + meshTemplate.element = DrawElementMode::TRIANGLES; + meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + meshTemplate.backFaceCulling = false; + meshTemplate.depthCulling = false; + + meshTemplate.scissorEnabled = true; + //Vulkan has different clip offset compared to OGL + if (!m_device->getIsVulkanAxisSystem()) { + meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } else { + meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } + + meshTemplate.ubo[1] = uboPart; + meshTemplate.textureCount = 1; + meshTemplate.texture[0] = pcmd->TextureId; + + meshTemplate.start = pcmd->IdxOffset * 2; + meshTemplate.end = pcmd->ElemCount; + + resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); + } + } + } + } + +// //1. Collect buffers +// auto &bufferChunks = updateStages[0]->uniformBufferChunks; +// int renderIndex = 0; +// for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { +// for (int i = 0; i < 5; i++ ) { +// auto bufferChunk = mesh->getUniformBuffer(i); +// +// if (bufferChunk != nullptr) { +// bufferChunks.push_back(bufferChunk); +// } +// } +// } +// +// std::sort( bufferChunks.begin(), bufferChunks.end()); +// bufferChunks.erase( unique( bufferChunks.begin(), bufferChunks.end() ), bufferChunks.end() ); +} diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h new file mode 100644 index 000000000..2967eb4a7 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -0,0 +1,58 @@ +// +// Created by Deamon on 12.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_FRONTENDUIRENDERFORWARDVLK_H +#define AWEBWOWVIEWERCPP_FRONTENDUIRENDERFORWARDVLK_H + + +#include +#include "../FrontendUIRenderer.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h" + +const int MAX_FRAMES_IN_FLIGHT = 2; + +class FrontendUIRenderForwardVLK : public FrontendUIRenderer { +public: + explicit FrontendUIRenderForwardVLK(HGDeviceVLK hDevice); + + void putIntoQueue(std::shared_ptr &frameInputParams) override; + void render(); + + HIVertexBufferDynamicImgui allocateDynamicVertexBuffer(int size) override; +// HGVertexBufferDynamic allocateDynamicIndexBuffer() = 0; +private: + HGDeviceVLK m_device; + + //Frame counter + int m_frame = 0; + + //Buffers + struct Buffer { + VkBuffer g_hBuffer = VK_NULL_HANDLE; + VmaAllocation g_hBufferAlloc = VK_NULL_HANDLE; + + VkBuffer stagingBuffer = VK_NULL_HANDLE; + VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; + VmaAllocationInfo stagingBufferAllocInfo; + + //Virtual block for suballocations + VmaVirtualBlock virtualBlock; + }; + + std::array vertexBuffers; //Both vertexes here are of exact size + std::array indexBuffers; + + //Rendering pipelining + std::mutex m_inputParamsMtx; + std::queue> m_inputParams; + std::queue> m_updateParams; + +private: + void createBuffer(Buffer &buffer, int bufferSize, VkBufferUsageFlags bufferUsageFlags); + void destroyBuffer(Buffer &buffer); + +}; + + +#endif //AWEBWOWVIEWERCPP_FRONTENDUIRENDERFORWARDVLK_H diff --git a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp new file mode 100644 index 000000000..4c7be8cd9 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp @@ -0,0 +1,15 @@ +// +// Created by Deamon on 14.12.22. +// + +#include "IVertexBufferDynamicImguiVLK.h" + +RVertexBufferDynamicImguiVLK::RVertexBufferDynamicImguiVLK(FrontendUIRenderer &renderer, VmaVirtualAllocation alloc, VkDeviceSize offset, int size) : m_renderer(renderer) { + m_alloc = alloc; + m_offset = offset; + m_size = size; +} + +RVertexBufferDynamicImguiVLK::~RVertexBufferDynamicImguiVLK() { + +} diff --git a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h new file mode 100644 index 000000000..6cf919454 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h @@ -0,0 +1,33 @@ +// +// Created by Deamon on 14.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H +#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H + +#include "../../buffers/IVertexBufferDynamicImgui.h" +#include "../../FrontendUIRenderer.h" +#include "../../../../../../wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h" + +class RVertexBufferDynamicImguiVLK : public IVertexBufferDynamicImgui { + friend class FrontendUIRenderer; +private: + VmaVirtualAllocation m_alloc; + VkDeviceSize m_offset; + int m_size; + + FrontendUIRenderer &m_renderer; +public: + RVertexBufferDynamicImguiVLK(FrontendUIRenderer &renderer, VmaVirtualAllocation alloc, VkDeviceSize offset, int size); + ~RVertexBufferDynamicImguiVLK() override; + + const std::vector &getBuffer() override { + return stagingVertexBuffer; + }; + void save(size_t sizeToSave) override { + m_renderer.planUpload() + }; +}; + + +#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index ed79477d8..798acad82 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -6,8 +6,8 @@ include(CheckCXXCompilerFlag) set(CMAKE_VERBOSE_MAKEFILE ON) set(LINK_GLEW 1) -set(LINK_OGL2 1) -set(LINK_OGL3 1) +set(LINK_OGL2 0) +set(LINK_OGL3 0) set(LINK_OGL4 0) set(LINK_EGL 1 PARENT_SCOPE) set(LINK_EGL 1) @@ -260,7 +260,6 @@ set(SOURCE_FILES src/engine/persistance/m2File.cpp src/engine/persistance/m2File.h src/gapi/interface/IDevice.cpp - src/gapi/interface/textures/IBlpTexture.h src/gapi/interface/textures/ITexture.h src/gapi/interface/buffers/IIndexBuffer.h src/gapi/interface/buffers/IUniformBuffer.h @@ -291,12 +290,7 @@ set(SOURCE_FILES src/engine/algorithms/quick-sort-omp.h src/include/databaseHandler.h src/engine/persistance/PersistentFile.h - src/engine/SceneComposer.cpp - src/engine/SceneComposer.h - src/engine/SceneScenario.h src/gapi/interface/IFrameBuffer.h - src/engine/SceneScenario.cpp - src/engine/DrawStage.h src/include/iostuff.h src/engine/ApiContainer.cpp src/engine/ApiContainer.h @@ -321,9 +315,18 @@ set(SOURCE_FILES src/engine/algorithms/mathHelper_culling_sse.h src/engine/algorithms/mathHelper_culling.cpp src/engine/algorithms/mathHelper_culling.h - src/renderer/MapSceneRenderer.cpp - src/renderer/MapSceneRenderer.h - src/renderer/MapSceneRendererFactory.cpp src/renderer/MapSceneRendererFactory.h) + src/renderer/frame/SceneScenario.cpp + src/renderer/frame/SceneComposer.cpp + src/renderer/frame/SceneComposer.h + src/renderer/frame/SceneScenario.h + src/renderer/mapScene/MapSceneRenderer.cpp + src/renderer/mapScene/MapSceneRenderer.h + src/renderer/mapScene/MapSceneRendererFactory.cpp src/renderer/mapScene/MapSceneRendererFactory.h + src/renderer/IRenderer.h + src/renderer/IRenderParameters.h + src/renderer/frame/FrameInputParams.h + src/renderer/mapScene/FrameDependentData.h + src/renderer/buffers/IVertexBufferDynamicTemplate.cpp src/renderer/buffers/IVertexBufferDynamicTemplate.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -365,6 +368,7 @@ if (LINK_OGL2) src/gapi/ogl2.0/GOcclusionQueryGL20.h) endif() +if (LINK_OGL3) set(OPENGL33_IMPLEMENTATION src/gapi/ogl3.3/textures/GBlpTextureGL33.cpp src/gapi/ogl3.3/textures/GBlpTextureGL33.h @@ -414,6 +418,7 @@ set(OPENGL33_IMPLEMENTATION src/gapi/ogl3.3/shaders/GWaterShaderGL33.h src/gapi/ogl3.3/shaders/GWaterfallShaderGL33.cpp src/gapi/ogl3.3/shaders/GWaterfallShaderGL33.h) +endif() if (LINK_OGL4) set(OPENGL4x_IMPLEMENTATION src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp @@ -497,11 +502,17 @@ if (LINK_VULKAN) src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp - src/gapi/vulkan/shaders/GWaterfallShaderVLK.h src/renderer/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/vulkan/MapSceneRenderForwardVLK.h) - set(Vulkan_INCLUDE_DIR $ENV{VULKAN_SDK}/Include) + src/gapi/vulkan/shaders/GWaterfallShaderVLK.h + src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp + src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h) + if (NOT Vulkan_SDK_DIR) + set(Vulkan_SDK_DIR $ENV{VULKAN_SDK}) + endif() + + set(Vulkan_INCLUDE_DIR ${Vulkan_SDK_DIR}/include) IF(WIN32) IF (NOT Vulkan_FOUND) - find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS "$ENV{VULKAN_SDK}/lib") + find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS "${Vulkan_SDK_DIR}/lib") IF (Vulkan_LIBRARY) set(Vulkan_FOUND ON PARENT_SCOPE) MESSAGE("Using bundled Vulkan library version win32, Vulkan_LIBRARY= ${Vulkan_LIBRARY}") @@ -513,7 +524,7 @@ if (LINK_VULKAN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR") ELSE(WIN32) IF (NOT Vulkan_FOUND) - find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan") + find_library(Vulkan_LIBRARY NAMES vulkan HINTS "${Vulkan_SDK_DIR}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan") IF (Vulkan_LIBRARY) set(Vulkan_FOUND ON PARENT_SCOPE) MESSAGE("Using bundled Vulkan library version non-win32") diff --git a/wowViewerLib/src/engine/ApiContainer.h b/wowViewerLib/src/engine/ApiContainer.h index f936c6c30..d95fa3127 100644 --- a/wowViewerLib/src/engine/ApiContainer.h +++ b/wowViewerLib/src/engine/ApiContainer.h @@ -33,7 +33,7 @@ class ApiContainer { typedef std::shared_ptr HApiContainer; -typedef std::array, 64> ADTBoundingBoxHolder; -typedef std::shared_ptr HADTBoundingBoxHolder; +//typedef std::array, 64> ADTBoundingBoxHolder; +//typedef std::shared_ptr HADTBoundingBoxHolder; #endif //AWEBWOWVIEWERCPP_APICONTAINER_H diff --git a/wowViewerLib/src/engine/SceneComposer.cpp b/wowViewerLib/src/engine/SceneComposer.cpp deleted file mode 100644 index 2b3911735..000000000 --- a/wowViewerLib/src/engine/SceneComposer.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// -// Created by deamon on 15.01.20. -// - -#include -#include -#include "SceneComposer.h" -#include "algorithms/FrameCounter.h" -#include "../gapi/UniformBufferStructures.h" -#ifdef __EMSCRIPTEN__ -#include -#endif - -void SceneComposer::processCaches(int limit) { -// std::cout << "WoWSceneImpl::processCaches called " << std::endl; -// std::cout << "this->adtObjectCache.m_cache.size() = " << this->adtObjectCache.m_cache.size()<< std::endl; - if (m_apiContainer->cacheStorage) { - m_apiContainer->cacheStorage->processCaches(limit); - } -} - -SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiContainer) { -#ifdef __EMSCRIPTEN__ - m_supportThreads = false; -// m_supportThreads = emscripten_run_script_int("(SharedArrayBuffer != null) ? 1 : 0") == 1; -#endif - nextDeltaTime[0] = std::promise(); - nextDeltaTime[1] = std::promise(); - nextDeltaTimeForUpdate[0] = std::promise(); - nextDeltaTimeForUpdate[1] = std::promise(); - - if (m_supportThreads) { - loadingResourcesThread = std::thread([&]() { -// try { - using namespace std::chrono_literals; - - while (!this->m_isTerminating) { - std::this_thread::sleep_for(1ms); - - processCaches(1000); - } -// } catch(const std::exception &e) { -// std::cerr << e.what() << std::endl; -// throw; -// } catch (...) { -// throw; -// } - }); - - - cullingThread = std::thread(([&]() { -// try { - using namespace std::chrono_literals; - FrameCounter frameCounter; - - - //NOTE: it's required to have separate counting process here with getPromiseInd/getNextPromiseInd, - //cause it's not known if the frameNumber will be updated from main thread before - //new currIndex is calculated (and if that doenst happen, desync in numbers happens) - auto currIndex = getPromiseInd(); - - while (!this->m_isTerminating) { - //std::cout << "cullingThread " << currIndex << std::endl; - auto future = nextDeltaTime[currIndex].get_future(); - future.wait(); - auto nextIndex = getNextPromiseInd(); - - // std::cout << "update frame = " << getDevice()->getUpdateFrameNumber() << std::endl; - - int currentFrame = m_apiContainer->hDevice->getCullingFrameNumber(); - - frameCounter.beginMeasurement(); - DoCulling(); - frameCounter.endMeasurement(); - m_apiContainer->getConfig()->cullingTimePerFrame = frameCounter.getTimePerFrame(); - - this->cullingFinished.set_value(true); - currIndex = nextIndex; - - } -// } catch(const std::exception &e) { -// std::cerr << e.what() << std::endl; -// throw; -// } catch (...) { -// throw; -// } - })); - - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - updateThread = std::thread(([&]() { -// try { - this->m_apiContainer->hDevice->initUploadThread(); - //NOTE: Refer to comment in cullingThread code - auto currIndex = getPromiseInd(); - while (!this->m_isTerminating) { - - //std::cout << "updateThread " << currIndex << std::endl; - auto future = nextDeltaTimeForUpdate[currIndex].get_future(); - future.wait(); - auto nextIndex = getNextPromiseInd(); - - updateTimePerFrame.beginMeasurement(); - DoUpdate(); - updateTimePerFrame.endMeasurement(); - - updateFinished.set_value(true); - currIndex = nextIndex; - } -// } catch(const std::exception &e) { -// std::cerr << e.what() << std::endl; -// throw; -// } catch (...) { -// throw; -// } - })); - } - } -} - -void SceneComposer::DoCulling() { - static const mathfu::vec3 upVector(0,0,1); - static const mathfu::mat4 vulkanMatrixFix = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1/2.0, - 0, 0, 0, 1).Transpose(); - - int currentFrame = m_apiContainer->hDevice->getCullingFrameNumber(); - auto frameScenario = m_frameScenarios[currentFrame]; - - if (frameScenario == nullptr) return; - - for (int i = 0; i < frameScenario->cullStages.size(); i++) { - auto cullStage = frameScenario->cullStages[i]; - - cullStage->scene->checkCulling(cullStage); - } -} - -void collectMeshes(HDrawStage drawStage, std::vector &meshes) { - if (drawStage->opaqueMeshes != nullptr) { - std::copy( - drawStage->opaqueMeshes->meshes.begin(), - drawStage->opaqueMeshes->meshes.end(), - std::back_inserter(meshes) - ); - } - if (drawStage->transparentMeshes != nullptr) { - std::copy( - drawStage->transparentMeshes->meshes.begin(), - drawStage->transparentMeshes->meshes.end(), - std::back_inserter(meshes) - ); - } - for (auto &deps : drawStage->drawStageDependencies) { - collectMeshes(deps, meshes); - } -} -#define logExecution {} -//#define logExecution { \ -// std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ -//} - -void SceneComposer::DoUpdate() { - logExecution - auto device = m_apiContainer->hDevice; - logExecution - - int updateObjFrame = device->getUpdateFrameNumber(); - logExecution - auto frameScenario = m_frameScenarios[updateObjFrame]; - if (frameScenario == nullptr) return; - logExecution - startUpdateForNexFrame.beginMeasurement(); - device->startUpdateForNextFrame(); - startUpdateForNexFrame.endMeasurement(); - logExecution - singleUpdateCNT.beginMeasurement(); - logExecution - for (auto updateStage : frameScenario->updateStages) { - updateStage->cullResult->scene->produceUpdateStage(updateStage); - } - logExecution - singleUpdateCNT.endMeasurement(); - logExecution - produceDrawStage.beginMeasurement(); - logExecution - - logExecution - for (auto &link : frameScenario->drawStageLinks) { - logExecution - link.scene->produceDrawStage(link.drawStage, link.updateStages); - logExecution - } - produceDrawStage.endMeasurement(); - - meshesCollectCNT.beginMeasurement(); - std::vector meshes; - logExecution - collectMeshes(frameScenario->getDrawStage(), meshes); - logExecution - meshesCollectCNT.endMeasurement(); - logExecution - - updateBuffersCNT.beginMeasurement(); - logExecution - for (auto updateStage : frameScenario->updateStages) { - logExecution - updateStage->cullResult->scene->updateBuffers(updateStage); - logExecution - } - updateBuffersCNT.endMeasurement(); - logExecution - - updateBuffersDeviceCNT.beginMeasurement(); - logExecution - std::vector*> uniformChunkVec; - std::vector frameDepDataVec; - logExecution -// uniformChunkVec.push_back(&additionalChunks); - for (auto &updateStage : frameScenario->updateStages) { - frameDepDataVec.push_back(updateStage->cullResult->frameDependentData); - uniformChunkVec.push_back(&updateStage->uniformBufferChunks); - } - logExecution - device->updateBuffers(uniformChunkVec, frameDepDataVec); - logExecution - updateBuffersDeviceCNT.endMeasurement(); - logExecution - postLoadCNT.beginMeasurement(); - for (auto cullStage : frameScenario->cullStages) { - logExecution - cullStage->scene->doPostLoad(cullStage); //Do post load after rendering is done! - logExecution - } - postLoadCNT.endMeasurement(); - logExecution - textureUploadCNT.beginMeasurement(); - logExecution - device->uploadTextureForMeshes(meshes); - logExecution - textureUploadCNT.endMeasurement(); - - if (device->getIsVulkanAxisSystem()) { - drawStageAndDepsCNT.beginMeasurement(); - if (frameScenario != nullptr) { - m_apiContainer->hDevice->drawStageAndDeps(frameScenario->getDrawStage()); - } - drawStageAndDepsCNT.endMeasurement(); - } - logExecution - endUpdateCNT.beginMeasurement(); - device->endUpdateForNextFrame(); - logExecution - endUpdateCNT.endMeasurement(); - logExecution - - auto config = m_apiContainer->getConfig(); - config->startUpdateForNexFrame = startUpdateForNexFrame.getTimePerFrame(); - config->updateTimePerFrame = updateTimePerFrame.getTimePerFrame(); - config->singleUpdateCNT = singleUpdateCNT.getTimePerFrame(); - config->produceDrawStage = produceDrawStage.getTimePerFrame();; - config->meshesCollectCNT = meshesCollectCNT.getTimePerFrame();; - config->updateBuffersCNT = updateBuffersCNT.getTimePerFrame();; - config->updateBuffersDeviceCNT = updateBuffersDeviceCNT.getTimePerFrame();; - config->postLoadCNT = postLoadCNT.getTimePerFrame();; - config->textureUploadCNT = textureUploadCNT.getTimePerFrame();; - config->drawStageAndDepsCNT = drawStageAndDepsCNT.getTimePerFrame();; - config->endUpdateCNT = endUpdateCNT.getTimePerFrame();; - logExecution - -} -#define logExecution {} -//#define logExecution { \ -// std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ -//} - - -void SceneComposer::draw(HFrameScenario frameScenario) { -// std::cout << __FILE__ << ":" << __LINE__<< "m_apiContainer == nullptr :" << ((m_apiContainer == nullptr) ? "true" : "false") << std::endl; -// std::cout << __FILE__ << ":" << __LINE__<< "hdevice == nullptr :" << ((m_apiContainer->hDevice == nullptr) ? "true" : "false") << std::endl; - - std::future cullingFuture; - std::future updateFuture; - logExecution - if (m_supportThreads) { - cullingFuture = cullingFinished.get_future(); - logExecution - nextDeltaTime[getNextPromiseInd()] = std::promise(); - logExecution - nextDeltaTime[getPromiseInd()].set_value(1.0f); - //std::cout << "set new nextDeltaTime value for " << getPromiseInd() << "frame " << std::endl; - //std::cout << "set new nextDeltaTime promise for " << getNextPromiseInd() << "frame " << std::endl; - logExecution - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - logExecution - nextDeltaTimeForUpdate[getNextPromiseInd()] = std::promise(); - logExecution - nextDeltaTimeForUpdate[getPromiseInd()].set_value(1.0f); - - //std::cout << "set new nextDeltaTime value for " << getPromiseInd() << "frame " << std::endl; - //std::cout << "set new nextDeltaTimeForUpdate promise for " << getNextPromiseInd() << "frame " << std::endl; - logExecution - updateFuture = updateFinished.get_future(); - logExecution - } - } - - //if (frameScenario == nullptr) return; - -// if (needToDropCache) { -// if (cacheStorage) { -// cacheStorage->actuallDropCache(); -// } -// needToDropCache = false; -// } - - - m_apiContainer->hDevice->reset(); - logExecution - int currentFrame = m_apiContainer->hDevice->getDrawFrameNumber(); - auto thisFrameScenario = m_frameScenarios[currentFrame]; - logExecution - m_frameScenarios[currentFrame] = frameScenario; - logExecution - if (!m_supportThreads) { - processCaches(10); - DoCulling(); - } - logExecution - m_apiContainer->hDevice->beginFrame(); - if (thisFrameScenario != nullptr && !m_apiContainer->hDevice->getIsVulkanAxisSystem()) { - drawStageAndDepsCNT.beginMeasurement(); - - m_apiContainer->hDevice->drawStageAndDeps(thisFrameScenario->getDrawStage()); - - drawStageAndDepsCNT.endMeasurement(); - } - logExecution - - m_apiContainer->hDevice->commitFrame(); - logExecution - m_apiContainer->hDevice->reset(); - logExecution - if (!m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - logExecution - updateTimePerFrame.beginMeasurement(); - DoUpdate(); - updateTimePerFrame.endMeasurement(); - logExecution - } - logExecution - - if (m_supportThreads) { - cullingFuture.wait(); - logExecution - cullingFinished = std::promise(); - logExecution - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - updateFuture.wait(); - logExecution - updateFinished = std::promise(); - logExecution - } - } - - logExecution - m_apiContainer->hDevice->increaseFrameNumber(); - logExecution -} diff --git a/wowViewerLib/src/engine/SceneComposer.h b/wowViewerLib/src/engine/SceneComposer.h deleted file mode 100644 index ede01aea8..000000000 --- a/wowViewerLib/src/engine/SceneComposer.h +++ /dev/null @@ -1,95 +0,0 @@ -// -// Created by deamon on 15.01.20. -// - -#ifndef AWEBWOWVIEWERCPP_SCENECOMPOSER_H -#define AWEBWOWVIEWERCPP_SCENECOMPOSER_H - - -#include -#include -#include "../include/iostuff.h" -#include "../gapi/interface/IDevice.h" -#include "SceneScenario.h" -#include "algorithms/FrameCounter.h" - -class SceneComposer { -private: - HApiContainer m_apiContainer = nullptr; - -private: - - - std::thread cullingThread; - std::thread updateThread; - std::thread loadingResourcesThread; - - bool m_supportThreads = true; - bool m_isTerminating = false; - - FrameCounter submitDrawCommands; - FrameCounter updateTimePerFrame; - - - FrameCounter startUpdateForNexFrame; - FrameCounter singleUpdateCNT; - FrameCounter produceDrawStage; - FrameCounter meshesCollectCNT; - FrameCounter updateBuffersCNT; - FrameCounter updateBuffersDeviceCNT; - FrameCounter postLoadCNT; - FrameCounter textureUploadCNT; - FrameCounter drawStageAndDepsCNT; - FrameCounter endUpdateCNT; - - - - void DoCulling(); - void DoUpdate(); - void processCaches(int limit); - - //Flip-flop delta promises - std::array,2> nextDeltaTime; - std::array,2> nextDeltaTimeForUpdate; - std::promise cullingFinished; - std::promise updateFinished; - - std::array m_frameScenarios; - - int getPromiseInd() { - auto frameNum = m_apiContainer->hDevice->getFrameNumber(); - auto promiseInd = frameNum & 1; - return promiseInd; - } - int getNextPromiseInd() { - auto frameNum = m_apiContainer->hDevice->getFrameNumber(); - auto promiseInd = (frameNum + 1) & 1; - return promiseInd; - } -public: - SceneComposer(HApiContainer apiContainer); - ~SceneComposer() { - m_isTerminating = true; - auto promiseInd = getPromiseInd(); - try { - float delta = 1.0f; - nextDeltaTime[promiseInd].set_value(delta); - } catch (...) {} - - cullingThread.join(); - - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - try { - nextDeltaTimeForUpdate[promiseInd].set_value(1.0f); - } catch (...) {} - updateThread.join(); - } - - loadingResourcesThread.join(); - } - - void draw(HFrameScenario frameScenario); -}; - - -#endif //AWEBWOWVIEWERCPP_SCENECOMPOSER_H diff --git a/wowViewerLib/src/engine/SceneScenario.cpp b/wowViewerLib/src/engine/SceneScenario.cpp deleted file mode 100644 index c07b80ad9..000000000 --- a/wowViewerLib/src/engine/SceneScenario.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Created by deamon on 30.01.20. -// - -#include "SceneScenario.h" - -HCullStage FrameScenario::addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene, mathfu::vec3 deltas) { - HCullStage newCullStage = std::make_shared(); - newCullStage->matricesForCulling = matricesForCulling; - newCullStage->scene = scene; - newCullStage->deltaX = deltas[0]; - newCullStage->deltaY = deltas[1]; - newCullStage->deltaZ = deltas[2]; - - cullStages.push_back(newCullStage); - - return newCullStage; -} - -HUpdateStage -FrameScenario::addUpdateStage(HCullStage &cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate) { - HUpdateStage newUpdateStage = std::make_shared(); - - newUpdateStage->cullResult = cullStage; - newUpdateStage->delta = deltaTime; - newUpdateStage->cameraMatrices = matricesForUpdate; - - updateStages.push_back(newUpdateStage); - - return newUpdateStage; -} - -HDrawStage FrameScenario::getDrawStage() { - return lastDrawStage; -} - -//FrameScenario::addDrawStage(std::shared_ptr, std::shared_ptr, std::shared_ptr, std::vector, std::allocator>> const&, bool, ViewPortDimensions const&, bool, mathfu::Vector const&, std::shared_ptr) -//FrameScenario::addDrawStage(std::shared_ptr, std::shared_ptr, std::shared_ptr, std::__debug::vector, std::allocator>> const&, bool, ViewPortDimensions const&, bool, mathfu::Vector const&, std::shared_ptr) -HDrawStage FrameScenario::addDrawStage(std::vector &updateStages, HScene scene, HCameraMatrices matricesForDrawing, - std::vector const &drawStageDependencies, bool setViewPort, - ViewPortDimensions const &viewPortDimensions, bool clearScreen, bool invertedZ, - mathfu::vec4 const &clearColor, HFrameBuffer fbTarget) { - HDrawStage drawStage = std::make_shared(); - - drawStage->drawStageDependencies = drawStageDependencies; - drawStage->matricesForRendering = matricesForDrawing; - drawStage->setViewPort = setViewPort; - drawStage->viewPortDimensions = viewPortDimensions; - drawStage->clearScreen = clearScreen; - drawStage->clearColor = clearColor; - drawStage->invertedZ = invertedZ; - drawStage->target = fbTarget; - -// drawStage->sceneWideBlockVSPSChunk; - - drawStageLinks.push_back({scene, updateStages, drawStage}); - - this->lastDrawStage = drawStage; - - return drawStage; -} - diff --git a/wowViewerLib/src/engine/SceneScenario.h b/wowViewerLib/src/engine/SceneScenario.h deleted file mode 100644 index 571c1577e..000000000 --- a/wowViewerLib/src/engine/SceneScenario.h +++ /dev/null @@ -1,100 +0,0 @@ -// -// Created by deamon on 15.01.20. -// - -#ifndef AWEBWOWVIEWERCPP_SCENESCENARIO_H -#define AWEBWOWVIEWERCPP_SCENESCENARIO_H - -#include - -class IScene; -typedef std::shared_ptr HScene; -struct CameraMatrices; -struct CullStage; -struct UpdateStage; - -//Holds dependency graph for different scenes -class FrameScenario; - - -#include -#include "../gapi/interface/IDevice.h" -#include "../gapi/interface/meshes/IMesh.h" -#include "objects/ViewsObjects.h" -#include "camera/CameraInterface.h" -#include "DrawStage.h" -#include "objects/wmo/wmoObject.h" - - -struct FrameInputParams { - HCameraMatrices matricesForCulling; - HCameraMatrices cameraMatricesForRendering; - HCameraMatrices cameraMatricesForDebugCamera; - HScene scene; - - //Just for proper BoundingBox calculus - float deltaX = 0.0f; - float deltaY = 0.0f; - float deltaZ = 0.0f; - - //Time advance - animTime_t delta; - - //Parameters for framebuffer - ViewPortDimensions viewPortDimensions; - bool invertedZ = false; - bool clearScreen = false; -}; - -struct MapRenderPlan { - int adtAreadId = -1; - int areaId = -1; - int parentAreaId = -1; - - //Result of culling test - std::vector m_currentInteriorGroups = {}; - bool currentWmoGroupIsExtLit = false; - bool currentWmoGroupShowExtSkybox = false; - std::shared_ptr m_currentWMO = nullptr; - int m_currentWmoGroup = -1; - - FrameViewsHolder viewsHolder; - - HFrameDepedantData frameDependentData = std::make_shared(); - - //Objects for update and rendering - std::vector> adtArray = {}; - M2ObjectListContainer m2Array; - WMOListContainer wmoArray; - WMOGroupListContainer wmoGroupArray; - - //Settings for the frame -}; - -class SceneComposer; - -#include "objects/iScene.h" - -class FrameScenario { - friend class SceneComposer; -private: - -public: - HCullStage addCullStage(HCameraMatrices matricesForCulling, std::shared_ptr scene, mathfu::vec3 deltas = {0,0,0}); - HUpdateStage addUpdateStage(HCullStage &cullStage, animTime_t deltaTime, HCameraMatrices matricesForUpdate); - - HDrawStage addDrawStage(std::vector &updateStage, - HScene scene, - HCameraMatrices matricesForDrawing, - std::vector const &drawStageDependencies, - bool setViewPort, - ViewPortDimensions const &viewPortDimensions, - bool clearScreen, bool invertedZ, - mathfu::vec4 const &clearColor, HFrameBuffer fbTarget); - - HDrawStage getDrawStage(); -}; -typedef std::shared_ptr HFrameScenario; - - -#endif //AWEBWOWVIEWERCPP_SCENESCENARIO_H diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index 72e69dd82..3804a36de 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -10,7 +10,10 @@ #include #include -#define toRadian(x) (float) ((float) (x) * ((float)M_PI/ (float)180.0)) +template +inline constexpr T toRadian(T x) { + return (x * M_PI) / 180.0; +} template inline const CAaBox &retrieveAABB(T &object); @@ -32,6 +35,7 @@ class MathHelper { mathfu::mat4 perspectiveMat; mathfu::mat4 viewMat; mathfu::vec4 farPlane; + mathfu::vec3 cameraPos; std::vector frustums; } FrustumCullingData; diff --git a/wowViewerLib/src/engine/engineClassList.h b/wowViewerLib/src/engine/engineClassList.h index 8f7a12e4d..d04240fd0 100644 --- a/wowViewerLib/src/engine/engineClassList.h +++ b/wowViewerLib/src/engine/engineClassList.h @@ -8,6 +8,7 @@ class AdtObject; class M2Object; class WmoObject; +class WmoGroupGeom; class AnimationManager; struct M2SkinProfile; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 90cbac774..32fa572ed 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -148,7 +148,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat auto blendMode = meshTemplate.blendMode; auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; - meshTemplate.ubo[4]->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + meshTemplate.ubo[4]->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { Ribbon::meshRibbonWideBlockPS& blockPS = self->getObject(); blockPS.uAlphaTest = -1.0f; @@ -866,39 +866,39 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { - auto &currFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; - if (currFrame.isDead) return; - - for (int i = 0; i < currFrame.m_meshes.size(); i++) { - auto mesh = currFrame.m_meshes[i]; - - mesh->setRenderOrder(renderOrder); - if (mesh->getIsTransparent()) { - transparentMeshes.push_back(mesh); - } else { - opaqueMeshes.push_back(mesh); - } - } +// auto &currFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; +// if (currFrame.isDead) return; +// +// for (int i = 0; i < currFrame.m_meshes.size(); i++) { +// auto mesh = currFrame.m_meshes[i]; +// +// mesh->setRenderOrder(renderOrder); +// if (mesh->getIsTransparent()) { +// transparentMeshes.push_back(mesh); +// } else { +// opaqueMeshes.push_back(mesh); +// } +// } } void CRibbonEmitter::updateBuffers() { // return; - - auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; - currentFrame.isDead = this->IsDead(); - if (currentFrame.isDead) return; - - currentFrame.m_indexVBO->uploadData((void *) m_gxIndices.data(), (int) (m_gxIndices.size() * sizeof(uint16_t))); - currentFrame.m_bufferVBO->uploadData((void *) m_gxVertices.data(), (int) (m_gxVertices.size() * sizeof(CRibbonVertex))); - - int indexCount = m_writePos > m_readPos ? - 2 *(m_writePos - m_readPos) + 2: - 2 *((int)m_edges.size() + m_writePos - m_readPos) + 2; - for (auto mesh : currentFrame.m_meshes) { - mesh->setStart(2 * m_readPos * sizeof(uint16_t)); - mesh->setEnd(indexCount); - mesh->setSortDistance(0); - mesh->setPriorityPlane(this->m_priority); - } +// +// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; +// currentFrame.isDead = this->IsDead(); +// if (currentFrame.isDead) return; +// +// currentFrame.m_indexVBO->uploadData((void *) m_gxIndices.data(), (int) (m_gxIndices.size() * sizeof(uint16_t))); +// currentFrame.m_bufferVBO->uploadData((void *) m_gxVertices.data(), (int) (m_gxVertices.size() * sizeof(CRibbonVertex))); +// +// int indexCount = m_writePos > m_readPos ? +// 2 *(m_writePos - m_readPos) + 2: +// 2 *((int)m_edges.size() + m_writePos - m_readPos) + 2; +// for (auto mesh : currentFrame.m_meshes) { +// mesh->setStart(2 * m_readPos * sizeof(uint16_t)); +// mesh->setEnd(indexCount); +// mesh->setSortDistance(0); +// mesh->setPriorityPlane(this->m_priority); +// } } \ No newline at end of file diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 529bfad8d..6e3e090c6 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -347,7 +347,7 @@ void ParticleEmitter::createMesh() { meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(Particle::meshParticleWideBlockPS)); auto l_blendMode = meshTemplate.blendMode; - meshTemplate.ubo[4]->setUpdateHandler([this, l_blendMode](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + meshTemplate.ubo[4]->setUpdateHandler([this, l_blendMode](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { Particle::meshParticleWideBlockPS &blockPS = self->getObject(); uint8_t blendMode = m_data->old.blendingType; if (blendMode == 0) { @@ -668,7 +668,9 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { this->calculateQuadToViewEtc(nullptr, viewMatrix); // FrameOfRerefence mat is null since it's not used - auto vboBufferDynamic = frame[m_api->hDevice->getUpdateFrameNumber()].m_bufferVBO; +// int frame = m_api->hDevice->getUpdateFrameNumber(); + int frameNum = 0; + auto vboBufferDynamic = frame[frameNum].m_bufferVBO; size_t maxFutureSize = particles.size() * sizeof(ParticleBuffStructQuad); if ((m_data->old.flags & 0x60000) == 0x60000) { maxFutureSize *= 2; @@ -1130,36 +1132,36 @@ ParticleEmitter::BuildQuadT3( } void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { - if (getGenerator() == nullptr) return; - - auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; - if (!currentFrame.active) - return; - - HGParticleMesh mesh = frame[m_api->hDevice->getUpdateFrameNumber()].m_mesh; - mesh->setRenderOrder(renderOrder); - if (mesh->getIsTransparent()) { - transparentMeshes.push_back(mesh); - } else { - opaqueMeshes.push_back(mesh); - } +// if (getGenerator() == nullptr) return; +// +// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; +// if (!currentFrame.active) +// return; +// +// HGParticleMesh mesh = frame[m_api->hDevice->getUpdateFrameNumber()].m_mesh; +// mesh->setRenderOrder(renderOrder); +// if (mesh->getIsTransparent()) { +// transparentMeshes.push_back(mesh); +// } else { +// opaqueMeshes.push_back(mesh); +// } } void ParticleEmitter::updateBuffers() { - if (getGenerator() == nullptr) return; - - auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; - currentFrame.active = szVertexCnt > 0; - - if (!currentFrame.active) - return; - -// currentFrame.m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); - currentFrame.m_bufferVBO->save(szVertexCnt * sizeof(ParticleBuffStructQuad)); - - currentFrame.m_mesh->setEnd(szVertexCnt * 6); - currentFrame.m_mesh->setSortDistance(m_currentBonePos); - currentFrame.m_mesh->setPriorityPlane(m_data->old.textureTileRotation); +// if (getGenerator() == nullptr) return; +// +// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; +// currentFrame.active = szVertexCnt > 0; +// +// if (!currentFrame.active) +// return; +// +//// currentFrame.m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); +// currentFrame.m_bufferVBO->save(szVertexCnt * sizeof(ParticleBuffStructQuad)); +// +// currentFrame.m_mesh->setEnd(szVertexCnt * 6); +// currentFrame.m_mesh->setSortDistance(m_currentBonePos); +// currentFrame.m_mesh->setPriorityPlane(m_data->old.textureTileRotation); } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index bb6acc45d..138212dd1 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -168,7 +168,7 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st meshTemplate.ubo[3] = nullptr; meshTemplate.ubo[4] = hDevice->createUniformBufferChunk(sizeof(DrawPortalShader::meshWideBlockPS)); - meshTemplate.ubo[4]->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + meshTemplate.ubo[4]->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { auto& blockPS = self->getObject(); blockPS.uColor = {0.058, 0.058, 0.819607843, 0.3}; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 051f56000..2f98d45a8 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -373,11 +373,11 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.ubo[1]->setUpdateHandler([](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData ) -> void { + meshTemplate.ubo[1]->setUpdateHandler([](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData ) -> void { mathfu::mat4 &placementMat = self->getObject(); placementMat = mathfu::mat4::Identity(); }); - meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, l_liquidObjectType, color, liquidFlags, minimapStaticCol, closeRiverColor](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData) -> void { + meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, l_liquidObjectType, color, liquidFlags, minimapStaticCol, closeRiverColor](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) -> void { mathfu::vec4_packed &color_ = self->getObject(); if (!frameDepedantData->useMinimapWaterColor) { if ((liquidFlags & 1024) > 0) {// Ocean @@ -632,7 +632,7 @@ void AdtObject::createMeshes() { int useHeightMixFormula = m_wdtFile->mphd->flags.adt_has_height_texturing > 0; // int useHeightMixFormula = 1; auto api = m_api; - adtWideBlockPS->setUpdateHandler([api, useHeightMixFormula](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + adtWideBlockPS->setUpdateHandler([api, useHeightMixFormula](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ auto *adtWideblockPS = &self->getObject(); adtWideblockPS->useHeightMixFormula[0] = useHeightMixFormula; }); @@ -668,7 +668,7 @@ void AdtObject::createMeshes() { aTemplate.texture = std::vector(aTemplate.textureCount, nullptr); int chunkIndex = i; - aTemplate.ubo[4]->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + aTemplate.ubo[4]->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { auto &blockPS = self->getObject(); for (int j = 0; j < 4; j++) { @@ -687,7 +687,7 @@ void AdtObject::createMeshes() { } }); - aTemplate.ubo[2]->setUpdateHandler([this, i](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + aTemplate.ubo[2]->setUpdateHandler([this, i](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { auto &blockVS = self->getObject(); blockVS.uPos = mathfu::vec4( this->m_adtFile->mapTile[i].position.x, diff --git a/wowViewerLib/src/engine/objects/iScene.cpp b/wowViewerLib/src/engine/objects/iScene.cpp index 419882c8d..23d4097d6 100644 --- a/wowViewerLib/src/engine/objects/iScene.cpp +++ b/wowViewerLib/src/engine/objects/iScene.cpp @@ -1,4 +1,3 @@ -#include "../DrawStage.h" #include "iScene.h" IScene::~IScene() { diff --git a/wowViewerLib/src/engine/objects/iScene.h b/wowViewerLib/src/engine/objects/iScene.h index c41819bcb..171c06158 100644 --- a/wowViewerLib/src/engine/objects/iScene.h +++ b/wowViewerLib/src/engine/objects/iScene.h @@ -5,39 +5,12 @@ #ifndef WEBWOWVIEWERCPP_IINNERSCENEAPI_H #define WEBWOWVIEWERCPP_IINNERSCENEAPI_H -#include "mathfu/glsl_mappings.h" -#include "../persistance/header/M2FileHeader.h" -#include "../DrawStage.h" -#include "../SceneScenario.h" -#include "../../exporters/IExporter.h" +#include class IScene { public: virtual ~IScene() = 0; - virtual void setReplaceTextureArray(std::vector &replaceTextureArray) = 0; - virtual void setMeshIdArray(std::vector &meshIds) = 0; - virtual void setReplaceParticleColors(std::array, 3> &particleColorReplacement) {}; - virtual void resetReplaceParticleColor() {}; - - virtual void setAnimationId(int animationId) = 0; - virtual void setMeshIds(std::vector &meshIds) = 0; - virtual void resetAnimation() = 0; - - virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStage) = 0; - virtual void produceUpdateStage(HUpdateStage &updateStage) = 0; - - virtual void checkCulling(HCullStage &cullStage) = 0; - - virtual void doPostLoad(HCullStage &cullStage) = 0; - virtual void updateBuffers(HUpdateStage &updateStage) = 0; - - virtual int getCameraNum() = 0; - virtual std::shared_ptr createCamera(int cameraNum) = 0; - - virtual void exportScene(IExporter * exporter) {}; - - virtual void setAdtConfig(HADTRenderConfigDataHolder &adtConfig) {}; - virtual void setMandatoryADTs(std::vector> &mandatoryADTs) {}; - virtual void getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAreaId) {}; }; +typedef std::shared_ptr HScene; + #endif //WEBWOWVIEWERCPP_IINNERSCENEAPI_H diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index c59463e4a..5f0d5fb81 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -7,8 +7,6 @@ #include #include "m2/m2Object.h" -#include "../../gapi/interface/IDevice.h" - #include "../engineClassList.h" #include diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index ee9319bb4..79849e770 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -27,7 +27,7 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object int batchIndex = materialData.batchIndex; auto vertexShader = materialData.vertexShader; - hmesh->getUniformBuffer(2)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, vertexShader](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + hmesh->getUniformBuffer(2)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, vertexShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ auto m2Data = m2Object->m_m2Geom->getM2Data(); auto batch = m2SkinProfile->batches[batchIndex]; @@ -50,7 +50,7 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object //3. Update individual PS buffer auto pixelShader = materialData.pixelShader; - hmesh->getUniformBuffer(4)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, pixelShader](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + hmesh->getUniformBuffer(4)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, pixelShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { auto m2Data = m2Object->m_m2Geom->getM2Data(); auto batch = m2SkinProfile->batches[batchIndex]; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 10c76c7ce..4091eb9e7 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1279,7 +1279,7 @@ void M2Object::createBoundingBoxMesh() { meshTemplate.ubo[4] = nullptr; auto l_m2Geom = m_m2Geom; - bbBlockVS->setUpdateHandler([this, l_m2Geom](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + bbBlockVS->setUpdateHandler([this, l_m2Geom](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ M2Data *m2Data = l_m2Geom->getM2Data(); CAaBox &aaBox = m2Data->bounding_box; @@ -1388,7 +1388,7 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshTemplate.ubo[1] = vertexModelWideUniformBuffer; meshTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::WaterfallData::meshWideBlockVS)); - meshTemplate.ubo[2]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + meshTemplate.ubo[2]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ auto &meshblockVS = self->getObject(); meshblockVS.bumpScale = mathfu::vec4(wfv3Data->bumpScale, 0, 0, 0); @@ -1397,7 +1397,7 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshTemplate.ubo[3] = nullptr; meshTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::WaterfallData::meshWideBlockPS)); - meshTemplate.ubo[4]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + meshTemplate.ubo[4]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ auto &meshblockPS = self->getObject(); meshblockPS.baseColor = mathfu::vec4( wfv3Data->basecolor.a / 255.0f, @@ -1628,7 +1628,9 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorhDevice->getUpdateFrameNumber()].m_mesh; +// int frame = m_api->hDevice->getUpdateFrameNumber(); + int frame = 0; + HGParticleMesh mesh = dynMesh[frame].m_mesh; mesh->setRenderOrder(renderOrder); if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); @@ -1923,7 +1925,7 @@ void M2Object::createVertexBindings() { vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockVS), (m_m2Geom->m_m2Data->bones.size + 1) * sizeof(mathfu::mat4)); fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockPS)); - vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ auto &blockVS = self->getObject(); blockVS.uPlacementMat = m_placementMatrix; @@ -1931,7 +1933,7 @@ void M2Object::createVertexBindings() { std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, blockVS.uBoneMatrixes); }); - fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); mathfu::vec4 localDiffuse = diffuseNon; @@ -1964,7 +1966,8 @@ void M2Object::createVertexBindings() { void M2Object::updateDynamicMeshes() { auto rootMatInverse = bonesMatrices[0].Inverse(); - auto frameNum = m_api->hDevice->getUpdateFrameNumber(); +// auto frameNum = m_api->hDevice->getUpdateFrameNumber(); + int frameNum = 0; for (auto &dynamicMesh: dynamicMeshes) { auto &dynMeshData = dynamicMesh[frameNum]; @@ -2000,11 +2003,6 @@ void M2Object::updateDynamicMeshes() { overrideVert.bone_indices[1] = 0; overrideVert.bone_indices[2] = 0; overrideVert.bone_indices[3] = 0; - -// overrideVert.bone_weights[0] = 1; -// overrideVert.bone_weights[1] = 0; -// overrideVert.bone_weights[2] = 0; -// overrideVert.bone_weights[3] = 0; } dynMeshData.m_bufferVBO->save(skinSection->vertexCount*sizeof(M2Vertex)); diff --git a/wowViewerLib/src/engine/objects/scenes/NullScene.h b/wowViewerLib/src/engine/objects/scenes/NullScene.h index 1f01814fb..0745ebeee 100644 --- a/wowViewerLib/src/engine/objects/scenes/NullScene.h +++ b/wowViewerLib/src/engine/objects/scenes/NullScene.h @@ -10,23 +10,6 @@ class NullScene : public IScene { public: ~NullScene() override {} - virtual void setReplaceTextureArray(std::vector &replaceTextureArray) override {}; - virtual void setMeshIdArray(std::vector &meshIds) override {}; - virtual void setAnimationId(int animationId) override {}; - virtual void setMeshIds(std::vector &meshIds) override {}; - virtual void produceUpdateStage(HUpdateStage &updateStage) override {}; - virtual void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override { - resultDrawStage->transparentMeshes = std::make_shared(); - resultDrawStage->opaqueMeshes = std::make_shared(); - }; - - virtual void checkCulling(HCullStage &cullStage) override {}; - - virtual void doPostLoad(HCullStage &cullStage) override {}; - virtual void updateBuffers(HUpdateStage &updateStage) override {}; - virtual void resetAnimation() override {}; - virtual int getCameraNum() override {return 0;}; - virtual std::shared_ptr createCamera(int cameraNum) override { return nullptr;}; }; #endif //AWEBWOWVIEWERCPP_NULLSCENE_H diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 67618deca..ba38b80e1 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -11,7 +11,7 @@ void M2Scene::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { potentialM2.addCandidate(m_m2Object); @@ -19,23 +19,24 @@ void M2Scene::getPotentialEntities(const MathHelper::FrustumCullingData &frustum void M2Scene::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { m2ObjectsCandidates.addCandidate(m_m2Object); } -void M2Scene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, - StateForConditions &stateForConditions, const AreaRecord &areaRecord) { +void M2Scene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, + MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, const AreaRecord &areaRecord) { Config* config = this->m_api->getConfig(); - Map::updateLightAndSkyboxData(cullStage, cameraVec3, stateForConditions, areaRecord); + Map::updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); if (config->globalLighting == EParameterSource::eM2) { auto ambient = m_m2Object->getM2SceneAmbientLight(); if (ambient.Length() < 0.0001) ambient = mathfu::vec4(1.0,1.0,1.0,1.0); - auto frameDepedantData = cullStage->frameDependentData; + auto frameDepedantData = mapRenderPlan->frameDependentData; frameDepedantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); frameDepedantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); @@ -43,7 +44,7 @@ void M2Scene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 frameDepedantData->exteriorDirectColor = mathfu::vec4(0.0,0.0,0.0,0.0); frameDepedantData->exteriorDirectColorDir = mathfu::vec3(0.0,0.0,0.0); } - auto frameDepedantData = cullStage->frameDependentData; + auto frameDepedantData = mapRenderPlan->frameDependentData; frameDepedantData->FogDataFound = false; } @@ -53,10 +54,6 @@ extern "C" { extern void offerFileAsDownload(std::string filename, std::string mime); } -void M2Scene::doPostLoad(HCullStage &cullStage) { - Map::doPostLoad(cullStage); -} - void M2Scene::setReplaceTextureArray(std::vector &replaceTextureArray) { //std::cout << "replaceTextureArray.size == " << replaceTextureArray.size() << std::endl; //std::cout << "m_m2Object == " << m_m2Object << std::endl; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index f8ad2a5a1..03590f8d0 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -8,6 +8,7 @@ #include "map.h" #include "../m2/m2Object.h" +#include "../../../exporters/IExporter.h" class M2Scene : public Map { private: @@ -16,18 +17,19 @@ class M2Scene : public Map { void getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) override; void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) override; - void updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, - StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; + void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, + MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; public: explicit M2Scene(HApiContainer api, std::string m2Model); @@ -38,26 +40,15 @@ class M2Scene : public Map { } - void setAnimationId(int animationId) override { - m_m2Object->setAnimationId(animationId); - }; - void setMeshIds(std::vector &meshIds) override { - m_m2Object->setMeshIds(meshIds); - }; - void resetAnimation() override { - m_m2Object->resetCurrentAnimation(); - } - - void setReplaceTextureArray(std::vector &replaceTextureArray) override; - void setMeshIdArray(std::vector &meshIds) override ; - void setReplaceParticleColors(std::array, 3> &particleColorReplacement) override; - void resetReplaceParticleColor() override; - void doPostLoad(HCullStage &cullStage) override; + void setReplaceTextureArray(std::vector &replaceTextureArray) ; + void setMeshIdArray(std::vector &meshIds) ; + void setReplaceParticleColors(std::array, 3> &particleColorReplacement) ; + void resetReplaceParticleColor() ; - int getCameraNum() override ; - std::shared_ptr createCamera(int cameraNum) override; - void exportScene(IExporter* exporter) override; + int getCameraNum() ; + std::shared_ptr createCamera(int cameraNum); + void exportScene(IExporter* exporter); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f8c2fda23..44334f98c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -22,8 +22,6 @@ #endif #include "../../algorithms/mathHelper_culling.h" -//#include "../../algorithms/quicksort-dualpivot.h" - static GBufferBinding fullScreen[1] = { {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, }; @@ -309,7 +307,7 @@ Map::Map(HApiContainer api, int mapId, std::string mapName) { HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config *config, bool conusFor0x4Sky) { auto skyVs = device->createUniformBufferChunk(sizeof(DnSky::meshWideBlockVS)); - skyVs->setUpdateHandler([config, conusFor0x4Sky](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { + skyVs->setUpdateHandler([config, conusFor0x4Sky](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { auto &meshblockVS = self->getObject(); if (!conusFor0x4Sky) { @@ -368,20 +366,20 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config return hmesh; } -void Map::checkCulling(HCullStage &cullStage) { +void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { // std::cout << "Map::checkCulling finished called" << std::endl; // std::cout << "m_wdtfile->getIsLoaded() = " << m_wdtfile->getIsLoaded() << std::endl; cullCreateVarsCounter.beginMeasurement(); Config* config = this->m_api->getConfig(); - mathfu::vec4 cameraPos = cullStage->matricesForCulling->cameraPos; + mathfu::vec4 cameraPos = frameInputParams.matricesForCulling->cameraPos; mathfu::vec3 cameraVec3 = cameraPos.xyz(); - mathfu::mat4 &frustumMat = cullStage->matricesForCulling->perspectiveMat; - mathfu::mat4 &lookAtMat4 = cullStage->matricesForCulling->lookAtMat; + mathfu::mat4 &frustumMat = frameInputParams.matricesForCulling->perspectiveMat; + mathfu::mat4 &lookAtMat4 = frameInputParams.matricesForCulling->lookAtMat; - size_t adtRenderedThisFramePrev = cullStage->adtArray.size(); - cullStage->adtArray = {}; - cullStage->adtArray.reserve(adtRenderedThisFramePrev); + size_t adtRenderedThisFramePrev = mapRenderPlan->adtArray.size(); + mapRenderPlan->adtArray = {}; + mapRenderPlan->adtArray.reserve(adtRenderedThisFramePrev); mathfu::mat4 viewPerspectiveMat = frustumMat*lookAtMat4; mathfu::vec4 &camera4 = cameraPos; @@ -402,16 +400,17 @@ void Map::checkCulling(HCullStage &cullStage) { frustumData.frustums = {planesUndPoints}; frustumData.perspectiveMat = frustumMat; frustumData.viewMat = lookAtMat4; + frustumData.cameraPos = cameraVec3; frustumData.farPlane = planesUndPoints.planes[planesUndPoints.planes.size() - 2]; //farPlane is always one before last m_viewRenderOrder = 0; - cullStage->m_currentInteriorGroups = {}; - cullStage->m_currentWMO = nullptr; + mapRenderPlan->m_currentInteriorGroups = {}; + mapRenderPlan->m_currentWMO = nullptr; int bspNodeId = -1; int interiorGroupNum = -1; - cullStage->m_currentWmoGroup = -1; + mapRenderPlan->m_currentWmoGroup = -1; //Get potential WMO WMOListContainer potentialWmo; @@ -422,20 +421,20 @@ void Map::checkCulling(HCullStage &cullStage) { cullGetCurrentWMOCounter.beginMeasurement(); //Hack that is needed to get the current WMO the camera is in. Basically it does frustum culling over current ADT - getPotentialEntities(frustumData, cameraPos, cullStage, potentialM2, potentialWmo); + getPotentialEntities(frustumData, cameraPos, mapRenderPlan, potentialM2, potentialWmo); for (auto &checkingWmoObj : potentialWmo.getCandidates()) { WmoGroupResult groupResult; bool result = checkingWmoObj->getGroupWmoThatCameraIsInside(camera4, groupResult); if (result) { - cullStage->m_currentWMO = checkingWmoObj; - cullStage->m_currentWmoGroup = groupResult.groupIndex; + mapRenderPlan->m_currentWMO = checkingWmoObj; + mapRenderPlan->m_currentWmoGroup = groupResult.groupIndex; if (checkingWmoObj->isGroupWmoInterior(groupResult.groupIndex)) { - cullStage->m_currentInteriorGroups.push_back(groupResult); + mapRenderPlan->m_currentInteriorGroups.push_back(groupResult); interiorGroupNum = groupResult.groupIndex; - cullStage->currentWmoGroupIsExtLit = checkingWmoObj->isGroupWmoExteriorLit(groupResult.groupIndex); - cullStage->currentWmoGroupShowExtSkybox = checkingWmoObj->isGroupWmoExtSkybox(groupResult.groupIndex); + mapRenderPlan->currentWmoGroupIsExtLit = checkingWmoObj->isGroupWmoExteriorLit(groupResult.groupIndex); + mapRenderPlan->currentWmoGroupShowExtSkybox = checkingWmoObj->isGroupWmoExtSkybox(groupResult.groupIndex); } else { } bspNodeId = groupResult.nodeId; @@ -450,10 +449,10 @@ void Map::checkCulling(HCullStage &cullStage) { StateForConditions stateForConditions; AreaRecord areaRecord; - if (cullStage->m_currentWMO != nullptr) { - auto nameId = cullStage->m_currentWMO->getNameSet(); - auto wmoId = cullStage->m_currentWMO->getWmoId(); - auto groupId = cullStage->m_currentWMO->getWmoGroupId(cullStage->m_currentWmoGroup); + if (mapRenderPlan->m_currentWMO != nullptr) { + auto nameId = mapRenderPlan->m_currentWMO->getNameSet(); + auto wmoId = mapRenderPlan->m_currentWMO->getWmoId(); + auto groupId = mapRenderPlan->m_currentWMO->getWmoGroupId(mapRenderPlan->m_currentWmoGroup); if (m_api->databaseHandler != nullptr) { areaRecord = m_api->databaseHandler->getWmoArea(wmoId, nameId, groupId); @@ -461,8 +460,8 @@ void Map::checkCulling(HCullStage &cullStage) { } if (areaRecord.areaId == 0) { - if (cullStage->adtAreadId > 0 && (m_api->databaseHandler != nullptr)) { - areaRecord = m_api->databaseHandler->getArea(cullStage->adtAreadId); + if (mapRenderPlan->adtAreadId > 0 && (m_api->databaseHandler != nullptr)) { + areaRecord = m_api->databaseHandler->getArea(mapRenderPlan->adtAreadId); } } @@ -471,58 +470,58 @@ void Map::checkCulling(HCullStage &cullStage) { stateForConditions.currentAreaId = areaRecord.areaId; stateForConditions.currentParentAreaId = areaRecord.parentAreaId; - cullStage->areaId = areaRecord.areaId; - cullStage->parentAreaId = areaRecord.parentAreaId; + mapRenderPlan->areaId = areaRecord.areaId; + mapRenderPlan->parentAreaId = areaRecord.parentAreaId; cullGetCurrentZoneCounter.endMeasurement(); //Get lights from DB cullUpdateLightsFromDBCounter.beginMeasurement(); - updateLightAndSkyboxData(cullStage, cameraVec3, stateForConditions, areaRecord); + updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); cullUpdateLightsFromDBCounter.endMeasurement(); ///----------------------------------- - auto lcurrentWMO = cullStage->m_currentWMO; - auto currentWmoGroup = cullStage->m_currentWmoGroup; + auto lcurrentWMO = mapRenderPlan->m_currentWMO; + auto currentWmoGroup = mapRenderPlan->m_currentWmoGroup; - if ((lcurrentWMO != nullptr) && (!cullStage->m_currentInteriorGroups.empty()) && (lcurrentWMO->isLoaded())) { + if ((lcurrentWMO != nullptr) && (!mapRenderPlan->m_currentInteriorGroups.empty()) && (lcurrentWMO->isLoaded())) { if (lcurrentWMO->startTraversingWMOGroup( cameraPos, frustumData, - cullStage->m_currentInteriorGroups[0].groupIndex, + mapRenderPlan->m_currentInteriorGroups[0].groupIndex, 0, m_viewRenderOrder, true, - cullStage->viewsHolder)) { - cullStage->wmoArray.addCand(cullStage->m_currentWMO); + mapRenderPlan->viewsHolder)) { + mapRenderPlan->wmoArray.addCand(mapRenderPlan->m_currentWMO); } cullExterior.beginMeasurement(); - auto exterior = cullStage->viewsHolder.getExterior(); + auto exterior = mapRenderPlan->viewsHolder.getExterior(); if ( exterior != nullptr ) { //Fix FrustumData for exterior was created after WMO traversal. So we need to fix it exterior->frustumData.perspectiveMat = frustumData.perspectiveMat; exterior->frustumData.viewMat = frustumData.viewMat; exterior->frustumData.farPlane = frustumData.farPlane; - checkExterior(cameraPos, exterior->frustumData, m_viewRenderOrder, cullStage); + checkExterior(cameraPos, exterior->frustumData, m_viewRenderOrder, mapRenderPlan); } cullExterior.endMeasurement(); } else { //Cull exterior cullExterior.beginMeasurement(); - auto exteriorView = cullStage->viewsHolder.getOrCreateExterior(frustumData); - checkExterior(cameraPos, exteriorView->frustumData, m_viewRenderOrder, cullStage); + auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); + checkExterior(cameraPos, exteriorView->frustumData, m_viewRenderOrder, mapRenderPlan); cullExterior.endMeasurement(); } cullSkyDoms.beginMeasurement(); - if ((cullStage->viewsHolder.getExterior() != nullptr || cullStage->currentWmoGroupIsExtLit || cullStage->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { - auto exteriorView = cullStage->viewsHolder.getOrCreateExterior(frustumData); + if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { + auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); if (m_wdlObject != nullptr) { m_wdlObject->checkSkyScenes( @@ -544,7 +543,7 @@ void Map::checkCulling(HCullStage &cullStage) { cullCombineAllObjects.beginMeasurement(); { - auto exteriorView = cullStage->viewsHolder.getExterior(); + auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); if (exteriorView != nullptr) { exteriorView->addM2FromGroups(frustumData, cameraPos); for (auto &adtRes: exteriorView->drawnADTs) { @@ -552,19 +551,19 @@ void Map::checkCulling(HCullStage &cullStage) { exteriorView->m_transparentMeshes, exteriorView->renderOrder); } - cullStage->m2Array.addDrawnAndToLoad(exteriorView->m2List); - cullStage->wmoGroupArray.addToLoadAndDraw(exteriorView->wmoGroupArray); + mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); + mapRenderPlan->wmoGroupArray.addToLoadAndDraw(exteriorView->wmoGroupArray); } } //Fill and collect M2 objects for views from WmoGroups { - auto &interiorViews = cullStage->viewsHolder.getInteriorViews(); + auto &interiorViews = mapRenderPlan->viewsHolder.getInteriorViews(); for (auto &interiorView: interiorViews) { interiorView->addM2FromGroups(frustumData, cameraPos); - cullStage->m2Array.addDrawnAndToLoad(interiorView->m2List); - cullStage->wmoGroupArray.addToLoadAndDraw(interiorView->wmoGroupArray); + mapRenderPlan->m2Array.addDrawnAndToLoad(interiorView->m2List); + mapRenderPlan->wmoGroupArray.addToLoadAndDraw(interiorView->wmoGroupArray); } } @@ -599,7 +598,7 @@ mathfu::vec3 blendV3(mathfu::vec3 a, mathfu::vec3 b, float alpha) { return (a - b) * alpha + a; } -void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, +void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) {///----------------------------------- Config* config = this->m_api->getConfig(); @@ -607,14 +606,14 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca mathfu::vec3 endFogColor = mathfu::vec3(0.0, 0.0, 0.0); std::vector wmoFogs = {}; - if (cullStage->m_currentWMO != nullptr) { - cullStage->m_currentWMO->checkFog(cameraVec3, wmoFogs); + if (mapRenderPlan->m_currentWMO != nullptr) { + mapRenderPlan->m_currentWMO->checkFog(frustumData.cameraPos, wmoFogs); } std::vector lightResults; if ((m_api->databaseHandler != nullptr)) { //Check zoneLight - getLightResultsFromDB(cameraVec3, config, lightResults, &stateForConditions); + getLightResultsFromDB(frustumData.cameraPos, config, lightResults, &stateForConditions); //Delete skyboxes that are not in light array std::unordered_map> perFdidMap; @@ -658,7 +657,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca skyBox->setAlpha(_light.blendCoef); if ((_light.skyBoxFlags & 4) > 0 ) { //In this case conus is still rendered been, but all values are final fog values. - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->overrideValuesWithFinalFog = true; } @@ -718,16 +717,16 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca // horizontAmbientColor *= ambientMult; if (config->glowSource == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->currentGlow = currentGlow; } else if (config->glowSource == EParameterSource::eConfig) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->currentGlow = config->currentGlow; } if (config->globalLighting == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->exteriorAmbientColor = mathfu::vec4(ambientColor[2], ambientColor[1], ambientColor[0], 0); fdd->exteriorGroundAmbientColor = mathfu::vec4(groundAmbientColor[2], groundAmbientColor[1], groundAmbientColor[0], @@ -736,45 +735,45 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca horizontAmbientColor[0], 0); fdd->exteriorDirectColor = mathfu::vec4(directColor[2], directColor[1], directColor[0], 0); auto extDir = MathHelper::calcExteriorColorDir( - cullStage->matricesForCulling->lookAtMat, + frustumData.viewMat, m_api->getConfig()->currentTime ); fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; } else if (config->globalLighting == EParameterSource::eConfig) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->exteriorAmbientColor = config->exteriorAmbientColor; fdd->exteriorGroundAmbientColor = config->exteriorGroundAmbientColor; fdd->exteriorHorizontAmbientColor = config->exteriorHorizontAmbientColor; fdd->exteriorDirectColor = config->exteriorDirectColor; auto extDir = MathHelper::calcExteriorColorDir( - cullStage->matricesForCulling->lookAtMat, + frustumData.viewMat, m_api->getConfig()->currentTime ); fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; } { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->useMinimapWaterColor = config->useMinimapWaterColor; fdd->useCloseRiverColorForDB = config->useCloseRiverColorForDB; } if (config->waterColorParams == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->closeRiverColor = mathfu::vec4(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0], 0); fdd->farRiverColor = mathfu::vec4(farRiverColor[2], farRiverColor[1], farRiverColor[0], 0); fdd->closeOceanColor = mathfu::vec4(closeOceanColor[2], closeOceanColor[1], closeOceanColor[0], 0); fdd->farOceanColor = mathfu::vec4(farOceanColor[2], farOceanColor[1], farOceanColor[0], 0); } else if (config->waterColorParams == EParameterSource::eConfig) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->closeRiverColor = config->closeRiverColor; fdd->farRiverColor = config->farRiverColor; fdd->closeOceanColor = config->closeOceanColor; fdd->farOceanColor = config->farOceanColor; } if (config->skyParams == EParameterSource::eDatabase) { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->SkyTopColor = mathfu::vec4(SkyTopColor[2], SkyTopColor[1], SkyTopColor[0], 1.0); fdd->SkyMiddleColor = mathfu::vec4(SkyMiddleColor[2], SkyMiddleColor[1], SkyMiddleColor[0], 1.0); fdd->SkyBand1Color = mathfu::vec4(SkyBand1Color[2], SkyBand1Color[1], SkyBand1Color[0], 1.0); @@ -909,7 +908,7 @@ void Map::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &ca //In case of no data -> disable the fog { - auto fdd = cullStage->frameDependentData; + auto fdd = mapRenderPlan->frameDependentData; fdd->FogDataFound = !combinedResults.empty(); // std::cout << "combinedResults.empty() = " << combinedResults.empty() << std::endl; // std::cout << "combinedResults.size() = " << combinedResults.size() << std::endl; @@ -1010,7 +1009,7 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { @@ -1021,7 +1020,7 @@ void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData if ((adt_x >= 64) || (adt_x < 0)) return; if ((adt_y >= 64) || (adt_y < 0)) return; - cullStage->adtAreadId = -1; + mapRenderPlan->adtAreadId = -1; auto &adtObjectCameraAt = mapTiles[adt_x][adt_y]; if (adtObjectCameraAt != nullptr) { @@ -1043,7 +1042,7 @@ void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData int adt_global_x = worldCoordinateToGlobalAdtChunk(cameraPos.y) % 16; int adt_global_y = worldCoordinateToGlobalAdtChunk(cameraPos.x) % 16; - cullStage->adtAreadId = adtObjectCameraAt->getAreaId(adt_global_x, adt_global_y); + mapRenderPlan->adtAreadId = adtObjectCameraAt->getAreaId(adt_global_x, adt_global_y); } } else { if (wmoMap == nullptr) { @@ -1087,7 +1086,7 @@ void Map::getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAr void Map::checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, int viewRenderOrder, - HCullStage cullStage + HMapRenderPlan &mapRenderPlan ) { // std::cout << "Map::checkExterior finished called" << std::endl; if (m_wdlObject == nullptr && m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { @@ -1097,21 +1096,21 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, } } - auto exteriorView = cullStage->viewsHolder.getExterior(); //Should not be null, since we called checkExterior + auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); //Should not be null, since we called checkExterior cullExteriorWDLCull.beginMeasurement(); if (m_wdlObject != nullptr) { - m_wdlObject->checkFrustumCulling(frustumData, cameraPos, exteriorView->m2List, cullStage->wmoArray); + m_wdlObject->checkFrustumCulling(frustumData, cameraPos, exteriorView->m2List, mapRenderPlan->wmoArray); } cullExteriorWDLCull.endMeasurement(); cullExteriorGetCands.beginMeasurement(); - getCandidatesEntities(frustumData, cameraPos, cullStage, exteriorView->m2List, cullStage->wmoArray); + getCandidatesEntities(frustumData, cameraPos, mapRenderPlan, exteriorView->m2List, mapRenderPlan->wmoArray); cullExteriorGetCands.endMeasurement(); cullExterioFrustumWMO.beginMeasurement(); //Frustum cull - for (auto &wmoCandidate : cullStage->wmoArray.getCandidates()) { + for (auto &wmoCandidate : mapRenderPlan->wmoArray.getCandidates()) { if (!wmoCandidate->isLoaded()) continue; if (wmoCandidate->startTraversingWMOGroup( @@ -1121,7 +1120,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, 0, viewRenderOrder, false, - cullStage->viewsHolder)) { + mapRenderPlan->viewsHolder)) { } } cullExterioFrustumWMO.endMeasurement(); @@ -1169,7 +1168,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { if (m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { @@ -1217,11 +1216,11 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat if (!m_wdtfile->mphd->flags.wdt_uses_global_map_obj) { for (int i = adt_x_min; i <= adt_x_max; i++) { for (int j = adt_y_min; j <= adt_y_max; j++) { - checkADTCulling(i, j, frustumData, cameraPos, cullStage, m2ObjectsCandidates, wmoCandidates); + checkADTCulling(i, j, frustumData, cameraPos, mapRenderPlan, m2ObjectsCandidates, wmoCandidates); } } for (auto &mandatoryAdt : m_mandatoryADT) { - checkADTCulling(mandatoryAdt[0], mandatoryAdt[1], frustumData, cameraPos, cullStage, m2ObjectsCandidates, wmoCandidates); + checkADTCulling(mandatoryAdt[0], mandatoryAdt[1], frustumData, cameraPos, mapRenderPlan, m2ObjectsCandidates, wmoCandidates); } } else { @@ -1232,7 +1231,8 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat void Map::checkADTCulling(int i, int j, const MathHelper::FrustumCullingData &frustumData, - const mathfu::vec4 &cameraPos, HCullStage &cullStage, + const mathfu::vec4 &cameraPos, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { if ((i < 0) || (i > 64)) return; @@ -1274,8 +1274,8 @@ void Map::checkADTCulling(int i, int j, // } if (result) { - cullStage->viewsHolder.getExterior()->drawnADTs.push_back(adtFrustRes); - cullStage->adtArray.push_back(adtFrustRes); + mapRenderPlan->viewsHolder.getExterior()->drawnADTs.push_back(adtFrustRes); + mapRenderPlan->adtArray.push_back(adtFrustRes); } } else if (!m_lockedMap && true) { //(m_wdtfile->mapTileTable->mainInfo[j][i].Flag_HasADT > 0) { if (m_wdtfile->mphd->flags.wdt_has_maid) { @@ -1305,7 +1305,7 @@ void Map::createAdtFreeLamdas() { FreeStrategy lamda; auto *config = m_api->getConfig(); if (m_api->getConfig()->adtFreeStrategy == EFreeStrategy::eTimeBased) { - int l_currentTime = 0; + animTime_t l_currentTime = 0; lamda = [l_currentTime, config](bool doCheck, bool doUpdate, animTime_t currentTime) mutable -> bool { if (doCheck) { return (currentTime - l_currentTime) > config->adtTTLWithoutUpdate; @@ -1320,10 +1320,10 @@ void Map::createAdtFreeLamdas() { auto l_hDevice = m_api->hDevice; lamda = [l_currentFrame, config, l_hDevice](bool doCheck, bool doUpdate, animTime_t currentTime) mutable -> bool { if (doCheck) { - return (l_hDevice->getFrameNumber() - l_currentFrame) > config->adtFTLWithoutUpdate; +// return (l_hDevice->getFrameNumber() - l_currentFrame) > config->adtFTLWithoutUpdate; } if (doUpdate) { - l_currentFrame = l_hDevice->getFrameNumber(); +// l_currentFrame = l_hDevice->getFrameNumber(); } return false; }; @@ -1335,33 +1335,33 @@ void Map::createAdtFreeLamdas() { -void Map::doPostLoad(HCullStage &cullStage) { +void Map::doPostLoad(const HMapRenderPlan &renderPlan) { int processedThisFrame = 0; int wmoProcessedThisFrame = 0; int wmoGroupsProcessedThisFrame = 0; // if (m_api->getConfig()->getRenderM2()) { - for (auto &m2Object : cullStage->m2Array.getToLoadMain()) { + for (auto &m2Object : renderPlan->m2Array.getToLoadMain()) { if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); } - for (auto &m2Object : cullStage->m2Array.getToLoadGeom()) { + for (auto &m2Object : renderPlan->m2Array.getToLoadGeom()) { if (m2Object == nullptr) continue; m2Object->doLoadGeom(); } // } - for (auto &wmoObject : cullStage->wmoArray.getToLoad()) { + for (auto &wmoObject : renderPlan->wmoArray.getToLoad()) { if (wmoObject == nullptr) continue; wmoObject->doPostLoad(); } - for (auto &wmoGroupObject : cullStage->wmoGroupArray.getToLoad()) { + for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToLoad()) { if (wmoGroupObject == nullptr) continue; wmoGroupObject->doPostLoad(); wmoGroupsProcessedThisFrame++; if (wmoGroupsProcessedThisFrame > 20) break; } - for (auto &adtObject : cullStage->adtArray) { + for (auto &adtObject : renderPlan->adtArray) { adtObject->adtObject->doPostLoad(); } @@ -1411,89 +1411,87 @@ void Map::doPostLoad(HCullStage &cullStage) { } }; -void Map::update(HUpdateStage &updateStage) { - mathfu::vec3 cameraVec3 = updateStage->cameraMatrices->cameraPos.xyz(); - mathfu::mat4 &frustumMat = updateStage->cameraMatrices->perspectiveMat; - mathfu::mat4 &lookAtMat = updateStage->cameraMatrices->lookAtMat; - animTime_t deltaTime = updateStage->delta; - - Config* config = this->m_api->getConfig(); - - auto &m2ToDraw = updateStage->cullResult->m2Array.getDrawn(); - { - m2UpdateframeCounter.beginMeasurement(); - - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 200), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto& m2Object = m2ToDraw[i]; - m2Object->update(deltaTime, cameraVec3, lookAtMat); - } - }, tbb::simple_partitioner()); - - m2UpdateframeCounter.endMeasurement(); - } - - wmoGroupUpdate.beginMeasurement(); - for (const auto &wmoGroupObject : updateStage->cullResult->wmoGroupArray.getToDraw()) { - if (wmoGroupObject == nullptr) continue; - wmoGroupObject->update(); - } - wmoGroupUpdate.endMeasurement(); - - adtUpdate.beginMeasurement(); - for (const auto &adtObjectRes : updateStage->cullResult->adtArray) { - adtObjectRes->adtObject->update(deltaTime); - } - adtUpdate.endMeasurement(); - - //2. Calc distance every 100 ms - m2calcDistanceCounter.beginMeasurement(); - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - if (m2Object == nullptr) continue; - m2Object->calcDistance(cameraVec3); - } - }, tbb::auto_partitioner() - ); - m2calcDistanceCounter.endMeasurement(); - - //Cleanup ADT every 10 seconds - adtCleanupCounter.beginMeasurement(); - if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - auto adtObj = mapTiles[i][j]; - //Free obj, if it was unused for 10 secs - if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { -// std::cout << "try to free adtObj" << std::endl; - - mapTiles[i][j] = nullptr; - } - } - } - - adtFreeLambda(false, true, this->m_currentTime + updateStage->delta); - } - adtCleanupCounter.endMeasurement(); - this->m_currentTime += updateStage->delta; - - m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); - m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); - m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); - m_api->getConfig()->m2calcDistanceTime = m2calcDistanceCounter.getTimePerFrame(); - m_api->getConfig()->adtCleanupTime = adtCleanupCounter.getTimePerFrame(); - //Collect meshes -} - -void Map::updateBuffers(HUpdateStage &updateStage) { - auto cullStage = updateStage->cullResult; - - for (auto &m2Object : cullStage->m2Array.getDrawn()) { +//void Map::update(const HMapRenderPlan &renderPlan) { +// mathfu::vec3 cameraVec3 = updateStage->cameraMatrices->cameraPos.xyz(); +// mathfu::mat4 &frustumMat = updateStage->cameraMatrices->perspectiveMat; +// mathfu::mat4 &lookAtMat = updateStage->cameraMatrices->lookAtMat; +// animTime_t deltaTime = updateStage->delta; +// +// Config* config = this->m_api->getConfig(); +// +// auto &m2ToDraw = renderPlan->m2Array.getDrawn(); +// { +// m2UpdateframeCounter.beginMeasurement(); +// +// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 200), +// [&](tbb::blocked_range r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { +// auto& m2Object = m2ToDraw[i]; +// m2Object->update(deltaTime, cameraVec3, lookAtMat); +// } +// }, tbb::simple_partitioner()); +// +// m2UpdateframeCounter.endMeasurement(); +// } +// +// wmoGroupUpdate.beginMeasurement(); +// for (const auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { +// if (wmoGroupObject == nullptr) continue; +// wmoGroupObject->update(); +// } +// wmoGroupUpdate.endMeasurement(); +// +// adtUpdate.beginMeasurement(); +// for (const auto &adtObjectRes : renderPlan->adtArray) { +// adtObjectRes->adtObject->update(deltaTime); +// } +// adtUpdate.endMeasurement(); +// +// //2. Calc distance every 100 ms +// m2calcDistanceCounter.beginMeasurement(); +// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), +// [&](tbb::blocked_range r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { +// auto &m2Object = m2ToDraw[i]; +// if (m2Object == nullptr) continue; +// m2Object->calcDistance(cameraVec3); +// } +// }, tbb::auto_partitioner() +// ); +// m2calcDistanceCounter.endMeasurement(); +// +// //Cleanup ADT every 10 seconds +// adtCleanupCounter.beginMeasurement(); +// if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { +// for (int i = 0; i < 64; i++) { +// for (int j = 0; j < 64; j++) { +// auto adtObj = mapTiles[i][j]; +// //Free obj, if it was unused for 10 secs +// if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { +//// std::cout << "try to free adtObj" << std::endl; +// +// mapTiles[i][j] = nullptr; +// } +// } +// } +// +// adtFreeLambda(false, true, this->m_currentTime + updateStage->delta); +// } +// adtCleanupCounter.endMeasurement(); +// this->m_currentTime += updateStage->delta; +// +// m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); +// m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); +// m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); +// m_api->getConfig()->m2calcDistanceTime = m2calcDistanceCounter.getTimePerFrame(); +// m_api->getConfig()->adtCleanupTime = adtCleanupCounter.getTimePerFrame(); +// //Collect meshes +//} + +void Map::updateBuffers(const HMapRenderPlan &renderPlan) { + for (auto &m2Object : renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(cullStage->matricesForCulling->lookAtMat); +// m2Object->uploadGeneratorBuffers(renderPlan->matricesForCulling->lookAtMat); } } @@ -1502,7 +1500,7 @@ void Map::updateBuffers(HUpdateStage &updateStage) { // wmoGroupObject->uploadGeneratorBuffers(); // } - for (auto &adtRes: cullStage->adtArray) { + for (auto &adtRes: renderPlan->adtArray) { if (adtRes == nullptr) continue; adtRes->adtObject->uploadGeneratorBuffers(*adtRes.get()); } @@ -1604,419 +1602,419 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDefObj1 &ma animTime_t Map::getCurrentSceneTime() { return m_currentTime; } -void Map::produceUpdateStage(HUpdateStage &updateStage) { - mapProduceUpdateCounter.beginMeasurement(); - mapUpdateCounter.beginMeasurement(); - this->update(updateStage); - mapUpdateCounter.endMeasurement(); - - //Create meshes - updateStage->opaqueMeshes = std::make_shared(); - updateStage->transparentMeshes = std::make_shared(); - - auto &opaqueMeshes = updateStage->opaqueMeshes->meshes; - auto transparentMeshes = std::vector(); - - opaqueMeshes.reserve(30000); - transparentMeshes.reserve(30000); - - auto cullStage = updateStage->cullResult; - auto fdd = cullStage->frameDependentData; - - if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && - (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { - if (fdd->overrideValuesWithFinalFog) { - if (skyMesh0x4Sky != nullptr) { - transparentMeshes.push_back(skyMesh0x4Sky); - skyMesh0x4Sky->setSortDistance(0); - - } - } - if ((m_skyConeAlpha > 0) ) { - if (skyMesh != nullptr) - opaqueMeshes.push_back(skyMesh); - } - } - - // Put everything into one array and sort - interiorViewCollectMeshCounter.beginMeasurement(); - bool renderPortals = m_api->getConfig()->renderPortals; - for (auto &view : cullStage->viewsHolder.getInteriorViews()) { - view->collectMeshes(opaqueMeshes, transparentMeshes); - if (renderPortals) { - view->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); - } - } - interiorViewCollectMeshCounter.endMeasurement(); - - exteriorViewCollectMeshCounter.beginMeasurement(); - { - auto exteriorView = cullStage->viewsHolder.getExterior(); - if (exteriorView != nullptr) { - exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); - if (renderPortals) { - exteriorView->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); - } - } - } - exteriorViewCollectMeshCounter.endMeasurement(); - - m2CollectMeshCounter.beginMeasurement(); - if (m_api->getConfig()->renderM2) { - for (auto &m2Object : cullStage->m2Array.getDrawn()) { - if (m2Object == nullptr) continue; - m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); - m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); - } - } - m2CollectMeshCounter.endMeasurement(); - - //No need to sort array which has only one element - sortMeshCounter.beginMeasurement(); - if (transparentMeshes.size() > 1) { - tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), - #include "../../../gapi/interface/sortLambda.h" - ); - - updateStage->transparentMeshes->meshes = transparentMeshes; - - } else { - auto &targetTranspMeshes = updateStage->transparentMeshes->meshes; - for (int i = 0; i < transparentMeshes.size(); i++) { - targetTranspMeshes.push_back(transparentMeshes[i]); - } - } - sortMeshCounter.endMeasurement(); - - //Collect textures for upload - auto &textureToUpload = updateStage->texturesForUpload; - textureToUpload.reserve(10000); - for (auto &mesh: updateStage->transparentMeshes->meshes) { - for (auto &text : mesh->texture()) { - if (text != nullptr && !text->getIsLoaded()) { - textureToUpload.push_back(text); - } - } - } - for (auto &mesh: updateStage->opaqueMeshes->meshes) { - for (auto &text : mesh->texture()) { - if (text != nullptr && !text->getIsLoaded()) { - textureToUpload.push_back(text); - } - } - } - - tbb::parallel_sort(textureToUpload.begin(), textureToUpload.end(), - [](auto &first, auto &end) { return first < end; } - ); - textureToUpload.erase(unique(textureToUpload.begin(), textureToUpload.end()), textureToUpload.end()); - - //1. Collect buffers - collectBuffersCounter.beginMeasurement(); - std::vector &bufferChunks = updateStage->uniformBufferChunks; - bufferChunks.reserve((opaqueMeshes.size() + updateStage->transparentMeshes->meshes.size()) * 5); - int renderIndex = 0; - for (const auto &mesh : opaqueMeshes) { - for (int i = 0; i < 5; i++ ) { - auto bufferChunk = mesh->getUniformBuffer(i); - - if (bufferChunk != nullptr) { - bufferChunks.push_back(bufferChunk); - } - } - } - for (const auto &mesh : updateStage->transparentMeshes->meshes) { - for (int i = 0; i < 5; i++ ) { - auto bufferChunk = mesh->getUniformBuffer(i); - - if (bufferChunk != nullptr) { - bufferChunks.push_back(bufferChunk); - } - } - } - collectBuffersCounter.endMeasurement(); - - sortBuffersCounter.beginMeasurement(); - tbb::parallel_sort(bufferChunks.begin(), bufferChunks.end(), - [](auto &first, auto &end) { return first < end; } - ); - bufferChunks.erase(unique(bufferChunks.begin(), bufferChunks.end()), bufferChunks.end()); - sortBuffersCounter.endMeasurement(); - - mapProduceUpdateCounter.endMeasurement(); - - - m_api->getConfig()->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); - m_api->getConfig()->mapUpdateTime = mapUpdateCounter.getTimePerFrame(); - m_api->getConfig()->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); - m_api->getConfig()->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); - m_api->getConfig()->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); - m_api->getConfig()->sortMeshTime = sortMeshCounter.getTimePerFrame(); - m_api->getConfig()->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); - m_api->getConfig()->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); -} - -void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { - //Smash all meshes into one array - - auto opaqueMeshes = std::make_shared(); - auto transparentMeshes = std::make_shared(); - for (auto &updateStage : updateStages) { - auto cullStage = updateStage->cullResult; - - //Create scenewide uniform - resultDrawStage->frameDepedantData = updateStage->cullResult->frameDependentData; - - opaqueMeshes->meshes.insert(std::end(opaqueMeshes->meshes), - std::begin(updateStage->opaqueMeshes->meshes), - std::end(updateStage->opaqueMeshes->meshes)); - transparentMeshes->meshes.insert(std::end(transparentMeshes->meshes), - std::begin(updateStage->transparentMeshes->meshes), - std::end(updateStage->transparentMeshes->meshes)); - } - - //Sort transparent meshes. Again - tbb::parallel_sort(transparentMeshes->meshes.begin(), transparentMeshes->meshes.end(), -#include "../../../gapi/interface/sortLambda.h" - ); - - resultDrawStage->opaqueMeshes = opaqueMeshes; - resultDrawStage->transparentMeshes = transparentMeshes; - - HDrawStage origResultDrawStage = resultDrawStage; - bool frameBufferSupported = m_api->hDevice->getIsRenderbufferSupported(); - - auto config = m_api->getConfig(); - - auto renderMats = resultDrawStage->matricesForRendering; - if (renderMats != nullptr) { - resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); - resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler( - this->generateSceneWideChunk(renderMats, config) - ); - updateStages[0]->uniformBufferChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); - } - - - - if (frameBufferSupported ) { - //Create a copy of exiting resultDrawStage - auto resultDrawStageCpy = std::make_shared(); - *resultDrawStageCpy = *resultDrawStage; - //Assign a new frame buffer to copy - resultDrawStageCpy->target = m_api->hDevice->createFrameBuffer( - resultDrawStage->viewPortDimensions.maxs[0], - resultDrawStage->viewPortDimensions.maxs[1], - {ITextureFormat::itRGBA}, - ITextureFormat::itDepth32, - m_api->hDevice->getMaxSamplesCnt(), - 4 - ); - resultDrawStageCpy->viewPortDimensions.mins = {0,0}; - - HDrawStage lastDrawStage = nullptr; - HDrawStage prevDrawStage = resultDrawStageCpy; - - if (!config->disableGlow) { - lastDrawStage = doGaussBlur(prevDrawStage, updateStages[0]->uniformBufferChunks); - if (lastDrawStage != nullptr) - prevDrawStage = lastDrawStage; - } - - - //End of effects stack - //Make last stage to draw to initial resultDrawStage target - prevDrawStage->target = resultDrawStage->target; - //Replace all data in target drawStage with new data - *resultDrawStage = *prevDrawStage; - } - - - -} - -HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const { - if (quadBindings == nullptr) - return nullptr; - - ///2 Rounds of ffxgauss4 (Horizontal and Vertical blur) - ///With two frameBuffers - ///Size for buffers : is 4 times less than current canvas - int targetWidth = parentDrawStage->viewPortDimensions.maxs[0] >> 2; - int targetHeight = parentDrawStage->viewPortDimensions.maxs[1] >> 2; - - auto frameB1 = m_api->hDevice->createFrameBuffer( - targetWidth, - targetHeight, - {ITextureFormat::itRGBA}, - ITextureFormat::itDepth32, - 1, - 2 - ); - auto frameB2 = m_api->hDevice->createFrameBuffer( - targetWidth, - targetHeight, - {ITextureFormat::itRGBA}, - ITextureFormat::itDepth32, - 1, - 2 - ); - - auto vertexChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); - uniformBufferChunks.push_back(vertexChunk); - vertexChunk->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); - meshblockVS.x = 1; - meshblockVS.y = 1; - meshblockVS.z = 0; - meshblockVS.w = 0; - }); - - - auto ffxGaussFrag = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - uniformBufferChunks.push_back(ffxGaussFrag); - ffxGaussFrag->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); - static const float s_texOffsetX[4] = {-1, 0, 0, -1}; - static const float s_texOffsetY[4] = {2, 2, -1, -1};; - - for (int i = 0; i < 4; i++) { - meshblockVS.texOffsetX[i] = s_texOffsetX[i]; - meshblockVS.texOffsetY[i] = s_texOffsetY[i]; - } - }); - - - auto ffxGaussFrag2 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - uniformBufferChunks.push_back(ffxGaussFrag2); - ffxGaussFrag2->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); - static const float s_texOffsetX[4] = {-6, -1, 1, 6}; - static const float s_texOffsetY[4] = {0, 0, 0, 0};; - - for (int i = 0; i < 4; i++) { - meshblockVS.texOffsetX[i] = s_texOffsetX[i]; - meshblockVS.texOffsetY[i] = s_texOffsetY[i]; - } - }); - auto ffxGaussFrag3 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); - uniformBufferChunks.push_back(ffxGaussFrag3); - ffxGaussFrag3->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); - static const float s_texOffsetX[4] = {0, 0, 0, 0}; - static const float s_texOffsetY[4] = {10, 2, -2, -10};; - - for (int i = 0; i < 4; i++) { - meshblockVS.texOffsetX[i] = s_texOffsetX[i]; - meshblockVS.texOffsetY[i] = s_texOffsetY[i]; - } - }); - HGUniformBufferChunk frags[3] = {ffxGaussFrag, ffxGaussFrag2, ffxGaussFrag3}; - - HDrawStage prevStage = parentDrawStage; - for (int i = 0; i < 3; i++) { - ///1. Create draw stage - HDrawStage drawStage = std::make_shared(); - - drawStage->drawStageDependencies = {prevStage}; - drawStage->matricesForRendering = nullptr; - drawStage->setViewPort = true; - drawStage->viewPortDimensions = {{0, 0}, - {parentDrawStage->viewPortDimensions.maxs[0] >> 2, - parentDrawStage->viewPortDimensions.maxs[1] >> 2}}; - drawStage->clearScreen = false; - drawStage->target = ((i & 1) > 0) ? frameB1 : frameB2; - - ///2. Create mesh - auto shader = m_api->hDevice->getShader("fullScreen_ffxgauss4", nullptr); - gMeshTemplate meshTemplate(quadBindings, shader); - meshTemplate.meshType = MeshType::eGeneralMesh; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = false; - meshTemplate.backFaceCulling = false; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; - - meshTemplate.texture.resize(1); - meshTemplate.texture[0] = prevStage->target->getAttachment(0); - - meshTemplate.textureCount = 1; - - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = vertexChunk; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = frags[i]; - - meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.start = 0; - meshTemplate.end = 6; - - //Make mesh - HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); - drawStage->opaqueMeshes = std::make_shared(); - drawStage->opaqueMeshes->meshes.push_back(hmesh); - - ///3. Reassign previous frame - prevStage = drawStage; - } - - //And the final is ffxglow to screen - { - auto config = m_api->getConfig();; - - auto glow = parentDrawStage->frameDepedantData->currentGlow; - auto ffxGlowfragmentChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); - uniformBufferChunks.push_back(ffxGlowfragmentChunk); - ffxGlowfragmentChunk->setUpdateHandler([glow, config](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); - meshblockVS.x = 1; - meshblockVS.y = 1; - meshblockVS.z = 0; //mix_coeficient - meshblockVS.w = glow; //glow multiplier - }); - - auto shader = m_api->hDevice->getShader("ffxGlowQuad", nullptr); - gMeshTemplate meshTemplate(quadBindings, shader); - meshTemplate.meshType = MeshType::eGeneralMesh; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = false; - meshTemplate.backFaceCulling = false; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; - - meshTemplate.texture.resize(2); - meshTemplate.texture[0] = parentDrawStage->target->getAttachment(0); - meshTemplate.texture[1] = prevStage->target->getAttachment(0); - - meshTemplate.textureCount = 2; - - - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = vertexChunk; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = ffxGlowfragmentChunk; - - meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.start = 0; - meshTemplate.end = 6; - - //Make mesh - HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); - - auto resultDrawStage = std::make_shared(); - *resultDrawStage = *parentDrawStage; - resultDrawStage->sceneWideBlockVSPSChunk = nullptr; //Since it's not used but this shader and it's important for vulkan - resultDrawStage->drawStageDependencies = {prevStage}; - resultDrawStage->transparentMeshes = nullptr; - resultDrawStage->opaqueMeshes = std::make_shared(); - resultDrawStage->opaqueMeshes->meshes.push_back(hmesh); - resultDrawStage->target = nullptr; - - return resultDrawStage; - } -} +//void Map::produceUpdateStage(HUpdateStage &updateStage) { +// mapProduceUpdateCounter.beginMeasurement(); +// mapUpdateCounter.beginMeasurement(); +// this->update(updateStage); +// mapUpdateCounter.endMeasurement(); +// +// //Create meshes +// updateStage->opaqueMeshes = std::make_shared(); +// updateStage->transparentMeshes = std::make_shared(); +// +// auto &opaqueMeshes = updateStage->opaqueMeshes->meshes; +// auto transparentMeshes = std::vector(); +// +// opaqueMeshes.reserve(30000); +// transparentMeshes.reserve(30000); +// +// auto cullStage = updateStage->cullResult; +// auto fdd = cullStage->frameDependentData; +// +// if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && +// (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { +// if (fdd->overrideValuesWithFinalFog) { +// if (skyMesh0x4Sky != nullptr) { +// transparentMeshes.push_back(skyMesh0x4Sky); +// skyMesh0x4Sky->setSortDistance(0); +// +// } +// } +// if ((m_skyConeAlpha > 0) ) { +// if (skyMesh != nullptr) +// opaqueMeshes.push_back(skyMesh); +// } +// } +// +// // Put everything into one array and sort +// interiorViewCollectMeshCounter.beginMeasurement(); +// bool renderPortals = m_api->getConfig()->renderPortals; +// for (auto &view : cullStage->viewsHolder.getInteriorViews()) { +// view->collectMeshes(opaqueMeshes, transparentMeshes); +// if (renderPortals) { +// view->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); +// } +// } +// interiorViewCollectMeshCounter.endMeasurement(); +// +// exteriorViewCollectMeshCounter.beginMeasurement(); +// { +// auto exteriorView = cullStage->viewsHolder.getExterior(); +// if (exteriorView != nullptr) { +// exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); +// if (renderPortals) { +// exteriorView->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); +// } +// } +// } +// exteriorViewCollectMeshCounter.endMeasurement(); +// +// m2CollectMeshCounter.beginMeasurement(); +// if (m_api->getConfig()->renderM2) { +// for (auto &m2Object : cullStage->m2Array.getDrawn()) { +// if (m2Object == nullptr) continue; +// m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); +// m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); +// } +// } +// m2CollectMeshCounter.endMeasurement(); +// +// //No need to sort array which has only one element +// sortMeshCounter.beginMeasurement(); +// if (transparentMeshes.size() > 1) { +// tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), +// #include "../../../gapi/interface/sortLambda.h" +// ); +// +// updateStage->transparentMeshes->meshes = transparentMeshes; +// +// } else { +// auto &targetTranspMeshes = updateStage->transparentMeshes->meshes; +// for (int i = 0; i < transparentMeshes.size(); i++) { +// targetTranspMeshes.push_back(transparentMeshes[i]); +// } +// } +// sortMeshCounter.endMeasurement(); +// +// //Collect textures for upload +// auto &textureToUpload = updateStage->texturesForUpload; +// textureToUpload.reserve(10000); +// for (auto &mesh: updateStage->transparentMeshes->meshes) { +// for (auto &text : mesh->texture()) { +// if (text != nullptr && !text->getIsLoaded()) { +// textureToUpload.push_back(text); +// } +// } +// } +// for (auto &mesh: updateStage->opaqueMeshes->meshes) { +// for (auto &text : mesh->texture()) { +// if (text != nullptr && !text->getIsLoaded()) { +// textureToUpload.push_back(text); +// } +// } +// } +// +// tbb::parallel_sort(textureToUpload.begin(), textureToUpload.end(), +// [](auto &first, auto &end) { return first < end; } +// ); +// textureToUpload.erase(unique(textureToUpload.begin(), textureToUpload.end()), textureToUpload.end()); +// +// //1. Collect buffers +// collectBuffersCounter.beginMeasurement(); +// std::vector &bufferChunks = updateStage->uniformBufferChunks; +// bufferChunks.reserve((opaqueMeshes.size() + updateStage->transparentMeshes->meshes.size()) * 5); +// int renderIndex = 0; +// for (const auto &mesh : opaqueMeshes) { +// for (int i = 0; i < 5; i++ ) { +// auto bufferChunk = mesh->getUniformBuffer(i); +// +// if (bufferChunk != nullptr) { +// bufferChunks.push_back(bufferChunk); +// } +// } +// } +// for (const auto &mesh : updateStage->transparentMeshes->meshes) { +// for (int i = 0; i < 5; i++ ) { +// auto bufferChunk = mesh->getUniformBuffer(i); +// +// if (bufferChunk != nullptr) { +// bufferChunks.push_back(bufferChunk); +// } +// } +// } +// collectBuffersCounter.endMeasurement(); +// +// sortBuffersCounter.beginMeasurement(); +// tbb::parallel_sort(bufferChunks.begin(), bufferChunks.end(), +// [](auto &first, auto &end) { return first < end; } +// ); +// bufferChunks.erase(unique(bufferChunks.begin(), bufferChunks.end()), bufferChunks.end()); +// sortBuffersCounter.endMeasurement(); +// +// mapProduceUpdateCounter.endMeasurement(); +// +// +// m_api->getConfig()->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); +// m_api->getConfig()->mapUpdateTime = mapUpdateCounter.getTimePerFrame(); +// m_api->getConfig()->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); +// m_api->getConfig()->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); +// m_api->getConfig()->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); +// m_api->getConfig()->sortMeshTime = sortMeshCounter.getTimePerFrame(); +// m_api->getConfig()->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); +// m_api->getConfig()->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); +//} + +//void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { +// //Smash all meshes into one array +// +// auto opaqueMeshes = std::make_shared(); +// auto transparentMeshes = std::make_shared(); +// for (auto &updateStage : updateStages) { +// auto cullStage = updateStage->cullResult; +// +// //Create scenewide uniform +// resultDrawStage->frameDepedantData = updateStage->cullResult->frameDependentData; +// +// opaqueMeshes->meshes.insert(std::end(opaqueMeshes->meshes), +// std::begin(updateStage->opaqueMeshes->meshes), +// std::end(updateStage->opaqueMeshes->meshes)); +// transparentMeshes->meshes.insert(std::end(transparentMeshes->meshes), +// std::begin(updateStage->transparentMeshes->meshes), +// std::end(updateStage->transparentMeshes->meshes)); +// } +// +// //Sort transparent meshes. Again +// tbb::parallel_sort(transparentMeshes->meshes.begin(), transparentMeshes->meshes.end(), +//#include "../../../gapi/interface/sortLambda.h" +// ); +// +// resultDrawStage->opaqueMeshes = opaqueMeshes; +// resultDrawStage->transparentMeshes = transparentMeshes; +// +// HDrawStage origResultDrawStage = resultDrawStage; +// bool frameBufferSupported = m_api->hDevice->getIsRenderbufferSupported(); +// +// auto config = m_api->getConfig(); +// +// auto renderMats = resultDrawStage->matricesForRendering; +// if (renderMats != nullptr) { +// resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); +// resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler( +// this->generateSceneWideChunk(renderMats, config) +// ); +// updateStages[0]->uniformBufferChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); +// } +// +// +// +// if (frameBufferSupported ) { +// //Create a copy of exiting resultDrawStage +// auto resultDrawStageCpy = std::make_shared(); +// *resultDrawStageCpy = *resultDrawStage; +// //Assign a new frame buffer to copy +// resultDrawStageCpy->target = m_api->hDevice->createFrameBuffer( +// resultDrawStage->viewPortDimensions.maxs[0], +// resultDrawStage->viewPortDimensions.maxs[1], +// {ITextureFormat::itRGBA}, +// ITextureFormat::itDepth32, +// m_api->hDevice->getMaxSamplesCnt(), +// 4 +// ); +// resultDrawStageCpy->viewPortDimensions.mins = {0,0}; +// +// HDrawStage lastDrawStage = nullptr; +// HDrawStage prevDrawStage = resultDrawStageCpy; +// +// if (!config->disableGlow) { +// lastDrawStage = doGaussBlur(prevDrawStage, updateStages[0]->uniformBufferChunks); +// if (lastDrawStage != nullptr) +// prevDrawStage = lastDrawStage; +// } +// +// +// //End of effects stack +// //Make last stage to draw to initial resultDrawStage target +// prevDrawStage->target = resultDrawStage->target; +// //Replace all data in target drawStage with new data +// *resultDrawStage = *prevDrawStage; +// } +// +// +// +//} +// +//HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const { +// if (quadBindings == nullptr) +// return nullptr; +// +// ///2 Rounds of ffxgauss4 (Horizontal and Vertical blur) +// ///With two frameBuffers +// ///Size for buffers : is 4 times less than current canvas +// int targetWidth = parentDrawStage->viewPortDimensions.maxs[0] >> 2; +// int targetHeight = parentDrawStage->viewPortDimensions.maxs[1] >> 2; +// +// auto frameB1 = m_api->hDevice->createFrameBuffer( +// targetWidth, +// targetHeight, +// {ITextureFormat::itRGBA}, +// ITextureFormat::itDepth32, +// 1, +// 2 +// ); +// auto frameB2 = m_api->hDevice->createFrameBuffer( +// targetWidth, +// targetHeight, +// {ITextureFormat::itRGBA}, +// ITextureFormat::itDepth32, +// 1, +// 2 +// ); +// +// auto vertexChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); +// uniformBufferChunks.push_back(vertexChunk); +// vertexChunk->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { +// auto &meshblockVS = self->getObject(); +// meshblockVS.x = 1; +// meshblockVS.y = 1; +// meshblockVS.z = 0; +// meshblockVS.w = 0; +// }); +// +// +// auto ffxGaussFrag = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); +// uniformBufferChunks.push_back(ffxGaussFrag); +// ffxGaussFrag->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { +// auto &meshblockVS = self->getObject(); +// static const float s_texOffsetX[4] = {-1, 0, 0, -1}; +// static const float s_texOffsetY[4] = {2, 2, -1, -1};; +// +// for (int i = 0; i < 4; i++) { +// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; +// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; +// } +// }); +// +// +// auto ffxGaussFrag2 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); +// uniformBufferChunks.push_back(ffxGaussFrag2); +// ffxGaussFrag2->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { +// auto &meshblockVS = self->getObject(); +// static const float s_texOffsetX[4] = {-6, -1, 1, 6}; +// static const float s_texOffsetY[4] = {0, 0, 0, 0};; +// +// for (int i = 0; i < 4; i++) { +// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; +// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; +// } +// }); +// auto ffxGaussFrag3 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); +// uniformBufferChunks.push_back(ffxGaussFrag3); +// ffxGaussFrag3->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { +// auto &meshblockVS = self->getObject(); +// static const float s_texOffsetX[4] = {0, 0, 0, 0}; +// static const float s_texOffsetY[4] = {10, 2, -2, -10};; +// +// for (int i = 0; i < 4; i++) { +// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; +// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; +// } +// }); +// HGUniformBufferChunk frags[3] = {ffxGaussFrag, ffxGaussFrag2, ffxGaussFrag3}; +// +// HDrawStage prevStage = parentDrawStage; +// for (int i = 0; i < 3; i++) { +// ///1. Create draw stage +// HDrawStage drawStage = std::make_shared(); +// +// drawStage->drawStageDependencies = {prevStage}; +// drawStage->matricesForRendering = nullptr; +// drawStage->setViewPort = true; +// drawStage->viewPortDimensions = {{0, 0}, +// {parentDrawStage->viewPortDimensions.maxs[0] >> 2, +// parentDrawStage->viewPortDimensions.maxs[1] >> 2}}; +// drawStage->clearScreen = false; +// drawStage->target = ((i & 1) > 0) ? frameB1 : frameB2; +// +// ///2. Create mesh +// auto shader = m_api->hDevice->getShader("fullScreen_ffxgauss4", nullptr); +// gMeshTemplate meshTemplate(quadBindings, shader); +// meshTemplate.meshType = MeshType::eGeneralMesh; +// meshTemplate.depthWrite = false; +// meshTemplate.depthCulling = false; +// meshTemplate.backFaceCulling = false; +// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; +// +// meshTemplate.texture.resize(1); +// meshTemplate.texture[0] = prevStage->target->getAttachment(0); +// +// meshTemplate.textureCount = 1; +// +// meshTemplate.ubo[0] = nullptr; +// meshTemplate.ubo[1] = nullptr; +// meshTemplate.ubo[2] = vertexChunk; +// +// meshTemplate.ubo[3] = nullptr; +// meshTemplate.ubo[4] = frags[i]; +// +// meshTemplate.element = DrawElementMode::TRIANGLES; +// meshTemplate.start = 0; +// meshTemplate.end = 6; +// +// //Make mesh +// HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); +// drawStage->opaqueMeshes = std::make_shared(); +// drawStage->opaqueMeshes->meshes.push_back(hmesh); +// +// ///3. Reassign previous frame +// prevStage = drawStage; +// } +// +// //And the final is ffxglow to screen +// { +// auto config = m_api->getConfig();; +// +// auto glow = parentDrawStage->frameDepedantData->currentGlow; +// auto ffxGlowfragmentChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); +// uniformBufferChunks.push_back(ffxGlowfragmentChunk); +// ffxGlowfragmentChunk->setUpdateHandler([glow, config](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { +// auto &meshblockVS = self->getObject(); +// meshblockVS.x = 1; +// meshblockVS.y = 1; +// meshblockVS.z = 0; //mix_coeficient +// meshblockVS.w = glow; //glow multiplier +// }); +// +// auto shader = m_api->hDevice->getShader("ffxGlowQuad", nullptr); +// gMeshTemplate meshTemplate(quadBindings, shader); +// meshTemplate.meshType = MeshType::eGeneralMesh; +// meshTemplate.depthWrite = false; +// meshTemplate.depthCulling = false; +// meshTemplate.backFaceCulling = false; +// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; +// +// meshTemplate.texture.resize(2); +// meshTemplate.texture[0] = parentDrawStage->target->getAttachment(0); +// meshTemplate.texture[1] = prevStage->target->getAttachment(0); +// +// meshTemplate.textureCount = 2; +// +// +// meshTemplate.ubo[0] = nullptr; +// meshTemplate.ubo[1] = nullptr; +// meshTemplate.ubo[2] = vertexChunk; +// +// meshTemplate.ubo[3] = nullptr; +// meshTemplate.ubo[4] = ffxGlowfragmentChunk; +// +// meshTemplate.element = DrawElementMode::TRIANGLES; +// meshTemplate.start = 0; +// meshTemplate.end = 6; +// +// //Make mesh +// HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); +// +// auto resultDrawStage = std::make_shared(); +// *resultDrawStage = *parentDrawStage; +// resultDrawStage->sceneWideBlockVSPSChunk = nullptr; //Since it's not used but this shader and it's important for vulkan +// resultDrawStage->drawStageDependencies = {prevStage}; +// resultDrawStage->transparentMeshes = nullptr; +// resultDrawStage->opaqueMeshes = std::make_shared(); +// resultDrawStage->opaqueMeshes->meshes.push_back(hmesh); +// resultDrawStage->target = nullptr; +// +// return resultDrawStage; +// } +//} void Map::loadZoneLights() { if (m_api->databaseHandler != nullptr) { @@ -2060,7 +2058,7 @@ void Map::loadZoneLights() { } IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrices &renderMats, Config* config) { - return [renderMats, config](IUniformBufferChunk *chunk, const HFrameDepedantData &fdd) -> void { + return [renderMats, config](IUniformBufferChunk *chunk, const HFrameDependantData &fdd) -> void { auto *blockPSVS = &chunk->getObject(); blockPSVS->uLookAtMat = renderMats->lookAtMat; diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 516330e3b..ae41b2454 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -14,9 +14,10 @@ #include "../iScene.h" #include "../objectCache.h" #include "../wdl/wdlObject.h" -#include "../../SceneScenario.h" #include "tbb/tbb.h" #include "../../algorithms/FrameCounter.h" +#include "../../../renderer/frame/FrameInputParams.h" +#include "../../../renderer/mapScene/MapScenePlan.h" enum class SceneMode { smMap, @@ -114,33 +115,29 @@ class Map : public IScene, public IMapApi { std::shared_ptr getWmoObject(std::string fileName, SMMapObjDefObj1 &mapObjDef) override ; std::shared_ptr getWmoObject(int fileDataId, SMMapObjDefObj1 &mapObjDef) override ; - int getCameraNum() override {return 0;}; - std::shared_ptr createCamera(int cameraNum) override { return nullptr;}; - - animTime_t getCurrentSceneTime() override ; virtual void getPotentialEntities( const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo); virtual void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates); void checkADTCulling(int i, int j, const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates); - virtual void updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, + virtual void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord); struct mapInnerZoneLightRecord { @@ -205,39 +202,30 @@ class Map : public IScene, public IMapApi { // std::cout << "Map destroyed " << std::endl; }; - void setReplaceTextureArray(std::vector &replaceTextureArray) override {}; - void setMeshIdArray(std::vector &meshIds) override {}; - void checkCulling(HCullStage &cullStage) override; + void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); - void setMandatoryADTs(std::vector> &mandatoryADTs) override { + void setMandatoryADTs(std::vector> &mandatoryADTs) { m_mandatoryADT = mandatoryADTs; } - void getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAreaId) override; - void setAnimationId(int animationId) override {}; - void setMeshIds(std::vector &meshIds) override {}; - - void resetAnimation() override { + void getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAreaId); - } - virtual void setAdtConfig(HADTRenderConfigDataHolder &adtConfig) override { + void setAdtConfig(HADTRenderConfigDataHolder &adtConfig) { m_adtConfigHolder = adtConfig; } + void doPostLoad(const HMapRenderPlan &renderPlan); - - void doPostLoad(HCullStage &cullStage) override; - - void update(HUpdateStage &updateStage); - void updateBuffers(HUpdateStage &updateStage) override; - void produceUpdateStage(HUpdateStage &updateStage) override; - void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; + void update(const HMapRenderPlan &renderPlan); + void updateBuffers(const HMapRenderPlan &renderPlan); +// void produceUpdateStage(HUpdateStage &updateStage) override; +// void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; private: void checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, int viewRenderOrder, - HCullStage cullStage); + HMapRenderPlan &mapRenderPlan); - HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; +// HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) override; @@ -246,5 +234,6 @@ class Map : public IScene, public IMapApi { IChunkHandlerType generateSceneWideChunk(HCameraMatrices &renderMats, Config* config); }; +typedef std::shared_ptr HMapScene; #endif //WEBWOWVIEWERCPP_MAP_H diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index f685e6ac3..956be8327 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -10,7 +10,7 @@ void WmoScene::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { potentialWmo.addCand(this->m_wmoObject); @@ -18,30 +18,30 @@ void WmoScene::getPotentialEntities(const MathHelper::FrustumCullingData &frustu void WmoScene::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { wmoCandidates.addCand(this->m_wmoObject); }; -void WmoScene::updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, - StateForConditions &stateForConditions, const AreaRecord &areaRecord) { +void WmoScene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, const AreaRecord &areaRecord) { Config* config = this->m_api->getConfig(); config->globalFog = EParameterSource::eNone; - Map::updateLightAndSkyboxData(cullStage, cameraVec3, stateForConditions, areaRecord); + Map::updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); mathfu::vec4 ambient = mathfu::vec4(1.0,1.0,1.0,1.0); - auto frameDepedantData = cullStage->frameDependentData; + auto frameDependantData = mapRenderPlan->frameDependentData; - frameDepedantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorDirectColor = mathfu::vec4(0.3,0.30,0.3,0.3); - frameDepedantData->exteriorDirectColorDir = MathHelper::calcExteriorColorDir( - cullStage->matricesForCulling->lookAtMat, + frameDependantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->exteriorDirectColor = mathfu::vec4(0.3, 0.30, 0.3, 0.3); + frameDependantData->exteriorDirectColorDir = MathHelper::calcExteriorColorDir( + mapRenderPlan->renderingMatrices->lookAtMat, m_api->getConfig()->currentTime ); } \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.h b/wowViewerLib/src/engine/objects/scenes/wmoScene.h index 9d21cc600..b592d1c2a 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.h +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.h @@ -17,13 +17,13 @@ class WmoScene : public Map { void getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) override; void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HCullStage &cullStage, + HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) override; public: @@ -72,8 +72,8 @@ class WmoScene : public Map { } - void updateLightAndSkyboxData(const HCullStage &cullStage, mathfu::vec3 &cameraVec3, - StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; + void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 914f37a00..4f7016f78 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -414,13 +414,13 @@ void WmoGroupObject::createMeshes() { vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); - vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ WMO::modelWideBlockVS &blockVS = self->getObject(); blockVS.uPlacementMat = *m_modelMatrix; }); fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockPS)); - fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ WMO::modelWideBlockPS &blockPS = self->getObject(); blockPS.intLight.uInteriorAmbientColorAndApplyInteriorLight = mathfu::vec4_packed( @@ -530,14 +530,14 @@ void WmoGroupObject::createMeshes() { HGMesh hmesh = device->createMesh(meshTemplate); this->m_meshArray.push_back(hmesh); - hmesh->getUniformBuffer(2)->setUpdateHandler([this, &material, vertexShader](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData){ + hmesh->getUniformBuffer(2)->setUpdateHandler([this, &material, vertexShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ WMO::meshWideBlockVS &blockVS = self->getObject(); blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; blockVS.VertexShader = vertexShader; }); - hmesh->getUniformBuffer(4)->setUpdateHandler([this, isBatchA, isBatchC, &material, blendMode, pixelShader](IUniformBufferChunk *self, const HFrameDepedantData &frameDepedantData) { + hmesh->getUniformBuffer(4)->setUpdateHandler([this, isBatchA, isBatchC, &material, blendMode, pixelShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { // mathfu::vec4 globalAmbientColor = m_api->getGlobalAmbientColor(); mathfu::vec4 localambientColor = this->getAmbientColor(); mathfu::vec3 directLight = mathfu::vec3(0,0,0); @@ -695,7 +695,7 @@ void WmoGroupObject::createWaterMeshes() { auto l_liquidType = liquid_type; - meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, liquidFlags, color](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData) -> void { + meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, liquidFlags, color](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) -> void { mathfu::vec4_packed &color_ = self->getObject(); if ((liquidFlags & 1024) > 0) {// Ocean color_ = frameDepedantData->closeOceanColor; diff --git a/wowViewerLib/src/gapi/IDeviceFactory.cpp b/wowViewerLib/src/gapi/IDeviceFactory.cpp index b2177340a..c6016870e 100644 --- a/wowViewerLib/src/gapi/IDeviceFactory.cpp +++ b/wowViewerLib/src/gapi/IDeviceFactory.cpp @@ -5,8 +5,13 @@ #include "IDeviceFactory.h" +#ifdef LINK_OGL2 #include "ogl2.0/GDeviceGL20.h" +#endif + +#ifdef LINK_OGL3 #include "ogl3.3/GDeviceGL33.h" +#endif #ifdef LINK_OGL4 #include "ogl4.x/GDeviceGL4x.h" #endif diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index e8af6f5f9..7dd8fed0c 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -56,7 +56,6 @@ typedef std::shared_ptr HFrameBuffer; #include "../../engine/texture/BlpTexture.h" #include "textures/ITexture.h" #include "IFrameBuffer.h" -#include "../../engine/DrawStage.h" struct M2ShaderCacheRecord { int vertexShader; @@ -150,11 +149,6 @@ class IDevice { virtual void initialize() = 0; virtual void reset() = 0; - virtual unsigned int getFrameNumber() = 0; - virtual unsigned int getUpdateFrameNumber() = 0; - virtual unsigned int getOcclusionFrameNumber() = 0; - virtual unsigned int getCullingFrameNumber() = 0; - virtual unsigned int getDrawFrameNumber() = 0; virtual bool getIsAsynBuffUploadSupported() = 0; virtual int getMaxSamplesCnt() = 0; @@ -175,10 +169,10 @@ class IDevice { virtual void startUpdateForNextFrame() {}; virtual void endUpdateForNextFrame() {}; - virtual void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData)= 0; +// virtual void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData)= 0; virtual void uploadTextureForMeshes(std::vector &meshes) = 0; virtual void drawMeshes(std::vector &meshes) = 0; - virtual void drawStageAndDeps(HDrawStage drawStage) = 0; +// virtual void drawStageAndDeps(HDrawStage drawStage) = 0; virtual bool getIsCompressedTexturesSupported(); virtual bool getIsAnisFiltrationSupported(); diff --git a/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h index ec4e9d49c..e3d957cab 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h +++ b/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h @@ -7,9 +7,9 @@ #include #include -#include "../../../engine/DrawStage.h" +#include "../../../renderer/mapScene/FrameDependentData.h" -typedef std::function IChunkHandlerType; +typedef std::function IChunkHandlerType; class IUniformBufferChunk { friend class IDevice; @@ -53,7 +53,7 @@ class IUniformBufferChunk { virtual void setUpdateHandler(IChunkHandlerType handler) { m_handler = handler; }; - virtual void update(const HFrameDepedantData &frameDepedantData) { + virtual void update(const HFrameDependantData &frameDepedantData) { if (m_handler) { m_handler(this, frameDepedantData); } diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp index efab3333e..912b4f377 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp @@ -233,7 +233,7 @@ void GDeviceGL20::drawMeshes(std::vector &meshes) { // } } -void GDeviceGL20::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { +void GDeviceGL20::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { int fullSize = 0; for (int i = 0; i < bufferChunks.size(); i++) { diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h index b7d83ef3e..6ba7c4750 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h @@ -50,11 +50,11 @@ class GDeviceGL20 : public IDevice { void initialize() override; void reset() override; - unsigned int getFrameNumber() override { return m_frameNumber; }; - unsigned int getUpdateFrameNumber() override; - unsigned int getCullingFrameNumber() override; - unsigned int getOcclusionFrameNumber() override; - unsigned int getDrawFrameNumber() override; + unsigned int getFrameNumber() { return m_frameNumber; }; + unsigned int getUpdateFrameNumber() ; + unsigned int getCullingFrameNumber() ; + unsigned int getOcclusionFrameNumber() ; + unsigned int getDrawFrameNumber() ; void increaseFrameNumber() override; @@ -76,7 +76,7 @@ class GDeviceGL20 : public IDevice { void bindTexture(ITexture *texture, int slot) override; - void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) override; + void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec); void uploadTextureForMeshes(std::vector &meshes) override; void drawMeshes(std::vector &meshes) override; void drawStageAndDeps(HDrawStage drawStage) override; diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp index 5b5ec3332..31d41cffc 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp @@ -331,7 +331,7 @@ void GDeviceGL33::drawMeshes(std::vector &meshes) { } #ifdef SINGLE_BUFFER_UPLOAD -void GDeviceGL33::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { +void GDeviceGL33::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { int fullSize = 0; int fullTargetSize = 0; for (int i = 0; i < bufferChunks.size(); i++) { @@ -411,7 +411,7 @@ void GDeviceGL33::updateBuffers(std::vector*> } #else -void GDeviceGL33::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { +void GDeviceGL33::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) { aggregationBufferForUpload.resize(maxUniformBufferSize); uploadAmountInBytes = 0; diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h index 13c91dc47..319d32ea3 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h @@ -96,7 +96,7 @@ class GDeviceGL33 : public IDevice, public std::enable_shared_from_this*> &bufferChunks, std::vector &frameDepedantDataVec) override; + void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantDataVec) override; void uploadTextureForMeshes(std::vector &meshes) override; void drawMeshes(std::vector &meshes) override; void drawStageAndDeps(HDrawStage drawStage) override; diff --git a/wowViewerLib/src/gapi/ogl3.3/GVertexBufferBindingsGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GVertexBufferBindingsGL33.cpp index 0f729a542..305986a2b 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GVertexBufferBindingsGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GVertexBufferBindingsGL33.cpp @@ -78,7 +78,6 @@ void GVertexBufferBindingsGL33::save() { } } - m_device->bindVertexBufferBindings(nullptr); } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index a9f5e3b95..0b3f0df7d 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -958,7 +958,7 @@ void GDeviceVLK::endUpdateForNextFrame() { } typedef std::shared_ptr HVKMesh; -void GDeviceVLK::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData) { +void GDeviceVLK::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData) { // aggregationBufferForUpload.resize(maxUniformBufferSize); if (!m_blackPixelTexture) { m_blackPixelTexture = createTexture(false, false); @@ -1300,7 +1300,6 @@ void GDeviceVLK::commitFrame() { int currentDrawFrame = getDrawFrameNumber(); - uint32_t imageIndex; VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame], VK_NULL_HANDLE, &imageIndex); @@ -1596,342 +1595,342 @@ GDeviceVLK::createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int return newPool->allocate(layout, uniforms, images); } -void GDeviceVLK::internalDrawStageAndDeps(HDrawStage drawStage) { - //Draw deps - for (int i = 0; i < drawStage->drawStageDependencies.size(); i++) { - this->internalDrawStageAndDeps(drawStage->drawStageDependencies[i]); - } - - this->setInvertZ(drawStage->invertedZ); - - if (drawStage->clearScreen) { - clearColor[0] = drawStage->clearColor[0]; - clearColor[1] = drawStage->clearColor[1]; - clearColor[2] = drawStage->clearColor[2]; - } - - int updateFrame = getUpdateFrameNumber(); - auto commandBufferForFilling = renderCommandBuffers[updateFrame]; - //Default renderPass for rendering to screen framebuffers - std::shared_ptr renderPass = swapchainRenderPass; - - if (drawStage->target != nullptr) { - commandBufferForFilling = renderCommandBuffersForFrameBuffers[updateFrame]; - - GFrameBufferVLK *frameBufferVlk = dynamic_cast(drawStage->target.get()); - - renderPass = frameBufferVlk->m_renderPass; - - std::vector clearValues = renderPass->produceClearColorVec( - { clearColor[0], clearColor[1], clearColor[2] }, - drawStage->invertedZ ? 0.0f : 1.0f - ); - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.pNext = NULL; - renderPassInfo.renderPass = renderPass->getRenderPass(); - renderPassInfo.framebuffer = frameBufferVlk->m_frameBuffer; - renderPassInfo.renderArea.offset = {drawStage->viewPortDimensions.mins[0], drawStage->viewPortDimensions.mins[1]}; - renderPassInfo.renderArea.extent = {static_cast(drawStage->viewPortDimensions.maxs[0]), static_cast(drawStage->viewPortDimensions.maxs[1])}; - renderPassInfo.clearValueCount = clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); - - vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - } - - std::array viewportsForThisStage; - - VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; - usualViewport.width = drawStage->viewPortDimensions.maxs[0]; - usualViewport.height = drawStage->viewPortDimensions.maxs[1]; - usualViewport.x = drawStage->viewPortDimensions.mins[0]; - usualViewport.y = drawStage->viewPortDimensions.mins[1]; - if (!getInvertZ()) { - usualViewport.minDepth = 0; - usualViewport.maxDepth = 0.990f; - } else { - usualViewport.minDepth = 0.06f; - usualViewport.maxDepth = 1.0f; - } - - VkViewport &mapAreaViewport = viewportsForThisStage[(int)ViewportType::vp_mapArea]; - mapAreaViewport = usualViewport; - if (!getInvertZ()) { - mapAreaViewport.minDepth = 0.991f; - mapAreaViewport.maxDepth = 0.996f; - } else { - mapAreaViewport.minDepth = 0.04f; - mapAreaViewport.maxDepth = 0.05f; - } - - VkViewport &skyBoxViewport = viewportsForThisStage[(int)ViewportType::vp_skyBox]; - skyBoxViewport = usualViewport; - if (!getInvertZ()) { - skyBoxViewport.minDepth = 0.997f; - skyBoxViewport.maxDepth = 1.0f; - } else { - skyBoxViewport.minDepth = 0; - skyBoxViewport.maxDepth = 0.03f; - } - - - //Set scissors - VkRect2D defaultScissor = {}; - defaultScissor.offset = {0, 0}; - defaultScissor.extent = { - static_cast(drawStage->viewPortDimensions.maxs[0]), - static_cast(drawStage->viewPortDimensions.maxs[1]) - }; - - vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); - - //Set new viewport - vkCmdSetViewport(commandBufferForFilling, 0, 1, &usualViewport); - - bool atLeastOneDrawCall = false; - if (drawStage->opaqueMeshes != nullptr) - atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, - drawStage->opaqueMeshes, viewportsForThisStage, - defaultScissor) || atLeastOneDrawCall; - if (drawStage->transparentMeshes != nullptr) - atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, - drawStage->transparentMeshes, viewportsForThisStage, - defaultScissor) || atLeastOneDrawCall; - - if (drawStage->target != nullptr) { - vkCmdEndRenderPass(commandBufferForFilling); - renderCommandBuffersForFrameBuffersNotNull[updateFrame] = renderCommandBuffersForFrameBuffersNotNull[updateFrame] || atLeastOneDrawCall; - } else { - renderCommandBuffersNotNull[updateFrame] = renderCommandBuffersNotNull[updateFrame] || atLeastOneDrawCall; - } - -} +//void GDeviceVLK::internalDrawStageAndDeps(HDrawStage drawStage) { +// //Draw deps +// for (int i = 0; i < drawStage->drawStageDependencies.size(); i++) { +// this->internalDrawStageAndDeps(drawStage->drawStageDependencies[i]); +// } +// +// this->setInvertZ(drawStage->invertedZ); +// +// if (drawStage->clearScreen) { +// clearColor[0] = drawStage->clearColor[0]; +// clearColor[1] = drawStage->clearColor[1]; +// clearColor[2] = drawStage->clearColor[2]; +// } +// +// int updateFrame = getUpdateFrameNumber(); +// auto commandBufferForFilling = renderCommandBuffers[updateFrame]; +// //Default renderPass for rendering to screen framebuffers +// std::shared_ptr renderPass = swapchainRenderPass; +// +// if (drawStage->target != nullptr) { +// commandBufferForFilling = renderCommandBuffersForFrameBuffers[updateFrame]; +// +// GFrameBufferVLK *frameBufferVlk = dynamic_cast(drawStage->target.get()); +// +// renderPass = frameBufferVlk->m_renderPass; +// +// std::vector clearValues = renderPass->produceClearColorVec( +// { clearColor[0], clearColor[1], clearColor[2] }, +// drawStage->invertedZ ? 0.0f : 1.0f +// ); +// +// VkRenderPassBeginInfo renderPassInfo = {}; +// renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; +// renderPassInfo.pNext = NULL; +// renderPassInfo.renderPass = renderPass->getRenderPass(); +// renderPassInfo.framebuffer = frameBufferVlk->m_frameBuffer; +// renderPassInfo.renderArea.offset = {drawStage->viewPortDimensions.mins[0], drawStage->viewPortDimensions.mins[1]}; +// renderPassInfo.renderArea.extent = {static_cast(drawStage->viewPortDimensions.maxs[0]), static_cast(drawStage->viewPortDimensions.maxs[1])}; +// renderPassInfo.clearValueCount = clearValues.size(); +// renderPassInfo.pClearValues = clearValues.data(); +// +// vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); +// } +// +// std::array viewportsForThisStage; +// +// VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; +// usualViewport.width = drawStage->viewPortDimensions.maxs[0]; +// usualViewport.height = drawStage->viewPortDimensions.maxs[1]; +// usualViewport.x = drawStage->viewPortDimensions.mins[0]; +// usualViewport.y = drawStage->viewPortDimensions.mins[1]; +// if (!getInvertZ()) { +// usualViewport.minDepth = 0; +// usualViewport.maxDepth = 0.990f; +// } else { +// usualViewport.minDepth = 0.06f; +// usualViewport.maxDepth = 1.0f; +// } +// +// VkViewport &mapAreaViewport = viewportsForThisStage[(int)ViewportType::vp_mapArea]; +// mapAreaViewport = usualViewport; +// if (!getInvertZ()) { +// mapAreaViewport.minDepth = 0.991f; +// mapAreaViewport.maxDepth = 0.996f; +// } else { +// mapAreaViewport.minDepth = 0.04f; +// mapAreaViewport.maxDepth = 0.05f; +// } +// +// VkViewport &skyBoxViewport = viewportsForThisStage[(int)ViewportType::vp_skyBox]; +// skyBoxViewport = usualViewport; +// if (!getInvertZ()) { +// skyBoxViewport.minDepth = 0.997f; +// skyBoxViewport.maxDepth = 1.0f; +// } else { +// skyBoxViewport.minDepth = 0; +// skyBoxViewport.maxDepth = 0.03f; +// } +// +// +// //Set scissors +// VkRect2D defaultScissor = {}; +// defaultScissor.offset = {0, 0}; +// defaultScissor.extent = { +// static_cast(drawStage->viewPortDimensions.maxs[0]), +// static_cast(drawStage->viewPortDimensions.maxs[1]) +// }; +// +// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); +// +// //Set new viewport +// vkCmdSetViewport(commandBufferForFilling, 0, 1, &usualViewport); +// +// bool atLeastOneDrawCall = false; +// if (drawStage->opaqueMeshes != nullptr) +// atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, +// drawStage->opaqueMeshes, viewportsForThisStage, +// defaultScissor) || atLeastOneDrawCall; +// if (drawStage->transparentMeshes != nullptr) +// atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, +// drawStage->transparentMeshes, viewportsForThisStage, +// defaultScissor) || atLeastOneDrawCall; +// +// if (drawStage->target != nullptr) { +// vkCmdEndRenderPass(commandBufferForFilling); +// renderCommandBuffersForFrameBuffersNotNull[updateFrame] = renderCommandBuffersForFrameBuffersNotNull[updateFrame] || atLeastOneDrawCall; +// } else { +// renderCommandBuffersNotNull[updateFrame] = renderCommandBuffersNotNull[updateFrame] || atLeastOneDrawCall; +// } +// +//} //Returns true if at least once command was written to buffer -bool GDeviceVLK::drawMeshesInternal( - const HDrawStage &drawStage, - VkCommandBuffer commandBufferForFilling, - std::shared_ptr renderPass, - const HMeshesToRender &meshes, - const std::array &viewportsForThisStage, - VkRect2D &defaultScissor) { - - int updateFrame = getUpdateFrameNumber(); - - ViewportType lastViewPort = ViewportType::vp_none; - - VkBuffer lastIndexBuffer = VK_NULL_HANDLE; - VkBuffer lastVertexBuffer = VK_NULL_HANDLE; - int8_t lastIsScissorsEnabled = -1; - std::shared_ptr lastPipeline = nullptr; -// uint32_t dynamicOffset[7] = {}; - - auto &iMeshes = meshes->meshes; - - auto dynamicOffsetPerMesh = std::vector>(iMeshes.size()); - auto uboIndPerMesh = std::vector(iMeshes.size()); - - tbb::parallel_for( - tbb::blocked_range(0, iMeshes.size(), 500), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); - auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); - uint32_t uboInd = 0; - auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); - if (uboB) { - dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); - } - - for (int k = 1; k < 6; k++) { - if (shaderVLK->hasBondUBO[k]) { - auto *uboB = (meshVLK->getUniformBuffer(k).get()); - if (uboB) { - dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); - } - } - } - uboIndPerMesh[i] = uboInd; - } - }, tbb::simple_partitioner()); - - bool atLeastOneDrawcall = false; - VkDeviceSize offsets[] = {0}; - - for (int i = 0; i < iMeshes.size(); i++) { - auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); -// auto *meshVLK = ((GMeshVLK *)mesh.get()); - auto *binding = ((GVertexBufferBindingsVLK *)meshVLK->m_bindings.get()); - auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); - -// uint32_t uboInd = 0; -// auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); -// if (uboB) { -// dynamicOffset[uboInd++] = (uboB)->getOffset(); +//bool GDeviceVLK::drawMeshesInternal( +// const HDrawStage &drawStage, +// VkCommandBuffer commandBufferForFilling, +// std::shared_ptr renderPass, +// const HMeshesToRender &meshes, +// const std::array &viewportsForThisStage, +// VkRect2D &defaultScissor) { +// +// int updateFrame = getUpdateFrameNumber(); +// +// ViewportType lastViewPort = ViewportType::vp_none; +// +// VkBuffer lastIndexBuffer = VK_NULL_HANDLE; +// VkBuffer lastVertexBuffer = VK_NULL_HANDLE; +// int8_t lastIsScissorsEnabled = -1; +// std::shared_ptr lastPipeline = nullptr; +//// uint32_t dynamicOffset[7] = {}; +// +// auto &iMeshes = meshes->meshes; +// +// auto dynamicOffsetPerMesh = std::vector>(iMeshes.size()); +// auto uboIndPerMesh = std::vector(iMeshes.size()); +// +// tbb::parallel_for( +// tbb::blocked_range(0, iMeshes.size(), 500), +// [&](tbb::blocked_range r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { +// auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); +// auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); +// uint32_t uboInd = 0; +// auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); +// if (uboB) { +// dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); +// } +// +// for (int k = 1; k < 6; k++) { +// if (shaderVLK->hasBondUBO[k]) { +// auto *uboB = (meshVLK->getUniformBuffer(k).get()); +// if (uboB) { +// dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); +// } +// } +// } +// uboIndPerMesh[i] = uboInd; +// } +// }, tbb::simple_partitioner()); +// +// bool atLeastOneDrawcall = false; +// VkDeviceSize offsets[] = {0}; +// +// for (int i = 0; i < iMeshes.size(); i++) { +// auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); +//// auto *meshVLK = ((GMeshVLK *)mesh.get()); +// auto *binding = ((GVertexBufferBindingsVLK *)meshVLK->m_bindings.get()); +// auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); +// +//// uint32_t uboInd = 0; +//// auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); +//// if (uboB) { +//// dynamicOffset[uboInd++] = (uboB)->getOffset(); +//// } +//// +//// for (int k = 1; k < 6; k++) { +//// if (shaderVLK->hasBondUBO[k]) { +//// auto *uboB = (meshVLK->getUniformBuffer(k).get()); +//// if (uboB) { +//// dynamicOffset[uboInd++] = (uboB)->getOffset(); +//// } +//// } +//// } +// +// std::shared_ptr h_pipeLine = meshVLK->getPipeLineForRenderPass(renderPass, drawStage->invertedZ); +// +// if (lastPipeline != h_pipeLine) { +// vkCmdBindPipeline(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, +// h_pipeLine->graphicsPipeline); +// +// lastPipeline = h_pipeLine; // } // -// for (int k = 1; k < 6; k++) { -// if (shaderVLK->hasBondUBO[k]) { -// auto *uboB = (meshVLK->getUniformBuffer(k).get()); -// if (uboB) { -// dynamicOffset[uboInd++] = (uboB)->getOffset(); -// } +// ViewportType newViewPort = meshVLK->m_isSkyBox ? ViewportType::vp_skyBox : ViewportType::vp_usual; +// if (lastViewPort != newViewPort) { +// if (viewportsForThisStage[+newViewPort].height > 32768) { +// std::cout << "newViewPort = " << +newViewPort << std::endl; // } +// vkCmdSetViewport(commandBufferForFilling, 0, 1, &viewportsForThisStage[+newViewPort]); +// +// lastViewPort = newViewPort; // } - - std::shared_ptr h_pipeLine = meshVLK->getPipeLineForRenderPass(renderPass, drawStage->invertedZ); - - if (lastPipeline != h_pipeLine) { - vkCmdBindPipeline(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, - h_pipeLine->graphicsPipeline); - - lastPipeline = h_pipeLine; - } - - ViewportType newViewPort = meshVLK->m_isSkyBox ? ViewportType::vp_skyBox : ViewportType::vp_usual; - if (lastViewPort != newViewPort) { - if (viewportsForThisStage[+newViewPort].height > 32768) { - std::cout << "newViewPort = " << +newViewPort << std::endl; - } - vkCmdSetViewport(commandBufferForFilling, 0, 1, &viewportsForThisStage[+newViewPort]); - - lastViewPort = newViewPort; - } - - - if (meshVLK->m_isScissorsEnabled > 0) { - VkRect2D rect; - rect.offset.x = meshVLK->m_scissorOffset[0]; - rect.offset.y = meshVLK->m_scissorOffset[1]; - rect.extent.width = meshVLK->m_scissorSize[0]; - rect.extent.height = meshVLK->m_scissorSize[1]; - - vkCmdSetScissor(commandBufferForFilling, 0, 1, &rect); - } else if (lastIsScissorsEnabled != meshVLK->m_isScissorsEnabled) { - vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); - } - lastIsScissorsEnabled = meshVLK->m_isScissorsEnabled; - - - auto indexBuffer = ((GIndexBufferVLK *)binding->m_indexBuffer.get())->g_hIndexBuffer; - auto vertexBuffer = ((GVertexBufferVLK *)binding->m_bindings[0].vertexBuffer.get())->g_hVertexBuffer; - - - if (lastIndexBuffer != indexBuffer) { - vkCmdBindIndexBuffer(commandBufferForFilling, indexBuffer, 0, VK_INDEX_TYPE_UINT16); - lastIndexBuffer = indexBuffer; - } - - if (lastVertexBuffer != vertexBuffer) { - uint32_t vboBind = 0; - - vkCmdBindVertexBuffers(commandBufferForFilling, vboBind++, 1, &vertexBuffer, offsets); - lastVertexBuffer = vertexBuffer; - } - - auto uboDescSet = shaderVLK->uboDescriptorSets[updateFrame]->getDescSet(); - auto imageDescSet = meshVLK->imageDescriptorSets[updateFrame]->getDescSet(); - - atLeastOneDrawcall = true; - - //UBO - vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, - h_pipeLine->pipelineLayout, 0, 1, &uboDescSet, uboIndPerMesh[i], dynamicOffsetPerMesh[i].data()); - - //Image - vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, - h_pipeLine->pipelineLayout, 1, 1, &imageDescSet, 0, nullptr); - - vkCmdDrawIndexed(commandBufferForFilling, meshVLK->m_end, 1, meshVLK->m_start/2, 0, 0); - } - - return atLeastOneDrawcall; -} - -void GDeviceVLK::drawStageAndDeps(HDrawStage drawStage) { - int updateFrame = getUpdateFrameNumber(); - -// std::cout << "drawStageAndDeps: updateFrame = " << updateFrame << std::endl; - - if (drawStage->target == nullptr && - ( - (drawStage->viewPortDimensions.maxs[0] != swapChainExtent.width) || - (drawStage->viewPortDimensions.maxs[1] != swapChainExtent.height) - ) - ) { - recreateSwapChain(); - } - - vkWaitForFences(device, 1, &inFlightFences[updateFrame], VK_TRUE, std::numeric_limits::max()); - - //Update - if (m_shaderDescriptorUpdateNeeded) { - for (auto shaderVLKRec : m_shaderPermutCache) { - ((GShaderPermutationVLK *) shaderVLKRec.second.get())->updateDescriptorSet(updateFrame); - } - m_shaderDescriptorUpdateNeeded = false; - } - - auto commandBufferForFilling = renderCommandBuffers[updateFrame]; - auto commandBufferForFillingFrameBuf = renderCommandBuffersForFrameBuffers[updateFrame]; - - renderCommandBuffersNotNull[updateFrame] = false; - renderCommandBuffersForFrameBuffersNotNull[updateFrame] = false; - - { - VkCommandBufferInheritanceInfo bufferInheritanceInfo; - bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - bufferInheritanceInfo.pNext = nullptr; - bufferInheritanceInfo.renderPass = swapchainRenderPass->getRenderPass(); - bufferInheritanceInfo.subpass = 0; - bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; - bufferInheritanceInfo.occlusionQueryEnable = false; - bufferInheritanceInfo.queryFlags = 0; - bufferInheritanceInfo.pipelineStatistics = 0; - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = &bufferInheritanceInfo; - - if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } - } - - { - VkCommandBufferInheritanceInfo bufferInheritanceInfo; - bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - bufferInheritanceInfo.pNext = nullptr; - bufferInheritanceInfo.renderPass = VK_NULL_HANDLE; - bufferInheritanceInfo.subpass = 0; - bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; - bufferInheritanceInfo.occlusionQueryEnable = false; - bufferInheritanceInfo.queryFlags = 0; - bufferInheritanceInfo.pipelineStatistics = 0; - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = &bufferInheritanceInfo; - - if (vkBeginCommandBuffer(commandBufferForFillingFrameBuf, &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } - } - - internalDrawStageAndDeps(drawStage); - - if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } - if (vkEndCommandBuffer(commandBufferForFillingFrameBuf) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } -} +// +// +// if (meshVLK->m_isScissorsEnabled > 0) { +// VkRect2D rect; +// rect.offset.x = meshVLK->m_scissorOffset[0]; +// rect.offset.y = meshVLK->m_scissorOffset[1]; +// rect.extent.width = meshVLK->m_scissorSize[0]; +// rect.extent.height = meshVLK->m_scissorSize[1]; +// +// vkCmdSetScissor(commandBufferForFilling, 0, 1, &rect); +// } else if (lastIsScissorsEnabled != meshVLK->m_isScissorsEnabled) { +// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); +// } +// lastIsScissorsEnabled = meshVLK->m_isScissorsEnabled; +// +// +// auto indexBuffer = ((GIndexBufferVLK *)binding->m_indexBuffer.get())->g_hIndexBuffer; +// auto vertexBuffer = ((GVertexBufferVLK *)binding->m_bindings[0].vertexBuffer.get())->g_hVertexBuffer; +// +// +// if (lastIndexBuffer != indexBuffer) { +// vkCmdBindIndexBuffer(commandBufferForFilling, indexBuffer, 0, VK_INDEX_TYPE_UINT16); +// lastIndexBuffer = indexBuffer; +// } +// +// if (lastVertexBuffer != vertexBuffer) { +// uint32_t vboBind = 0; +// +// vkCmdBindVertexBuffers(commandBufferForFilling, vboBind++, 1, &vertexBuffer, offsets); +// lastVertexBuffer = vertexBuffer; +// } +// +// auto uboDescSet = shaderVLK->uboDescriptorSets[updateFrame]->getDescSet(); +// auto imageDescSet = meshVLK->imageDescriptorSets[updateFrame]->getDescSet(); +// +// atLeastOneDrawcall = true; +// +// //UBO +// vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, +// h_pipeLine->pipelineLayout, 0, 1, &uboDescSet, uboIndPerMesh[i], dynamicOffsetPerMesh[i].data()); +// +// //Image +// vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, +// h_pipeLine->pipelineLayout, 1, 1, &imageDescSet, 0, nullptr); +// +// vkCmdDrawIndexed(commandBufferForFilling, meshVLK->m_end, 1, meshVLK->m_start/2, 0, 0); +// } +// +// return atLeastOneDrawcall; +//} +// +//void GDeviceVLK::drawStageAndDeps(HDrawStage drawStage) { +// int updateFrame = getUpdateFrameNumber(); +// +//// std::cout << "drawStageAndDeps: updateFrame = " << updateFrame << std::endl; +// +// if (drawStage->target == nullptr && +// ( +// (drawStage->viewPortDimensions.maxs[0] != swapChainExtent.width) || +// (drawStage->viewPortDimensions.maxs[1] != swapChainExtent.height) +// ) +// ) { +// recreateSwapChain(); +// } +// +// vkWaitForFences(device, 1, &inFlightFences[updateFrame], VK_TRUE, std::numeric_limits::max()); +// +// //Update +// if (m_shaderDescriptorUpdateNeeded) { +// for (auto shaderVLKRec : m_shaderPermutCache) { +// ((GShaderPermutationVLK *) shaderVLKRec.second.get())->updateDescriptorSet(updateFrame); +// } +// m_shaderDescriptorUpdateNeeded = false; +// } +// +// auto commandBufferForFilling = renderCommandBuffers[updateFrame]; +// auto commandBufferForFillingFrameBuf = renderCommandBuffersForFrameBuffers[updateFrame]; +// +// renderCommandBuffersNotNull[updateFrame] = false; +// renderCommandBuffersForFrameBuffersNotNull[updateFrame] = false; +// +// { +// VkCommandBufferInheritanceInfo bufferInheritanceInfo; +// bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; +// bufferInheritanceInfo.pNext = nullptr; +// bufferInheritanceInfo.renderPass = swapchainRenderPass->getRenderPass(); +// bufferInheritanceInfo.subpass = 0; +// bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; +// bufferInheritanceInfo.occlusionQueryEnable = false; +// bufferInheritanceInfo.queryFlags = 0; +// bufferInheritanceInfo.pipelineStatistics = 0; +// +// VkCommandBufferBeginInfo beginInfo = {}; +// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; +// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; +// beginInfo.pNext = NULL; +// beginInfo.pInheritanceInfo = &bufferInheritanceInfo; +// +// if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { +// throw std::runtime_error("failed to begin recording command buffer!"); +// } +// } +// +// { +// VkCommandBufferInheritanceInfo bufferInheritanceInfo; +// bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; +// bufferInheritanceInfo.pNext = nullptr; +// bufferInheritanceInfo.renderPass = VK_NULL_HANDLE; +// bufferInheritanceInfo.subpass = 0; +// bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; +// bufferInheritanceInfo.occlusionQueryEnable = false; +// bufferInheritanceInfo.queryFlags = 0; +// bufferInheritanceInfo.pipelineStatistics = 0; +// +// VkCommandBufferBeginInfo beginInfo = {}; +// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; +// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; +// beginInfo.pNext = NULL; +// beginInfo.pInheritanceInfo = &bufferInheritanceInfo; +// +// if (vkBeginCommandBuffer(commandBufferForFillingFrameBuf, &beginInfo) != VK_SUCCESS) { +// throw std::runtime_error("failed to begin recording command buffer!"); +// } +// } +// +// internalDrawStageAndDeps(drawStage); +// +// if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { +// throw std::runtime_error("failed to record command buffer!"); +// } +// if (vkEndCommandBuffer(commandBufferForFillingFrameBuf) != VK_SUCCESS) { +// throw std::runtime_error("failed to record command buffer!"); +// } +//} void GDeviceVLK::initUploadThread() { if (getIsAsynBuffUploadSupported()) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 2c1266b5f..d2c595217 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -68,11 +68,11 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this*> &bufferChunks, std::vector &frameDepedantData) override; + void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; void drawMeshes(std::vector &meshes) override; - void drawStageAndDeps(HDrawStage drawStage) override; +// void drawStageAndDeps(HDrawStage drawStage) override; bool wasTexturesUploaded() override { return m_texturesWereUploaded; }; @@ -239,7 +239,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback); private: void drawMesh(HGMesh &hmesh); - void internalDrawStageAndDeps(HDrawStage drawStage); +// void internalDrawStageAndDeps(HDrawStage drawStage); void setupDebugMessenger(); void pickPhysicalDevice(); @@ -269,13 +269,13 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this renderPass, - const HMeshesToRender &iMeshes, - const std::array &viewportsForThisStage, - VkRect2D &defaultScissor); +// bool drawMeshesInternal( +// const HDrawStage &drawStage, +// VkCommandBuffer commandBufferForFilling, +// std::shared_ptr renderPass, +// const HMeshesToRender &iMeshes, +// const std::array &viewportsForThisStage, +// VkRect2D &defaultScissor); protected: struct BlpCacheRecord { diff --git a/wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h b/wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h index 30cb9ac38..844bbff78 100644 --- a/wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h +++ b/wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2017-2022 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 @@ -23,18 +23,14 @@ #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H #define AMD_VULKAN_MEMORY_ALLOCATOR_H -#ifdef __cplusplus -extern "C" { -#endif - /** \mainpage Vulkan Memory Allocator -Version 3.0.0-development (2020-03-23) +Version 3.1.0-development -Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved. \n +Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved. \n License: MIT -Documentation of all members: vk_mem_alloc.h +API documentation divided into groups: [Modules](modules.html) \section main_table_of_contents Table of contents @@ -53,10 +49,10 @@ Documentation of all members: vk_mem_alloc.h - [Mapping functions](@ref memory_mapping_mapping_functions) - [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory) - [Cache flush and invalidate](@ref memory_mapping_cache_control) - - [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable) - \subpage staying_within_budget - [Querying for budget](@ref staying_within_budget_querying_for_budget) - [Controlling memory usage](@ref staying_within_budget_controlling_memory_usage) + - \subpage resource_aliasing - \subpage custom_memory_pools - [Choosing memory type index](@ref custom_memory_pools_MemTypeIndex) - [Linear allocation algorithm](@ref linear_algorithm) @@ -64,5935 +60,6763 @@ Documentation of all members: vk_mem_alloc.h - [Stack](@ref linear_algorithm_stack) - [Double stack](@ref linear_algorithm_double_stack) - [Ring buffer](@ref linear_algorithm_ring_buffer) - - [Buddy allocation algorithm](@ref buddy_algorithm) - \subpage defragmentation - - [Defragmenting CPU memory](@ref defragmentation_cpu) - - [Defragmenting GPU memory](@ref defragmentation_gpu) - - [Additional notes](@ref defragmentation_additional_notes) - - [Writing custom allocation algorithm](@ref defragmentation_custom_algorithm) - - \subpage lost_allocations - \subpage statistics - [Numeric statistics](@ref statistics_numeric_statistics) - [JSON dump](@ref statistics_json_dump) - \subpage allocation_annotation - [Allocation user data](@ref allocation_user_data) - [Allocation names](@ref allocation_names) + - \subpage virtual_allocator - \subpage debugging_memory_usage - [Memory initialization](@ref debugging_memory_usage_initialization) - [Margins](@ref debugging_memory_usage_margins) - [Corruption detection](@ref debugging_memory_usage_corruption_detection) - - \subpage record_and_replay + - \subpage opengl_interop - \subpage usage_patterns - - [Common mistakes](@ref usage_patterns_common_mistakes) - - [Simple patterns](@ref usage_patterns_simple) - - [Advanced patterns](@ref usage_patterns_advanced) + - [GPU-only resource](@ref usage_patterns_gpu_only) + - [Staging copy for upload](@ref usage_patterns_staging_copy_upload) + - [Readback](@ref usage_patterns_readback) + - [Advanced data uploading](@ref usage_patterns_advanced_data_uploading) + - [Other use cases](@ref usage_patterns_other_use_cases) - \subpage configuration + - [Pointers to Vulkan functions](@ref config_Vulkan_functions) - [Custom host memory allocator](@ref custom_memory_allocator) - [Device memory allocation callbacks](@ref allocation_callbacks) - [Device heap memory limit](@ref heap_memory_limit) - - \subpage vk_khr_dedicated_allocation - - \subpage enabling_buffer_device_address - - \subpage vk_amd_device_coherent_memory +- Extension support + - \subpage vk_khr_dedicated_allocation + - \subpage enabling_buffer_device_address + - \subpage vk_ext_memory_priority + - \subpage vk_amd_device_coherent_memory - \subpage general_considerations - [Thread safety](@ref general_considerations_thread_safety) + - [Versioning and compatibility](@ref general_considerations_versioning_and_compatibility) - [Validation layer warnings](@ref general_considerations_validation_layer_warnings) - [Allocation algorithm](@ref general_considerations_allocation_algorithm) - [Features not supported](@ref general_considerations_features_not_supported) \section main_see_also See also -- [Product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) -- [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) +- [**Product page on GPUOpen**](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) +- [**Source repository on GitHub**](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) +\defgroup group_init Library initialization +\brief API elements related to the initialization and management of the entire library, especially #VmaAllocator object. +\defgroup group_alloc Memory allocation -\page quick_start Quick start - -\section quick_start_project_setup Project setup - -Vulkan Memory Allocator comes in form of a "stb-style" single header file. -You don't need to build it as a separate library project. -You can add this file directly to your project and submit it to code repository next to your other source files. +\brief API elements related to the allocation, deallocation, and management of Vulkan memory, buffers, images. +Most basic ones being: vmaCreateBuffer(), vmaCreateImage(). -"Single header" doesn't mean that everything is contained in C/C++ declarations, -like it tends to be in case of inline functions or C++ templates. -It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. -If you don't do it properly, you will get linker errors. +\defgroup group_virtual Virtual allocator -To do it properly: +\brief API elements related to the mechanism of \ref virtual_allocator - using the core allocation algorithm +for user-defined purpose without allocating any real GPU memory. --# Include "vk_mem_alloc.h" file in each CPP file where you want to use the library. - This includes declarations of all members of the library. --# In exacly one CPP file define following macro before this include. - It enables also internal definitions. +\defgroup group_stats Statistics -\code -#define VMA_IMPLEMENTATION -#include "vk_mem_alloc.h" -\endcode +\brief API elements that query current status of the allocator, from memory usage, budget, to full dump of the internal state in JSON format. +See documentation chapter: \ref statistics. +*/ -It may be a good idea to create dedicated CPP file just for this purpose. -Note on language: This library is written in C++, but has C-compatible interface. -Thus you can include and use vk_mem_alloc.h in C or C++ code, but full -implementation with `VMA_IMPLEMENTATION` macro must be compiled as C++, NOT as C. +#ifdef __cplusplus +extern "C" { +#endif -Please note that this library includes header ``, which in turn -includes `` on Windows. If you need some specific macros defined -before including these headers (like `WIN32_LEAN_AND_MEAN` or -`WINVER` for Windows, `VK_USE_PLATFORM_WIN32_KHR` for Vulkan), you must define -them before every `#include` of this library. +#ifndef VULKAN_H_ + #include +#endif +#if !defined(VMA_VULKAN_VERSION) + #if defined(VK_VERSION_1_3) + #define VMA_VULKAN_VERSION 1003000 + #elif defined(VK_VERSION_1_2) + #define VMA_VULKAN_VERSION 1002000 + #elif defined(VK_VERSION_1_1) + #define VMA_VULKAN_VERSION 1001000 + #else + #define VMA_VULKAN_VERSION 1000000 + #endif +#endif -\section quick_start_initialization Initialization +#if defined(__ANDROID__) && defined(VK_NO_PROTOTYPES) && VMA_STATIC_VULKAN_FUNCTIONS + extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; + extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; + extern PFN_vkAllocateMemory vkAllocateMemory; + extern PFN_vkFreeMemory vkFreeMemory; + extern PFN_vkMapMemory vkMapMemory; + extern PFN_vkUnmapMemory vkUnmapMemory; + extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + extern PFN_vkBindBufferMemory vkBindBufferMemory; + extern PFN_vkBindImageMemory vkBindImageMemory; + extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + extern PFN_vkCreateBuffer vkCreateBuffer; + extern PFN_vkDestroyBuffer vkDestroyBuffer; + extern PFN_vkCreateImage vkCreateImage; + extern PFN_vkDestroyImage vkDestroyImage; + extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + #if VMA_VULKAN_VERSION >= 1001000 + extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; + extern PFN_vkBindImageMemory2 vkBindImageMemory2; + extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; + #endif // #if VMA_VULKAN_VERSION >= 1001000 +#endif // #if defined(__ANDROID__) && VMA_STATIC_VULKAN_FUNCTIONS && VK_NO_PROTOTYPES -At program startup: +#if !defined(VMA_DEDICATED_ALLOCATION) + #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation + #define VMA_DEDICATED_ALLOCATION 1 + #else + #define VMA_DEDICATED_ALLOCATION 0 + #endif +#endif --# Initialize Vulkan to have `VkPhysicalDevice` and `VkDevice` object. --# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by - calling vmaCreateAllocator(). +#if !defined(VMA_BIND_MEMORY2) + #if VK_KHR_bind_memory2 + #define VMA_BIND_MEMORY2 1 + #else + #define VMA_BIND_MEMORY2 0 + #endif +#endif -\code -VmaAllocatorCreateInfo allocatorInfo = {}; -allocatorInfo.physicalDevice = physicalDevice; -allocatorInfo.device = device; +#if !defined(VMA_MEMORY_BUDGET) + #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) + #define VMA_MEMORY_BUDGET 1 + #else + #define VMA_MEMORY_BUDGET 0 + #endif +#endif -VmaAllocator allocator; -vmaCreateAllocator(&allocatorInfo, &allocator); -\endcode +// Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. +#if !defined(VMA_BUFFER_DEVICE_ADDRESS) + #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 + #define VMA_BUFFER_DEVICE_ADDRESS 1 + #else + #define VMA_BUFFER_DEVICE_ADDRESS 0 + #endif +#endif -\section quick_start_resource_allocation Resource allocation +// Defined to 1 when VK_EXT_memory_priority device extension is defined in Vulkan headers. +#if !defined(VMA_MEMORY_PRIORITY) + #if VK_EXT_memory_priority + #define VMA_MEMORY_PRIORITY 1 + #else + #define VMA_MEMORY_PRIORITY 0 + #endif +#endif -When you want to create a buffer or image: +// Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. +#if !defined(VMA_EXTERNAL_MEMORY) + #if VK_KHR_external_memory + #define VMA_EXTERNAL_MEMORY 1 + #else + #define VMA_EXTERNAL_MEMORY 0 + #endif +#endif --# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure. --# Fill VmaAllocationCreateInfo structure. --# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory - already allocated and bound to it. +// Define these macros to decorate all public functions with additional code, +// before and after returned type, appropriately. This may be useful for +// exporting the functions when compiling VMA as a separate library. Example: +// #define VMA_CALL_PRE __declspec(dllexport) +// #define VMA_CALL_POST __cdecl +#ifndef VMA_CALL_PRE + #define VMA_CALL_PRE +#endif +#ifndef VMA_CALL_POST + #define VMA_CALL_POST +#endif -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufferInfo.size = 65536; -bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; +// Define this macro to decorate pointers with an attribute specifying the +// length of the array they point to if they are not null. +// +// The length may be one of +// - The name of another parameter in the argument list where the pointer is declared +// - The name of another member in the struct where the pointer is declared +// - The name of a member of a struct type, meaning the value of that member in +// the context of the call. For example +// VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount"), +// this means the number of memory heaps available in the device associated +// with the VmaAllocator being dealt with. +#ifndef VMA_LEN_IF_NOT_NULL + #define VMA_LEN_IF_NOT_NULL(len) +#endif -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; +// The VMA_NULLABLE macro is defined to be _Nullable when compiling with Clang. +// see: https://clang.llvm.org/docs/AttributeReference.html#nullable +#ifndef VMA_NULLABLE + #ifdef __clang__ + #define VMA_NULLABLE _Nullable + #else + #define VMA_NULLABLE + #endif +#endif -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode +// The VMA_NOT_NULL macro is defined to be _Nonnull when compiling with Clang. +// see: https://clang.llvm.org/docs/AttributeReference.html#nonnull +#ifndef VMA_NOT_NULL + #ifdef __clang__ + #define VMA_NOT_NULL _Nonnull + #else + #define VMA_NOT_NULL + #endif +#endif -Don't forget to destroy your objects when no longer needed: +// If non-dispatchable handles are represented as pointers then we can give +// then nullability annotations +#ifndef VMA_NOT_NULL_NON_DISPATCHABLE + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL + #else + #define VMA_NOT_NULL_NON_DISPATCHABLE + #endif +#endif -\code -vmaDestroyBuffer(allocator, buffer, allocation); -vmaDestroyAllocator(allocator); -\endcode +#ifndef VMA_NULLABLE_NON_DISPATCHABLE + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE + #else + #define VMA_NULLABLE_NON_DISPATCHABLE + #endif +#endif +#ifndef VMA_STATS_STRING_ENABLED + #define VMA_STATS_STRING_ENABLED 1 +#endif -\page choosing_memory_type Choosing memory type +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// INTERFACE +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// -Physical devices in Vulkan support various combinations of memory heaps and -types. Help with choosing correct and optimal memory type for your specific -resource is one of the key features of this library. You can use it by filling -appropriate members of VmaAllocationCreateInfo structure, as described below. -You can also combine multiple methods. +// Sections for managing code placement in file, only for development purposes e.g. for convenient folding inside an IDE. +#ifndef _VMA_ENUM_DECLARATIONS --# If you just want to find memory type index that meets your requirements, you - can use function: vmaFindMemoryTypeIndex(), vmaFindMemoryTypeIndexForBufferInfo(), - vmaFindMemoryTypeIndexForImageInfo(). --# If you want to allocate a region of device memory without association with any - specific image or buffer, you can use function vmaAllocateMemory(). Usage of - this function is not recommended and usually not needed. - vmaAllocateMemoryPages() function is also provided for creating multiple allocations at once, - which may be useful for sparse binding. --# If you already have a buffer or an image created, you want to allocate memory - for it and then you will bind it yourself, you can use function - vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). - For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory() - or their extended versions: vmaBindBufferMemory2(), vmaBindImageMemory2(). --# If you want to create a buffer or an image, allocate memory for it and bind - them together, all in one call, you can use function vmaCreateBuffer(), - vmaCreateImage(). This is the easiest and recommended way to use this library. +/** +\addtogroup group_init +@{ +*/ -When using 3. or 4., the library internally queries Vulkan for memory types -supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) -and uses only one of these types. +/// Flags for created #VmaAllocator. +typedef enum VmaAllocatorCreateFlagBits +{ + /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. -If no memory type can be found that meets all the requirements, these functions -return `VK_ERROR_FEATURE_NOT_PRESENT`. + Using this flag may increase performance because internal mutexes are not used. + */ + VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + /** \brief Enables usage of VK_KHR_dedicated_allocation extension. -You can leave VmaAllocationCreateInfo structure completely filled with zeros. -It means no requirements are specified for memory type. -It is valid, although not very useful. + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. -\section choosing_memory_type_usage Usage + Using this extension will automatically allocate dedicated blocks of memory for + some buffers and images instead of suballocating place for them out of bigger + memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT + flag) when it is recommended by the driver. It may improve performance on some + GPUs. -The easiest way to specify memory requirements is to fill member -VmaAllocationCreateInfo::usage using one of the values of enum #VmaMemoryUsage. -It defines high level, common usage types. -For more details, see description of this enum. + You may set this flag only if you found out that following device extensions are + supported, you enabled them while creating Vulkan device passed as + VmaAllocatorCreateInfo::device, and you want them to be used internally by this + library: -For example, if you want to create a uniform buffer that will be filled using -transfer only once or infrequently and used for rendering every frame, you can -do it using following code: + - VK_KHR_get_memory_requirements2 (device extension) + - VK_KHR_dedicated_allocation (device extension) -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufferInfo.size = 65536; -bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + When this flag is set, you can experience following warnings reported by Vulkan + validation layer. You can ignore them. -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. + */ + VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, + /** + Enables usage of VK_KHR_bind_memory2 extension. -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. -\section choosing_memory_type_required_preferred_flags Required and preferred flags + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library. -You can specify more detailed requirements by filling members -VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags -with a combination of bits from enum `VkMemoryPropertyFlags`. For example, -if you want to create a buffer that will be persistently mapped on host (so it -must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`, -use following code: + The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, + which allow to pass a chain of `pNext` structures while binding. + This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). + */ + VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, + /** + Enables usage of VK_EXT_memory_budget extension. -\code -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; -allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; -allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library, along with another instance extension + VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode + The extension provides query for current memory usage and budget, which will probably + be more accurate than an estimation used by the library otherwise. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, + /** + Enables usage of VK_AMD_device_coherent_memory extension. -A memory type is chosen that has all the required flags and as many preferred -flags set as possible. + You may set this flag only if you: -If you use VmaAllocationCreateInfo::usage, it is just internally converted to -a set of required and preferred flags. + - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, + - want it to be used internally by this library. -\section choosing_memory_type_explicit_memory_types Explicit memory types + The extension and accompanying device feature provide access to memory types with + `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. + They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. -If you inspected memory types available on the physical device and you have -a preference for memory types that you want to use, you can fill member -VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set -means that a memory type with that index is allowed to be used for the -allocation. Special value 0, just like `UINT32_MAX`, means there are no -restrictions to memory type index. + When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. + To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, + returning `VK_ERROR_FEATURE_NOT_PRESENT`. + */ + VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, + /** + Enables usage of "buffer device address" feature, which allows you to use function + `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. -Please note that this member is NOT just a memory type index. -Still you can use it to choose just one, specific memory type. -For example, if you already determined that your buffer should be created in -memory type 2, use following code: + You may set this flag only if you: -\code -uint32_t memoryTypeIndex = 2; + 1. (For Vulkan version < 1.2) Found as available and enabled device extension + VK_KHR_buffer_device_address. + This extension is promoted to core Vulkan 1.2. + 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.memoryTypeBits = 1u << memoryTypeIndex; + When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. + The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to + allocated memory blocks wherever it might be needed. -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode + For more information, see documentation chapter \ref enabling_buffer_device_address. + */ + VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, + /** + Enables usage of VK_EXT_memory_priority extension in the library. -\section choosing_memory_type_custom_memory_pools Custom memory pools + You may set this flag only if you found available and enabled this device extension, + along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. -If you allocate from custom memory pool, all the ways of specifying memory -requirements described above are not applicable and the aforementioned members -of VmaAllocationCreateInfo structure are ignored. Memory type is selected -explicitly when creating the pool and then used to make all the allocations from -that pool. For further details, see \ref custom_memory_pools. + When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority + are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. -\section choosing_memory_type_dedicated_allocations Dedicated allocations + A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. + Larger values are higher priority. The granularity of the priorities is implementation-dependent. + It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. + The value to be used for default priority is 0.5. + For more details, see the documentation of the VK_EXT_memory_priority extension. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, -Memory for allocations is reserved out of larger block of `VkDeviceMemory` -allocated from Vulkan internally. That's the main feature of this whole library. -You can still request a separate memory block to be created for an allocation, -just like you would do in a trivial solution without using any allocator. -In that case, a buffer or image is always bound to that memory at offset 0. -This is called a "dedicated allocation". -You can explicitly request it by using flag #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. -The library can also internally decide to use dedicated allocation in some cases, e.g.: + VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocatorCreateFlagBits; +/// See #VmaAllocatorCreateFlagBits. +typedef VkFlags VmaAllocatorCreateFlags; -- When the size of the allocation is large. -- When [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension is enabled - and it reports that dedicated allocation is required or recommended for the resource. -- When allocation of next big memory block fails due to not enough device memory, - but allocation with the exact requested size succeeds. +/** @} */ +/** +\addtogroup group_alloc +@{ +*/ -\page memory_mapping Memory mapping +/// \brief Intended usage of the allocated memory. +typedef enum VmaMemoryUsage +{ + /** No intended memory usage specified. + Use other members of VmaAllocationCreateInfo to specify your requirements. + */ + VMA_MEMORY_USAGE_UNKNOWN = 0, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_GPU_ONLY = 1, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. + */ + VMA_MEMORY_USAGE_CPU_ONLY = 2, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_TO_GPU = 3, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. + */ + VMA_MEMORY_USAGE_GPU_TO_CPU = 4, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_COPY = 5, + /** + Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. + Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. -To "map memory" in Vulkan means to obtain a CPU pointer to `VkDeviceMemory`, -to be able to read from it or write to it in CPU code. -Mapping is possible only of memory allocated from a memory type that has -`VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. -Functions `vkMapMemory()`, `vkUnmapMemory()` are designed for this purpose. -You can use them directly with memory allocated by this library, -but it is not recommended because of following issue: -Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. -This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. -Because of this, Vulkan Memory Allocator provides following facilities: + Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. -\section memory_mapping_mapping_functions Mapping functions + Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + */ + VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, + /** + Selects best memory type automatically. + This flag is recommended for most common use cases. -The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). -They are safer and more convenient to use than standard Vulkan functions. -You can map an allocation multiple times simultaneously - mapping is reference-counted internally. -You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. -The way it's implemented is that the library always maps entire memory block, not just region of the allocation. -For further details, see description of vmaMapMemory() function. -Example: + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. -\code -// Having these objects initialized: + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO = 7, + /** + Selects best memory type automatically with preference for GPU (device) memory. -struct ConstantBuffer -{ - ... -}; -ConstantBuffer constantBufferData; + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. -VmaAllocator allocator; -VkBuffer constantBuffer; -VmaAllocation constantBufferAllocation; + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, + /** + Selects best memory type automatically with preference for CPU (host) memory. -// You can map and fill your buffer using following code: + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. -void* mappedData; -vmaMapMemory(allocator, constantBufferAllocation, &mappedData); -memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); -vmaUnmapMemory(allocator, constantBufferAllocation); -\endcode + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, -When mapping, you may see a warning from Vulkan validation layer similar to this one: + VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF +} VmaMemoryUsage; -Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used. +/// Flags to be passed as VmaAllocationCreateInfo::flags. +typedef enum VmaAllocationCreateFlagBits +{ + /** \brief Set this flag if the allocation should have its own memory block. -It happens because the library maps entire `VkDeviceMemory` block, where different -types of images and buffers may end up together, especially on GPUs with unified memory like Intel. -You can safely ignore it if you are sure you access only memory of the intended -object that you wanted to map. + Use it for special, big resources, like fullscreen images used as attachments. + */ + VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, + /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. -\section memory_mapping_persistently_mapped_memory Persistently mapped memory + If new allocation cannot be placed in any of the existing blocks, allocation + fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. -Kepping your memory persistently mapped is generally OK in Vulkan. -You don't need to unmap it before using its data on the GPU. -The library provides a special feature designed for that: -Allocations made with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in -VmaAllocationCreateInfo::flags stay mapped all the time, -so you can just access CPU pointer to it any time -without a need to call any "map" or "unmap" function. -Example: + You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and + #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. + */ + VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, + /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + It is valid to use this flag for allocation made from memory type that is not + `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is + useful if you need an allocation that is efficient to use on GPU + (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that + support it (e.g. Intel GPU). + */ + VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, + /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a + null-terminated string. Instead of copying pointer value, a local copy of the + string is made and stored in allocation's `pName`. The string is automatically + freed together with the allocation. It is also used in vmaBuildStatsString(). + */ + VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, + /** Allocation will be created from upper stack in a double stack pool. -// Buffer is already mapped. You can access its memory. -memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); -\endcode + This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, + /** Create both buffer/image and allocation, but don't bind them together. + It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. + The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). + Otherwise it is ignored. -There are some exceptions though, when you should consider mapping memory only for a short period of time: - -- When operating system is Windows 7 or 8.x (Windows 10 is not affected because it uses WDDM2), - device is discrete AMD GPU, - and memory type is the special 256 MiB pool of `DEVICE_LOCAL + HOST_VISIBLE` memory - (selected when you use #VMA_MEMORY_USAGE_CPU_TO_GPU), - then whenever a memory block allocated from this memory type stays mapped - for the time of any call to `vkQueueSubmit()` or `vkQueuePresentKHR()`, this - block is migrated by WDDM to system RAM, which degrades performance. It doesn't - matter if that particular memory block is actually used by the command buffer - being submitted. -- On Mac/MoltenVK there is a known bug - [Issue #175](https://github.com/KhronosGroup/MoltenVK/issues/175) - which requires unmapping before GPU can see updated texture. -- Keeping many large memory blocks mapped may impact performance or stability of some debugging tools. + If you want to make sure the new buffer/image is not tied to the new memory allocation + through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, + use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. + */ + VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, + /** Create allocation only if additional device memory required for it, if any, won't exceed + memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + */ + VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, + /** \brief Set this flag if the allocated memory will have aliasing resources. -\section memory_mapping_cache_control Cache flush and invalidate - -Memory in Vulkan doesn't need to be unmapped before using it on GPU, -but unless a memory types has `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag set, -you need to manually **invalidate** cache before reading of mapped pointer -and **flush** cache after writing to mapped pointer. -Map/unmap operations don't do that automatically. -Vulkan provides following functions for this purpose `vkFlushMappedMemoryRanges()`, -`vkInvalidateMappedMemoryRanges()`, but this library provides more convenient -functions that refer to given allocation object: vmaFlushAllocation(), -vmaInvalidateAllocation(). + Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. + Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. + */ + VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). -Regions of memory specified for flush/invalidate must be aligned to -`VkPhysicalDeviceLimits::nonCoherentAtomSize`. This is automatically ensured by the library. -In any memory type that is `HOST_VISIBLE` but not `HOST_COHERENT`, all allocations -within blocks are aligned to this value, so their offsets are always multiply of -`nonCoherentAtomSize` and two different allocations never share same "line" of this size. + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. -Please note that memory allocated with #VMA_MEMORY_USAGE_CPU_ONLY is guaranteed to be `HOST_COHERENT`. + Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, + never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. -Also, Windows drivers from all 3 **PC** GPU vendors (AMD, Intel, NVIDIA) -currently provide `HOST_COHERENT` flag on all memory types that are -`HOST_VISIBLE`, so on this platform you may not need to bother. + \warning Violating this declaration may work correctly, but will likely be very slow. + Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` + Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). -\section memory_mapping_finding_if_memory_mappable Finding out if memory is mappable + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. -It may happen that your allocation ends up in memory that is `HOST_VISIBLE` (available for mapping) -despite it wasn't explicitly requested. -For example, application may work on integrated graphics with unified memory (like Intel) or -allocation from video memory might have failed, so the library chose system memory as fallback. + Declares that mapped memory can be read, written, and accessed in random order, + so a `HOST_CACHED` memory type is required. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, + /** + Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, + it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected + if it may improve performance. + + By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type + (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and + issue an explicit transfer to write/read your data. + To prepare for this possibility, don't forget to add appropriate flags like + `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, + /** Allocation strategy that chooses smallest possible free range for the allocation + to minimize memory usage and fragmentation, possibly at the expense of allocation time. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, + /** Allocation strategy that chooses first suitable free range for the allocation - + not necessarily in terms of the smallest offset but the one that is easiest and fastest to find + to minimize allocation time, possibly at the expense of allocation quality. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + Used internally by defragmentation, not recommended in typical usage. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** A bit mask to extract only `STRATEGY` bits from entire set of flags. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MASK = + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT | + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, -You can detect this case and map such allocation to access its memory on CPU directly, -instead of launching a transfer operation. -In order to do that: inspect `allocInfo.memoryType`, call vmaGetMemoryTypeProperties(), -and look for `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag in properties of that memory type. + VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocationCreateFlagBits; +/// See #VmaAllocationCreateFlagBits. +typedef VkFlags VmaAllocationCreateFlags; -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; +/// Flags to be passed as VmaPoolCreateInfo::flags. +typedef enum VmaPoolCreateFlagBits +{ + /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + This is an optional optimization flag. -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + If you always allocate using vmaCreateBuffer(), vmaCreateImage(), + vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator + knows exact type of your allocations so it can handle Buffer-Image Granularity + in the optimal way. -VkMemoryPropertyFlags memFlags; -vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags); -if((memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) -{ - // Allocation ended up in mappable memory. You can map it and access it directly. - void* mappedData; - vmaMapMemory(allocator, alloc, &mappedData); - memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); - vmaUnmapMemory(allocator, alloc); -} -else -{ - // Allocation ended up in non-mappable memory. - // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. -} -\endcode + If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), + exact type of such allocations is not known, so allocator must be conservative + in handling Buffer-Image Granularity, which can lead to suboptimal allocation + (wasted memory). In that case, if you can make sure you always allocate only + buffers and linear images or only optimal images out of this pool, use this flag + to make allocator disregard Buffer-Image Granularity and so make allocations + faster and more optimal. + */ + VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, -You can even use #VMA_ALLOCATION_CREATE_MAPPED_BIT flag while creating allocations -that are not necessarily `HOST_VISIBLE` (e.g. using #VMA_MEMORY_USAGE_GPU_ONLY). -If the allocation ends up in memory type that is `HOST_VISIBLE`, it will be persistently mapped and you can use it directly. -If not, the flag is just ignored. -Example: + /** \brief Enables alternative, linear allocation algorithm in this pool. -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, -if(allocInfo.pUserData != nullptr) -{ - // Allocation ended up in mappable memory. - // It's persistently mapped. You can access it directly. - memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); -} -else -{ - // Allocation ended up in non-mappable memory. - // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. -} -\endcode + /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_POOL_CREATE_ALGORITHM_MASK = + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT, + VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaPoolCreateFlagBits; +/// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. +typedef VkFlags VmaPoolCreateFlags; -\page staying_within_budget Staying within budget +/// Flags to be passed as VmaDefragmentationInfo::flags. +typedef enum VmaDefragmentationFlagBits +{ + /* \brief Use simple but fast algorithm for defragmentation. + May not achieve best results but will require least time to compute and least allocations to copy. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, + /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. + Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, + /* \brief Perform full defragmentation of memory. + Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, + /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. + Only available when bufferImageGranularity is greater than 1, since it aims to reduce + alignment issues between different types of resources. + Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, -When developing a graphics-intensive game or program, it is important to avoid allocating -more GPU memory than it's physically available. When the memory is over-committed, -various bad things can happen, depending on the specific GPU, graphics driver, and -operating system: + /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT, -- It may just work without any problems. -- The application may slow down because some memory blocks are moved to system RAM - and the GPU has to access them through PCI Express bus. -- A new allocation may take very long time to complete, even few seconds, and possibly - freeze entire system. -- The new allocation may fail with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. -- It may even result in GPU crash (TDR), observed as `VK_ERROR_DEVICE_LOST` - returned somewhere later. + VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaDefragmentationFlagBits; +/// See #VmaDefragmentationFlagBits. +typedef VkFlags VmaDefragmentationFlags; -\section staying_within_budget_querying_for_budget Querying for budget +/// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. +typedef enum VmaDefragmentationMoveOperation +{ + /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). + VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, + /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. + VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, + /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. + VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, +} VmaDefragmentationMoveOperation; -To query for current memory usage and available budget, use function vmaGetBudget(). -Returned structure #VmaBudget contains quantities expressed in bytes, per Vulkan memory heap. +/** @} */ -Please note that this function returns different information and works faster than -vmaCalculateStats(). vmaGetBudget() can be called every frame or even before every -allocation, while vmaCalculateStats() is intended to be used rarely, -only to obtain statistical information, e.g. for debugging purposes. +/** +\addtogroup group_virtual +@{ +*/ -It is recommended to use VK_EXT_memory_budget device extension to obtain information -about the budget from Vulkan device. VMA is able to use this extension automatically. -When not enabled, the allocator behaves same way, but then it estimates current usage -and available budget based on its internal information and Vulkan memory heap sizes, -which may be less precise. In order to use this extension: +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. +typedef enum VmaVirtualBlockCreateFlagBits +{ + /** \brief Enables alternative, linear allocation algorithm in this virtual block. -1. Make sure extensions VK_EXT_memory_budget and VK_KHR_get_physical_device_properties2 - required by it are available and enable them. Please note that the first is a device - extension and the second is instance extension! -2. Use flag #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT when creating #VmaAllocator object. -3. Make sure to call vmaSetCurrentFrameIndex() every frame. Budget is queried from - Vulkan inside of it to avoid overhead of querying it with every allocation. + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. -\section staying_within_budget_controlling_memory_usage Controlling memory usage + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, -There are many ways in which you can try to stay within the budget. + /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT, -First, when making new allocation requires allocating a new memory block, the library -tries not to exceed the budget automatically. If a block with default recommended size -(e.g. 256 MB) would go over budget, a smaller block is allocated, possibly even -dedicated memory for just this resource. + VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualBlockCreateFlagBits; +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. +typedef VkFlags VmaVirtualBlockCreateFlags; -If the size of the requested resource plus current memory usage is more than the -budget, by default the library still tries to create it, leaving it to the Vulkan -implementation whether the allocation succeeds or fails. You can change this behavior -by using #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag. With it, the allocation is -not made if it would exceed the budget or if the budget is already exceeded. -Some other allocations become lost instead to make room for it, if the mechanism of -[lost allocations](@ref lost_allocations) is used. -If that is not possible, the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. -Example usage pattern may be to pass the #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag -when creating resources that are not essential for the application (e.g. the texture -of a specific object) and not to pass it when creating critically important resources -(e.g. render targets). +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. +typedef enum VmaVirtualAllocationCreateFlagBits +{ + /** \brief Allocation will be created from upper stack in a double stack pool. -Finally, you can also use #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT flag to make sure -a new allocation is created only when it fits inside one of the existing memory blocks. -If it would require to allocate a new block, if fails instead with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. -This also ensures that the function call is very fast because it never goes to Vulkan -to obtain a new block. + This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, + /** \brief Allocation strategy that tries to minimize memory usage. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** \brief Allocation strategy that tries to minimize allocation time. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. -Please note that creating \ref custom_memory_pools with VmaPoolCreateInfo::minBlockCount -set to more than 0 will try to allocate memory blocks without checking whether they -fit within budget. + These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, + VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualAllocationCreateFlagBits; +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. +typedef VkFlags VmaVirtualAllocationCreateFlags; -\page custom_memory_pools Custom memory pools +/** @} */ -A memory pool contains a number of `VkDeviceMemory` blocks. -The library automatically creates and manages default pool for each memory type available on the device. -Default memory pool automatically grows in size. -Size of allocated blocks is also variable and managed automatically. +#endif // _VMA_ENUM_DECLARATIONS -You can create custom pool and allocate memory out of it. -It can be useful if you want to: +#ifndef _VMA_DATA_TYPES_DECLARATIONS -- Keep certain kind of allocations separate from others. -- Enforce particular, fixed size of Vulkan memory blocks. -- Limit maximum amount of Vulkan memory allocated for that pool. -- Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool. +/** +\addtogroup group_init +@{ */ -To use custom memory pools: +/** \struct VmaAllocator +\brief Represents main object of this library initialized. --# Fill VmaPoolCreateInfo structure. --# Call vmaCreatePool() to obtain #VmaPool handle. --# When making an allocation, set VmaAllocationCreateInfo::pool to this handle. - You don't need to specify any other parameters of this structure, like `usage`. +Fill structure #VmaAllocatorCreateInfo and call function vmaCreateAllocator() to create it. +Call function vmaDestroyAllocator() to destroy it. -Example: +It is recommended to create just one object of this type per `VkDevice` object, +right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. +*/ +VK_DEFINE_HANDLE(VmaAllocator) -\code -// Create a pool that can have at most 2 blocks, 128 MiB each. -VmaPoolCreateInfo poolCreateInfo = {}; -poolCreateInfo.memoryTypeIndex = ... -poolCreateInfo.blockSize = 128ull * 1024 * 1024; -poolCreateInfo.maxBlockCount = 2; +/** @} */ -VmaPool pool; -vmaCreatePool(allocator, &poolCreateInfo, &pool); +/** +\addtogroup group_alloc +@{ +*/ -// Allocate a buffer out of it. -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = 1024; -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; +/** \struct VmaPool +\brief Represents custom memory pool -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.pool = pool; +Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. +Call function vmaDestroyPool() to destroy it. -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); -\endcode +For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). +*/ +VK_DEFINE_HANDLE(VmaPool) -You have to free all allocations made from this pool before destroying it. +/** \struct VmaAllocation +\brief Represents single memory allocation. -\code -vmaDestroyBuffer(allocator, buf, alloc); -vmaDestroyPool(allocator, pool); -\endcode +It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type +plus unique offset. -\section custom_memory_pools_MemTypeIndex Choosing memory type index +There are multiple ways to create such object. +You need to fill structure VmaAllocationCreateInfo. +For more information see [Choosing memory type](@ref choosing_memory_type). -When creating a pool, you must explicitly specify memory type index. -To find the one suitable for your buffers or images, you can use helper functions -vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo(). -You need to provide structures with example parameters of buffers or images -that you are going to create in that pool. +Although the library provides convenience functions that create Vulkan buffer or image, +allocate memory for it and bind them together, +binding of the allocation to a buffer or an image is out of scope of the allocation itself. +Allocation object can exist without buffer/image bound, +binding can be done manually by the user, and destruction of it can be done +independently of destruction of the allocation. -\code -VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -exampleBufCreateInfo.size = 1024; // Whatever. -exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change if needed. +The object also remembers its size and some other information. +To retrieve this information, use function vmaGetAllocationInfo() and inspect +returned structure VmaAllocationInfo. +*/ +VK_DEFINE_HANDLE(VmaAllocation) -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; // Change if needed. +/** \struct VmaDefragmentationContext +\brief An opaque object that represents started defragmentation process. -uint32_t memTypeIndex; -vmaFindMemoryTypeIndexForBufferInfo(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); +Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. +Call function vmaEndDefragmentation() to destroy it. +*/ +VK_DEFINE_HANDLE(VmaDefragmentationContext) -VmaPoolCreateInfo poolCreateInfo = {}; -poolCreateInfo.memoryTypeIndex = memTypeIndex; -// ... -\endcode +/** @} */ -When creating buffers/images allocated in that pool, provide following parameters: +/** +\addtogroup group_virtual +@{ +*/ -- `VkBufferCreateInfo`: Prefer to pass same parameters as above. - Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. - Using different `VK_BUFFER_USAGE_` flags may work, but you shouldn't create images in a pool intended for buffers - or the other way around. -- VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. - Other members are ignored anyway. +/** \struct VmaVirtualAllocation +\brief Represents single memory allocation done inside VmaVirtualBlock. -\section linear_algorithm Linear allocation algorithm +Use it as a unique identifier to virtual allocation within the single block. -Each Vulkan memory block managed by this library has accompanying metadata that -keeps track of used and unused regions. By default, the metadata structure and -algorithm tries to find best place for new allocations among free regions to -optimize memory usage. This way you can allocate and free objects in any order. +Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. +*/ +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) -![Default allocation algorithm](../gfx/Linear_allocator_1_algo_default.png) +/** @} */ -Sometimes there is a need to use simpler, linear allocation algorithm. You can -create custom pool that uses such algorithm by adding flag -#VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating -#VmaPool object. Then an alternative metadata management is used. It always -creates new allocations after last one and doesn't reuse free regions after -allocations freed in the middle. It results in better allocation performance and -less memory consumed by metadata. +/** +\addtogroup group_virtual +@{ +*/ -![Linear allocation algorithm](../gfx/Linear_allocator_2_algo_linear.png) +/** \struct VmaVirtualBlock +\brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. -With this one flag, you can create a custom pool that can be used in many ways: -free-at-once, stack, double stack, and ring buffer. See below for details. +Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. +For more information, see documentation chapter \ref virtual_allocator. -\subsection linear_algorithm_free_at_once Free-at-once +This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. +*/ +VK_DEFINE_HANDLE(VmaVirtualBlock) -In a pool that uses linear algorithm, you still need to free all the allocations -individually, e.g. by using vmaFreeMemory() or vmaDestroyBuffer(). You can free -them in any order. New allocations are always made after last one - free space -in the middle is not reused. However, when you release all the allocation and -the pool becomes empty, allocation starts from the beginning again. This way you -can use linear algorithm to speed up creation of allocations that you are going -to release all at once. +/** @} */ -![Free-at-once](../gfx/Linear_allocator_3_free_at_once.png) +/** +\addtogroup group_init +@{ +*/ -This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount -value that allows multiple memory blocks. +/// Callback function called after successful vkAllocateMemory. +typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); -\subsection linear_algorithm_stack Stack +/// Callback function called before vkFreeMemory. +typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); -When you free an allocation that was created last, its space can be reused. -Thanks to this, if you always release allocations in the order opposite to their -creation (LIFO - Last In First Out), you can achieve behavior of a stack. +/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. -![Stack](../gfx/Linear_allocator_4_stack.png) +Provided for informative purpose, e.g. to gather statistics about number of +allocations or total amount of memory allocated in Vulkan. -This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount -value that allows multiple memory blocks. +Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. +*/ +typedef struct VmaDeviceMemoryCallbacks +{ + /// Optional, can be null. + PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; + /// Optional, can be null. + PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; + /// Optional, can be null. + void* VMA_NULLABLE pUserData; +} VmaDeviceMemoryCallbacks; -\subsection linear_algorithm_double_stack Double stack +/** \brief Pointers to some Vulkan functions - a subset used by the library. -The space reserved by a custom pool with linear algorithm may be used by two -stacks: - -- First, default one, growing up from offset 0. -- Second, "upper" one, growing down from the end towards lower offsets. - -To make allocation from upper stack, add flag #VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT -to VmaAllocationCreateInfo::flags. - -![Double stack](../gfx/Linear_allocator_7_double_stack.png) - -Double stack is available only in pools with one memory block - -VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. +Used in VmaAllocatorCreateInfo::pVulkanFunctions. +*/ +typedef struct VmaVulkanFunctions +{ + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; + PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; + PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; + PFN_vkMapMemory VMA_NULLABLE vkMapMemory; + PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; + PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; + PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; + PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; + PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; + PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; + PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; + PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; + PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; + PFN_vkCreateImage VMA_NULLABLE vkCreateImage; + PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; + PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; + /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; +#endif +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; + /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; +#endif +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; +#endif +#if VMA_VULKAN_VERSION >= 1003000 + /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceBufferMemoryRequirements VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; + /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceImageMemoryRequirements VMA_NULLABLE vkGetDeviceImageMemoryRequirements; +#endif +} VmaVulkanFunctions; -When the two stacks' ends meet so there is not enough space between them for a -new allocation, such allocation fails with usual -`VK_ERROR_OUT_OF_DEVICE_MEMORY` error. +/// Description of a Allocator to be created. +typedef struct VmaAllocatorCreateInfo +{ + /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. + VmaAllocatorCreateFlags flags; + /// Vulkan physical device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /// Vulkan device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkDevice VMA_NOT_NULL device; + /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. + /** Set to 0 to use default, which is currently 256 MiB. */ + VkDeviceSize preferredLargeHeapBlockSize; + /// Custom CPU memory allocation callbacks. Optional. + /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; + /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. + /** Optional, can be null. */ + const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; + /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. -\subsection linear_algorithm_ring_buffer Ring buffer + If not NULL, it must be a pointer to an array of + `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on + maximum number of bytes that can be allocated out of particular Vulkan memory + heap. -When you free some allocations from the beginning and there is not enough free space -for a new one at the end of a pool, allocator's "cursor" wraps around to the -beginning and starts allocation there. Thanks to this, if you always release -allocations in the same order as you created them (FIFO - First In First Out), -you can achieve behavior of a ring buffer / queue. + Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that + heap. This is also the default in case of `pHeapSizeLimit` = NULL. -![Ring buffer](../gfx/Linear_allocator_5_ring_buffer.png) + If there is a limit defined for a heap: -Pools with linear algorithm support [lost allocations](@ref lost_allocations) when used as ring buffer. -If there is not enough free space for a new allocation, but existing allocations -from the front of the queue can become lost, they become lost and the allocation -succeeds. + - If user tries to allocate more memory from that heap using this allocator, + the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the + value of this limit will be reported instead when using vmaGetMemoryProperties(). -![Ring buffer with lost allocations](../gfx/Linear_allocator_6_ring_buffer_lost.png) + Warning! Using this feature may not be equivalent to installing a GPU with + smaller amount of memory, because graphics driver doesn't necessary fail new + allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is + exceeded. It may return success and just silently migrate some device memory + blocks to system RAM. This driver behavior can also be controlled using + VK_AMD_memory_overallocation_behavior extension. + */ + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; -Ring buffer is available only in pools with one memory block - -VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. + /** \brief Pointers to Vulkan functions. Can be null. -\section buddy_algorithm Buddy allocation algorithm + For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). + */ + const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; + /** \brief Handle to Vulkan instance object. -There is another allocation algorithm that can be used with custom pools, called -"buddy". Its internal data structure is based on a tree of blocks, each having -size that is a power of two and a half of its parent's size. When you want to -allocate memory of certain size, a free node in the tree is located. If it's too -large, it is recursively split into two halves (called "buddies"). However, if -requested allocation size is not a power of two, the size of a tree node is -aligned up to the nearest power of two and the remaining space is wasted. When -two buddy nodes become free, they are merged back into one larger node. + Starting from version 3.0.0 this member is no longer optional, it must be set! + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Optional. The highest version of Vulkan that the application is designed to use. -![Buddy allocator](../gfx/Buddy_allocator.png) + It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. + The patch version number specified is ignored. Only the major and minor versions are considered. + It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`. + Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. + Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. + */ + uint32_t vulkanApiVersion; +#if VMA_EXTERNAL_MEMORY + /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. -The advantage of buddy allocation algorithm over default algorithm is faster -allocation and deallocation, as well as smaller external fragmentation. The -disadvantage is more wasted space (internal fragmentation). + If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` + elements, defining external memory handle types of particular Vulkan memory type, + to be passed using `VkExportMemoryAllocateInfoKHR`. -For more information, please read ["Buddy memory allocation" on Wikipedia](https://en.wikipedia.org/wiki/Buddy_memory_allocation) -or other sources that describe this concept in general. + Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. + This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. + */ + const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; +#endif // #if VMA_EXTERNAL_MEMORY +} VmaAllocatorCreateInfo; -To use buddy allocation algorithm with a custom pool, add flag -#VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating -#VmaPool object. +/// Information about existing #VmaAllocator object. +typedef struct VmaAllocatorInfo +{ + /** \brief Handle to Vulkan instance object. -Several limitations apply to pools that use buddy algorithm: + This is the same value as has been passed through VmaAllocatorCreateInfo::instance. + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Handle to Vulkan physical device object. -- It is recommended to use VmaPoolCreateInfo::blockSize that is a power of two. - Otherwise, only largest power of two smaller than the size is used for - allocations. The remaining space always stays unused. -- [Margins](@ref debugging_memory_usage_margins) and - [corruption detection](@ref debugging_memory_usage_corruption_detection) - don't work in such pools. -- [Lost allocations](@ref lost_allocations) don't work in such pools. You can - use them, but they never become lost. Support may be added in the future. -- [Defragmentation](@ref defragmentation) doesn't work with allocations made from - such pool. + This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. + */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /** \brief Handle to Vulkan device object. -\page defragmentation Defragmentation + This is the same value as has been passed through VmaAllocatorCreateInfo::device. + */ + VkDevice VMA_NOT_NULL device; +} VmaAllocatorInfo; -Interleaved allocations and deallocations of many objects of varying size can -cause fragmentation over time, which can lead to a situation where the library is unable -to find a continuous range of free memory for a new allocation despite there is -enough free space, just scattered across many small free ranges between existing -allocations. +/** @} */ -To mitigate this problem, you can use defragmentation feature: -structure #VmaDefragmentationInfo2, function vmaDefragmentationBegin(), vmaDefragmentationEnd(). -Given set of allocations, -this function can move them to compact used memory, ensure more continuous free -space and possibly also free some `VkDeviceMemory` blocks. +/** +\addtogroup group_stats +@{ +*/ -What the defragmentation does is: +/** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. -- Updates #VmaAllocation objects to point to new `VkDeviceMemory` and offset. - After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or - VmaAllocationInfo::offset changes. You must query them again using - vmaGetAllocationInfo() if you need them. -- Moves actual data in memory. +These are fast to calculate. +See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). +*/ +typedef struct VmaStatistics +{ + /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. + */ + uint32_t blockCount; + /** \brief Number of #VmaAllocation objects allocated. -What it doesn't do, so you need to do it yourself: + Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. + */ + uint32_t allocationCount; + /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. -- Recreate buffers and images that were bound to allocations that were defragmented and - bind them with their new places in memory. - You must use `vkDestroyBuffer()`, `vkDestroyImage()`, - `vkCreateBuffer()`, `vkCreateImage()`, vmaBindBufferMemory(), vmaBindImageMemory() - for that purpose and NOT vmaDestroyBuffer(), - vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage(), because you don't need to - destroy or create allocation objects! -- Recreate views and update descriptors that point to these buffers and images. + \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object + (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls + "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. + */ + VkDeviceSize blockBytes; + /** \brief Total number of bytes occupied by all #VmaAllocation objects. -\section defragmentation_cpu Defragmenting CPU memory + Always less or equal than `blockBytes`. + Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan + but unused by any #VmaAllocation. + */ + VkDeviceSize allocationBytes; +} VmaStatistics; -Following example demonstrates how you can run defragmentation on CPU. -Only allocations created in memory types that are `HOST_VISIBLE` can be defragmented. -Others are ignored. +/** \brief More detailed statistics than #VmaStatistics. -The way it works is: +These are slower to calculate. Use for debugging purposes. +See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). -- It temporarily maps entire memory blocks when necessary. -- It moves data using `memmove()` function. +Previous version of the statistics API provided averages, but they have been removed +because they can be easily calculated as: \code -// Given following variables already initialized: -VkDevice device; -VmaAllocator allocator; -std::vector buffers; -std::vector allocations; - +VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; +VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; +VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; +\endcode +*/ +typedef struct VmaDetailedStatistics +{ + /// Basic statistics. + VmaStatistics statistics; + /// Number of free ranges of memory between allocations. + uint32_t unusedRangeCount; + /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. + VkDeviceSize allocationSizeMin; + /// Largest allocation size. 0 if there are 0 allocations. + VkDeviceSize allocationSizeMax; + /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMin; + /// Largest empty range size. 0 if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMax; +} VmaDetailedStatistics; -const uint32_t allocCount = (uint32_t)allocations.size(); -std::vector allocationsChanged(allocCount); +/** \brief General statistics from current state of the Allocator - +total memory usage across all memory heaps and types. -VmaDefragmentationInfo2 defragInfo = {}; -defragInfo.allocationCount = allocCount; -defragInfo.pAllocations = allocations.data(); -defragInfo.pAllocationsChanged = allocationsChanged.data(); -defragInfo.maxCpuBytesToMove = VK_WHOLE_SIZE; // No limit. -defragInfo.maxCpuAllocationsToMove = UINT32_MAX; // No limit. +These are slower to calculate. Use for debugging purposes. +See function vmaCalculateStatistics(). +*/ +typedef struct VmaTotalStatistics +{ + VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; + VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; + VmaDetailedStatistics total; +} VmaTotalStatistics; -VmaDefragmentationContext defragCtx; -vmaDefragmentationBegin(allocator, &defragInfo, nullptr, &defragCtx); -vmaDefragmentationEnd(allocator, defragCtx); +/** \brief Statistics of current memory usage and available budget for a specific memory heap. -for(uint32_t i = 0; i < allocCount; ++i) +These are fast to calculate. +See function vmaGetHeapBudgets(). +*/ +typedef struct VmaBudget { - if(allocationsChanged[i]) - { - // Destroy buffer that is immutably bound to memory region which is no longer valid. - vkDestroyBuffer(device, buffers[i], nullptr); - - // Create new buffer with same parameters. - VkBufferCreateInfo bufferInfo = ...; - vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); - - // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. - - // Bind new buffer to new memory region. Data contained in it is already moved. - VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); - vmaBindBufferMemory(allocator, allocations[i], buffers[i]); - } -} -\endcode + /** \brief Statistics fetched from the library. + */ + VmaStatistics statistics; + /** \brief Estimated current memory usage of the program, in bytes. -Setting VmaDefragmentationInfo2::pAllocationsChanged is optional. -This output array tells whether particular allocation in VmaDefragmentationInfo2::pAllocations at the same index -has been modified during defragmentation. -You can pass null, but you then need to query every allocation passed to defragmentation -for new parameters using vmaGetAllocationInfo() if you might need to recreate and rebind a buffer or image associated with it. + Fetched from system using VK_EXT_memory_budget extension if enabled. -If you use [Custom memory pools](@ref choosing_memory_type_custom_memory_pools), -you can fill VmaDefragmentationInfo2::poolCount and VmaDefragmentationInfo2::pPools -instead of VmaDefragmentationInfo2::allocationCount and VmaDefragmentationInfo2::pAllocations -to defragment all allocations in given pools. -You cannot use VmaDefragmentationInfo2::pAllocationsChanged in that case. -You can also combine both methods. + It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects + also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or + `VkDeviceMemory` blocks allocated outside of this library, if any. + */ + VkDeviceSize usage; + /** \brief Estimated amount of memory available to the program, in bytes. -\section defragmentation_gpu Defragmenting GPU memory + Fetched from system using VK_EXT_memory_budget extension if enabled. -It is also possible to defragment allocations created in memory types that are not `HOST_VISIBLE`. -To do that, you need to pass a command buffer that meets requirements as described in -VmaDefragmentationInfo2::commandBuffer. The way it works is: + It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors + external to the program, decided by the operating system. + Difference `budget - usage` is the amount of additional memory that can probably + be allocated without problems. Exceeding the budget may result in various problems. + */ + VkDeviceSize budget; +} VmaBudget; -- It creates temporary buffers and binds them to entire memory blocks when necessary. -- It issues `vkCmdCopyBuffer()` to passed command buffer. +/** @} */ -Example: +/** +\addtogroup group_alloc +@{ +*/ -\code -// Given following variables already initialized: -VkDevice device; -VmaAllocator allocator; -VkCommandBuffer commandBuffer; -std::vector buffers; -std::vector allocations; +/** \brief Parameters of new #VmaAllocation. +To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. +*/ +typedef struct VmaAllocationCreateInfo +{ + /// Use #VmaAllocationCreateFlagBits enum. + VmaAllocationCreateFlags flags; + /** \brief Intended usage of memory. -const uint32_t allocCount = (uint32_t)allocations.size(); -std::vector allocationsChanged(allocCount); + You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored. + */ + VmaMemoryUsage usage; + /** \brief Flags that must be set in a Memory Type chosen for an allocation. -VkCommandBufferBeginInfo cmdBufBeginInfo = ...; -vkBeginCommandBuffer(commandBuffer, &cmdBufBeginInfo); + Leave 0 if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored.*/ + VkMemoryPropertyFlags requiredFlags; + /** \brief Flags that preferably should be set in a memory type chosen for an allocation. -VmaDefragmentationInfo2 defragInfo = {}; -defragInfo.allocationCount = allocCount; -defragInfo.pAllocations = allocations.data(); -defragInfo.pAllocationsChanged = allocationsChanged.data(); -defragInfo.maxGpuBytesToMove = VK_WHOLE_SIZE; // Notice it's "GPU" this time. -defragInfo.maxGpuAllocationsToMove = UINT32_MAX; // Notice it's "GPU" this time. -defragInfo.commandBuffer = commandBuffer; + Set to 0 if no additional flags are preferred. \n + If `pool` is not null, this member is ignored. */ + VkMemoryPropertyFlags preferredFlags; + /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. -VmaDefragmentationContext defragCtx; -vmaDefragmentationBegin(allocator, &defragInfo, nullptr, &defragCtx); + Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if + it meets other requirements specified by this structure, with no further + restrictions on memory type index. \n + If `pool` is not null, this member is ignored. + */ + uint32_t memoryTypeBits; + /** \brief Pool that this allocation should be created in. -vkEndCommandBuffer(commandBuffer); + Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: + `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). -// Submit commandBuffer. -// Wait for a fence that ensures commandBuffer execution finished. + If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either + null or pointer to a null-terminated string. The string will be then copied to + internal buffer, so it doesn't need to be valid after allocation call. + */ + void* VMA_NULLABLE pUserData; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. -vmaDefragmentationEnd(allocator, defragCtx); + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object + and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. + */ + float priority; +} VmaAllocationCreateInfo; -for(uint32_t i = 0; i < allocCount; ++i) +/// Describes parameter of created #VmaPool. +typedef struct VmaPoolCreateInfo { - if(allocationsChanged[i]) - { - // Destroy buffer that is immutably bound to memory region which is no longer valid. - vkDestroyBuffer(device, buffers[i], nullptr); + /** \brief Vulkan memory type index to allocate this pool from. + */ + uint32_t memoryTypeIndex; + /** \brief Use combination of #VmaPoolCreateFlagBits. + */ + VmaPoolCreateFlags flags; + /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. - // Create new buffer with same parameters. - VkBufferCreateInfo bufferInfo = ...; - vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); - - // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. - - // Bind new buffer to new memory region. Data contained in it is already moved. - VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); - vmaBindBufferMemory(allocator, allocations[i], buffers[i]); - } -} -\endcode + Specify nonzero to set explicit, constant size of memory blocks used by this + pool. -You can combine these two methods by specifying non-zero `maxGpu*` as well as `maxCpu*` parameters. -The library automatically chooses best method to defragment each memory pool. - -You may try not to block your entire program to wait until defragmentation finishes, -but do it in the background, as long as you carefully fullfill requirements described -in function vmaDefragmentationBegin(). - -\section defragmentation_additional_notes Additional notes - -It is only legal to defragment allocations bound to: - -- buffers -- images created with `VK_IMAGE_CREATE_ALIAS_BIT`, `VK_IMAGE_TILING_LINEAR`, and - being currently in `VK_IMAGE_LAYOUT_GENERAL` or `VK_IMAGE_LAYOUT_PREINITIALIZED`. - -Defragmentation of images created with `VK_IMAGE_TILING_OPTIMAL` or in any other -layout may give undefined results. - -If you defragment allocations bound to images, new images to be bound to new -memory region after defragmentation should be created with `VK_IMAGE_LAYOUT_PREINITIALIZED` -and then transitioned to their original layout from before defragmentation if -needed using an image memory barrier. - -While using defragmentation, you may experience validation layer warnings, which you just need to ignore. -See [Validation layer warnings](@ref general_considerations_validation_layer_warnings). - -Please don't expect memory to be fully compacted after defragmentation. -Algorithms inside are based on some heuristics that try to maximize number of Vulkan -memory blocks to make totally empty to release them, as well as to maximimze continuous -empty space inside remaining blocks, while minimizing the number and size of allocations that -need to be moved. Some fragmentation may still remain - this is normal. - -\section defragmentation_custom_algorithm Writing custom defragmentation algorithm - -If you want to implement your own, custom defragmentation algorithm, -there is infrastructure prepared for that, -but it is not exposed through the library API - you need to hack its source code. -Here are steps needed to do this: - --# Main thing you need to do is to define your own class derived from base abstract - class `VmaDefragmentationAlgorithm` and implement your version of its pure virtual methods. - See definition and comments of this class for details. --# Your code needs to interact with device memory block metadata. - If you need more access to its data than it's provided by its public interface, - declare your new class as a friend class e.g. in class `VmaBlockMetadata_Generic`. --# If you want to create a flag that would enable your algorithm or pass some additional - flags to configure it, add them to `VmaDefragmentationFlagBits` and use them in - VmaDefragmentationInfo2::flags. --# Modify function `VmaBlockVectorDefragmentationContext::Begin` to create object - of your new class whenever needed. - - -\page lost_allocations Lost allocations - -If your game oversubscribes video memory, if may work OK in previous-generation -graphics APIs (DirectX 9, 10, 11, OpenGL) because resources are automatically -paged to system RAM. In Vulkan you can't do it because when you run out of -memory, an allocation just fails. If you have more data (e.g. textures) that can -fit into VRAM and you don't need it all at once, you may want to upload them to -GPU on demand and "push out" ones that are not used for a long time to make room -for the new ones, effectively using VRAM (or a cartain memory pool) as a form of -cache. Vulkan Memory Allocator can help you with that by supporting a concept of -"lost allocations". - -To create an allocation that can become lost, include #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT -flag in VmaAllocationCreateInfo::flags. Before using a buffer or image bound to -such allocation in every new frame, you need to query it if it's not lost. -To check it, call vmaTouchAllocation(). -If the allocation is lost, you should not use it or buffer/image bound to it. -You mustn't forget to destroy this allocation and this buffer/image. -vmaGetAllocationInfo() can also be used for checking status of the allocation. -Allocation is lost when returned VmaAllocationInfo::deviceMemory == `VK_NULL_HANDLE`. - -To create an allocation that can make some other allocations lost to make room -for it, use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag. You will -usually use both flags #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT and -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT at the same time. - -Warning! Current implementation uses quite naive, brute force algorithm, -which can make allocation calls that use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT -flag quite slow. A new, more optimal algorithm and data structure to speed this -up is planned for the future. - -Q: When interleaving creation of new allocations with usage of existing ones, -how do you make sure that an allocation won't become lost while it's used in the -current frame? - -It is ensured because vmaTouchAllocation() / vmaGetAllocationInfo() not only returns allocation -status/parameters and checks whether it's not lost, but when it's not, it also -atomically marks it as used in the current frame, which makes it impossible to -become lost in that frame. It uses lockless algorithm, so it works fast and -doesn't involve locking any internal mutex. - -Q: What if my allocation may still be in use by the GPU when it's rendering a -previous frame while I already submit new frame on the CPU? - -You can make sure that allocations "touched" by vmaTouchAllocation() / vmaGetAllocationInfo() will not -become lost for a number of additional frames back from the current one by -specifying this number as VmaAllocatorCreateInfo::frameInUseCount (for default -memory pool) and VmaPoolCreateInfo::frameInUseCount (for custom pool). - -Q: How do you inform the library when new frame starts? - -You need to call function vmaSetCurrentFrameIndex(). - -Example code: + Leave 0 to use default and let the library manage block sizes automatically. + Sizes of particular blocks may vary. + In this case, the pool will also support dedicated allocations. + */ + VkDeviceSize blockSize; + /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. -\code -struct MyBuffer -{ - VkBuffer m_Buf = nullptr; - VmaAllocation m_Alloc = nullptr; + Set to 0 to have no preallocated blocks and allow the pool be completely empty. + */ + size_t minBlockCount; + /** \brief Maximum number of blocks that can be allocated in this pool. Optional. - // Called when the buffer is really needed in the current frame. - void EnsureBuffer(); -}; + Set to 0 to use default, which is `SIZE_MAX`, which means no limit. -void MyBuffer::EnsureBuffer() -{ - // Buffer has been created. - if(m_Buf != VK_NULL_HANDLE) - { - // Check if its allocation is not lost + mark it as used in current frame. - if(vmaTouchAllocation(allocator, m_Alloc)) - { - // It's all OK - safe to use m_Buf. - return; - } - } + Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated + throughout whole lifetime of this pool. + */ + size_t maxBlockCount; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. - // Buffer not yet exists or lost - destroy and recreate it. + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. + Otherwise, this variable is ignored. + */ + float priority; + /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. - vmaDestroyBuffer(allocator, m_Buf, m_Alloc); + Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. + It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, + e.g. when doing interop with OpenGL. + */ + VkDeviceSize minAllocationAlignment; + /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. - VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufCreateInfo.size = 1024; - bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. + It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. + Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. - VmaAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT | - VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT; + Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, + can be attached automatically by this library when using other, more convenient of its features. + */ + void* VMA_NULLABLE pMemoryAllocateNext; +} VmaPoolCreateInfo; - vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr); -} -\endcode +/** @} */ -When using lost allocations, you may see some Vulkan validation layer warnings -about overlapping regions of memory bound to different kinds of buffers and -images. This is still valid as long as you implement proper handling of lost -allocations (like in the example above) and don't use them. +/** +\addtogroup group_alloc +@{ +*/ -You can create an allocation that is already in lost state from the beginning using function -vmaCreateLostAllocation(). It may be useful if you need a "dummy" allocation that is not null. +/// Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). +typedef struct VmaAllocationInfo +{ + /** \brief Memory type index that this allocation was allocated from. -You can call function vmaMakePoolAllocationsLost() to set all eligible allocations -in a specified custom pool to lost state. -Allocations that have been "touched" in current frame or VmaPoolCreateInfo::frameInUseCount frames back -cannot become lost. + It never changes. + */ + uint32_t memoryType; + /** \brief Handle to Vulkan memory object. -Q: Can I touch allocation that cannot become lost? + Same memory object can be shared by multiple allocations. -Yes, although it has no visible effect. -Calls to vmaGetAllocationInfo() and vmaTouchAllocation() update last use frame index -also for allocations that cannot become lost, but the only way to observe it is to dump -internal allocator state using vmaBuildStatsString(). -You can use this feature for debugging purposes to explicitly mark allocations that you use -in current frame and then analyze JSON dump to see for how long each allocation stays unused. + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; + /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. + You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function + vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, + not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation + and apply this offset automatically. -\page statistics Statistics + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceSize offset; + /** \brief Size of this allocation, in bytes. -This library contains functions that return information about its internal state, -especially the amount of memory allocated from Vulkan. -Please keep in mind that these functions need to traverse all internal data structures -to gather these information, so they may be quite time-consuming. -Don't call them too often. + It never changes. -\section statistics_numeric_statistics Numeric statistics + \note Allocation size returned in this variable may be greater than the size + requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the + allocation is accessible for operations on memory e.g. using a pointer after + mapping with vmaMapMemory(), but operations on the resource e.g. using + `vkCmdCopyBuffer` must be limited to the size of the resource. + */ + VkDeviceSize size; + /** \brief Pointer to the beginning of this allocation as mapped data. -You can query for overall statistics of the allocator using function vmaCalculateStats(). -Information are returned using structure #VmaStats. -It contains #VmaStatInfo - number of allocated blocks, number of allocations -(occupied ranges in these blocks), number of unused (free) ranges in these blocks, -number of bytes used and unused (but still allocated from Vulkan) and other information. -They are summed across memory heaps, memory types and total for whole allocator. + If the allocation hasn't been mapped using vmaMapMemory() and hasn't been + created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. -You can query for statistics of a custom pool using function vmaGetPoolStats(). -Information are returned using structure #VmaPoolStats. + It can change after call to vmaMapMemory(), vmaUnmapMemory(). + It can also change after the allocation is moved during \ref defragmentation. + */ + void* VMA_NULLABLE pMappedData; + /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). -You can query for information about specific allocation using function vmaGetAllocationInfo(). -It fill structure #VmaAllocationInfo. + It can change after call to vmaSetAllocationUserData() for this allocation. + */ + void* VMA_NULLABLE pUserData; + /** \brief Custom allocation name that was set with vmaSetAllocationName(). -\section statistics_json_dump JSON dump + It can change after call to vmaSetAllocationName() for this allocation. -You can dump internal state of the allocator to a string in JSON format using function vmaBuildStatsString(). -The result is guaranteed to be correct JSON. -It uses ANSI encoding. -Any strings provided by user (see [Allocation names](@ref allocation_names)) -are copied as-is and properly escaped for JSON, so if they use UTF-8, ISO-8859-2 or any other encoding, -this JSON string can be treated as using this encoding. -It must be freed using function vmaFreeStatsString(). + Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with + additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. + */ + const char* VMA_NULLABLE pName; +} VmaAllocationInfo; -The format of this JSON string is not part of official documentation of the library, -but it will not change in backward-incompatible way without increasing library major version number -and appropriate mention in changelog. +/** \brief Parameters for defragmentation. -The JSON string contains all the data that can be obtained using vmaCalculateStats(). -It can also contain detailed map of allocated memory blocks and their regions - -free and occupied by allocations. -This allows e.g. to visualize the memory or assess fragmentation. +To be used with function vmaBeginDefragmentation(). +*/ +typedef struct VmaDefragmentationInfo +{ + /// \brief Use combination of #VmaDefragmentationFlagBits. + VmaDefragmentationFlags flags; + /** \brief Custom pool to be defragmented. + If null then default pools will undergo defragmentation process. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. -\page allocation_annotation Allocation names and user data + `0` means no limit. + */ + VkDeviceSize maxBytesPerPass; + /** \brief Maximum number of allocations that can be moved during single pass to a different place. -\section allocation_user_data Allocation user data + `0` means no limit. + */ + uint32_t maxAllocationsPerPass; +} VmaDefragmentationInfo; -You can annotate allocations with your own information, e.g. for debugging purposes. -To do that, fill VmaAllocationCreateInfo::pUserData field when creating -an allocation. It's an opaque `void*` pointer. You can use it e.g. as a pointer, -some handle, index, key, ordinal number or any other value that would associate -the allocation with your custom metadata. +/// Single move of an allocation to be done for defragmentation. +typedef struct VmaDefragmentationMove +{ + /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. + VmaDefragmentationMoveOperation operation; + /// Allocation that should be moved. + VmaAllocation VMA_NOT_NULL srcAllocation; + /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -// Fill bufferInfo... + \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, + to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). + vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. + */ + VmaAllocation VMA_NOT_NULL dstTmpAllocation; +} VmaDefragmentationMove; -MyBufferMetadata* pMetadata = CreateBufferMetadata(); +/** \brief Parameters for incremental defragmentation steps. -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.pUserData = pMetadata; +To be used with function vmaBeginDefragmentationPass(). +*/ +typedef struct VmaDefragmentationPassMoveInfo +{ + /// Number of elements in the `pMoves` array. + uint32_t moveCount; + /** \brief Array of moves to be performed by the user in the current defragmentation pass. -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, nullptr); -\endcode + Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). -The pointer may be later retrieved as VmaAllocationInfo::pUserData: + For each element, you should: -\code -VmaAllocationInfo allocInfo; -vmaGetAllocationInfo(allocator, allocation, &allocInfo); -MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData; -\endcode + 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. + 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. + 3. Make sure these commands finished executing on the GPU. + 4. Destroy the old buffer/image. -It can also be changed using function vmaSetAllocationUserData(). + Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). + After this call, the allocation will point to the new place in memory. -Values of (non-zero) allocations' `pUserData` are printed in JSON report created by -vmaBuildStatsString(), in hexadecimal form. + Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. -\section allocation_names Allocation names + Alternatively, if you decide you want to completely remove the allocation: -There is alternative mode available where `pUserData` pointer is used to point to -a null-terminated string, giving a name to the allocation. To use this mode, -set #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT flag in VmaAllocationCreateInfo::flags. -Then `pUserData` passed as VmaAllocationCreateInfo::pUserData or argument to -vmaSetAllocationUserData() must be either null or pointer to a null-terminated string. -The library creates internal copy of the string, so the pointer you pass doesn't need -to be valid for whole lifetime of the allocation. You can free it after the call. + 1. Destroy its buffer/image. + 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. -\code -VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; -// Fill imageInfo... + Then, after vmaEndDefragmentationPass() the allocation will be freed. + */ + VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; +} VmaDefragmentationPassMoveInfo; -std::string imageName = "Texture: "; -imageName += fileName; +/// Statistics returned for defragmentation process in function vmaEndDefragmentation(). +typedef struct VmaDefragmentationStats +{ + /// Total number of bytes that have been copied while moving allocations to different places. + VkDeviceSize bytesMoved; + /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. + VkDeviceSize bytesFreed; + /// Number of allocations that have been moved to different places. + uint32_t allocationsMoved; + /// Number of empty `VkDeviceMemory` objects that have been released to the system. + uint32_t deviceMemoryBlocksFreed; +} VmaDefragmentationStats; -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT; -allocCreateInfo.pUserData = imageName.c_str(); +/** @} */ -VkImage image; -VmaAllocation allocation; -vmaCreateImage(allocator, &imageInfo, &allocCreateInfo, &image, &allocation, nullptr); -\endcode +/** +\addtogroup group_virtual +@{ +*/ -The value of `pUserData` pointer of the allocation will be different than the one -you passed when setting allocation's name - pointing to a buffer managed -internally that holds copy of the string. +/// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). +typedef struct VmaVirtualBlockCreateInfo +{ + /** \brief Total size of the virtual block. -\code -VmaAllocationInfo allocInfo; -vmaGetAllocationInfo(allocator, allocation, &allocInfo); -const char* imageName = (const char*)allocInfo.pUserData; -printf("Image name: %s\n", imageName); -\endcode + Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. + For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. + */ + VkDeviceSize size; -That string is also printed in JSON report created by vmaBuildStatsString(). + /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. + */ + VmaVirtualBlockCreateFlags flags; -\note Passing string name to VMA allocation doesn't automatically set it to the Vulkan buffer or image created with it. -You must do it manually using an extension like VK_EXT_debug_utils, which is independent of this library. + /** \brief Custom CPU memory allocation callbacks. Optional. + Optional, can be null. When specified, they will be used for all CPU-side memory allocations. + */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; +} VmaVirtualBlockCreateInfo; -\page debugging_memory_usage Debugging incorrect memory usage +/// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). +typedef struct VmaVirtualAllocationCreateInfo +{ + /** \brief Size of the allocation. -If you suspect a bug with memory usage, like usage of uninitialized memory or -memory being overwritten out of bounds of an allocation, -you can use debug features of this library to verify this. + Cannot be zero. + */ + VkDeviceSize size; + /** \brief Required alignment of the allocation. Optional. -\section debugging_memory_usage_initialization Memory initialization + Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. + */ + VkDeviceSize alignment; + /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. + */ + VmaVirtualAllocationCreateFlags flags; + /** \brief Custom pointer to be associated with the allocation. Optional. -If you experience a bug with incorrect and nondeterministic data in your program and you suspect uninitialized memory to be used, -you can enable automatic memory initialization to verify this. -To do it, define macro `VMA_DEBUG_INITIALIZE_ALLOCATIONS` to 1. + It can be any value and can be used for user-defined purposes. It can be fetched or changed later. + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationCreateInfo; -\code -#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1 -#include "vk_mem_alloc.h" -\endcode +/// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). +typedef struct VmaVirtualAllocationInfo +{ + /** \brief Offset of the allocation. -It makes memory of all new allocations initialized to bit pattern `0xDCDCDCDC`. -Before an allocation is destroyed, its memory is filled with bit pattern `0xEFEFEFEF`. -Memory is automatically mapped and unmapped if necessary. + Offset at which the allocation was made. + */ + VkDeviceSize offset; + /** \brief Size of the allocation. -If you find these values while debugging your program, good chances are that you incorrectly -read Vulkan memory that is allocated but not initialized, or already freed, respectively. + Same value as passed in VmaVirtualAllocationCreateInfo::size. + */ + VkDeviceSize size; + /** \brief Custom pointer associated with the allocation. -Memory initialization works only with memory types that are `HOST_VISIBLE`. -It works also with dedicated allocations. -It doesn't work with allocations created with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, -as they cannot be mapped. + Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationInfo; -\section debugging_memory_usage_margins Margins +/** @} */ -By default, allocations are laid out in memory blocks next to each other if possible -(considering required alignment, `bufferImageGranularity`, and `nonCoherentAtomSize`). +#endif // _VMA_DATA_TYPES_DECLARATIONS -![Allocations without margin](../gfx/Margins_1.png) +#ifndef _VMA_FUNCTION_HEADERS -Define macro `VMA_DEBUG_MARGIN` to some non-zero value (e.g. 16) to enforce specified -number of bytes as a margin before and after every allocation. +/** +\addtogroup group_init +@{ +*/ -\code -#define VMA_DEBUG_MARGIN 16 -#include "vk_mem_alloc.h" -\endcode +/// Creates #VmaAllocator object. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); -![Allocations with margin](../gfx/Margins_2.png) +/// Destroys allocator object. +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator VMA_NULLABLE allocator); -If your bug goes away after enabling margins, it means it may be caused by memory -being overwritten outside of allocation boundaries. It is not 100% certain though. -Change in application behavior may also be caused by different order and distribution -of allocations across memory blocks after margins are applied. +/** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. -The margin is applied also before first and after last allocation in a block. -It may occur only once between two adjacent allocations. +It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to +`VkPhysicalDevice`, `VkDevice` etc. every time using this function. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); -Margins work with all types of memory. +/** +PhysicalDeviceProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); -Margin is applied only to allocations made out of memory blocks and not to dedicated -allocations, which have their own memory block of specific size. -It is thus not applied to allocations made using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT flag -or those automatically decided to put into dedicated allocations, e.g. due to its -large size or recommended by VK_KHR_dedicated_allocation extension. -Margins are also not active in custom pools created with #VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT flag. +/** +PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); -Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space. +/** +\brief Given Memory Type Index, returns Property Flags of this memory type. -Note that enabling margins increases memory usage and fragmentation. +This is just a convenience function. Same information can be obtained using +vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); -\section debugging_memory_usage_corruption_detection Corruption detection +/** \brief Sets index of the current frame. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t frameIndex); -You can additionally define macro `VMA_DEBUG_DETECT_CORRUPTION` to 1 to enable validation -of contents of the margins. +/** @} */ -\code -#define VMA_DEBUG_MARGIN 16 -#define VMA_DEBUG_DETECT_CORRUPTION 1 -#include "vk_mem_alloc.h" -\endcode +/** +\addtogroup group_stats +@{ +*/ -When this feature is enabled, number of bytes specified as `VMA_DEBUG_MARGIN` -(it must be multiply of 4) before and after every allocation is filled with a magic number. -This idea is also know as "canary". -Memory is automatically mapped and unmapped if necessary. +/** \brief Retrieves statistics from current state of the Allocator. -This number is validated automatically when the allocation is destroyed. -If it's not equal to the expected value, `VMA_ASSERT()` is executed. -It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation, -which indicates a serious bug. +This function is called "calculate" not "get" because it has to traverse all +internal data structures, so it may be quite slow. Use it for debugging purposes. +For faster but more brief statistics suitable to be called every frame or every allocation, +use vmaGetHeapBudgets(). -You can also explicitly request checking margins of all allocations in all memory blocks -that belong to specified memory types by using function vmaCheckCorruption(), -or in memory blocks that belong to specified custom pool, by using function -vmaCheckPoolCorruption(). +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaTotalStatistics* VMA_NOT_NULL pStats); -Margin validation (corruption detection) works only for memory types that are -`HOST_VISIBLE` and `HOST_COHERENT`. +/** \brief Retrieves information about current memory usage and budget for all memory heaps. +\param allocator +\param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. -\page record_and_replay Record and replay +This function is called "get" not "calculate" because it is very fast, suitable to be called +every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). -\section record_and_replay_introduction Introduction +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator VMA_NOT_NULL allocator, + VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); -While using the library, sequence of calls to its functions together with their -parameters can be recorded to a file and later replayed using standalone player -application. It can be useful to: +/** @} */ -- Test correctness - check if same sequence of calls will not cause crash or - failures on a target platform. -- Gather statistics - see number of allocations, peak memory usage, number of - calls etc. -- Benchmark performance - see how much time it takes to replay the whole - sequence. +/** +\addtogroup group_alloc +@{ +*/ -\section record_and_replay_usage Usage +/** +\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. -Recording functionality is disabled by default. -To enable it, define following macro before every include of this library: +This algorithm tries to find a memory type that: -\code -#define VMA_RECORDING_ENABLED 1 -\endcode +- Is allowed by memoryTypeBits. +- Contains all the flags from pAllocationCreateInfo->requiredFlags. +- Matches intended usage. +- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. -To record sequence of calls to a file: Fill in -VmaAllocatorCreateInfo::pRecordSettings member while creating #VmaAllocator -object. File is opened and written during whole lifetime of the allocator. +\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result +from this function or any other allocating function probably means that your +device doesn't support any memory type with requested features for the specific +type of resource you want to use it for. Please check parameters of your +resource, like image layout (OPTIMAL versus LINEAR) or mip level count. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); -To replay file: Use VmaReplay - standalone command-line program. -Precompiled binary can be found in "bin" directory. -Its source can be found in "src/VmaReplay" directory. -Its project is generated by Premake. -Command line syntax is printed when the program is launched without parameters. -Basic usage: +/** +\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. - VmaReplay.exe MyRecording.csv +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy buffer that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); -Documentation of file format can be found in file: "docs/Recording file format.md". -It's a human-readable, text file in CSV format (Comma Separated Values). +/** +\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. -\section record_and_replay_additional_considerations Additional considerations +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy image that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); -- Replaying file that was recorded on a different GPU (with different parameters - like `bufferImageGranularity`, `nonCoherentAtomSize`, and especially different - set of memory heaps and types) may give different performance and memory usage - results, as well as issue some warnings and errors. -- Current implementation of recording in VMA, as well as VmaReplay application, is - coded and tested only on Windows. Inclusion of recording code is driven by - `VMA_RECORDING_ENABLED` macro. Support for other platforms should be easy to - add. Contributions are welcomed. +/** \brief Allocates Vulkan device memory and creates #VmaPool object. +\param allocator Allocator object. +\param pCreateInfo Parameters of pool to create. +\param[out] pPool Handle to created pool. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator VMA_NOT_NULL allocator, + const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); -\page usage_patterns Recommended usage patterns +/** \brief Destroys #VmaPool object and frees Vulkan device memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NULLABLE pool); -See also slides from talk: -[Sawicki, Adam. Advanced Graphics Techniques Tutorial: Memory management in Vulkan and DX12. Game Developers Conference, 2018](https://www.gdcvault.com/play/1025458/Advanced-Graphics-Techniques-Tutorial-New) +/** @} */ +/** +\addtogroup group_stats +@{ +*/ -\section usage_patterns_common_mistakes Common mistakes +/** \brief Retrieves statistics of existing #VmaPool object. -Use of CPU_TO_GPU instead of CPU_ONLY memory +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaStatistics* VMA_NOT_NULL pPoolStats); -#VMA_MEMORY_USAGE_CPU_TO_GPU is recommended only for resources that will be -mapped and written by the CPU, as well as read directly by the GPU - like some -buffers or textures updated every frame (dynamic). If you create a staging copy -of a resource to be written by CPU and then used as a source of transfer to -another resource placed in the GPU memory, that staging resource should be -created with #VMA_MEMORY_USAGE_CPU_ONLY. Please read the descriptions of these -enums carefully for details. +/** \brief Retrieves detailed statistics of existing #VmaPool object. -Unnecessary use of custom pools +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); -\ref custom_memory_pools may be useful for special purposes - when you want to -keep certain type of resources separate e.g. to reserve minimum amount of memory -for them, limit maximum amount of memory they can occupy, or make some of them -push out the other through the mechanism of \ref lost_allocations. For most -resources this is not needed and so it is not recommended to create #VmaPool -objects and allocations out of them. Allocating from the default pool is sufficient. +/** @} */ -\section usage_patterns_simple Simple patterns +/** +\addtogroup group_alloc +@{ +*/ -\subsection usage_patterns_simple_render_targets Render targets +/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. -When: -Any resources that you frequently write and read on GPU, -e.g. images used as color attachments (aka "render targets"), depth-stencil attachments, -images/buffers used as storage image/buffer (aka "Unordered Access View (UAV)"). +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). -What to do: -Create them in video memory that is fastest to access from GPU using -#VMA_MEMORY_USAGE_GPU_ONLY. +Possible return values: -Consider using [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension -and/or manually creating them as dedicated allocations using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, -especially if they are large or if you plan to destroy and recreate them e.g. when -display resolution changes. -Prefer to create such resources first and all other GPU resources (like textures and vertex buffers) later. +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool); -\subsection usage_patterns_simple_immutable_resources Immutable resources +/** \brief Retrieves name of a custom pool. -When: -Any resources that you fill on CPU only once (aka "immutable") or infrequently -and then read frequently on GPU, -e.g. textures, vertex and index buffers, constant buffers that don't change often. +After the call `ppName` is either null or points to an internally-owned null-terminated string +containing name of the pool that was previously set. The pointer becomes invalid when the pool is +destroyed or its name is changed using vmaSetPoolName(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE* VMA_NOT_NULL ppName); -What to do: -Create them in video memory that is fastest to access from GPU using -#VMA_MEMORY_USAGE_GPU_ONLY. +/** \brief Sets name of a custom pool. -To initialize content of such resource, create a CPU-side (aka "staging") copy of it -in system memory - #VMA_MEMORY_USAGE_CPU_ONLY, map it, fill it, -and submit a transfer from it to the GPU resource. -You can keep the staging copy if you need it for another upload transfer in the future. -If you don't, you can destroy it or reuse this buffer for uploading different resource -after the transfer finishes. +`pName` can be either null or pointer to a null-terminated string with new name for the pool. +Function makes internal copy of the string, so it can be changed or freed immediately after this call. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE pName); -Prefer to create just buffers in system memory rather than images, even for uploading textures. -Use `vkCmdCopyBufferToImage()`. -Dont use images with `VK_IMAGE_TILING_LINEAR`. +/** \brief General purpose memory allocation. -\subsection usage_patterns_dynamic_resources Dynamic resources +\param allocator +\param pVkMemoryRequirements +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). -When: -Any resources that change frequently (aka "dynamic"), e.g. every frame or every draw call, -written on CPU, read on GPU. +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). -What to do: -Create them using #VMA_MEMORY_USAGE_CPU_TO_GPU. -You can map it and write to it directly on CPU, as well as read from it on GPU. +It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), +vmaCreateBuffer(), vmaCreateImage() instead whenever possible. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); -This is a more complex situation. Different solutions are possible, -and the best one depends on specific GPU type, but you can use this simple approach for the start. -Prefer to write to such resource sequentially (e.g. using `memcpy`). -Don't perform random access or any reads from it on CPU, as it may be very slow. +/** \brief General purpose memory allocation for multiple allocation objects at once. -\subsection usage_patterns_readback Readback +\param allocator Allocator object. +\param pVkMemoryRequirements Memory requirements for each allocation. +\param pCreateInfo Creation parameters for each allocation. +\param allocationCount Number of allocations to make. +\param[out] pAllocations Pointer to array that will be filled with handles to created allocations. +\param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. -When: -Resources that contain data written by GPU that you want to read back on CPU, -e.g. results of some computations. +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). -What to do: -Create them using #VMA_MEMORY_USAGE_GPU_TO_CPU. -You can write to them directly on GPU, as well as map and read them on CPU. +Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. +It is just a general purpose allocation function able to make multiple allocations at once. +It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. -\section usage_patterns_advanced Advanced patterns +All allocations are made using same parameters. All of them are created out of the same memory pool and type. +If any allocation fails, all allocations already made within this function call are also freed, so that when +returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, + size_t allocationCount, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, + VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); -\subsection usage_patterns_integrated_graphics Detecting integrated graphics +/** \brief Allocates memory suitable for given `VkBuffer`. -You can support integrated graphics (like Intel HD Graphics, AMD APU) better -by detecting it in Vulkan. -To do it, call `vkGetPhysicalDeviceProperties()`, inspect -`VkPhysicalDeviceProperties::deviceType` and look for `VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU`. -When you find it, you can assume that memory is unified and all memory types are comparably fast -to access from GPU, regardless of `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. +\param allocator +\param buffer +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). -You can then sum up sizes of all available memory heaps and treat them as useful for -your GPU resources, instead of only `DEVICE_LOCAL` ones. -You can also prefer to create your resources in memory types that are `HOST_VISIBLE` to map them -directly instead of submitting explicit transfer (see below). +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). -\subsection usage_patterns_direct_vs_transfer Direct access versus transfer +This is a special-purpose function. In most cases you should use vmaCreateBuffer(). -For resources that you frequently write on CPU and read on GPU, many solutions are possible: +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); --# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, - second copy in system memory using #VMA_MEMORY_USAGE_CPU_ONLY and submit explicit tranfer each time. --# Create just single copy using #VMA_MEMORY_USAGE_CPU_TO_GPU, map it and fill it on CPU, - read it directly on GPU. --# Create just single copy using #VMA_MEMORY_USAGE_CPU_ONLY, map it and fill it on CPU, - read it directly on GPU. +/** \brief Allocates memory suitable for given `VkImage`. -Which solution is the most efficient depends on your resource and especially on the GPU. -It is best to measure it and then make the decision. -Some general recommendations: +\param allocator +\param image +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). -- On integrated graphics use (2) or (3) to avoid unnecesary time and memory overhead - related to using a second copy and making transfer. -- For small resources (e.g. constant buffers) use (2). - Discrete AMD cards have special 256 MiB pool of video memory that is directly mappable. - Even if the resource ends up in system memory, its data may be cached on GPU after first - fetch over PCIe bus. -- For larger resources (e.g. textures), decide between (1) and (2). - You may want to differentiate NVIDIA and AMD, e.g. by looking for memory type that is - both `DEVICE_LOCAL` and `HOST_VISIBLE`. When you find it, use (2), otherwise use (1). +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). -Similarly, for resources that you frequently write on GPU and read on CPU, multiple -solutions are possible: +This is a special-purpose function. In most cases you should use vmaCreateImage(). --# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, - second copy in system memory using #VMA_MEMORY_USAGE_GPU_TO_CPU and submit explicit tranfer each time. --# Create just single copy using #VMA_MEMORY_USAGE_GPU_TO_CPU, write to it directly on GPU, - map it and read it on CPU. +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); -You should take some measurements to decide which option is faster in case of your specific -resource. +/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). -If you don't want to specialize your code for specific types of GPUs, you can still make -an simple optimization for cases when your resource ends up in mappable memory to use it -directly in this case instead of creating CPU-side staging copy. -For details see [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable). +Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VmaAllocation VMA_NULLABLE allocation); +/** \brief Frees memory and destroys multiple allocations. -\page configuration Configuration +Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. +It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), +vmaAllocateMemoryPages() and other functions. +It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. -Please check "CONFIGURATION SECTION" in the code to find macros that you can define -before each include of this file or change directly in this file to provide -your own implementation of basic facilities like assert, `min()` and `max()` functions, -mutex, atomic etc. -The library uses its own implementation of containers by default, but you can switch to using -STL containers instead. +Allocations in `pAllocations` array can come from any memory pools and types. +Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + size_t allocationCount, + const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); -For example, define `VMA_ASSERT(expr)` before including the library to provide -custom implementation of the assertion, compatible with your project. -By default it is defined to standard C `assert(expr)` in `_DEBUG` configuration -and empty otherwise. +/** \brief Returns current information about specified allocation. -\section custom_memory_allocator Custom host memory allocator +Current parameters of given allocation are returned in `pAllocationInfo`. -If you use custom allocator for CPU memory rather than default operator `new` -and `delete` from C++, you can make this library using your allocator as well -by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These -functions will be passed to Vulkan, as well as used by the library itself to -make any CPU-side allocations. +Although this function doesn't lock any mutex, so it should be quite efficient, +you should avoid calling it too often. +You can retrieve same VmaAllocationInfo structure while creating your resource, from function +vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change +(e.g. due to defragmentation). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); -\section allocation_callbacks Device memory allocation callbacks +/** \brief Sets pUserData in given allocation to new value. -The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally. -You can setup callbacks to be informed about these calls, e.g. for the purpose -of gathering some statistics. To do it, fill optional member -VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. +The value of pointer `pUserData` is copied to allocation's `pUserData`. +It is opaque, so you can use it however you want - e.g. +as a pointer, ordinal number or some handle to you own data. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE pUserData); -\section heap_memory_limit Device heap memory limit +/** \brief Sets pName in given allocation to new value. -When device memory of certain heap runs out of free space, new allocations may -fail (returning error code) or they may succeed, silently pushing some existing -memory blocks from GPU VRAM to system RAM (which degrades performance). This -behavior is implementation-dependant - it depends on GPU vendor and graphics -driver. +`pName` must be either null, or pointer to a null-terminated string. The function +makes local copy of the string and sets it as allocation's `pName`. String +passed as pName doesn't need to be valid for whole lifetime of the allocation - +you can free it after this call. String previously pointed by allocation's +`pName` is freed from memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName); -On AMD cards it can be controlled while creating Vulkan device object by using -VK_AMD_memory_overallocation_behavior extension, if available. +/** +\brief Given an allocation, returns Property Flags of its memory type. -Alternatively, if you want to test how your program behaves with limited amount of Vulkan device -memory available without switching your graphics card to one that really has -smaller VRAM, you can use a feature of this library intended for this purpose. -To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit. +This is just a convenience function. Same information can be obtained using +vmaGetAllocationInfo() + vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); +/** \brief Maps memory represented by given allocation and returns pointer to it. +Maps memory represented by given allocation to make it accessible to CPU code. +When succeeded, `*ppData` contains pointer to first byte of this memory. -\page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation +\warning +If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is +correctly offsetted to the beginning of region assigned to this particular allocation. +Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. +You should not add VmaAllocationInfo::offset to it! -VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve -performance on some GPUs. It augments Vulkan API with possibility to query -driver whether it prefers particular buffer or image to have its own, dedicated -allocation (separate `VkDeviceMemory` block) for better efficiency - to be able -to do some internal optimizations. +Mapping is internally reference-counted and synchronized, so despite raw Vulkan +function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` +multiple times simultaneously, it is safe to call this function on allocations +assigned to the same memory block. Actual Vulkan memory will be mapped on first +mapping and unmapped on last unmapping. -The extension is supported by this library. It will be used automatically when -enabled. To enable it: +If the function succeeded, you must call vmaUnmapMemory() to unmap the +allocation when mapping is no longer needed or before freeing the allocation, at +the latest. -1 . When creating Vulkan device, check if following 2 device extensions are -supported (call `vkEnumerateDeviceExtensionProperties()`). -If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`). +It also safe to call this function multiple times on the same allocation. You +must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). -- VK_KHR_get_memory_requirements2 -- VK_KHR_dedicated_allocation +It is also safe to call this function on allocation created with +#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. +You must still call vmaUnmapMemory() same number of times as you called +vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the +"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. -If you enabled these extensions: +This function fails when used on allocation made in memory type that is not +`HOST_VISIBLE`. -2 . Use #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag when creating -your #VmaAllocator`to inform the library that you enabled required extensions -and you want the library to use them. +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE* VMA_NOT_NULL ppData); -\code -allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; +/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). -vmaCreateAllocator(&allocatorInfo, &allocator); -\endcode +For details, see description of vmaMapMemory(). -That's all. The extension will be automatically used whenever you create a -buffer using vmaCreateBuffer() or image using vmaCreateImage(). +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation); -When using the extension together with Vulkan Validation Layer, you will receive -warnings like this: +/** \brief Flushes memory of given allocation. - vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer. +Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. +Unmap operation doesn't do that automatically. -It is OK, you should just ignore it. It happens because you use function -`vkGetBufferMemoryRequirements2KHR()` instead of standard -`vkGetBufferMemoryRequirements()`, while the validation layer seems to be -unaware of it. +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. -To learn more about this extension, see: +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! -- [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap44.html#VK_KHR_dedicated_allocation) -- [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5) +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); +/** \brief Invalidates memory of given allocation. +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. +Map operation doesn't do that automatically. -\page vk_amd_device_coherent_memory VK_AMD_device_coherent_memory +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. -VK_AMD_device_coherent_memory is a device extension that enables access to -additional memory types with `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and -`VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flag. It is useful mostly for -allocation of buffers intended for writing "breadcrumb markers" in between passes -or draw calls, which in turn are useful for debugging GPU crash/hang/TDR cases. +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! -When the extension is available but has not been enabled, Vulkan physical device -still exposes those memory types, but their usage is forbidden. VMA automatically -takes care of that - it returns `VK_ERROR_FEATURE_NOT_PRESENT` when an attempt -to allocate memory of such type is made. +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if +it is called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); -If you want to use this extension in connection with VMA, follow these steps: +/** \brief Flushes memory of given set of allocations. -\section vk_amd_device_coherent_memory_initialization Initialization +Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaFlushAllocation(). -1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. -Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_AMD_device_coherent_memory". +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. -2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. -Attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to `VkPhysicalDeviceFeatures2::pNext` to be returned. -Check if the device feature is really supported - check if `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true. +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); -3) While creating device with `vkCreateDevice`, enable this extension - add "VK_AMD_device_coherent_memory" -to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. +/** \brief Invalidates memory of given set of allocations. -4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. -Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. -Enable this device feature - attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to -`VkPhysicalDeviceFeatures2::pNext` and set its member `deviceCoherentMemory` to `VK_TRUE`. +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaInvalidateAllocation(). -5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you -have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT -to VmaAllocatorCreateInfo::flags. +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. -\section vk_amd_device_coherent_memory_usage Usage +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); -After following steps described above, you can create VMA allocations and custom pools -out of the special `DEVICE_COHERENT` and `DEVICE_UNCACHED` memory types on eligible -devices. There are multiple ways to do it, for example: +/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. -- You can request or prefer to allocate out of such memory types by adding - `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` to VmaAllocationCreateInfo::requiredFlags - or VmaAllocationCreateInfo::preferredFlags. Those flags can be freely mixed with - other ways of \ref choosing_memory_type, like setting VmaAllocationCreateInfo::usage. -- If you manually found memory type index to use for this purpose, force allocation - from this specific index by setting VmaAllocationCreateInfo::memoryTypeBits `= 1u << index`. +\param allocator +\param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. -\section vk_amd_device_coherent_memory_more_information More information +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). -To learn more about this extension, see [VK_AMD_device_coherent_memory in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap44.html#VK_AMD_device_coherent_memory) +Possible return values: -Example use of this extension can be found in the code of the sample and test suite -accompanying this library. +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits); +/** \brief Begins defragmentation process. -\page enabling_buffer_device_address Enabling buffer device address +\param allocator Allocator object. +\param pInfo Structure filled with parameters of defragmentation. +\param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. +\returns +- `VK_SUCCESS` if defragmentation can begin. +- `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. -Device extension VK_KHR_buffer_device_address -allow to fetch raw GPU pointer to a buffer and pass it for usage in a shader code. -It is promoted to core Vulkan 1.2. +For more information about defragmentation, see documentation chapter: +[Defragmentation](@ref defragmentation). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, + VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); -If you want to use this feature in connection with VMA, follow these steps: +/** \brief Ends defragmentation process. -\section enabling_buffer_device_address_initialization Initialization +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pStats Optional stats for the defragmentation. Can be null. -1) (For Vulkan version < 1.2) Call `vkEnumerateDeviceExtensionProperties` for the physical device. -Check if the extension is supported - if returned array of `VkExtensionProperties` contains -"VK_KHR_buffer_device_address". +Use this function to finish defragmentation started by vmaBeginDefragmentation(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationStats* VMA_NULLABLE pStats); + +/** \brief Starts single defragmentation pass. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pPassInfo Computed information for current pass. +\returns +- `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. +- `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), + and then preferably try another pass with vmaBeginDefragmentationPass(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); -2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. -Attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to `VkPhysicalDeviceFeatures2::pNext` to be returned. -Check if the device feature is really supported - check if `VkPhysicalDeviceBufferDeviceAddressFeatures*::bufferDeviceAddress` is true. +/** \brief Ends single defragmentation pass. -3) (For Vulkan version < 1.2) While creating device with `vkCreateDevice`, enable this extension - add -"VK_KHR_buffer_device_address" to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param pPassInfo Computed information for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. -4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. -Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. -Enable this device feature - attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to -`VkPhysicalDeviceFeatures2::pNext` and set its member `bufferDeviceAddress` to `VK_TRUE`. +Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. -5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you -have enabled this feature - add #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT -to VmaAllocatorCreateInfo::flags. +Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. +After this call: -\section enabling_buffer_device_address_usage Usage +- Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY + (which is the default) will be pointing to the new destination place. +- Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY + will be freed. -After following steps described above, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. -The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to -allocated memory blocks wherever it might be needed. +If no more moves are possible you can end whole defragmentation. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); -Please note that the library supports only `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*`. -The second part of this functionality related to "capture and replay" is not supported, -as it is intended for usage in debugging tools like RenderDoc, not in everyday Vulkan usage. +/** \brief Binds buffer to allocation. -\section enabling_buffer_device_address_more_information More information +Binds specified buffer to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create a buffer, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindBufferMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). -To learn more about this extension, see [VK_KHR_buffer_device_address in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap46.html#VK_KHR_buffer_device_address) +It is recommended to use function vmaCreateBuffer() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); -Example use of this extension can be found in the code of the sample and test suite -accompanying this library. +/** \brief Binds buffer to allocation with additional parameters. -\page general_considerations General considerations +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param buffer +\param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. -\section general_considerations_thread_safety Thread safety +This function is similar to vmaBindBufferMemory(), but it provides additional parameters. -- The library has no global state, so separate #VmaAllocator objects can be used - independently. - There should be no need to create multiple such objects though - one per `VkDevice` is enough. -- By default, all calls to functions that take #VmaAllocator as first parameter - are safe to call from multiple threads simultaneously because they are - synchronized internally when needed. -- When the allocator is created with #VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT - flag, calls to functions that take such #VmaAllocator object must be - synchronized externally. -- Access to a #VmaAllocation object must be externally synchronized. For example, - you must not call vmaGetAllocationInfo() and vmaMapMemory() from different - threads at the same time if you pass the same #VmaAllocation object to these - functions. +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const void* VMA_NULLABLE pNext); -\section general_considerations_validation_layer_warnings Validation layer warnings +/** \brief Binds image to allocation. -When using this library, you can meet following types of warnings issued by -Vulkan validation layer. They don't necessarily indicate a bug, so you may need -to just ignore them. +Binds specified image to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create an image, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindImageMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). -- *vkBindBufferMemory(): Binding memory to buffer 0xeb8e4 but vkGetBufferMemoryRequirements() has not been called on that buffer.* - - It happens when VK_KHR_dedicated_allocation extension is enabled. - `vkGetBufferMemoryRequirements2KHR` function is used instead, while validation layer seems to be unaware of it. -- *Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used.* - - It happens when you map a buffer or image, because the library maps entire - `VkDeviceMemory` block, where different types of images and buffers may end - up together, especially on GPUs with unified memory like Intel. -- *Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug.* - - It happens when you use lost allocations, and a new image or buffer is - created in place of an existing object that bacame lost. - - It may happen also when you use [defragmentation](@ref defragmentation). +It is recommended to use function vmaCreateImage() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); -\section general_considerations_allocation_algorithm Allocation algorithm +/** \brief Binds image to allocation with additional parameters. -The library uses following algorithm for allocation, in order: +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param image +\param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. --# Try to find free range of memory in existing blocks. --# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size. --# If failed, try to create such block with size/2, size/4, size/8. --# If failed and #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag was - specified, try to find space in existing blocks, possilby making some other - allocations lost. --# If failed, try to allocate separate `VkDeviceMemory` for this allocation, - just like when you use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. --# If failed, choose other memory type that meets the requirements specified in - VmaAllocationCreateInfo and go to point 1. --# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +This function is similar to vmaBindImageMemory(), but it provides additional parameters. -\section general_considerations_features_not_supported Features not supported +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const void* VMA_NULLABLE pNext); -Features deliberately excluded from the scope of this library: +/** \brief Creates a new `VkBuffer`, allocates and binds memory for it. -- Data transfer. Uploading (straming) and downloading data of buffers and images - between CPU and GPU memory and related synchronization is responsibility of the user. - Defining some "texture" object that would automatically stream its data from a - staging copy in CPU memory to GPU memory would rather be a feature of another, - higher-level library implemented on top of VMA. -- Allocations for imported/exported external memory. They tend to require - explicit memory type index and dedicated allocation anyway, so they don't - interact with main features of this library. Such special purpose allocations - should be made manually, using `vkCreateBuffer()` and `vkAllocateMemory()`. -- Recreation of buffers and images. Although the library has functions for - buffer and image creation (vmaCreateBuffer(), vmaCreateImage()), you need to - recreate these objects yourself after defragmentation. That's because the big - structures `VkBufferCreateInfo`, `VkImageCreateInfo` are not stored in - #VmaAllocation object. -- Handling CPU memory allocation failures. When dynamically creating small C++ - objects in CPU memory (not Vulkan memory), allocation failures are not checked - and handled gracefully, because that would complicate code significantly and - is usually not needed in desktop PC applications anyway. -- Code free of any compiler warnings. Maintaining the library to compile and - work correctly on so many different platforms is hard enough. Being free of - any warnings, on any version of any compiler, is simply not feasible. -- This is a C++ library with C interface. - Bindings or ports to any other programming languages are welcomed as external projects and - are not going to be included into this repository. +\param allocator +\param pBufferCreateInfo +\param pAllocationCreateInfo +\param[out] pBuffer Buffer that was created. +\param[out] pAllocation Allocation that was created. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). -*/ +This function automatically: -/* -Define this macro to 0/1 to disable/enable support for recording functionality, -available through VmaAllocatorCreateInfo::pRecordSettings. +-# Creates buffer. +-# Allocates appropriate memory for it. +-# Binds the buffer with the memory. + +If any of these operations fail, buffer and allocation are not created, +returned value is negative error code, `*pBuffer` and `*pAllocation` are null. + +If the function succeeded, you must destroy both buffer and allocation when you +no longer need them using either convenience function vmaDestroyBuffer() or +separately, using `vkDestroyBuffer()` and vmaFreeMemory(). + +If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, +VK_KHR_dedicated_allocation extension is used internally to query driver whether +it requires or prefers the new buffer to have dedicated allocation. If yes, +and if dedicated allocation is possible +(#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated +allocation for this buffer, just like when using +#VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + +\note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, +although recommended as a good practice, is out of scope of this library and could be implemented +by the user as a higher-level logic on top of VMA. */ -#ifndef VMA_RECORDING_ENABLED - #define VMA_RECORDING_ENABLED 0 -#endif +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a buffer with additional minimum alignment. + +Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, +minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. +for interop with OpenGL. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a new `VkBuffer`, binds already created memory for it. + +\param allocator +\param allocation Allocation that provides memory to be used for binding new buffer to it. +\param pBufferCreateInfo +\param[out] pBuffer Buffer that was created. -#ifndef NOMINMAX - #define NOMINMAX // For windows.h -#endif +This function automatically: -#ifndef VULKAN_H_ - #include -#endif +-# Creates buffer. +-# Binds the buffer with the supplied memory. -#if VMA_RECORDING_ENABLED - #include -#endif +If any of these operations fail, buffer is not created, +returned value is negative error code and `*pBuffer` is null. -// Define this macro to declare maximum supported Vulkan version in format AAABBBCCC, -// where AAA = major, BBB = minor, CCC = patch. -// If you want to use version > 1.0, it still needs to be enabled via VmaAllocatorCreateInfo::vulkanApiVersion. -#if !defined(VMA_VULKAN_VERSION) - #if defined(VK_VERSION_1_2) - #define VMA_VULKAN_VERSION 1002000 - #elif defined(VK_VERSION_1_1) - #define VMA_VULKAN_VERSION 1001000 - #else - #define VMA_VULKAN_VERSION 1000000 - #endif -#endif +If the function succeeded, you must destroy the buffer when you +no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding +allocation you can use convenience function vmaDestroyBuffer(). -#if !defined(VMA_DEDICATED_ALLOCATION) - #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation - #define VMA_DEDICATED_ALLOCATION 1 - #else - #define VMA_DEDICATED_ALLOCATION 0 - #endif -#endif +\note There is a new version of this function augmented with parameter `allocationLocalOffset` - see vmaCreateAliasingBuffer2(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); -#if !defined(VMA_BIND_MEMORY2) - #if VK_KHR_bind_memory2 - #define VMA_BIND_MEMORY2 1 - #else - #define VMA_BIND_MEMORY2 0 - #endif -#endif +/** \brief Creates a new `VkBuffer`, binds already created memory for it. -#if !defined(VMA_MEMORY_BUDGET) - #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) - #define VMA_MEMORY_BUDGET 1 - #else - #define VMA_MEMORY_BUDGET 0 - #endif -#endif +\param allocator +\param allocation Allocation that provides memory to be used for binding new buffer to it. +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the allocation. Normally it should be 0. +\param pBufferCreateInfo +\param[out] pBuffer Buffer that was created. -// Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. -#if !defined(VMA_BUFFER_DEVICE_ADDRESS) - #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 - #define VMA_BUFFER_DEVICE_ADDRESS 1 - #else - #define VMA_BUFFER_DEVICE_ADDRESS 0 - #endif -#endif +This function automatically: -// Define these macros to decorate all public functions with additional code, -// before and after returned type, appropriately. This may be useful for -// exporing the functions when compiling VMA as a separate library. Example: -// #define VMA_CALL_PRE __declspec(dllexport) -// #define VMA_CALL_POST __cdecl -#ifndef VMA_CALL_PRE - #define VMA_CALL_PRE -#endif -#ifndef VMA_CALL_POST - #define VMA_CALL_POST -#endif +-# Creates buffer. +-# Binds the buffer with the supplied memory. -/** \struct VmaAllocator -\brief Represents main object of this library initialized. +If any of these operations fail, buffer is not created, +returned value is negative error code and `*pBuffer` is null. -Fill structure #VmaAllocatorCreateInfo and call function vmaCreateAllocator() to create it. -Call function vmaDestroyAllocator() to destroy it. +If the function succeeded, you must destroy the buffer when you +no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding +allocation you can use convenience function vmaDestroyBuffer(). -It is recommended to create just one object of this type per `VkDevice` object, -right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. +\note This is a new version of the function augmented with parameter `allocationLocalOffset`. */ -VK_DEFINE_HANDLE(VmaAllocator) +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); -/// Callback function called after successful vkAllocateMemory. -typedef void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)( - VmaAllocator allocator, - uint32_t memoryType, - VkDeviceMemory memory, - VkDeviceSize size, - void* pUserData); -/// Callback function called before vkFreeMemory. -typedef void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)( - VmaAllocator allocator, - uint32_t memoryType, - VkDeviceMemory memory, - VkDeviceSize size, - void* pUserData); +/** \brief Destroys Vulkan buffer and frees allocated memory. -/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. +This is just a convenience function equivalent to: -Provided for informative purpose, e.g. to gather statistics about number of -allocations or total amount of memory allocated in Vulkan. +\code +vkDestroyBuffer(device, buffer, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode -Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. +It is safe to pass null as buffer and/or allocation. */ -typedef struct VmaDeviceMemoryCallbacks { - /// Optional, can be null. - PFN_vmaAllocateDeviceMemoryFunction pfnAllocate; - /// Optional, can be null. - PFN_vmaFreeDeviceMemoryFunction pfnFree; - /// Optional, can be null. - void* pUserData; -} VmaDeviceMemoryCallbacks; +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, + VmaAllocation VMA_NULLABLE allocation); -/// Flags for created #VmaAllocator. -typedef enum VmaAllocatorCreateFlagBits { - /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. +/// Function similar to vmaCreateBuffer(). +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/// Function similar to vmaCreateAliasingBuffer() but for images. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + +/// Function similar to vmaCreateAliasingBuffer2() but for images. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); - Using this flag may increase performance because internal mutexes are not used. - */ - VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, - /** \brief Enables usage of VK_KHR_dedicated_allocation extension. +/** \brief Destroys Vulkan image and frees allocated memory. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it's `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. +This is just a convenience function equivalent to: - Using this extenion will automatically allocate dedicated blocks of memory for - some buffers and images instead of suballocating place for them out of bigger - memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT - flag) when it is recommended by the driver. It may improve performance on some - GPUs. +\code +vkDestroyImage(device, image, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode - You may set this flag only if you found out that following device extensions are - supported, you enabled them while creating Vulkan device passed as - VmaAllocatorCreateInfo::device, and you want them to be used internally by this - library: +It is safe to pass null as image and/or allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation); - - VK_KHR_get_memory_requirements2 (device extension) - - VK_KHR_dedicated_allocation (device extension) +/** @} */ - When this flag is set, you can experience following warnings reported by Vulkan - validation layer. You can ignore them. +/** +\addtogroup group_virtual +@{ +*/ - > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. - */ - VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, - /** - Enables usage of VK_KHR_bind_memory2 extension. +/** \brief Creates new #VmaVirtualBlock object. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it's `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. +\param pCreateInfo Parameters for creation. +\param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library. +/** \brief Destroys #VmaVirtualBlock object. - The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, - which allow to pass a chain of `pNext` structures while binding. - This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). - */ - VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, - /** - Enables usage of VK_EXT_memory_budget extension. +Please note that you should consciously handle virtual allocations that could remain unfreed in the block. +You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() +if you are sure this is what you want. If you do neither, an assert is called. - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library, along with another instance extension - VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). +If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, +don't forget to free them. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( + VmaVirtualBlock VMA_NULLABLE virtualBlock); - The extension provides query for current memory usage and budget, which will probably - be more accurate than an estimation used by the library otherwise. - */ - VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, - /** - Enables usage of VK_AMD_device_coherent_memory extension. - - You may set this flag only if you: +/** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. +*/ +VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); - - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, - - want it to be used internally by this library. +/** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); - The extension and accompanying device feature provide access to memory types with - `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. - They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. - - When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. - To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, - returning `VK_ERROR_FEATURE_NOT_PRESENT`. - */ - VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, - /** - Enables usage of "buffer device address" feature, which allows you to use function - `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. +/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. - You may set this flag only if you: +If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned +(despite the function doesn't ever allocate actual GPU memory). +`pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. - 1. (For Vulkan version < 1.2) Found as available and enabled device extension - VK_KHR_buffer_device_address. - This extension is promoted to core Vulkan 1.2. - 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures*::bufferDeviceAddress`. +\param virtualBlock Virtual block +\param pCreateInfo Parameters for the allocation +\param[out] pAllocation Returned handle of the new allocation +\param[out] pOffset Returned offset of the new allocation. Optional, can be null. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset); - When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. - The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to - allocated memory blocks wherever it might be needed. +/** \brief Frees virtual allocation inside given #VmaVirtualBlock. - For more information, see documentation chapter \ref enabling_buffer_device_address. - */ - VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, +It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); - VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocatorCreateFlagBits; -typedef VkFlags VmaAllocatorCreateFlags; +/** \brief Frees all virtual allocations inside given #VmaVirtualBlock. -/** \brief Pointers to some Vulkan functions - a subset used by the library. +You must either call this function or free each virtual allocation individually with vmaVirtualFree() +before destroying a virtual block. Otherwise, an assert is called. -Used in VmaAllocatorCreateInfo::pVulkanFunctions. +If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, +don't forget to free it as well. */ -typedef struct VmaVulkanFunctions { - PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; - PFN_vkAllocateMemory vkAllocateMemory; - PFN_vkFreeMemory vkFreeMemory; - PFN_vkMapMemory vkMapMemory; - PFN_vkUnmapMemory vkUnmapMemory; - PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; - PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; - PFN_vkBindBufferMemory vkBindBufferMemory; - PFN_vkBindImageMemory vkBindImageMemory; - PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; - PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; - PFN_vkCreateBuffer vkCreateBuffer; - PFN_vkDestroyBuffer vkDestroyBuffer; - PFN_vkCreateImage vkCreateImage; - PFN_vkDestroyImage vkDestroyImage; - PFN_vkCmdCopyBuffer vkCmdCopyBuffer; -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; - PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; -#endif -#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; - PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; -#endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; -#endif -} VmaVulkanFunctions; +VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); -/// Flags to be used in VmaRecordSettings::flags. -typedef enum VmaRecordFlagBits { - /** \brief Enables flush after recording every function call. +/** \brief Changes custom pointer associated with given virtual allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, + void* VMA_NULLABLE pUserData); - Enable it if you expect your application to crash, which may leave recording file truncated. - It may degrade performance though. - */ - VMA_RECORD_FLUSH_AFTER_CALL_BIT = 0x00000001, - - VMA_RECORD_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaRecordFlagBits; -typedef VkFlags VmaRecordFlags; - -/// Parameters for recording calls to VMA functions. To be used in VmaAllocatorCreateInfo::pRecordSettings. -typedef struct VmaRecordSettings -{ - /// Flags for recording. Use #VmaRecordFlagBits enum. - VmaRecordFlags flags; - /** \brief Path to the file that should be written by the recording. - - Suggested extension: "csv". - If the file already exists, it will be overwritten. - It will be opened for the whole time #VmaAllocator object is alive. - If opening this file fails, creation of the whole allocator object fails. - */ - const char* pFilePath; -} VmaRecordSettings; +/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. -/// Description of a Allocator to be created. -typedef struct VmaAllocatorCreateInfo -{ - /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. - VmaAllocatorCreateFlags flags; - /// Vulkan physical device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkPhysicalDevice physicalDevice; - /// Vulkan device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkDevice device; - /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. - /** Set to 0 to use default, which is currently 256 MiB. */ - VkDeviceSize preferredLargeHeapBlockSize; - /// Custom CPU memory allocation callbacks. Optional. - /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ - const VkAllocationCallbacks* pAllocationCallbacks; - /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. - /** Optional, can be null. */ - const VmaDeviceMemoryCallbacks* pDeviceMemoryCallbacks; - /** \brief Maximum number of additional frames that are in use at the same time as current frame. +This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats); - This value is used only when you make allocations with - VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become - lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. +/** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. - For example, if you double-buffer your command buffers, so resources used for - rendering in previous frame may still be in use by the GPU at the moment you - allocate resources needed for the current frame, set this value to 1. +This function is slow to call. Use for debugging purposes. +For less detailed statistics, see vmaGetVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats); - If you want to allow any allocations other than used in the current frame to - become lost, set this value to 0. - */ - uint32_t frameInUseCount; - /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. +/** @} */ - If not NULL, it must be a pointer to an array of - `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on - maximum number of bytes that can be allocated out of particular Vulkan memory - heap. +#if VMA_STATS_STRING_ENABLED +/** +\addtogroup group_stats +@{ +*/ - Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that - heap. This is also the default in case of `pHeapSizeLimit` = NULL. +/** \brief Builds and returns a null-terminated string in JSON format with information about given #VmaVirtualBlock. +\param virtualBlock Virtual block. +\param[out] ppStatsString Returned string. +\param detailedMap Pass `VK_FALSE` to only obtain statistics as returned by vmaCalculateVirtualBlockStatistics(). Pass `VK_TRUE` to also obtain full list of allocations and free spaces. - If there is a limit defined for a heap: +Returned string must be freed using vmaFreeVirtualBlockStatsString(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); - - If user tries to allocate more memory from that heap using this allocator, - the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the - value of this limit will be reported instead when using vmaGetMemoryProperties(). +/// Frees a string returned by vmaBuildVirtualBlockStatsString(). +VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString); - Warning! Using this feature may not be equivalent to installing a GPU with - smaller amount of memory, because graphics driver doesn't necessary fail new - allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is - exceeded. It may return success and just silently migrate some device memory - blocks to system RAM. This driver behavior can also be controlled using - VK_AMD_memory_overallocation_behavior extension. - */ - const VkDeviceSize* pHeapSizeLimit; - /** \brief Pointers to Vulkan functions. Can be null. +/** \brief Builds and returns statistics as a null-terminated string in JSON format. +\param allocator +\param[out] ppStatsString Must be freed using vmaFreeStatsString() function. +\param detailedMap +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); - You can pass null as this member, because the library will fetch pointers to - Vulkan functions internally. - Fill this member if you want to provide your own pointers to Vulkan functions, - e.g. fetched using `vkGetInstanceProcAddr()` and `vkGetDeviceProcAddr()`. - */ - const VmaVulkanFunctions* pVulkanFunctions; - /** \brief Parameters for recording of VMA calls. Can be null. +VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE pStatsString); - If not null, it enables recording of calls to VMA functions to a file. - If support for recording is not enabled using `VMA_RECORDING_ENABLED` macro, - creation of the allocator object fails with `VK_ERROR_FEATURE_NOT_PRESENT`. - */ - const VmaRecordSettings* pRecordSettings; - /** \brief Handle to Vulkan instance object. +/** @} */ - Starting from version 3.0.0 this member is no longer optional, it must be set! - */ - VkInstance instance; - /** \brief Optional. The highest version of Vulkan that the application is designed to use. - - It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. - The patch version number specified is ignored. Only the major and minor versions are considered. - It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`. - Only versions 1.0 and 1.1 are supported by the current implementation. - Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. - */ - uint32_t vulkanApiVersion; -} VmaAllocatorCreateInfo; +#endif // VMA_STATS_STRING_ENABLED -/// Creates Allocator object. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( - const VmaAllocatorCreateInfo* pCreateInfo, - VmaAllocator* pAllocator); +#endif // _VMA_FUNCTION_HEADERS -/// Destroys allocator object. -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( - VmaAllocator allocator); +#ifdef __cplusplus +} +#endif -/** \brief Information about existing #VmaAllocator object. -*/ -typedef struct VmaAllocatorInfo -{ - /** \brief Handle to Vulkan instance object. +#endif // AMD_VULKAN_MEMORY_ALLOCATOR_H - This is the same value as has been passed through VmaAllocatorCreateInfo::instance. - */ - VkInstance instance; - /** \brief Handle to Vulkan physical device object. +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// - This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. - */ - VkPhysicalDevice physicalDevice; - /** \brief Handle to Vulkan device object. +// For Visual Studio IntelliSense. +#if defined(__cplusplus) && defined(__INTELLISENSE__) +#define VMA_IMPLEMENTATION +#endif - This is the same value as has been passed through VmaAllocatorCreateInfo::device. - */ - VkDevice device; -} VmaAllocatorInfo; +#ifdef VMA_IMPLEMENTATION +#undef VMA_IMPLEMENTATION -/** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. +#include +#include +#include +#include +#include -It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to -`VkPhysicalDevice`, `VkDevice` etc. every time using this function. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo); +#ifdef _MSC_VER + #include // For functions like __popcnt, _BitScanForward etc. +#endif +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + #include // For std::popcount +#endif -/** -PhysicalDeviceProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( - VmaAllocator allocator, - const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties); +/******************************************************************************* +CONFIGURATION SECTION -/** -PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. +Define some of these macros before each #include of this header or change them +here if you need other then default behavior depending on your environment. */ -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( - VmaAllocator allocator, - const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties); +#ifndef _VMA_CONFIGURATION -/** -\brief Given Memory Type Index, returns Property Flags of this memory type. +/* +Define this macro to 1 to make the library fetch pointers to Vulkan functions +internally, like: -This is just a convenience function. Same information can be obtained using -vmaGetMemoryProperties(). + vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; */ -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( - VmaAllocator allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* pFlags); +#if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) + #define VMA_STATIC_VULKAN_FUNCTIONS 1 +#endif -/** \brief Sets index of the current frame. +/* +Define this macro to 1 to make the library fetch pointers to Vulkan functions +internally, like: -This function must be used if you make allocations with -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT and -#VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flags to inform the allocator -when a new frame begins. Allocations queried using vmaGetAllocationInfo() cannot -become lost in the current frame. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( - VmaAllocator allocator, - uint32_t frameIndex); + vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(device, "vkAllocateMemory"); -/** \brief Calculated statistics of memory usage in entire allocator. +To use this feature in new versions of VMA you now have to pass +VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as +VmaAllocatorCreateInfo::pVulkanFunctions. Other members can be null. */ -typedef struct VmaStatInfo -{ - /// Number of `VkDeviceMemory` Vulkan memory blocks allocated. - uint32_t blockCount; - /// Number of #VmaAllocation allocation objects allocated. - uint32_t allocationCount; - /// Number of free ranges of memory between allocations. - uint32_t unusedRangeCount; - /// Total number of bytes occupied by all allocations. - VkDeviceSize usedBytes; - /// Total number of bytes occupied by unused ranges. - VkDeviceSize unusedBytes; - VkDeviceSize allocationSizeMin, allocationSizeAvg, allocationSizeMax; - VkDeviceSize unusedRangeSizeMin, unusedRangeSizeAvg, unusedRangeSizeMax; -} VmaStatInfo; - -/// General statistics from current state of Allocator. -typedef struct VmaStats -{ - VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES]; - VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS]; - VmaStatInfo total; -} VmaStats; - -/** \brief Retrieves statistics from current state of the Allocator. +#if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS) + #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#endif -This function is called "calculate" not "get" because it has to traverse all -internal data structures, so it may be quite slow. For faster but more brief statistics -suitable to be called every frame or every allocation, use vmaGetBudget(). +#ifndef VMA_USE_STL_SHARED_MUTEX + // Compiler conforms to C++17. + #if __cplusplus >= 201703L + #define VMA_USE_STL_SHARED_MUTEX 1 + // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus + // Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. + #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L + #define VMA_USE_STL_SHARED_MUTEX 1 + #else + #define VMA_USE_STL_SHARED_MUTEX 0 + #endif +#endif -Note that when using allocator from multiple threads, returned information may immediately -become outdated. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats( - VmaAllocator allocator, - VmaStats* pStats); +/* +Define this macro to include custom header files without having to edit this file directly, e.g.: -/** \brief Statistics of current memory usage and available budget, in bytes, for specific memory heap. -*/ -typedef struct VmaBudget -{ - /** \brief Sum size of all `VkDeviceMemory` blocks allocated from particular heap, in bytes. - */ - VkDeviceSize blockBytes; - - /** \brief Sum size of all allocations created in particular heap, in bytes. - - Usually less or equal than `blockBytes`. - Difference `blockBytes - allocationBytes` is the amount of memory allocated but unused - - available for new allocations or wasted due to fragmentation. - - It might be greater than `blockBytes` if there are some allocations in lost state, as they account - to this value as well. - */ - VkDeviceSize allocationBytes; - - /** \brief Estimated current memory usage of the program, in bytes. - - Fetched from system using `VK_EXT_memory_budget` extension if enabled. - - It might be different than `blockBytes` (usually higher) due to additional implicit objects - also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or - `VkDeviceMemory` blocks allocated outside of this library, if any. - */ - VkDeviceSize usage; - - /** \brief Estimated amount of memory available to the program, in bytes. - - Fetched from system using `VK_EXT_memory_budget` extension if enabled. - - It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors - external to the program, like other programs also consuming system resources. - Difference `budget - usage` is the amount of additional memory that can probably - be allocated without problems. Exceeding the budget may result in various problems. - */ - VkDeviceSize budget; -} VmaBudget; + // Inside of "my_vma_configuration_user_includes.h": -/** \brief Retrieves information about current memory budget for all memory heaps. + #include "my_custom_assert.h" // for MY_CUSTOM_ASSERT + #include "my_custom_min.h" // for my_custom_min + #include + #include -\param[out] pBudget Must point to array with number of elements at least equal to number of memory heaps in physical device used. + // Inside a different file, which includes "vk_mem_alloc.h": -This function is called "get" not "calculate" because it is very fast, suitable to be called -every frame or every allocation. For more detailed statistics use vmaCalculateStats(). + #define VMA_CONFIGURATION_USER_INCLUDES_H "my_vma_configuration_user_includes.h" + #define VMA_ASSERT(expr) MY_CUSTOM_ASSERT(expr) + #define VMA_MIN(v1, v2) (my_custom_min(v1, v2)) + #include "vk_mem_alloc.h" + ... -Note that when using allocator from multiple threads, returned information may immediately -become outdated. +The following headers are used in this CONFIGURATION section only, so feel free to +remove them if not needed. */ -VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget( - VmaAllocator allocator, - VmaBudget* pBudget); - -#ifndef VMA_STATS_STRING_ENABLED -#define VMA_STATS_STRING_ENABLED 1 +#if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) + #include // for assert + #include // for min, max + #include +#else + #include VMA_CONFIGURATION_USER_INCLUDES_H #endif -#if VMA_STATS_STRING_ENABLED - -/// Builds and returns statistics as string in JSON format. -/** @param[out] ppStatsString Must be freed using vmaFreeStatsString() function. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( - VmaAllocator allocator, - char** ppStatsString, - VkBool32 detailedMap); +#ifndef VMA_NULL + // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. + #define VMA_NULL nullptr +#endif -VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( - VmaAllocator allocator, - char* pStatsString); +// Normal assert to check for programmer's errors, especially in Debug configuration. +#ifndef VMA_ASSERT + #ifdef NDEBUG + #define VMA_ASSERT(expr) + #else + #define VMA_ASSERT(expr) assert(expr) + #endif +#endif -#endif // #if VMA_STATS_STRING_ENABLED +// Assert that will be called very often, like inside data structures e.g. operator[]. +// Making it non-empty can make program slow. +#ifndef VMA_HEAVY_ASSERT + #ifdef NDEBUG + #define VMA_HEAVY_ASSERT(expr) + #else + #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) + #endif +#endif -/** \struct VmaPool -\brief Represents custom memory pool +// If your compiler is not compatible with C++17 and definition of +// aligned_alloc() function is missing, uncommenting following line may help: -Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. -Call function vmaDestroyPool() to destroy it. +//#include -For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). -*/ -VK_DEFINE_HANDLE(VmaPool) +#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16) +#include +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + // alignment must be >= sizeof(void*) + if(alignment < sizeof(void*)) + { + alignment = sizeof(void*); + } -typedef enum VmaMemoryUsage + return memalign(alignment, size); +} +#elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)) +#include + +#if defined(__APPLE__) +#include +#endif + +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + // Unfortunately, aligned_alloc causes VMA to crash due to it returning null pointers. (At least under 11.4) + // Therefore, for now disable this specific exception until a proper solution is found. + //#if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0)) + //#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 + // // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only + // // with the MacOSX11.0 SDK in Xcode 12 (which is what adds + // // MAC_OS_X_VERSION_10_16), even though the function is marked + // // available for 10.15. That is why the preprocessor checks for 10.16 but + // // the __builtin_available checks for 10.15. + // // People who use C++17 could call aligned_alloc with the 10.15 SDK already. + // if (__builtin_available(macOS 10.15, iOS 13, *)) + // return aligned_alloc(alignment, size); + //#endif + //#endif + + // alignment must be >= sizeof(void*) + if(alignment < sizeof(void*)) + { + alignment = sizeof(void*); + } + + void *pointer; + if(posix_memalign(&pointer, alignment, size) == 0) + return pointer; + return VMA_NULL; +} +#elif defined(_WIN32) +static void* vma_aligned_alloc(size_t alignment, size_t size) { - /** No intended memory usage specified. - Use other members of VmaAllocationCreateInfo to specify your requirements. - */ - VMA_MEMORY_USAGE_UNKNOWN = 0, - /** Memory will be used on device only, so fast access from the device is preferred. - It usually means device-local GPU (video) memory. - No need to be mappable on host. - It is roughly equivalent of `D3D12_HEAP_TYPE_DEFAULT`. - - Usage: - - - Resources written and read by device, e.g. images used as attachments. - - Resources transferred from host once (immutable) or infrequently and read by - device multiple times, e.g. textures to be sampled, vertex buffers, uniform - (constant) buffers, and majority of other types of resources used on GPU. - - Allocation may still end up in `HOST_VISIBLE` memory on some implementations. - In such case, you are free to map it. - You can use #VMA_ALLOCATION_CREATE_MAPPED_BIT with this usage type. - */ - VMA_MEMORY_USAGE_GPU_ONLY = 1, - /** Memory will be mappable on host. - It usually means CPU (system) memory. - Guarantees to be `HOST_VISIBLE` and `HOST_COHERENT`. - CPU access is typically uncached. Writes may be write-combined. - Resources created in this pool may still be accessible to the device, but access to them can be slow. - It is roughly equivalent of `D3D12_HEAP_TYPE_UPLOAD`. - - Usage: Staging copy of resources used as transfer source. - */ - VMA_MEMORY_USAGE_CPU_ONLY = 2, - /** - Memory that is both mappable on host (guarantees to be `HOST_VISIBLE`) and preferably fast to access by GPU. - CPU access is typically uncached. Writes may be write-combined. + return _aligned_malloc(size, alignment); +} +#elif __cplusplus >= 201703L // Compiler conforms to C++17. +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + return aligned_alloc(alignment, size); +} +#else +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + VMA_ASSERT(0 && "Could not implement aligned_alloc automatically. Please enable C++17 or later in your compiler or provide custom implementation of macro VMA_SYSTEM_ALIGNED_MALLOC (and VMA_SYSTEM_ALIGNED_FREE if needed) using the API of your system."); + return VMA_NULL; +} +#endif - Usage: Resources written frequently by host (dynamic), read by device. E.g. textures, vertex buffers, uniform buffers updated every frame or every draw call. - */ - VMA_MEMORY_USAGE_CPU_TO_GPU = 3, - /** Memory mappable on host (guarantees to be `HOST_VISIBLE`) and cached. - It is roughly equivalent of `D3D12_HEAP_TYPE_READBACK`. +#if defined(_WIN32) +static void vma_aligned_free(void* ptr) +{ + _aligned_free(ptr); +} +#else +static void vma_aligned_free(void* VMA_NULLABLE ptr) +{ + free(ptr); +} +#endif - Usage: +#ifndef VMA_ALIGN_OF + #define VMA_ALIGN_OF(type) (__alignof(type)) +#endif - - Resources written by device, read by host - results of some computations, e.g. screen capture, average scene luminance for HDR tone mapping. - - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection. - */ - VMA_MEMORY_USAGE_GPU_TO_CPU = 4, - /** CPU memory - memory that is preferably not `DEVICE_LOCAL`, but also not guaranteed to be `HOST_VISIBLE`. +#ifndef VMA_SYSTEM_ALIGNED_MALLOC + #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) +#endif - Usage: Staging copy of resources moved from GPU memory to CPU memory as part - of custom paging/residency mechanism, to be moved back to GPU memory when needed. - */ - VMA_MEMORY_USAGE_CPU_COPY = 5, - /** Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. - Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. - - Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. +#ifndef VMA_SYSTEM_ALIGNED_FREE + // VMA_SYSTEM_FREE is the old name, but might have been defined by the user + #if defined(VMA_SYSTEM_FREE) + #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) + #else + #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) + #endif +#endif - Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - */ - VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, +#ifndef VMA_COUNT_BITS_SET + // Returns number of bits set to 1 in (v) + #define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) +#endif - VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF -} VmaMemoryUsage; +#ifndef VMA_BITSCAN_LSB + // Scans integer for index of first nonzero value from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX + #define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) +#endif -/// Flags to be passed as VmaAllocationCreateInfo::flags. -typedef enum VmaAllocationCreateFlagBits { - /** \brief Set this flag if the allocation should have its own memory block. - - Use it for special, big resources, like fullscreen images used as attachments. - - You should not use this flag if VmaAllocationCreateInfo::pool is not null. - */ - VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, +#ifndef VMA_BITSCAN_MSB + // Scans integer for index of first nonzero value from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX + #define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) +#endif - /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. - - If new allocation cannot be placed in any of the existing blocks, allocation - fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. - - You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and - #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. - - If VmaAllocationCreateInfo::pool is not null, this flag is implied and ignored. */ - VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, - /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. - - Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. +#ifndef VMA_MIN + #define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) +#endif - Is it valid to use this flag for allocation made from memory type that is not - `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is - useful if you need an allocation that is efficient to use on GPU - (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that - support it (e.g. Intel GPU). +#ifndef VMA_MAX + #define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) +#endif - You should not use this flag together with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT. - */ - VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, - /** Allocation created with this flag can become lost as a result of another - allocation with #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag, so you - must check it before use. +#ifndef VMA_SWAP + #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) +#endif - To check if allocation is not lost, call vmaGetAllocationInfo() and check if - VmaAllocationInfo::deviceMemory is not `VK_NULL_HANDLE`. +#ifndef VMA_SORT + #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) +#endif - For details about supporting lost allocations, see Lost Allocations - chapter of User Guide on Main Page. +#ifndef VMA_DEBUG_LOG_FORMAT + #define VMA_DEBUG_LOG_FORMAT(format, ...) + /* + #define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ + printf((format), __VA_ARGS__); \ + printf("\n"); \ + } while(false) + */ +#endif - You should not use this flag together with #VMA_ALLOCATION_CREATE_MAPPED_BIT. - */ - VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT = 0x00000008, - /** While creating allocation using this flag, other allocations that were - created with flag #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT can become lost. +#ifndef VMA_DEBUG_LOG + #define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) +#endif - For details about supporting lost allocations, see Lost Allocations - chapter of User Guide on Main Page. - */ - VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT = 0x00000010, - /** Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a - null-terminated string. Instead of copying pointer value, a local copy of the - string is made and stored in allocation's `pUserData`. The string is automatically - freed together with the allocation. It is also used in vmaBuildStatsString(). - */ - VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, - /** Allocation will be created from upper stack in a double stack pool. +// Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. +#if VMA_STATS_STRING_ENABLED + static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) + { + snprintf(outStr, strLen, "%u", static_cast(num)); + } + static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) + { + snprintf(outStr, strLen, "%llu", static_cast(num)); + } + static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) + { + snprintf(outStr, strLen, "%p", ptr); + } +#endif - This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. - */ - VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, - /** Create both buffer/image and allocation, but don't bind them together. - It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. - The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). - Otherwise it is ignored. - */ - VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, - /** Create allocation only if additional device memory required for it, if any, won't exceed - memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - */ - VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, +#ifndef VMA_MUTEX + class VmaMutex + { + public: + void Lock() { m_Mutex.lock(); } + void Unlock() { m_Mutex.unlock(); } + bool TryLock() { return m_Mutex.try_lock(); } + private: + std::mutex m_Mutex; + }; + #define VMA_MUTEX VmaMutex +#endif - /** Allocation strategy that chooses smallest possible free range for the - allocation. - */ - VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = 0x00010000, - /** Allocation strategy that chooses biggest possible free range for the - allocation. - */ - VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT = 0x00020000, - /** Allocation strategy that chooses first suitable free range for the - allocation. +// Read-write mutex, where "read" is shared access, "write" is exclusive access. +#ifndef VMA_RW_MUTEX + #if VMA_USE_STL_SHARED_MUTEX + // Use std::shared_mutex from C++17. + #include + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.lock_shared(); } + void UnlockRead() { m_Mutex.unlock_shared(); } + bool TryLockRead() { return m_Mutex.try_lock_shared(); } + void LockWrite() { m_Mutex.lock(); } + void UnlockWrite() { m_Mutex.unlock(); } + bool TryLockWrite() { return m_Mutex.try_lock(); } + private: + std::shared_mutex m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 + // Use SRWLOCK from WinAPI. + // Minimum supported client = Windows Vista, server = Windows Server 2008. + class VmaRWMutex + { + public: + VmaRWMutex() { InitializeSRWLock(&m_Lock); } + void LockRead() { AcquireSRWLockShared(&m_Lock); } + void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } + bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } + void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } + void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } + bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } + private: + SRWLOCK m_Lock; + }; + #define VMA_RW_MUTEX VmaRWMutex + #else + // Less efficient fallback: Use normal mutex. + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.Lock(); } + void UnlockRead() { m_Mutex.Unlock(); } + bool TryLockRead() { return m_Mutex.TryLock(); } + void LockWrite() { m_Mutex.Lock(); } + void UnlockWrite() { m_Mutex.Unlock(); } + bool TryLockWrite() { return m_Mutex.TryLock(); } + private: + VMA_MUTEX m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #endif // #if VMA_USE_STL_SHARED_MUTEX +#endif // #ifndef VMA_RW_MUTEX - "First" doesn't necessarily means the one with smallest offset in memory, - but rather the one that is easiest and fastest to find. - */ - VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = 0x00040000, +/* +If providing your own implementation, you need to implement a subset of std::atomic. +*/ +#ifndef VMA_ATOMIC_UINT32 + #include + #define VMA_ATOMIC_UINT32 std::atomic +#endif - /** Allocation strategy that tries to minimize memory usage. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT, - /** Allocation strategy that tries to minimize allocation time. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT, - /** Allocation strategy that tries to minimize memory fragmentation. +#ifndef VMA_ATOMIC_UINT64 + #include + #define VMA_ATOMIC_UINT64 std::atomic +#endif + +#ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY + /** + Every allocation will have its own memory block. + Define to 1 for debugging purposes only. */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT = VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT, + #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) +#endif - /** A bit mask to extract only `STRATEGY` bits from entire set of flags. +#ifndef VMA_MIN_ALIGNMENT + /** + Minimum alignment of all allocations, in bytes. + Set to more than 1 for debugging purposes. Must be power of two. */ - VMA_ALLOCATION_CREATE_STRATEGY_MASK = - VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT | - VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT | - VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT, + #ifdef VMA_DEBUG_ALIGNMENT // Old name + #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT + #else + #define VMA_MIN_ALIGNMENT (1) + #endif +#endif - VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocationCreateFlagBits; -typedef VkFlags VmaAllocationCreateFlags; +#ifndef VMA_DEBUG_MARGIN + /** + Minimum margin after every allocation, in bytes. + Set nonzero for debugging purposes only. + */ + #define VMA_DEBUG_MARGIN (0) +#endif -typedef struct VmaAllocationCreateInfo -{ - /// Use #VmaAllocationCreateFlagBits enum. - VmaAllocationCreateFlags flags; - /** \brief Intended usage of memory. - - You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored. +#ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS + /** + Define this macro to 1 to automatically fill new allocations and destroyed + allocations with some bit pattern. */ - VmaMemoryUsage usage; - /** \brief Flags that must be set in a Memory Type chosen for an allocation. - - Leave 0 if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored.*/ - VkMemoryPropertyFlags requiredFlags; - /** \brief Flags that preferably should be set in a memory type chosen for an allocation. - - Set to 0 if no additional flags are prefered. \n - If `pool` is not null, this member is ignored. */ - VkMemoryPropertyFlags preferredFlags; - /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. + #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) +#endif - Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if - it meets other requirements specified by this structure, with no further - restrictions on memory type index. \n - If `pool` is not null, this member is ignored. +#ifndef VMA_DEBUG_DETECT_CORRUPTION + /** + Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to + enable writing magic value to the margin after every allocation and + validating it, so that memory corruptions (out-of-bounds writes) are detected. */ - uint32_t memoryTypeBits; - /** \brief Pool that this allocation should be created in. + #define VMA_DEBUG_DETECT_CORRUPTION (0) +#endif - Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: - `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. +#ifndef VMA_DEBUG_GLOBAL_MUTEX + /** + Set this to 1 for debugging purposes only, to enable single mutex protecting all + entry calls to the library. Can be useful for debugging multithreading issues. */ - VmaPool pool; - /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). - - If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either - null or pointer to a null-terminated string. The string will be then copied to - internal buffer, so it doesn't need to be valid after allocation call. + #define VMA_DEBUG_GLOBAL_MUTEX (0) +#endif + +#ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY + /** + Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. + Set to more than 1 for debugging purposes only. Must be power of two. */ - void* pUserData; -} VmaAllocationCreateInfo; + #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) +#endif -/** -\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. +#ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT + /* + Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount + and return error instead of leaving up to Vulkan implementation what to do in such cases. + */ + #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) +#endif -This algorithm tries to find a memory type that: +#ifndef VMA_SMALL_HEAP_MAX_SIZE + /// Maximum size of a memory heap in Vulkan to consider it "small". + #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) +#endif -- Is allowed by memoryTypeBits. -- Contains all the flags from pAllocationCreateInfo->requiredFlags. -- Matches intended usage. -- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. +#ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE + /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. + #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) +#endif -\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result -from this function or any other allocating function probably means that your -device doesn't support any memory type with requested features for the specific -type of resource you want to use it for. Please check parameters of your -resource, like image layout (OPTIMAL versus LINEAR) or mip level count. +/* +Mapping hysteresis is a logic that launches when vmaMapMemory/vmaUnmapMemory is called +or a persistently mapped allocation is created and destroyed several times in a row. +It keeps additional +1 mapping of a device memory block to prevent calling actual +vkMapMemory/vkUnmapMemory too many times, which may improve performance and help +tools like RenderDoc. */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( - VmaAllocator allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); +#ifndef VMA_MAPPING_HYSTERESIS_ENABLED + #define VMA_MAPPING_HYSTERESIS_ENABLED 1 +#endif -/** -\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. +#ifndef VMA_CLASS_NO_COPY + #define VMA_CLASS_NO_COPY(className) \ + private: \ + className(const className&) = delete; \ + className& operator=(const className&) = delete; +#endif -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy buffer that never has memory bound. -It is just a convenience function, equivalent to calling: +#define VMA_VALIDATE(cond) do { if(!(cond)) { \ + VMA_ASSERT(0 && "Validation failed: " #cond); \ + return false; \ + } } while(false) -- `vkCreateBuffer` -- `vkGetBufferMemoryRequirements` -- `vmaFindMemoryTypeIndex` -- `vkDestroyBuffer` +/******************************************************************************* +END OF CONFIGURATION */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); +#endif // _VMA_CONFIGURATION -/** -\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy image that never has memory bound. -It is just a convenience function, equivalent to calling: +static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC; +static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF; +// Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F. +static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666; -- `vkCreateImage` -- `vkGetImageMemoryRequirements` -- `vmaFindMemoryTypeIndex` -- `vkDestroyImage` -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); +// Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants. +static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040; +static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080; +static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000; +static const uint32_t VK_IMAGE_CREATE_DISJOINT_BIT_COPY = 0x00000200; +static const int32_t VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY = 1000158000; +static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u; +static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32; +static const uint32_t VMA_VENDOR_ID_AMD = 4098; -/// Flags to be passed as VmaPoolCreateInfo::flags. -typedef enum VmaPoolCreateFlagBits { - /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. +// This one is tricky. Vulkan specification defines this code as available since +// Vulkan 1.0, but doesn't actually define it in Vulkan SDK earlier than 1.2.131. +// See pull request #207. +#define VK_ERROR_UNKNOWN_COPY ((VkResult)-13) - This is an optional optimization flag. - If you always allocate using vmaCreateBuffer(), vmaCreateImage(), - vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator - knows exact type of your allocations so it can handle Buffer-Image Granularity - in the optimal way. +#if VMA_STATS_STRING_ENABLED +// Correspond to values of enum VmaSuballocationType. +static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = +{ + "FREE", + "UNKNOWN", + "BUFFER", + "IMAGE_UNKNOWN", + "IMAGE_LINEAR", + "IMAGE_OPTIMAL", +}; +#endif - If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), - exact type of such allocations is not known, so allocator must be conservative - in handling Buffer-Image Granularity, which can lead to suboptimal allocation - (wasted memory). In that case, if you can make sure you always allocate only - buffers and linear images or only optimal images out of this pool, use this flag - to make allocator disregard Buffer-Image Granularity and so make allocations - faster and more optimal. - */ - VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, +static VkAllocationCallbacks VmaEmptyAllocationCallbacks = + { VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; - /** \brief Enables alternative, linear allocation algorithm in this pool. - Specify this flag to enable linear allocation algorithm, which always creates - new allocations after last one and doesn't reuse space from allocations freed in - between. It trades memory consumption for simplified algorithm and data - structure, which has better performance and uses less memory for metadata. +#ifndef _VMA_ENUM_DECLARATIONS - By using this flag, you can achieve behavior of free-at-once, stack, - ring buffer, and double stack. For details, see documentation chapter - \ref linear_algorithm. +enum VmaSuballocationType +{ + VMA_SUBALLOCATION_TYPE_FREE = 0, + VMA_SUBALLOCATION_TYPE_UNKNOWN = 1, + VMA_SUBALLOCATION_TYPE_BUFFER = 2, + VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3, + VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4, + VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5, + VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +}; - When using this flag, you must specify VmaPoolCreateInfo::maxBlockCount == 1 (or 0 for default). +enum VMA_CACHE_OPERATION +{ + VMA_CACHE_FLUSH, + VMA_CACHE_INVALIDATE +}; - For more details, see [Linear allocation algorithm](@ref linear_algorithm). - */ - VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, +enum class VmaAllocationRequestType +{ + Normal, + TLSF, + // Used by "Linear" algorithm. + UpperAddress, + EndOf1st, + EndOf2nd, +}; - /** \brief Enables alternative, buddy allocation algorithm in this pool. +#endif // _VMA_ENUM_DECLARATIONS - It operates on a tree of blocks, each having size that is a power of two and - a half of its parent's size. Comparing to default algorithm, this one provides - faster allocation and deallocation and decreased external fragmentation, - at the expense of more memory wasted (internal fragmentation). +#ifndef _VMA_FORWARD_DECLARATIONS +// Opaque handle used by allocation algorithms to identify single allocation in any conforming way. +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaAllocHandle) - For more details, see [Buddy allocation algorithm](@ref buddy_algorithm). - */ - VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT = 0x00000008, +struct VmaMutexLock; +struct VmaMutexLockRead; +struct VmaMutexLockWrite; - /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. - */ - VMA_POOL_CREATE_ALGORITHM_MASK = - VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT | - VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT, +template +struct AtomicTransactionalIncrement; - VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaPoolCreateFlagBits; -typedef VkFlags VmaPoolCreateFlags; +template +struct VmaStlAllocator; -/** \brief Describes parameter of created #VmaPool. -*/ -typedef struct VmaPoolCreateInfo { - /** \brief Vulkan memory type index to allocate this pool from. - */ - uint32_t memoryTypeIndex; - /** \brief Use combination of #VmaPoolCreateFlagBits. - */ - VmaPoolCreateFlags flags; - /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. +template +class VmaVector; - Specify nonzero to set explicit, constant size of memory blocks used by this - pool. +template +class VmaSmallVector; - Leave 0 to use default and let the library manage block sizes automatically. - Sizes of particular blocks may vary. - */ - VkDeviceSize blockSize; - /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. +template +class VmaPoolAllocator; - Set to 0 to have no preallocated blocks and allow the pool be completely empty. - */ - size_t minBlockCount; - /** \brief Maximum number of blocks that can be allocated in this pool. Optional. +template +struct VmaListItem; - Set to 0 to use default, which is `SIZE_MAX`, which means no limit. - - Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated - throughout whole lifetime of this pool. - */ - size_t maxBlockCount; - /** \brief Maximum number of additional frames that are in use at the same time as current frame. +template +class VmaRawList; - This value is used only when you make allocations with - #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become - lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. +template +class VmaList; - For example, if you double-buffer your command buffers, so resources used for - rendering in previous frame may still be in use by the GPU at the moment you - allocate resources needed for the current frame, set this value to 1. +template +class VmaIntrusiveLinkedList; - If you want to allow any allocations other than used in the current frame to - become lost, set this value to 0. - */ - uint32_t frameInUseCount; -} VmaPoolCreateInfo; +// Unused in this version +#if 0 +template +struct VmaPair; +template +struct VmaPairFirstLess; -/** \brief Describes parameter of existing #VmaPool. -*/ -typedef struct VmaPoolStats { - /** \brief Total amount of `VkDeviceMemory` allocated from Vulkan for this pool, in bytes. - */ - VkDeviceSize size; - /** \brief Total number of bytes in the pool not used by any #VmaAllocation. - */ - VkDeviceSize unusedSize; - /** \brief Number of #VmaAllocation objects created from this pool that were not destroyed or lost. - */ - size_t allocationCount; - /** \brief Number of continuous memory ranges in the pool not used by any #VmaAllocation. - */ - size_t unusedRangeCount; - /** \brief Size of the largest continuous free memory region available for new allocation. +template +class VmaMap; +#endif - Making a new allocation of that size is not guaranteed to succeed because of - possible additional margin required to respect alignment and buffer/image - granularity. - */ - VkDeviceSize unusedRangeSizeMax; - /** \brief Number of `VkDeviceMemory` blocks allocated for this pool. - */ - size_t blockCount; -} VmaPoolStats; +#if VMA_STATS_STRING_ENABLED +class VmaStringBuilder; +class VmaJsonWriter; +#endif -/** \brief Allocates Vulkan device memory and creates #VmaPool object. +class VmaDeviceMemoryBlock; -@param allocator Allocator object. -@param pCreateInfo Parameters of pool to create. -@param[out] pPool Handle to created pool. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( - VmaAllocator allocator, - const VmaPoolCreateInfo* pCreateInfo, - VmaPool* pPool); +struct VmaDedicatedAllocationListItemTraits; +class VmaDedicatedAllocationList; -/** \brief Destroys #VmaPool object and frees Vulkan device memory. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( - VmaAllocator allocator, - VmaPool pool); +struct VmaSuballocation; +struct VmaSuballocationOffsetLess; +struct VmaSuballocationOffsetGreater; +struct VmaSuballocationItemSizeLess; -/** \brief Retrieves statistics of existing #VmaPool object. +typedef VmaList> VmaSuballocationList; -@param allocator Allocator object. -@param pool Pool object. -@param[out] pPoolStats Statistics of specified pool. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats( - VmaAllocator allocator, - VmaPool pool, - VmaPoolStats* pPoolStats); +struct VmaAllocationRequest; -/** \brief Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInfo::frameInUseCount back from now. +class VmaBlockMetadata; +class VmaBlockMetadata_Linear; +class VmaBlockMetadata_TLSF; -@param allocator Allocator object. -@param pool Pool. -@param[out] pLostAllocationCount Number of allocations marked as lost. Optional - pass null if you don't need this information. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost( - VmaAllocator allocator, - VmaPool pool, - size_t* pLostAllocationCount); +class VmaBlockVector; -/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. +struct VmaPoolListItemTraits; -Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, -`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is -`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). +struct VmaCurrentBudgetData; -Possible return values: +class VmaAllocationObjectAllocator; -- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. -- `VK_SUCCESS` - corruption detection has been performed and succeeded. -- `VK_ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. -- Other value: Error returned by Vulkan, e.g. memory mapping failure. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool); +#endif // _VMA_FORWARD_DECLARATIONS -/** \brief Retrieves name of a custom pool. -After the call `ppName` is either null or points to an internally-owned null-terminated string -containing name of the pool that was previously set. The pointer becomes invalid when the pool is -destroyed or its name is changed using vmaSetPoolName(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( - VmaAllocator allocator, - VmaPool pool, - const char** ppName); +#ifndef _VMA_FUNCTIONS -/** \brief Sets name of a custom pool. +/* +Returns number of bits set to 1 in (v). -`pName` can be either null or pointer to a null-terminated string with new name for the pool. -Function makes internal copy of the string, so it can be changed or freed immediately after this call. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( - VmaAllocator allocator, - VmaPool pool, - const char* pName); +On specific platforms and compilers you can use instrinsics like: -/** \struct VmaAllocation -\brief Represents single memory allocation. +Visual Studio: + return __popcnt(v); +GCC, Clang: + return static_cast(__builtin_popcount(v)); -It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type -plus unique offset. +Define macro VMA_COUNT_BITS_SET to provide your optimized implementation. +But you need to check in runtime whether user's CPU supports these, as some old processors don't. +*/ +static inline uint32_t VmaCountBitsSet(uint32_t v) +{ +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + return std::popcount(v); +#else + uint32_t c = v - ((v >> 1) & 0x55555555); + c = ((c >> 2) & 0x33333333) + (c & 0x33333333); + c = ((c >> 4) + c) & 0x0F0F0F0F; + c = ((c >> 8) + c) & 0x00FF00FF; + c = ((c >> 16) + c) & 0x0000FFFF; + return c; +#endif +} -There are multiple ways to create such object. -You need to fill structure VmaAllocationCreateInfo. -For more information see [Choosing memory type](@ref choosing_memory_type). +static inline uint8_t VmaBitScanLSB(uint64_t mask) +{ +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long pos; + if (_BitScanForward64(&pos, mask)) + return static_cast(pos); + return UINT8_MAX; +#elif defined __GNUC__ || defined __clang__ + return static_cast(__builtin_ffsll(mask)) - 1U; +#else + uint8_t pos = 0; + uint64_t bit = 1; + do + { + if (mask & bit) + return pos; + bit <<= 1; + } while (pos++ < 63); + return UINT8_MAX; +#endif +} -Although the library provides convenience functions that create Vulkan buffer or image, -allocate memory for it and bind them together, -binding of the allocation to a buffer or an image is out of scope of the allocation itself. -Allocation object can exist without buffer/image bound, -binding can be done manually by the user, and destruction of it can be done -independently of destruction of the allocation. +static inline uint8_t VmaBitScanLSB(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanForward(&pos, mask)) + return static_cast(pos); + return UINT8_MAX; +#elif defined __GNUC__ || defined __clang__ + return static_cast(__builtin_ffs(mask)) - 1U; +#else + uint8_t pos = 0; + uint32_t bit = 1; + do + { + if (mask & bit) + return pos; + bit <<= 1; + } while (pos++ < 31); + return UINT8_MAX; +#endif +} -The object also remembers its size and some other information. -To retrieve this information, use function vmaGetAllocationInfo() and inspect -returned structure VmaAllocationInfo. +static inline uint8_t VmaBitScanMSB(uint64_t mask) +{ +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long pos; + if (_BitScanReverse64(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 63 - static_cast(__builtin_clzll(mask)); +#else + uint8_t pos = 63; + uint64_t bit = 1ULL << 63; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} -Some kinds allocations can be in lost state. -For more information, see [Lost allocations](@ref lost_allocations). -*/ -VK_DEFINE_HANDLE(VmaAllocation) +static inline uint8_t VmaBitScanMSB(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} -/** \brief Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). +/* +Returns true if given number is a power of two. +T must be unsigned integer number or signed integer but always nonnegative. +For 0 returns true. */ -typedef struct VmaAllocationInfo { - /** \brief Memory type index that this allocation was allocated from. - - It never changes. - */ - uint32_t memoryType; - /** \brief Handle to Vulkan memory object. +template +inline bool VmaIsPow2(T x) +{ + return (x & (x - 1)) == 0; +} - Same memory object can be shared by multiple allocations. - - It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. +// Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16. +// Use types like uint32_t, uint64_t as T. +template +static inline T VmaAlignUp(T val, T alignment) +{ + VMA_HEAVY_ASSERT(VmaIsPow2(alignment)); + return (val + alignment - 1) & ~(alignment - 1); +} - If the allocation is lost, it is equal to `VK_NULL_HANDLE`. - */ - VkDeviceMemory deviceMemory; - /** \brief Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation. +// Aligns given value down to nearest multiply of align value. For example: VmaAlignDown(11, 8) = 8. +// Use types like uint32_t, uint64_t as T. +template +static inline T VmaAlignDown(T val, T alignment) +{ + VMA_HEAVY_ASSERT(VmaIsPow2(alignment)); + return val & ~(alignment - 1); +} - It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. - */ - VkDeviceSize offset; - /** \brief Size of this allocation, in bytes. +// Division with mathematical rounding to nearest number. +template +static inline T VmaRoundDiv(T x, T y) +{ + return (x + (y / (T)2)) / y; +} - It never changes, unless allocation is lost. - */ - VkDeviceSize size; - /** \brief Pointer to the beginning of this allocation as mapped data. +// Divide by 'y' and round up to nearest integer. +template +static inline T VmaDivideRoundingUp(T x, T y) +{ + return (x + y - (T)1) / y; +} - If the allocation hasn't been mapped using vmaMapMemory() and hasn't been - created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value null. +// Returns smallest power of 2 greater or equal to v. +static inline uint32_t VmaNextPow2(uint32_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} - It can change after call to vmaMapMemory(), vmaUnmapMemory(). - It can also change after call to vmaDefragment() if this allocation is passed to the function. - */ - void* pMappedData; - /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). +static inline uint64_t VmaNextPow2(uint64_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v++; + return v; +} - It can change after call to vmaSetAllocationUserData() for this allocation. - */ - void* pUserData; -} VmaAllocationInfo; +// Returns largest power of 2 less or equal to v. +static inline uint32_t VmaPrevPow2(uint32_t v) +{ + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v = v ^ (v >> 1); + return v; +} -/** \brief General purpose memory allocation. +static inline uint64_t VmaPrevPow2(uint64_t v) +{ + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v = v ^ (v >> 1); + return v; +} -@param[out] pAllocation Handle to allocated memory. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). +static inline bool VmaStrIsEmpty(const char* pStr) +{ + return pStr == VMA_NULL || *pStr == '\0'; +} -You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). +/* +Returns true if two memory blocks occupy overlapping pages. +ResourceA must be in less memory offset than ResourceB. -It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), -vmaCreateBuffer(), vmaCreateImage() instead whenever possible. +Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)" +chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity". */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/** \brief General purpose memory allocation for multiple allocation objects at once. - -@param allocator Allocator object. -@param pVkMemoryRequirements Memory requirements for each allocation. -@param pCreateInfo Creation parameters for each alloction. -@param allocationCount Number of allocations to make. -@param[out] pAllocations Pointer to array that will be filled with handles to created allocations. -@param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. - -You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). - -Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. -It is just a general purpose allocation function able to make multiple allocations at once. -It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. +static inline bool VmaBlocksOnSamePage( + VkDeviceSize resourceAOffset, + VkDeviceSize resourceASize, + VkDeviceSize resourceBOffset, + VkDeviceSize pageSize) +{ + VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0); + VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1; + VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1); + VkDeviceSize resourceBStart = resourceBOffset; + VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1); + return resourceAEndPage == resourceBStartPage; +} -All allocations are made using same parameters. All of them are created out of the same memory pool and type. -If any allocation fails, all allocations already made within this function call are also freed, so that when -returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. +/* +Returns true if given suballocation types could conflict and must respect +VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer +or linear image and another one is optimal image. If type is unknown, behave +conservatively. */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - size_t allocationCount, - VmaAllocation* pAllocations, - VmaAllocationInfo* pAllocationInfo); - -/** -@param[out] pAllocation Handle to allocated memory. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). +static inline bool VmaIsBufferImageGranularityConflict( + VmaSuballocationType suballocType1, + VmaSuballocationType suballocType2) +{ + if (suballocType1 > suballocType2) + { + VMA_SWAP(suballocType1, suballocType2); + } -You should free the memory using vmaFreeMemory(). -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( - VmaAllocator allocator, - VkBuffer buffer, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); + switch (suballocType1) + { + case VMA_SUBALLOCATION_TYPE_FREE: + return false; + case VMA_SUBALLOCATION_TYPE_UNKNOWN: + return true; + case VMA_SUBALLOCATION_TYPE_BUFFER: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL: + return false; + default: + VMA_ASSERT(0); + return true; + } +} -/// Function similar to vmaAllocateMemoryForBuffer(). -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( - VmaAllocator allocator, - VkImage image, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); +static void VmaWriteMagicValue(void* pData, VkDeviceSize offset) +{ +#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION + uint32_t* pDst = (uint32_t*)((char*)pData + offset); + const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); + for (size_t i = 0; i < numberCount; ++i, ++pDst) + { + *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE; + } +#else + // no-op +#endif +} -/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). +static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset) +{ +#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION + const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset); + const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); + for (size_t i = 0; i < numberCount; ++i, ++pSrc) + { + if (*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE) + { + return false; + } + } +#endif + return true; +} -Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. +/* +Fills structure with parameters of an example buffer to be used for transfers +during GPU memory defragmentation. */ -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( - VmaAllocator allocator, - VmaAllocation allocation); +static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo) +{ + memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo)); + outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size. +} -/** \brief Frees memory and destroys multiple allocations. -Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. -It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), -vmaAllocateMemoryPages() and other functions. -It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. +/* +Performs binary search and returns iterator to first element that is greater or +equal to (key), according to comparison (cmp). -Allocations in `pAllocations` array can come from any memory pools and types. -Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. +Cmp should return true if first argument is less than second argument. + +Returned value is the found element, if present in the collection or place where +new element with value (key) should be inserted. */ -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( - VmaAllocator allocator, - size_t allocationCount, - VmaAllocation* pAllocations); +template +static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp) +{ + size_t down = 0, up = (end - beg); + while (down < up) + { + const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation + if (cmp(*(beg + mid), key)) + { + down = mid + 1; + } + else + { + up = mid; + } + } + return beg + down; +} -/** \brief Deprecated. +template +IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp) +{ + IterT it = VmaBinaryFindFirstNotLess( + beg, end, value, cmp); + if (it == end || + (!cmp(*it, value) && !cmp(value, *it))) + { + return it; + } + return end; +} -\deprecated -In version 2.2.0 it used to try to change allocation's size without moving or reallocating it. -In current version it returns `VK_SUCCESS` only if `newSize` equals current allocation's size. -Otherwise returns `VK_ERROR_OUT_OF_POOL_MEMORY`, indicating that allocation's size could not be changed. +/* +Returns true if all pointers in the array are not-null and unique. +Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT. +T must be pointer type, e.g. VmaAllocation, VmaPool. */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeAllocation( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize newSize); +template +static bool VmaValidatePointerArray(uint32_t count, const T* arr) +{ + for (uint32_t i = 0; i < count; ++i) + { + const T iPtr = arr[i]; + if (iPtr == VMA_NULL) + { + return false; + } + for (uint32_t j = i + 1; j < count; ++j) + { + if (iPtr == arr[j]) + { + return false; + } + } + } + return true; +} -/** \brief Returns current information about specified allocation and atomically marks it as used in current frame. +template +static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) +{ + newStruct->pNext = mainStruct->pNext; + mainStruct->pNext = newStruct; +} -Current paramters of given allocation are returned in `pAllocationInfo`. +// This is the main algorithm that guides the selection of a memory type best for an allocation - +// converts usage to required/preferred/not preferred flags. +static bool FindMemoryPreferences( + bool isIntegratedGPU, + const VmaAllocationCreateInfo& allocCreateInfo, + VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + VkMemoryPropertyFlags& outRequiredFlags, + VkMemoryPropertyFlags& outPreferredFlags, + VkMemoryPropertyFlags& outNotPreferredFlags) +{ + outRequiredFlags = allocCreateInfo.requiredFlags; + outPreferredFlags = allocCreateInfo.preferredFlags; + outNotPreferredFlags = 0; -This function also atomically "touches" allocation - marks it as used in current frame, -just like vmaTouchAllocation(). -If the allocation is in lost state, `pAllocationInfo->deviceMemory == VK_NULL_HANDLE`. + switch(allocCreateInfo.usage) + { + case VMA_MEMORY_USAGE_UNKNOWN: + break; + case VMA_MEMORY_USAGE_GPU_ONLY: + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + case VMA_MEMORY_USAGE_CPU_ONLY: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; + case VMA_MEMORY_USAGE_CPU_TO_GPU: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + case VMA_MEMORY_USAGE_GPU_TO_CPU: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + outPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + break; + case VMA_MEMORY_USAGE_CPU_COPY: + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + case VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED: + outRequiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + break; + case VMA_MEMORY_USAGE_AUTO: + case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: + case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: + { + if(bufImgUsage == UINT32_MAX) + { + VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known."); + return false; + } + // This relies on values of VK_IMAGE_USAGE_TRANSFER* being the same VK_BUFFER_IMAGE_TRANSFER*. + const bool deviceAccess = (bufImgUsage & ~(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) != 0; + const bool hostAccessSequentialWrite = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT) != 0; + const bool hostAccessRandom = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT) != 0; + const bool hostAccessAllowTransferInstead = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) != 0; + const bool preferDevice = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + const bool preferHost = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST; -Although this function uses atomics and doesn't lock any mutex, so it should be quite efficient, -you can avoid calling it too often. + // CPU random access - e.g. a buffer written to or transferred from GPU to read back on CPU. + if(hostAccessRandom) + { + if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + { + // Nice if it will end up in HOST_VISIBLE, but more importantly prefer DEVICE_LOCAL. + // Omitting HOST_VISIBLE here is intentional. + // In case there is DEVICE_LOCAL | HOST_VISIBLE | HOST_CACHED, it will pick that one. + // Otherwise, this will give same weight to DEVICE_LOCAL as HOST_VISIBLE | HOST_CACHED and select the former if occurs first on the list. + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + else + { + // Always CPU memory, cached. + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + } + // CPU sequential write - may be CPU or host-visible GPU memory, uncached and write-combined. + else if(hostAccessSequentialWrite) + { + // Want uncached and write-combined. + outNotPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; -- You can retrieve same VmaAllocationInfo structure while creating your resource, from function - vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change - (e.g. due to defragmentation or allocation becoming lost). -- If you just want to check if allocation is not lost, vmaTouchAllocation() will work faster. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( - VmaAllocator allocator, - VmaAllocation allocation, - VmaAllocationInfo* pAllocationInfo); + if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + } + else + { + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + // Direct GPU access, CPU sequential write (e.g. a dynamic uniform buffer updated every frame) + if(deviceAccess) + { + // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose GPU memory. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + // GPU no direct access, CPU sequential write (e.g. an upload buffer to be transferred to the GPU) + else + { + // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose CPU memory. + if(preferDevice) + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + } + } + // No CPU access + else + { + // GPU access, no CPU access (e.g. a color attachment image) - prefer GPU memory + if(deviceAccess) + { + // ...unless there is a clear preference from the user not to do so. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + // No direct GPU access, no CPU access, just transfers. + // It may be staging copy intended for e.g. preserving image for next frame (then better GPU memory) or + // a "swap file" copy to free some GPU memory (then better CPU memory). + // Up to the user to decide. If no preferece, assume the former and choose GPU memory. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + } + default: + VMA_ASSERT(0); + } -/** \brief Returns `VK_TRUE` if allocation is not lost and atomically marks it as used in current frame. + // Avoid DEVICE_COHERENT unless explicitly requested. + if(((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & + (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0) + { + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY; + } -If the allocation has been created with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, -this function returns `VK_TRUE` if it's not in lost state, so it can still be used. -It then also atomically "touches" the allocation - marks it as used in current frame, -so that you can be sure it won't become lost in current frame or next `frameInUseCount` frames. + return true; +} -If the allocation is in lost state, the function returns `VK_FALSE`. -Memory of such allocation, as well as buffer or image bound to it, should not be used. -Lost allocation and the buffer/image still need to be destroyed. +//////////////////////////////////////////////////////////////////////////////// +// Memory allocation -If the allocation has been created without #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, -this function always returns `VK_TRUE`. -*/ -VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation( - VmaAllocator allocator, - VmaAllocation allocation); +static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment) +{ + void* result = VMA_NULL; + if ((pAllocationCallbacks != VMA_NULL) && + (pAllocationCallbacks->pfnAllocation != VMA_NULL)) + { + result = (*pAllocationCallbacks->pfnAllocation)( + pAllocationCallbacks->pUserData, + size, + alignment, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + else + { + result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment); + } + VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed."); + return result; +} -/** \brief Sets pUserData in given allocation to new value. +static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr) +{ + if ((pAllocationCallbacks != VMA_NULL) && + (pAllocationCallbacks->pfnFree != VMA_NULL)) + { + (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr); + } + else + { + VMA_SYSTEM_ALIGNED_FREE(ptr); + } +} -If the allocation was created with VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT, -pUserData must be either null, or pointer to a null-terminated string. The function -makes local copy of the string and sets it as allocation's `pUserData`. String -passed as pUserData doesn't need to be valid for whole lifetime of the allocation - -you can free it after this call. String previously pointed by allocation's -pUserData is freed from memory. +template +static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks) +{ + return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T)); +} -If the flag was not used, the value of pointer `pUserData` is just copied to -allocation's `pUserData`. It is opaque, so you can use it however you want - e.g. -as a pointer, ordinal number or some handle to you own data. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( - VmaAllocator allocator, - VmaAllocation allocation, - void* pUserData); +template +static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count) +{ + return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T)); +} -/** \brief Creates new allocation that is in lost state from the beginning. +#define vma_new(allocator, type) new(VmaAllocate(allocator))(type) -It can be useful if you need a dummy, non-null allocation. +#define vma_new_array(allocator, type, count) new(VmaAllocateArray((allocator), (count)))(type) -You still need to destroy created object using vmaFreeMemory(). +template +static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr) +{ + ptr->~T(); + VmaFree(pAllocationCallbacks, ptr); +} -Returned allocation is not tied to any specific memory pool or memory type and -not bound to any image or buffer. It has size = 0. It cannot be turned into -a real, non-empty allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation( - VmaAllocator allocator, - VmaAllocation* pAllocation); +template +static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count) +{ + if (ptr != VMA_NULL) + { + for (size_t i = count; i--; ) + { + ptr[i].~T(); + } + VmaFree(pAllocationCallbacks, ptr); + } +} -/** \brief Maps memory represented by given allocation and returns pointer to it. +static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr) +{ + if (srcStr != VMA_NULL) + { + const size_t len = strlen(srcStr); + char* const result = vma_new_array(allocs, char, len + 1); + memcpy(result, srcStr, len + 1); + return result; + } + return VMA_NULL; +} -Maps memory represented by given allocation to make it accessible to CPU code. -When succeeded, `*ppData` contains pointer to first byte of this memory. -If the allocation is part of bigger `VkDeviceMemory` block, the pointer is -correctly offseted to the beginning of region assigned to this particular -allocation. +#if VMA_STATS_STRING_ENABLED +static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr, size_t strLen) +{ + if (srcStr != VMA_NULL) + { + char* const result = vma_new_array(allocs, char, strLen + 1); + memcpy(result, srcStr, strLen); + result[strLen] = '\0'; + return result; + } + return VMA_NULL; +} +#endif // VMA_STATS_STRING_ENABLED -Mapping is internally reference-counted and synchronized, so despite raw Vulkan -function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` -multiple times simultaneously, it is safe to call this function on allocations -assigned to the same memory block. Actual Vulkan memory will be mapped on first -mapping and unmapped on last unmapping. +static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str) +{ + if (str != VMA_NULL) + { + const size_t len = strlen(str); + vma_delete_array(allocs, str, len + 1); + } +} -If the function succeeded, you must call vmaUnmapMemory() to unmap the -allocation when mapping is no longer needed or before freeing the allocation, at -the latest. +template +size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value) +{ + const size_t indexToInsert = VmaBinaryFindFirstNotLess( + vector.data(), + vector.data() + vector.size(), + value, + CmpLess()) - vector.data(); + VmaVectorInsert(vector, indexToInsert, value); + return indexToInsert; +} -It also safe to call this function multiple times on the same allocation. You -must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). +template +bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value) +{ + CmpLess comparator; + typename VectorT::iterator it = VmaBinaryFindFirstNotLess( + vector.begin(), + vector.end(), + value, + comparator); + if ((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it)) + { + size_t indexToRemove = it - vector.begin(); + VmaVectorRemove(vector, indexToRemove); + return true; + } + return false; +} +#endif // _VMA_FUNCTIONS -It is also safe to call this function on allocation created with -#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. -You must still call vmaUnmapMemory() same number of times as you called -vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the -"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. +#ifndef _VMA_STATISTICS_FUNCTIONS -This function fails when used on allocation made in memory type that is not -`HOST_VISIBLE`. +static void VmaClearStatistics(VmaStatistics& outStats) +{ + outStats.blockCount = 0; + outStats.allocationCount = 0; + outStats.blockBytes = 0; + outStats.allocationBytes = 0; +} -This function always fails when called for allocation that was created with -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocations cannot be -mapped. +static void VmaAddStatistics(VmaStatistics& inoutStats, const VmaStatistics& src) +{ + inoutStats.blockCount += src.blockCount; + inoutStats.allocationCount += src.allocationCount; + inoutStats.blockBytes += src.blockBytes; + inoutStats.allocationBytes += src.allocationBytes; +} -This function doesn't automatically flush or invalidate caches. -If the allocation is made from a memory types that is not `HOST_COHERENT`, -you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( - VmaAllocator allocator, - VmaAllocation allocation, - void** ppData); +static void VmaClearDetailedStatistics(VmaDetailedStatistics& outStats) +{ + VmaClearStatistics(outStats.statistics); + outStats.unusedRangeCount = 0; + outStats.allocationSizeMin = VK_WHOLE_SIZE; + outStats.allocationSizeMax = 0; + outStats.unusedRangeSizeMin = VK_WHOLE_SIZE; + outStats.unusedRangeSizeMax = 0; +} -/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). +static void VmaAddDetailedStatisticsAllocation(VmaDetailedStatistics& inoutStats, VkDeviceSize size) +{ + inoutStats.statistics.allocationCount++; + inoutStats.statistics.allocationBytes += size; + inoutStats.allocationSizeMin = VMA_MIN(inoutStats.allocationSizeMin, size); + inoutStats.allocationSizeMax = VMA_MAX(inoutStats.allocationSizeMax, size); +} -For details, see description of vmaMapMemory(). +static void VmaAddDetailedStatisticsUnusedRange(VmaDetailedStatistics& inoutStats, VkDeviceSize size) +{ + inoutStats.unusedRangeCount++; + inoutStats.unusedRangeSizeMin = VMA_MIN(inoutStats.unusedRangeSizeMin, size); + inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, size); +} -This function doesn't automatically flush or invalidate caches. -If the allocation is made from a memory types that is not `HOST_COHERENT`, -you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( - VmaAllocator allocator, - VmaAllocation allocation); +static void VmaAddDetailedStatistics(VmaDetailedStatistics& inoutStats, const VmaDetailedStatistics& src) +{ + VmaAddStatistics(inoutStats.statistics, src.statistics); + inoutStats.unusedRangeCount += src.unusedRangeCount; + inoutStats.allocationSizeMin = VMA_MIN(inoutStats.allocationSizeMin, src.allocationSizeMin); + inoutStats.allocationSizeMax = VMA_MAX(inoutStats.allocationSizeMax, src.allocationSizeMax); + inoutStats.unusedRangeSizeMin = VMA_MIN(inoutStats.unusedRangeSizeMin, src.unusedRangeSizeMin); + inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, src.unusedRangeSizeMax); +} -/** \brief Flushes memory of given allocation. +#endif // _VMA_STATISTICS_FUNCTIONS -Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. -It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. -Unmap operation doesn't do that automatically. +#ifndef _VMA_MUTEX_LOCK +// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope). +struct VmaMutexLock +{ + VMA_CLASS_NO_COPY(VmaMutexLock) +public: + VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) : + m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->Lock(); } + } + ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } -- `offset` must be relative to the beginning of allocation. -- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. -- `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. -- If `size` is 0, this call is ignored. -- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. +private: + VMA_MUTEX* m_pMutex; +}; -Warning! `offset` and `size` are relative to the contents of given `allocation`. -If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. -Do not pass allocation's offset as `offset`!!! -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size); +// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading. +struct VmaMutexLockRead +{ + VMA_CLASS_NO_COPY(VmaMutexLockRead) +public: + VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) : + m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->LockRead(); } + } + ~VmaMutexLockRead() { if (m_pMutex) { m_pMutex->UnlockRead(); } } -/** \brief Invalidates memory of given allocation. +private: + VMA_RW_MUTEX* m_pMutex; +}; -Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. -It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. -Map operation doesn't do that automatically. +// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing. +struct VmaMutexLockWrite +{ + VMA_CLASS_NO_COPY(VmaMutexLockWrite) +public: + VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) + : m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->LockWrite(); } + } + ~VmaMutexLockWrite() { if (m_pMutex) { m_pMutex->UnlockWrite(); } } -- `offset` must be relative to the beginning of allocation. -- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. -- `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. -- If `size` is 0, this call is ignored. -- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. +private: + VMA_RW_MUTEX* m_pMutex; +}; -Warning! `offset` and `size` are relative to the contents of given `allocation`. -If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. -Do not pass allocation's offset as `offset`!!! -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size); +#if VMA_DEBUG_GLOBAL_MUTEX + static VMA_MUTEX gDebugGlobalMutex; + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); +#else + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK +#endif +#endif // _VMA_MUTEX_LOCK -/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. +#ifndef _VMA_ATOMIC_TRANSACTIONAL_INCREMENT +// An object that increments given atomic but decrements it back in the destructor unless Commit() is called. +template +struct AtomicTransactionalIncrement +{ +public: + typedef std::atomic AtomicT; -@param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. + ~AtomicTransactionalIncrement() + { + if(m_Atomic) + --(*m_Atomic); + } -Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, -`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are -`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + void Commit() { m_Atomic = nullptr; } + T Increment(AtomicT* atomic) + { + m_Atomic = atomic; + return m_Atomic->fetch_add(1); + } -Possible return values: +private: + AtomicT* m_Atomic = nullptr; +}; +#endif // _VMA_ATOMIC_TRANSACTIONAL_INCREMENT -- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. -- `VK_SUCCESS` - corruption detection has been performed and succeeded. -- `VK_ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. -- Other value: Error returned by Vulkan, e.g. memory mapping failure. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits); +#ifndef _VMA_STL_ALLOCATOR +// STL-compatible allocator. +template +struct VmaStlAllocator +{ + const VkAllocationCallbacks* const m_pCallbacks; + typedef T value_type; -/** \struct VmaDefragmentationContext -\brief Represents Opaque object that represents started defragmentation process. + VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) {} + template + VmaStlAllocator(const VmaStlAllocator& src) : m_pCallbacks(src.m_pCallbacks) {} + VmaStlAllocator(const VmaStlAllocator&) = default; + VmaStlAllocator& operator=(const VmaStlAllocator&) = delete; -Fill structure #VmaDefragmentationInfo2 and call function vmaDefragmentationBegin() to create it. -Call function vmaDefragmentationEnd() to destroy it. -*/ -VK_DEFINE_HANDLE(VmaDefragmentationContext) + T* allocate(size_t n) { return VmaAllocateArray(m_pCallbacks, n); } + void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); } -/// Flags to be used in vmaDefragmentationBegin(). None at the moment. Reserved for future use. -typedef enum VmaDefragmentationFlagBits { - VMA_DEFRAGMENTATION_FLAG_INCREMENTAL = 0x1, - VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaDefragmentationFlagBits; -typedef VkFlags VmaDefragmentationFlags; + template + bool operator==(const VmaStlAllocator& rhs) const + { + return m_pCallbacks == rhs.m_pCallbacks; + } + template + bool operator!=(const VmaStlAllocator& rhs) const + { + return m_pCallbacks != rhs.m_pCallbacks; + } +}; +#endif // _VMA_STL_ALLOCATOR -/** \brief Parameters for defragmentation. +#ifndef _VMA_VECTOR +/* Class with interface compatible with subset of std::vector. +T must be POD because constructors and destructors are not called and memcpy is +used for these objects. */ +template +class VmaVector +{ +public: + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; -To be used with function vmaDefragmentationBegin(). -*/ -typedef struct VmaDefragmentationInfo2 { - /** \brief Reserved for future use. Should be 0. - */ - VmaDefragmentationFlags flags; - /** \brief Number of allocations in `pAllocations` array. - */ - uint32_t allocationCount; - /** \brief Pointer to array of allocations that can be defragmented. + VmaVector(const AllocatorT& allocator); + VmaVector(size_t count, const AllocatorT& allocator); + // This version of the constructor is here for compatibility with pre-C++14 std::vector. + // value is unused. + VmaVector(size_t count, const T& value, const AllocatorT& allocator) : VmaVector(count, allocator) {} + VmaVector(const VmaVector& src); + VmaVector& operator=(const VmaVector& rhs); + ~VmaVector() { VmaFree(m_Allocator.m_pCallbacks, m_pArray); } - The array should have `allocationCount` elements. - The array should not contain nulls. - Elements in the array should be unique - same allocation cannot occur twice. - It is safe to pass allocations that are in the lost state - they are ignored. - All allocations not present in this array are considered non-moveable during this defragmentation. - */ - VmaAllocation* pAllocations; - /** \brief Optional, output. Pointer to array that will be filled with information whether the allocation at certain index has been changed during defragmentation. + bool empty() const { return m_Count == 0; } + size_t size() const { return m_Count; } + T* data() { return m_pArray; } + T& front() { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[0]; } + T& back() { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[m_Count - 1]; } + const T* data() const { return m_pArray; } + const T& front() const { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[0]; } + const T& back() const { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[m_Count - 1]; } - The array should have `allocationCount` elements. - You can pass null if you are not interested in this information. - */ - VkBool32* pAllocationsChanged; - /** \brief Numer of pools in `pPools` array. - */ - uint32_t poolCount; - /** \brief Either null or pointer to array of pools to be defragmented. + iterator begin() { return m_pArray; } + iterator end() { return m_pArray + m_Count; } + const_iterator cbegin() const { return m_pArray; } + const_iterator cend() const { return m_pArray + m_Count; } + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } + + void pop_front() { VMA_HEAVY_ASSERT(m_Count > 0); remove(0); } + void pop_back() { VMA_HEAVY_ASSERT(m_Count > 0); resize(size() - 1); } + void push_front(const T& src) { insert(0, src); } + + void push_back(const T& src); + void reserve(size_t newCapacity, bool freeMemory = false); + void resize(size_t newCount); + void clear() { resize(0); } + void shrink_to_fit(); + void insert(size_t index, const T& src); + void remove(size_t index); + + T& operator[](size_t index) { VMA_HEAVY_ASSERT(index < m_Count); return m_pArray[index]; } + const T& operator[](size_t index) const { VMA_HEAVY_ASSERT(index < m_Count); return m_pArray[index]; } - All the allocations in the specified pools can be moved during defragmentation - and there is no way to check if they were really moved as in `pAllocationsChanged`, - so you must query all the allocations in all these pools for new `VkDeviceMemory` - and offset using vmaGetAllocationInfo() if you might need to recreate buffers - and images bound to them. +private: + AllocatorT m_Allocator; + T* m_pArray; + size_t m_Count; + size_t m_Capacity; +}; - The array should have `poolCount` elements. - The array should not contain nulls. - Elements in the array should be unique - same pool cannot occur twice. +#ifndef _VMA_VECTOR_FUNCTIONS +template +VmaVector::VmaVector(const AllocatorT& allocator) + : m_Allocator(allocator), + m_pArray(VMA_NULL), + m_Count(0), + m_Capacity(0) {} - Using this array is equivalent to specifying all allocations from the pools in `pAllocations`. - It might be more efficient. - */ - VmaPool* pPools; - /** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places using transfers on CPU side, like `memcpy()`, `memmove()`. - - `VK_WHOLE_SIZE` means no limit. - */ - VkDeviceSize maxCpuBytesToMove; - /** \brief Maximum number of allocations that can be moved to a different place using transfers on CPU side, like `memcpy()`, `memmove()`. +template +VmaVector::VmaVector(size_t count, const AllocatorT& allocator) + : m_Allocator(allocator), + m_pArray(count ? (T*)VmaAllocateArray(allocator.m_pCallbacks, count) : VMA_NULL), + m_Count(count), + m_Capacity(count) {} - `UINT32_MAX` means no limit. - */ - uint32_t maxCpuAllocationsToMove; - /** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places using transfers on GPU side, posted to `commandBuffer`. - - `VK_WHOLE_SIZE` means no limit. - */ - VkDeviceSize maxGpuBytesToMove; - /** \brief Maximum number of allocations that can be moved to a different place using transfers on GPU side, posted to `commandBuffer`. +template +VmaVector::VmaVector(const VmaVector& src) + : m_Allocator(src.m_Allocator), + m_pArray(src.m_Count ? (T*)VmaAllocateArray(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL), + m_Count(src.m_Count), + m_Capacity(src.m_Count) +{ + if (m_Count != 0) + { + memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T)); + } +} - `UINT32_MAX` means no limit. - */ - uint32_t maxGpuAllocationsToMove; - /** \brief Optional. Command buffer where GPU copy commands will be posted. +template +VmaVector& VmaVector::operator=(const VmaVector& rhs) +{ + if (&rhs != this) + { + resize(rhs.m_Count); + if (m_Count != 0) + { + memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T)); + } + } + return *this; +} - If not null, it must be a valid command buffer handle that supports Transfer queue type. - It must be in the recording state and outside of a render pass instance. - You need to submit it and make sure it finished execution before calling vmaDefragmentationEnd(). +template +void VmaVector::push_back(const T& src) +{ + const size_t newIndex = size(); + resize(newIndex + 1); + m_pArray[newIndex] = src; +} - Passing null means that only CPU defragmentation will be performed. - */ - VkCommandBuffer commandBuffer; -} VmaDefragmentationInfo2; +template +void VmaVector::reserve(size_t newCapacity, bool freeMemory) +{ + newCapacity = VMA_MAX(newCapacity, m_Count); -typedef struct VmaDefragmentationPassMoveInfo { - VmaAllocation allocation; - VkDeviceMemory memory; - VkDeviceSize offset; -} VmaDefragmentationPassMoveInfo; + if ((newCapacity < m_Capacity) && !freeMemory) + { + newCapacity = m_Capacity; + } -/** \brief Parameters for incremental defragmentation steps. + if (newCapacity != m_Capacity) + { + T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator, newCapacity) : VMA_NULL; + if (m_Count != 0) + { + memcpy(newArray, m_pArray, m_Count * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = newCapacity; + m_pArray = newArray; + } +} -To be used with function vmaBeginDefragmentationPass(). -*/ -typedef struct VmaDefragmentationPassInfo { - uint32_t moveCount; - VmaDefragmentationPassMoveInfo* pMoves; -} VmaDefragmentationPassInfo; +template +void VmaVector::resize(size_t newCount) +{ + size_t newCapacity = m_Capacity; + if (newCount > m_Capacity) + { + newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8)); + } -/** \brief Deprecated. Optional configuration parameters to be passed to function vmaDefragment(). + if (newCapacity != m_Capacity) + { + T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL; + const size_t elementsToCopy = VMA_MIN(m_Count, newCount); + if (elementsToCopy != 0) + { + memcpy(newArray, m_pArray, elementsToCopy * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = newCapacity; + m_pArray = newArray; + } -\deprecated This is a part of the old interface. It is recommended to use structure #VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead. -*/ -typedef struct VmaDefragmentationInfo { - /** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places. - - Default is `VK_WHOLE_SIZE`, which means no limit. - */ - VkDeviceSize maxBytesToMove; - /** \brief Maximum number of allocations that can be moved to different place. + m_Count = newCount; +} - Default is `UINT32_MAX`, which means no limit. - */ - uint32_t maxAllocationsToMove; -} VmaDefragmentationInfo; +template +void VmaVector::shrink_to_fit() +{ + if (m_Capacity > m_Count) + { + T* newArray = VMA_NULL; + if (m_Count > 0) + { + newArray = VmaAllocateArray(m_Allocator.m_pCallbacks, m_Count); + memcpy(newArray, m_pArray, m_Count * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = m_Count; + m_pArray = newArray; + } +} -/** \brief Statistics returned by function vmaDefragment(). */ -typedef struct VmaDefragmentationStats { - /// Total number of bytes that have been copied while moving allocations to different places. - VkDeviceSize bytesMoved; - /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. - VkDeviceSize bytesFreed; - /// Number of allocations that have been moved to different places. - uint32_t allocationsMoved; - /// Number of empty `VkDeviceMemory` objects that have been released to the system. - uint32_t deviceMemoryBlocksFreed; -} VmaDefragmentationStats; +template +void VmaVector::insert(size_t index, const T& src) +{ + VMA_HEAVY_ASSERT(index <= m_Count); + const size_t oldCount = size(); + resize(oldCount + 1); + if (index < oldCount) + { + memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T)); + } + m_pArray[index] = src; +} -/** \brief Begins defragmentation process. +template +void VmaVector::remove(size_t index) +{ + VMA_HEAVY_ASSERT(index < m_Count); + const size_t oldCount = size(); + if (index < oldCount - 1) + { + memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T)); + } + resize(oldCount - 1); +} +#endif // _VMA_VECTOR_FUNCTIONS -@param allocator Allocator object. -@param pInfo Structure filled with parameters of defragmentation. -@param[out] pStats Optional. Statistics of defragmentation. You can pass null if you are not interested in this information. -@param[out] pContext Context object that must be passed to vmaDefragmentationEnd() to finish defragmentation. -@return `VK_SUCCESS` and `*pContext == null` if defragmentation finished within this function call. `VK_NOT_READY` and `*pContext != null` if defragmentation has been started and you need to call vmaDefragmentationEnd() to finish it. Negative value in case of error. - -Use this function instead of old, deprecated vmaDefragment(). - -Warning! Between the call to vmaDefragmentationBegin() and vmaDefragmentationEnd(): - -- You should not use any of allocations passed as `pInfo->pAllocations` or - any allocations that belong to pools passed as `pInfo->pPools`, - including calling vmaGetAllocationInfo(), vmaTouchAllocation(), or access - their data. -- Some mutexes protecting internal data structures may be locked, so trying to - make or free any allocations, bind buffers or images, map memory, or launch - another simultaneous defragmentation in between may cause stall (when done on - another thread) or deadlock (when done on the same thread), unless you are - 100% sure that defragmented allocations are in different pools. -- Information returned via `pStats` and `pInfo->pAllocationsChanged` are undefined. - They become valid after call to vmaDefragmentationEnd(). -- If `pInfo->commandBuffer` is not null, you must submit that command buffer - and make sure it finished execution before calling vmaDefragmentationEnd(). - -For more information and important limitations regarding defragmentation, see documentation chapter: -[Defragmentation](@ref defragmentation). -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin( - VmaAllocator allocator, - const VmaDefragmentationInfo2* pInfo, - VmaDefragmentationStats* pStats, - VmaDefragmentationContext *pContext); +template +static void VmaVectorInsert(VmaVector& vec, size_t index, const T& item) +{ + vec.insert(index, item); +} -/** \brief Ends defragmentation process. +template +static void VmaVectorRemove(VmaVector& vec, size_t index) +{ + vec.remove(index); +} +#endif // _VMA_VECTOR -Use this function to finish defragmentation started by vmaDefragmentationBegin(). -It is safe to pass `context == null`. The function then does nothing. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd( - VmaAllocator allocator, - VmaDefragmentationContext context); +#ifndef _VMA_SMALL_VECTOR +/* +This is a vector (a variable-sized array), optimized for the case when the array is small. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( - VmaAllocator allocator, - VmaDefragmentationContext context, - VmaDefragmentationPassInfo* pInfo -); -VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( - VmaAllocator allocator, - VmaDefragmentationContext context -); - -/** \brief Deprecated. Compacts memory by moving allocations. - -@param pAllocations Array of allocations that can be moved during this compation. -@param allocationCount Number of elements in pAllocations and pAllocationsChanged arrays. -@param[out] pAllocationsChanged Array of boolean values that will indicate whether matching allocation in pAllocations array has been moved. This parameter is optional. Pass null if you don't need this information. -@param pDefragmentationInfo Configuration parameters. Optional - pass null to use default values. -@param[out] pDefragmentationStats Statistics returned by the function. Optional - pass null if you don't need this information. -@return `VK_SUCCESS` if completed, negative error code in case of error. - -\deprecated This is a part of the old interface. It is recommended to use structure #VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead. - -This function works by moving allocations to different places (different -`VkDeviceMemory` objects and/or different offsets) in order to optimize memory -usage. Only allocations that are in `pAllocations` array can be moved. All other -allocations are considered nonmovable in this call. Basic rules: - -- Only allocations made in memory types that have - `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` - flags can be compacted. You may pass other allocations but it makes no sense - - these will never be moved. -- Custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT or - #VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT flag are not defragmented. Allocations - passed to this function that come from such pools are ignored. -- Allocations created with #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT or - created as dedicated allocations for any other reason are also ignored. -- Both allocations made with or without #VMA_ALLOCATION_CREATE_MAPPED_BIT - flag can be compacted. If not persistently mapped, memory will be mapped - temporarily inside this function if needed. -- You must not pass same #VmaAllocation object multiple times in `pAllocations` array. - -The function also frees empty `VkDeviceMemory` blocks. - -Warning: This function may be time-consuming, so you shouldn't call it too often -(like after every resource creation/destruction). -You can call it on special occasions (like when reloading a game level or -when you just destroyed a lot of objects). Calling it every frame may be OK, but -you should measure that on your platform. - -For more information, see [Defragmentation](@ref defragmentation) chapter. +It contains some number of elements in-place, which allows it to avoid heap allocation +when the actual number of elements is below that threshold. This allows normal "small" +cases to be fast without losing generality for large inputs. */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment( - VmaAllocator allocator, - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo *pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats); +template +class VmaSmallVector +{ +public: + typedef T value_type; + typedef T* iterator; -/** \brief Binds buffer to allocation. + VmaSmallVector(const AllocatorT& allocator); + VmaSmallVector(size_t count, const AllocatorT& allocator); + template + VmaSmallVector(const VmaSmallVector&) = delete; + template + VmaSmallVector& operator=(const VmaSmallVector&) = delete; + ~VmaSmallVector() = default; -Binds specified buffer to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create a buffer, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindBufferMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). + bool empty() const { return m_Count == 0; } + size_t size() const { return m_Count; } + T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; } + T& front() { VMA_HEAVY_ASSERT(m_Count > 0); return data()[0]; } + T& back() { VMA_HEAVY_ASSERT(m_Count > 0); return data()[m_Count - 1]; } + const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; } + const T& front() const { VMA_HEAVY_ASSERT(m_Count > 0); return data()[0]; } + const T& back() const { VMA_HEAVY_ASSERT(m_Count > 0); return data()[m_Count - 1]; } -It is recommended to use function vmaCreateBuffer() instead of this one. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkBuffer buffer); + iterator begin() { return data(); } + iterator end() { return data() + m_Count; } -/** \brief Binds buffer to allocation with additional parameters. + void pop_front() { VMA_HEAVY_ASSERT(m_Count > 0); remove(0); } + void pop_back() { VMA_HEAVY_ASSERT(m_Count > 0); resize(size() - 1); } + void push_front(const T& src) { insert(0, src); } -@param allocationLocalOffset Additional offset to be added while binding, relative to the beginnig of the `allocation`. Normally it should be 0. -@param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. + void push_back(const T& src); + void resize(size_t newCount, bool freeMemory = false); + void clear(bool freeMemory = false); + void insert(size_t index, const T& src); + void remove(size_t index); -This function is similar to vmaBindBufferMemory(), but it provides additional parameters. + T& operator[](size_t index) { VMA_HEAVY_ASSERT(index < m_Count); return data()[index]; } + const T& operator[](size_t index) const { VMA_HEAVY_ASSERT(index < m_Count); return data()[index]; } -If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag -or with VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_1`. Otherwise the call fails. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize allocationLocalOffset, - VkBuffer buffer, - const void* pNext); +private: + size_t m_Count; + T m_StaticArray[N]; // Used when m_Size <= N + VmaVector m_DynamicArray; // Used when m_Size > N +}; -/** \brief Binds image to allocation. +#ifndef _VMA_SMALL_VECTOR_FUNCTIONS +template +VmaSmallVector::VmaSmallVector(const AllocatorT& allocator) + : m_Count(0), + m_DynamicArray(allocator) {} -Binds specified image to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create an image, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindImageMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). +template +VmaSmallVector::VmaSmallVector(size_t count, const AllocatorT& allocator) + : m_Count(count), + m_DynamicArray(count > N ? count : 0, allocator) {} -It is recommended to use function vmaCreateImage() instead of this one. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkImage image); +template +void VmaSmallVector::push_back(const T& src) +{ + const size_t newIndex = size(); + resize(newIndex + 1); + data()[newIndex] = src; +} -/** \brief Binds image to allocation with additional parameters. +template +void VmaSmallVector::resize(size_t newCount, bool freeMemory) +{ + if (newCount > N && m_Count > N) + { + // Any direction, staying in m_DynamicArray + m_DynamicArray.resize(newCount); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + } + else if (newCount > N && m_Count <= N) + { + // Growing, moving from m_StaticArray to m_DynamicArray + m_DynamicArray.resize(newCount); + if (m_Count > 0) + { + memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T)); + } + } + else if (newCount <= N && m_Count > N) + { + // Shrinking, moving from m_DynamicArray to m_StaticArray + if (newCount > 0) + { + memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T)); + } + m_DynamicArray.resize(0); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + } + else + { + // Any direction, staying in m_StaticArray - nothing to do here + } + m_Count = newCount; +} -@param allocationLocalOffset Additional offset to be added while binding, relative to the beginnig of the `allocation`. Normally it should be 0. -@param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. +template +void VmaSmallVector::clear(bool freeMemory) +{ + m_DynamicArray.clear(); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + m_Count = 0; +} -This function is similar to vmaBindImageMemory(), but it provides additional parameters. +template +void VmaSmallVector::insert(size_t index, const T& src) +{ + VMA_HEAVY_ASSERT(index <= m_Count); + const size_t oldCount = size(); + resize(oldCount + 1); + T* const dataPtr = data(); + if (index < oldCount) + { + // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray. + memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T)); + } + dataPtr[index] = src; +} -If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag -or with VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_1`. Otherwise the call fails. +template +void VmaSmallVector::remove(size_t index) +{ + VMA_HEAVY_ASSERT(index < m_Count); + const size_t oldCount = size(); + if (index < oldCount - 1) + { + // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray. + T* const dataPtr = data(); + memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T)); + } + resize(oldCount - 1); +} +#endif // _VMA_SMALL_VECTOR_FUNCTIONS +#endif // _VMA_SMALL_VECTOR + +#ifndef _VMA_POOL_ALLOCATOR +/* +Allocator for objects of type T using a list of arrays (pools) to speed up +allocation. Number of elements that can be allocated is not bounded because +allocator can create multiple blocks. */ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize allocationLocalOffset, - VkImage image, - const void* pNext); +template +class VmaPoolAllocator +{ + VMA_CLASS_NO_COPY(VmaPoolAllocator) +public: + VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity); + ~VmaPoolAllocator(); + template T* Alloc(Types&&... args); + void Free(T* ptr); -/** -@param[out] pBuffer Buffer that was created. -@param[out] pAllocation Allocation that was created. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). +private: + union Item + { + uint32_t NextFreeIndex; + alignas(T) char Value[sizeof(T)]; + }; + struct ItemBlock + { + Item* pItems; + uint32_t Capacity; + uint32_t FirstFreeIndex; + }; -This function automatically: + const VkAllocationCallbacks* m_pAllocationCallbacks; + const uint32_t m_FirstBlockCapacity; + VmaVector> m_ItemBlocks; --# Creates buffer. --# Allocates appropriate memory for it. --# Binds the buffer with the memory. + ItemBlock& CreateNewBlock(); +}; -If any of these operations fail, buffer and allocation are not created, -returned value is negative error code, *pBuffer and *pAllocation are null. +#ifndef _VMA_POOL_ALLOCATOR_FUNCTIONS +template +VmaPoolAllocator::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) + : m_pAllocationCallbacks(pAllocationCallbacks), + m_FirstBlockCapacity(firstBlockCapacity), + m_ItemBlocks(VmaStlAllocator(pAllocationCallbacks)) +{ + VMA_ASSERT(m_FirstBlockCapacity > 1); +} -If the function succeeded, you must destroy both buffer and allocation when you -no longer need them using either convenience function vmaDestroyBuffer() or -separately, using `vkDestroyBuffer()` and vmaFreeMemory(). +template +VmaPoolAllocator::~VmaPoolAllocator() +{ + for (size_t i = m_ItemBlocks.size(); i--;) + vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity); + m_ItemBlocks.clear(); +} -If VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, -VK_KHR_dedicated_allocation extension is used internally to query driver whether -it requires or prefers the new buffer to have dedicated allocation. If yes, -and if dedicated allocation is possible (VmaAllocationCreateInfo::pool is null -and VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated -allocation for this buffer, just like when using -VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkBuffer* pBuffer, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); +template +template T* VmaPoolAllocator::Alloc(Types&&... args) +{ + for (size_t i = m_ItemBlocks.size(); i--; ) + { + ItemBlock& block = m_ItemBlocks[i]; + // This block has some free items: Use first one. + if (block.FirstFreeIndex != UINT32_MAX) + { + Item* const pItem = &block.pItems[block.FirstFreeIndex]; + block.FirstFreeIndex = pItem->NextFreeIndex; + T* result = (T*)&pItem->Value; + new(result)T(std::forward(args)...); // Explicit constructor call. + return result; + } + } -/** \brief Destroys Vulkan buffer and frees allocated memory. + // No block has free item: Create new one and use it. + ItemBlock& newBlock = CreateNewBlock(); + Item* const pItem = &newBlock.pItems[0]; + newBlock.FirstFreeIndex = pItem->NextFreeIndex; + T* result = (T*)&pItem->Value; + new(result) T(std::forward(args)...); // Explicit constructor call. + return result; +} -This is just a convenience function equivalent to: +template +void VmaPoolAllocator::Free(T* ptr) +{ + // Search all memory blocks to find ptr. + for (size_t i = m_ItemBlocks.size(); i--; ) + { + ItemBlock& block = m_ItemBlocks[i]; -\code -vkDestroyBuffer(device, buffer, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode - -It it safe to pass null as buffer and/or allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( - VmaAllocator allocator, - VkBuffer buffer, - VmaAllocation allocation); - -/// Function similar to vmaCreateBuffer(). -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkImage* pImage, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); + // Casting to union. + Item* pItemPtr; + memcpy(&pItemPtr, &ptr, sizeof(pItemPtr)); -/** \brief Destroys Vulkan image and frees allocated memory. + // Check if pItemPtr is in address range of this block. + if ((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity)) + { + ptr->~T(); // Explicit destructor call. + const uint32_t index = static_cast(pItemPtr - block.pItems); + pItemPtr->NextFreeIndex = block.FirstFreeIndex; + block.FirstFreeIndex = index; + return; + } + } + VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool."); +} -This is just a convenience function equivalent to: +template +typename VmaPoolAllocator::ItemBlock& VmaPoolAllocator::CreateNewBlock() +{ + const uint32_t newBlockCapacity = m_ItemBlocks.empty() ? + m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2; -\code -vkDestroyImage(device, image, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode + const ItemBlock newBlock = + { + vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity), + newBlockCapacity, + 0 + }; -It it safe to pass null as image and/or allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( - VmaAllocator allocator, - VkImage image, - VmaAllocation allocation); + m_ItemBlocks.push_back(newBlock); -#ifdef __cplusplus + // Setup singly-linked list of all free items in this block. + for (uint32_t i = 0; i < newBlockCapacity - 1; ++i) + newBlock.pItems[i].NextFreeIndex = i + 1; + newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX; + return m_ItemBlocks.back(); } -#endif - -#endif // AMD_VULKAN_MEMORY_ALLOCATOR_H +#endif // _VMA_POOL_ALLOCATOR_FUNCTIONS +#endif // _VMA_POOL_ALLOCATOR -// For Visual Studio IntelliSense. -#if defined(__cplusplus) && defined(__INTELLISENSE__) -#define VMA_IMPLEMENTATION -#endif +#ifndef _VMA_RAW_LIST +template +struct VmaListItem +{ + VmaListItem* pPrev; + VmaListItem* pNext; + T Value; +}; -#ifdef VMA_IMPLEMENTATION -#undef VMA_IMPLEMENTATION +// Doubly linked list. +template +class VmaRawList +{ + VMA_CLASS_NO_COPY(VmaRawList) +public: + typedef VmaListItem ItemType; -#include -#include -#include -#include + VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks); + // Intentionally not calling Clear, because that would be unnecessary + // computations to return all items to m_ItemAllocator as free. + ~VmaRawList() = default; -/******************************************************************************* -CONFIGURATION SECTION + size_t GetCount() const { return m_Count; } + bool IsEmpty() const { return m_Count == 0; } -Define some of these macros before each #include of this header or change them -here if you need other then default behavior depending on your environment. -*/ + ItemType* Front() { return m_pFront; } + ItemType* Back() { return m_pBack; } + const ItemType* Front() const { return m_pFront; } + const ItemType* Back() const { return m_pBack; } -// Define this macro to 1 to make the library use STL containers instead of its own implementation. -//#define VMA_USE_STL_CONTAINERS 1 + ItemType* PushFront(); + ItemType* PushBack(); + ItemType* PushFront(const T& value); + ItemType* PushBack(const T& value); + void PopFront(); + void PopBack(); -/* Set this macro to 1 to make the library including and using STL containers: -std::pair, std::vector, std::list, std::unordered_map. + // Item can be null - it means PushBack. + ItemType* InsertBefore(ItemType* pItem); + // Item can be null - it means PushFront. + ItemType* InsertAfter(ItemType* pItem); + ItemType* InsertBefore(ItemType* pItem, const T& value); + ItemType* InsertAfter(ItemType* pItem, const T& value); -Set it to 0 or undefined to make the library using its own implementation of -the containers. -*/ -#if VMA_USE_STL_CONTAINERS - #define VMA_USE_STL_VECTOR 1 - #define VMA_USE_STL_UNORDERED_MAP 1 - #define VMA_USE_STL_LIST 1 -#endif + void Clear(); + void Remove(ItemType* pItem); -#ifndef VMA_USE_STL_SHARED_MUTEX - // Compiler conforms to C++17. - #if __cplusplus >= 201703L - #define VMA_USE_STL_SHARED_MUTEX 1 - // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus - // Otherwise it's always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. - // See: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/ - #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L - #define VMA_USE_STL_SHARED_MUTEX 1 - #else - #define VMA_USE_STL_SHARED_MUTEX 0 - #endif -#endif +private: + const VkAllocationCallbacks* const m_pAllocationCallbacks; + VmaPoolAllocator m_ItemAllocator; + ItemType* m_pFront; + ItemType* m_pBack; + size_t m_Count; +}; -/* -THESE INCLUDES ARE NOT ENABLED BY DEFAULT. -Library has its own container implementation. -*/ -#if VMA_USE_STL_VECTOR - #include -#endif +#ifndef _VMA_RAW_LIST_FUNCTIONS +template +VmaRawList::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) + : m_pAllocationCallbacks(pAllocationCallbacks), + m_ItemAllocator(pAllocationCallbacks, 128), + m_pFront(VMA_NULL), + m_pBack(VMA_NULL), + m_Count(0) {} -#if VMA_USE_STL_UNORDERED_MAP - #include -#endif +template +VmaListItem* VmaRawList::PushFront() +{ + ItemType* const pNewItem = m_ItemAllocator.Alloc(); + pNewItem->pPrev = VMA_NULL; + if (IsEmpty()) + { + pNewItem->pNext = VMA_NULL; + m_pFront = pNewItem; + m_pBack = pNewItem; + m_Count = 1; + } + else + { + pNewItem->pNext = m_pFront; + m_pFront->pPrev = pNewItem; + m_pFront = pNewItem; + ++m_Count; + } + return pNewItem; +} -#if VMA_USE_STL_LIST - #include -#endif +template +VmaListItem* VmaRawList::PushBack() +{ + ItemType* const pNewItem = m_ItemAllocator.Alloc(); + pNewItem->pNext = VMA_NULL; + if(IsEmpty()) + { + pNewItem->pPrev = VMA_NULL; + m_pFront = pNewItem; + m_pBack = pNewItem; + m_Count = 1; + } + else + { + pNewItem->pPrev = m_pBack; + m_pBack->pNext = pNewItem; + m_pBack = pNewItem; + ++m_Count; + } + return pNewItem; +} -/* -Following headers are used in this CONFIGURATION section only, so feel free to -remove them if not needed. -*/ -#include // for assert -#include // for min, max -#include +template +VmaListItem* VmaRawList::PushFront(const T& value) +{ + ItemType* const pNewItem = PushFront(); + pNewItem->Value = value; + return pNewItem; +} -#ifndef VMA_NULL - // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. - #define VMA_NULL nullptr -#endif +template +VmaListItem* VmaRawList::PushBack(const T& value) +{ + ItemType* const pNewItem = PushBack(); + pNewItem->Value = value; + return pNewItem; +} -#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16) -#include -void *aligned_alloc(size_t alignment, size_t size) +template +void VmaRawList::PopFront() { - // alignment must be >= sizeof(void*) - if(alignment < sizeof(void*)) + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const pFrontItem = m_pFront; + ItemType* const pNextItem = pFrontItem->pNext; + if (pNextItem != VMA_NULL) { - alignment = sizeof(void*); + pNextItem->pPrev = VMA_NULL; } - - return memalign(alignment, size); + m_pFront = pNextItem; + m_ItemAllocator.Free(pFrontItem); + --m_Count; } -#elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)) -#include -void *aligned_alloc(size_t alignment, size_t size) + +template +void VmaRawList::PopBack() { - // alignment must be >= sizeof(void*) - if(alignment < sizeof(void*)) + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const pBackItem = m_pBack; + ItemType* const pPrevItem = pBackItem->pPrev; + if(pPrevItem != VMA_NULL) { - alignment = sizeof(void*); + pPrevItem->pNext = VMA_NULL; } - - void *pointer; - if(posix_memalign(&pointer, alignment, size) == 0) - return pointer; - return VMA_NULL; + m_pBack = pPrevItem; + m_ItemAllocator.Free(pBackItem); + --m_Count; } -#endif -// If your compiler is not compatible with C++11 and definition of -// aligned_alloc() function is missing, uncommeting following line may help: +template +void VmaRawList::Clear() +{ + if (IsEmpty() == false) + { + ItemType* pItem = m_pBack; + while (pItem != VMA_NULL) + { + ItemType* const pPrevItem = pItem->pPrev; + m_ItemAllocator.Free(pItem); + pItem = pPrevItem; + } + m_pFront = VMA_NULL; + m_pBack = VMA_NULL; + m_Count = 0; + } +} -//#include +template +void VmaRawList::Remove(ItemType* pItem) +{ + VMA_HEAVY_ASSERT(pItem != VMA_NULL); + VMA_HEAVY_ASSERT(m_Count > 0); -// Normal assert to check for programmer's errors, especially in Debug configuration. -#ifndef VMA_ASSERT - #ifdef NDEBUG - #define VMA_ASSERT(expr) - #else - #define VMA_ASSERT(expr) assert(expr) - #endif -#endif + if(pItem->pPrev != VMA_NULL) + { + pItem->pPrev->pNext = pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(m_pFront == pItem); + m_pFront = pItem->pNext; + } -// Assert that will be called very often, like inside data structures e.g. operator[]. -// Making it non-empty can make program slow. -#ifndef VMA_HEAVY_ASSERT - #ifdef NDEBUG - #define VMA_HEAVY_ASSERT(expr) - #else - #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) - #endif -#endif + if(pItem->pNext != VMA_NULL) + { + pItem->pNext->pPrev = pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(m_pBack == pItem); + m_pBack = pItem->pPrev; + } -#ifndef VMA_ALIGN_OF - #define VMA_ALIGN_OF(type) (__alignof(type)) -#endif + m_ItemAllocator.Free(pItem); + --m_Count; +} -#ifndef VMA_SYSTEM_ALIGNED_MALLOC - #if defined(_WIN32) - #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment))) - #else - #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) )) - #endif -#endif +template +VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) +{ + if(pItem != VMA_NULL) + { + ItemType* const prevItem = pItem->pPrev; + ItemType* const newItem = m_ItemAllocator.Alloc(); + newItem->pPrev = prevItem; + newItem->pNext = pItem; + pItem->pPrev = newItem; + if(prevItem != VMA_NULL) + { + prevItem->pNext = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_pFront == pItem); + m_pFront = newItem; + } + ++m_Count; + return newItem; + } + else + return PushBack(); +} -#ifndef VMA_SYSTEM_FREE - #if defined(_WIN32) - #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr) - #else - #define VMA_SYSTEM_FREE(ptr) free(ptr) - #endif -#endif +template +VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) +{ + if(pItem != VMA_NULL) + { + ItemType* const nextItem = pItem->pNext; + ItemType* const newItem = m_ItemAllocator.Alloc(); + newItem->pNext = nextItem; + newItem->pPrev = pItem; + pItem->pNext = newItem; + if(nextItem != VMA_NULL) + { + nextItem->pPrev = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_pBack == pItem); + m_pBack = newItem; + } + ++m_Count; + return newItem; + } + else + return PushFront(); +} -#ifndef VMA_MIN - #define VMA_MIN(v1, v2) (std::min((v1), (v2))) -#endif +template +VmaListItem* VmaRawList::InsertBefore(ItemType* pItem, const T& value) +{ + ItemType* const newItem = InsertBefore(pItem); + newItem->Value = value; + return newItem; +} -#ifndef VMA_MAX - #define VMA_MAX(v1, v2) (std::max((v1), (v2))) -#endif +template +VmaListItem* VmaRawList::InsertAfter(ItemType* pItem, const T& value) +{ + ItemType* const newItem = InsertAfter(pItem); + newItem->Value = value; + return newItem; +} +#endif // _VMA_RAW_LIST_FUNCTIONS +#endif // _VMA_RAW_LIST -#ifndef VMA_SWAP - #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) -#endif +#ifndef _VMA_LIST +template +class VmaList +{ + VMA_CLASS_NO_COPY(VmaList) +public: + class reverse_iterator; + class const_iterator; + class const_reverse_iterator; -#ifndef VMA_SORT - #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) -#endif + class iterator + { + friend class const_iterator; + friend class VmaList; + public: + iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} -#ifndef VMA_DEBUG_LOG - #define VMA_DEBUG_LOG(format, ...) - /* - #define VMA_DEBUG_LOG(format, ...) do { \ - printf(format, __VA_ARGS__); \ - printf("\n"); \ - } while(false) - */ -#endif + T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } -// Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. -#if VMA_STATS_STRING_ENABLED - static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num) - { - snprintf(outStr, strLen, "%u", static_cast(num)); - } - static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num) - { - snprintf(outStr, strLen, "%llu", static_cast(num)); - } - static inline void VmaPtrToStr(char* outStr, size_t strLen, const void* ptr) - { - snprintf(outStr, strLen, "%p", ptr); - } -#endif + bool operator==(const iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } -#ifndef VMA_MUTEX - class VmaMutex + iterator operator++(int) { iterator result = *this; ++*this; return result; } + iterator operator--(int) { iterator result = *this; --*this; return result; } + + iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } + iterator& operator--(); + + private: + VmaRawList* m_pList; + VmaListItem* m_pItem; + + iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + class reverse_iterator { + friend class const_reverse_iterator; + friend class VmaList; public: - void Lock() { m_Mutex.lock(); } - void Unlock() { m_Mutex.unlock(); } - bool TryLock() { return m_Mutex.try_lock(); } + reverse_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + reverse_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + + T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } + + bool operator==(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } + + reverse_iterator operator++(int) { reverse_iterator result = *this; ++* this; return result; } + reverse_iterator operator--(int) { reverse_iterator result = *this; --* this; return result; } + + reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } + reverse_iterator& operator--(); + private: - std::mutex m_Mutex; + VmaRawList* m_pList; + VmaListItem* m_pItem; + + reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} }; - #define VMA_MUTEX VmaMutex -#endif + class const_iterator + { + friend class VmaList; + public: + const_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + const_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + const_iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} -// Read-write mutex, where "read" is shared access, "write" is exclusive access. -#ifndef VMA_RW_MUTEX - #if VMA_USE_STL_SHARED_MUTEX - // Use std::shared_mutex from C++17. - #include - class VmaRWMutex - { - public: - void LockRead() { m_Mutex.lock_shared(); } - void UnlockRead() { m_Mutex.unlock_shared(); } - bool TryLockRead() { return m_Mutex.try_lock_shared(); } - void LockWrite() { m_Mutex.lock(); } - void UnlockWrite() { m_Mutex.unlock(); } - bool TryLockWrite() { return m_Mutex.try_lock(); } - private: - std::shared_mutex m_Mutex; - }; - #define VMA_RW_MUTEX VmaRWMutex - #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 - // Use SRWLOCK from WinAPI. - // Minimum supported client = Windows Vista, server = Windows Server 2008. - class VmaRWMutex - { - public: - VmaRWMutex() { InitializeSRWLock(&m_Lock); } - void LockRead() { AcquireSRWLockShared(&m_Lock); } - void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } - bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } - void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } - void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } - bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } - private: - SRWLOCK m_Lock; - }; - #define VMA_RW_MUTEX VmaRWMutex - #else - // Less efficient fallback: Use normal mutex. - class VmaRWMutex - { - public: - void LockRead() { m_Mutex.Lock(); } - void UnlockRead() { m_Mutex.Unlock(); } - bool TryLockRead() { return m_Mutex.TryLock(); } - void LockWrite() { m_Mutex.Lock(); } - void UnlockWrite() { m_Mutex.Unlock(); } - bool TryLockWrite() { return m_Mutex.TryLock(); } - private: - VMA_MUTEX m_Mutex; - }; - #define VMA_RW_MUTEX VmaRWMutex - #endif // #if VMA_USE_STL_SHARED_MUTEX -#endif // #ifndef VMA_RW_MUTEX + iterator drop_const() { return { const_cast*>(m_pList), const_cast*>(m_pItem) }; } -/* -If providing your own implementation, you need to implement a subset of std::atomic. -*/ -#ifndef VMA_ATOMIC_UINT32 - #include - #define VMA_ATOMIC_UINT32 std::atomic -#endif + const T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + const T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } -#ifndef VMA_ATOMIC_UINT64 - #include - #define VMA_ATOMIC_UINT64 std::atomic -#endif + bool operator==(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } -#ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY - /** - Every allocation will have its own memory block. - Define to 1 for debugging purposes only. - */ - #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) -#endif + const_iterator operator++(int) { const_iterator result = *this; ++* this; return result; } + const_iterator operator--(int) { const_iterator result = *this; --* this; return result; } -#ifndef VMA_DEBUG_ALIGNMENT - /** - Minimum alignment of all allocations, in bytes. - Set to more than 1 for debugging purposes only. Must be power of two. - */ - #define VMA_DEBUG_ALIGNMENT (1) -#endif + const_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } + const_iterator& operator--(); -#ifndef VMA_DEBUG_MARGIN - /** - Minimum margin before and after every allocation, in bytes. - Set nonzero for debugging purposes only. - */ - #define VMA_DEBUG_MARGIN (0) -#endif + private: + const VmaRawList* m_pList; + const VmaListItem* m_pItem; -#ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS - /** - Define this macro to 1 to automatically fill new allocations and destroyed - allocations with some bit pattern. - */ - #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) -#endif + const_iterator(const VmaRawList* pList, const VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + class const_reverse_iterator + { + friend class VmaList; + public: + const_reverse_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + const_reverse_iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + const_reverse_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} -#ifndef VMA_DEBUG_DETECT_CORRUPTION - /** - Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to - enable writing magic value to the margin before and after every allocation and - validating it, so that memory corruptions (out-of-bounds writes) are detected. - */ - #define VMA_DEBUG_DETECT_CORRUPTION (0) -#endif + reverse_iterator drop_const() { return { const_cast*>(m_pList), const_cast*>(m_pItem) }; } -#ifndef VMA_DEBUG_GLOBAL_MUTEX - /** - Set this to 1 for debugging purposes only, to enable single mutex protecting all - entry calls to the library. Can be useful for debugging multithreading issues. - */ - #define VMA_DEBUG_GLOBAL_MUTEX (0) -#endif + const T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + const T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } -#ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY - /** - Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. - Set to more than 1 for debugging purposes only. Must be power of two. - */ - #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) -#endif + bool operator==(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } -#ifndef VMA_SMALL_HEAP_MAX_SIZE - /// Maximum size of a memory heap in Vulkan to consider it "small". - #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) -#endif + const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++* this; return result; } + const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --* this; return result; } -#ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE - /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. - #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) -#endif + const_reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } + const_reverse_iterator& operator--(); -#ifndef VMA_CLASS_NO_COPY - #define VMA_CLASS_NO_COPY(className) \ - private: \ - className(const className&) = delete; \ - className& operator=(const className&) = delete; -#endif + private: + const VmaRawList* m_pList; + const VmaListItem* m_pItem; -static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX; + const_reverse_iterator(const VmaRawList* pList, const VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; -// Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F. -static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666; + VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) {} -static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC; -static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF; + bool empty() const { return m_RawList.IsEmpty(); } + size_t size() const { return m_RawList.GetCount(); } -/******************************************************************************* -END OF CONFIGURATION -*/ + iterator begin() { return iterator(&m_RawList, m_RawList.Front()); } + iterator end() { return iterator(&m_RawList, VMA_NULL); } + + const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); } + const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); } -// # Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants. + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } -static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040; -static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080; -static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000; + reverse_iterator rbegin() { return reverse_iterator(&m_RawList, m_RawList.Back()); } + reverse_iterator rend() { return reverse_iterator(&m_RawList, VMA_NULL); } -static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u; + const_reverse_iterator crbegin() const { return const_reverse_iterator(&m_RawList, m_RawList.Back()); } + const_reverse_iterator crend() const { return const_reverse_iterator(&m_RawList, VMA_NULL); } -static VkAllocationCallbacks VmaEmptyAllocationCallbacks = { - VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; + const_reverse_iterator rbegin() const { return crbegin(); } + const_reverse_iterator rend() const { return crend(); } -// Returns number of bits set to 1 in (v). -static inline uint32_t VmaCountBitsSet(uint32_t v) + void push_back(const T& value) { m_RawList.PushBack(value); } + iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); } + + void clear() { m_RawList.Clear(); } + void erase(iterator it) { m_RawList.Remove(it.m_pItem); } + +private: + VmaRawList m_RawList; +}; + +#ifndef _VMA_LIST_FUNCTIONS +template +typename VmaList::iterator& VmaList::iterator::operator--() { - uint32_t c = v - ((v >> 1) & 0x55555555); - c = ((c >> 2) & 0x33333333) + (c & 0x33333333); - c = ((c >> 4) + c) & 0x0F0F0F0F; - c = ((c >> 8) + c) & 0x00FF00FF; - c = ((c >> 16) + c) & 0x0000FFFF; - return c; + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; } -// Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16. -// Use types like uint32_t, uint64_t as T. -template -static inline T VmaAlignUp(T val, T align) +template +typename VmaList::reverse_iterator& VmaList::reverse_iterator::operator--() { - return (val + align - 1) / align * align; + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Front(); + } + return *this; } -// Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8. -// Use types like uint32_t, uint64_t as T. -template -static inline T VmaAlignDown(T val, T align) + +template +typename VmaList::const_iterator& VmaList::const_iterator::operator--() { - return val / align * align; + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; } -// Division with mathematical rounding to nearest number. -template -static inline T VmaRoundDiv(T x, T y) +template +typename VmaList::const_reverse_iterator& VmaList::const_reverse_iterator::operator--() { - return (x + (y / (T)2)) / y; + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; } +#endif // _VMA_LIST_FUNCTIONS +#endif // _VMA_LIST +#ifndef _VMA_INTRUSIVE_LINKED_LIST /* -Returns true if given number is a power of two. -T must be unsigned integer number or signed integer but always nonnegative. -For 0 returns true. +Expected interface of ItemTypeTraits: +struct MyItemTypeTraits +{ + typedef MyItem ItemType; + static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; } + static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; } + static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; } + static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; } +}; */ -template -inline bool VmaIsPow2(T x) +template +class VmaIntrusiveLinkedList { - return (x & (x-1)) == 0; -} +public: + typedef typename ItemTypeTraits::ItemType ItemType; + static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); } + static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); } + + // Movable, not copyable. + VmaIntrusiveLinkedList() = default; + VmaIntrusiveLinkedList(VmaIntrusiveLinkedList && src); + VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList&) = delete; + VmaIntrusiveLinkedList& operator=(VmaIntrusiveLinkedList&& src); + VmaIntrusiveLinkedList& operator=(const VmaIntrusiveLinkedList&) = delete; + ~VmaIntrusiveLinkedList() { VMA_HEAVY_ASSERT(IsEmpty()); } -// Returns smallest power of 2 greater or equal to v. -static inline uint32_t VmaNextPow2(uint32_t v) + size_t GetCount() const { return m_Count; } + bool IsEmpty() const { return m_Count == 0; } + ItemType* Front() { return m_Front; } + ItemType* Back() { return m_Back; } + const ItemType* Front() const { return m_Front; } + const ItemType* Back() const { return m_Back; } + + void PushBack(ItemType* item); + void PushFront(ItemType* item); + ItemType* PopBack(); + ItemType* PopFront(); + + // MyItem can be null - it means PushBack. + void InsertBefore(ItemType* existingItem, ItemType* newItem); + // MyItem can be null - it means PushFront. + void InsertAfter(ItemType* existingItem, ItemType* newItem); + void Remove(ItemType* item); + void RemoveAll(); + +private: + ItemType* m_Front = VMA_NULL; + ItemType* m_Back = VMA_NULL; + size_t m_Count = 0; +}; + +#ifndef _VMA_INTRUSIVE_LINKED_LIST_FUNCTIONS +template +VmaIntrusiveLinkedList::VmaIntrusiveLinkedList(VmaIntrusiveLinkedList&& src) + : m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; + src.m_Front = src.m_Back = VMA_NULL; + src.m_Count = 0; } -static inline uint64_t VmaNextPow2(uint64_t v) + +template +VmaIntrusiveLinkedList& VmaIntrusiveLinkedList::operator=(VmaIntrusiveLinkedList&& src) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; - v++; - return v; + if (&src != this) + { + VMA_HEAVY_ASSERT(IsEmpty()); + m_Front = src.m_Front; + m_Back = src.m_Back; + m_Count = src.m_Count; + src.m_Front = src.m_Back = VMA_NULL; + src.m_Count = 0; + } + return *this; } -// Returns largest power of 2 less or equal to v. -static inline uint32_t VmaPrevPow2(uint32_t v) +template +void VmaIntrusiveLinkedList::PushBack(ItemType* item) { - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v = v ^ (v >> 1); - return v; + VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL); + if (IsEmpty()) + { + m_Front = item; + m_Back = item; + m_Count = 1; + } + else + { + ItemTypeTraits::AccessPrev(item) = m_Back; + ItemTypeTraits::AccessNext(m_Back) = item; + m_Back = item; + ++m_Count; + } } -static inline uint64_t VmaPrevPow2(uint64_t v) + +template +void VmaIntrusiveLinkedList::PushFront(ItemType* item) { - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; - v = v ^ (v >> 1); - return v; + VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL); + if (IsEmpty()) + { + m_Front = item; + m_Back = item; + m_Count = 1; + } + else + { + ItemTypeTraits::AccessNext(item) = m_Front; + ItemTypeTraits::AccessPrev(m_Front) = item; + m_Front = item; + ++m_Count; + } } -static inline bool VmaStrIsEmpty(const char* pStr) +template +typename VmaIntrusiveLinkedList::ItemType* VmaIntrusiveLinkedList::PopBack() { - return pStr == VMA_NULL || *pStr == '\0'; + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const backItem = m_Back; + ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem); + if (prevItem != VMA_NULL) + { + ItemTypeTraits::AccessNext(prevItem) = VMA_NULL; + } + m_Back = prevItem; + --m_Count; + ItemTypeTraits::AccessPrev(backItem) = VMA_NULL; + ItemTypeTraits::AccessNext(backItem) = VMA_NULL; + return backItem; } -#if VMA_STATS_STRING_ENABLED - -static const char* VmaAlgorithmToStr(uint32_t algorithm) +template +typename VmaIntrusiveLinkedList::ItemType* VmaIntrusiveLinkedList::PopFront() { - switch(algorithm) + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const frontItem = m_Front; + ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem); + if (nextItem != VMA_NULL) { - case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT: - return "Linear"; - case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT: - return "Buddy"; - case 0: - return "Default"; - default: - VMA_ASSERT(0); - return ""; + ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL; } + m_Front = nextItem; + --m_Count; + ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL; + ItemTypeTraits::AccessNext(frontItem) = VMA_NULL; + return frontItem; } -#endif // #if VMA_STATS_STRING_ENABLED - -#ifndef VMA_SORT +template +void VmaIntrusiveLinkedList::InsertBefore(ItemType* existingItem, ItemType* newItem) +{ + VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL); + if (existingItem != VMA_NULL) + { + ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem); + ItemTypeTraits::AccessPrev(newItem) = prevItem; + ItemTypeTraits::AccessNext(newItem) = existingItem; + ItemTypeTraits::AccessPrev(existingItem) = newItem; + if (prevItem != VMA_NULL) + { + ItemTypeTraits::AccessNext(prevItem) = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_Front == existingItem); + m_Front = newItem; + } + ++m_Count; + } + else + PushBack(newItem); +} -template -Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp) +template +void VmaIntrusiveLinkedList::InsertAfter(ItemType* existingItem, ItemType* newItem) { - Iterator centerValue = end; --centerValue; - Iterator insertIndex = beg; - for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex) + VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL); + if (existingItem != VMA_NULL) { - if(cmp(*memTypeIndex, *centerValue)) + ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem); + ItemTypeTraits::AccessNext(newItem) = nextItem; + ItemTypeTraits::AccessPrev(newItem) = existingItem; + ItemTypeTraits::AccessNext(existingItem) = newItem; + if (nextItem != VMA_NULL) { - if(insertIndex != memTypeIndex) - { - VMA_SWAP(*memTypeIndex, *insertIndex); - } - ++insertIndex; + ItemTypeTraits::AccessPrev(nextItem) = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_Back == existingItem); + m_Back = newItem; } + ++m_Count; + } + else + return PushFront(newItem); +} + +template +void VmaIntrusiveLinkedList::Remove(ItemType* item) +{ + VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0); + if (ItemTypeTraits::GetPrev(item) != VMA_NULL) + { + ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item); + } + else + { + VMA_HEAVY_ASSERT(m_Front == item); + m_Front = ItemTypeTraits::GetNext(item); + } + + if (ItemTypeTraits::GetNext(item) != VMA_NULL) + { + ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item); } - if(insertIndex != centerValue) + else { - VMA_SWAP(*insertIndex, *centerValue); + VMA_HEAVY_ASSERT(m_Back == item); + m_Back = ItemTypeTraits::GetPrev(item); } - return insertIndex; + ItemTypeTraits::AccessPrev(item) = VMA_NULL; + ItemTypeTraits::AccessNext(item) = VMA_NULL; + --m_Count; } -template -void VmaQuickSort(Iterator beg, Iterator end, Compare cmp) +template +void VmaIntrusiveLinkedList::RemoveAll() { - if(beg < end) + if (!IsEmpty()) { - Iterator it = VmaQuickSortPartition(beg, end, cmp); - VmaQuickSort(beg, it, cmp); - VmaQuickSort(it + 1, end, cmp); + ItemType* item = m_Back; + while (item != VMA_NULL) + { + ItemType* const prevItem = ItemTypeTraits::AccessPrev(item); + ItemTypeTraits::AccessPrev(item) = VMA_NULL; + ItemTypeTraits::AccessNext(item) = VMA_NULL; + item = prevItem; + } + m_Front = VMA_NULL; + m_Back = VMA_NULL; + m_Count = 0; } } +#endif // _VMA_INTRUSIVE_LINKED_LIST_FUNCTIONS +#endif // _VMA_INTRUSIVE_LINKED_LIST -#define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp) +// Unused in this version. +#if 0 -#endif // #ifndef VMA_SORT +#ifndef _VMA_PAIR +template +struct VmaPair +{ + T1 first; + T2 second; -/* -Returns true if two memory blocks occupy overlapping pages. -ResourceA must be in less memory offset than ResourceB. + VmaPair() : first(), second() {} + VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) {} +}; -Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)" -chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity". -*/ -static inline bool VmaBlocksOnSamePage( - VkDeviceSize resourceAOffset, - VkDeviceSize resourceASize, - VkDeviceSize resourceBOffset, - VkDeviceSize pageSize) +template +struct VmaPairFirstLess { - VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0); - VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1; - VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1); - VkDeviceSize resourceBStart = resourceBOffset; - VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1); - return resourceAEndPage == resourceBStartPage; -} + bool operator()(const VmaPair& lhs, const VmaPair& rhs) const + { + return lhs.first < rhs.first; + } + bool operator()(const VmaPair& lhs, const FirstT& rhsFirst) const + { + return lhs.first < rhsFirst; + } +}; +#endif // _VMA_PAIR -enum VmaSuballocationType +#ifndef _VMA_MAP +/* Class compatible with subset of interface of std::unordered_map. +KeyT, ValueT must be POD because they will be stored in VmaVector. +*/ +template +class VmaMap { - VMA_SUBALLOCATION_TYPE_FREE = 0, - VMA_SUBALLOCATION_TYPE_UNKNOWN = 1, - VMA_SUBALLOCATION_TYPE_BUFFER = 2, - VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3, - VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4, - VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5, - VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +public: + typedef VmaPair PairType; + typedef PairType* iterator; + + VmaMap(const VmaStlAllocator& allocator) : m_Vector(allocator) {} + + iterator begin() { return m_Vector.begin(); } + iterator end() { return m_Vector.end(); } + size_t size() { return m_Vector.size(); } + + void insert(const PairType& pair); + iterator find(const KeyT& key); + void erase(iterator it); + +private: + VmaVector< PairType, VmaStlAllocator> m_Vector; }; -/* -Returns true if given suballocation types could conflict and must respect -VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer -or linear image and another one is optimal image. If type is unknown, behave -conservatively. -*/ -static inline bool VmaIsBufferImageGranularityConflict( - VmaSuballocationType suballocType1, - VmaSuballocationType suballocType2) +#ifndef _VMA_MAP_FUNCTIONS +template +void VmaMap::insert(const PairType& pair) { - if(suballocType1 > suballocType2) - { - VMA_SWAP(suballocType1, suballocType2); - } - - switch(suballocType1) - { - case VMA_SUBALLOCATION_TYPE_FREE: - return false; - case VMA_SUBALLOCATION_TYPE_UNKNOWN: - return true; - case VMA_SUBALLOCATION_TYPE_BUFFER: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL: - return false; - default: - VMA_ASSERT(0); - return true; - } + const size_t indexToInsert = VmaBinaryFindFirstNotLess( + m_Vector.data(), + m_Vector.data() + m_Vector.size(), + pair, + VmaPairFirstLess()) - m_Vector.data(); + VmaVectorInsert(m_Vector, indexToInsert, pair); } -static void VmaWriteMagicValue(void* pData, VkDeviceSize offset) +template +VmaPair* VmaMap::find(const KeyT& key) { -#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION - uint32_t* pDst = (uint32_t*)((char*)pData + offset); - const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); - for(size_t i = 0; i < numberCount; ++i, ++pDst) + PairType* it = VmaBinaryFindFirstNotLess( + m_Vector.data(), + m_Vector.data() + m_Vector.size(), + key, + VmaPairFirstLess()); + if ((it != m_Vector.end()) && (it->first == key)) { - *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE; + return it; } -#else - // no-op -#endif -} - -static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset) -{ -#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION - const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset); - const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); - for(size_t i = 0; i < numberCount; ++i, ++pSrc) + else { - if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE) - { - return false; - } + return m_Vector.end(); } -#endif - return true; } -/* -Fills structure with parameters of an example buffer to be used for transfers -during GPU memory defragmentation. -*/ -static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo) +template +void VmaMap::erase(iterator it) { - memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo)); - outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size. + VmaVectorRemove(m_Vector, it - m_Vector.begin()); } +#endif // _VMA_MAP_FUNCTIONS +#endif // _VMA_MAP -// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope). -struct VmaMutexLock -{ - VMA_CLASS_NO_COPY(VmaMutexLock) -public: - VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) : - m_pMutex(useMutex ? &mutex : VMA_NULL) - { if(m_pMutex) { m_pMutex->Lock(); } } - ~VmaMutexLock() - { if(m_pMutex) { m_pMutex->Unlock(); } } -private: - VMA_MUTEX* m_pMutex; -}; - -// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading. -struct VmaMutexLockRead -{ - VMA_CLASS_NO_COPY(VmaMutexLockRead) -public: - VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) : - m_pMutex(useMutex ? &mutex : VMA_NULL) - { if(m_pMutex) { m_pMutex->LockRead(); } } - ~VmaMutexLockRead() { if(m_pMutex) { m_pMutex->UnlockRead(); } } -private: - VMA_RW_MUTEX* m_pMutex; -}; +#endif // #if 0 -// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing. -struct VmaMutexLockWrite +#if !defined(_VMA_STRING_BUILDER) && VMA_STATS_STRING_ENABLED +class VmaStringBuilder { - VMA_CLASS_NO_COPY(VmaMutexLockWrite) public: - VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) : - m_pMutex(useMutex ? &mutex : VMA_NULL) - { if(m_pMutex) { m_pMutex->LockWrite(); } } - ~VmaMutexLockWrite() { if(m_pMutex) { m_pMutex->UnlockWrite(); } } -private: - VMA_RW_MUTEX* m_pMutex; -}; - -#if VMA_DEBUG_GLOBAL_MUTEX - static VMA_MUTEX gDebugGlobalMutex; - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); -#else - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK -#endif + VmaStringBuilder(const VkAllocationCallbacks* allocationCallbacks) : m_Data(VmaStlAllocator(allocationCallbacks)) {} + ~VmaStringBuilder() = default; -// Minimum size of a free suballocation to register it in the free suballocation collection. -static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16; + size_t GetLength() const { return m_Data.size(); } + const char* GetData() const { return m_Data.data(); } + void AddNewLine() { Add('\n'); } + void Add(char ch) { m_Data.push_back(ch); } -/* -Performs binary search and returns iterator to first element that is greater or -equal to (key), according to comparison (cmp). + void Add(const char* pStr); + void AddNumber(uint32_t num); + void AddNumber(uint64_t num); + void AddPointer(const void* ptr); -Cmp should return true if first argument is less than second argument. +private: + VmaVector> m_Data; +}; -Returned value is the found element, if present in the collection or place where -new element with value (key) should be inserted. -*/ -template -static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp) +#ifndef _VMA_STRING_BUILDER_FUNCTIONS +void VmaStringBuilder::Add(const char* pStr) { - size_t down = 0, up = (end - beg); - while(down < up) + const size_t strLen = strlen(pStr); + if (strLen > 0) { - const size_t mid = (down + up) / 2; - if(cmp(*(beg+mid), key)) - { - down = mid + 1; - } - else - { - up = mid; - } + const size_t oldCount = m_Data.size(); + m_Data.resize(oldCount + strLen); + memcpy(m_Data.data() + oldCount, pStr, strLen); } - return beg + down; } -template -IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp) +void VmaStringBuilder::AddNumber(uint32_t num) { - IterT it = VmaBinaryFindFirstNotLess( - beg, end, value, cmp); - if(it == end || - (!cmp(*it, value) && !cmp(value, *it))) + char buf[11]; + buf[10] = '\0'; + char* p = &buf[10]; + do { - return it; - } - return end; + *--p = '0' + (num % 10); + num /= 10; + } while (num); + Add(p); } -/* -Returns true if all pointers in the array are not-null and unique. -Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT. -T must be pointer type, e.g. VmaAllocation, VmaPool. -*/ -template -static bool VmaValidatePointerArray(uint32_t count, const T* arr) +void VmaStringBuilder::AddNumber(uint64_t num) { - for(uint32_t i = 0; i < count; ++i) + char buf[21]; + buf[20] = '\0'; + char* p = &buf[20]; + do { - const T iPtr = arr[i]; - if(iPtr == VMA_NULL) - { - return false; - } - for(uint32_t j = i + 1; j < count; ++j) - { - if(iPtr == arr[j]) - { - return false; - } - } - } - return true; + *--p = '0' + (num % 10); + num /= 10; + } while (num); + Add(p); } -template -static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) +void VmaStringBuilder::AddPointer(const void* ptr) { - newStruct->pNext = mainStruct->pNext; - mainStruct->pNext = newStruct; + char buf[21]; + VmaPtrToStr(buf, sizeof(buf), ptr); + Add(buf); } +#endif //_VMA_STRING_BUILDER_FUNCTIONS +#endif // _VMA_STRING_BUILDER -//////////////////////////////////////////////////////////////////////////////// -// Memory allocation - -static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment) +#if !defined(_VMA_JSON_WRITER) && VMA_STATS_STRING_ENABLED +/* +Allows to conveniently build a correct JSON document to be written to the +VmaStringBuilder passed to the constructor. +*/ +class VmaJsonWriter { - if((pAllocationCallbacks != VMA_NULL) && - (pAllocationCallbacks->pfnAllocation != VMA_NULL)) + VMA_CLASS_NO_COPY(VmaJsonWriter) +public: + // sb - string builder to write the document to. Must remain alive for the whole lifetime of this object. + VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb); + ~VmaJsonWriter(); + + // Begins object by writing "{". + // Inside an object, you must call pairs of WriteString and a value, e.g.: + // j.BeginObject(true); j.WriteString("A"); j.WriteNumber(1); j.WriteString("B"); j.WriteNumber(2); j.EndObject(); + // Will write: { "A": 1, "B": 2 } + void BeginObject(bool singleLine = false); + // Ends object by writing "}". + void EndObject(); + + // Begins array by writing "[". + // Inside an array, you can write a sequence of any values. + void BeginArray(bool singleLine = false); + // Ends array by writing "[". + void EndArray(); + + // Writes a string value inside "". + // pStr can contain any ANSI characters, including '"', new line etc. - they will be properly escaped. + void WriteString(const char* pStr); + + // Begins writing a string value. + // Call BeginString, ContinueString, ContinueString, ..., EndString instead of + // WriteString to conveniently build the string content incrementally, made of + // parts including numbers. + void BeginString(const char* pStr = VMA_NULL); + // Posts next part of an open string. + void ContinueString(const char* pStr); + // Posts next part of an open string. The number is converted to decimal characters. + void ContinueString(uint32_t n); + void ContinueString(uint64_t n); + // Posts next part of an open string. Pointer value is converted to characters + // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00 + void ContinueString_Pointer(const void* ptr); + // Ends writing a string value by writing '"'. + void EndString(const char* pStr = VMA_NULL); + + // Writes a number value. + void WriteNumber(uint32_t n); + void WriteNumber(uint64_t n); + // Writes a boolean value - false or true. + void WriteBool(bool b); + // Writes a null value. + void WriteNull(); + +private: + enum COLLECTION_TYPE { - return (*pAllocationCallbacks->pfnAllocation)( - pAllocationCallbacks->pUserData, - size, - alignment, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } - else + COLLECTION_TYPE_OBJECT, + COLLECTION_TYPE_ARRAY, + }; + struct StackItem { - return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment); - } + COLLECTION_TYPE type; + uint32_t valueCount; + bool singleLineMode; + }; + + static const char* const INDENT; + + VmaStringBuilder& m_SB; + VmaVector< StackItem, VmaStlAllocator > m_Stack; + bool m_InsideString; + + void BeginValue(bool isString); + void WriteIndent(bool oneLess = false); +}; +const char* const VmaJsonWriter::INDENT = " "; + +#ifndef _VMA_JSON_WRITER_FUNCTIONS +VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) + : m_SB(sb), + m_Stack(VmaStlAllocator(pAllocationCallbacks)), + m_InsideString(false) {} + +VmaJsonWriter::~VmaJsonWriter() +{ + VMA_ASSERT(!m_InsideString); + VMA_ASSERT(m_Stack.empty()); } -static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr) +void VmaJsonWriter::BeginObject(bool singleLine) { - if((pAllocationCallbacks != VMA_NULL) && - (pAllocationCallbacks->pfnFree != VMA_NULL)) - { - (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr); - } - else - { - VMA_SYSTEM_FREE(ptr); - } + VMA_ASSERT(!m_InsideString); + + BeginValue(false); + m_SB.Add('{'); + + StackItem item; + item.type = COLLECTION_TYPE_OBJECT; + item.valueCount = 0; + item.singleLineMode = singleLine; + m_Stack.push_back(item); } -template -static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks) +void VmaJsonWriter::EndObject() { - return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T)); + VMA_ASSERT(!m_InsideString); + + WriteIndent(true); + m_SB.Add('}'); + + VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT); + m_Stack.pop_back(); } -template -static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count) +void VmaJsonWriter::BeginArray(bool singleLine) { - return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T)); + VMA_ASSERT(!m_InsideString); + + BeginValue(false); + m_SB.Add('['); + + StackItem item; + item.type = COLLECTION_TYPE_ARRAY; + item.valueCount = 0; + item.singleLineMode = singleLine; + m_Stack.push_back(item); } -#define vma_new(allocator, type) new(VmaAllocate(allocator))(type) +void VmaJsonWriter::EndArray() +{ + VMA_ASSERT(!m_InsideString); -#define vma_new_array(allocator, type, count) new(VmaAllocateArray((allocator), (count)))(type) + WriteIndent(true); + m_SB.Add(']'); -template -static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr) + VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY); + m_Stack.pop_back(); +} + +void VmaJsonWriter::WriteString(const char* pStr) { - ptr->~T(); - VmaFree(pAllocationCallbacks, ptr); + BeginString(pStr); + EndString(); } -template -static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count) +void VmaJsonWriter::BeginString(const char* pStr) { - if(ptr != VMA_NULL) + VMA_ASSERT(!m_InsideString); + + BeginValue(true); + m_SB.Add('"'); + m_InsideString = true; + if (pStr != VMA_NULL && pStr[0] != '\0') { - for(size_t i = count; i--; ) - { - ptr[i].~T(); - } - VmaFree(pAllocationCallbacks, ptr); + ContinueString(pStr); } } -static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr) +void VmaJsonWriter::ContinueString(const char* pStr) { - if(srcStr != VMA_NULL) - { - const size_t len = strlen(srcStr); - char* const result = vma_new_array(allocs, char, len + 1); - memcpy(result, srcStr, len + 1); - return result; - } - else + VMA_ASSERT(m_InsideString); + + const size_t strLen = strlen(pStr); + for (size_t i = 0; i < strLen; ++i) { - return VMA_NULL; + char ch = pStr[i]; + if (ch == '\\') + { + m_SB.Add("\\\\"); + } + else if (ch == '"') + { + m_SB.Add("\\\""); + } + else if (ch >= 32) + { + m_SB.Add(ch); + } + else switch (ch) + { + case '\b': + m_SB.Add("\\b"); + break; + case '\f': + m_SB.Add("\\f"); + break; + case '\n': + m_SB.Add("\\n"); + break; + case '\r': + m_SB.Add("\\r"); + break; + case '\t': + m_SB.Add("\\t"); + break; + default: + VMA_ASSERT(0 && "Character not currently supported."); + break; + } } } -static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str) +void VmaJsonWriter::ContinueString(uint32_t n) { - if(str != VMA_NULL) - { - const size_t len = strlen(str); - vma_delete_array(allocs, str, len + 1); - } + VMA_ASSERT(m_InsideString); + m_SB.AddNumber(n); } -// STL-compatible allocator. -template -class VmaStlAllocator +void VmaJsonWriter::ContinueString(uint64_t n) { -public: - const VkAllocationCallbacks* const m_pCallbacks; - typedef T value_type; - - VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { } - template VmaStlAllocator(const VmaStlAllocator& src) : m_pCallbacks(src.m_pCallbacks) { } + VMA_ASSERT(m_InsideString); + m_SB.AddNumber(n); +} - T* allocate(size_t n) { return VmaAllocateArray(m_pCallbacks, n); } - void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); } +void VmaJsonWriter::ContinueString_Pointer(const void* ptr) +{ + VMA_ASSERT(m_InsideString); + m_SB.AddPointer(ptr); +} - template - bool operator==(const VmaStlAllocator& rhs) const - { - return m_pCallbacks == rhs.m_pCallbacks; - } - template - bool operator!=(const VmaStlAllocator& rhs) const +void VmaJsonWriter::EndString(const char* pStr) +{ + VMA_ASSERT(m_InsideString); + if (pStr != VMA_NULL && pStr[0] != '\0') { - return m_pCallbacks != rhs.m_pCallbacks; + ContinueString(pStr); } + m_SB.Add('"'); + m_InsideString = false; +} - VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete; -}; - -#if VMA_USE_STL_VECTOR - -#define VmaVector std::vector - -template -static void VmaVectorInsert(std::vector& vec, size_t index, const T& item) +void VmaJsonWriter::WriteNumber(uint32_t n) { - vec.insert(vec.begin() + index, item); + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.AddNumber(n); } -template -static void VmaVectorRemove(std::vector& vec, size_t index) +void VmaJsonWriter::WriteNumber(uint64_t n) { - vec.erase(vec.begin() + index); + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.AddNumber(n); } -#else // #if VMA_USE_STL_VECTOR - -/* Class with interface compatible with subset of std::vector. -T must be POD because constructors and destructors are not called and memcpy is -used for these objects. */ -template -class VmaVector +void VmaJsonWriter::WriteBool(bool b) { -public: - typedef T value_type; + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.Add(b ? "true" : "false"); +} - VmaVector(const AllocatorT& allocator) : - m_Allocator(allocator), - m_pArray(VMA_NULL), - m_Count(0), - m_Capacity(0) - { - } +void VmaJsonWriter::WriteNull() +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.Add("null"); +} - VmaVector(size_t count, const AllocatorT& allocator) : - m_Allocator(allocator), - m_pArray(count ? (T*)VmaAllocateArray(allocator.m_pCallbacks, count) : VMA_NULL), - m_Count(count), - m_Capacity(count) +void VmaJsonWriter::BeginValue(bool isString) +{ + if (!m_Stack.empty()) { - } - - // This version of the constructor is here for compatibility with pre-C++14 std::vector. - // value is unused. - VmaVector(size_t count, const T& value, const AllocatorT& allocator) - : VmaVector(count, allocator) {} - - VmaVector(const VmaVector& src) : - m_Allocator(src.m_Allocator), - m_pArray(src.m_Count ? (T*)VmaAllocateArray(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL), - m_Count(src.m_Count), - m_Capacity(src.m_Count) - { - if(m_Count != 0) + StackItem& currItem = m_Stack.back(); + if (currItem.type == COLLECTION_TYPE_OBJECT && + currItem.valueCount % 2 == 0) { - memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T)); + VMA_ASSERT(isString); } - } - - ~VmaVector() - { - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - } - VmaVector& operator=(const VmaVector& rhs) - { - if(&rhs != this) + if (currItem.type == COLLECTION_TYPE_OBJECT && + currItem.valueCount % 2 != 0) { - resize(rhs.m_Count); - if(m_Count != 0) - { - memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T)); - } + m_SB.Add(": "); } - return *this; - } - - bool empty() const { return m_Count == 0; } - size_t size() const { return m_Count; } - T* data() { return m_pArray; } - const T* data() const { return m_pArray; } - - T& operator[](size_t index) - { - VMA_HEAVY_ASSERT(index < m_Count); - return m_pArray[index]; - } - const T& operator[](size_t index) const - { - VMA_HEAVY_ASSERT(index < m_Count); - return m_pArray[index]; - } - - T& front() - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[0]; - } - const T& front() const - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[0]; - } - T& back() - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[m_Count - 1]; - } - const T& back() const - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[m_Count - 1]; - } - - void reserve(size_t newCapacity, bool freeMemory = false) - { - newCapacity = VMA_MAX(newCapacity, m_Count); - - if((newCapacity < m_Capacity) && !freeMemory) + else if (currItem.valueCount > 0) { - newCapacity = m_Capacity; + m_SB.Add(", "); + WriteIndent(); } - - if(newCapacity != m_Capacity) + else { - T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator, newCapacity) : VMA_NULL; - if(m_Count != 0) - { - memcpy(newArray, m_pArray, m_Count * sizeof(T)); - } - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - m_Capacity = newCapacity; - m_pArray = newArray; + WriteIndent(); } + ++currItem.valueCount; } +} - void resize(size_t newCount, bool freeMemory = false) +void VmaJsonWriter::WriteIndent(bool oneLess) +{ + if (!m_Stack.empty() && !m_Stack.back().singleLineMode) { - size_t newCapacity = m_Capacity; - if(newCount > m_Capacity) + m_SB.AddNewLine(); + + size_t count = m_Stack.size(); + if (count > 0 && oneLess) { - newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8)); + --count; } - else if(freeMemory) + for (size_t i = 0; i < count; ++i) { - newCapacity = newCount; + m_SB.Add(INDENT); } + } +} +#endif // _VMA_JSON_WRITER_FUNCTIONS - if(newCapacity != m_Capacity) - { - T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL; - const size_t elementsToCopy = VMA_MIN(m_Count, newCount); - if(elementsToCopy != 0) - { - memcpy(newArray, m_pArray, elementsToCopy * sizeof(T)); - } - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - m_Capacity = newCapacity; - m_pArray = newArray; - } +static void VmaPrintDetailedStatistics(VmaJsonWriter& json, const VmaDetailedStatistics& stat) +{ + json.BeginObject(); - m_Count = newCount; - } + json.WriteString("BlockCount"); + json.WriteNumber(stat.statistics.blockCount); + json.WriteString("BlockBytes"); + json.WriteNumber(stat.statistics.blockBytes); + json.WriteString("AllocationCount"); + json.WriteNumber(stat.statistics.allocationCount); + json.WriteString("AllocationBytes"); + json.WriteNumber(stat.statistics.allocationBytes); + json.WriteString("UnusedRangeCount"); + json.WriteNumber(stat.unusedRangeCount); - void clear(bool freeMemory = false) + if (stat.statistics.allocationCount > 1) { - resize(0, freeMemory); + json.WriteString("AllocationSizeMin"); + json.WriteNumber(stat.allocationSizeMin); + json.WriteString("AllocationSizeMax"); + json.WriteNumber(stat.allocationSizeMax); } - - void insert(size_t index, const T& src) + if (stat.unusedRangeCount > 1) { - VMA_HEAVY_ASSERT(index <= m_Count); - const size_t oldCount = size(); - resize(oldCount + 1); - if(index < oldCount) - { - memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T)); - } - m_pArray[index] = src; + json.WriteString("UnusedRangeSizeMin"); + json.WriteNumber(stat.unusedRangeSizeMin); + json.WriteString("UnusedRangeSizeMax"); + json.WriteNumber(stat.unusedRangeSizeMax); } + json.EndObject(); +} +#endif // _VMA_JSON_WRITER + +#ifndef _VMA_MAPPING_HYSTERESIS + +class VmaMappingHysteresis +{ + VMA_CLASS_NO_COPY(VmaMappingHysteresis) +public: + VmaMappingHysteresis() = default; - void remove(size_t index) + uint32_t GetExtraMapping() const { return m_ExtraMapping; } + + // Call when Map was called. + // Returns true if switched to extra +1 mapping reference count. + bool PostMap() { - VMA_HEAVY_ASSERT(index < m_Count); - const size_t oldCount = size(); - if(index < oldCount - 1) +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 0) { - memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T)); + ++m_MajorCounter; + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) + { + m_ExtraMapping = 1; + m_MajorCounter = 0; + m_MinorCounter = 0; + return true; + } } - resize(oldCount - 1); + else // m_ExtraMapping == 1 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + return false; } - void push_back(const T& src) + // Call when Unmap was called. + void PostUnmap() { - const size_t newIndex = size(); - resize(newIndex + 1); - m_pArray[newIndex] = src; +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 0) + ++m_MajorCounter; + else // m_ExtraMapping == 1 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED } - void pop_back() + // Call when allocation was made from the memory block. + void PostAlloc() { - VMA_HEAVY_ASSERT(m_Count > 0); - resize(size() - 1); +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 1) + ++m_MajorCounter; + else // m_ExtraMapping == 0 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED } - void push_front(const T& src) + // Call when allocation was freed from the memory block. + // Returns true if switched to extra -1 mapping reference count. + bool PostFree() { - insert(0, src); +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 1) + { + ++m_MajorCounter; + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && + m_MajorCounter > m_MinorCounter + 1) + { + m_ExtraMapping = 0; + m_MajorCounter = 0; + m_MinorCounter = 0; + return true; + } + } + else // m_ExtraMapping == 0 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + return false; } - void pop_front() +private: + static const int32_t COUNTER_MIN_EXTRA_MAPPING = 7; + + uint32_t m_MinorCounter = 0; + uint32_t m_MajorCounter = 0; + uint32_t m_ExtraMapping = 0; // 0 or 1. + + void PostMinorCounter() { - VMA_HEAVY_ASSERT(m_Count > 0); - remove(0); + if(m_MinorCounter < m_MajorCounter) + { + ++m_MinorCounter; + } + else if(m_MajorCounter > 0) + { + --m_MajorCounter; + --m_MinorCounter; + } } +}; - typedef T* iterator; - - iterator begin() { return m_pArray; } - iterator end() { return m_pArray + m_Count; } +#endif // _VMA_MAPPING_HYSTERESIS -private: - AllocatorT m_Allocator; - T* m_pArray; - size_t m_Count; - size_t m_Capacity; -}; +#ifndef _VMA_DEVICE_MEMORY_BLOCK +/* +Represents a single block of device memory (`VkDeviceMemory`) with all the +data about its regions (aka suballocations, #VmaAllocation), assigned and free. -template -static void VmaVectorInsert(VmaVector& vec, size_t index, const T& item) +Thread-safety: +- Access to m_pMetadata must be externally synchronized. +- Map, Unmap, Bind* are synchronized internally. +*/ +class VmaDeviceMemoryBlock { - vec.insert(index, item); -} + VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock) +public: + VmaBlockMetadata* m_pMetadata; -template -static void VmaVectorRemove(VmaVector& vec, size_t index) -{ - vec.remove(index); -} + VmaDeviceMemoryBlock(VmaAllocator hAllocator); + ~VmaDeviceMemoryBlock(); + + // Always call after construction. + void Init( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t newMemoryTypeIndex, + VkDeviceMemory newMemory, + VkDeviceSize newSize, + uint32_t id, + uint32_t algorithm, + VkDeviceSize bufferImageGranularity); + // Always call before destruction. + void Destroy(VmaAllocator allocator); -#endif // #if VMA_USE_STL_VECTOR + VmaPool GetParentPool() const { return m_hParentPool; } + VkDeviceMemory GetDeviceMemory() const { return m_hMemory; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + uint32_t GetId() const { return m_Id; } + void* GetMappedData() const { return m_pMappedData; } + uint32_t GetMapRefCount() const { return m_MapCount; } -template -size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value) -{ - const size_t indexToInsert = VmaBinaryFindFirstNotLess( - vector.data(), - vector.data() + vector.size(), - value, - CmpLess()) - vector.data(); - VmaVectorInsert(vector, indexToInsert, value); - return indexToInsert; -} + // Call when allocation/free was made from m_pMetadata. + // Used for m_MappingHysteresis. + void PostAlloc(VmaAllocator hAllocator); + void PostFree(VmaAllocator hAllocator); -template -bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value) -{ - CmpLess comparator; - typename VectorT::iterator it = VmaBinaryFindFirstNotLess( - vector.begin(), - vector.end(), - value, - comparator); - if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it)) - { - size_t indexToRemove = it - vector.begin(); - VmaVectorRemove(vector, indexToRemove); - return true; - } - return false; -} + // Validates all data structures inside this object. If not valid, returns false. + bool Validate() const; + VkResult CheckCorruption(VmaAllocator hAllocator); -//////////////////////////////////////////////////////////////////////////////// -// class VmaPoolAllocator + // ppData can be null. + VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData); + void Unmap(VmaAllocator hAllocator, uint32_t count); -/* -Allocator for objects of type T using a list of arrays (pools) to speed up -allocation. Number of elements that can be allocated is not bounded because -allocator can create multiple blocks. -*/ -template -class VmaPoolAllocator -{ - VMA_CLASS_NO_COPY(VmaPoolAllocator) -public: - VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity); - ~VmaPoolAllocator(); - template T* Alloc(Types... args); - void Free(T* ptr); + VkResult WriteMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); + VkResult ValidateMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); -private: - union Item - { - uint32_t NextFreeIndex; - alignas(T) char Value[sizeof(T)]; - }; + VkResult BindBufferMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext); + VkResult BindImageMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext); - struct ItemBlock - { - Item* pItems; - uint32_t Capacity; - uint32_t FirstFreeIndex; - }; - - const VkAllocationCallbacks* m_pAllocationCallbacks; - const uint32_t m_FirstBlockCapacity; - VmaVector< ItemBlock, VmaStlAllocator > m_ItemBlocks; +private: + VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. + uint32_t m_MemoryTypeIndex; + uint32_t m_Id; + VkDeviceMemory m_hMemory; - ItemBlock& CreateNewBlock(); + /* + Protects access to m_hMemory so it is not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. + Also protects m_MapCount, m_pMappedData. + Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. + */ + VMA_MUTEX m_MapAndBindMutex; + VmaMappingHysteresis m_MappingHysteresis; + uint32_t m_MapCount; + void* m_pMappedData; }; +#endif // _VMA_DEVICE_MEMORY_BLOCK -template -VmaPoolAllocator::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) : - m_pAllocationCallbacks(pAllocationCallbacks), - m_FirstBlockCapacity(firstBlockCapacity), - m_ItemBlocks(VmaStlAllocator(pAllocationCallbacks)) +#ifndef _VMA_ALLOCATION_T +struct VmaAllocation_T { - VMA_ASSERT(m_FirstBlockCapacity > 1); -} + friend struct VmaDedicatedAllocationListItemTraits; -template -VmaPoolAllocator::~VmaPoolAllocator() -{ - for(size_t i = m_ItemBlocks.size(); i--; ) - vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity); - m_ItemBlocks.clear(); -} + enum FLAGS + { + FLAG_PERSISTENT_MAP = 0x01, + FLAG_MAPPING_ALLOWED = 0x02, + }; -template -template T* VmaPoolAllocator::Alloc(Types... args) -{ - for(size_t i = m_ItemBlocks.size(); i--; ) +public: + enum ALLOCATION_TYPE { - ItemBlock& block = m_ItemBlocks[i]; - // This block has some free items: Use first one. - if(block.FirstFreeIndex != UINT32_MAX) - { - Item* const pItem = &block.pItems[block.FirstFreeIndex]; - block.FirstFreeIndex = pItem->NextFreeIndex; - T* result = (T*)&pItem->Value; - new(result)T(std::forward(args)...); // Explicit constructor call. - return result; - } - } + ALLOCATION_TYPE_NONE, + ALLOCATION_TYPE_BLOCK, + ALLOCATION_TYPE_DEDICATED, + }; - // No block has free item: Create new one and use it. - ItemBlock& newBlock = CreateNewBlock(); - Item* const pItem = &newBlock.pItems[0]; - newBlock.FirstFreeIndex = pItem->NextFreeIndex; - T* result = (T*)&pItem->Value; - new(result)T(std::forward(args)...); // Explicit constructor call. - return result; -} - -template -void VmaPoolAllocator::Free(T* ptr) -{ - // Search all memory blocks to find ptr. - for(size_t i = m_ItemBlocks.size(); i--; ) - { - ItemBlock& block = m_ItemBlocks[i]; - - // Casting to union. - Item* pItemPtr; - memcpy(&pItemPtr, &ptr, sizeof(pItemPtr)); - - // Check if pItemPtr is in address range of this block. - if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity)) - { - ptr->~T(); // Explicit destructor call. - const uint32_t index = static_cast(pItemPtr - block.pItems); - pItemPtr->NextFreeIndex = block.FirstFreeIndex; - block.FirstFreeIndex = index; - return; - } - } - VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool."); -} + // This struct is allocated using VmaPoolAllocator. + VmaAllocation_T(bool mappingAllowed); + ~VmaAllocation_T(); -template -typename VmaPoolAllocator::ItemBlock& VmaPoolAllocator::CreateNewBlock() -{ - const uint32_t newBlockCapacity = m_ItemBlocks.empty() ? - m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2; + void InitBlockAllocation( + VmaDeviceMemoryBlock* block, + VmaAllocHandle allocHandle, + VkDeviceSize alignment, + VkDeviceSize size, + uint32_t memoryTypeIndex, + VmaSuballocationType suballocationType, + bool mapped); + // pMappedData not null means allocation is created with MAPPED flag. + void InitDedicatedAllocation( + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceMemory hMemory, + VmaSuballocationType suballocationType, + void* pMappedData, + VkDeviceSize size); - const ItemBlock newBlock = { - vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity), - newBlockCapacity, - 0 }; + ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; } + VkDeviceSize GetAlignment() const { return m_Alignment; } + VkDeviceSize GetSize() const { return m_Size; } + void* GetUserData() const { return m_pUserData; } + const char* GetName() const { return m_pName; } + VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; } - m_ItemBlocks.push_back(newBlock); + VmaDeviceMemoryBlock* GetBlock() const { VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); return m_BlockAllocation.m_Block; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + bool IsPersistentMap() const { return (m_Flags & FLAG_PERSISTENT_MAP) != 0; } + bool IsMappingAllowed() const { return (m_Flags & FLAG_MAPPING_ALLOWED) != 0; } + + void SetUserData(VmaAllocator hAllocator, void* pUserData) { m_pUserData = pUserData; } + void SetName(VmaAllocator hAllocator, const char* pName); + void FreeName(VmaAllocator hAllocator); + uint8_t SwapBlockAllocation(VmaAllocator hAllocator, VmaAllocation allocation); + VmaAllocHandle GetAllocHandle() const; + VkDeviceSize GetOffset() const; + VmaPool GetParentPool() const; + VkDeviceMemory GetMemory() const; + void* GetMappedData() const; - // Setup singly-linked list of all free items in this block. - for(uint32_t i = 0; i < newBlockCapacity - 1; ++i) - newBlock.pItems[i].NextFreeIndex = i + 1; - newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX; - return m_ItemBlocks.back(); -} + void BlockAllocMap(); + void BlockAllocUnmap(); + VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData); + void DedicatedAllocUnmap(VmaAllocator hAllocator); -//////////////////////////////////////////////////////////////////////////////// -// class VmaRawList, VmaList +#if VMA_STATS_STRING_ENABLED + uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; } -#if VMA_USE_STL_LIST + void InitBufferImageUsage(uint32_t bufferImageUsage); + void PrintParameters(class VmaJsonWriter& json) const; +#endif -#define VmaList std::list +private: + // Allocation out of VmaDeviceMemoryBlock. + struct BlockAllocation + { + VmaDeviceMemoryBlock* m_Block; + VmaAllocHandle m_AllocHandle; + }; + // Allocation for an object that has its own private VkDeviceMemory. + struct DedicatedAllocation + { + VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. + VkDeviceMemory m_hMemory; + void* m_pMappedData; // Not null means memory is mapped. + VmaAllocation_T* m_Prev; + VmaAllocation_T* m_Next; + }; + union + { + // Allocation out of VmaDeviceMemoryBlock. + BlockAllocation m_BlockAllocation; + // Allocation for an object that has its own private VkDeviceMemory. + DedicatedAllocation m_DedicatedAllocation; + }; -#else // #if VMA_USE_STL_LIST + VkDeviceSize m_Alignment; + VkDeviceSize m_Size; + void* m_pUserData; + char* m_pName; + uint32_t m_MemoryTypeIndex; + uint8_t m_Type; // ALLOCATION_TYPE + uint8_t m_SuballocationType; // VmaSuballocationType + // Reference counter for vmaMapMemory()/vmaUnmapMemory(). + uint8_t m_MapCount; + uint8_t m_Flags; // enum FLAGS +#if VMA_STATS_STRING_ENABLED + uint32_t m_BufferImageUsage; // 0 if unknown. +#endif +}; +#endif // _VMA_ALLOCATION_T -template -struct VmaListItem +#ifndef _VMA_DEDICATED_ALLOCATION_LIST_ITEM_TRAITS +struct VmaDedicatedAllocationListItemTraits { - VmaListItem* pPrev; - VmaListItem* pNext; - T Value; + typedef VmaAllocation_T ItemType; + + static ItemType* GetPrev(const ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Prev; + } + static ItemType* GetNext(const ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Next; + } + static ItemType*& AccessPrev(ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Prev; + } + static ItemType*& AccessNext(ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Next; + } }; +#endif // _VMA_DEDICATED_ALLOCATION_LIST_ITEM_TRAITS -// Doubly linked list. -template -class VmaRawList +#ifndef _VMA_DEDICATED_ALLOCATION_LIST +/* +Stores linked list of VmaAllocation_T objects. +Thread-safe, synchronized internally. +*/ +class VmaDedicatedAllocationList { - VMA_CLASS_NO_COPY(VmaRawList) public: - typedef VmaListItem ItemType; - - VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks); - ~VmaRawList(); - void Clear(); - - size_t GetCount() const { return m_Count; } - bool IsEmpty() const { return m_Count == 0; } - - ItemType* Front() { return m_pFront; } - const ItemType* Front() const { return m_pFront; } - ItemType* Back() { return m_pBack; } - const ItemType* Back() const { return m_pBack; } + VmaDedicatedAllocationList() {} + ~VmaDedicatedAllocationList(); - ItemType* PushBack(); - ItemType* PushFront(); - ItemType* PushBack(const T& value); - ItemType* PushFront(const T& value); - void PopBack(); - void PopFront(); - - // Item can be null - it means PushBack. - ItemType* InsertBefore(ItemType* pItem); - // Item can be null - it means PushFront. - ItemType* InsertAfter(ItemType* pItem); + void Init(bool useMutex) { m_UseMutex = useMutex; } + bool Validate(); - ItemType* InsertBefore(ItemType* pItem, const T& value); - ItemType* InsertAfter(ItemType* pItem, const T& value); + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats); + void AddStatistics(VmaStatistics& inoutStats); +#if VMA_STATS_STRING_ENABLED + // Writes JSON array with the list of allocations. + void BuildStatsString(VmaJsonWriter& json); +#endif - void Remove(ItemType* pItem); + bool IsEmpty(); + void Register(VmaAllocation alloc); + void Unregister(VmaAllocation alloc); private: - const VkAllocationCallbacks* const m_pAllocationCallbacks; - VmaPoolAllocator m_ItemAllocator; - ItemType* m_pFront; - ItemType* m_pBack; - size_t m_Count; + typedef VmaIntrusiveLinkedList DedicatedAllocationLinkedList; + + bool m_UseMutex = true; + VMA_RW_MUTEX m_Mutex; + DedicatedAllocationLinkedList m_AllocationList; }; -template -VmaRawList::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) : - m_pAllocationCallbacks(pAllocationCallbacks), - m_ItemAllocator(pAllocationCallbacks, 128), - m_pFront(VMA_NULL), - m_pBack(VMA_NULL), - m_Count(0) -{ -} +#ifndef _VMA_DEDICATED_ALLOCATION_LIST_FUNCTIONS -template -VmaRawList::~VmaRawList() +VmaDedicatedAllocationList::~VmaDedicatedAllocationList() { - // Intentionally not calling Clear, because that would be unnecessary - // computations to return all items to m_ItemAllocator as free. -} + VMA_HEAVY_ASSERT(Validate()); -template -void VmaRawList::Clear() -{ - if(IsEmpty() == false) + if (!m_AllocationList.IsEmpty()) { - ItemType* pItem = m_pBack; - while(pItem != VMA_NULL) - { - ItemType* const pPrevItem = pItem->pPrev; - m_ItemAllocator.Free(pItem); - pItem = pPrevItem; - } - m_pFront = VMA_NULL; - m_pBack = VMA_NULL; - m_Count = 0; + VMA_ASSERT(false && "Unfreed dedicated allocations found!"); } } -template -VmaListItem* VmaRawList::PushBack() +bool VmaDedicatedAllocationList::Validate() { - ItemType* const pNewItem = m_ItemAllocator.Alloc(); - pNewItem->pNext = VMA_NULL; - if(IsEmpty()) + const size_t declaredCount = m_AllocationList.GetCount(); + size_t actualCount = 0; + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + for (VmaAllocation alloc = m_AllocationList.Front(); + alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc)) { - pNewItem->pPrev = VMA_NULL; - m_pFront = pNewItem; - m_pBack = pNewItem; - m_Count = 1; + ++actualCount; } - else + VMA_VALIDATE(actualCount == declaredCount); + + return true; +} + +void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) +{ + for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) { - pNewItem->pPrev = m_pBack; - m_pBack->pNext = pNewItem; - m_pBack = pNewItem; - ++m_Count; + const VkDeviceSize size = item->GetSize(); + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += size; + VmaAddDetailedStatisticsAllocation(inoutStats, item->GetSize()); } - return pNewItem; } -template -VmaListItem* VmaRawList::PushFront() +void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats) { - ItemType* const pNewItem = m_ItemAllocator.Alloc(); - pNewItem->pPrev = VMA_NULL; - if(IsEmpty()) + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + + const uint32_t allocCount = (uint32_t)m_AllocationList.GetCount(); + inoutStats.blockCount += allocCount; + inoutStats.allocationCount += allocCount; + + for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) { - pNewItem->pNext = VMA_NULL; - m_pFront = pNewItem; - m_pBack = pNewItem; - m_Count = 1; + const VkDeviceSize size = item->GetSize(); + inoutStats.blockBytes += size; + inoutStats.allocationBytes += size; } - else +} + +#if VMA_STATS_STRING_ENABLED +void VmaDedicatedAllocationList::BuildStatsString(VmaJsonWriter& json) +{ + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + json.BeginArray(); + for (VmaAllocation alloc = m_AllocationList.Front(); + alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc)) { - pNewItem->pNext = m_pFront; - m_pFront->pPrev = pNewItem; - m_pFront = pNewItem; - ++m_Count; + json.BeginObject(true); + alloc->PrintParameters(json); + json.EndObject(); } - return pNewItem; + json.EndArray(); } +#endif // VMA_STATS_STRING_ENABLED -template -VmaListItem* VmaRawList::PushBack(const T& value) +bool VmaDedicatedAllocationList::IsEmpty() { - ItemType* const pNewItem = PushBack(); - pNewItem->Value = value; - return pNewItem; + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + return m_AllocationList.IsEmpty(); } -template -VmaListItem* VmaRawList::PushFront(const T& value) +void VmaDedicatedAllocationList::Register(VmaAllocation alloc) { - ItemType* const pNewItem = PushFront(); - pNewItem->Value = value; - return pNewItem; + VmaMutexLockWrite lock(m_Mutex, m_UseMutex); + m_AllocationList.PushBack(alloc); } -template -void VmaRawList::PopBack() +void VmaDedicatedAllocationList::Unregister(VmaAllocation alloc) { - VMA_HEAVY_ASSERT(m_Count > 0); - ItemType* const pBackItem = m_pBack; - ItemType* const pPrevItem = pBackItem->pPrev; - if(pPrevItem != VMA_NULL) - { - pPrevItem->pNext = VMA_NULL; - } - m_pBack = pPrevItem; - m_ItemAllocator.Free(pBackItem); - --m_Count; + VmaMutexLockWrite lock(m_Mutex, m_UseMutex); + m_AllocationList.Remove(alloc); } +#endif // _VMA_DEDICATED_ALLOCATION_LIST_FUNCTIONS +#endif // _VMA_DEDICATED_ALLOCATION_LIST -template -void VmaRawList::PopFront() +#ifndef _VMA_SUBALLOCATION +/* +Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as +allocated memory block or free. +*/ +struct VmaSuballocation { - VMA_HEAVY_ASSERT(m_Count > 0); - ItemType* const pFrontItem = m_pFront; - ItemType* const pNextItem = pFrontItem->pNext; - if(pNextItem != VMA_NULL) + VkDeviceSize offset; + VkDeviceSize size; + void* userData; + VmaSuballocationType type; +}; + +// Comparator for offsets. +struct VmaSuballocationOffsetLess +{ + bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const { - pNextItem->pPrev = VMA_NULL; + return lhs.offset < rhs.offset; } - m_pFront = pNextItem; - m_ItemAllocator.Free(pFrontItem); - --m_Count; -} +}; -template -void VmaRawList::Remove(ItemType* pItem) +struct VmaSuballocationOffsetGreater { - VMA_HEAVY_ASSERT(pItem != VMA_NULL); - VMA_HEAVY_ASSERT(m_Count > 0); + bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const + { + return lhs.offset > rhs.offset; + } +}; - if(pItem->pPrev != VMA_NULL) +struct VmaSuballocationItemSizeLess +{ + bool operator()(const VmaSuballocationList::iterator lhs, + const VmaSuballocationList::iterator rhs) const { - pItem->pPrev->pNext = pItem->pNext; + return lhs->size < rhs->size; } - else + + bool operator()(const VmaSuballocationList::iterator lhs, + VkDeviceSize rhsSize) const { - VMA_HEAVY_ASSERT(m_pFront == pItem); - m_pFront = pItem->pNext; + return lhs->size < rhsSize; } +}; +#endif // _VMA_SUBALLOCATION - if(pItem->pNext != VMA_NULL) +#ifndef _VMA_ALLOCATION_REQUEST +/* +Parameters of planned allocation inside a VmaDeviceMemoryBlock. +item points to a FREE suballocation. +*/ +struct VmaAllocationRequest +{ + VmaAllocHandle allocHandle; + VkDeviceSize size; + VmaSuballocationList::iterator item; + void* customData; + uint64_t algorithmData; + VmaAllocationRequestType type; +}; +#endif // _VMA_ALLOCATION_REQUEST + +#ifndef _VMA_BLOCK_METADATA +/* +Data structure used for bookkeeping of allocations and unused ranges of memory +in a single VkDeviceMemory block. +*/ +class VmaBlockMetadata +{ +public: + // pAllocationCallbacks, if not null, must be owned externally - alive and unchanged for the whole lifetime of this object. + VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata() = default; + + virtual void Init(VkDeviceSize size) { m_Size = size; } + bool IsVirtual() const { return m_IsVirtual; } + VkDeviceSize GetSize() const { return m_Size; } + + // Validates all data structures inside this object. If not valid, returns false. + virtual bool Validate() const = 0; + virtual size_t GetAllocationCount() const = 0; + virtual size_t GetFreeRegionsCount() const = 0; + virtual VkDeviceSize GetSumFreeSize() const = 0; + // Returns true if this block is empty - contains only single free suballocation. + virtual bool IsEmpty() const = 0; + virtual void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) = 0; + virtual VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const = 0; + virtual void* GetAllocationUserData(VmaAllocHandle allocHandle) const = 0; + + virtual VmaAllocHandle GetAllocationListBegin() const = 0; + virtual VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const = 0; + virtual VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const = 0; + + // Shouldn't modify blockCount. + virtual void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const = 0; + virtual void AddStatistics(VmaStatistics& inoutStats) const = 0; + +#if VMA_STATS_STRING_ENABLED + virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0; +#endif + + // Tries to find a place for suballocation with given parameters inside this block. + // If succeeded, fills pAllocationRequest and returns true. + // If failed, returns false. + virtual bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags. + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) = 0; + + virtual VkResult CheckCorruption(const void* pBlockData) = 0; + + // Makes actual allocation based on request. Request must already be checked and valid. + virtual void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) = 0; + + // Frees suballocation assigned to given memory region. + virtual void Free(VmaAllocHandle allocHandle) = 0; + + // Frees all allocations. + // Careful! Don't call it if there are VmaAllocation objects owned by userData of cleared allocations! + virtual void Clear() = 0; + + virtual void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) = 0; + virtual void DebugLogAllAllocations() const = 0; + +protected: + const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; } + VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } + VkDeviceSize GetDebugMargin() const { return IsVirtual() ? 0 : VMA_DEBUG_MARGIN; } + + void DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const; +#if VMA_STATS_STRING_ENABLED + // mapRefCount == UINT32_MAX means unspecified. + void PrintDetailedMap_Begin(class VmaJsonWriter& json, + VkDeviceSize unusedBytes, + size_t allocationCount, + size_t unusedRangeCount) const; + void PrintDetailedMap_Allocation(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size, void* userData) const; + void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, + VkDeviceSize offset, + VkDeviceSize size) const; + void PrintDetailedMap_End(class VmaJsonWriter& json) const; +#endif + +private: + VkDeviceSize m_Size; + const VkAllocationCallbacks* m_pAllocationCallbacks; + const VkDeviceSize m_BufferImageGranularity; + const bool m_IsVirtual; +}; + +#ifndef _VMA_BLOCK_METADATA_FUNCTIONS +VmaBlockMetadata::VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : m_Size(0), + m_pAllocationCallbacks(pAllocationCallbacks), + m_BufferImageGranularity(bufferImageGranularity), + m_IsVirtual(isVirtual) {} + +void VmaBlockMetadata::DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const +{ + if (IsVirtual()) { - pItem->pNext->pPrev = pItem->pPrev; + VMA_DEBUG_LOG_FORMAT("UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; UserData: %p", offset, size, userData); } else { - VMA_HEAVY_ASSERT(m_pBack == pItem); - m_pBack = pItem->pPrev; + VMA_ASSERT(userData != VMA_NULL); + VmaAllocation allocation = reinterpret_cast(userData); + + userData = allocation->GetUserData(); + const char* name = allocation->GetName(); + +#if VMA_STATS_STRING_ENABLED + VMA_DEBUG_LOG_FORMAT("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %s; Usage: %u", + offset, size, userData, name ? name : "vma_empty", + VMA_SUBALLOCATION_TYPE_NAMES[allocation->GetSuballocationType()], + allocation->GetBufferImageUsage()); +#else + VMA_DEBUG_LOG_FORMAT("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %u", + offset, size, userData, name ? name : "vma_empty", + (uint32_t)allocation->GetSuballocationType()); +#endif // VMA_STATS_STRING_ENABLED } - m_ItemAllocator.Free(pItem); - --m_Count; } -template -VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json, + VkDeviceSize unusedBytes, size_t allocationCount, size_t unusedRangeCount) const { - if(pItem != VMA_NULL) - { - ItemType* const prevItem = pItem->pPrev; - ItemType* const newItem = m_ItemAllocator.Alloc(); - newItem->pPrev = prevItem; - newItem->pNext = pItem; - pItem->pPrev = newItem; - if(prevItem != VMA_NULL) - { - prevItem->pNext = newItem; - } - else - { - VMA_HEAVY_ASSERT(m_pFront == pItem); - m_pFront = newItem; - } - ++m_Count; - return newItem; - } - else - return PushBack(); + json.WriteString("TotalBytes"); + json.WriteNumber(GetSize()); + + json.WriteString("UnusedBytes"); + json.WriteNumber(unusedBytes); + + json.WriteString("Allocations"); + json.WriteNumber((uint64_t)allocationCount); + + json.WriteString("UnusedRanges"); + json.WriteNumber((uint64_t)unusedRangeCount); + + json.WriteString("Suballocations"); + json.BeginArray(); } -template -VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) +void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size, void* userData) const { - if(pItem != VMA_NULL) + json.BeginObject(true); + + json.WriteString("Offset"); + json.WriteNumber(offset); + + if (IsVirtual()) { - ItemType* const nextItem = pItem->pNext; - ItemType* const newItem = m_ItemAllocator.Alloc(); - newItem->pNext = nextItem; - newItem->pPrev = pItem; - pItem->pNext = newItem; - if(nextItem != VMA_NULL) - { - nextItem->pPrev = newItem; - } - else + json.WriteString("Size"); + json.WriteNumber(size); + if (userData) { - VMA_HEAVY_ASSERT(m_pBack == pItem); - m_pBack = newItem; + json.WriteString("CustomData"); + json.BeginString(); + json.ContinueString_Pointer(userData); + json.EndString(); } - ++m_Count; - return newItem; } else - return PushFront(); + { + ((VmaAllocation)userData)->PrintParameters(json); + } + + json.EndObject(); } -template -VmaListItem* VmaRawList::InsertBefore(ItemType* pItem, const T& value) +void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size) const { - ItemType* const newItem = InsertBefore(pItem); - newItem->Value = value; - return newItem; + json.BeginObject(true); + + json.WriteString("Offset"); + json.WriteNumber(offset); + + json.WriteString("Type"); + json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]); + + json.WriteString("Size"); + json.WriteNumber(size); + + json.EndObject(); } -template -VmaListItem* VmaRawList::InsertAfter(ItemType* pItem, const T& value) +void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const { - ItemType* const newItem = InsertAfter(pItem); - newItem->Value = value; - return newItem; + json.EndArray(); } +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_BLOCK_METADATA_FUNCTIONS +#endif // _VMA_BLOCK_METADATA -template -class VmaList +#ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY +// Before deleting object of this class remember to call 'Destroy()' +class VmaBlockBufferImageGranularity final { - VMA_CLASS_NO_COPY(VmaList) public: - class iterator + struct ValidationContext { - public: - iterator() : - m_pList(VMA_NULL), - m_pItem(VMA_NULL) - { - } + const VkAllocationCallbacks* allocCallbacks; + uint16_t* pageAllocs; + }; - T& operator*() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return m_pItem->Value; - } - T* operator->() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return &m_pItem->Value; - } + VmaBlockBufferImageGranularity(VkDeviceSize bufferImageGranularity); + ~VmaBlockBufferImageGranularity(); - iterator& operator++() - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - m_pItem = m_pItem->pNext; - return *this; - } - iterator& operator--() - { - if(m_pItem != VMA_NULL) - { - m_pItem = m_pItem->pPrev; - } - else - { - VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); - m_pItem = m_pList->Back(); - } - return *this; - } + bool IsEnabled() const { return m_BufferImageGranularity > MAX_LOW_BUFFER_IMAGE_GRANULARITY; } - iterator operator++(int) - { - iterator result = *this; - ++*this; - return result; - } - iterator operator--(int) - { - iterator result = *this; - --*this; - return result; - } - - bool operator==(const iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem == rhs.m_pItem; - } - bool operator!=(const iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem != rhs.m_pItem; - } - - private: - VmaRawList* m_pList; - VmaListItem* m_pItem; - - iterator(VmaRawList* pList, VmaListItem* pItem) : - m_pList(pList), - m_pItem(pItem) - { - } - - friend class VmaList; - }; - - class const_iterator - { - public: - const_iterator() : - m_pList(VMA_NULL), - m_pItem(VMA_NULL) - { - } + void Init(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize size); + // Before destroying object you must call free it's memory + void Destroy(const VkAllocationCallbacks* pAllocationCallbacks); - const_iterator(const iterator& src) : - m_pList(src.m_pList), - m_pItem(src.m_pItem) - { - } - - const T& operator*() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return m_pItem->Value; - } - const T* operator->() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return &m_pItem->Value; - } + void RoundupAllocRequest(VmaSuballocationType allocType, + VkDeviceSize& inOutAllocSize, + VkDeviceSize& inOutAllocAlignment) const; - const_iterator& operator++() - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - m_pItem = m_pItem->pNext; - return *this; - } - const_iterator& operator--() - { - if(m_pItem != VMA_NULL) - { - m_pItem = m_pItem->pPrev; - } - else - { - VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); - m_pItem = m_pList->Back(); - } - return *this; - } + bool CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, + VkDeviceSize allocSize, + VkDeviceSize blockOffset, + VkDeviceSize blockSize, + VmaSuballocationType allocType) const; - const_iterator operator++(int) - { - const_iterator result = *this; - ++*this; - return result; - } - const_iterator operator--(int) - { - const_iterator result = *this; - --*this; - return result; - } + void AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size); + void FreePages(VkDeviceSize offset, VkDeviceSize size); + void Clear(); - bool operator==(const const_iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem == rhs.m_pItem; - } - bool operator!=(const const_iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem != rhs.m_pItem; - } - - private: - const_iterator(const VmaRawList* pList, const VmaListItem* pItem) : - m_pList(pList), - m_pItem(pItem) - { - } + ValidationContext StartValidation(const VkAllocationCallbacks* pAllocationCallbacks, + bool isVirutal) const; + bool Validate(ValidationContext& ctx, VkDeviceSize offset, VkDeviceSize size) const; + bool FinishValidation(ValidationContext& ctx) const; - const VmaRawList* m_pList; - const VmaListItem* m_pItem; +private: + static const uint16_t MAX_LOW_BUFFER_IMAGE_GRANULARITY = 256; - friend class VmaList; + struct RegionInfo + { + uint8_t allocType; + uint16_t allocCount; }; - VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { } - - bool empty() const { return m_RawList.IsEmpty(); } - size_t size() const { return m_RawList.GetCount(); } - - iterator begin() { return iterator(&m_RawList, m_RawList.Front()); } - iterator end() { return iterator(&m_RawList, VMA_NULL); } - - const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); } - const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); } + VkDeviceSize m_BufferImageGranularity; + uint32_t m_RegionCount; + RegionInfo* m_RegionInfo; - void clear() { m_RawList.Clear(); } - void push_back(const T& value) { m_RawList.PushBack(value); } - void erase(iterator it) { m_RawList.Remove(it.m_pItem); } - iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); } + uint32_t GetStartPage(VkDeviceSize offset) const { return OffsetToPageIndex(offset & ~(m_BufferImageGranularity - 1)); } + uint32_t GetEndPage(VkDeviceSize offset, VkDeviceSize size) const { return OffsetToPageIndex((offset + size - 1) & ~(m_BufferImageGranularity - 1)); } -private: - VmaRawList m_RawList; + uint32_t OffsetToPageIndex(VkDeviceSize offset) const; + void AllocPage(RegionInfo& page, uint8_t allocType); }; -#endif // #if VMA_USE_STL_LIST - -//////////////////////////////////////////////////////////////////////////////// -// class VmaMap - -// Unused in this version. -#if 0 - -#if VMA_USE_STL_UNORDERED_MAP - -#define VmaPair std::pair +#ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY_FUNCTIONS +VmaBlockBufferImageGranularity::VmaBlockBufferImageGranularity(VkDeviceSize bufferImageGranularity) + : m_BufferImageGranularity(bufferImageGranularity), + m_RegionCount(0), + m_RegionInfo(VMA_NULL) {} -#define VMA_MAP_TYPE(KeyT, ValueT) \ - std::unordered_map< KeyT, ValueT, std::hash, std::equal_to, VmaStlAllocator< std::pair > > - -#else // #if VMA_USE_STL_UNORDERED_MAP - -template -struct VmaPair +VmaBlockBufferImageGranularity::~VmaBlockBufferImageGranularity() { - T1 first; - T2 second; - - VmaPair() : first(), second() { } - VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { } -}; + VMA_ASSERT(m_RegionInfo == VMA_NULL && "Free not called before destroying object!"); +} -/* Class compatible with subset of interface of std::unordered_map. -KeyT, ValueT must be POD because they will be stored in VmaVector. -*/ -template -class VmaMap +void VmaBlockBufferImageGranularity::Init(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize size) { -public: - typedef VmaPair PairType; - typedef PairType* iterator; - - VmaMap(const VmaStlAllocator& allocator) : m_Vector(allocator) { } - - iterator begin() { return m_Vector.begin(); } - iterator end() { return m_Vector.end(); } - - void insert(const PairType& pair); - iterator find(const KeyT& key); - void erase(iterator it); - -private: - VmaVector< PairType, VmaStlAllocator > m_Vector; -}; - -#define VMA_MAP_TYPE(KeyT, ValueT) VmaMap + if (IsEnabled()) + { + m_RegionCount = static_cast(VmaDivideRoundingUp(size, m_BufferImageGranularity)); + m_RegionInfo = vma_new_array(pAllocationCallbacks, RegionInfo, m_RegionCount); + memset(m_RegionInfo, 0, m_RegionCount * sizeof(RegionInfo)); + } +} -template -struct VmaPairFirstLess +void VmaBlockBufferImageGranularity::Destroy(const VkAllocationCallbacks* pAllocationCallbacks) { - bool operator()(const VmaPair& lhs, const VmaPair& rhs) const + if (m_RegionInfo) { - return lhs.first < rhs.first; + vma_delete_array(pAllocationCallbacks, m_RegionInfo, m_RegionCount); + m_RegionInfo = VMA_NULL; } - bool operator()(const VmaPair& lhs, const FirstT& rhsFirst) const +} + +void VmaBlockBufferImageGranularity::RoundupAllocRequest(VmaSuballocationType allocType, + VkDeviceSize& inOutAllocSize, + VkDeviceSize& inOutAllocAlignment) const +{ + if (m_BufferImageGranularity > 1 && + m_BufferImageGranularity <= MAX_LOW_BUFFER_IMAGE_GRANULARITY) { - return lhs.first < rhsFirst; + if (allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) + { + inOutAllocAlignment = VMA_MAX(inOutAllocAlignment, m_BufferImageGranularity); + inOutAllocSize = VmaAlignUp(inOutAllocSize, m_BufferImageGranularity); + } } -}; +} -template -void VmaMap::insert(const PairType& pair) +bool VmaBlockBufferImageGranularity::CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, + VkDeviceSize allocSize, + VkDeviceSize blockOffset, + VkDeviceSize blockSize, + VmaSuballocationType allocType) const { - const size_t indexToInsert = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - pair, - VmaPairFirstLess()) - m_Vector.data(); - VmaVectorInsert(m_Vector, indexToInsert, pair); + if (IsEnabled()) + { + uint32_t startPage = GetStartPage(inOutAllocOffset); + if (m_RegionInfo[startPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) + { + inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); + if (blockSize < allocSize + inOutAllocOffset - blockOffset) + return true; + ++startPage; + } + uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); + if (endPage != startPage && + m_RegionInfo[endPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) + { + return true; + } + } + return false; } -template -VmaPair* VmaMap::find(const KeyT& key) +void VmaBlockBufferImageGranularity::AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size) { - PairType* it = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - key, - VmaPairFirstLess()); - if((it != m_Vector.end()) && (it->first == key)) + if (IsEnabled()) { - return it; + uint32_t startPage = GetStartPage(offset); + AllocPage(m_RegionInfo[startPage], allocType); + + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + AllocPage(m_RegionInfo[endPage], allocType); } - else +} + +void VmaBlockBufferImageGranularity::FreePages(VkDeviceSize offset, VkDeviceSize size) +{ + if (IsEnabled()) { - return m_Vector.end(); + uint32_t startPage = GetStartPage(offset); + --m_RegionInfo[startPage].allocCount; + if (m_RegionInfo[startPage].allocCount == 0) + m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + { + --m_RegionInfo[endPage].allocCount; + if (m_RegionInfo[endPage].allocCount == 0) + m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + } } } -template -void VmaMap::erase(iterator it) +void VmaBlockBufferImageGranularity::Clear() { - VmaVectorRemove(m_Vector, it - m_Vector.begin()); + if (m_RegionInfo) + memset(m_RegionInfo, 0, m_RegionCount * sizeof(RegionInfo)); } -#endif // #if VMA_USE_STL_UNORDERED_MAP - -#endif // #if 0 - -//////////////////////////////////////////////////////////////////////////////// - -class VmaDeviceMemoryBlock; - -enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE }; - -struct VmaAllocation_T +VmaBlockBufferImageGranularity::ValidationContext VmaBlockBufferImageGranularity::StartValidation( + const VkAllocationCallbacks* pAllocationCallbacks, bool isVirutal) const { -private: - static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80; - - enum FLAGS + ValidationContext ctx{ pAllocationCallbacks, VMA_NULL }; + if (!isVirutal && IsEnabled()) { - FLAG_USER_DATA_STRING = 0x01, - }; + ctx.pageAllocs = vma_new_array(pAllocationCallbacks, uint16_t, m_RegionCount); + memset(ctx.pageAllocs, 0, m_RegionCount * sizeof(uint16_t)); + } + return ctx; +} -public: - enum ALLOCATION_TYPE +bool VmaBlockBufferImageGranularity::Validate(ValidationContext& ctx, + VkDeviceSize offset, VkDeviceSize size) const +{ + if (IsEnabled()) { - ALLOCATION_TYPE_NONE, - ALLOCATION_TYPE_BLOCK, - ALLOCATION_TYPE_DEDICATED, - }; - - /* - This struct is allocated using VmaPoolAllocator. - */ + uint32_t start = GetStartPage(offset); + ++ctx.pageAllocs[start]; + VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); - VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) : - m_Alignment{1}, - m_Size{0}, - m_pUserData{VMA_NULL}, - m_LastUseFrameIndex{currentFrameIndex}, - m_MemoryTypeIndex{0}, - m_Type{(uint8_t)ALLOCATION_TYPE_NONE}, - m_SuballocationType{(uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN}, - m_MapCount{0}, - m_Flags{userDataString ? (uint8_t)FLAG_USER_DATA_STRING : (uint8_t)0} - { -#if VMA_STATS_STRING_ENABLED - m_CreationFrameIndex = currentFrameIndex; - m_BufferImageUsage = 0; -#endif + uint32_t end = GetEndPage(offset, size); + if (start != end) + { + ++ctx.pageAllocs[end]; + VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); + } } + return true; +} - ~VmaAllocation_T() +bool VmaBlockBufferImageGranularity::FinishValidation(ValidationContext& ctx) const +{ + // Check proper page structure + if (IsEnabled()) { - VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction."); + VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); - // Check if owned string was freed. - VMA_ASSERT(m_pUserData == VMA_NULL); + for (uint32_t page = 0; page < m_RegionCount; ++page) + { + VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); + } + vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); + ctx.pageAllocs = VMA_NULL; } + return true; +} - void InitBlockAllocation( - VmaDeviceMemoryBlock* block, - VkDeviceSize offset, - VkDeviceSize alignment, - VkDeviceSize size, - uint32_t memoryTypeIndex, - VmaSuballocationType suballocationType, - bool mapped, - bool canBecomeLost) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(block != VMA_NULL); - m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; - m_Alignment = alignment; - m_Size = size; - m_MemoryTypeIndex = memoryTypeIndex; - m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; - m_SuballocationType = (uint8_t)suballocationType; - m_BlockAllocation.m_Block = block; - m_BlockAllocation.m_Offset = offset; - m_BlockAllocation.m_CanBecomeLost = canBecomeLost; - } - - void InitLost() - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST); - m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; - m_MemoryTypeIndex = 0; - m_BlockAllocation.m_Block = VMA_NULL; - m_BlockAllocation.m_Offset = 0; - m_BlockAllocation.m_CanBecomeLost = true; - } - - void ChangeBlockAllocation( - VmaAllocator hAllocator, - VmaDeviceMemoryBlock* block, - VkDeviceSize offset); +uint32_t VmaBlockBufferImageGranularity::OffsetToPageIndex(VkDeviceSize offset) const +{ + return static_cast(offset >> VMA_BITSCAN_MSB(m_BufferImageGranularity)); +} - void ChangeOffset(VkDeviceSize newOffset); +void VmaBlockBufferImageGranularity::AllocPage(RegionInfo& page, uint8_t allocType) +{ + // When current alloc type is free then it can be overridden by new type + if (page.allocCount == 0 || (page.allocCount > 0 && page.allocType == VMA_SUBALLOCATION_TYPE_FREE)) + page.allocType = allocType; - // pMappedData not null means allocation is created with MAPPED flag. - void InitDedicatedAllocation( - uint32_t memoryTypeIndex, - VkDeviceMemory hMemory, - VmaSuballocationType suballocationType, - void* pMappedData, - VkDeviceSize size) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(hMemory != VK_NULL_HANDLE); - m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED; - m_Alignment = 0; - m_Size = size; - m_MemoryTypeIndex = memoryTypeIndex; - m_SuballocationType = (uint8_t)suballocationType; - m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; - m_DedicatedAllocation.m_hMemory = hMemory; - m_DedicatedAllocation.m_pMappedData = pMappedData; - } + ++page.allocCount; +} +#endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY_FUNCTIONS +#endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY - ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; } - VkDeviceSize GetAlignment() const { return m_Alignment; } - VkDeviceSize GetSize() const { return m_Size; } - bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; } - void* GetUserData() const { return m_pUserData; } - void SetUserData(VmaAllocator hAllocator, void* pUserData); - VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; } +#if 0 +#ifndef _VMA_BLOCK_METADATA_GENERIC +class VmaBlockMetadata_Generic : public VmaBlockMetadata +{ + friend class VmaDefragmentationAlgorithm_Generic; + friend class VmaDefragmentationAlgorithm_Fast; + VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic) +public: + VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Generic() = default; - VmaDeviceMemoryBlock* GetBlock() const - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - return m_BlockAllocation.m_Block; - } - VkDeviceSize GetOffset() const; - VkDeviceMemory GetMemory() const; - uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } - bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; } - void* GetMappedData() const; - bool CanBecomeLost() const; - - uint32_t GetLastUseFrameIndex() const - { - return m_LastUseFrameIndex.load(); - } - bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired) - { - return m_LastUseFrameIndex.compare_exchange_weak(expected, desired); - } - /* - - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex, - makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true. - - Else, returns false. - - If hAllocation is already lost, assert - you should not call it then. - If hAllocation was not created with CAN_BECOME_LOST_BIT, assert. - */ - bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); + size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; } + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } + bool IsEmpty() const override { return (m_Suballocations.size() == 1) && (m_FreeCount == 1); } + void Free(VmaAllocHandle allocHandle) override { FreeSuballocation(FindAtOffset((VkDeviceSize)allocHandle - 1)); } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; } - void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED); - outInfo.blockCount = 1; - outInfo.allocationCount = 1; - outInfo.unusedRangeCount = 0; - outInfo.usedBytes = m_Size; - outInfo.unusedBytes = 0; - outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size; - outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMax = 0; - } + void Init(VkDeviceSize size) override; + bool Validate() const override; - void BlockAllocMap(); - void BlockAllocUnmap(); - VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData); - void DedicatedAllocUnmap(VmaAllocator hAllocator); + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; #if VMA_STATS_STRING_ENABLED - uint32_t GetCreationFrameIndex() const { return m_CreationFrameIndex; } - uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; } - - void InitBufferImageUsage(uint32_t bufferImageUsage) - { - VMA_ASSERT(m_BufferImageUsage == 0); - m_BufferImageUsage = bufferImageUsage; - } - - void PrintParameters(class VmaJsonWriter& json) const; + void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; #endif -private: - VkDeviceSize m_Alignment; - VkDeviceSize m_Size; - void* m_pUserData; - VMA_ATOMIC_UINT32 m_LastUseFrameIndex; - uint32_t m_MemoryTypeIndex; - uint8_t m_Type; // ALLOCATION_TYPE - uint8_t m_SuballocationType; // VmaSuballocationType - // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT. - // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory(). - uint8_t m_MapCount; - uint8_t m_Flags; // enum FLAGS - - // Allocation out of VmaDeviceMemoryBlock. - struct BlockAllocation - { - VmaDeviceMemoryBlock* m_Block; - VkDeviceSize m_Offset; - bool m_CanBecomeLost; - }; - - // Allocation for an object that has its own private VkDeviceMemory. - struct DedicatedAllocation - { - VkDeviceMemory m_hMemory; - void* m_pMappedData; // Not null means memory is mapped. - }; - - union - { - // Allocation out of VmaDeviceMemoryBlock. - BlockAllocation m_BlockAllocation; - // Allocation for an object that has its own private VkDeviceMemory. - DedicatedAllocation m_DedicatedAllocation; - }; - -#if VMA_STATS_STRING_ENABLED - uint32_t m_CreationFrameIndex; - uint32_t m_BufferImageUsage; // 0 if unknown. -#endif - - void FreeUserDataString(VmaAllocator hAllocator); -}; - -/* -Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as -allocated memory block or free. -*/ -struct VmaSuballocation -{ - VkDeviceSize offset; - VkDeviceSize size; - VmaAllocation hAllocation; - VmaSuballocationType type; -}; - -// Comparator for offsets. -struct VmaSuballocationOffsetLess -{ - bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const - { - return lhs.offset < rhs.offset; - } -}; -struct VmaSuballocationOffsetGreater -{ - bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const - { - return lhs.offset > rhs.offset; - } -}; - -typedef VmaList< VmaSuballocation, VmaStlAllocator > VmaSuballocationList; - -// Cost of one additional allocation lost, as equivalent in bytes. -static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576; - -enum class VmaAllocationRequestType -{ - Normal, - // Used by "Linear" algorithm. - UpperAddress, - EndOf1st, - EndOf2nd, -}; - -/* -Parameters of planned allocation inside a VmaDeviceMemoryBlock. - -If canMakeOtherLost was false: -- item points to a FREE suballocation. -- itemsToMakeLostCount is 0. - -If canMakeOtherLost was true: -- item points to first of sequence of suballocations, which are either FREE, - or point to VmaAllocations that can become lost. -- itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for - the requested allocation to succeed. -*/ -struct VmaAllocationRequest -{ - VkDeviceSize offset; - VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation. - VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation. - VmaSuballocationList::iterator item; - size_t itemsToMakeLostCount; - void* customData; - VmaAllocationRequestType type; - - VkDeviceSize CalcCost() const - { - return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST; - } -}; - -/* -Data structure used for bookkeeping of allocations and unused ranges of memory -in a single VkDeviceMemory block. -*/ -class VmaBlockMetadata -{ -public: - VmaBlockMetadata(VmaAllocator hAllocator); - virtual ~VmaBlockMetadata() { } - virtual void Init(VkDeviceSize size) { m_Size = size; } - - // Validates all data structures inside this object. If not valid, returns false. - virtual bool Validate() const = 0; - VkDeviceSize GetSize() const { return m_Size; } - virtual size_t GetAllocationCount() const = 0; - virtual VkDeviceSize GetSumFreeSize() const = 0; - virtual VkDeviceSize GetUnusedRangeSizeMax() const = 0; - // Returns true if this block is empty - contains only single free suballocation. - virtual bool IsEmpty() const = 0; - - virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0; - // Shouldn't modify blockCount. - virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0; - -#if VMA_STATS_STRING_ENABLED - virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0; -#endif - - // Tries to find a place for suballocation with given parameters inside this block. - // If succeeded, fills pAllocationRequest and returns true. - // If failed, returns false. - virtual bool CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags. - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) = 0; - - virtual bool MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest) = 0; - - virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) = 0; - - virtual VkResult CheckCorruption(const void* pBlockData) = 0; - - // Makes actual allocation based on request. Request must already be checked and valid. - virtual void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation) = 0; - - // Frees suballocation assigned to given memory region. - virtual void Free(const VmaAllocation allocation) = 0; - virtual void FreeAtOffset(VkDeviceSize offset) = 0; - -protected: - const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; } - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap_Begin(class VmaJsonWriter& json, - VkDeviceSize unusedBytes, - size_t allocationCount, - size_t unusedRangeCount) const; - void PrintDetailedMap_Allocation(class VmaJsonWriter& json, - VkDeviceSize offset, - VmaAllocation hAllocation) const; - void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, - VkDeviceSize offset, - VkDeviceSize size) const; - void PrintDetailedMap_End(class VmaJsonWriter& json) const; -#endif - -private: - VkDeviceSize m_Size; - const VkAllocationCallbacks* m_pAllocationCallbacks; -}; - -#define VMA_VALIDATE(cond) do { if(!(cond)) { \ - VMA_ASSERT(0 && "Validation failed: " #cond); \ - return false; \ - } } while(false) - -class VmaBlockMetadata_Generic : public VmaBlockMetadata -{ - VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic) -public: - VmaBlockMetadata_Generic(VmaAllocator hAllocator); - virtual ~VmaBlockMetadata_Generic(); - virtual void Init(VkDeviceSize size); - - virtual bool Validate() const; - virtual size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; } - virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; } - virtual VkDeviceSize GetUnusedRangeSizeMax() const; - virtual bool IsEmpty() const; - - virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const; - virtual void AddPoolStats(VmaPoolStats& inoutStats) const; - -#if VMA_STATS_STRING_ENABLED - virtual void PrintDetailedMap(class VmaJsonWriter& json) const; -#endif - - virtual bool CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, + bool CreateAllocationRequest( VkDeviceSize allocSize, VkDeviceSize allocAlignment, bool upperAddress, VmaSuballocationType allocType, - bool canMakeOtherLost, uint32_t strategy, - VmaAllocationRequest* pAllocationRequest); - - virtual bool MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest); + VmaAllocationRequest* pAllocationRequest) override; - virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); + VkResult CheckCorruption(const void* pBlockData) override; - virtual VkResult CheckCorruption(const void* pBlockData); - - virtual void Alloc( + void Alloc( const VmaAllocationRequest& request, VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation); - - virtual void Free(const VmaAllocation allocation); - virtual void FreeAtOffset(VkDeviceSize offset); + void* userData) override; - //////////////////////////////////////////////////////////////////////////////// - // For defragmentation - - bool IsBufferImageGranularityConflictPossible( - VkDeviceSize bufferImageGranularity, - VmaSuballocationType& inOutPrevSuballocType) const; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; private: - friend class VmaDefragmentationAlgorithm_Generic; - friend class VmaDefragmentationAlgorithm_Fast; - uint32_t m_FreeCount; VkDeviceSize m_SumFreeSize; VmaSuballocationList m_Suballocations; - // Suballocations that are free and have size greater than certain threshold. - // Sorted by size, ascending. - VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize; + // Suballocations that are free. Sorted by size, ascending. + VmaVector> m_FreeSuballocationsBySize; + VkDeviceSize AlignAllocationSize(VkDeviceSize size) const { return IsVirtual() ? size : VmaAlignUp(size, (VkDeviceSize)16); } + + VmaSuballocationList::iterator FindAtOffset(VkDeviceSize offset) const; bool ValidateFreeSuballocationList() const; // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. // If yes, fills pOffset and returns true. If no, returns false. bool CheckAllocation( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, VkDeviceSize allocSize, VkDeviceSize allocAlignment, VmaSuballocationType allocType, VmaSuballocationList::const_iterator suballocItem, - bool canMakeOtherLost, - VkDeviceSize* pOffset, - size_t* itemsToMakeLostCount, - VkDeviceSize* pSumFreeSize, - VkDeviceSize* pSumItemSize) const; + VmaAllocHandle* pAllocHandle) const; + // Given free suballocation, it merges it with following one, which must also be free. void MergeFreeWithNext(VmaSuballocationList::iterator item); // Releases given suballocation, making it free. @@ -6000,6018 +6824,5439 @@ class VmaBlockMetadata_Generic : public VmaBlockMetadata // Returns iterator to new free suballocation at this place. VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem); // Given free suballocation, it inserts it into sorted list of - // m_FreeSuballocationsBySize if it's suitable. + // m_FreeSuballocationsBySize if it is suitable. void RegisterFreeSuballocation(VmaSuballocationList::iterator item); // Given free suballocation, it removes it from sorted list of - // m_FreeSuballocationsBySize if it's suitable. + // m_FreeSuballocationsBySize if it is suitable. void UnregisterFreeSuballocation(VmaSuballocationList::iterator item); }; -/* -Allocations and their references in internal data structure look like this: +#ifndef _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS +VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_FreeCount(0), + m_SumFreeSize(0), + m_Suballocations(VmaStlAllocator(pAllocationCallbacks)), + m_FreeSuballocationsBySize(VmaStlAllocator(pAllocationCallbacks)) {} -if(m_2ndVectorMode == SECOND_VECTOR_EMPTY): +void VmaBlockMetadata_Generic::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); - 0 +-------+ - | | - | | - | | - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount] - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount + 1] - +-------+ - | ... | - +-------+ - | Alloc | 1st[1st.size() - 1] - +-------+ - | | - | | - | | -GetSize() +-------+ + m_FreeCount = 1; + m_SumFreeSize = size; -if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER): + VmaSuballocation suballoc = {}; + suballoc.offset = 0; + suballoc.size = size; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - 0 +-------+ - | Alloc | 2nd[0] - +-------+ - | Alloc | 2nd[1] - +-------+ - | ... | - +-------+ - | Alloc | 2nd[2nd.size() - 1] - +-------+ - | | - | | - | | - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount] - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount + 1] - +-------+ - | ... | - +-------+ - | Alloc | 1st[1st.size() - 1] - +-------+ - | | -GetSize() +-------+ + m_Suballocations.push_back(suballoc); + m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); +} -if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK): +bool VmaBlockMetadata_Generic::Validate() const +{ + VMA_VALIDATE(!m_Suballocations.empty()); - 0 +-------+ - | | - | | - | | - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount] - +-------+ - | Alloc | 1st[m_1stNullItemsBeginCount + 1] - +-------+ - | ... | - +-------+ - | Alloc | 1st[1st.size() - 1] - +-------+ - | | - | | - | | - +-------+ - | Alloc | 2nd[2nd.size() - 1] - +-------+ - | ... | - +-------+ - | Alloc | 2nd[1] - +-------+ - | Alloc | 2nd[0] -GetSize() +-------+ - -*/ -class VmaBlockMetadata_Linear : public VmaBlockMetadata -{ - VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear) -public: - VmaBlockMetadata_Linear(VmaAllocator hAllocator); - virtual ~VmaBlockMetadata_Linear(); - virtual void Init(VkDeviceSize size); - - virtual bool Validate() const; - virtual size_t GetAllocationCount() const; - virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; } - virtual VkDeviceSize GetUnusedRangeSizeMax() const; - virtual bool IsEmpty() const { return GetAllocationCount() == 0; } + // Expected offset of new suballocation as calculated from previous ones. + VkDeviceSize calculatedOffset = 0; + // Expected number of free suballocations as calculated from traversing their list. + uint32_t calculatedFreeCount = 0; + // Expected sum size of free suballocations as calculated from traversing their list. + VkDeviceSize calculatedSumFreeSize = 0; + // Expected number of free suballocations that should be registered in + // m_FreeSuballocationsBySize calculated from traversing their list. + size_t freeSuballocationsToRegister = 0; + // True if previous visited suballocation was free. + bool prevFree = false; - virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const; - virtual void AddPoolStats(VmaPoolStats& inoutStats) const; + const VkDeviceSize debugMargin = GetDebugMargin(); -#if VMA_STATS_STRING_ENABLED - virtual void PrintDetailedMap(class VmaJsonWriter& json) const; -#endif + for (const auto& subAlloc : m_Suballocations) + { + // Actual offset of this suballocation doesn't match expected one. + VMA_VALIDATE(subAlloc.offset == calculatedOffset); - virtual bool CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest); + const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE); + // Two adjacent free suballocations are invalid. They should be merged. + VMA_VALIDATE(!prevFree || !currFree); - virtual bool MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest); + VmaAllocation alloc = (VmaAllocation)subAlloc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } - virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); + if (currFree) + { + calculatedSumFreeSize += subAlloc.size; + ++calculatedFreeCount; + ++freeSuballocationsToRegister; - virtual VkResult CheckCorruption(const void* pBlockData); + // Margin required between allocations - every free space must be at least that large. + VMA_VALIDATE(subAlloc.size >= debugMargin); + } + else + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == subAlloc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == subAlloc.size); + } - virtual void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation); + // Margin required between allocations - previous allocation must be free. + VMA_VALIDATE(debugMargin == 0 || prevFree); + } - virtual void Free(const VmaAllocation allocation); - virtual void FreeAtOffset(VkDeviceSize offset); + calculatedOffset += subAlloc.size; + prevFree = currFree; + } -private: - /* - There are two suballocation vectors, used in ping-pong way. - The one with index m_1stVectorIndex is called 1st. - The one with index (m_1stVectorIndex ^ 1) is called 2nd. - 2nd can be non-empty only when 1st is not empty. - When 2nd is not empty, m_2ndVectorMode indicates its mode of operation. - */ - typedef VmaVector< VmaSuballocation, VmaStlAllocator > SuballocationVectorType; + // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't + // match expected one. + VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister); - enum SECOND_VECTOR_MODE + VkDeviceSize lastSize = 0; + for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) { - SECOND_VECTOR_EMPTY, - /* - Suballocations in 2nd vector are created later than the ones in 1st, but they - all have smaller offset. - */ - SECOND_VECTOR_RING_BUFFER, - /* - Suballocations in 2nd vector are upper side of double stack. - They all have offsets higher than those in 1st vector. - Top of this stack means smaller offsets, but higher indices in this vector. - */ - SECOND_VECTOR_DOUBLE_STACK, - }; - - VkDeviceSize m_SumFreeSize; - SuballocationVectorType m_Suballocations0, m_Suballocations1; - uint32_t m_1stVectorIndex; - SECOND_VECTOR_MODE m_2ndVectorMode; + VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; - SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } - SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } - const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } - const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } - - // Number of items in 1st vector with hAllocation = null at the beginning. - size_t m_1stNullItemsBeginCount; - // Number of other items in 1st vector with hAllocation = null somewhere in the middle. - size_t m_1stNullItemsMiddleCount; - // Number of items in 2nd vector with hAllocation = null. - size_t m_2ndNullItemsCount; + // Only free suballocations can be registered in m_FreeSuballocationsBySize. + VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE); + // They must be sorted by size ascending. + VMA_VALIDATE(suballocItem->size >= lastSize); - bool ShouldCompact1st() const; - void CleanupAfterFree(); + lastSize = suballocItem->size; + } - bool CreateAllocationRequest_LowerAddress( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest); - bool CreateAllocationRequest_UpperAddress( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest); -}; + // Check if totals match calculated values. + VMA_VALIDATE(ValidateFreeSuballocationList()); + VMA_VALIDATE(calculatedOffset == GetSize()); + VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize); + VMA_VALIDATE(calculatedFreeCount == m_FreeCount); -/* -- GetSize() is the original size of allocated memory block. -- m_UsableSize is this size aligned down to a power of two. - All allocations and calculations happen relative to m_UsableSize. -- GetUnusableSize() is the difference between them. - It is repoted as separate, unused range, not available for allocations. + return true; +} -Node at level 0 has size = m_UsableSize. -Each next level contains nodes with size 2 times smaller than current level. -m_LevelCount is the maximum number of levels to use in the current object. -*/ -class VmaBlockMetadata_Buddy : public VmaBlockMetadata +void VmaBlockMetadata_Generic::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const { - VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy) -public: - VmaBlockMetadata_Buddy(VmaAllocator hAllocator); - virtual ~VmaBlockMetadata_Buddy(); - virtual void Init(VkDeviceSize size); + const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); - virtual bool Validate() const; - virtual size_t GetAllocationCount() const { return m_AllocationCount; } - virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize + GetUnusableSize(); } - virtual VkDeviceSize GetUnusedRangeSizeMax() const; - virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; } + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); + else + VmaAddDetailedStatisticsUnusedRange(inoutStats, suballoc.size); + } +} - virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const; - virtual void AddPoolStats(VmaPoolStats& inoutStats) const; +void VmaBlockMetadata_Generic::AddStatistics(VmaStatistics& inoutStats) const +{ + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_Suballocations.size() - m_FreeCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - m_SumFreeSize; +} #if VMA_STATS_STRING_ENABLED - virtual void PrintDetailedMap(class VmaJsonWriter& json) const; -#endif - - virtual bool CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest); +void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const +{ + PrintDetailedMap_Begin(json, + m_SumFreeSize, // unusedBytes + m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount + m_FreeCount, // unusedRangeCount + mapRefCount); - virtual bool MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest); + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE) + { + PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size); + } + else + { + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + } + } - virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); + PrintDetailedMap_End(json); +} +#endif // VMA_STATS_STRING_ENABLED - virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; } +bool VmaBlockMetadata_Generic::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(!upperAddress); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(pAllocationRequest != VMA_NULL); + VMA_HEAVY_ASSERT(Validate()); - virtual void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation); + allocSize = AlignAllocationSize(allocSize); - virtual void Free(const VmaAllocation allocation) { FreeAtOffset(allocation, allocation->GetOffset()); } - virtual void FreeAtOffset(VkDeviceSize offset) { FreeAtOffset(VMA_NULL, offset); } + pAllocationRequest->type = VmaAllocationRequestType::Normal; + pAllocationRequest->size = allocSize; -private: - static const VkDeviceSize MIN_NODE_SIZE = 32; - static const size_t MAX_LEVELS = 30; + const VkDeviceSize debugMargin = GetDebugMargin(); - struct ValidationContext + // There is not enough total free space in this block to fulfill the request: Early return. + if (m_SumFreeSize < allocSize + debugMargin) { - size_t calculatedAllocationCount; - size_t calculatedFreeCount; - VkDeviceSize calculatedSumFreeSize; - - ValidationContext() : - calculatedAllocationCount(0), - calculatedFreeCount(0), - calculatedSumFreeSize(0) { } - }; + return false; + } - struct Node + // New algorithm, efficiently searching freeSuballocationsBySize. + const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); + if (freeSuballocCount > 0) { - VkDeviceSize offset; - enum TYPE - { - TYPE_FREE, - TYPE_ALLOCATION, - TYPE_SPLIT, - TYPE_COUNT - } type; - Node* parent; - Node* buddy; - - union + if (strategy == 0 || + strategy == VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT) { - struct - { - Node* prev; - Node* next; - } free; - struct + // Find first free suballocation with size not less than allocSize + debugMargin. + VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( + m_FreeSuballocationsBySize.data(), + m_FreeSuballocationsBySize.data() + freeSuballocCount, + allocSize + debugMargin, + VmaSuballocationItemSizeLess()); + size_t index = it - m_FreeSuballocationsBySize.data(); + for (; index < freeSuballocCount; ++index) { - VmaAllocation alloc; - } allocation; - struct + if (CheckAllocation( + allocSize, + allocAlignment, + allocType, + m_FreeSuballocationsBySize[index], + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = m_FreeSuballocationsBySize[index]; + return true; + } + } + } + else if (strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET) + { + for (VmaSuballocationList::iterator it = m_Suballocations.begin(); + it != m_Suballocations.end(); + ++it) { - Node* leftChild; - } split; - }; - }; - - // Size of the memory block aligned down to a power of two. - VkDeviceSize m_UsableSize; - uint32_t m_LevelCount; - - Node* m_Root; - struct { - Node* front; - Node* back; - } m_FreeList[MAX_LEVELS]; - // Number of nodes in the tree with type == TYPE_ALLOCATION. - size_t m_AllocationCount; - // Number of nodes in the tree with type == TYPE_FREE. - size_t m_FreeCount; - // This includes space wasted due to internal fragmentation. Doesn't include unusable size. - VkDeviceSize m_SumFreeSize; - - VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; } - void DeleteNode(Node* node); - bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const; - uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const; - inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; } - // Alloc passed just for validation. Can be null. - void FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset); - void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const; - // Adds node to the front of FreeList at given level. - // node->type must be FREE. - // node->free.prev, next can be undefined. - void AddToFreeListFront(uint32_t level, Node* node); - // Removes node from FreeList at given level. - // node->type must be FREE. - // node->free.prev, next stay untouched. - void RemoveFromFreeList(uint32_t level, Node* node); - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const; -#endif -}; + if (it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation( + allocSize, + allocAlignment, + allocType, + it, + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = it; + return true; + } + } + } + else + { + VMA_ASSERT(strategy & (VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT )); + // Search staring from biggest suballocations. + for (size_t index = freeSuballocCount; index--; ) + { + if (CheckAllocation( + allocSize, + allocAlignment, + allocType, + m_FreeSuballocationsBySize[index], + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = m_FreeSuballocationsBySize[index]; + return true; + } + } + } + } -/* -Represents a single block of device memory (`VkDeviceMemory`) with all the -data about its regions (aka suballocations, #VmaAllocation), assigned and free. + return false; +} -Thread-safety: This class must be externally synchronized. -*/ -class VmaDeviceMemoryBlock +VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData) { - VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock) -public: - VmaBlockMetadata* m_pMetadata; - - VmaDeviceMemoryBlock(VmaAllocator hAllocator); - - ~VmaDeviceMemoryBlock() + for (auto& suballoc : m_Suballocations) { - VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); - VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } } - // Always call after construction. - void Init( - VmaAllocator hAllocator, - VmaPool hParentPool, - uint32_t newMemoryTypeIndex, - VkDeviceMemory newMemory, - VkDeviceSize newSize, - uint32_t id, - uint32_t algorithm); - // Always call before destruction. - void Destroy(VmaAllocator allocator); - - VmaPool GetParentPool() const { return m_hParentPool; } - VkDeviceMemory GetDeviceMemory() const { return m_hMemory; } - uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } - uint32_t GetId() const { return m_Id; } - void* GetMappedData() const { return m_pMappedData; } - - // Validates all data structures inside this object. If not valid, returns false. - bool Validate() const; + return VK_SUCCESS; +} - VkResult CheckCorruption(VmaAllocator hAllocator); +void VmaBlockMetadata_Generic::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) +{ + VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); + VMA_ASSERT(request.item != m_Suballocations.end()); + VmaSuballocation& suballoc = *request.item; + // Given suballocation is a free block. + VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - // ppData can be null. - VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData); - void Unmap(VmaAllocator hAllocator, uint32_t count); + // Given offset is inside this suballocation. + VMA_ASSERT((VkDeviceSize)request.allocHandle - 1 >= suballoc.offset); + const VkDeviceSize paddingBegin = (VkDeviceSize)request.allocHandle - suballoc.offset - 1; + VMA_ASSERT(suballoc.size >= paddingBegin + request.size); + const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - request.size; - VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); - VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); + // Unregister this free suballocation from m_FreeSuballocationsBySize and update + // it to become used. + UnregisterFreeSuballocation(request.item); - VkResult BindBufferMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkBuffer hBuffer, - const void* pNext); - VkResult BindImageMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkImage hImage, - const void* pNext); + suballoc.offset = (VkDeviceSize)request.allocHandle - 1; + suballoc.size = request.size; + suballoc.type = type; + suballoc.userData = userData; -private: - VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. - uint32_t m_MemoryTypeIndex; - uint32_t m_Id; - VkDeviceMemory m_hMemory; + // If there are any free bytes remaining at the end, insert new free suballocation after current one. + if (paddingEnd) + { + VmaSuballocation paddingSuballoc = {}; + paddingSuballoc.offset = suballoc.offset + suballoc.size; + paddingSuballoc.size = paddingEnd; + paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + VmaSuballocationList::iterator next = request.item; + ++next; + const VmaSuballocationList::iterator paddingEndItem = + m_Suballocations.insert(next, paddingSuballoc); + RegisterFreeSuballocation(paddingEndItem); + } - /* - Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. - Also protects m_MapCount, m_pMappedData. - Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. - */ - VMA_MUTEX m_Mutex; - uint32_t m_MapCount; - void* m_pMappedData; -}; + // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. + if (paddingBegin) + { + VmaSuballocation paddingSuballoc = {}; + paddingSuballoc.offset = suballoc.offset - paddingBegin; + paddingSuballoc.size = paddingBegin; + paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + const VmaSuballocationList::iterator paddingBeginItem = + m_Suballocations.insert(request.item, paddingSuballoc); + RegisterFreeSuballocation(paddingBeginItem); + } -struct VmaPointerLess -{ - bool operator()(const void* lhs, const void* rhs) const + // Update totals. + m_FreeCount = m_FreeCount - 1; + if (paddingBegin > 0) { - return lhs < rhs; + ++m_FreeCount; } -}; + if (paddingEnd > 0) + { + ++m_FreeCount; + } + m_SumFreeSize -= request.size; +} -struct VmaDefragmentationMove +void VmaBlockMetadata_Generic::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) { - size_t srcBlockIndex; - size_t dstBlockIndex; - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; - VmaAllocation hAllocation; - VmaDeviceMemoryBlock* pSrcBlock; - VmaDeviceMemoryBlock* pDstBlock; -}; - -class VmaDefragmentationAlgorithm; - -/* -Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific -Vulkan memory type. + outInfo.offset = (VkDeviceSize)allocHandle - 1; + const VmaSuballocation& suballoc = *FindAtOffset(outInfo.offset); + outInfo.size = suballoc.size; + outInfo.pUserData = suballoc.userData; +} -Synchronized internally with a mutex. -*/ -struct VmaBlockVector +void* VmaBlockMetadata_Generic::GetAllocationUserData(VmaAllocHandle allocHandle) const { - VMA_CLASS_NO_COPY(VmaBlockVector) -public: - VmaBlockVector( - VmaAllocator hAllocator, - VmaPool hParentPool, - uint32_t memoryTypeIndex, - VkDeviceSize preferredBlockSize, - size_t minBlockCount, - size_t maxBlockCount, - VkDeviceSize bufferImageGranularity, - uint32_t frameInUseCount, - bool explicitBlockSize, - uint32_t algorithm); - ~VmaBlockVector(); + return FindAtOffset((VkDeviceSize)allocHandle - 1)->userData; +} - VkResult CreateMinBlocks(); +VmaAllocHandle VmaBlockMetadata_Generic::GetAllocationListBegin() const +{ + if (IsEmpty()) + return VK_NULL_HANDLE; - VmaAllocator GetAllocator() const { return m_hAllocator; } - VmaPool GetParentPool() const { return m_hParentPool; } - bool IsCustomPool() const { return m_hParentPool != VMA_NULL; } - uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } - VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; } - VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } - uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; } - uint32_t GetAlgorithm() const { return m_Algorithm; } + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + return (VmaAllocHandle)(suballoc.offset + 1); + } + VMA_ASSERT(false && "Should contain at least 1 allocation!"); + return VK_NULL_HANDLE; +} - void GetPoolStats(VmaPoolStats* pStats); +VmaAllocHandle VmaBlockMetadata_Generic::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + VmaSuballocationList::const_iterator prev = FindAtOffset((VkDeviceSize)prevAlloc - 1); - bool IsEmpty(); - bool IsCorruptionDetectionEnabled() const; + for (VmaSuballocationList::const_iterator it = ++prev; it != m_Suballocations.end(); ++it) + { + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + return (VmaAllocHandle)(it->offset + 1); + } + return VK_NULL_HANDLE; +} - VkResult Allocate( - uint32_t currentFrameIndex, - VkDeviceSize size, - VkDeviceSize alignment, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - size_t allocationCount, - VmaAllocation* pAllocations); +void VmaBlockMetadata_Generic::Clear() +{ + const VkDeviceSize size = GetSize(); - void Free(const VmaAllocation hAllocation); + VMA_ASSERT(IsVirtual()); + m_FreeCount = 1; + m_SumFreeSize = size; + m_Suballocations.clear(); + m_FreeSuballocationsBySize.clear(); - // Adds statistics of this BlockVector to pStats. - void AddStats(VmaStats* pStats); + VmaSuballocation suballoc = {}; + suballoc.offset = 0; + suballoc.size = size; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + m_Suballocations.push_back(suballoc); -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json); -#endif + m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); +} - void MakePoolAllocationsLost( - uint32_t currentFrameIndex, - size_t* pLostAllocationCount); - VkResult CheckCorruption(); +void VmaBlockMetadata_Generic::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + VmaSuballocation& suballoc = *FindAtOffset((VkDeviceSize)allocHandle - 1); + suballoc.userData = userData; +} - // Saves results in pCtx->res. - void Defragment( - class VmaBlockVectorDefragmentationContext* pCtx, - VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags, - VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove, - VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove, - VkCommandBuffer commandBuffer); - void DefragmentationEnd( - class VmaBlockVectorDefragmentationContext* pCtx, - VmaDefragmentationStats* pStats); - - uint32_t ProcessDefragmentations( - class VmaBlockVectorDefragmentationContext *pCtx, - VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves); - - void CommitDefragmentations( - class VmaBlockVectorDefragmentationContext *pCtx, - VmaDefragmentationStats* pStats); - - //////////////////////////////////////////////////////////////////////////////// - // To be used only while the m_Mutex is locked. Used during defragmentation. +void VmaBlockMetadata_Generic::DebugLogAllAllocations() const +{ + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(suballoc.offset, suballoc.size, suballoc.userData); + } +} - size_t GetBlockCount() const { return m_Blocks.size(); } - VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; } - size_t CalcAllocationCount() const; - bool IsBufferImageGranularityConflictPossible() const; +VmaSuballocationList::iterator VmaBlockMetadata_Generic::FindAtOffset(VkDeviceSize offset) const +{ + VMA_HEAVY_ASSERT(!m_Suballocations.empty()); + const VkDeviceSize last = m_Suballocations.rbegin()->offset; + if (last == offset) + return m_Suballocations.rbegin().drop_const(); + const VkDeviceSize first = m_Suballocations.begin()->offset; + if (first == offset) + return m_Suballocations.begin().drop_const(); -private: - friend class VmaDefragmentationAlgorithm_Generic; + const size_t suballocCount = m_Suballocations.size(); + const VkDeviceSize step = (last - first + m_Suballocations.begin()->size) / suballocCount; + auto findSuballocation = [&](auto begin, auto end) -> VmaSuballocationList::iterator + { + for (auto suballocItem = begin; + suballocItem != end; + ++suballocItem) + { + if (suballocItem->offset == offset) + return suballocItem.drop_const(); + } + VMA_ASSERT(false && "Not found!"); + return m_Suballocations.end().drop_const(); + }; + // If requested offset is closer to the end of range, search from the end + if (offset - first > suballocCount * step / 2) + { + return findSuballocation(m_Suballocations.rbegin(), m_Suballocations.rend()); + } + return findSuballocation(m_Suballocations.begin(), m_Suballocations.end()); +} - const VmaAllocator m_hAllocator; - const VmaPool m_hParentPool; - const uint32_t m_MemoryTypeIndex; - const VkDeviceSize m_PreferredBlockSize; - const size_t m_MinBlockCount; - const size_t m_MaxBlockCount; - const VkDeviceSize m_BufferImageGranularity; - const uint32_t m_FrameInUseCount; - const bool m_ExplicitBlockSize; - const uint32_t m_Algorithm; - VMA_RW_MUTEX m_Mutex; - - /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) - - a hysteresis to avoid pessimistic case of alternating creation and destruction of a VkDeviceMemory. */ - bool m_HasEmptyBlock; - // Incrementally sorted by sumFreeSize, ascending. - VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator > m_Blocks; - uint32_t m_NextBlockId; - - VkDeviceSize CalcMaxBlockSize() const; - - // Finds and removes given block from vector. - void Remove(VmaDeviceMemoryBlock* pBlock); - - // Performs single step in sorting m_Blocks. They may not be fully sorted - // after this call. - void IncrementallySortBlocks(); - - VkResult AllocatePage( - uint32_t currentFrameIndex, - VkDeviceSize size, - VkDeviceSize alignment, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation); - - // To be used only without CAN_MAKE_OTHER_LOST flag. - VkResult AllocateFromBlock( - VmaDeviceMemoryBlock* pBlock, - uint32_t currentFrameIndex, - VkDeviceSize size, - VkDeviceSize alignment, - VmaAllocationCreateFlags allocFlags, - void* pUserData, - VmaSuballocationType suballocType, - uint32_t strategy, - VmaAllocation* pAllocation); - - VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex); - - // Saves result to pCtx->res. - void ApplyDefragmentationMovesCpu( - class VmaBlockVectorDefragmentationContext* pDefragCtx, - const VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves); - // Saves result to pCtx->res. - void ApplyDefragmentationMovesGpu( - class VmaBlockVectorDefragmentationContext* pDefragCtx, - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkCommandBuffer commandBuffer); - - /* - Used during defragmentation. pDefragmentationStats is optional. It's in/out - - updated with new data. - */ - void FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats); - - void UpdateHasEmptyBlock(); -}; - -struct VmaPool_T +bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const { - VMA_CLASS_NO_COPY(VmaPool_T) -public: - VmaBlockVector m_BlockVector; - - VmaPool_T( - VmaAllocator hAllocator, - const VmaPoolCreateInfo& createInfo, - VkDeviceSize preferredBlockSize); - ~VmaPool_T(); - - uint32_t GetId() const { return m_Id; } - void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; } + VkDeviceSize lastSize = 0; + for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) + { + const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i]; - const char* GetName() const { return m_Name; } - void SetName(const char* pName); + VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_VALIDATE(it->size >= lastSize); + lastSize = it->size; + } + return true; +} -#if VMA_STATS_STRING_ENABLED - //void PrintDetailedMap(class VmaStringBuilder& sb); -#endif +bool VmaBlockMetadata_Generic::CheckAllocation( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaSuballocationList::const_iterator suballocItem, + VmaAllocHandle* pAllocHandle) const +{ + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(suballocItem != m_Suballocations.cend()); + VMA_ASSERT(pAllocHandle != VMA_NULL); -private: - uint32_t m_Id; - char* m_Name; -}; + const VkDeviceSize debugMargin = GetDebugMargin(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); -/* -Performs defragmentation: + const VmaSuballocation& suballoc = *suballocItem; + VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); -- Updates `pBlockVector->m_pMetadata`. -- Updates allocations by calling ChangeBlockAllocation() or ChangeOffset(). -- Does not move actual data, only returns requested moves as `moves`. -*/ -class VmaDefragmentationAlgorithm -{ - VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm) -public: - VmaDefragmentationAlgorithm( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex) : - m_hAllocator(hAllocator), - m_pBlockVector(pBlockVector), - m_CurrentFrameIndex(currentFrameIndex) - { - } - virtual ~VmaDefragmentationAlgorithm() + // Size of this suballocation is too small for this request: Early return. + if (suballoc.size < allocSize) { + return false; } - virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) = 0; - virtual void AddAll() = 0; + // Start from offset equal to beginning of this suballocation. + VkDeviceSize offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin()); - virtual VkResult Defragment( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - VmaDefragmentationFlags flags) = 0; - - virtual VkDeviceSize GetBytesMoved() const = 0; - virtual uint32_t GetAllocationsMoved() const = 0; + // Apply debugMargin from the end of previous alloc. + if (debugMargin > 0) + { + offset += debugMargin; + } -protected: - VmaAllocator const m_hAllocator; - VmaBlockVector* const m_pBlockVector; - const uint32_t m_CurrentFrameIndex; + // Apply alignment. + offset = VmaAlignUp(offset, allocAlignment); - struct AllocationInfo + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment) { - VmaAllocation m_hAllocation; - VkBool32* m_pChanged; - - AllocationInfo() : - m_hAllocation(VK_NULL_HANDLE), - m_pChanged(VMA_NULL) + bool bufferImageGranularityConflict = false; + VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; + while (prevSuballocItem != m_Suballocations.cbegin()) { + --prevSuballocItem; + const VmaSuballocation& prevSuballoc = *prevSuballocItem; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; } - AllocationInfo(VmaAllocation hAlloc, VkBool32* pChanged) : - m_hAllocation(hAlloc), - m_pChanged(pChanged) + if (bufferImageGranularityConflict) { + offset = VmaAlignUp(offset, bufferImageGranularity); } - }; -}; - -class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm -{ - VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Generic) -public: - VmaDefragmentationAlgorithm_Generic( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex, - bool overlappingMoveSupported); - virtual ~VmaDefragmentationAlgorithm_Generic(); - - virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged); - virtual void AddAll() { m_AllAllocations = true; } - - virtual VkResult Defragment( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - VmaDefragmentationFlags flags); - - virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; } - virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; } - -private: - uint32_t m_AllocationCount; - bool m_AllAllocations; + } - VkDeviceSize m_BytesMoved; - uint32_t m_AllocationsMoved; + // Calculate padding at the beginning based on current offset. + const VkDeviceSize paddingBegin = offset - suballoc.offset; - struct AllocationInfoSizeGreater + // Fail if requested size plus margin after is bigger than size of this suballocation. + if (paddingBegin + allocSize + debugMargin > suballoc.size) { - bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const - { - return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize(); - } - }; + return false; + } - struct AllocationInfoOffsetGreater + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (allocSize % bufferImageGranularity || offset % bufferImageGranularity) { - bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const + VmaSuballocationList::const_iterator nextSuballocItem = suballocItem; + ++nextSuballocItem; + while (nextSuballocItem != m_Suballocations.cend()) { - return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset(); + const VmaSuballocation& nextSuballoc = *nextSuballocItem; + if (VmaBlocksOnSamePage(offset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + ++nextSuballocItem; } - }; + } - struct BlockInfo - { - size_t m_OriginalBlockIndex; - VmaDeviceMemoryBlock* m_pBlock; - bool m_HasNonMovableAllocations; - VmaVector< AllocationInfo, VmaStlAllocator > m_Allocations; + *pAllocHandle = (VmaAllocHandle)(offset + 1); + // All tests passed: Success. pAllocHandle is already filled. + return true; +} - BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) : - m_OriginalBlockIndex(SIZE_MAX), - m_pBlock(VMA_NULL), - m_HasNonMovableAllocations(true), - m_Allocations(pAllocationCallbacks) - { - } +void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item) +{ + VMA_ASSERT(item != m_Suballocations.end()); + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - void CalcHasNonMovableAllocations() - { - const size_t blockAllocCount = m_pBlock->m_pMetadata->GetAllocationCount(); - const size_t defragmentAllocCount = m_Allocations.size(); - m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount; - } + VmaSuballocationList::iterator nextItem = item; + ++nextItem; + VMA_ASSERT(nextItem != m_Suballocations.end()); + VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE); - void SortAllocationsBySizeDescending() - { - VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater()); - } + item->size += nextItem->size; + --m_FreeCount; + m_Suballocations.erase(nextItem); +} - void SortAllocationsByOffsetDescending() - { - VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater()); - } - }; +VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem) +{ + // Change this suballocation to be marked as free. + VmaSuballocation& suballoc = *suballocItem; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + suballoc.userData = VMA_NULL; + + // Update totals. + ++m_FreeCount; + m_SumFreeSize += suballoc.size; + + // Merge with previous and/or next suballocation if it's also free. + bool mergeWithNext = false; + bool mergeWithPrev = false; - struct BlockPointerLess + VmaSuballocationList::iterator nextItem = suballocItem; + ++nextItem; + if ((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)) { - bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const - { - return pLhsBlockInfo->m_pBlock < pRhsBlock; - } - bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const - { - return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock; - } - }; + mergeWithNext = true; + } - // 1. Blocks with some non-movable allocations go first. - // 2. Blocks with smaller sumFreeSize go first. - struct BlockInfoCompareMoveDestination + VmaSuballocationList::iterator prevItem = suballocItem; + if (suballocItem != m_Suballocations.begin()) { - bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const + --prevItem; + if (prevItem->type == VMA_SUBALLOCATION_TYPE_FREE) { - if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations) - { - return true; - } - if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations) - { - return false; - } - if(pLhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize()) - { - return true; - } - return false; + mergeWithPrev = true; } - }; - - typedef VmaVector< BlockInfo*, VmaStlAllocator > BlockInfoVector; - BlockInfoVector m_Blocks; - - VkResult DefragmentRound( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - bool freeOldAllocations); + } - size_t CalcBlocksWithNonMovableCount() const; + if (mergeWithNext) + { + UnregisterFreeSuballocation(nextItem); + MergeFreeWithNext(suballocItem); + } - static bool MoveMakesSense( - size_t dstBlockIndex, VkDeviceSize dstOffset, - size_t srcBlockIndex, VkDeviceSize srcOffset); -}; + if (mergeWithPrev) + { + UnregisterFreeSuballocation(prevItem); + MergeFreeWithNext(prevItem); + RegisterFreeSuballocation(prevItem); + return prevItem; + } + else + { + RegisterFreeSuballocation(suballocItem); + return suballocItem; + } +} -class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm +void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item) { - VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Fast) -public: - VmaDefragmentationAlgorithm_Fast( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex, - bool overlappingMoveSupported); - virtual ~VmaDefragmentationAlgorithm_Fast(); + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(item->size > 0); - virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; } - virtual void AddAll() { m_AllAllocations = true; } + // You may want to enable this validation at the beginning or at the end of + // this function, depending on what do you want to check. + VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - virtual VkResult Defragment( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - VmaDefragmentationFlags flags); + if (m_FreeSuballocationsBySize.empty()) + { + m_FreeSuballocationsBySize.push_back(item); + } + else + { + VmaVectorInsertSorted(m_FreeSuballocationsBySize, item); + } - virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; } - virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; } + //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); +} -private: - struct BlockInfo - { - size_t origBlockIndex; - }; +void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item) +{ + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(item->size > 0); + + // You may want to enable this validation at the beginning or at the end of + // this function, depending on what do you want to check. + VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - class FreeSpaceDatabase + VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( + m_FreeSuballocationsBySize.data(), + m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), + item, + VmaSuballocationItemSizeLess()); + for (size_t index = it - m_FreeSuballocationsBySize.data(); + index < m_FreeSuballocationsBySize.size(); + ++index) { - public: - FreeSpaceDatabase() + if (m_FreeSuballocationsBySize[index] == item) { - FreeSpace s = {}; - s.blockInfoIndex = SIZE_MAX; - for(size_t i = 0; i < MAX_COUNT; ++i) - { - m_FreeSpaces[i] = s; - } + VmaVectorRemove(m_FreeSuballocationsBySize, index); + return; } + VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); + } + VMA_ASSERT(0 && "Not found."); - void Register(size_t blockInfoIndex, VkDeviceSize offset, VkDeviceSize size) - { - if(size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - return; - } - - // Find first invalid or the smallest structure. - size_t bestIndex = SIZE_MAX; - for(size_t i = 0; i < MAX_COUNT; ++i) - { - // Empty structure. - if(m_FreeSpaces[i].blockInfoIndex == SIZE_MAX) - { - bestIndex = i; - break; - } - if(m_FreeSpaces[i].size < size && - (bestIndex == SIZE_MAX || m_FreeSpaces[bestIndex].size > m_FreeSpaces[i].size)) - { - bestIndex = i; - } - } - - if(bestIndex != SIZE_MAX) - { - m_FreeSpaces[bestIndex].blockInfoIndex = blockInfoIndex; - m_FreeSpaces[bestIndex].offset = offset; - m_FreeSpaces[bestIndex].size = size; - } - } - - bool Fetch(VkDeviceSize alignment, VkDeviceSize size, - size_t& outBlockInfoIndex, VkDeviceSize& outDstOffset) - { - size_t bestIndex = SIZE_MAX; - VkDeviceSize bestFreeSpaceAfter = 0; - for(size_t i = 0; i < MAX_COUNT; ++i) - { - // Structure is valid. - if(m_FreeSpaces[i].blockInfoIndex != SIZE_MAX) - { - const VkDeviceSize dstOffset = VmaAlignUp(m_FreeSpaces[i].offset, alignment); - // Allocation fits into this structure. - if(dstOffset + size <= m_FreeSpaces[i].offset + m_FreeSpaces[i].size) - { - const VkDeviceSize freeSpaceAfter = (m_FreeSpaces[i].offset + m_FreeSpaces[i].size) - - (dstOffset + size); - if(bestIndex == SIZE_MAX || freeSpaceAfter > bestFreeSpaceAfter) - { - bestIndex = i; - bestFreeSpaceAfter = freeSpaceAfter; - } - } - } - } - - if(bestIndex != SIZE_MAX) - { - outBlockInfoIndex = m_FreeSpaces[bestIndex].blockInfoIndex; - outDstOffset = VmaAlignUp(m_FreeSpaces[bestIndex].offset, alignment); + //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); +} +#endif // _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_GENERIC +#endif // #if 0 - if(bestFreeSpaceAfter >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - // Leave this structure for remaining empty space. - const VkDeviceSize alignmentPlusSize = (outDstOffset - m_FreeSpaces[bestIndex].offset) + size; - m_FreeSpaces[bestIndex].offset += alignmentPlusSize; - m_FreeSpaces[bestIndex].size -= alignmentPlusSize; - } - else - { - // This structure becomes invalid. - m_FreeSpaces[bestIndex].blockInfoIndex = SIZE_MAX; - } +#ifndef _VMA_BLOCK_METADATA_LINEAR +/* +Allocations and their references in internal data structure look like this: - return true; - } +if(m_2ndVectorMode == SECOND_VECTOR_EMPTY): - return false; - } + 0 +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | + | | + | | +GetSize() +-------+ - private: - static const size_t MAX_COUNT = 4; +if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER): - struct FreeSpace - { - size_t blockInfoIndex; // SIZE_MAX means this structure is invalid. - VkDeviceSize offset; - VkDeviceSize size; - } m_FreeSpaces[MAX_COUNT]; - }; + 0 +-------+ + | Alloc | 2nd[0] + +-------+ + | Alloc | 2nd[1] + +-------+ + | ... | + +-------+ + | Alloc | 2nd[2nd.size() - 1] + +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | +GetSize() +-------+ - const bool m_OverlappingMoveSupported; +if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK): - uint32_t m_AllocationCount; - bool m_AllAllocations; + 0 +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | + | | + | | + +-------+ + | Alloc | 2nd[2nd.size() - 1] + +-------+ + | ... | + +-------+ + | Alloc | 2nd[1] + +-------+ + | Alloc | 2nd[0] +GetSize() +-------+ - VkDeviceSize m_BytesMoved; - uint32_t m_AllocationsMoved; +*/ +class VmaBlockMetadata_Linear : public VmaBlockMetadata +{ + VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear) +public: + VmaBlockMetadata_Linear(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Linear() = default; - VmaVector< BlockInfo, VmaStlAllocator > m_BlockInfos; + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } + bool IsEmpty() const override { return GetAllocationCount() == 0; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; } - void PreprocessMetadata(); - void PostprocessMetadata(); - void InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc); -}; + void Init(VkDeviceSize size) override; + bool Validate() const override; + size_t GetAllocationCount() const override; + size_t GetFreeRegionsCount() const override; -struct VmaBlockDefragmentationContext -{ - enum BLOCK_FLAG - { - BLOCK_FLAG_USED = 0x00000001, - }; - uint32_t flags; - VkBuffer hBuffer; -}; + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; -class VmaBlockVectorDefragmentationContext -{ - VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext) -public: - VkResult res; - bool mutexLocked; - VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator > blockContexts; - VmaVector< VmaDefragmentationMove, VmaStlAllocator > defragmentationMoves; - uint32_t defragmentationMovesProcessed; - uint32_t defragmentationMovesCommitted; - bool hasDefragmentationPlan; - - VmaBlockVectorDefragmentationContext( - VmaAllocator hAllocator, - VmaPool hCustomPool, // Optional. - VmaBlockVector* pBlockVector, - uint32_t currFrameIndex); - ~VmaBlockVectorDefragmentationContext(); +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json) const override; +#endif - VmaPool GetCustomPool() const { return m_hCustomPool; } - VmaBlockVector* GetBlockVector() const { return m_pBlockVector; } - VmaDefragmentationAlgorithm* GetAlgorithm() const { return m_pAlgorithm; } + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; - void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged); - void AddAll() { m_AllAllocations = true; } + VkResult CheckCorruption(const void* pBlockData) override; - void Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags); + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; private: - const VmaAllocator m_hAllocator; - // Null if not from custom pool. - const VmaPool m_hCustomPool; - // Redundant, for convenience not to fetch from m_hCustomPool->m_BlockVector or m_hAllocator->m_pBlockVectors. - VmaBlockVector* const m_pBlockVector; - const uint32_t m_CurrFrameIndex; - // Owner of this object. - VmaDefragmentationAlgorithm* m_pAlgorithm; - - struct AllocInfo - { - VmaAllocation hAlloc; - VkBool32* pChanged; - }; - // Used between constructor and Begin. - VmaVector< AllocInfo, VmaStlAllocator > m_Allocations; - bool m_AllAllocations; -}; + /* + There are two suballocation vectors, used in ping-pong way. + The one with index m_1stVectorIndex is called 1st. + The one with index (m_1stVectorIndex ^ 1) is called 2nd. + 2nd can be non-empty only when 1st is not empty. + When 2nd is not empty, m_2ndVectorMode indicates its mode of operation. + */ + typedef VmaVector> SuballocationVectorType; -struct VmaDefragmentationContext_T -{ -private: - VMA_CLASS_NO_COPY(VmaDefragmentationContext_T) -public: - VmaDefragmentationContext_T( - VmaAllocator hAllocator, - uint32_t currFrameIndex, - uint32_t flags, - VmaDefragmentationStats* pStats); - ~VmaDefragmentationContext_T(); + enum SECOND_VECTOR_MODE + { + SECOND_VECTOR_EMPTY, + /* + Suballocations in 2nd vector are created later than the ones in 1st, but they + all have smaller offset. + */ + SECOND_VECTOR_RING_BUFFER, + /* + Suballocations in 2nd vector are upper side of double stack. + They all have offsets higher than those in 1st vector. + Top of this stack means smaller offsets, but higher indices in this vector. + */ + SECOND_VECTOR_DOUBLE_STACK, + }; - void AddPools(uint32_t poolCount, VmaPool* pPools); - void AddAllocations( - uint32_t allocationCount, - VmaAllocation* pAllocations, - VkBool32* pAllocationsChanged); + VkDeviceSize m_SumFreeSize; + SuballocationVectorType m_Suballocations0, m_Suballocations1; + uint32_t m_1stVectorIndex; + SECOND_VECTOR_MODE m_2ndVectorMode; + // Number of items in 1st vector with hAllocation = null at the beginning. + size_t m_1stNullItemsBeginCount; + // Number of other items in 1st vector with hAllocation = null somewhere in the middle. + size_t m_1stNullItemsMiddleCount; + // Number of items in 2nd vector with hAllocation = null. + size_t m_2ndNullItemsCount; - /* - Returns: - - `VK_SUCCESS` if succeeded and object can be destroyed immediately. - - `VK_NOT_READY` if succeeded but the object must remain alive until vmaDefragmentationEnd(). - - Negative value if error occured and object can be destroyed immediately. - */ - VkResult Defragment( - VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove, - VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove, - VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags); + SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } + SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } + const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } + const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } - VkResult DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo); - VkResult DefragmentPassEnd(); + VmaSuballocation& FindSuballocation(VkDeviceSize offset) const; + bool ShouldCompact1st() const; + void CleanupAfterFree(); -private: - const VmaAllocator m_hAllocator; - const uint32_t m_CurrFrameIndex; - const uint32_t m_Flags; - VmaDefragmentationStats* const m_pStats; - - VkDeviceSize m_MaxCpuBytesToMove; - uint32_t m_MaxCpuAllocationsToMove; - VkDeviceSize m_MaxGpuBytesToMove; - uint32_t m_MaxGpuAllocationsToMove; - - // Owner of these objects. - VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES]; - // Owner of these objects. - VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator > m_CustomPoolContexts; + bool CreateAllocationRequest_LowerAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest); + bool CreateAllocationRequest_UpperAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest); }; -#if VMA_RECORDING_ENABLED +#ifndef _VMA_BLOCK_METADATA_LINEAR_FUNCTIONS +VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_SumFreeSize(0), + m_Suballocations0(VmaStlAllocator(pAllocationCallbacks)), + m_Suballocations1(VmaStlAllocator(pAllocationCallbacks)), + m_1stVectorIndex(0), + m_2ndVectorMode(SECOND_VECTOR_EMPTY), + m_1stNullItemsBeginCount(0), + m_1stNullItemsMiddleCount(0), + m_2ndNullItemsCount(0) {} -class VmaRecorder +void VmaBlockMetadata_Linear::Init(VkDeviceSize size) { -public: - VmaRecorder(); - VkResult Init(const VmaRecordSettings& settings, bool useMutex); - void WriteConfiguration( - const VkPhysicalDeviceProperties& devProps, - const VkPhysicalDeviceMemoryProperties& memProps, - uint32_t vulkanApiVersion, - bool dedicatedAllocationExtensionEnabled, - bool bindMemory2ExtensionEnabled, - bool memoryBudgetExtensionEnabled, - bool deviceCoherentMemoryExtensionEnabled); - ~VmaRecorder(); - - void RecordCreateAllocator(uint32_t frameIndex); - void RecordDestroyAllocator(uint32_t frameIndex); - void RecordCreatePool(uint32_t frameIndex, - const VmaPoolCreateInfo& createInfo, - VmaPool pool); - void RecordDestroyPool(uint32_t frameIndex, VmaPool pool); - void RecordAllocateMemory(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation); - void RecordAllocateMemoryPages(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - uint64_t allocationCount, - const VmaAllocation* pAllocations); - void RecordAllocateMemoryForBuffer(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation); - void RecordAllocateMemoryForImage(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation); - void RecordFreeMemory(uint32_t frameIndex, - VmaAllocation allocation); - void RecordFreeMemoryPages(uint32_t frameIndex, - uint64_t allocationCount, - const VmaAllocation* pAllocations); - void RecordSetAllocationUserData(uint32_t frameIndex, - VmaAllocation allocation, - const void* pUserData); - void RecordCreateLostAllocation(uint32_t frameIndex, - VmaAllocation allocation); - void RecordMapMemory(uint32_t frameIndex, - VmaAllocation allocation); - void RecordUnmapMemory(uint32_t frameIndex, - VmaAllocation allocation); - void RecordFlushAllocation(uint32_t frameIndex, - VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size); - void RecordInvalidateAllocation(uint32_t frameIndex, - VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size); - void RecordCreateBuffer(uint32_t frameIndex, - const VkBufferCreateInfo& bufCreateInfo, - const VmaAllocationCreateInfo& allocCreateInfo, - VmaAllocation allocation); - void RecordCreateImage(uint32_t frameIndex, - const VkImageCreateInfo& imageCreateInfo, - const VmaAllocationCreateInfo& allocCreateInfo, - VmaAllocation allocation); - void RecordDestroyBuffer(uint32_t frameIndex, - VmaAllocation allocation); - void RecordDestroyImage(uint32_t frameIndex, - VmaAllocation allocation); - void RecordTouchAllocation(uint32_t frameIndex, - VmaAllocation allocation); - void RecordGetAllocationInfo(uint32_t frameIndex, - VmaAllocation allocation); - void RecordMakePoolAllocationsLost(uint32_t frameIndex, - VmaPool pool); - void RecordDefragmentationBegin(uint32_t frameIndex, - const VmaDefragmentationInfo2& info, - VmaDefragmentationContext ctx); - void RecordDefragmentationEnd(uint32_t frameIndex, - VmaDefragmentationContext ctx); - void RecordSetPoolName(uint32_t frameIndex, - VmaPool pool, - const char* name); + VmaBlockMetadata::Init(size); + m_SumFreeSize = size; +} -private: - struct CallParams - { - uint32_t threadId; - double time; - }; +bool VmaBlockMetadata_Linear::Validate() const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - class UserDataString - { - public: - UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData); - const char* GetString() const { return m_Str; } + VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY)); + VMA_VALIDATE(!suballocations1st.empty() || + suballocations2nd.empty() || + m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER); - private: - char m_PtrStr[17]; - const char* m_Str; - }; + if (!suballocations1st.empty()) + { + // Null item at the beginning should be accounted into m_1stNullItemsBeginCount. + VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].type != VMA_SUBALLOCATION_TYPE_FREE); + // Null item at the end should be just pop_back(). + VMA_VALIDATE(suballocations1st.back().type != VMA_SUBALLOCATION_TYPE_FREE); + } + if (!suballocations2nd.empty()) + { + // Null item at the end should be just pop_back(). + VMA_VALIDATE(suballocations2nd.back().type != VMA_SUBALLOCATION_TYPE_FREE); + } - bool m_UseMutex; - VmaRecordFlags m_Flags; - FILE* m_File; - VMA_MUTEX m_FileMutex; - int64_t m_Freq; - int64_t m_StartCounter; + VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size()); + VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size()); - void GetBasicParams(CallParams& outParams); + VkDeviceSize sumUsedSize = 0; + const size_t suballoc1stCount = suballocations1st.size(); + const VkDeviceSize debugMargin = GetDebugMargin(); + VkDeviceSize offset = 0; - // T must be a pointer type, e.g. VmaAllocation, VmaPool. - template - void PrintPointerList(uint64_t count, const T* pItems) + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) { - if(count) + const size_t suballoc2ndCount = suballocations2nd.size(); + size_t nullItem2ndCount = 0; + for (size_t i = 0; i < suballoc2ndCount; ++i) { - fprintf(m_File, "%p", pItems[0]); - for(uint64_t i = 1; i < count; ++i) - { - fprintf(m_File, " %p", pItems[i]); + const VmaSuballocation& suballoc = suballocations2nd[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); } - } - } + VMA_VALIDATE(suballoc.offset >= offset); - void PrintPointerList(uint64_t count, const VmaAllocation* pItems); - void Flush(); -}; + if (!currFree) + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem2ndCount; + } -#endif // #if VMA_RECORDING_ENABLED + offset = suballoc.offset + suballoc.size + debugMargin; + } -/* -Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects. -*/ -class VmaAllocationObjectAllocator -{ - VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator) -public: - VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks); + VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); + } - template VmaAllocation Allocate(Types... args); - void Free(VmaAllocation hAlloc); + for (size_t i = 0; i < m_1stNullItemsBeginCount; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE && + suballoc.userData == VMA_NULL); + } -private: - VMA_MUTEX m_Mutex; - VmaPoolAllocator m_Allocator; -}; + size_t nullItem1stCount = m_1stNullItemsBeginCount; -struct VmaCurrentBudgetData -{ - VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS]; - VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS]; + for (size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); -#if VMA_MEMORY_BUDGET - VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch; - VMA_RW_MUTEX m_BudgetMutex; - uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS]; - uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS]; - uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS]; -#endif // #if VMA_MEMORY_BUDGET + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + VMA_VALIDATE(suballoc.offset >= offset); + VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree); - VmaCurrentBudgetData() - { - for(uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex) + if (!currFree) { - m_BlockBytes[heapIndex] = 0; - m_AllocationBytes[heapIndex] = 0; -#if VMA_MEMORY_BUDGET - m_VulkanUsage[heapIndex] = 0; - m_VulkanBudget[heapIndex] = 0; - m_BlockBytesAtBudgetFetch[heapIndex] = 0; -#endif + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem1stCount; } -#if VMA_MEMORY_BUDGET - m_OperationsSinceBudgetFetch = 0; -#endif + offset = suballoc.offset + suballoc.size + debugMargin; } + VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount); - void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) { - m_AllocationBytes[heapIndex] += allocationSize; -#if VMA_MEMORY_BUDGET - ++m_OperationsSinceBudgetFetch; -#endif - } + const size_t suballoc2ndCount = suballocations2nd.size(); + size_t nullItem2ndCount = 0; + for (size_t i = suballoc2ndCount; i--; ) + { + const VmaSuballocation& suballoc = suballocations2nd[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) - { - VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME - m_AllocationBytes[heapIndex] -= allocationSize; -#if VMA_MEMORY_BUDGET - ++m_OperationsSinceBudgetFetch; -#endif - } -}; + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + VMA_VALIDATE(suballoc.offset >= offset); -// Main allocator object. -struct VmaAllocator_T -{ - VMA_CLASS_NO_COPY(VmaAllocator_T) -public: - bool m_UseMutex; - uint32_t m_VulkanApiVersion; - bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). - bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). - bool m_UseExtMemoryBudget; - bool m_UseAmdDeviceCoherentMemory; - bool m_UseKhrBufferDeviceAddress; - VkDevice m_hDevice; - VkInstance m_hInstance; - bool m_AllocationCallbacksSpecified; - VkAllocationCallbacks m_AllocationCallbacks; - VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; - VmaAllocationObjectAllocator m_AllocationObjectAllocator; - - // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size. - uint32_t m_HeapSizeLimitMask; + if (!currFree) + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem2ndCount; + } - VkPhysicalDeviceProperties m_PhysicalDeviceProperties; - VkPhysicalDeviceMemoryProperties m_MemProps; + offset = suballoc.offset + suballoc.size + debugMargin; + } - // Default pools. - VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES]; + VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); + } - // Each vector is sorted by memory (handle value). - typedef VmaVector< VmaAllocation, VmaStlAllocator > AllocationVectorType; - AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES]; - VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES]; + VMA_VALIDATE(offset <= GetSize()); + VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize); - VmaCurrentBudgetData m_Budget; + return true; +} - VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo); - VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo); - ~VmaAllocator_T(); +size_t VmaBlockMetadata_Linear::GetAllocationCount() const +{ + return AccessSuballocations1st().size() - m_1stNullItemsBeginCount - m_1stNullItemsMiddleCount + + AccessSuballocations2nd().size() - m_2ndNullItemsCount; +} - const VkAllocationCallbacks* GetAllocationCallbacks() const - { - return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0; - } - const VmaVulkanFunctions& GetVulkanFunctions() const - { - return m_VulkanFunctions; - } +size_t VmaBlockMetadata_Linear::GetFreeRegionsCount() const +{ + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return SIZE_MAX; +} - VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; } +void VmaBlockMetadata_Linear::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + const VkDeviceSize size = GetSize(); + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); - VkDeviceSize GetBufferImageGranularity() const - { - return VMA_MAX( - static_cast(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY), - m_PhysicalDeviceProperties.limits.bufferImageGranularity); - } + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += size; - uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; } - uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; } + VkDeviceSize lastOffset = 0; - uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const - { - VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount); - return m_MemProps.memoryTypes[memTypeIndex].heapIndex; - } - // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT. - bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const - { - return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - } - // Minimum alignment for all allocations in specific memory type. - VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) { - return IsMemoryTypeNonCoherent(memTypeIndex) ? - VMA_MAX((VkDeviceSize)VMA_DEBUG_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) : - (VkDeviceSize)VMA_DEBUG_ALIGNMENT; - } + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } - bool IsIntegratedGpu() const - { - return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; - } + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; } + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } -#if VMA_RECORDING_ENABLED - VmaRecorder* GetRecorder() const { return m_pRecorder; } -#endif + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); - void GetBufferMemoryRequirements( - VkBuffer hBuffer, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const; - void GetImageMemoryRequirements( - VkImage hImage, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const; + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + if (lastOffset < freeSpace2ndTo1stEnd) + { + const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } - // Main allocation function. - VkResult AllocateMemory( - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, // UINT32_MAX when unknown. - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - size_t allocationCount, - VmaAllocation* pAllocations); + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } - // Main deallocation function. - void FreeMemory( - size_t allocationCount, - const VmaAllocation* pAllocations); + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } - VkResult ResizeAllocation( - const VmaAllocation alloc, - VkDeviceSize newSize); + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - void CalculateStats(VmaStats* pStats); + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } - void GetBudget( - VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount); + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json); -#endif + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + if (lastOffset < freeSpace1stTo2ndEnd) + { + const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } - VkResult DefragmentationBegin( - const VmaDefragmentationInfo2& info, - VmaDefragmentationStats* pStats, - VmaDefragmentationContext* pContext); - VkResult DefragmentationEnd( - VmaDefragmentationContext context); + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } - VkResult DefragmentationPassBegin( - VmaDefragmentationPassInfo* pInfo, - VmaDefragmentationContext context); - VkResult DefragmentationPassEnd( - VmaDefragmentationContext context); + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } - void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo); - bool TouchAllocation(VmaAllocation hAllocation); + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool); - void DestroyPool(VmaPool pool); - void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats); + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } - void SetCurrentFrameIndex(uint32_t frameIndex); - uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); } + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); - void MakePoolAllocationsLost( - VmaPool hPool, - size_t* pLostAllocationCount); - VkResult CheckPoolCorruption(VmaPool hPool); - VkResult CheckCorruption(uint32_t memoryTypeBits); + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to size. + if (lastOffset < size) + { + const VkDeviceSize unusedRangeSize = size - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } - void CreateLostAllocation(VmaAllocation* pAllocation); + // End of loop. + lastOffset = size; + } + } + } +} - // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping. - VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory); - // Call to Vulkan function vkFreeMemory with accompanying bookkeeping. - void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory); - // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR. - VkResult BindVulkanBuffer( - VkDeviceMemory memory, - VkDeviceSize memoryOffset, - VkBuffer buffer, - const void* pNext); - // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR. - VkResult BindVulkanImage( - VkDeviceMemory memory, - VkDeviceSize memoryOffset, - VkImage image, - const void* pNext); +void VmaBlockMetadata_Linear::AddStatistics(VmaStatistics& inoutStats) const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const VkDeviceSize size = GetSize(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); - VkResult Map(VmaAllocation hAllocation, void** ppData); - void Unmap(VmaAllocation hAllocation); + inoutStats.blockCount++; + inoutStats.blockBytes += size; + inoutStats.allocationBytes += size - m_SumFreeSize; - VkResult BindBufferMemory( - VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkBuffer hBuffer, - const void* pNext); - VkResult BindImageMemory( - VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkImage hImage, - const void* pNext); + VkDeviceSize lastOffset = 0; - void FlushOrInvalidateAllocation( - VmaAllocation hAllocation, - VkDeviceSize offset, VkDeviceSize size, - VMA_CACHE_OPERATION op); + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } - void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern); + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - /* - Returns bit mask of memory types that can support defragmentation on GPU as - they support creation of required buffer for copy operations. - */ - uint32_t GetGpuDefragmentationMemoryTypeBits(); + // Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; -private: - VkDeviceSize m_PreferredLargeHeapBlockSize; + // Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } - VkPhysicalDevice m_PhysicalDevice; - VMA_ATOMIC_UINT32 m_CurrentFrameIndex; - VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized. - - VMA_RW_MUTEX m_PoolsMutex; - // Protected by m_PoolsMutex. Sorted by pointer value. - VmaVector > m_Pools; - uint32_t m_NextPoolId; + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } - VmaVulkanFunctions m_VulkanFunctions; + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types. - uint32_t m_GlobalMemoryTypeBits; + // Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; -#if VMA_RECORDING_ENABLED - VmaRecorder* m_pRecorder; -#endif + // Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } - void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions); + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } - VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex); + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - VkResult AllocateMemoryOfType( - VkDeviceSize size, - VkDeviceSize alignment, - bool dedicatedAllocation, - VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - uint32_t memTypeIndex, - VmaSuballocationType suballocType, - size_t allocationCount, - VmaAllocation* pAllocations); + // Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; - // Helper function only to be used inside AllocateDedicatedMemory. - VkResult AllocateDedicatedMemoryPage( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - const VkMemoryAllocateInfo& allocInfo, - bool map, - bool isUserDataString, - void* pUserData, - VmaAllocation* pAllocation); + // Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + // End of loop. + lastOffset = size; + } + } + } +} - // Allocates and registers new VkDeviceMemory specifically for dedicated allocations. - VkResult AllocateDedicatedMemory( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - bool withinBudget, - bool map, - bool isUserDataString, - void* pUserData, - VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, - VkImage dedicatedImage, - size_t allocationCount, - VmaAllocation* pAllocations); +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const +{ + const VkDeviceSize size = GetSize(); + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); - void FreeDedicatedMemory(const VmaAllocation allocation); + // FIRST PASS - /* - Calculates and returns bit mask of memory types that can support defragmentation - on GPU as they support creation of required buffer for copy operations. - */ - uint32_t CalculateGpuDefragmentationMemoryTypeBits() const; + size_t unusedRangeCount = 0; + VkDeviceSize usedBytes = 0; - uint32_t CalculateGlobalMemoryTypeBits() const; + VkDeviceSize lastOffset = 0; -#if VMA_MEMORY_BUDGET - void UpdateVulkanBudget(); -#endif // #if VMA_MEMORY_BUDGET -}; + size_t alloc2ndCount = 0; + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } -//////////////////////////////////////////////////////////////////////////////// -// Memory allocation #2 after VmaAllocator_T definition + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; -static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment) -{ - return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment); -} - -static void VmaFree(VmaAllocator hAllocator, void* ptr) -{ - VmaFree(&hAllocator->m_AllocationCallbacks, ptr); -} + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } -template -static T* VmaAllocate(VmaAllocator hAllocator) -{ - return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T)); -} + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc2ndCount; + usedBytes += suballoc.size; -template -static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) -{ - return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T)); -} + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace2ndTo1stEnd) + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + ++unusedRangeCount; + } -template -static void vma_delete(VmaAllocator hAllocator, T* ptr) -{ - if(ptr != VMA_NULL) - { - ptr->~T(); - VmaFree(hAllocator, ptr); + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } } -} -template -static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) -{ - if(ptr != VMA_NULL) + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + size_t alloc1stCount = 0; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) { - for(size_t i = count; i--; ) - ptr[i].~T(); - VmaFree(hAllocator, ptr); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// VmaStringBuilder - -#if VMA_STATS_STRING_ENABLED + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } -class VmaStringBuilder -{ -public: - VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator(alloc->GetAllocationCallbacks())) { } - size_t GetLength() const { return m_Data.size(); } - const char* GetData() const { return m_Data.data(); } + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - void Add(char ch) { m_Data.push_back(ch); } - void Add(const char* pStr); - void AddNewLine() { Add('\n'); } - void AddNumber(uint32_t num); - void AddNumber(uint64_t num); - void AddPointer(const void* ptr); + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } -private: - VmaVector< char, VmaStlAllocator > m_Data; -}; + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc1stCount; + usedBytes += suballoc.size; -void VmaStringBuilder::Add(const char* pStr) -{ - const size_t strLen = strlen(pStr); - if(strLen > 0) - { - const size_t oldCount = m_Data.size(); - m_Data.resize(oldCount + strLen); - memcpy(m_Data.data() + oldCount, pStr, strLen); - } -} + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + ++unusedRangeCount; + } -void VmaStringBuilder::AddNumber(uint32_t num) -{ - char buf[11]; - buf[10] = '\0'; - char *p = &buf[10]; - do - { - *--p = '0' + (num % 10); - num /= 10; + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } } - while(num); - Add(p); -} -void VmaStringBuilder::AddNumber(uint64_t num) -{ - char buf[21]; - buf[20] = '\0'; - char *p = &buf[20]; - do + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) { - *--p = '0' + (num % 10); - num /= 10; - } - while(num); - Add(p); -} + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } -void VmaStringBuilder::AddPointer(const void* ptr) -{ - char buf[21]; - VmaPtrToStr(buf, sizeof(buf), ptr); - Add(buf); -} + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; -#endif // #if VMA_STATS_STRING_ENABLED + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } -//////////////////////////////////////////////////////////////////////////////// -// VmaJsonWriter + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc2ndCount; + usedBytes += suballoc.size; -#if VMA_STATS_STRING_ENABLED + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to size. + ++unusedRangeCount; + } -class VmaJsonWriter -{ - VMA_CLASS_NO_COPY(VmaJsonWriter) -public: - VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb); - ~VmaJsonWriter(); + // End of loop. + lastOffset = size; + } + } + } - void BeginObject(bool singleLine = false); - void EndObject(); - - void BeginArray(bool singleLine = false); - void EndArray(); - - void WriteString(const char* pStr); - void BeginString(const char* pStr = VMA_NULL); - void ContinueString(const char* pStr); - void ContinueString(uint32_t n); - void ContinueString(uint64_t n); - void ContinueString_Pointer(const void* ptr); - void EndString(const char* pStr = VMA_NULL); - - void WriteNumber(uint32_t n); - void WriteNumber(uint64_t n); - void WriteBool(bool b); - void WriteNull(); + const VkDeviceSize unusedBytes = size - usedBytes; + PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount); -private: - static const char* const INDENT; + // SECOND PASS + lastOffset = 0; - enum COLLECTION_TYPE + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) { - COLLECTION_TYPE_OBJECT, - COLLECTION_TYPE_ARRAY, - }; - struct StackItem - { - COLLECTION_TYPE type; - uint32_t valueCount; - bool singleLineMode; - }; - - VmaStringBuilder& m_SB; - VmaVector< StackItem, VmaStlAllocator > m_Stack; - bool m_InsideString; - - void BeginValue(bool isString); - void WriteIndent(bool oneLess = false); -}; - -const char* const VmaJsonWriter::INDENT = " "; + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } -VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) : - m_SB(sb), - m_Stack(VmaStlAllocator(pAllocationCallbacks)), - m_InsideString(false) -{ -} + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; -VmaJsonWriter::~VmaJsonWriter() -{ - VMA_ASSERT(!m_InsideString); - VMA_ASSERT(m_Stack.empty()); -} + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } -void VmaJsonWriter::BeginObject(bool singleLine) -{ - VMA_ASSERT(!m_InsideString); + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); - BeginValue(false); - m_SB.Add('{'); + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace2ndTo1stEnd) + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } - StackItem item; - item.type = COLLECTION_TYPE_OBJECT; - item.valueCount = 0; - item.singleLineMode = singleLine; - m_Stack.push_back(item); -} + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } -void VmaJsonWriter::EndObject() -{ - VMA_ASSERT(!m_InsideString); + nextAlloc1stIndex = m_1stNullItemsBeginCount; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } - WriteIndent(true); - m_SB.Add('}'); + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT); - m_Stack.pop_back(); -} + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } -void VmaJsonWriter::BeginArray(bool singleLine) -{ - VMA_ASSERT(!m_InsideString); + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); - BeginValue(false); - m_SB.Add('['); + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace1stTo2ndEnd) + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } - StackItem item; - item.type = COLLECTION_TYPE_ARRAY; - item.valueCount = 0; - item.singleLineMode = singleLine; - m_Stack.push_back(item); -} + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } -void VmaJsonWriter::EndArray() -{ - VMA_ASSERT(!m_InsideString); + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } - WriteIndent(true); - m_SB.Add(']'); + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY); - m_Stack.pop_back(); + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to size. + const VkDeviceSize unusedRangeSize = size - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // End of loop. + lastOffset = size; + } + } + } + + PrintDetailedMap_End(json); } +#endif // VMA_STATS_STRING_ENABLED -void VmaJsonWriter::WriteString(const char* pStr) +bool VmaBlockMetadata_Linear::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) { - BeginString(pStr); - EndString(); + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(pAllocationRequest != VMA_NULL); + VMA_HEAVY_ASSERT(Validate()); + pAllocationRequest->size = allocSize; + return upperAddress ? + CreateAllocationRequest_UpperAddress( + allocSize, allocAlignment, allocType, strategy, pAllocationRequest) : + CreateAllocationRequest_LowerAddress( + allocSize, allocAlignment, allocType, strategy, pAllocationRequest); } -void VmaJsonWriter::BeginString(const char* pStr) +VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData) { - VMA_ASSERT(!m_InsideString); + VMA_ASSERT(!IsVirtual()); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + for (size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } + } - BeginValue(true); - m_SB.Add('"'); - m_InsideString = true; - if(pStr != VMA_NULL && pStr[0] != '\0') + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + for (size_t i = 0, count = suballocations2nd.size(); i < count; ++i) { - ContinueString(pStr); + const VmaSuballocation& suballoc = suballocations2nd[i]; + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } } + + return VK_SUCCESS; } -void VmaJsonWriter::ContinueString(const char* pStr) +void VmaBlockMetadata_Linear::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) { - VMA_ASSERT(m_InsideString); + const VkDeviceSize offset = (VkDeviceSize)request.allocHandle - 1; + const VmaSuballocation newSuballoc = { offset, request.size, userData, type }; - const size_t strLen = strlen(pStr); - for(size_t i = 0; i < strLen; ++i) + switch (request.type) { - char ch = pStr[i]; - if(ch == '\\') - { - m_SB.Add("\\\\"); - } - else if(ch == '"') - { - m_SB.Add("\\\""); - } - else if(ch >= 32) - { - m_SB.Add(ch); - } - else switch(ch) + case VmaAllocationRequestType::UpperAddress: + { + VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER && + "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer."); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + suballocations2nd.push_back(newSuballoc); + m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK; + } + break; + case VmaAllocationRequestType::EndOf1st: + { + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + + VMA_ASSERT(suballocations1st.empty() || + offset >= suballocations1st.back().offset + suballocations1st.back().size); + // Check if it fits before the end of the block. + VMA_ASSERT(offset + request.size <= GetSize()); + + suballocations1st.push_back(newSuballoc); + } + break; + case VmaAllocationRequestType::EndOf2nd: + { + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector. + VMA_ASSERT(!suballocations1st.empty() && + offset + request.size <= suballocations1st[m_1stNullItemsBeginCount].offset); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + switch (m_2ndVectorMode) { - case '\b': - m_SB.Add("\\b"); - break; - case '\f': - m_SB.Add("\\f"); - break; - case '\n': - m_SB.Add("\\n"); + case SECOND_VECTOR_EMPTY: + // First allocation from second part ring buffer. + VMA_ASSERT(suballocations2nd.empty()); + m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER; break; - case '\r': - m_SB.Add("\\r"); + case SECOND_VECTOR_RING_BUFFER: + // 2-part ring buffer is already started. + VMA_ASSERT(!suballocations2nd.empty()); break; - case '\t': - m_SB.Add("\\t"); + case SECOND_VECTOR_DOUBLE_STACK: + VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack."); break; default: - VMA_ASSERT(0 && "Character not currently supported."); - break; + VMA_ASSERT(0); } - } -} -void VmaJsonWriter::ContinueString(uint32_t n) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddNumber(n); -} + suballocations2nd.push_back(newSuballoc); + } + break; + default: + VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR."); + } -void VmaJsonWriter::ContinueString(uint64_t n) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddNumber(n); + m_SumFreeSize -= newSuballoc.size; } -void VmaJsonWriter::ContinueString_Pointer(const void* ptr) +void VmaBlockMetadata_Linear::Free(VmaAllocHandle allocHandle) { - VMA_ASSERT(m_InsideString); - m_SB.AddPointer(ptr); -} + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + VkDeviceSize offset = (VkDeviceSize)allocHandle - 1; -void VmaJsonWriter::EndString(const char* pStr) -{ - VMA_ASSERT(m_InsideString); - if(pStr != VMA_NULL && pStr[0] != '\0') + if (!suballocations1st.empty()) { - ContinueString(pStr); + // First allocation: Mark it as next empty at the beginning. + VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount]; + if (firstSuballoc.offset == offset) + { + firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + firstSuballoc.userData = VMA_NULL; + m_SumFreeSize += firstSuballoc.size; + ++m_1stNullItemsBeginCount; + CleanupAfterFree(); + return; + } } - m_SB.Add('"'); - m_InsideString = false; -} - -void VmaJsonWriter::WriteNumber(uint32_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.AddNumber(n); -} -void VmaJsonWriter::WriteNumber(uint64_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.AddNumber(n); -} - -void VmaJsonWriter::WriteBool(bool b) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.Add(b ? "true" : "false"); -} - -void VmaJsonWriter::WriteNull() -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.Add("null"); -} - -void VmaJsonWriter::BeginValue(bool isString) -{ - if(!m_Stack.empty()) + // Last allocation in 2-part ring buffer or top of upper stack (same logic). + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER || + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) { - StackItem& currItem = m_Stack.back(); - if(currItem.type == COLLECTION_TYPE_OBJECT && - currItem.valueCount % 2 == 0) - { - VMA_ASSERT(isString); - } - - if(currItem.type == COLLECTION_TYPE_OBJECT && - currItem.valueCount % 2 != 0) - { - m_SB.Add(": "); - } - else if(currItem.valueCount > 0) - { - m_SB.Add(", "); - WriteIndent(); - } - else + VmaSuballocation& lastSuballoc = suballocations2nd.back(); + if (lastSuballoc.offset == offset) { - WriteIndent(); + m_SumFreeSize += lastSuballoc.size; + suballocations2nd.pop_back(); + CleanupAfterFree(); + return; } - ++currItem.valueCount; } -} - -void VmaJsonWriter::WriteIndent(bool oneLess) -{ - if(!m_Stack.empty() && !m_Stack.back().singleLineMode) + // Last allocation in 1st vector. + else if (m_2ndVectorMode == SECOND_VECTOR_EMPTY) { - m_SB.AddNewLine(); - - size_t count = m_Stack.size(); - if(count > 0 && oneLess) - { - --count; - } - for(size_t i = 0; i < count; ++i) + VmaSuballocation& lastSuballoc = suballocations1st.back(); + if (lastSuballoc.offset == offset) { - m_SB.Add(INDENT); + m_SumFreeSize += lastSuballoc.size; + suballocations1st.pop_back(); + CleanupAfterFree(); + return; } } -} - -#endif // #if VMA_STATS_STRING_ENABLED -//////////////////////////////////////////////////////////////////////////////// + VmaSuballocation refSuballoc; + refSuballoc.offset = offset; + // Rest of members stays uninitialized intentionally for better performance. -void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData) -{ - if(IsUserDataString()) + // Item from the middle of 1st vector. { - VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData); - - FreeUserDataString(hAllocator); - - if(pUserData != VMA_NULL) + const SuballocationVectorType::iterator it = VmaBinaryFindSorted( + suballocations1st.begin() + m_1stNullItemsBeginCount, + suballocations1st.end(), + refSuballoc, + VmaSuballocationOffsetLess()); + if (it != suballocations1st.end()) { - m_pUserData = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), (const char*)pUserData); + it->type = VMA_SUBALLOCATION_TYPE_FREE; + it->userData = VMA_NULL; + ++m_1stNullItemsMiddleCount; + m_SumFreeSize += it->size; + CleanupAfterFree(); + return; } } - else - { - m_pUserData = pUserData; - } -} -void VmaAllocation_T::ChangeBlockAllocation( - VmaAllocator hAllocator, - VmaDeviceMemoryBlock* block, - VkDeviceSize offset) -{ - VMA_ASSERT(block != VMA_NULL); - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - - // Move mapping reference counter from old block to new block. - if(block != m_BlockAllocation.m_Block) + if (m_2ndVectorMode != SECOND_VECTOR_EMPTY) { - uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP; - if(IsPersistentMap()) - ++mapRefCount; - m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount); - block->Map(hAllocator, mapRefCount, VMA_NULL); + // Item from the middle of 2nd vector. + const SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ? + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) : + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater()); + if (it != suballocations2nd.end()) + { + it->type = VMA_SUBALLOCATION_TYPE_FREE; + it->userData = VMA_NULL; + ++m_2ndNullItemsCount; + m_SumFreeSize += it->size; + CleanupAfterFree(); + return; + } } - m_BlockAllocation.m_Block = block; - m_BlockAllocation.m_Offset = offset; + VMA_ASSERT(0 && "Allocation to free not found in linear allocator!"); } -void VmaAllocation_T::ChangeOffset(VkDeviceSize newOffset) +void VmaBlockMetadata_Linear::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - m_BlockAllocation.m_Offset = newOffset; + outInfo.offset = (VkDeviceSize)allocHandle - 1; + VmaSuballocation& suballoc = FindSuballocation(outInfo.offset); + outInfo.size = suballoc.size; + outInfo.pUserData = suballoc.userData; } -VkDeviceSize VmaAllocation_T::GetOffset() const +void* VmaBlockMetadata_Linear::GetAllocationUserData(VmaAllocHandle allocHandle) const { - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Offset; - case ALLOCATION_TYPE_DEDICATED: - return 0; - default: - VMA_ASSERT(0); - return 0; - } + return FindSuballocation((VkDeviceSize)allocHandle - 1).userData; } -VkDeviceMemory VmaAllocation_T::GetMemory() const +VmaAllocHandle VmaBlockMetadata_Linear::GetAllocationListBegin() const { - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Block->GetDeviceMemory(); - case ALLOCATION_TYPE_DEDICATED: - return m_DedicatedAllocation.m_hMemory; - default: - VMA_ASSERT(0); - return VK_NULL_HANDLE; - } + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return VK_NULL_HANDLE; } -void* VmaAllocation_T::GetMappedData() const +VmaAllocHandle VmaBlockMetadata_Linear::GetNextAllocation(VmaAllocHandle prevAlloc) const { - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - if(m_MapCount != 0) - { - void* pBlockData = m_BlockAllocation.m_Block->GetMappedData(); - VMA_ASSERT(pBlockData != VMA_NULL); - return (char*)pBlockData + m_BlockAllocation.m_Offset; - } - else - { - return VMA_NULL; - } - break; - case ALLOCATION_TYPE_DEDICATED: - VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0)); - return m_DedicatedAllocation.m_pMappedData; - default: - VMA_ASSERT(0); - return VMA_NULL; - } + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return VK_NULL_HANDLE; } -bool VmaAllocation_T::CanBecomeLost() const +VkDeviceSize VmaBlockMetadata_Linear::GetNextFreeRegionSize(VmaAllocHandle alloc) const { - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_CanBecomeLost; - case ALLOCATION_TYPE_DEDICATED: - return false; - default: - VMA_ASSERT(0); - return false; - } + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return 0; } -bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) +void VmaBlockMetadata_Linear::Clear() { - VMA_ASSERT(CanBecomeLost()); + m_SumFreeSize = GetSize(); + m_Suballocations0.clear(); + m_Suballocations1.clear(); + // Leaving m_1stVectorIndex unchanged - it doesn't matter. + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; + m_2ndNullItemsCount = 0; +} - /* - Warning: This is a carefully designed algorithm. - Do not modify unless you really know what you're doing :) - */ - uint32_t localLastUseFrameIndex = GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - VMA_ASSERT(0); - return false; - } - else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex) - { - return false; - } - else // Last use time earlier than current time. - { - if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST)) - { - // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST. - // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock. - return true; - } - } - } +void VmaBlockMetadata_Linear::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + VmaSuballocation& suballoc = FindSuballocation((VkDeviceSize)allocHandle - 1); + suballoc.userData = userData; } -#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Linear::DebugLogAllAllocations() const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it) + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(it->offset, it->size, it->userData); -// Correspond to values of enum VmaSuballocationType. -static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = { - "FREE", - "UNKNOWN", - "BUFFER", - "IMAGE_UNKNOWN", - "IMAGE_LINEAR", - "IMAGE_OPTIMAL", -}; + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it) + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(it->offset, it->size, it->userData); +} -void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const +VmaSuballocation& VmaBlockMetadata_Linear::FindSuballocation(VkDeviceSize offset) const { - json.WriteString("Type"); - json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]); + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - json.WriteString("Size"); - json.WriteNumber(m_Size); + VmaSuballocation refSuballoc; + refSuballoc.offset = offset; + // Rest of members stays uninitialized intentionally for better performance. - if(m_pUserData != VMA_NULL) + // Item from the 1st vector. { - json.WriteString("UserData"); - if(IsUserDataString()) - { - json.WriteString((const char*)m_pUserData); - } - else + SuballocationVectorType::const_iterator it = VmaBinaryFindSorted( + suballocations1st.begin() + m_1stNullItemsBeginCount, + suballocations1st.end(), + refSuballoc, + VmaSuballocationOffsetLess()); + if (it != suballocations1st.end()) { - json.BeginString(); - json.ContinueString_Pointer(m_pUserData); - json.EndString(); + return const_cast(*it); } } - json.WriteString("CreationFrameIndex"); - json.WriteNumber(m_CreationFrameIndex); - - json.WriteString("LastUseFrameIndex"); - json.WriteNumber(GetLastUseFrameIndex()); - - if(m_BufferImageUsage != 0) + if (m_2ndVectorMode != SECOND_VECTOR_EMPTY) { - json.WriteString("Usage"); - json.WriteNumber(m_BufferImageUsage); + // Rest of members stays uninitialized intentionally for better performance. + SuballocationVectorType::const_iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ? + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) : + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater()); + if (it != suballocations2nd.end()) + { + return const_cast(*it); + } } -} - -#endif -void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator) -{ - VMA_ASSERT(IsUserDataString()); - VmaFreeString(hAllocator->GetAllocationCallbacks(), (char*)m_pUserData); - m_pUserData = VMA_NULL; + VMA_ASSERT(0 && "Allocation not found in linear allocator!"); + return const_cast(suballocations1st.back()); // Should never occur. } -void VmaAllocation_T::BlockAllocMap() +bool VmaBlockMetadata_Linear::ShouldCompact1st() const { - VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); - - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F) - { - ++m_MapCount; - } - else - { - VMA_ASSERT(0 && "Allocation mapped too many times simultaneously."); - } + const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; + const size_t suballocCount = AccessSuballocations1st().size(); + return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3; } -void VmaAllocation_T::BlockAllocUnmap() +void VmaBlockMetadata_Linear::CleanupAfterFree() { - VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0) + if (IsEmpty()) { - --m_MapCount; + suballocations1st.clear(); + suballocations2nd.clear(); + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; + m_2ndNullItemsCount = 0; + m_2ndVectorMode = SECOND_VECTOR_EMPTY; } else { - VMA_ASSERT(0 && "Unmapping allocation not previously mapped."); - } -} - -VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData) -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; + VMA_ASSERT(nullItem1stCount <= suballoc1stCount); - if(m_MapCount != 0) - { - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F) + // Find more null items at the beginning of 1st vector. + while (m_1stNullItemsBeginCount < suballoc1stCount && + suballocations1st[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE) { - VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL); - *ppData = m_DedicatedAllocation.m_pMappedData; - ++m_MapCount; - return VK_SUCCESS; + ++m_1stNullItemsBeginCount; + --m_1stNullItemsMiddleCount; } - else + + // Find more null items at the end of 1st vector. + while (m_1stNullItemsMiddleCount > 0 && + suballocations1st.back().type == VMA_SUBALLOCATION_TYPE_FREE) { - VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously."); - return VK_ERROR_MEMORY_MAP_FAILED; - } - } - else - { - VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( - hAllocator->m_hDevice, - m_DedicatedAllocation.m_hMemory, - 0, // offset - VK_WHOLE_SIZE, - 0, // flags - ppData); - if(result == VK_SUCCESS) + --m_1stNullItemsMiddleCount; + suballocations1st.pop_back(); + } + + // Find more null items at the end of 2nd vector. + while (m_2ndNullItemsCount > 0 && + suballocations2nd.back().type == VMA_SUBALLOCATION_TYPE_FREE) { - m_DedicatedAllocation.m_pMappedData = *ppData; - m_MapCount = 1; + --m_2ndNullItemsCount; + suballocations2nd.pop_back(); } - return result; - } -} -void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator) -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); + // Find more null items at the beginning of 2nd vector. + while (m_2ndNullItemsCount > 0 && + suballocations2nd[0].type == VMA_SUBALLOCATION_TYPE_FREE) + { + --m_2ndNullItemsCount; + VmaVectorRemove(suballocations2nd, 0); + } - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0) - { - --m_MapCount; - if(m_MapCount == 0) + if (ShouldCompact1st()) { - m_DedicatedAllocation.m_pMappedData = VMA_NULL; - (*hAllocator->GetVulkanFunctions().vkUnmapMemory)( - hAllocator->m_hDevice, - m_DedicatedAllocation.m_hMemory); + const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount; + size_t srcIndex = m_1stNullItemsBeginCount; + for (size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex) + { + while (suballocations1st[srcIndex].type == VMA_SUBALLOCATION_TYPE_FREE) + { + ++srcIndex; + } + if (dstIndex != srcIndex) + { + suballocations1st[dstIndex] = suballocations1st[srcIndex]; + } + ++srcIndex; + } + suballocations1st.resize(nonNullItemCount); + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; } - } - else - { - VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped."); - } -} -#if VMA_STATS_STRING_ENABLED + // 2nd vector became empty. + if (suballocations2nd.empty()) + { + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + } -static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat) -{ - json.BeginObject(); + // 1st vector became empty. + if (suballocations1st.size() - m_1stNullItemsBeginCount == 0) + { + suballocations1st.clear(); + m_1stNullItemsBeginCount = 0; - json.WriteString("Blocks"); - json.WriteNumber(stat.blockCount); + if (!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + // Swap 1st with 2nd. Now 2nd is empty. + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + m_1stNullItemsMiddleCount = m_2ndNullItemsCount; + while (m_1stNullItemsBeginCount < suballocations2nd.size() && + suballocations2nd[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE) + { + ++m_1stNullItemsBeginCount; + --m_1stNullItemsMiddleCount; + } + m_2ndNullItemsCount = 0; + m_1stVectorIndex ^= 1; + } + } + } - json.WriteString("Allocations"); - json.WriteNumber(stat.allocationCount); + VMA_HEAVY_ASSERT(Validate()); +} - json.WriteString("UnusedRanges"); - json.WriteNumber(stat.unusedRangeCount); +bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + const VkDeviceSize blockSize = GetSize(); + const VkDeviceSize debugMargin = GetDebugMargin(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - json.WriteString("UsedBytes"); - json.WriteNumber(stat.usedBytes); + if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + // Try to allocate at the end of 1st vector. - json.WriteString("UnusedBytes"); - json.WriteNumber(stat.unusedBytes); + VkDeviceSize resultBaseOffset = 0; + if (!suballocations1st.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations1st.back(); + resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + debugMargin; + } - if(stat.allocationCount > 1) - { - json.WriteString("AllocationSize"); - json.BeginObject(true); - json.WriteString("Min"); - json.WriteNumber(stat.allocationSizeMin); - json.WriteString("Avg"); - json.WriteNumber(stat.allocationSizeAvg); - json.WriteString("Max"); - json.WriteNumber(stat.allocationSizeMax); - json.EndObject(); - } + // Start from offset equal to beginning of free space. + VkDeviceSize resultOffset = resultBaseOffset; - if(stat.unusedRangeCount > 1) - { - json.WriteString("UnusedRangeSize"); - json.BeginObject(true); - json.WriteString("Min"); - json.WriteNumber(stat.unusedRangeSizeMin); - json.WriteString("Avg"); - json.WriteNumber(stat.unusedRangeSizeAvg); - json.WriteString("Max"); - json.WriteNumber(stat.unusedRangeSizeMax); - json.EndObject(); - } + // Apply alignment. + resultOffset = VmaAlignUp(resultOffset, allocAlignment); - json.EndObject(); -} + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); + } + } -#endif // #if VMA_STATS_STRING_ENABLED + const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? + suballocations2nd.back().offset : blockSize; -struct VmaSuballocationItemSizeLess -{ - bool operator()( - const VmaSuballocationList::iterator lhs, - const VmaSuballocationList::iterator rhs) const - { - return lhs->size < rhs->size; - } - bool operator()( - const VmaSuballocationList::iterator lhs, - VkDeviceSize rhsSize) const - { - return lhs->size < rhsSize; - } -}; + // There is enough free space at the end after alignment. + if (resultOffset + allocSize + debugMargin <= freeSpaceEnd) + { + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if ((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + for (size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) + { + const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on previous page. + break; + } + } + } + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + // pAllocationRequest->item, customData unused. + pAllocationRequest->type = VmaAllocationRequestType::EndOf1st; + return true; + } + } -//////////////////////////////////////////////////////////////////////////////// -// class VmaBlockMetadata + // Wrap-around to end of 2nd vector. Try to allocate there, watching for the + // beginning of 1st vector as the end of free space. + if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + VMA_ASSERT(!suballocations1st.empty()); -VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) : - m_Size(0), - m_pAllocationCallbacks(hAllocator->GetAllocationCallbacks()) -{ -} + VkDeviceSize resultBaseOffset = 0; + if (!suballocations2nd.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations2nd.back(); + resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + debugMargin; + } -#if VMA_STATS_STRING_ENABLED + // Start from offset equal to beginning of free space. + VkDeviceSize resultOffset = resultBaseOffset; -void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json, - VkDeviceSize unusedBytes, - size_t allocationCount, - size_t unusedRangeCount) const -{ - json.BeginObject(); + // Apply alignment. + resultOffset = VmaAlignUp(resultOffset, allocAlignment); - json.WriteString("TotalBytes"); - json.WriteNumber(GetSize()); + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); + } + } - json.WriteString("UnusedBytes"); - json.WriteNumber(unusedBytes); + size_t index1st = m_1stNullItemsBeginCount; - json.WriteString("Allocations"); - json.WriteNumber((uint64_t)allocationCount); + // There is enough free space at the end after alignment. + if ((index1st == suballocations1st.size() && resultOffset + allocSize + debugMargin <= blockSize) || + (index1st < suballocations1st.size() && resultOffset + allocSize + debugMargin <= suballocations1st[index1st].offset)) + { + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) + { + for (size_t nextSuballocIndex = index1st; + nextSuballocIndex < suballocations1st.size(); + nextSuballocIndex++) + { + const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + } + } - json.WriteString("UnusedRanges"); - json.WriteNumber((uint64_t)unusedRangeCount); + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd; + // pAllocationRequest->item, customData unused. + return true; + } + } - json.WriteString("Suballocations"); - json.BeginArray(); + return false; } -void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json, - VkDeviceSize offset, - VmaAllocation hAllocation) const -{ - json.BeginObject(true); - - json.WriteString("Offset"); - json.WriteNumber(offset); - - hAllocation->PrintParameters(json); - - json.EndObject(); -} - -void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, - VkDeviceSize offset, - VkDeviceSize size) const -{ - json.BeginObject(true); - - json.WriteString("Offset"); - json.WriteNumber(offset); - - json.WriteString("Type"); - json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]); - - json.WriteString("Size"); - json.WriteNumber(size); - - json.EndObject(); -} - -void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const -{ - json.EndArray(); - json.EndObject(); -} - -#endif // #if VMA_STATS_STRING_ENABLED - -//////////////////////////////////////////////////////////////////////////////// -// class VmaBlockMetadata_Generic - -VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(VmaAllocator hAllocator) : - VmaBlockMetadata(hAllocator), - m_FreeCount(0), - m_SumFreeSize(0), - m_Suballocations(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_FreeSuballocationsBySize(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ -} - -VmaBlockMetadata_Generic::~VmaBlockMetadata_Generic() -{ -} - -void VmaBlockMetadata_Generic::Init(VkDeviceSize size) +bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) { - VmaBlockMetadata::Init(size); + const VkDeviceSize blockSize = GetSize(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - m_FreeCount = 1; - m_SumFreeSize = size; + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer."); + return false; + } - VmaSuballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = size; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; + // Try to allocate before 2nd.back(), or end of block if 2nd.empty(). + if (allocSize > blockSize) + { + return false; + } + VkDeviceSize resultBaseOffset = blockSize - allocSize; + if (!suballocations2nd.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations2nd.back(); + resultBaseOffset = lastSuballoc.offset - allocSize; + if (allocSize > lastSuballoc.offset) + { + return false; + } + } - VMA_ASSERT(size > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER); - m_Suballocations.push_back(suballoc); - VmaSuballocationList::iterator suballocItem = m_Suballocations.end(); - --suballocItem; - m_FreeSuballocationsBySize.push_back(suballocItem); -} + // Start from offset equal to end of free space. + VkDeviceSize resultOffset = resultBaseOffset; -bool VmaBlockMetadata_Generic::Validate() const -{ - VMA_VALIDATE(!m_Suballocations.empty()); - - // Expected offset of new suballocation as calculated from previous ones. - VkDeviceSize calculatedOffset = 0; - // Expected number of free suballocations as calculated from traversing their list. - uint32_t calculatedFreeCount = 0; - // Expected sum size of free suballocations as calculated from traversing their list. - VkDeviceSize calculatedSumFreeSize = 0; - // Expected number of free suballocations that should be registered in - // m_FreeSuballocationsBySize calculated from traversing their list. - size_t freeSuballocationsToRegister = 0; - // True if previous visited suballocation was free. - bool prevFree = false; + const VkDeviceSize debugMargin = GetDebugMargin(); - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem) + // Apply debugMargin at the end. + if (debugMargin > 0) { - const VmaSuballocation& subAlloc = *suballocItem; - - // Actual offset of this suballocation doesn't match expected one. - VMA_VALIDATE(subAlloc.offset == calculatedOffset); - - const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE); - // Two adjacent free suballocations are invalid. They should be merged. - VMA_VALIDATE(!prevFree || !currFree); + if (resultOffset < debugMargin) + { + return false; + } + resultOffset -= debugMargin; + } - VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE)); + // Apply alignment. + resultOffset = VmaAlignDown(resultOffset, allocAlignment); - if(currFree) + // Check next suballocations from 2nd for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) { - calculatedSumFreeSize += subAlloc.size; - ++calculatedFreeCount; - if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) + const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) { - ++freeSuballocationsToRegister; + if (VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } } - - // Margin required between allocations - every free space must be at least that large. - VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN); + else + // Already on previous page. + break; } - else + if (bufferImageGranularityConflict) { - VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset); - VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size); - - // Margin required between allocations - previous allocation must be free. - VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree); + resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity); } - - calculatedOffset += subAlloc.size; - prevFree = currFree; } - // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't - // match expected one. - VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister); - - VkDeviceSize lastSize = 0; - for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) + // There is enough free space. + const VkDeviceSize endOf1st = !suballocations1st.empty() ? + suballocations1st.back().offset + suballocations1st.back().size : + 0; + if (endOf1st + debugMargin <= resultOffset) { - VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; - - // Only free suballocations can be registered in m_FreeSuballocationsBySize. - VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE); - // They must be sorted by size ascending. - VMA_VALIDATE(suballocItem->size >= lastSize); + // Check previous suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (bufferImageGranularity > 1) + { + for (size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + } + } - lastSize = suballocItem->size; + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + // pAllocationRequest->item unused. + pAllocationRequest->type = VmaAllocationRequestType::UpperAddress; + return true; } - // Check if totals match calculacted values. - VMA_VALIDATE(ValidateFreeSuballocationList()); - VMA_VALIDATE(calculatedOffset == GetSize()); - VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize); - VMA_VALIDATE(calculatedFreeCount == m_FreeCount); - - return true; + return false; } +#endif // _VMA_BLOCK_METADATA_LINEAR_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_LINEAR -VkDeviceSize VmaBlockMetadata_Generic::GetUnusedRangeSizeMax() const -{ - if(!m_FreeSuballocationsBySize.empty()) - { - return m_FreeSuballocationsBySize.back()->size; - } - else - { - return 0; - } -} +#if 0 +#ifndef _VMA_BLOCK_METADATA_BUDDY +/* +- GetSize() is the original size of allocated memory block. +- m_UsableSize is this size aligned down to a power of two. + All allocations and calculations happen relative to m_UsableSize. +- GetUnusableSize() is the difference between them. + It is reported as separate, unused range, not available for allocations. -bool VmaBlockMetadata_Generic::IsEmpty() const +Node at level 0 has size = m_UsableSize. +Each next level contains nodes with size 2 times smaller than current level. +m_LevelCount is the maximum number of levels to use in the current object. +*/ +class VmaBlockMetadata_Buddy : public VmaBlockMetadata { - return (m_Suballocations.size() == 1) && (m_FreeCount == 1); -} + VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy) +public: + VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Buddy(); -void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const -{ - outInfo.blockCount = 1; + size_t GetAllocationCount() const override { return m_AllocationCount; } + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize + GetUnusableSize(); } + bool IsEmpty() const override { return m_Root->type == Node::TYPE_FREE; } + VkResult CheckCorruption(const void* pBlockData) override { return VK_ERROR_FEATURE_NOT_PRESENT; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; } + void DebugLogAllAllocations() const override { DebugLogAllAllocationNode(m_Root, 0); } - const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); - outInfo.allocationCount = rangeCount - m_FreeCount; - outInfo.unusedRangeCount = m_FreeCount; - - outInfo.unusedBytes = m_SumFreeSize; - outInfo.usedBytes = GetSize() - outInfo.unusedBytes; + void Init(VkDeviceSize size) override; + bool Validate() const override; - outInfo.allocationSizeMin = UINT64_MAX; - outInfo.allocationSizeMax = 0; - outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMax = 0; + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem) - { - const VmaSuballocation& suballoc = *suballocItem; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size); - outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size); - } - else - { - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size); - outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size); - } - } -} +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; +#endif -void VmaBlockMetadata_Generic::AddPoolStats(VmaPoolStats& inoutStats) const -{ - const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; - inoutStats.size += GetSize(); - inoutStats.unusedSize += m_SumFreeSize; - inoutStats.allocationCount += rangeCount - m_FreeCount; - inoutStats.unusedRangeCount += m_FreeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax()); -} + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; -#if VMA_STATS_STRING_ENABLED + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; -void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const -{ - PrintDetailedMap_Begin(json, - m_SumFreeSize, // unusedBytes - m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount - m_FreeCount); // unusedRangeCount +private: + static const size_t MAX_LEVELS = 48; - size_t i = 0; - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem, ++i) + struct ValidationContext + { + size_t calculatedAllocationCount = 0; + size_t calculatedFreeCount = 0; + VkDeviceSize calculatedSumFreeSize = 0; + }; + struct Node { - if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE) + VkDeviceSize offset; + enum TYPE { - PrintDetailedMap_UnusedRange(json, suballocItem->offset, suballocItem->size); - } - else + TYPE_FREE, + TYPE_ALLOCATION, + TYPE_SPLIT, + TYPE_COUNT + } type; + Node* parent; + Node* buddy; + + union { - PrintDetailedMap_Allocation(json, suballocItem->offset, suballocItem->hAllocation); - } - } + struct + { + Node* prev; + Node* next; + } free; + struct + { + void* userData; + } allocation; + struct + { + Node* leftChild; + } split; + }; + }; - PrintDetailedMap_End(json); -} + // Size of the memory block aligned down to a power of two. + VkDeviceSize m_UsableSize; + uint32_t m_LevelCount; + VmaPoolAllocator m_NodeAllocator; + Node* m_Root; + struct + { + Node* front; + Node* back; + } m_FreeList[MAX_LEVELS]; -#endif // #if VMA_STATS_STRING_ENABLED + // Number of nodes in the tree with type == TYPE_ALLOCATION. + size_t m_AllocationCount; + // Number of nodes in the tree with type == TYPE_FREE. + size_t m_FreeCount; + // Doesn't include space wasted due to internal fragmentation - allocation sizes are just aligned up to node sizes. + // Doesn't include unusable size. + VkDeviceSize m_SumFreeSize; -bool VmaBlockMetadata_Generic::CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) + VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; } + VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; } + + VkDeviceSize AlignAllocationSize(VkDeviceSize size) const + { + if (!IsVirtual()) + { + size = VmaAlignUp(size, (VkDeviceSize)16); + } + return VmaNextPow2(size); + } + Node* FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const; + void DeleteNodeChildren(Node* node); + bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const; + uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const; + void AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const; + // Adds node to the front of FreeList at given level. + // node->type must be FREE. + // node->free.prev, next can be undefined. + void AddToFreeListFront(uint32_t level, Node* node); + // Removes node from FreeList at given level. + // node->type must be FREE. + // node->free.prev, next stay untouched. + void RemoveFromFreeList(uint32_t level, Node* node); + void DebugLogAllAllocationNode(Node* node, uint32_t level) const; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const; +#endif +}; + +#ifndef _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS +VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_NodeAllocator(pAllocationCallbacks, 32), // firstBlockCapacity + m_Root(VMA_NULL), + m_AllocationCount(0), + m_FreeCount(1), + m_SumFreeSize(0) { - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(!upperAddress); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(pAllocationRequest != VMA_NULL); - VMA_HEAVY_ASSERT(Validate()); + memset(m_FreeList, 0, sizeof(m_FreeList)); +} - pAllocationRequest->type = VmaAllocationRequestType::Normal; +VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy() +{ + DeleteNodeChildren(m_Root); + m_NodeAllocator.Free(m_Root); +} + +void VmaBlockMetadata_Buddy::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + + m_UsableSize = VmaPrevPow2(size); + m_SumFreeSize = m_UsableSize; - // There is not enough total free space in this block to fullfill the request: Early return. - if(canMakeOtherLost == false && - m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN) + // Calculate m_LevelCount. + const VkDeviceSize minNodeSize = IsVirtual() ? 1 : 16; + m_LevelCount = 1; + while (m_LevelCount < MAX_LEVELS && + LevelToNodeSize(m_LevelCount) >= minNodeSize) { - return false; + ++m_LevelCount; } - // New algorithm, efficiently searching freeSuballocationsBySize. - const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); - if(freeSuballocCount > 0) + Node* rootNode = m_NodeAllocator.Alloc(); + rootNode->offset = 0; + rootNode->type = Node::TYPE_FREE; + rootNode->parent = VMA_NULL; + rootNode->buddy = VMA_NULL; + + m_Root = rootNode; + AddToFreeListFront(0, rootNode); +} + +bool VmaBlockMetadata_Buddy::Validate() const +{ + // Validate tree. + ValidationContext ctx; + if (!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0))) { - if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT) - { - // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN. - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + freeSuballocCount, - allocSize + 2 * VMA_DEBUG_MARGIN, - VmaSuballocationItemSizeLess()); - size_t index = it - m_FreeSuballocationsBySize.data(); - for(; index < freeSuballocCount; ++index) - { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - false, // canMakeOtherLost - &pAllocationRequest->offset, - &pAllocationRequest->itemsToMakeLostCount, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET) + VMA_VALIDATE(false && "ValidateNode failed."); + } + VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount); + VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize); + + // Validate free node lists. + for (uint32_t level = 0; level < m_LevelCount; ++level) + { + VMA_VALIDATE(m_FreeList[level].front == VMA_NULL || + m_FreeList[level].front->free.prev == VMA_NULL); + + for (Node* node = m_FreeList[level].front; + node != VMA_NULL; + node = node->free.next) { - for(VmaSuballocationList::iterator it = m_Suballocations.begin(); - it != m_Suballocations.end(); - ++it) + VMA_VALIDATE(node->type == Node::TYPE_FREE); + + if (node->free.next == VMA_NULL) { - if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - it, - false, // canMakeOtherLost - &pAllocationRequest->offset, - &pAllocationRequest->itemsToMakeLostCount, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize)) - { - pAllocationRequest->item = it; - return true; - } + VMA_VALIDATE(m_FreeList[level].back == node); } - } - else // WORST_FIT, FIRST_FIT - { - // Search staring from biggest suballocations. - for(size_t index = freeSuballocCount; index--; ) + else { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - false, // canMakeOtherLost - &pAllocationRequest->offset, - &pAllocationRequest->itemsToMakeLostCount, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } + VMA_VALIDATE(node->free.next->free.prev == node); } } } - if(canMakeOtherLost) + // Validate that free lists ar higher levels are empty. + for (uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level) { - // Brute-force algorithm. TODO: Come up with something better. + VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL); + } - bool found = false; - VmaAllocationRequest tmpAllocRequest = {}; - tmpAllocRequest.type = VmaAllocationRequestType::Normal; - for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin(); - suballocIt != m_Suballocations.end(); - ++suballocIt) - { - if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE || - suballocIt->hAllocation->CanBecomeLost()) - { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - suballocIt, - canMakeOtherLost, - &tmpAllocRequest.offset, - &tmpAllocRequest.itemsToMakeLostCount, - &tmpAllocRequest.sumFreeSize, - &tmpAllocRequest.sumItemSize)) - { - if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT) - { - *pAllocationRequest = tmpAllocRequest; - pAllocationRequest->item = suballocIt; - break; - } - if(!found || tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost()) - { - *pAllocationRequest = tmpAllocRequest; - pAllocationRequest->item = suballocIt; - found = true; - } - } - } - } + return true; +} - return found; - } +void VmaBlockMetadata_Buddy::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); - return false; + AddNodeToDetailedStatistics(inoutStats, m_Root, LevelToNodeSize(0)); + + const VkDeviceSize unusableSize = GetUnusableSize(); + if (unusableSize > 0) + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusableSize); } -bool VmaBlockMetadata_Generic::MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest) +void VmaBlockMetadata_Buddy::AddStatistics(VmaStatistics& inoutStats) const +{ + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_AllocationCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - m_SumFreeSize; +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const { - VMA_ASSERT(pAllocationRequest && pAllocationRequest->type == VmaAllocationRequestType::Normal); + VmaDetailedStatistics stats; + VmaClearDetailedStatistics(stats); + AddDetailedStatistics(stats); - while(pAllocationRequest->itemsToMakeLostCount > 0) + PrintDetailedMap_Begin( + json, + stats.statistics.blockBytes - stats.statistics.allocationBytes, + stats.statistics.allocationCount, + stats.unusedRangeCount, + mapRefCount); + + PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0)); + + const VkDeviceSize unusableSize = GetUnusableSize(); + if (unusableSize > 0) { - if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE) - { - ++pAllocationRequest->item; - } - VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end()); - VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE); - VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost()); - if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item); - --pAllocationRequest->itemsToMakeLostCount; - } - else - { - return false; - } + PrintDetailedMap_UnusedRange(json, + m_UsableSize, // offset + unusableSize); // size } - VMA_HEAVY_ASSERT(Validate()); - VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end()); - VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE); - - return true; + PrintDetailedMap_End(json); } +#endif // VMA_STATS_STRING_ENABLED -uint32_t VmaBlockMetadata_Generic::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) +bool VmaBlockMetadata_Buddy::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) { - uint32_t lostAllocationCount = 0; - for(VmaSuballocationList::iterator it = m_Suballocations.begin(); - it != m_Suballocations.end(); - ++it) + VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); + + allocSize = AlignAllocationSize(allocSize); + + // Simple way to respect bufferImageGranularity. May be optimized some day. + // Whenever it might be an OPTIMAL image... + if (allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) { - if(it->type != VMA_SUBALLOCATION_TYPE_FREE && - it->hAllocation->CanBecomeLost() && - it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - it = FreeSuballocation(it); - ++lostAllocationCount; - } + allocAlignment = VMA_MAX(allocAlignment, GetBufferImageGranularity()); + allocSize = VmaAlignUp(allocSize, GetBufferImageGranularity()); } - return lostAllocationCount; -} -VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData) -{ - for(VmaSuballocationList::iterator it = m_Suballocations.begin(); - it != m_Suballocations.end(); - ++it) + if (allocSize > m_UsableSize) + { + return false; + } + + const uint32_t targetLevel = AllocSizeToLevel(allocSize); + for (uint32_t level = targetLevel; level--; ) { - if(it->type != VMA_SUBALLOCATION_TYPE_FREE) + for (Node* freeNode = m_FreeList[level].front; + freeNode != VMA_NULL; + freeNode = freeNode->free.next) { - if(!VmaValidateMagicValue(pBlockData, it->offset - VMA_DEBUG_MARGIN)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if(!VmaValidateMagicValue(pBlockData, it->offset + it->size)) + if (freeNode->offset % allocAlignment == 0) { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; + pAllocationRequest->type = VmaAllocationRequestType::Normal; + pAllocationRequest->allocHandle = (VmaAllocHandle)(freeNode->offset + 1); + pAllocationRequest->size = allocSize; + pAllocationRequest->customData = (void*)(uintptr_t)level; + return true; } } } - return VK_SUCCESS; + return false; } -void VmaBlockMetadata_Generic::Alloc( +void VmaBlockMetadata_Buddy::Alloc( const VmaAllocationRequest& request, VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation) + void* userData) { VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); - VMA_ASSERT(request.item != m_Suballocations.end()); - VmaSuballocation& suballoc = *request.item; - // Given suballocation is a free block. - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - // Given offset is inside this suballocation. - VMA_ASSERT(request.offset >= suballoc.offset); - const VkDeviceSize paddingBegin = request.offset - suballoc.offset; - VMA_ASSERT(suballoc.size >= paddingBegin + allocSize); - const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize; - - // Unregister this free suballocation from m_FreeSuballocationsBySize and update - // it to become used. - UnregisterFreeSuballocation(request.item); - suballoc.offset = request.offset; - suballoc.size = allocSize; - suballoc.type = type; - suballoc.hAllocation = hAllocation; + const uint32_t targetLevel = AllocSizeToLevel(request.size); + uint32_t currLevel = (uint32_t)(uintptr_t)request.customData; - // If there are any free bytes remaining at the end, insert new free suballocation after current one. - if(paddingEnd) + Node* currNode = m_FreeList[currLevel].front; + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + const VkDeviceSize offset = (VkDeviceSize)request.allocHandle - 1; + while (currNode->offset != offset) { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = request.offset + allocSize; - paddingSuballoc.size = paddingEnd; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - VmaSuballocationList::iterator next = request.item; - ++next; - const VmaSuballocationList::iterator paddingEndItem = - m_Suballocations.insert(next, paddingSuballoc); - RegisterFreeSuballocation(paddingEndItem); + currNode = currNode->free.next; + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); } - // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. - if(paddingBegin) + // Go down, splitting free nodes. + while (currLevel < targetLevel) { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = request.offset - paddingBegin; - paddingSuballoc.size = paddingBegin; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - const VmaSuballocationList::iterator paddingBeginItem = - m_Suballocations.insert(request.item, paddingSuballoc); - RegisterFreeSuballocation(paddingBeginItem); - } + // currNode is already first free node at currLevel. + // Remove it from list of free nodes at this currLevel. + RemoveFromFreeList(currLevel, currNode); + + const uint32_t childrenLevel = currLevel + 1; + + // Create two free sub-nodes. + Node* leftChild = m_NodeAllocator.Alloc(); + Node* rightChild = m_NodeAllocator.Alloc(); + + leftChild->offset = currNode->offset; + leftChild->type = Node::TYPE_FREE; + leftChild->parent = currNode; + leftChild->buddy = rightChild; + + rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel); + rightChild->type = Node::TYPE_FREE; + rightChild->parent = currNode; + rightChild->buddy = leftChild; + + // Convert current currNode to split type. + currNode->type = Node::TYPE_SPLIT; + currNode->split.leftChild = leftChild; + + // Add child nodes to free list. Order is important! + AddToFreeListFront(childrenLevel, rightChild); + AddToFreeListFront(childrenLevel, leftChild); - // Update totals. - m_FreeCount = m_FreeCount - 1; - if(paddingBegin > 0) - { - ++m_FreeCount; - } - if(paddingEnd > 0) - { ++m_FreeCount; + ++currLevel; + currNode = m_FreeList[currLevel].front; + + /* + We can be sure that currNode, as left child of node previously split, + also fulfills the alignment requirement. + */ } - m_SumFreeSize -= allocSize; + + // Remove from free list. + VMA_ASSERT(currLevel == targetLevel && + currNode != VMA_NULL && + currNode->type == Node::TYPE_FREE); + RemoveFromFreeList(currLevel, currNode); + + // Convert to allocation node. + currNode->type = Node::TYPE_ALLOCATION; + currNode->allocation.userData = userData; + + ++m_AllocationCount; + --m_FreeCount; + m_SumFreeSize -= request.size; } -void VmaBlockMetadata_Generic::Free(const VmaAllocation allocation) +void VmaBlockMetadata_Buddy::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) { - for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin(); - suballocItem != m_Suballocations.end(); - ++suballocItem) - { - VmaSuballocation& suballoc = *suballocItem; - if(suballoc.hAllocation == allocation) - { - FreeSuballocation(suballocItem); - VMA_HEAVY_ASSERT(Validate()); - return; - } - } - VMA_ASSERT(0 && "Not found!"); + uint32_t level = 0; + outInfo.offset = (VkDeviceSize)allocHandle - 1; + const Node* const node = FindAllocationNode(outInfo.offset, level); + outInfo.size = LevelToNodeSize(level); + outInfo.pUserData = node->allocation.userData; } -void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset) +void* VmaBlockMetadata_Buddy::GetAllocationUserData(VmaAllocHandle allocHandle) const { - for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin(); - suballocItem != m_Suballocations.end(); - ++suballocItem) - { - VmaSuballocation& suballoc = *suballocItem; - if(suballoc.offset == offset) - { - FreeSuballocation(suballocItem); - return; - } - } - VMA_ASSERT(0 && "Not found!"); + uint32_t level = 0; + const Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); + return node->allocation.userData; } -bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const +VmaAllocHandle VmaBlockMetadata_Buddy::GetAllocationListBegin() const { - VkDeviceSize lastSize = 0; - for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) - { - const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i]; + // Function only used for defragmentation, which is disabled for this algorithm + return VK_NULL_HANDLE; +} - VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER); - VMA_VALIDATE(it->size >= lastSize); - lastSize = it->size; +VmaAllocHandle VmaBlockMetadata_Buddy::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + // Function only used for defragmentation, which is disabled for this algorithm + return VK_NULL_HANDLE; +} + +void VmaBlockMetadata_Buddy::DeleteNodeChildren(Node* node) +{ + if (node->type == Node::TYPE_SPLIT) + { + DeleteNodeChildren(node->split.leftChild->buddy); + DeleteNodeChildren(node->split.leftChild); + const VkAllocationCallbacks* allocationCallbacks = GetAllocationCallbacks(); + m_NodeAllocator.Free(node->split.leftChild->buddy); + m_NodeAllocator.Free(node->split.leftChild); } - return true; } -bool VmaBlockMetadata_Generic::CheckAllocation( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - VmaSuballocationList::const_iterator suballocItem, - bool canMakeOtherLost, - VkDeviceSize* pOffset, - size_t* itemsToMakeLostCount, - VkDeviceSize* pSumFreeSize, - VkDeviceSize* pSumItemSize) const +void VmaBlockMetadata_Buddy::Clear() { - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(suballocItem != m_Suballocations.cend()); - VMA_ASSERT(pOffset != VMA_NULL); - - *itemsToMakeLostCount = 0; - *pSumFreeSize = 0; - *pSumItemSize = 0; + DeleteNodeChildren(m_Root); + m_Root->type = Node::TYPE_FREE; + m_AllocationCount = 0; + m_FreeCount = 1; + m_SumFreeSize = m_UsableSize; +} + +void VmaBlockMetadata_Buddy::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + uint32_t level = 0; + Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); + node->allocation.userData = userData; +} - if(canMakeOtherLost) +VmaBlockMetadata_Buddy::Node* VmaBlockMetadata_Buddy::FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const +{ + Node* node = m_Root; + VkDeviceSize nodeOffset = 0; + outLevel = 0; + VkDeviceSize levelNodeSize = LevelToNodeSize(0); + while (node->type == Node::TYPE_SPLIT) { - if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE) + const VkDeviceSize nextLevelNodeSize = levelNodeSize >> 1; + if (offset < nodeOffset + nextLevelNodeSize) { - *pSumFreeSize = suballocItem->size; + node = node->split.leftChild; } else { - if(suballocItem->hAllocation->CanBecomeLost() && - suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - *pSumItemSize = suballocItem->size; - } - else - { - return false; - } + node = node->split.leftChild->buddy; + nodeOffset += nextLevelNodeSize; } + ++outLevel; + levelNodeSize = nextLevelNodeSize; + } - // Remaining size is too small for this request: Early return. - if(GetSize() - suballocItem->offset < allocSize) - { - return false; - } + VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION); + return node; +} - // Start from offset equal to beginning of this suballocation. - *pOffset = suballocItem->offset; - - // Apply VMA_DEBUG_MARGIN at the beginning. - if(VMA_DEBUG_MARGIN > 0) +bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const +{ + VMA_VALIDATE(level < m_LevelCount); + VMA_VALIDATE(curr->parent == parent); + VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL)); + VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr); + switch (curr->type) + { + case Node::TYPE_FREE: + // curr->free.prev, next are validated separately. + ctx.calculatedSumFreeSize += levelNodeSize; + ++ctx.calculatedFreeCount; + break; + case Node::TYPE_ALLOCATION: + ++ctx.calculatedAllocationCount; + if (!IsVirtual()) { - *pOffset += VMA_DEBUG_MARGIN; + VMA_VALIDATE(curr->allocation.userData != VMA_NULL); } - - // Apply alignment. - *pOffset = VmaAlignUp(*pOffset, allocAlignment); - - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1) + break; + case Node::TYPE_SPLIT: + { + const uint32_t childrenLevel = level + 1; + const VkDeviceSize childrenLevelNodeSize = levelNodeSize >> 1; + const Node* const leftChild = curr->split.leftChild; + VMA_VALIDATE(leftChild != VMA_NULL); + VMA_VALIDATE(leftChild->offset == curr->offset); + if (!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize)) { - bool bufferImageGranularityConflict = false; - VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; - while(prevSuballocItem != m_Suballocations.cbegin()) - { - --prevSuballocItem; - const VmaSuballocation& prevSuballoc = *prevSuballocItem; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity); - } + VMA_VALIDATE(false && "ValidateNode for left child failed."); } - - // Now that we have final *pOffset, check if we are past suballocItem. - // If yes, return false - this function should be called for another suballocItem as starting point. - if(*pOffset >= suballocItem->offset + suballocItem->size) + const Node* const rightChild = leftChild->buddy; + VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize); + if (!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize)) { - return false; + VMA_VALIDATE(false && "ValidateNode for right child failed."); } - - // Calculate padding at the beginning based on current offset. - const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset; + } + break; + default: + return false; + } - // Calculate required margin at the end. - const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN; + return true; +} - const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin; - // Another early return check. - if(suballocItem->offset + totalSize > GetSize()) - { - return false; - } +uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const +{ + // I know this could be optimized somehow e.g. by using std::log2p1 from C++20. + uint32_t level = 0; + VkDeviceSize currLevelNodeSize = m_UsableSize; + VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1; + while (allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount) + { + ++level; + currLevelNodeSize >>= 1; + nextLevelNodeSize >>= 1; + } + return level; +} - // Advance lastSuballocItem until desired size is reached. - // Update itemsToMakeLostCount. - VmaSuballocationList::const_iterator lastSuballocItem = suballocItem; - if(totalSize > suballocItem->size) - { - VkDeviceSize remainingSize = totalSize - suballocItem->size; - while(remainingSize > 0) - { - ++lastSuballocItem; - if(lastSuballocItem == m_Suballocations.cend()) - { - return false; - } - if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - *pSumFreeSize += lastSuballocItem->size; - } - else - { - VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE); - if(lastSuballocItem->hAllocation->CanBecomeLost() && - lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - *pSumItemSize += lastSuballocItem->size; - } - else - { - return false; - } - } - remainingSize = (lastSuballocItem->size < remainingSize) ? - remainingSize - lastSuballocItem->size : 0; - } - } +void VmaBlockMetadata_Buddy::Free(VmaAllocHandle allocHandle) +{ + uint32_t level = 0; + Node* node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, we must mark more allocations lost or fail. - if(bufferImageGranularity > 1) - { - VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem; - ++nextSuballocItem; - while(nextSuballocItem != m_Suballocations.cend()) - { - const VmaSuballocation& nextSuballoc = *nextSuballocItem; - if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE); - if(nextSuballoc.hAllocation->CanBecomeLost() && - nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - } - else - { - return false; - } - } - } - else - { - // Already on next page. - break; - } - ++nextSuballocItem; - } - } - } - else - { - const VmaSuballocation& suballoc = *suballocItem; - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + ++m_FreeCount; + --m_AllocationCount; + m_SumFreeSize += LevelToNodeSize(level); - *pSumFreeSize = suballoc.size; + node->type = Node::TYPE_FREE; - // Size of this suballocation is too small for this request: Early return. - if(suballoc.size < allocSize) - { - return false; - } + // Join free nodes if possible. + while (level > 0 && node->buddy->type == Node::TYPE_FREE) + { + RemoveFromFreeList(level, node->buddy); + Node* const parent = node->parent; - // Start from offset equal to beginning of this suballocation. - *pOffset = suballoc.offset; - - // Apply VMA_DEBUG_MARGIN at the beginning. - if(VMA_DEBUG_MARGIN > 0) - { - *pOffset += VMA_DEBUG_MARGIN; - } - - // Apply alignment. - *pOffset = VmaAlignUp(*pOffset, allocAlignment); - - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1) - { - bool bufferImageGranularityConflict = false; - VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; - while(prevSuballocItem != m_Suballocations.cbegin()) - { - --prevSuballocItem; - const VmaSuballocation& prevSuballoc = *prevSuballocItem; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity); - } - } - - // Calculate padding at the beginning based on current offset. - const VkDeviceSize paddingBegin = *pOffset - suballoc.offset; + m_NodeAllocator.Free(node->buddy); + m_NodeAllocator.Free(node); + parent->type = Node::TYPE_FREE; - // Calculate required margin at the end. - const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN; + node = parent; + --level; + --m_FreeCount; + } - // Fail if requested size plus margin before and after is bigger than size of this suballocation. - if(paddingBegin + allocSize + requiredEndMargin > suballoc.size) - { - return false; - } + AddToFreeListFront(level, node); +} - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if(bufferImageGranularity > 1) - { - VmaSuballocationList::const_iterator nextSuballocItem = suballocItem; - ++nextSuballocItem; - while(nextSuballocItem != m_Suballocations.cend()) - { - const VmaSuballocation& nextSuballoc = *nextSuballocItem; - if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - return false; - } - } - else - { - // Already on next page. - break; - } - ++nextSuballocItem; - } - } +void VmaBlockMetadata_Buddy::AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const +{ + switch (node->type) + { + case Node::TYPE_FREE: + VmaAddDetailedStatisticsUnusedRange(inoutStats, levelNodeSize); + break; + case Node::TYPE_ALLOCATION: + VmaAddDetailedStatisticsAllocation(inoutStats, levelNodeSize); + break; + case Node::TYPE_SPLIT: + { + const VkDeviceSize childrenNodeSize = levelNodeSize / 2; + const Node* const leftChild = node->split.leftChild; + AddNodeToDetailedStatistics(inoutStats, leftChild, childrenNodeSize); + const Node* const rightChild = leftChild->buddy; + AddNodeToDetailedStatistics(inoutStats, rightChild, childrenNodeSize); + } + break; + default: + VMA_ASSERT(0); } - - // All tests passed: Success. pOffset is already filled. - return true; } -void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item) +void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node) { - VMA_ASSERT(item != m_Suballocations.end()); - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - - VmaSuballocationList::iterator nextItem = item; - ++nextItem; - VMA_ASSERT(nextItem != m_Suballocations.end()); - VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(node->type == Node::TYPE_FREE); - item->size += nextItem->size; - --m_FreeCount; - m_Suballocations.erase(nextItem); + // List is empty. + Node* const frontNode = m_FreeList[level].front; + if (frontNode == VMA_NULL) + { + VMA_ASSERT(m_FreeList[level].back == VMA_NULL); + node->free.prev = node->free.next = VMA_NULL; + m_FreeList[level].front = m_FreeList[level].back = node; + } + else + { + VMA_ASSERT(frontNode->free.prev == VMA_NULL); + node->free.prev = VMA_NULL; + node->free.next = frontNode; + frontNode->free.prev = node; + m_FreeList[level].front = node; + } } -VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem) +void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node) { - // Change this suballocation to be marked as free. - VmaSuballocation& suballoc = *suballocItem; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - - // Update totals. - ++m_FreeCount; - m_SumFreeSize += suballoc.size; + VMA_ASSERT(m_FreeList[level].front != VMA_NULL); - // Merge with previous and/or next suballocation if it's also free. - bool mergeWithNext = false; - bool mergeWithPrev = false; - - VmaSuballocationList::iterator nextItem = suballocItem; - ++nextItem; - if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)) + // It is at the front. + if (node->free.prev == VMA_NULL) { - mergeWithNext = true; + VMA_ASSERT(m_FreeList[level].front == node); + m_FreeList[level].front = node->free.next; } - - VmaSuballocationList::iterator prevItem = suballocItem; - if(suballocItem != m_Suballocations.begin()) + else { - --prevItem; - if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - mergeWithPrev = true; - } + Node* const prevFreeNode = node->free.prev; + VMA_ASSERT(prevFreeNode->free.next == node); + prevFreeNode->free.next = node->free.next; } - if(mergeWithNext) + // It is at the back. + if (node->free.next == VMA_NULL) { - UnregisterFreeSuballocation(nextItem); - MergeFreeWithNext(suballocItem); + VMA_ASSERT(m_FreeList[level].back == node); + m_FreeList[level].back = node->free.prev; + } + else + { + Node* const nextFreeNode = node->free.next; + VMA_ASSERT(nextFreeNode->free.prev == node); + nextFreeNode->free.prev = node->free.prev; } +} - if(mergeWithPrev) +void VmaBlockMetadata_Buddy::DebugLogAllAllocationNode(Node* node, uint32_t level) const +{ + switch (node->type) { - UnregisterFreeSuballocation(prevItem); - MergeFreeWithNext(prevItem); - RegisterFreeSuballocation(prevItem); - return prevItem; + case Node::TYPE_FREE: + break; + case Node::TYPE_ALLOCATION: + DebugLogAllocation(node->offset, LevelToNodeSize(level), node->allocation.userData); + break; + case Node::TYPE_SPLIT: + { + ++level; + DebugLogAllAllocationNode(node->split.leftChild, level); + DebugLogAllAllocationNode(node->split.leftChild->buddy, level); } - else + break; + default: + VMA_ASSERT(0); + } +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const +{ + switch (node->type) { - RegisterFreeSuballocation(suballocItem); - return suballocItem; + case Node::TYPE_FREE: + PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize); + break; + case Node::TYPE_ALLOCATION: + PrintDetailedMap_Allocation(json, node->offset, levelNodeSize, node->allocation.userData); + break; + case Node::TYPE_SPLIT: + { + const VkDeviceSize childrenNodeSize = levelNodeSize / 2; + const Node* const leftChild = node->split.leftChild; + PrintDetailedMapNode(json, leftChild, childrenNodeSize); + const Node* const rightChild = leftChild->buddy; + PrintDetailedMapNode(json, rightChild, childrenNodeSize); + } + break; + default: + VMA_ASSERT(0); } } +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_BUDDY +#endif // #if 0 -void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item) +#ifndef _VMA_BLOCK_METADATA_TLSF +// To not search current larger region if first allocation won't succeed and skip to smaller range +// use with VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT as strategy in CreateAllocationRequest(). +// When fragmentation and reusal of previous blocks doesn't matter then use with +// VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT for fastest alloc time possible. +class VmaBlockMetadata_TLSF : public VmaBlockMetadata { - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); + VMA_CLASS_NO_COPY(VmaBlockMetadata_TLSF) +public: + VmaBlockMetadata_TLSF(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_TLSF(); - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); + size_t GetAllocationCount() const override { return m_AllocCount; } + size_t GetFreeRegionsCount() const override { return m_BlocksFreeCount + 1; } + VkDeviceSize GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; } + bool IsEmpty() const override { return m_NullBlock->offset == 0; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; } + + void Init(VkDeviceSize size) override; + bool Validate() const override; + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json) const override; +#endif + + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; + + VkResult CheckCorruption(const void* pBlockData) override; + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; + +private: + // According to original paper it should be preferable 4 or 5: + // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems" + // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf + static const uint8_t SECOND_LEVEL_INDEX = 5; + static const uint16_t SMALL_BUFFER_SIZE = 256; + static const uint32_t INITIAL_BLOCK_ALLOC_COUNT = 16; + static const uint8_t MEMORY_CLASS_SHIFT = 7; + static const uint8_t MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT; - if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) + class Block { - if(m_FreeSuballocationsBySize.empty()) - { - m_FreeSuballocationsBySize.push_back(item); - } - else + public: + VkDeviceSize offset; + VkDeviceSize size; + Block* prevPhysical; + Block* nextPhysical; + + void MarkFree() { prevFree = VMA_NULL; } + void MarkTaken() { prevFree = this; } + bool IsFree() const { return prevFree != this; } + void*& UserData() { VMA_HEAVY_ASSERT(!IsFree()); return userData; } + Block*& PrevFree() { return prevFree; } + Block*& NextFree() { VMA_HEAVY_ASSERT(IsFree()); return nextFree; } + + private: + Block* prevFree; // Address of the same block here indicates that block is taken + union { - VmaVectorInsertSorted(m_FreeSuballocationsBySize, item); - } - } + Block* nextFree; + void* userData; + }; + }; - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); + size_t m_AllocCount; + // Total number of free blocks besides null block + size_t m_BlocksFreeCount; + // Total size of free blocks excluding null block + VkDeviceSize m_BlocksFreeSize; + uint32_t m_IsFreeBitmap; + uint8_t m_MemoryClasses; + uint32_t m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES]; + uint32_t m_ListsCount; + /* + * 0: 0-3 lists for small buffers + * 1+: 0-(2^SLI-1) lists for normal buffers + */ + Block** m_FreeList; + VmaPoolAllocator m_BlockAllocator; + Block* m_NullBlock; + VmaBlockBufferImageGranularity m_GranularityHandler; + + uint8_t SizeToMemoryClass(VkDeviceSize size) const; + uint16_t SizeToSecondIndex(VkDeviceSize size, uint8_t memoryClass) const; + uint32_t GetListIndex(uint8_t memoryClass, uint16_t secondIndex) const; + uint32_t GetListIndex(VkDeviceSize size) const; + + void RemoveFreeBlock(Block* block); + void InsertFreeBlock(Block* block); + void MergeBlock(Block* block, Block* prev); + + Block* FindFreeBlock(VkDeviceSize size, uint32_t& listIndex) const; + bool CheckBlock( + Block& block, + uint32_t listIndex, + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaAllocationRequest* pAllocationRequest); +}; + +#ifndef _VMA_BLOCK_METADATA_TLSF_FUNCTIONS +VmaBlockMetadata_TLSF::VmaBlockMetadata_TLSF(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_AllocCount(0), + m_BlocksFreeCount(0), + m_BlocksFreeSize(0), + m_IsFreeBitmap(0), + m_MemoryClasses(0), + m_ListsCount(0), + m_FreeList(VMA_NULL), + m_BlockAllocator(pAllocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT), + m_NullBlock(VMA_NULL), + m_GranularityHandler(bufferImageGranularity) {} + +VmaBlockMetadata_TLSF::~VmaBlockMetadata_TLSF() +{ + if (m_FreeList) + vma_delete_array(GetAllocationCallbacks(), m_FreeList, m_ListsCount); + m_GranularityHandler.Destroy(GetAllocationCallbacks()); } +void VmaBlockMetadata_TLSF::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + + if (!IsVirtual()) + m_GranularityHandler.Init(GetAllocationCallbacks(), size); + + m_NullBlock = m_BlockAllocator.Alloc(); + m_NullBlock->size = size; + m_NullBlock->offset = 0; + m_NullBlock->prevPhysical = VMA_NULL; + m_NullBlock->nextPhysical = VMA_NULL; + m_NullBlock->MarkFree(); + m_NullBlock->NextFree() = VMA_NULL; + m_NullBlock->PrevFree() = VMA_NULL; + uint8_t memoryClass = SizeToMemoryClass(size); + uint16_t sli = SizeToSecondIndex(size, memoryClass); + m_ListsCount = (memoryClass == 0 ? 0 : (memoryClass - 1) * (1UL << SECOND_LEVEL_INDEX) + sli) + 1; + if (IsVirtual()) + m_ListsCount += 1UL << SECOND_LEVEL_INDEX; + else + m_ListsCount += 4; -void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item) + m_MemoryClasses = memoryClass + 2; + memset(m_InnerIsFreeBitmap, 0, MAX_MEMORY_CLASSES * sizeof(uint32_t)); + + m_FreeList = vma_new_array(GetAllocationCallbacks(), Block*, m_ListsCount); + memset(m_FreeList, 0, m_ListsCount * sizeof(Block*)); +} + +bool VmaBlockMetadata_TLSF::Validate() const { - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); + VMA_VALIDATE(GetSumFreeSize() <= GetSize()); - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); + VkDeviceSize calculatedSize = m_NullBlock->size; + VkDeviceSize calculatedFreeSize = m_NullBlock->size; + size_t allocCount = 0; + size_t freeCount = 0; - if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) + // Check integrity of free lists + for (uint32_t list = 0; list < m_ListsCount; ++list) { - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), - item, - VmaSuballocationItemSizeLess()); - for(size_t index = it - m_FreeSuballocationsBySize.data(); - index < m_FreeSuballocationsBySize.size(); - ++index) + Block* block = m_FreeList[list]; + if (block != VMA_NULL) { - if(m_FreeSuballocationsBySize[index] == item) + VMA_VALIDATE(block->IsFree()); + VMA_VALIDATE(block->PrevFree() == VMA_NULL); + while (block->NextFree()) { - VmaVectorRemove(m_FreeSuballocationsBySize, index); - return; + VMA_VALIDATE(block->NextFree()->IsFree()); + VMA_VALIDATE(block->NextFree()->PrevFree() == block); + block = block->NextFree(); } - VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); } - VMA_ASSERT(0 && "Not found."); } - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} + VkDeviceSize nextOffset = m_NullBlock->offset; + auto validateCtx = m_GranularityHandler.StartValidation(GetAllocationCallbacks(), IsVirtual()); -bool VmaBlockMetadata_Generic::IsBufferImageGranularityConflictPossible( - VkDeviceSize bufferImageGranularity, - VmaSuballocationType& inOutPrevSuballocType) const -{ - if(bufferImageGranularity == 1 || IsEmpty()) + VMA_VALIDATE(m_NullBlock->nextPhysical == VMA_NULL); + if (m_NullBlock->prevPhysical) { - return false; + VMA_VALIDATE(m_NullBlock->prevPhysical->nextPhysical == m_NullBlock); } - - VkDeviceSize minAlignment = VK_WHOLE_SIZE; - bool typeConflictFound = false; - for(VmaSuballocationList::const_iterator it = m_Suballocations.cbegin(); - it != m_Suballocations.cend(); - ++it) + // Check all blocks + for (Block* prev = m_NullBlock->prevPhysical; prev != VMA_NULL; prev = prev->prevPhysical) { - const VmaSuballocationType suballocType = it->type; - if(suballocType != VMA_SUBALLOCATION_TYPE_FREE) + VMA_VALIDATE(prev->offset + prev->size == nextOffset); + nextOffset = prev->offset; + calculatedSize += prev->size; + + uint32_t listIndex = GetListIndex(prev->size); + if (prev->IsFree()) { - minAlignment = VMA_MIN(minAlignment, it->hAllocation->GetAlignment()); - if(VmaIsBufferImageGranularityConflict(inOutPrevSuballocType, suballocType)) + ++freeCount; + // Check if free block belongs to free list + Block* freeBlock = m_FreeList[listIndex]; + VMA_VALIDATE(freeBlock != VMA_NULL); + + bool found = false; + do + { + if (freeBlock == prev) + found = true; + + freeBlock = freeBlock->NextFree(); + } while (!found && freeBlock != VMA_NULL); + + VMA_VALIDATE(found); + calculatedFreeSize += prev->size; + } + else + { + ++allocCount; + // Check if taken block is not on a free list + Block* freeBlock = m_FreeList[listIndex]; + while (freeBlock) + { + VMA_VALIDATE(freeBlock != prev); + freeBlock = freeBlock->NextFree(); + } + + if (!IsVirtual()) { - typeConflictFound = true; + VMA_VALIDATE(m_GranularityHandler.Validate(validateCtx, prev->offset, prev->size)); } - inOutPrevSuballocType = suballocType; + } + + if (prev->prevPhysical) + { + VMA_VALIDATE(prev->prevPhysical->nextPhysical == prev); } } - return typeConflictFound || minAlignment >= bufferImageGranularity; -} + if (!IsVirtual()) + { + VMA_VALIDATE(m_GranularityHandler.FinishValidation(validateCtx)); + } -//////////////////////////////////////////////////////////////////////////////// -// class VmaBlockMetadata_Linear + VMA_VALIDATE(nextOffset == 0); + VMA_VALIDATE(calculatedSize == GetSize()); + VMA_VALIDATE(calculatedFreeSize == GetSumFreeSize()); + VMA_VALIDATE(allocCount == m_AllocCount); + VMA_VALIDATE(freeCount == m_BlocksFreeCount); -VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(VmaAllocator hAllocator) : - VmaBlockMetadata(hAllocator), - m_SumFreeSize(0), - m_Suballocations0(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_Suballocations1(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_1stVectorIndex(0), - m_2ndVectorMode(SECOND_VECTOR_EMPTY), - m_1stNullItemsBeginCount(0), - m_1stNullItemsMiddleCount(0), - m_2ndNullItemsCount(0) -{ + return true; } -VmaBlockMetadata_Linear::~VmaBlockMetadata_Linear() +void VmaBlockMetadata_TLSF::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const { + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); + if (m_NullBlock->size > 0) + VmaAddDetailedStatisticsUnusedRange(inoutStats, m_NullBlock->size); + + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (block->IsFree()) + VmaAddDetailedStatisticsUnusedRange(inoutStats, block->size); + else + VmaAddDetailedStatisticsAllocation(inoutStats, block->size); + } } -void VmaBlockMetadata_Linear::Init(VkDeviceSize size) +void VmaBlockMetadata_TLSF::AddStatistics(VmaStatistics& inoutStats) const { - VmaBlockMetadata::Init(size); - m_SumFreeSize = size; + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_AllocCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - GetSumFreeSize(); } -bool VmaBlockMetadata_Linear::Validate() const +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_TLSF::PrintDetailedMap(class VmaJsonWriter& json) const { - const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - - VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY)); - VMA_VALIDATE(!suballocations1st.empty() || - suballocations2nd.empty() || - m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER); + size_t blockCount = m_AllocCount + m_BlocksFreeCount; + VmaStlAllocator allocator(GetAllocationCallbacks()); + VmaVector> blockList(blockCount, allocator); - if(!suballocations1st.empty()) + size_t i = blockCount; + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) { - // Null item at the beginning should be accounted into m_1stNullItemsBeginCount. - VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE); - // Null item at the end should be just pop_back(). - VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE); - } - if(!suballocations2nd.empty()) - { - // Null item at the end should be just pop_back(). - VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE); + blockList[--i] = block; } + VMA_ASSERT(i == 0); - VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size()); - VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size()); + VmaDetailedStatistics stats; + VmaClearDetailedStatistics(stats); + AddDetailedStatistics(stats); - VkDeviceSize sumUsedSize = 0; - const size_t suballoc1stCount = suballocations1st.size(); - VkDeviceSize offset = VMA_DEBUG_MARGIN; + PrintDetailedMap_Begin(json, + stats.statistics.blockBytes - stats.statistics.allocationBytes, + stats.statistics.allocationCount, + stats.unusedRangeCount); - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + for (; i < blockCount; ++i) { - const size_t suballoc2ndCount = suballocations2nd.size(); - size_t nullItem2ndCount = 0; - for(size_t i = 0; i < suballoc2ndCount; ++i) - { - const VmaSuballocation& suballoc = suballocations2nd[i]; - const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + Block* block = blockList[i]; + if (block->IsFree()) + PrintDetailedMap_UnusedRange(json, block->offset, block->size); + else + PrintDetailedMap_Allocation(json, block->offset, block->size, block->UserData()); + } + if (m_NullBlock->size > 0) + PrintDetailedMap_UnusedRange(json, m_NullBlock->offset, m_NullBlock->size); - VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE)); - VMA_VALIDATE(suballoc.offset >= offset); + PrintDetailedMap_End(json); +} +#endif - if(!currFree) - { - VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset); - VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size); - sumUsedSize += suballoc.size; - } - else - { - ++nullItem2ndCount; - } +bool VmaBlockMetadata_TLSF::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(allocSize > 0 && "Cannot allocate empty block!"); + VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); - offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN; - } + // For small granularity round up + if (!IsVirtual()) + m_GranularityHandler.RoundupAllocRequest(allocType, allocSize, allocAlignment); - VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); - } + allocSize += GetDebugMargin(); + // Quick check for too small pool + if (allocSize > GetSumFreeSize()) + return false; - for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i) + // If no free blocks in pool then check only null block + if (m_BlocksFreeCount == 0) + return CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest); + + // Round up to the next block + VkDeviceSize sizeForNextList = allocSize; + VkDeviceSize smallSizeStep = SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4); + if (allocSize > SMALL_BUFFER_SIZE) { - const VmaSuballocation& suballoc = suballocations1st[i]; - VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE && - suballoc.hAllocation == VK_NULL_HANDLE); + sizeForNextList += (1ULL << (VMA_BITSCAN_MSB(allocSize) - SECOND_LEVEL_INDEX)); } + else if (allocSize > SMALL_BUFFER_SIZE - smallSizeStep) + sizeForNextList = SMALL_BUFFER_SIZE + 1; + else + sizeForNextList += smallSizeStep; - size_t nullItem1stCount = m_1stNullItemsBeginCount; + uint32_t nextListIndex = 0; + uint32_t prevListIndex = 0; + Block* nextListBlock = VMA_NULL; + Block* prevListBlock = VMA_NULL; - for(size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i) + // Check blocks according to strategies + if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT) { - const VmaSuballocation& suballoc = suballocations1st[i]; - const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + // Quick check for larger block first + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + if (nextListBlock != VMA_NULL && CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; - VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE)); - VMA_VALIDATE(suballoc.offset >= offset); - VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree); + // If not fitted then null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; - if(!currFree) + // Null block failed, search larger bucket + while (nextListBlock) { - VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset); - VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size); - sumUsedSize += suballoc.size; + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); } - else + + // Failed again, check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) { - ++nullItem1stCount; + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); } - - offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN; } - VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount); - - if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT) { - const size_t suballoc2ndCount = suballocations2nd.size(); - size_t nullItem2ndCount = 0; - for(size_t i = suballoc2ndCount; i--; ) + // Check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) { - const VmaSuballocation& suballoc = suballocations2nd[i]; - const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - - VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE)); - VMA_VALIDATE(suballoc.offset >= offset); + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); + } - if(!currFree) - { - VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset); - VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size); - sumUsedSize += suballoc.size; - } - else - { - ++nullItem2ndCount; - } + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; - offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN; + // Check larger bucket + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + while (nextListBlock) + { + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); } - - VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); } + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT ) + { + // Perform search from the start + VmaStlAllocator allocator(GetAllocationCallbacks()); + VmaVector> blockList(m_BlocksFreeCount, allocator); - VMA_VALIDATE(offset <= GetSize()); - VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize); - - return true; -} + size_t i = m_BlocksFreeCount; + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (block->IsFree() && block->size >= allocSize) + blockList[--i] = block; + } -size_t VmaBlockMetadata_Linear::GetAllocationCount() const -{ - return AccessSuballocations1st().size() - (m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount) + - AccessSuballocations2nd().size() - m_2ndNullItemsCount; -} + for (; i < m_BlocksFreeCount; ++i) + { + Block& block = *blockList[i]; + if (CheckBlock(block, GetListIndex(block.size), allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + } -VkDeviceSize VmaBlockMetadata_Linear::GetUnusedRangeSizeMax() const -{ - const VkDeviceSize size = GetSize(); + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; - /* - We don't consider gaps inside allocation vectors with freed allocations because - they are not suitable for reuse in linear allocator. We consider only space that - is available for new allocations. - */ - if(IsEmpty()) - { - return size; + // Whole range searched, no more memory + return false; } - - const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - - switch(m_2ndVectorMode) + else { - case SECOND_VECTOR_EMPTY: - /* - Available space is after end of 1st, as well as before beginning of 1st (which - whould make it a ring buffer). - */ + // Check larger bucket + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + while (nextListBlock) { - const size_t suballocations1stCount = suballocations1st.size(); - VMA_ASSERT(suballocations1stCount > m_1stNullItemsBeginCount); - const VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount]; - const VmaSuballocation& lastSuballoc = suballocations1st[suballocations1stCount - 1]; - return VMA_MAX( - firstSuballoc.offset, - size - (lastSuballoc.offset + lastSuballoc.size)); + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); } - break; - case SECOND_VECTOR_RING_BUFFER: - /* - Available space is only between end of 2nd and beginning of 1st. - */ + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // Check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) { - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - const VmaSuballocation& lastSuballoc2nd = suballocations2nd.back(); - const VmaSuballocation& firstSuballoc1st = suballocations1st[m_1stNullItemsBeginCount]; - return firstSuballoc1st.offset - (lastSuballoc2nd.offset + lastSuballoc2nd.size); + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); } - break; + } - case SECOND_VECTOR_DOUBLE_STACK: - /* - Available space is only between end of 1st and top of 2nd. - */ + // Worst case, full search has to be done + while (++nextListIndex < m_ListsCount) + { + nextListBlock = m_FreeList[nextListIndex]; + while (nextListBlock) { - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - const VmaSuballocation& topSuballoc2nd = suballocations2nd.back(); - const VmaSuballocation& lastSuballoc1st = suballocations1st.back(); - return topSuballoc2nd.offset - (lastSuballoc1st.offset + lastSuballoc1st.size); + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); } - break; + } - default: - VMA_ASSERT(0); - return 0; + // No more memory sadly + return false; +} + +VkResult VmaBlockMetadata_TLSF::CheckCorruption(const void* pBlockData) +{ + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (!block->IsFree()) + { + if (!VmaValidateMagicValue(pBlockData, block->offset + block->size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } } + + return VK_SUCCESS; } -void VmaBlockMetadata_Linear::CalcAllocationStatInfo(VmaStatInfo& outInfo) const +void VmaBlockMetadata_TLSF::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) { - const VkDeviceSize size = GetSize(); - const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - const size_t suballoc1stCount = suballocations1st.size(); - const size_t suballoc2ndCount = suballocations2nd.size(); + VMA_ASSERT(request.type == VmaAllocationRequestType::TLSF); - outInfo.blockCount = 1; - outInfo.allocationCount = (uint32_t)GetAllocationCount(); - outInfo.unusedRangeCount = 0; - outInfo.usedBytes = 0; - outInfo.allocationSizeMin = UINT64_MAX; - outInfo.allocationSizeMax = 0; - outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMax = 0; + // Get block and pop it from the free list + Block* currentBlock = (Block*)request.allocHandle; + VkDeviceSize offset = request.algorithmData; + VMA_ASSERT(currentBlock != VMA_NULL); + VMA_ASSERT(currentBlock->offset <= offset); - VkDeviceSize lastOffset = 0; + if (currentBlock != m_NullBlock) + RemoveFreeBlock(currentBlock); - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + VkDeviceSize debugMargin = GetDebugMargin(); + VkDeviceSize misssingAlignment = offset - currentBlock->offset; + + // Append missing alignment to prev block or create new one + if (misssingAlignment) { - const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; - size_t nextAlloc2ndIndex = 0; - while(lastOffset < freeSpace2ndTo1stEnd) - { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc2ndIndex < suballoc2ndCount && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc2ndIndex; - } + Block* prevBlock = currentBlock->prevPhysical; + VMA_ASSERT(prevBlock != VMA_NULL && "There should be no missing alignment at offset 0!"); - // Found non-null allocation. - if(nextAlloc2ndIndex < suballoc2ndCount) + if (prevBlock->IsFree() && prevBlock->size != debugMargin) + { + uint32_t oldList = GetListIndex(prevBlock->size); + prevBlock->size += misssingAlignment; + // Check if new size crosses list bucket + if (oldList != GetListIndex(prevBlock->size)) { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - outInfo.usedBytes += suballoc.size; - outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size); - outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc2ndIndex; + prevBlock->size -= misssingAlignment; + RemoveFreeBlock(prevBlock); + prevBlock->size += misssingAlignment; + InsertFreeBlock(prevBlock); } - // We are at the end. else - { - // There is free space from lastOffset to freeSpace2ndTo1stEnd. - if(lastOffset < freeSpace2ndTo1stEnd) - { - const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } + m_BlocksFreeSize += misssingAlignment; + } + else + { + Block* newBlock = m_BlockAllocator.Alloc(); + currentBlock->prevPhysical = newBlock; + prevBlock->nextPhysical = newBlock; + newBlock->prevPhysical = prevBlock; + newBlock->nextPhysical = currentBlock; + newBlock->size = misssingAlignment; + newBlock->offset = currentBlock->offset; + newBlock->MarkTaken(); - // End of loop. - lastOffset = freeSpace2ndTo1stEnd; - } + InsertFreeBlock(newBlock); } + + currentBlock->size -= misssingAlignment; + currentBlock->offset += misssingAlignment; } - size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; - const VkDeviceSize freeSpace1stTo2ndEnd = - m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; - while(lastOffset < freeSpace1stTo2ndEnd) + VkDeviceSize size = request.size + debugMargin; + if (currentBlock->size == size) { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc1stIndex < suballoc1stCount && - suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE) + if (currentBlock == m_NullBlock) { - ++nextAlloc1stIndex; + // Setup new null block + m_NullBlock = m_BlockAllocator.Alloc(); + m_NullBlock->size = 0; + m_NullBlock->offset = currentBlock->offset + size; + m_NullBlock->prevPhysical = currentBlock; + m_NullBlock->nextPhysical = VMA_NULL; + m_NullBlock->MarkFree(); + m_NullBlock->PrevFree() = VMA_NULL; + m_NullBlock->NextFree() = VMA_NULL; + currentBlock->nextPhysical = m_NullBlock; + currentBlock->MarkTaken(); } + } + else + { + VMA_ASSERT(currentBlock->size > size && "Proper block already found, shouldn't find smaller one!"); - // Found non-null allocation. - if(nextAlloc1stIndex < suballoc1stCount) + // Create new free block + Block* newBlock = m_BlockAllocator.Alloc(); + newBlock->size = currentBlock->size - size; + newBlock->offset = currentBlock->offset + size; + newBlock->prevPhysical = currentBlock; + newBlock->nextPhysical = currentBlock->nextPhysical; + currentBlock->nextPhysical = newBlock; + currentBlock->size = size; + + if (currentBlock == m_NullBlock) { - const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - outInfo.usedBytes += suballoc.size; - outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size); - outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc1stIndex; + m_NullBlock = newBlock; + m_NullBlock->MarkFree(); + m_NullBlock->NextFree() = VMA_NULL; + m_NullBlock->PrevFree() = VMA_NULL; + currentBlock->MarkTaken(); } - // We are at the end. else { - // There is free space from lastOffset to freeSpace1stTo2ndEnd. - if(lastOffset < freeSpace1stTo2ndEnd) - { - const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } - - // End of loop. - lastOffset = freeSpace1stTo2ndEnd; + newBlock->nextPhysical->prevPhysical = newBlock; + newBlock->MarkTaken(); + InsertFreeBlock(newBlock); } } + currentBlock->UserData() = userData; - if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + if (debugMargin > 0) { - size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; - while(lastOffset < size) - { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc2ndIndex != SIZE_MAX && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - --nextAlloc2ndIndex; - } + currentBlock->size -= debugMargin; + Block* newBlock = m_BlockAllocator.Alloc(); + newBlock->size = debugMargin; + newBlock->offset = currentBlock->offset + currentBlock->size; + newBlock->prevPhysical = currentBlock; + newBlock->nextPhysical = currentBlock->nextPhysical; + newBlock->MarkTaken(); + currentBlock->nextPhysical->prevPhysical = newBlock; + currentBlock->nextPhysical = newBlock; + InsertFreeBlock(newBlock); + } - // Found non-null allocation. - if(nextAlloc2ndIndex != SIZE_MAX) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - outInfo.usedBytes += suballoc.size; - outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size); - outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - --nextAlloc2ndIndex; - } - // We are at the end. - else - { - // There is free space from lastOffset to size. - if(lastOffset < size) - { - const VkDeviceSize unusedRangeSize = size - lastOffset; - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize); - outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize); - } + if (!IsVirtual()) + m_GranularityHandler.AllocPages((uint8_t)(uintptr_t)request.customData, + currentBlock->offset, currentBlock->size); + ++m_AllocCount; +} - // End of loop. - lastOffset = size; - } - } +void VmaBlockMetadata_TLSF::Free(VmaAllocHandle allocHandle) +{ + Block* block = (Block*)allocHandle; + Block* next = block->nextPhysical; + VMA_ASSERT(!block->IsFree() && "Block is already free!"); + + if (!IsVirtual()) + m_GranularityHandler.FreePages(block->offset, block->size); + --m_AllocCount; + + VkDeviceSize debugMargin = GetDebugMargin(); + if (debugMargin > 0) + { + RemoveFreeBlock(next); + MergeBlock(next, block); + block = next; + next = next->nextPhysical; + } + + // Try merging + Block* prev = block->prevPhysical; + if (prev != VMA_NULL && prev->IsFree() && prev->size != debugMargin) + { + RemoveFreeBlock(prev); + MergeBlock(block, prev); } - outInfo.unusedBytes = size - outInfo.usedBytes; + if (!next->IsFree()) + InsertFreeBlock(block); + else if (next == m_NullBlock) + MergeBlock(m_NullBlock, block); + else + { + RemoveFreeBlock(next); + MergeBlock(next, block); + InsertFreeBlock(next); + } } -void VmaBlockMetadata_Linear::AddPoolStats(VmaPoolStats& inoutStats) const +void VmaBlockMetadata_TLSF::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) { - const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - const VkDeviceSize size = GetSize(); - const size_t suballoc1stCount = suballocations1st.size(); - const size_t suballoc2ndCount = suballocations2nd.size(); + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Cannot get allocation info for free block!"); + outInfo.offset = block->offset; + outInfo.size = block->size; + outInfo.pUserData = block->UserData(); +} - inoutStats.size += size; +void* VmaBlockMetadata_TLSF::GetAllocationUserData(VmaAllocHandle allocHandle) const +{ + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Cannot get user data for free block!"); + return block->UserData(); +} - VkDeviceSize lastOffset = 0; +VmaAllocHandle VmaBlockMetadata_TLSF::GetAllocationListBegin() const +{ + if (m_AllocCount == 0) + return VK_NULL_HANDLE; - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + for (Block* block = m_NullBlock->prevPhysical; block; block = block->prevPhysical) { - const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; - size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount; - while(lastOffset < freeSpace2ndTo1stEnd) - { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex < suballoc2ndCount && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc2ndIndex; - } + if (!block->IsFree()) + return (VmaAllocHandle)block; + } + VMA_ASSERT(false && "If m_AllocCount > 0 then should find any allocation!"); + return VK_NULL_HANDLE; +} - // Found non-null allocation. - if(nextAlloc2ndIndex < suballoc2ndCount) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++inoutStats.allocationCount; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < freeSpace2ndTo1stEnd) - { - // There is free space from lastOffset to freeSpace2ndTo1stEnd. - const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } +VmaAllocHandle VmaBlockMetadata_TLSF::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + Block* startBlock = (Block*)prevAlloc; + VMA_ASSERT(!startBlock->IsFree() && "Incorrect block!"); - // End of loop. - lastOffset = freeSpace2ndTo1stEnd; - } - } + for (Block* block = startBlock->prevPhysical; block; block = block->prevPhysical) + { + if (!block->IsFree()) + return (VmaAllocHandle)block; } + return VK_NULL_HANDLE; +} - size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; - const VkDeviceSize freeSpace1stTo2ndEnd = - m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; - while(lastOffset < freeSpace1stTo2ndEnd) - { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc1stIndex < suballoc1stCount && - suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc1stIndex; - } +VkDeviceSize VmaBlockMetadata_TLSF::GetNextFreeRegionSize(VmaAllocHandle alloc) const +{ + Block* block = (Block*)alloc; + VMA_ASSERT(!block->IsFree() && "Incorrect block!"); - // Found non-null allocation. - if(nextAlloc1stIndex < suballoc1stCount) - { - const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++inoutStats.allocationCount; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc1stIndex; - } - // We are at the end. - else - { - if(lastOffset < freeSpace1stTo2ndEnd) - { - // There is free space from lastOffset to freeSpace1stTo2ndEnd. - const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } + if (block->prevPhysical) + return block->prevPhysical->IsFree() ? block->prevPhysical->size : 0; + return 0; +} - // End of loop. - lastOffset = freeSpace1stTo2ndEnd; - } +void VmaBlockMetadata_TLSF::Clear() +{ + m_AllocCount = 0; + m_BlocksFreeCount = 0; + m_BlocksFreeSize = 0; + m_IsFreeBitmap = 0; + m_NullBlock->offset = 0; + m_NullBlock->size = GetSize(); + Block* block = m_NullBlock->prevPhysical; + m_NullBlock->prevPhysical = VMA_NULL; + while (block) + { + Block* prev = block->prevPhysical; + m_BlockAllocator.Free(block); + block = prev; } + memset(m_FreeList, 0, m_ListsCount * sizeof(Block*)); + memset(m_InnerIsFreeBitmap, 0, m_MemoryClasses * sizeof(uint32_t)); + m_GranularityHandler.Clear(); +} - if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) - { - size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; - while(lastOffset < size) - { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex != SIZE_MAX && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - --nextAlloc2ndIndex; - } +void VmaBlockMetadata_TLSF::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Trying to set user data for not allocated block!"); + block->UserData() = userData; +} - // Found non-null allocation. - if(nextAlloc2ndIndex != SIZE_MAX) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++inoutStats.allocationCount; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - --nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < size) - { - // There is free space from lastOffset to size. - const VkDeviceSize unusedRangeSize = size - lastOffset; - inoutStats.unusedSize += unusedRangeSize; - ++inoutStats.unusedRangeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize); - } +void VmaBlockMetadata_TLSF::DebugLogAllAllocations() const +{ + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + if (!block->IsFree()) + DebugLogAllocation(block->offset, block->size, block->UserData()); +} - // End of loop. - lastOffset = size; - } - } +uint8_t VmaBlockMetadata_TLSF::SizeToMemoryClass(VkDeviceSize size) const +{ + if (size > SMALL_BUFFER_SIZE) + return VMA_BITSCAN_MSB(size) - MEMORY_CLASS_SHIFT; + return 0; +} + +uint16_t VmaBlockMetadata_TLSF::SizeToSecondIndex(VkDeviceSize size, uint8_t memoryClass) const +{ + if (memoryClass == 0) + { + if (IsVirtual()) + return static_cast((size - 1) / 8); + else + return static_cast((size - 1) / 64); } + return static_cast((size >> (memoryClass + MEMORY_CLASS_SHIFT - SECOND_LEVEL_INDEX)) ^ (1U << SECOND_LEVEL_INDEX)); } -#if VMA_STATS_STRING_ENABLED -void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const +uint32_t VmaBlockMetadata_TLSF::GetListIndex(uint8_t memoryClass, uint16_t secondIndex) const { - const VkDeviceSize size = GetSize(); - const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - const size_t suballoc1stCount = suballocations1st.size(); - const size_t suballoc2ndCount = suballocations2nd.size(); + if (memoryClass == 0) + return secondIndex; - // FIRST PASS + const uint32_t index = static_cast(memoryClass - 1) * (1 << SECOND_LEVEL_INDEX) + secondIndex; + if (IsVirtual()) + return index + (1 << SECOND_LEVEL_INDEX); + else + return index + 4; +} - size_t unusedRangeCount = 0; - VkDeviceSize usedBytes = 0; +uint32_t VmaBlockMetadata_TLSF::GetListIndex(VkDeviceSize size) const +{ + uint8_t memoryClass = SizeToMemoryClass(size); + return GetListIndex(memoryClass, SizeToSecondIndex(size, memoryClass)); +} - VkDeviceSize lastOffset = 0; +void VmaBlockMetadata_TLSF::RemoveFreeBlock(Block* block) +{ + VMA_ASSERT(block != m_NullBlock); + VMA_ASSERT(block->IsFree()); - size_t alloc2ndCount = 0; - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + if (block->NextFree() != VMA_NULL) + block->NextFree()->PrevFree() = block->PrevFree(); + if (block->PrevFree() != VMA_NULL) + block->PrevFree()->NextFree() = block->NextFree(); + else { - const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; - size_t nextAlloc2ndIndex = 0; - while(lastOffset < freeSpace2ndTo1stEnd) + uint8_t memClass = SizeToMemoryClass(block->size); + uint16_t secondIndex = SizeToSecondIndex(block->size, memClass); + uint32_t index = GetListIndex(memClass, secondIndex); + VMA_ASSERT(m_FreeList[index] == block); + m_FreeList[index] = block->NextFree(); + if (block->NextFree() == VMA_NULL) { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex < suballoc2ndCount && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc2ndIndex; - } - - // Found non-null allocation. - if(nextAlloc2ndIndex < suballoc2ndCount) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - ++unusedRangeCount; - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++alloc2ndCount; - usedBytes += suballoc.size; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < freeSpace2ndTo1stEnd) - { - // There is free space from lastOffset to freeSpace2ndTo1stEnd. - ++unusedRangeCount; - } - - // End of loop. - lastOffset = freeSpace2ndTo1stEnd; - } + m_InnerIsFreeBitmap[memClass] &= ~(1U << secondIndex); + if (m_InnerIsFreeBitmap[memClass] == 0) + m_IsFreeBitmap &= ~(1UL << memClass); } } + block->MarkTaken(); + block->UserData() = VMA_NULL; + --m_BlocksFreeCount; + m_BlocksFreeSize -= block->size; +} - size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; - size_t alloc1stCount = 0; - const VkDeviceSize freeSpace1stTo2ndEnd = - m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; - while(lastOffset < freeSpace1stTo2ndEnd) +void VmaBlockMetadata_TLSF::InsertFreeBlock(Block* block) +{ + VMA_ASSERT(block != m_NullBlock); + VMA_ASSERT(!block->IsFree() && "Cannot insert block twice!"); + + uint8_t memClass = SizeToMemoryClass(block->size); + uint16_t secondIndex = SizeToSecondIndex(block->size, memClass); + uint32_t index = GetListIndex(memClass, secondIndex); + VMA_ASSERT(index < m_ListsCount); + block->PrevFree() = VMA_NULL; + block->NextFree() = m_FreeList[index]; + m_FreeList[index] = block; + if (block->NextFree() != VMA_NULL) + block->NextFree()->PrevFree() = block; + else { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc1stIndex < suballoc1stCount && - suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc1stIndex; - } + m_InnerIsFreeBitmap[memClass] |= 1U << secondIndex; + m_IsFreeBitmap |= 1UL << memClass; + } + ++m_BlocksFreeCount; + m_BlocksFreeSize += block->size; +} - // Found non-null allocation. - if(nextAlloc1stIndex < suballoc1stCount) - { - const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - ++unusedRangeCount; - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++alloc1stCount; - usedBytes += suballoc.size; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc1stIndex; - } - // We are at the end. - else - { - if(lastOffset < size) - { - // There is free space from lastOffset to freeSpace1stTo2ndEnd. - ++unusedRangeCount; - } +void VmaBlockMetadata_TLSF::MergeBlock(Block* block, Block* prev) +{ + VMA_ASSERT(block->prevPhysical == prev && "Cannot merge separate physical regions!"); + VMA_ASSERT(!prev->IsFree() && "Cannot merge block that belongs to free list!"); - // End of loop. - lastOffset = freeSpace1stTo2ndEnd; - } - } + block->offset = prev->offset; + block->size += prev->size; + block->prevPhysical = prev->prevPhysical; + if (block->prevPhysical) + block->prevPhysical->nextPhysical = block; + m_BlockAllocator.Free(prev); +} - if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) +VmaBlockMetadata_TLSF::Block* VmaBlockMetadata_TLSF::FindFreeBlock(VkDeviceSize size, uint32_t& listIndex) const +{ + uint8_t memoryClass = SizeToMemoryClass(size); + uint32_t innerFreeMap = m_InnerIsFreeBitmap[memoryClass] & (~0U << SizeToSecondIndex(size, memoryClass)); + if (!innerFreeMap) { - size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; - while(lastOffset < size) - { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex != SIZE_MAX && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - --nextAlloc2ndIndex; - } - - // Found non-null allocation. - if(nextAlloc2ndIndex != SIZE_MAX) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - ++unusedRangeCount; - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - ++alloc2ndCount; - usedBytes += suballoc.size; - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - --nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < size) - { - // There is free space from lastOffset to size. - ++unusedRangeCount; - } + // Check higher levels for available blocks + uint32_t freeMap = m_IsFreeBitmap & (~0UL << (memoryClass + 1)); + if (!freeMap) + return VMA_NULL; // No more memory available - // End of loop. - lastOffset = size; - } - } + // Find lowest free region + memoryClass = VMA_BITSCAN_LSB(freeMap); + innerFreeMap = m_InnerIsFreeBitmap[memoryClass]; + VMA_ASSERT(innerFreeMap != 0); } + // Find lowest free subregion + listIndex = GetListIndex(memoryClass, VMA_BITSCAN_LSB(innerFreeMap)); + VMA_ASSERT(m_FreeList[listIndex]); + return m_FreeList[listIndex]; +} - const VkDeviceSize unusedBytes = size - usedBytes; - PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount); +bool VmaBlockMetadata_TLSF::CheckBlock( + Block& block, + uint32_t listIndex, + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(block.IsFree() && "Block is already taken!"); - // SECOND PASS - lastOffset = 0; + VkDeviceSize alignedOffset = VmaAlignUp(block.offset, allocAlignment); + if (block.size < allocSize + alignedOffset - block.offset) + return false; + + // Check for granularity conflicts + if (!IsVirtual() && + m_GranularityHandler.CheckConflictAndAlignUp(alignedOffset, allocSize, block.offset, block.size, allocType)) + return false; - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + // Alloc successful + pAllocationRequest->type = VmaAllocationRequestType::TLSF; + pAllocationRequest->allocHandle = (VmaAllocHandle)█ + pAllocationRequest->size = allocSize - GetDebugMargin(); + pAllocationRequest->customData = (void*)allocType; + pAllocationRequest->algorithmData = alignedOffset; + + // Place block at the start of list if it's normal block + if (listIndex != m_ListsCount && block.PrevFree()) { - const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; - size_t nextAlloc2ndIndex = 0; - while(lastOffset < freeSpace2ndTo1stEnd) - { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex < suballoc2ndCount && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc2ndIndex; - } + block.PrevFree()->NextFree() = block.NextFree(); + if (block.NextFree()) + block.NextFree()->PrevFree() = block.PrevFree(); + block.PrevFree() = VMA_NULL; + block.NextFree() = m_FreeList[listIndex]; + m_FreeList[listIndex] = █ + if (block.NextFree()) + block.NextFree()->PrevFree() = █ + } - // Found non-null allocation. - if(nextAlloc2ndIndex < suballoc2ndCount) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < freeSpace2ndTo1stEnd) - { - // There is free space from lastOffset to freeSpace2ndTo1stEnd. - const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } + return true; +} +#endif // _VMA_BLOCK_METADATA_TLSF_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_TLSF - // End of loop. - lastOffset = freeSpace2ndTo1stEnd; - } - } - } +#ifndef _VMA_BLOCK_VECTOR +/* +Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific +Vulkan memory type. - nextAlloc1stIndex = m_1stNullItemsBeginCount; - while(lastOffset < freeSpace1stTo2ndEnd) - { - // Find next non-null allocation or move nextAllocIndex to the end. - while(nextAlloc1stIndex < suballoc1stCount && - suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE) - { - ++nextAlloc1stIndex; - } +Synchronized internally with a mutex. +*/ +class VmaBlockVector +{ + friend struct VmaDefragmentationContext_T; + VMA_CLASS_NO_COPY(VmaBlockVector) +public: + VmaBlockVector( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceSize preferredBlockSize, + size_t minBlockCount, + size_t maxBlockCount, + VkDeviceSize bufferImageGranularity, + bool explicitBlockSize, + uint32_t algorithm, + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext); + ~VmaBlockVector(); - // Found non-null allocation. - if(nextAlloc1stIndex < suballoc1stCount) - { - const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - ++nextAlloc1stIndex; - } - // We are at the end. - else - { - if(lastOffset < freeSpace1stTo2ndEnd) - { - // There is free space from lastOffset to freeSpace1stTo2ndEnd. - const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } + VmaAllocator GetAllocator() const { return m_hAllocator; } + VmaPool GetParentPool() const { return m_hParentPool; } + bool IsCustomPool() const { return m_hParentPool != VMA_NULL; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; } + VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } + uint32_t GetAlgorithm() const { return m_Algorithm; } + bool HasExplicitBlockSize() const { return m_ExplicitBlockSize; } + float GetPriority() const { return m_Priority; } + const void* GetAllocationNextPtr() const { return m_pMemoryAllocateNext; } + // To be used only while the m_Mutex is locked. Used during defragmentation. + size_t GetBlockCount() const { return m_Blocks.size(); } + // To be used only while the m_Mutex is locked. Used during defragmentation. + VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; } + VMA_RW_MUTEX &GetMutex() { return m_Mutex; } - // End of loop. - lastOffset = freeSpace1stTo2ndEnd; - } - } + VkResult CreateMinBlocks(); + void AddStatistics(VmaStatistics& inoutStats); + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats); + bool IsEmpty(); + bool IsCorruptionDetectionEnabled() const; - if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) - { - size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; - while(lastOffset < size) - { - // Find next non-null allocation or move nextAlloc2ndIndex to the end. - while(nextAlloc2ndIndex != SIZE_MAX && - suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE) - { - --nextAlloc2ndIndex; - } + VkResult Allocate( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations); - // Found non-null allocation. - if(nextAlloc2ndIndex != SIZE_MAX) - { - const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - - // 1. Process free space before this allocation. - if(lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } - - // 2. Process this allocation. - // There is allocation with suballoc.offset, suballoc.size. - PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation); - - // 3. Prepare for next iteration. - lastOffset = suballoc.offset + suballoc.size; - --nextAlloc2ndIndex; - } - // We are at the end. - else - { - if(lastOffset < size) - { - // There is free space from lastOffset to size. - const VkDeviceSize unusedRangeSize = size - lastOffset; - PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); - } + void Free(const VmaAllocation hAllocation); - // End of loop. - lastOffset = size; - } - } - } +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json); +#endif - PrintDetailedMap_End(json); -} -#endif // #if VMA_STATS_STRING_ENABLED + VkResult CheckCorruption(); -bool VmaBlockMetadata_Linear::CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(pAllocationRequest != VMA_NULL); - VMA_HEAVY_ASSERT(Validate()); - return upperAddress ? - CreateAllocationRequest_UpperAddress( - currentFrameIndex, frameInUseCount, bufferImageGranularity, - allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest) : - CreateAllocationRequest_LowerAddress( - currentFrameIndex, frameInUseCount, bufferImageGranularity, - allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest); -} +private: + const VmaAllocator m_hAllocator; + const VmaPool m_hParentPool; + const uint32_t m_MemoryTypeIndex; + const VkDeviceSize m_PreferredBlockSize; + const size_t m_MinBlockCount; + const size_t m_MaxBlockCount; + const VkDeviceSize m_BufferImageGranularity; + const bool m_ExplicitBlockSize; + const uint32_t m_Algorithm; + const float m_Priority; + const VkDeviceSize m_MinAllocationAlignment; -bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) + void* const m_pMemoryAllocateNext; + VMA_RW_MUTEX m_Mutex; + // Incrementally sorted by sumFreeSize, ascending. + VmaVector> m_Blocks; + uint32_t m_NextBlockId; + bool m_IncrementalSort = true; + + void SetIncrementalSort(bool val) { m_IncrementalSort = val; } + + VkDeviceSize CalcMaxBlockSize() const; + // Finds and removes given block from vector. + void Remove(VmaDeviceMemoryBlock* pBlock); + // Performs single step in sorting m_Blocks. They may not be fully sorted + // after this call. + void IncrementallySortBlocks(); + void SortByFreeSize(); + + VkResult AllocatePage( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation); + + VkResult AllocateFromBlock( + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize size, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + uint32_t strategy, + VmaAllocation* pAllocation); + + VkResult CommitAllocationRequest( + VmaAllocationRequest& allocRequest, + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation); + + VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex); + bool HasEmptyBlock(); +}; +#endif // _VMA_BLOCK_VECTOR + +#ifndef _VMA_DEFRAGMENTATION_CONTEXT +struct VmaDefragmentationContext_T { - const VkDeviceSize size = GetSize(); - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + VMA_CLASS_NO_COPY(VmaDefragmentationContext_T) +public: + VmaDefragmentationContext_T( + VmaAllocator hAllocator, + const VmaDefragmentationInfo& info); + ~VmaDefragmentationContext_T(); - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) - { - VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer."); - return false; - } + void GetStats(VmaDefragmentationStats& outStats) { outStats = m_GlobalStats; } - // Try to allocate before 2nd.back(), or end of block if 2nd.empty(). - if(allocSize > size) + VkResult DefragmentPassBegin(VmaDefragmentationPassMoveInfo& moveInfo); + VkResult DefragmentPassEnd(VmaDefragmentationPassMoveInfo& moveInfo); + +private: + // Max number of allocations to ignore due to size constraints before ending single pass + static const uint8_t MAX_ALLOCS_TO_IGNORE = 16; + enum class CounterStatus { Pass, Ignore, End }; + + struct FragmentedBlock { - return false; - } - VkDeviceSize resultBaseOffset = size - allocSize; - if(!suballocations2nd.empty()) + uint32_t data; + VmaDeviceMemoryBlock* block; + }; + struct StateBalanced { - const VmaSuballocation& lastSuballoc = suballocations2nd.back(); - resultBaseOffset = lastSuballoc.offset - allocSize; - if(allocSize > lastSuballoc.offset) + VkDeviceSize avgFreeSize = 0; + VkDeviceSize avgAllocSize = UINT64_MAX; + }; + struct StateExtensive + { + enum class Operation : uint8_t { - return false; - } - } - - // Start from offset equal to end of free space. - VkDeviceSize resultOffset = resultBaseOffset; + FindFreeBlockBuffer, FindFreeBlockTexture, FindFreeBlockAll, + MoveBuffers, MoveTextures, MoveAll, + Cleanup, Done + }; - // Apply VMA_DEBUG_MARGIN at the end. - if(VMA_DEBUG_MARGIN > 0) + Operation operation = Operation::FindFreeBlockTexture; + size_t firstFreeBlock = SIZE_MAX; + }; + struct MoveAllocationData { - if(resultOffset < VMA_DEBUG_MARGIN) - { - return false; - } - resultOffset -= VMA_DEBUG_MARGIN; - } + VkDeviceSize size; + VkDeviceSize alignment; + VmaSuballocationType type; + VmaAllocationCreateFlags flags; + VmaDefragmentationMove move = {}; + }; - // Apply alignment. - resultOffset = VmaAlignDown(resultOffset, allocAlignment); + const VkDeviceSize m_MaxPassBytes; + const uint32_t m_MaxPassAllocations; + + VmaStlAllocator m_MoveAllocator; + VmaVector> m_Moves; + + uint8_t m_IgnoredAllocs = 0; + uint32_t m_Algorithm; + uint32_t m_BlockVectorCount; + VmaBlockVector* m_PoolBlockVector; + VmaBlockVector** m_pBlockVectors; + size_t m_ImmovableBlockCount = 0; + VmaDefragmentationStats m_GlobalStats = { 0 }; + VmaDefragmentationStats m_PassStats = { 0 }; + void* m_AlgorithmState = VMA_NULL; + + static MoveAllocationData GetMoveData(VmaAllocHandle handle, VmaBlockMetadata* metadata); + CounterStatus CheckCounters(VkDeviceSize bytes); + bool IncrementCounters(VkDeviceSize bytes); + bool ReallocWithinBlock(VmaBlockVector& vector, VmaDeviceMemoryBlock* block); + bool AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, VmaBlockVector& vector); + + bool ComputeDefragmentation(VmaBlockVector& vector, size_t index); + bool ComputeDefragmentation_Fast(VmaBlockVector& vector); + bool ComputeDefragmentation_Balanced(VmaBlockVector& vector, size_t index, bool update); + bool ComputeDefragmentation_Full(VmaBlockVector& vector); + bool ComputeDefragmentation_Extensive(VmaBlockVector& vector, size_t index); + + void UpdateVectorStatistics(VmaBlockVector& vector, StateBalanced& state); + bool MoveDataToFreeBlocks(VmaSuballocationType currentType, + VmaBlockVector& vector, size_t firstFreeBlock, + bool& texturePresent, bool& bufferPresent, bool& otherPresent); +}; +#endif // _VMA_DEFRAGMENTATION_CONTEXT - // Check next suballocations from 2nd for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1 && !suballocations2nd.empty()) - { - bool bufferImageGranularityConflict = false; - for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) - { - const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; - if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity); - } - } +#ifndef _VMA_POOL_T +struct VmaPool_T +{ + friend struct VmaPoolListItemTraits; + VMA_CLASS_NO_COPY(VmaPool_T) +public: + VmaBlockVector m_BlockVector; + VmaDedicatedAllocationList m_DedicatedAllocations; - // There is enough free space. - const VkDeviceSize endOf1st = !suballocations1st.empty() ? - suballocations1st.back().offset + suballocations1st.back().size : - 0; - if(endOf1st + VMA_DEBUG_MARGIN <= resultOffset) - { - // Check previous suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if(bufferImageGranularity > 1) - { - for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) - { - const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type)) - { - return false; - } - } - else - { - // Already on next page. - break; - } - } - } + VmaPool_T( + VmaAllocator hAllocator, + const VmaPoolCreateInfo& createInfo, + VkDeviceSize preferredBlockSize); + ~VmaPool_T(); - // All tests passed: Success. - pAllocationRequest->offset = resultOffset; - pAllocationRequest->sumFreeSize = resultBaseOffset + allocSize - endOf1st; - pAllocationRequest->sumItemSize = 0; - // pAllocationRequest->item unused. - pAllocationRequest->itemsToMakeLostCount = 0; - pAllocationRequest->type = VmaAllocationRequestType::UpperAddress; - return true; + uint32_t GetId() const { return m_Id; } + void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; } + + const char* GetName() const { return m_Name; } + void SetName(const char* pName); + +#if VMA_STATS_STRING_ENABLED + //void PrintDetailedMap(class VmaStringBuilder& sb); +#endif + +private: + uint32_t m_Id; + char* m_Name; + VmaPool_T* m_PrevPool = VMA_NULL; + VmaPool_T* m_NextPool = VMA_NULL; +}; + +struct VmaPoolListItemTraits +{ + typedef VmaPool_T ItemType; + + static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; } + static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; } + static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; } + static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; } +}; +#endif // _VMA_POOL_T + +#ifndef _VMA_CURRENT_BUDGET_DATA +struct VmaCurrentBudgetData +{ + VMA_ATOMIC_UINT32 m_BlockCount[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT32 m_AllocationCount[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS]; + +#if VMA_MEMORY_BUDGET + VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch; + VMA_RW_MUTEX m_BudgetMutex; + uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS]; + uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS]; + uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS]; +#endif // VMA_MEMORY_BUDGET + + VmaCurrentBudgetData(); + + void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize); + void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize); +}; + +#ifndef _VMA_CURRENT_BUDGET_DATA_FUNCTIONS +VmaCurrentBudgetData::VmaCurrentBudgetData() +{ + for (uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex) + { + m_BlockCount[heapIndex] = 0; + m_AllocationCount[heapIndex] = 0; + m_BlockBytes[heapIndex] = 0; + m_AllocationBytes[heapIndex] = 0; +#if VMA_MEMORY_BUDGET + m_VulkanUsage[heapIndex] = 0; + m_VulkanBudget[heapIndex] = 0; + m_BlockBytesAtBudgetFetch[heapIndex] = 0; +#endif } - return false; +#if VMA_MEMORY_BUDGET + m_OperationsSinceBudgetFetch = 0; +#endif } -bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) +void VmaCurrentBudgetData::AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) { - const VkDeviceSize size = GetSize(); - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + m_AllocationBytes[heapIndex] += allocationSize; + ++m_AllocationCount[heapIndex]; +#if VMA_MEMORY_BUDGET + ++m_OperationsSinceBudgetFetch; +#endif +} - if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) - { - // Try to allocate at the end of 1st vector. +void VmaCurrentBudgetData::RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) +{ + VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); + m_AllocationBytes[heapIndex] -= allocationSize; + VMA_ASSERT(m_AllocationCount[heapIndex] > 0); + --m_AllocationCount[heapIndex]; +#if VMA_MEMORY_BUDGET + ++m_OperationsSinceBudgetFetch; +#endif +} +#endif // _VMA_CURRENT_BUDGET_DATA_FUNCTIONS +#endif // _VMA_CURRENT_BUDGET_DATA - VkDeviceSize resultBaseOffset = 0; - if(!suballocations1st.empty()) - { - const VmaSuballocation& lastSuballoc = suballocations1st.back(); - resultBaseOffset = lastSuballoc.offset + lastSuballoc.size; - } +#ifndef _VMA_ALLOCATION_OBJECT_ALLOCATOR +/* +Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects. +*/ +class VmaAllocationObjectAllocator +{ + VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator) +public: + VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) + : m_Allocator(pAllocationCallbacks, 1024) {} - // Start from offset equal to beginning of free space. - VkDeviceSize resultOffset = resultBaseOffset; + template VmaAllocation Allocate(Types&&... args); + void Free(VmaAllocation hAlloc); - // Apply VMA_DEBUG_MARGIN at the beginning. - if(VMA_DEBUG_MARGIN > 0) - { - resultOffset += VMA_DEBUG_MARGIN; - } +private: + VMA_MUTEX m_Mutex; + VmaPoolAllocator m_Allocator; +}; - // Apply alignment. - resultOffset = VmaAlignUp(resultOffset, allocAlignment); +template +VmaAllocation VmaAllocationObjectAllocator::Allocate(Types&&... args) +{ + VmaMutexLock mutexLock(m_Mutex); + return m_Allocator.Alloc(std::forward(args)...); +} - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1 && !suballocations1st.empty()) - { - bool bufferImageGranularityConflict = false; - for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) - { - const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); - } - } +void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc) +{ + VmaMutexLock mutexLock(m_Mutex); + m_Allocator.Free(hAlloc); +} +#endif // _VMA_ALLOCATION_OBJECT_ALLOCATOR - const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? - suballocations2nd.back().offset : size; +#ifndef _VMA_VIRTUAL_BLOCK_T +struct VmaVirtualBlock_T +{ + VMA_CLASS_NO_COPY(VmaVirtualBlock_T) +public: + const bool m_AllocationCallbacksSpecified; + const VkAllocationCallbacks m_AllocationCallbacks; + + VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo); + ~VmaVirtualBlock_T(); + + VkResult Init() { return VK_SUCCESS; } + bool IsEmpty() const { return m_Metadata->IsEmpty(); } + void Free(VmaVirtualAllocation allocation) { m_Metadata->Free((VmaAllocHandle)allocation); } + void SetAllocationUserData(VmaVirtualAllocation allocation, void* userData) { m_Metadata->SetAllocationUserData((VmaAllocHandle)allocation, userData); } + void Clear() { m_Metadata->Clear(); } + + const VkAllocationCallbacks* GetAllocationCallbacks() const; + void GetAllocationInfo(VmaVirtualAllocation allocation, VmaVirtualAllocationInfo& outInfo); + VkResult Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VmaVirtualAllocation& outAllocation, + VkDeviceSize* outOffset); + void GetStatistics(VmaStatistics& outStats) const; + void CalculateDetailedStatistics(VmaDetailedStatistics& outStats) const; +#if VMA_STATS_STRING_ENABLED + void BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const; +#endif - // There is enough free space at the end after alignment. - if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd) - { - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if(bufferImageGranularity > 1 && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) - { - for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) - { - const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; - if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - return false; - } - } - else - { - // Already on previous page. - break; - } - } - } +private: + VmaBlockMetadata* m_Metadata; +}; - // All tests passed: Success. - pAllocationRequest->offset = resultOffset; - pAllocationRequest->sumFreeSize = freeSpaceEnd - resultBaseOffset; - pAllocationRequest->sumItemSize = 0; - // pAllocationRequest->item, customData unused. - pAllocationRequest->type = VmaAllocationRequestType::EndOf1st; - pAllocationRequest->itemsToMakeLostCount = 0; - return true; - } +#ifndef _VMA_VIRTUAL_BLOCK_T_FUNCTIONS +VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo) + : m_AllocationCallbacksSpecified(createInfo.pAllocationCallbacks != VMA_NULL), + m_AllocationCallbacks(createInfo.pAllocationCallbacks != VMA_NULL ? *createInfo.pAllocationCallbacks : VmaEmptyAllocationCallbacks) +{ + const uint32_t algorithm = createInfo.flags & VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK; + switch (algorithm) + { + case 0: + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_TLSF)(VK_NULL_HANDLE, 1, true); + break; + case VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT: + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Linear)(VK_NULL_HANDLE, 1, true); + break; + default: + VMA_ASSERT(0); + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_TLSF)(VK_NULL_HANDLE, 1, true); } - // Wrap-around to end of 2nd vector. Try to allocate there, watching for the - // beginning of 1st vector as the end of free space. - if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) - { - VMA_ASSERT(!suballocations1st.empty()); + m_Metadata->Init(createInfo.size); +} - VkDeviceSize resultBaseOffset = 0; - if(!suballocations2nd.empty()) - { - const VmaSuballocation& lastSuballoc = suballocations2nd.back(); - resultBaseOffset = lastSuballoc.offset + lastSuballoc.size; - } +VmaVirtualBlock_T::~VmaVirtualBlock_T() +{ + // Define macro VMA_DEBUG_LOG_FORMAT to receive the list of the unfreed allocations + if (!m_Metadata->IsEmpty()) + m_Metadata->DebugLogAllAllocations(); + // This is the most important assert in the entire library. + // Hitting it means you have some memory leak - unreleased virtual allocations. + VMA_ASSERT(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!"); - // Start from offset equal to beginning of free space. - VkDeviceSize resultOffset = resultBaseOffset; + vma_delete(GetAllocationCallbacks(), m_Metadata); +} - // Apply VMA_DEBUG_MARGIN at the beginning. - if(VMA_DEBUG_MARGIN > 0) - { - resultOffset += VMA_DEBUG_MARGIN; - } +const VkAllocationCallbacks* VmaVirtualBlock_T::GetAllocationCallbacks() const +{ + return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL; +} - // Apply alignment. - resultOffset = VmaAlignUp(resultOffset, allocAlignment); +void VmaVirtualBlock_T::GetAllocationInfo(VmaVirtualAllocation allocation, VmaVirtualAllocationInfo& outInfo) +{ + m_Metadata->GetAllocationInfo((VmaAllocHandle)allocation, outInfo); +} - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1 && !suballocations2nd.empty()) - { - bool bufferImageGranularityConflict = false; - for(size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; ) - { - const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex]; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); - } - } +VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VmaVirtualAllocation& outAllocation, + VkDeviceSize* outOffset) +{ + VmaAllocationRequest request = {}; + if (m_Metadata->CreateAllocationRequest( + createInfo.size, // allocSize + VMA_MAX(createInfo.alignment, (VkDeviceSize)1), // allocAlignment + (createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0, // upperAddress + VMA_SUBALLOCATION_TYPE_UNKNOWN, // allocType - unimportant + createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK, // strategy + &request)) + { + m_Metadata->Alloc(request, + VMA_SUBALLOCATION_TYPE_UNKNOWN, // type - unimportant + createInfo.pUserData); + outAllocation = (VmaVirtualAllocation)request.allocHandle; + if(outOffset) + *outOffset = m_Metadata->GetAllocationOffset(request.allocHandle); + return VK_SUCCESS; + } + outAllocation = (VmaVirtualAllocation)VK_NULL_HANDLE; + if (outOffset) + *outOffset = UINT64_MAX; + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} - pAllocationRequest->itemsToMakeLostCount = 0; - pAllocationRequest->sumItemSize = 0; - size_t index1st = m_1stNullItemsBeginCount; +void VmaVirtualBlock_T::GetStatistics(VmaStatistics& outStats) const +{ + VmaClearStatistics(outStats); + m_Metadata->AddStatistics(outStats); +} - if(canMakeOtherLost) - { - while(index1st < suballocations1st.size() && - resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset) - { - // Next colliding allocation at the beginning of 1st vector found. Try to make it lost. - const VmaSuballocation& suballoc = suballocations1st[index1st]; - if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE) - { - // No problem. - } - else - { - VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE); - if(suballoc.hAllocation->CanBecomeLost() && - suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++pAllocationRequest->itemsToMakeLostCount; - pAllocationRequest->sumItemSize += suballoc.size; - } - else - { - return false; - } - } - ++index1st; - } +void VmaVirtualBlock_T::CalculateDetailedStatistics(VmaDetailedStatistics& outStats) const +{ + VmaClearDetailedStatistics(outStats); + m_Metadata->AddDetailedStatistics(outStats); +} - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, we must mark more allocations lost or fail. - if(bufferImageGranularity > 1) - { - while(index1st < suballocations1st.size()) - { - const VmaSuballocation& suballoc = suballocations1st[index1st]; - if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity)) - { - if(suballoc.hAllocation != VK_NULL_HANDLE) - { - // Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type). - if(suballoc.hAllocation->CanBecomeLost() && - suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++pAllocationRequest->itemsToMakeLostCount; - pAllocationRequest->sumItemSize += suballoc.size; - } - else - { - return false; - } - } - } - else - { - // Already on next page. - break; - } - ++index1st; - } - } +#if VMA_STATS_STRING_ENABLED +void VmaVirtualBlock_T::BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const +{ + VmaJsonWriter json(GetAllocationCallbacks(), sb); + json.BeginObject(); - // Special case: There is not enough room at the end for this allocation, even after making all from the 1st lost. - if(index1st == suballocations1st.size() && - resultOffset + allocSize + VMA_DEBUG_MARGIN > size) - { - // TODO: This is a known bug that it's not yet implemented and the allocation is failing. - VMA_DEBUG_LOG("Unsupported special case in custom pool with linear allocation algorithm used as ring buffer with allocations that can be lost."); - } - } + VmaDetailedStatistics stats; + CalculateDetailedStatistics(stats); - // There is enough free space at the end after alignment. - if((index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= size) || - (index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset)) - { - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if(bufferImageGranularity > 1) - { - for(size_t nextSuballocIndex = index1st; - nextSuballocIndex < suballocations1st.size(); - nextSuballocIndex++) - { - const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex]; - if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - return false; - } - } - else - { - // Already on next page. - break; - } - } - } + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats); - // All tests passed: Success. - pAllocationRequest->offset = resultOffset; - pAllocationRequest->sumFreeSize = - (index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size) - - resultBaseOffset - - pAllocationRequest->sumItemSize; - pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd; - // pAllocationRequest->item, customData unused. - return true; - } + if (detailedMap) + { + json.WriteString("Details"); + json.BeginObject(); + m_Metadata->PrintDetailedMap(json); + json.EndObject(); } - return false; + json.EndObject(); } +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_VIRTUAL_BLOCK_T_FUNCTIONS +#endif // _VMA_VIRTUAL_BLOCK_T -bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest) + +// Main allocator object. +struct VmaAllocator_T { - if(pAllocationRequest->itemsToMakeLostCount == 0) + VMA_CLASS_NO_COPY(VmaAllocator_T) +public: + bool m_UseMutex; + uint32_t m_VulkanApiVersion; + bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). + bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). + bool m_UseExtMemoryBudget; + bool m_UseAmdDeviceCoherentMemory; + bool m_UseKhrBufferDeviceAddress; + bool m_UseExtMemoryPriority; + VkDevice m_hDevice; + VkInstance m_hInstance; + bool m_AllocationCallbacksSpecified; + VkAllocationCallbacks m_AllocationCallbacks; + VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; + VmaAllocationObjectAllocator m_AllocationObjectAllocator; + + // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size. + uint32_t m_HeapSizeLimitMask; + + VkPhysicalDeviceProperties m_PhysicalDeviceProperties; + VkPhysicalDeviceMemoryProperties m_MemProps; + + // Default pools. + VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES]; + VmaDedicatedAllocationList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES]; + + VmaCurrentBudgetData m_Budget; + VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects. + + VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo); + VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo); + ~VmaAllocator_T(); + + const VkAllocationCallbacks* GetAllocationCallbacks() const { - return true; + return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL; } - - VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER); - - // We always start from 1st. - SuballocationVectorType* suballocations = &AccessSuballocations1st(); - size_t index = m_1stNullItemsBeginCount; - size_t madeLostCount = 0; - while(madeLostCount < pAllocationRequest->itemsToMakeLostCount) + const VmaVulkanFunctions& GetVulkanFunctions() const { - if(index == suballocations->size()) - { - index = 0; - // If we get to the end of 1st, we wrap around to beginning of 2nd of 1st. - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) - { - suballocations = &AccessSuballocations2nd(); - } - // else: m_2ndVectorMode == SECOND_VECTOR_EMPTY: - // suballocations continues pointing at AccessSuballocations1st(). - VMA_ASSERT(!suballocations->empty()); - } - VmaSuballocation& suballoc = (*suballocations)[index]; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE); - VMA_ASSERT(suballoc.hAllocation->CanBecomeLost()); - if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - m_SumFreeSize += suballoc.size; - if(suballocations == &AccessSuballocations1st()) - { - ++m_1stNullItemsMiddleCount; - } - else - { - ++m_2ndNullItemsCount; - } - ++madeLostCount; - } - else - { - return false; - } - } - ++index; + return m_VulkanFunctions; } - CleanupAfterFree(); - //VMA_HEAVY_ASSERT(Validate()); // Already called by ClanupAfterFree(). - - return true; -} + VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; } -uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) -{ - uint32_t lostAllocationCount = 0; - - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i) + VkDeviceSize GetBufferImageGranularity() const { - VmaSuballocation& suballoc = suballocations1st[i]; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE && - suballoc.hAllocation->CanBecomeLost() && - suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - ++m_1stNullItemsMiddleCount; - m_SumFreeSize += suballoc.size; - ++lostAllocationCount; - } + return VMA_MAX( + static_cast(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY), + m_PhysicalDeviceProperties.limits.bufferImageGranularity); } - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i) + uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; } + uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; } + + uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const { - VmaSuballocation& suballoc = suballocations2nd[i]; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE && - suballoc.hAllocation->CanBecomeLost() && - suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - ++m_2ndNullItemsCount; - m_SumFreeSize += suballoc.size; - ++lostAllocationCount; - } + VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount); + return m_MemProps.memoryTypes[memTypeIndex].heapIndex; } - - if(lostAllocationCount) + // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT. + bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const { - CleanupAfterFree(); + return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } - - return lostAllocationCount; -} - -VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData) -{ - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i) + // Minimum alignment for all allocations in specific memory type. + VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const { - const VmaSuballocation& suballoc = suballocations1st[i]; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - } + return IsMemoryTypeNonCoherent(memTypeIndex) ? + VMA_MAX((VkDeviceSize)VMA_MIN_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) : + (VkDeviceSize)VMA_MIN_ALIGNMENT; } - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i) + bool IsIntegratedGpu() const { - const VmaSuballocation& suballoc = suballocations2nd[i]; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - } + return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; } - return VK_SUCCESS; -} + uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; } -void VmaBlockMetadata_Linear::Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation) -{ - const VmaSuballocation newSuballoc = { request.offset, allocSize, hAllocation, type }; + void GetBufferMemoryRequirements( + VkBuffer hBuffer, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const; + void GetImageMemoryRequirements( + VkImage hImage, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const; + VkResult FindMemoryTypeIndex( + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + uint32_t* pMemoryTypeIndex) const; - switch(request.type) - { - case VmaAllocationRequestType::UpperAddress: - { - VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER && - "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer."); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); - suballocations2nd.push_back(newSuballoc); - m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK; - } - break; - case VmaAllocationRequestType::EndOf1st: - { - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + // Main allocation function. + VkResult AllocateMemory( + const VkMemoryRequirements& vkMemReq, + bool requiresDedicatedAllocation, + bool prefersDedicatedAllocation, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, // UINT32_MAX if unknown. + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations); - VMA_ASSERT(suballocations1st.empty() || - request.offset >= suballocations1st.back().offset + suballocations1st.back().size); - // Check if it fits before the end of the block. - VMA_ASSERT(request.offset + allocSize <= GetSize()); + // Main deallocation function. + void FreeMemory( + size_t allocationCount, + const VmaAllocation* pAllocations); - suballocations1st.push_back(newSuballoc); - } - break; - case VmaAllocationRequestType::EndOf2nd: - { - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector. - VMA_ASSERT(!suballocations1st.empty() && - request.offset + allocSize <= suballocations1st[m_1stNullItemsBeginCount].offset); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + void CalculateStatistics(VmaTotalStatistics* pStats); - switch(m_2ndVectorMode) - { - case SECOND_VECTOR_EMPTY: - // First allocation from second part ring buffer. - VMA_ASSERT(suballocations2nd.empty()); - m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER; - break; - case SECOND_VECTOR_RING_BUFFER: - // 2-part ring buffer is already started. - VMA_ASSERT(!suballocations2nd.empty()); - break; - case SECOND_VECTOR_DOUBLE_STACK: - VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack."); - break; - default: - VMA_ASSERT(0); - } + void GetHeapBudgets( + VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount); - suballocations2nd.push_back(newSuballoc); - } - break; - default: - VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR."); - } +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json); +#endif - m_SumFreeSize -= newSuballoc.size; -} + void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo); -void VmaBlockMetadata_Linear::Free(const VmaAllocation allocation) -{ - FreeAtOffset(allocation->GetOffset()); -} + VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool); + void DestroyPool(VmaPool pool); + void GetPoolStatistics(VmaPool pool, VmaStatistics* pPoolStats); + void CalculatePoolStatistics(VmaPool pool, VmaDetailedStatistics* pPoolStats); -void VmaBlockMetadata_Linear::FreeAtOffset(VkDeviceSize offset) -{ - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + void SetCurrentFrameIndex(uint32_t frameIndex); + uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); } - if(!suballocations1st.empty()) - { - // First allocation: Mark it as next empty at the beginning. - VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount]; - if(firstSuballoc.offset == offset) - { - firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - firstSuballoc.hAllocation = VK_NULL_HANDLE; - m_SumFreeSize += firstSuballoc.size; - ++m_1stNullItemsBeginCount; - CleanupAfterFree(); - return; - } - } + VkResult CheckPoolCorruption(VmaPool hPool); + VkResult CheckCorruption(uint32_t memoryTypeBits); - // Last allocation in 2-part ring buffer or top of upper stack (same logic). - if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER || - m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) - { - VmaSuballocation& lastSuballoc = suballocations2nd.back(); - if(lastSuballoc.offset == offset) - { - m_SumFreeSize += lastSuballoc.size; - suballocations2nd.pop_back(); - CleanupAfterFree(); - return; - } - } - // Last allocation in 1st vector. - else if(m_2ndVectorMode == SECOND_VECTOR_EMPTY) - { - VmaSuballocation& lastSuballoc = suballocations1st.back(); - if(lastSuballoc.offset == offset) - { - m_SumFreeSize += lastSuballoc.size; - suballocations1st.pop_back(); - CleanupAfterFree(); - return; - } - } + // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping. + VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory); + // Call to Vulkan function vkFreeMemory with accompanying bookkeeping. + void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory); + // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR. + VkResult BindVulkanBuffer( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkBuffer buffer, + const void* pNext); + // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR. + VkResult BindVulkanImage( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkImage image, + const void* pNext); - // Item from the middle of 1st vector. - { - VmaSuballocation refSuballoc; - refSuballoc.offset = offset; - // Rest of members stays uninitialized intentionally for better performance. - SuballocationVectorType::iterator it = VmaBinaryFindSorted( - suballocations1st.begin() + m_1stNullItemsBeginCount, - suballocations1st.end(), - refSuballoc, - VmaSuballocationOffsetLess()); - if(it != suballocations1st.end()) - { - it->type = VMA_SUBALLOCATION_TYPE_FREE; - it->hAllocation = VK_NULL_HANDLE; - ++m_1stNullItemsMiddleCount; - m_SumFreeSize += it->size; - CleanupAfterFree(); - return; - } - } + VkResult Map(VmaAllocation hAllocation, void** ppData); + void Unmap(VmaAllocation hAllocation); - if(m_2ndVectorMode != SECOND_VECTOR_EMPTY) - { - // Item from the middle of 2nd vector. - VmaSuballocation refSuballoc; - refSuballoc.offset = offset; - // Rest of members stays uninitialized intentionally for better performance. - SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ? - VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) : - VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater()); - if(it != suballocations2nd.end()) - { - it->type = VMA_SUBALLOCATION_TYPE_FREE; - it->hAllocation = VK_NULL_HANDLE; - ++m_2ndNullItemsCount; - m_SumFreeSize += it->size; - CleanupAfterFree(); - return; - } - } + VkResult BindBufferMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext); + VkResult BindImageMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext); - VMA_ASSERT(0 && "Allocation to free not found in linear allocator!"); -} + VkResult FlushOrInvalidateAllocation( + VmaAllocation hAllocation, + VkDeviceSize offset, VkDeviceSize size, + VMA_CACHE_OPERATION op); + VkResult FlushOrInvalidateAllocations( + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, const VkDeviceSize* sizes, + VMA_CACHE_OPERATION op); -bool VmaBlockMetadata_Linear::ShouldCompact1st() const -{ - const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; - const size_t suballocCount = AccessSuballocations1st().size(); - return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3; -} + void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern); -void VmaBlockMetadata_Linear::CleanupAfterFree() -{ - SuballocationVectorType& suballocations1st = AccessSuballocations1st(); - SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + /* + Returns bit mask of memory types that can support defragmentation on GPU as + they support creation of required buffer for copy operations. + */ + uint32_t GetGpuDefragmentationMemoryTypeBits(); - if(IsEmpty()) +#if VMA_EXTERNAL_MEMORY + VkExternalMemoryHandleTypeFlagsKHR GetExternalMemoryHandleTypeFlags(uint32_t memTypeIndex) const { - suballocations1st.clear(); - suballocations2nd.clear(); - m_1stNullItemsBeginCount = 0; - m_1stNullItemsMiddleCount = 0; - m_2ndNullItemsCount = 0; - m_2ndVectorMode = SECOND_VECTOR_EMPTY; + return m_TypeExternalMemoryHandleTypes[memTypeIndex]; } - else - { - const size_t suballoc1stCount = suballocations1st.size(); - const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; - VMA_ASSERT(nullItem1stCount <= suballoc1stCount); +#endif // #if VMA_EXTERNAL_MEMORY - // Find more null items at the beginning of 1st vector. - while(m_1stNullItemsBeginCount < suballoc1stCount && - suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE) - { - ++m_1stNullItemsBeginCount; - --m_1stNullItemsMiddleCount; - } +private: + VkDeviceSize m_PreferredLargeHeapBlockSize; - // Find more null items at the end of 1st vector. - while(m_1stNullItemsMiddleCount > 0 && - suballocations1st.back().hAllocation == VK_NULL_HANDLE) - { - --m_1stNullItemsMiddleCount; - suballocations1st.pop_back(); - } + VkPhysicalDevice m_PhysicalDevice; + VMA_ATOMIC_UINT32 m_CurrentFrameIndex; + VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized. +#if VMA_EXTERNAL_MEMORY + VkExternalMemoryHandleTypeFlagsKHR m_TypeExternalMemoryHandleTypes[VK_MAX_MEMORY_TYPES]; +#endif // #if VMA_EXTERNAL_MEMORY - // Find more null items at the end of 2nd vector. - while(m_2ndNullItemsCount > 0 && - suballocations2nd.back().hAllocation == VK_NULL_HANDLE) - { - --m_2ndNullItemsCount; - suballocations2nd.pop_back(); - } + VMA_RW_MUTEX m_PoolsMutex; + typedef VmaIntrusiveLinkedList PoolList; + // Protected by m_PoolsMutex. + PoolList m_Pools; + uint32_t m_NextPoolId; - // Find more null items at the beginning of 2nd vector. - while(m_2ndNullItemsCount > 0 && - suballocations2nd[0].hAllocation == VK_NULL_HANDLE) - { - --m_2ndNullItemsCount; - VmaVectorRemove(suballocations2nd, 0); - } + VmaVulkanFunctions m_VulkanFunctions; - if(ShouldCompact1st()) - { - const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount; - size_t srcIndex = m_1stNullItemsBeginCount; - for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex) - { - while(suballocations1st[srcIndex].hAllocation == VK_NULL_HANDLE) - { - ++srcIndex; - } - if(dstIndex != srcIndex) - { - suballocations1st[dstIndex] = suballocations1st[srcIndex]; - } - ++srcIndex; - } - suballocations1st.resize(nonNullItemCount); - m_1stNullItemsBeginCount = 0; - m_1stNullItemsMiddleCount = 0; - } + // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types. + uint32_t m_GlobalMemoryTypeBits; - // 2nd vector became empty. - if(suballocations2nd.empty()) - { - m_2ndVectorMode = SECOND_VECTOR_EMPTY; - } + void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions); - // 1st vector became empty. - if(suballocations1st.size() - m_1stNullItemsBeginCount == 0) - { - suballocations1st.clear(); - m_1stNullItemsBeginCount = 0; +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + void ImportVulkanFunctions_Static(); +#endif - if(!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) - { - // Swap 1st with 2nd. Now 2nd is empty. - m_2ndVectorMode = SECOND_VECTOR_EMPTY; - m_1stNullItemsMiddleCount = m_2ndNullItemsCount; - while(m_1stNullItemsBeginCount < suballocations2nd.size() && - suballocations2nd[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE) - { - ++m_1stNullItemsBeginCount; - --m_1stNullItemsMiddleCount; - } - m_2ndNullItemsCount = 0; - m_1stVectorIndex ^= 1; - } - } - } + void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions); - VMA_HEAVY_ASSERT(Validate()); -} +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + void ImportVulkanFunctions_Dynamic(); +#endif + void ValidateVulkanFunctions(); -//////////////////////////////////////////////////////////////////////////////// -// class VmaBlockMetadata_Buddy + VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex); -VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) : - VmaBlockMetadata(hAllocator), - m_Root(VMA_NULL), - m_AllocationCount(0), - m_FreeCount(1), - m_SumFreeSize(0) -{ - memset(m_FreeList, 0, sizeof(m_FreeList)); -} + VkResult AllocateMemoryOfType( + VmaPool pool, + VkDeviceSize size, + VkDeviceSize alignment, + bool dedicatedPreferred, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + const VmaAllocationCreateInfo& createInfo, + uint32_t memTypeIndex, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + VmaBlockVector& blockVector, + size_t allocationCount, + VmaAllocation* pAllocations); -VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy() -{ - DeleteNode(m_Root); -} + // Helper function only to be used inside AllocateDedicatedMemory. + VkResult AllocateDedicatedMemoryPage( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + uint32_t memTypeIndex, + const VkMemoryAllocateInfo& allocInfo, + bool map, + bool isUserDataString, + bool isMappingAllowed, + void* pUserData, + VmaAllocation* pAllocation); -void VmaBlockMetadata_Buddy::Init(VkDeviceSize size) -{ - VmaBlockMetadata::Init(size); + // Allocates and registers new VkDeviceMemory specifically for dedicated allocations. + VkResult AllocateDedicatedMemory( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + uint32_t memTypeIndex, + bool map, + bool isUserDataString, + bool isMappingAllowed, + bool canAliasMemory, + void* pUserData, + float priority, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + size_t allocationCount, + VmaAllocation* pAllocations, + const void* pNextChain = nullptr); - m_UsableSize = VmaPrevPow2(size); - m_SumFreeSize = m_UsableSize; + void FreeDedicatedMemory(const VmaAllocation allocation); - // Calculate m_LevelCount. - m_LevelCount = 1; - while(m_LevelCount < MAX_LEVELS && - LevelToNodeSize(m_LevelCount) >= MIN_NODE_SIZE) - { - ++m_LevelCount; - } + VkResult CalcMemTypeParams( + VmaAllocationCreateInfo& outCreateInfo, + uint32_t memTypeIndex, + VkDeviceSize size, + size_t allocationCount); + VkResult CalcAllocationParams( + VmaAllocationCreateInfo& outCreateInfo, + bool dedicatedRequired, + bool dedicatedPreferred); - Node* rootNode = vma_new(GetAllocationCallbacks(), Node)(); - rootNode->offset = 0; - rootNode->type = Node::TYPE_FREE; - rootNode->parent = VMA_NULL; - rootNode->buddy = VMA_NULL; + /* + Calculates and returns bit mask of memory types that can support defragmentation + on GPU as they support creation of required buffer for copy operations. + */ + uint32_t CalculateGpuDefragmentationMemoryTypeBits() const; + uint32_t CalculateGlobalMemoryTypeBits() const; - m_Root = rootNode; - AddToFreeListFront(0, rootNode); + bool GetFlushOrInvalidateRange( + VmaAllocation allocation, + VkDeviceSize offset, VkDeviceSize size, + VkMappedMemoryRange& outRange) const; + +#if VMA_MEMORY_BUDGET + void UpdateVulkanBudget(); +#endif // #if VMA_MEMORY_BUDGET +}; + + +#ifndef _VMA_MEMORY_FUNCTIONS +static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment) +{ + return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment); } -bool VmaBlockMetadata_Buddy::Validate() const +static void VmaFree(VmaAllocator hAllocator, void* ptr) { - // Validate tree. - ValidationContext ctx; - if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0))) - { - VMA_VALIDATE(false && "ValidateNode failed."); - } - VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount); - VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize); + VmaFree(&hAllocator->m_AllocationCallbacks, ptr); +} - // Validate free node lists. - for(uint32_t level = 0; level < m_LevelCount; ++level) - { - VMA_VALIDATE(m_FreeList[level].front == VMA_NULL || - m_FreeList[level].front->free.prev == VMA_NULL); +template +static T* VmaAllocate(VmaAllocator hAllocator) +{ + return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T)); +} - for(Node* node = m_FreeList[level].front; - node != VMA_NULL; - node = node->free.next) - { - VMA_VALIDATE(node->type == Node::TYPE_FREE); - - if(node->free.next == VMA_NULL) - { - VMA_VALIDATE(m_FreeList[level].back == node); - } - else - { - VMA_VALIDATE(node->free.next->free.prev == node); - } - } - } +template +static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) +{ + return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T)); +} - // Validate that free lists ar higher levels are empty. - for(uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level) +template +static void vma_delete(VmaAllocator hAllocator, T* ptr) +{ + if(ptr != VMA_NULL) { - VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL); + ptr->~T(); + VmaFree(hAllocator, ptr); } - - return true; } -VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const +template +static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) { - for(uint32_t level = 0; level < m_LevelCount; ++level) + if(ptr != VMA_NULL) { - if(m_FreeList[level].front != VMA_NULL) - { - return LevelToNodeSize(level); - } + for(size_t i = count; i--; ) + ptr[i].~T(); + VmaFree(hAllocator, ptr); } - return 0; } +#endif // _VMA_MEMORY_FUNCTIONS -void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const -{ - const VkDeviceSize unusableSize = GetUnusableSize(); - - outInfo.blockCount = 1; +#ifndef _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS +VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) + : m_pMetadata(VMA_NULL), + m_MemoryTypeIndex(UINT32_MAX), + m_Id(0), + m_hMemory(VK_NULL_HANDLE), + m_MapCount(0), + m_pMappedData(VMA_NULL) {} - outInfo.allocationCount = outInfo.unusedRangeCount = 0; - outInfo.usedBytes = outInfo.unusedBytes = 0; +VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() +{ + VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); + VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); +} - outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0; - outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused. +void VmaDeviceMemoryBlock::Init( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t newMemoryTypeIndex, + VkDeviceMemory newMemory, + VkDeviceSize newSize, + uint32_t id, + uint32_t algorithm, + VkDeviceSize bufferImageGranularity) +{ + VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); - CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0)); + m_hParentPool = hParentPool; + m_MemoryTypeIndex = newMemoryTypeIndex; + m_Id = id; + m_hMemory = newMemory; - if(unusableSize > 0) + switch (algorithm) { - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusableSize; - outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize); - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize); + case 0: + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_TLSF)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual + break; + case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT: + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual + break; + default: + VMA_ASSERT(0); + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_TLSF)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual } + m_pMetadata->Init(newSize); } -void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const +void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) { - const VkDeviceSize unusableSize = GetUnusableSize(); + // Define macro VMA_DEBUG_LOG_FORMAT to receive the list of the unfreed allocations + if (!m_pMetadata->IsEmpty()) + m_pMetadata->DebugLogAllAllocations(); + // This is the most important assert in the entire library. + // Hitting it means you have some memory leak - unreleased VmaAllocation objects. + VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); - inoutStats.size += GetSize(); - inoutStats.unusedSize += m_SumFreeSize + unusableSize; - inoutStats.allocationCount += m_AllocationCount; - inoutStats.unusedRangeCount += m_FreeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax()); + VMA_ASSERT(m_hMemory != VK_NULL_HANDLE); + allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); + m_hMemory = VK_NULL_HANDLE; - if(unusableSize > 0) - { - ++inoutStats.unusedRangeCount; - // Not updating inoutStats.unusedRangeSizeMax with unusableSize because this space is not available for allocations. - } + vma_delete(allocator, m_pMetadata); + m_pMetadata = VMA_NULL; } -#if VMA_STATS_STRING_ENABLED +void VmaDeviceMemoryBlock::PostAlloc(VmaAllocator hAllocator) +{ + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + m_MappingHysteresis.PostAlloc(); +} -void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const +void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) { - // TODO optimize - VmaStatInfo stat; - CalcAllocationStatInfo(stat); + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + if(m_MappingHysteresis.PostFree()) + { + VMA_ASSERT(m_MappingHysteresis.GetExtraMapping() == 0); + if (m_MapCount == 0) + { + m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); + } + } +} - PrintDetailedMap_Begin( - json, - stat.unusedBytes, - stat.allocationCount, - stat.unusedRangeCount); +bool VmaDeviceMemoryBlock::Validate() const +{ + VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) && + (m_pMetadata->GetSize() != 0)); - PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0)); + return m_pMetadata->Validate(); +} - const VkDeviceSize unusableSize = GetUnusableSize(); - if(unusableSize > 0) +VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator) +{ + void* pData = nullptr; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) { - PrintDetailedMap_UnusedRange(json, - m_UsableSize, // offset - unusableSize); // size + return res; } - PrintDetailedMap_End(json); -} + res = m_pMetadata->CheckCorruption(pData); -#endif // #if VMA_STATS_STRING_ENABLED + Unmap(hAllocator, 1); -bool VmaBlockMetadata_Buddy::CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - bool canMakeOtherLost, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); + return res; +} - // Simple way to respect bufferImageGranularity. May be optimized some day. - // Whenever it might be an OPTIMAL image... - if(allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || - allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) +VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData) +{ + if (count == 0) { - allocAlignment = VMA_MAX(allocAlignment, bufferImageGranularity); - allocSize = VMA_MAX(allocSize, bufferImageGranularity); + return VK_SUCCESS; } - if(allocSize > m_UsableSize) + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + const uint32_t oldTotalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping(); + m_MappingHysteresis.PostMap(); + if (oldTotalMapCount != 0) { - return false; + m_MapCount += count; + VMA_ASSERT(m_pMappedData != VMA_NULL); + if (ppData != VMA_NULL) + { + *ppData = m_pMappedData; + } + return VK_SUCCESS; } - - const uint32_t targetLevel = AllocSizeToLevel(allocSize); - for(uint32_t level = targetLevel + 1; level--; ) + else { - for(Node* freeNode = m_FreeList[level].front; - freeNode != VMA_NULL; - freeNode = freeNode->free.next) + VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( + hAllocator->m_hDevice, + m_hMemory, + 0, // offset + VK_WHOLE_SIZE, + 0, // flags + &m_pMappedData); + if (result == VK_SUCCESS) { - if(freeNode->offset % allocAlignment == 0) + if (ppData != VMA_NULL) { - pAllocationRequest->type = VmaAllocationRequestType::Normal; - pAllocationRequest->offset = freeNode->offset; - pAllocationRequest->sumFreeSize = LevelToNodeSize(level); - pAllocationRequest->sumItemSize = 0; - pAllocationRequest->itemsToMakeLostCount = 0; - pAllocationRequest->customData = (void*)(uintptr_t)level; - return true; + *ppData = m_pMappedData; } + m_MapCount = count; } + return result; } - - return false; } -bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest) +void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) { - /* - Lost allocations are not supported in buddy allocator at the moment. - Support might be added in the future. - */ - return pAllocationRequest->itemsToMakeLostCount == 0; + if (count == 0) + { + return; + } + + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + if (m_MapCount >= count) + { + m_MapCount -= count; + const uint32_t totalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping(); + if (totalMapCount == 0) + { + m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); + } + m_MappingHysteresis.PostUnmap(); + } + else + { + VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped."); + } } -uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) +VkResult VmaDeviceMemoryBlock::WriteMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) { - /* - Lost allocations are not supported in buddy allocator at the moment. - Support might be added in the future. - */ - return 0; + VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); + + void* pData; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) + { + return res; + } + + VmaWriteMagicValue(pData, allocOffset + allocSize); + + Unmap(hAllocator, 1); + return VK_SUCCESS; } -void VmaBlockMetadata_Buddy::Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation) +VkResult VmaDeviceMemoryBlock::ValidateMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) { - VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); + VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); - const uint32_t targetLevel = AllocSizeToLevel(allocSize); - uint32_t currLevel = (uint32_t)(uintptr_t)request.customData; - - Node* currNode = m_FreeList[currLevel].front; - VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); - while(currNode->offset != request.offset) + void* pData; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) { - currNode = currNode->free.next; - VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + return res; } - - // Go down, splitting free nodes. - while(currLevel < targetLevel) + + if (!VmaValidateMagicValue(pData, allocOffset + allocSize)) { - // currNode is already first free node at currLevel. - // Remove it from list of free nodes at this currLevel. - RemoveFromFreeList(currLevel, currNode); - - const uint32_t childrenLevel = currLevel + 1; + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!"); + } - // Create two free sub-nodes. - Node* leftChild = vma_new(GetAllocationCallbacks(), Node)(); - Node* rightChild = vma_new(GetAllocationCallbacks(), Node)(); + Unmap(hAllocator, 1); + return VK_SUCCESS; +} - leftChild->offset = currNode->offset; - leftChild->type = Node::TYPE_FREE; - leftChild->parent = currNode; - leftChild->buddy = rightChild; +VkResult VmaDeviceMemoryBlock::BindBufferMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext) +{ + VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && + hAllocation->GetBlock() == this); + VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && + "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); + const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; + // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext); +} - rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel); - rightChild->type = Node::TYPE_FREE; - rightChild->parent = currNode; - rightChild->buddy = leftChild; +VkResult VmaDeviceMemoryBlock::BindImageMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext) +{ + VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && + hAllocation->GetBlock() == this); + VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && + "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); + const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; + // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); +} +#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS - // Convert current currNode to split type. - currNode->type = Node::TYPE_SPLIT; - currNode->split.leftChild = leftChild; +#ifndef _VMA_ALLOCATION_T_FUNCTIONS +VmaAllocation_T::VmaAllocation_T(bool mappingAllowed) + : m_Alignment{ 1 }, + m_Size{ 0 }, + m_pUserData{ VMA_NULL }, + m_pName{ VMA_NULL }, + m_MemoryTypeIndex{ 0 }, + m_Type{ (uint8_t)ALLOCATION_TYPE_NONE }, + m_SuballocationType{ (uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN }, + m_MapCount{ 0 }, + m_Flags{ 0 } +{ + if(mappingAllowed) + m_Flags |= (uint8_t)FLAG_MAPPING_ALLOWED; - // Add child nodes to free list. Order is important! - AddToFreeListFront(childrenLevel, rightChild); - AddToFreeListFront(childrenLevel, leftChild); +#if VMA_STATS_STRING_ENABLED + m_BufferImageUsage = 0; +#endif +} - ++m_FreeCount; - //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2. - ++currLevel; - currNode = m_FreeList[currLevel].front; +VmaAllocation_T::~VmaAllocation_T() +{ + VMA_ASSERT(m_MapCount == 0 && "Allocation was not unmapped before destruction."); - /* - We can be sure that currNode, as left child of node previously split, - also fullfills the alignment requirement. - */ + // Check if owned string was freed. + VMA_ASSERT(m_pName == VMA_NULL); +} + +void VmaAllocation_T::InitBlockAllocation( + VmaDeviceMemoryBlock* block, + VmaAllocHandle allocHandle, + VkDeviceSize alignment, + VkDeviceSize size, + uint32_t memoryTypeIndex, + VmaSuballocationType suballocationType, + bool mapped) +{ + VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); + VMA_ASSERT(block != VMA_NULL); + m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; + m_Alignment = alignment; + m_Size = size; + m_MemoryTypeIndex = memoryTypeIndex; + if(mapped) + { + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; } + m_SuballocationType = (uint8_t)suballocationType; + m_BlockAllocation.m_Block = block; + m_BlockAllocation.m_AllocHandle = allocHandle; +} - // Remove from free list. - VMA_ASSERT(currLevel == targetLevel && - currNode != VMA_NULL && - currNode->type == Node::TYPE_FREE); - RemoveFromFreeList(currLevel, currNode); +void VmaAllocation_T::InitDedicatedAllocation( + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceMemory hMemory, + VmaSuballocationType suballocationType, + void* pMappedData, + VkDeviceSize size) +{ + VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); + VMA_ASSERT(hMemory != VK_NULL_HANDLE); + m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED; + m_Alignment = 0; + m_Size = size; + m_MemoryTypeIndex = memoryTypeIndex; + m_SuballocationType = (uint8_t)suballocationType; + if(pMappedData != VMA_NULL) + { + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; + } + m_DedicatedAllocation.m_hParentPool = hParentPool; + m_DedicatedAllocation.m_hMemory = hMemory; + m_DedicatedAllocation.m_pMappedData = pMappedData; + m_DedicatedAllocation.m_Prev = VMA_NULL; + m_DedicatedAllocation.m_Next = VMA_NULL; +} - // Convert to allocation node. - currNode->type = Node::TYPE_ALLOCATION; - currNode->allocation.alloc = hAllocation; +void VmaAllocation_T::SetName(VmaAllocator hAllocator, const char* pName) +{ + VMA_ASSERT(pName == VMA_NULL || pName != m_pName); - ++m_AllocationCount; - --m_FreeCount; - m_SumFreeSize -= allocSize; + FreeName(hAllocator); + + if (pName != VMA_NULL) + m_pName = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), pName); } -void VmaBlockMetadata_Buddy::DeleteNode(Node* node) +uint8_t VmaAllocation_T::SwapBlockAllocation(VmaAllocator hAllocator, VmaAllocation allocation) { - if(node->type == Node::TYPE_SPLIT) - { - DeleteNode(node->split.leftChild->buddy); - DeleteNode(node->split.leftChild); - } + VMA_ASSERT(allocation != VMA_NULL); + VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); + VMA_ASSERT(allocation->m_Type == ALLOCATION_TYPE_BLOCK); + + if (m_MapCount != 0) + m_BlockAllocation.m_Block->Unmap(hAllocator, m_MapCount); - vma_delete(GetAllocationCallbacks(), node); + m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, allocation); + VMA_SWAP(m_BlockAllocation, allocation->m_BlockAllocation); + m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, this); + +#if VMA_STATS_STRING_ENABLED + VMA_SWAP(m_BufferImageUsage, allocation->m_BufferImageUsage); +#endif + return m_MapCount; } -bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const +VmaAllocHandle VmaAllocation_T::GetAllocHandle() const { - VMA_VALIDATE(level < m_LevelCount); - VMA_VALIDATE(curr->parent == parent); - VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL)); - VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr); - switch(curr->type) + switch (m_Type) { - case Node::TYPE_FREE: - // curr->free.prev, next are validated separately. - ctx.calculatedSumFreeSize += levelNodeSize; - ++ctx.calculatedFreeCount; - break; - case Node::TYPE_ALLOCATION: - ++ctx.calculatedAllocationCount; - ctx.calculatedSumFreeSize += levelNodeSize - curr->allocation.alloc->GetSize(); - VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE); - break; - case Node::TYPE_SPLIT: - { - const uint32_t childrenLevel = level + 1; - const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2; - const Node* const leftChild = curr->split.leftChild; - VMA_VALIDATE(leftChild != VMA_NULL); - VMA_VALIDATE(leftChild->offset == curr->offset); - if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize)) - { - VMA_VALIDATE(false && "ValidateNode for left child failed."); - } - const Node* const rightChild = leftChild->buddy; - VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize); - if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize)) - { - VMA_VALIDATE(false && "ValidateNode for right child failed."); - } - } - break; + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_AllocHandle; + case ALLOCATION_TYPE_DEDICATED: + return VK_NULL_HANDLE; default: - return false; + VMA_ASSERT(0); + return VK_NULL_HANDLE; } - - return true; } -uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const +VkDeviceSize VmaAllocation_T::GetOffset() const { - // I know this could be optimized somehow e.g. by using std::log2p1 from C++20. - uint32_t level = 0; - VkDeviceSize currLevelNodeSize = m_UsableSize; - VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1; - while(allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount) + switch (m_Type) { - ++level; - currLevelNodeSize = nextLevelNodeSize; - nextLevelNodeSize = currLevelNodeSize >> 1; + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->m_pMetadata->GetAllocationOffset(m_BlockAllocation.m_AllocHandle); + case ALLOCATION_TYPE_DEDICATED: + return 0; + default: + VMA_ASSERT(0); + return 0; } - return level; } -void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset) +VmaPool VmaAllocation_T::GetParentPool() const { - // Find node and level. - Node* node = m_Root; - VkDeviceSize nodeOffset = 0; - uint32_t level = 0; - VkDeviceSize levelNodeSize = LevelToNodeSize(0); - while(node->type == Node::TYPE_SPLIT) + switch (m_Type) { - const VkDeviceSize nextLevelSize = levelNodeSize >> 1; - if(offset < nodeOffset + nextLevelSize) - { - node = node->split.leftChild; - } - else - { - node = node->split.leftChild->buddy; - nodeOffset += nextLevelSize; - } - ++level; - levelNodeSize = nextLevelSize; + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->GetParentPool(); + case ALLOCATION_TYPE_DEDICATED: + return m_DedicatedAllocation.m_hParentPool; + default: + VMA_ASSERT(0); + return VK_NULL_HANDLE; } +} - VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION); - VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc); - - ++m_FreeCount; - --m_AllocationCount; - m_SumFreeSize += alloc->GetSize(); - - node->type = Node::TYPE_FREE; - - // Join free nodes if possible. - while(level > 0 && node->buddy->type == Node::TYPE_FREE) +VkDeviceMemory VmaAllocation_T::GetMemory() const +{ + switch (m_Type) { - RemoveFromFreeList(level, node->buddy); - Node* const parent = node->parent; - - vma_delete(GetAllocationCallbacks(), node->buddy); - vma_delete(GetAllocationCallbacks(), node); - parent->type = Node::TYPE_FREE; - - node = parent; - --level; - //m_SumFreeSize += LevelToNodeSize(level) % 2; // Useful only when level node sizes can be non power of 2. - --m_FreeCount; + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->GetDeviceMemory(); + case ALLOCATION_TYPE_DEDICATED: + return m_DedicatedAllocation.m_hMemory; + default: + VMA_ASSERT(0); + return VK_NULL_HANDLE; } - - AddToFreeListFront(level, node); } -void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const +void* VmaAllocation_T::GetMappedData() const { - switch(node->type) + switch (m_Type) { - case Node::TYPE_FREE: - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += levelNodeSize; - outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize); - outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize); - break; - case Node::TYPE_ALLOCATION: + case ALLOCATION_TYPE_BLOCK: + if (m_MapCount != 0 || IsPersistentMap()) { - const VkDeviceSize allocSize = node->allocation.alloc->GetSize(); - ++outInfo.allocationCount; - outInfo.usedBytes += allocSize; - outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize); - outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize); - - const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize; - if(unusedRangeSize > 0) - { - ++outInfo.unusedRangeCount; - outInfo.unusedBytes += unusedRangeSize; - outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize); - outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize); - } + void* pBlockData = m_BlockAllocation.m_Block->GetMappedData(); + VMA_ASSERT(pBlockData != VMA_NULL); + return (char*)pBlockData + GetOffset(); } - break; - case Node::TYPE_SPLIT: + else { - const VkDeviceSize childrenNodeSize = levelNodeSize / 2; - const Node* const leftChild = node->split.leftChild; - CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize); - const Node* const rightChild = leftChild->buddy; - CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize); + return VMA_NULL; } break; + case ALLOCATION_TYPE_DEDICATED: + VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0 || IsPersistentMap())); + return m_DedicatedAllocation.m_pMappedData; default: VMA_ASSERT(0); + return VMA_NULL; } } -void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node) +void VmaAllocation_T::BlockAllocMap() { - VMA_ASSERT(node->type == Node::TYPE_FREE); + VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); - // List is empty. - Node* const frontNode = m_FreeList[level].front; - if(frontNode == VMA_NULL) + if (m_MapCount < 0xFF) { - VMA_ASSERT(m_FreeList[level].back == VMA_NULL); - node->free.prev = node->free.next = VMA_NULL; - m_FreeList[level].front = m_FreeList[level].back = node; + ++m_MapCount; } else { - VMA_ASSERT(frontNode->free.prev == VMA_NULL); - node->free.prev = VMA_NULL; - node->free.next = frontNode; - frontNode->free.prev = node; - m_FreeList[level].front = node; + VMA_ASSERT(0 && "Allocation mapped too many times simultaneously."); } } -void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node) +void VmaAllocation_T::BlockAllocUnmap() { - VMA_ASSERT(m_FreeList[level].front != VMA_NULL); - - // It is at the front. - if(node->free.prev == VMA_NULL) - { - VMA_ASSERT(m_FreeList[level].front == node); - m_FreeList[level].front = node->free.next; - } - else - { - Node* const prevFreeNode = node->free.prev; - VMA_ASSERT(prevFreeNode->free.next == node); - prevFreeNode->free.next = node->free.next; - } + VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); - // It is at the back. - if(node->free.next == VMA_NULL) + if (m_MapCount > 0) { - VMA_ASSERT(m_FreeList[level].back == node); - m_FreeList[level].back = node->free.prev; + --m_MapCount; } else { - Node* const nextFreeNode = node->free.next; - VMA_ASSERT(nextFreeNode->free.prev == node); - nextFreeNode->free.prev = node->free.prev; + VMA_ASSERT(0 && "Unmapping allocation not previously mapped."); } } -#if VMA_STATS_STRING_ENABLED -void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const +VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData) { - switch(node->type) + VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + + if (m_MapCount != 0 || IsPersistentMap()) { - case Node::TYPE_FREE: - PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize); - break; - case Node::TYPE_ALLOCATION: - { - PrintDetailedMap_Allocation(json, node->offset, node->allocation.alloc); - const VkDeviceSize allocSize = node->allocation.alloc->GetSize(); - if(allocSize < levelNodeSize) - { - PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize); - } - } - break; - case Node::TYPE_SPLIT: + if (m_MapCount < 0xFF) { - const VkDeviceSize childrenNodeSize = levelNodeSize / 2; - const Node* const leftChild = node->split.leftChild; - PrintDetailedMapNode(json, leftChild, childrenNodeSize); - const Node* const rightChild = leftChild->buddy; - PrintDetailedMapNode(json, rightChild, childrenNodeSize); + VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL); + *ppData = m_DedicatedAllocation.m_pMappedData; + ++m_MapCount; + return VK_SUCCESS; } - break; - default: - VMA_ASSERT(0); - } -} -#endif // #if VMA_STATS_STRING_ENABLED - - -//////////////////////////////////////////////////////////////////////////////// -// class VmaDeviceMemoryBlock - -VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) : - m_pMetadata(VMA_NULL), - m_MemoryTypeIndex(UINT32_MAX), - m_Id(0), - m_hMemory(VK_NULL_HANDLE), - m_MapCount(0), - m_pMappedData(VMA_NULL) -{ -} - -void VmaDeviceMemoryBlock::Init( - VmaAllocator hAllocator, - VmaPool hParentPool, - uint32_t newMemoryTypeIndex, - VkDeviceMemory newMemory, - VkDeviceSize newSize, - uint32_t id, - uint32_t algorithm) -{ - VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); - - m_hParentPool = hParentPool; - m_MemoryTypeIndex = newMemoryTypeIndex; - m_Id = id; - m_hMemory = newMemory; - - switch(algorithm) - { - case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT: - m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator); - break; - case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT: - m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator); - break; - default: - VMA_ASSERT(0); - // Fall-through. - case 0: - m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator); - } - m_pMetadata->Init(newSize); -} - -void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) -{ - // This is the most important assert in the entire library. - // Hitting it means you have some memory leak - unreleased VmaAllocation objects. - VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); - - VMA_ASSERT(m_hMemory != VK_NULL_HANDLE); - allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); - m_hMemory = VK_NULL_HANDLE; - - vma_delete(allocator, m_pMetadata); - m_pMetadata = VMA_NULL; -} - -bool VmaDeviceMemoryBlock::Validate() const -{ - VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) && - (m_pMetadata->GetSize() != 0)); - - return m_pMetadata->Validate(); -} - -VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator) -{ - void* pData = nullptr; - VkResult res = Map(hAllocator, 1, &pData); - if(res != VK_SUCCESS) - { - return res; - } - - res = m_pMetadata->CheckCorruption(pData); - - Unmap(hAllocator, 1); - - return res; -} - -VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData) -{ - if(count == 0) - { - return VK_SUCCESS; - } - - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - if(m_MapCount != 0) - { - m_MapCount += count; - VMA_ASSERT(m_pMappedData != VMA_NULL); - if(ppData != VMA_NULL) + else { - *ppData = m_pMappedData; + VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously."); + return VK_ERROR_MEMORY_MAP_FAILED; } - return VK_SUCCESS; } else { VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( hAllocator->m_hDevice, - m_hMemory, + m_DedicatedAllocation.m_hMemory, 0, // offset VK_WHOLE_SIZE, 0, // flags - &m_pMappedData); - if(result == VK_SUCCESS) + ppData); + if (result == VK_SUCCESS) { - if(ppData != VMA_NULL) - { - *ppData = m_pMappedData; - } - m_MapCount = count; + m_DedicatedAllocation.m_pMappedData = *ppData; + m_MapCount = 1; } return result; } } -void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) +void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator) { - if(count == 0) - { - return; - } + VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - if(m_MapCount >= count) + if (m_MapCount > 0) { - m_MapCount -= count; - if(m_MapCount == 0) + --m_MapCount; + if (m_MapCount == 0 && !IsPersistentMap()) { - m_pMappedData = VMA_NULL; - (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); + m_DedicatedAllocation.m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)( + hAllocator->m_hDevice, + m_DedicatedAllocation.m_hMemory); } } else { - VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped."); + VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped."); } } -VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) +#if VMA_STATS_STRING_ENABLED +void VmaAllocation_T::InitBufferImageUsage(uint32_t bufferImageUsage) { - VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); - VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN); - - void* pData; - VkResult res = Map(hAllocator, 1, &pData); - if(res != VK_SUCCESS) - { - return res; - } - - VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN); - VmaWriteMagicValue(pData, allocOffset + allocSize); - - Unmap(hAllocator, 1); - - return VK_SUCCESS; + VMA_ASSERT(m_BufferImageUsage == 0); + m_BufferImageUsage = bufferImageUsage; } -VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) +void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const { - VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); - VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN); + json.WriteString("Type"); + json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]); - void* pData; - VkResult res = Map(hAllocator, 1, &pData); - if(res != VK_SUCCESS) - { - return res; - } + json.WriteString("Size"); + json.WriteNumber(m_Size); + json.WriteString("Usage"); + json.WriteNumber(m_BufferImageUsage); - if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN)) + if (m_pUserData != VMA_NULL) { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!"); + json.WriteString("CustomData"); + json.BeginString(); + json.ContinueString_Pointer(m_pUserData); + json.EndString(); } - else if(!VmaValidateMagicValue(pData, allocOffset + allocSize)) + if (m_pName != VMA_NULL) { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!"); + json.WriteString("Name"); + json.WriteString(m_pName); } - - Unmap(hAllocator, 1); - - return VK_SUCCESS; -} - -VkResult VmaDeviceMemoryBlock::BindBufferMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkBuffer hBuffer, - const void* pNext) -{ - VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && - hAllocation->GetBlock() == this); - VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && - "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); - const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; - // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext); -} - -VkResult VmaDeviceMemoryBlock::BindImageMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkImage hImage, - const void* pNext) -{ - VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && - hAllocation->GetBlock() == this); - VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && - "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); - const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; - // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); -} - -static void InitStatInfo(VmaStatInfo& outInfo) -{ - memset(&outInfo, 0, sizeof(outInfo)); - outInfo.allocationSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMin = UINT64_MAX; -} - -// Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo. -static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo) -{ - inoutInfo.blockCount += srcInfo.blockCount; - inoutInfo.allocationCount += srcInfo.allocationCount; - inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount; - inoutInfo.usedBytes += srcInfo.usedBytes; - inoutInfo.unusedBytes += srcInfo.unusedBytes; - inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin); - inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax); - inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin); - inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax); -} - -static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo) -{ - inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ? - VmaRoundDiv(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0; - inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ? - VmaRoundDiv(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0; -} - -VmaPool_T::VmaPool_T( - VmaAllocator hAllocator, - const VmaPoolCreateInfo& createInfo, - VkDeviceSize preferredBlockSize) : - m_BlockVector( - hAllocator, - this, // hParentPool - createInfo.memoryTypeIndex, - createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize, - createInfo.minBlockCount, - createInfo.maxBlockCount, - (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), - createInfo.frameInUseCount, - createInfo.blockSize != 0, // explicitBlockSize - createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK), // algorithm - m_Id(0), - m_Name(VMA_NULL) -{ -} - -VmaPool_T::~VmaPool_T() -{ } +#endif // VMA_STATS_STRING_ENABLED -void VmaPool_T::SetName(const char* pName) +void VmaAllocation_T::FreeName(VmaAllocator hAllocator) { - const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks(); - VmaFreeString(allocs, m_Name); - - if(pName != VMA_NULL) - { - m_Name = VmaCreateStringCopy(allocs, pName); - } - else + if(m_pName) { - m_Name = VMA_NULL; + VmaFreeString(hAllocator->GetAllocationCallbacks(), m_pName); + m_pName = VMA_NULL; } } +#endif // _VMA_ALLOCATION_T_FUNCTIONS -#if VMA_STATS_STRING_ENABLED - -#endif // #if VMA_STATS_STRING_ENABLED - +#ifndef _VMA_BLOCK_VECTOR_FUNCTIONS VmaBlockVector::VmaBlockVector( VmaAllocator hAllocator, VmaPool hParentPool, @@ -12020,28 +12265,29 @@ VmaBlockVector::VmaBlockVector( size_t minBlockCount, size_t maxBlockCount, VkDeviceSize bufferImageGranularity, - uint32_t frameInUseCount, bool explicitBlockSize, - uint32_t algorithm) : - m_hAllocator(hAllocator), + uint32_t algorithm, + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext) + : m_hAllocator(hAllocator), m_hParentPool(hParentPool), m_MemoryTypeIndex(memoryTypeIndex), m_PreferredBlockSize(preferredBlockSize), m_MinBlockCount(minBlockCount), m_MaxBlockCount(maxBlockCount), m_BufferImageGranularity(bufferImageGranularity), - m_FrameInUseCount(frameInUseCount), m_ExplicitBlockSize(explicitBlockSize), m_Algorithm(algorithm), - m_HasEmptyBlock(false), + m_Priority(priority), + m_MinAllocationAlignment(minAllocationAlignment), + m_pMemoryAllocateNext(pMemoryAllocateNext), m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_NextBlockId(0) -{ -} + m_NextBlockId(0) {} VmaBlockVector::~VmaBlockVector() { - for(size_t i = m_Blocks.size(); i--; ) + for (size_t i = m_Blocks.size(); i--; ) { m_Blocks[i]->Destroy(m_hAllocator); vma_delete(m_hAllocator, m_Blocks[i]); @@ -12050,10 +12296,10 @@ VmaBlockVector::~VmaBlockVector() VkResult VmaBlockVector::CreateMinBlocks() { - for(size_t i = 0; i < m_MinBlockCount; ++i) + for (size_t i = 0; i < m_MinBlockCount; ++i) { VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) { return res; } @@ -12061,25 +12307,31 @@ VkResult VmaBlockVector::CreateMinBlocks() return VK_SUCCESS; } -void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats) +void VmaBlockVector::AddStatistics(VmaStatistics& inoutStats) { VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); const size_t blockCount = m_Blocks.size(); + for (uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + { + const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pBlock); + VMA_HEAVY_ASSERT(pBlock->Validate()); + pBlock->m_pMetadata->AddStatistics(inoutStats); + } +} - pStats->size = 0; - pStats->unusedSize = 0; - pStats->allocationCount = 0; - pStats->unusedRangeCount = 0; - pStats->unusedRangeSizeMax = 0; - pStats->blockCount = blockCount; +void VmaBlockVector::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); - for(uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + const size_t blockCount = m_Blocks.size(); + for (uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) { const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; VMA_ASSERT(pBlock); VMA_HEAVY_ASSERT(pBlock->Validate()); - pBlock->m_pMetadata->AddPoolStats(*pStats); + pBlock->m_pMetadata->AddDetailedStatistics(inoutStats); } } @@ -12098,10 +12350,7 @@ bool VmaBlockVector::IsCorruptionDetectionEnabled() const (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags; } -static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32; - VkResult VmaBlockVector::Allocate( - uint32_t currentFrameIndex, VkDeviceSize size, VkDeviceSize alignment, const VmaAllocationCreateInfo& createInfo, @@ -12112,7 +12361,9 @@ VkResult VmaBlockVector::Allocate( size_t allocIndex; VkResult res = VK_SUCCESS; - if(IsCorruptionDetectionEnabled()) + alignment = VMA_MAX(alignment, m_MinAllocationAlignment); + + if (IsCorruptionDetectionEnabled()) { size = VmaAlignUp(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE)); alignment = VmaAlignUp(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE)); @@ -12120,29 +12371,26 @@ VkResult VmaBlockVector::Allocate( { VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); - for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { res = AllocatePage( - currentFrameIndex, size, alignment, createInfo, suballocType, pAllocations + allocIndex); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) { break; } } } - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) { // Free all already created allocations. - while(allocIndex--) - { + while (allocIndex--) Free(pAllocations[allocIndex]); - } memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); } @@ -12150,7 +12398,6 @@ VkResult VmaBlockVector::Allocate( } VkResult VmaBlockVector::AllocatePage( - uint32_t currentFrameIndex, VkDeviceSize size, VkDeviceSize alignment, const VmaAllocationCreateInfo& createInfo, @@ -12158,377 +12405,203 @@ VkResult VmaBlockVector::AllocatePage( VmaAllocation* pAllocation) { const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0; - bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0; - const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; - const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0; - + VkDeviceSize freeMemory; { const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex); VmaBudget heapBudget = {}; - m_hAllocator->GetBudget(&heapBudget, heapIndex, 1); + m_hAllocator->GetHeapBudgets(&heapBudget, heapIndex, 1); freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0; } - - const bool canFallbackToDedicated = !IsCustomPool(); + + const bool canFallbackToDedicated = !HasExplicitBlockSize() && + (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0; const bool canCreateNewBlock = ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) && (m_Blocks.size() < m_MaxBlockCount) && (freeMemory >= size || !canFallbackToDedicated); uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK; - // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer. - // Which in turn is available only when maxBlockCount = 1. - if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1) - { - canMakeOtherLost = false; - } - // Upper address can only be used with linear allocator and within single memory block. - if(isUpperAddress && + if (isUpperAddress && (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1)) { return VK_ERROR_FEATURE_NOT_PRESENT; } - // Validate strategy. - switch(strategy) - { - case 0: - strategy = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT; - break; - case VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT: - case VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT: - case VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT: - break; - default: - return VK_ERROR_FEATURE_NOT_PRESENT; - } - // Early reject: requested allocation size is larger that maximum block size for this block vector. - if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize) + if (size + VMA_DEBUG_MARGIN > m_PreferredBlockSize) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - /* - Under certain condition, this whole section can be skipped for optimization, so - we move on directly to trying to allocate with canMakeOtherLost. That's the case - e.g. for custom pools with linear algorithm. - */ - if(!canMakeOtherLost || canCreateNewBlock) + // 1. Search existing allocations. Try to allocate. + if (m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) { - // 1. Search existing allocations. Try to allocate without making other allocations lost. - VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags; - allocFlagsCopy &= ~VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT; - - if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + // Use only last block. + if (!m_Blocks.empty()) { - // Use only last block. - if(!m_Blocks.empty()) + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back(); + VMA_ASSERT(pCurrBlock); + VkResult res = AllocateFromBlock( + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back(); - VMA_ASSERT(pCurrBlock); - VkResult res = AllocateFromBlock( - pCurrBlock, - currentFrameIndex, - size, - alignment, - allocFlagsCopy, - createInfo.pUserData, - suballocType, - strategy, - pAllocation); - if(res == VK_SUCCESS) - { - VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId()); - return VK_SUCCESS; - } + VMA_DEBUG_LOG_FORMAT(" Returned from last block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; } } - else + } + else + { + if (strategy != VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT) // MIN_MEMORY or default { - if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT) + const bool isHostVisible = + (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; + if(isHostVisible) { - // Forward order in m_Blocks - prefer blocks with smallest amount of free space. - for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex ) + const bool isMappingAllowed = (createInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; + /* + For non-mappable allocations, check blocks that are not mapped first. + For mappable allocations, check blocks that are already mapped first. + This way, having many blocks, we will separate mappable and non-mappable allocations, + hopefully limiting the number of blocks that are mapped, which will help tools like RenderDoc. + */ + for(size_t mappingI = 0; mappingI < 2; ++mappingI) { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pCurrBlock); - VkResult res = AllocateFromBlock( - pCurrBlock, - currentFrameIndex, - size, - alignment, - allocFlagsCopy, - createInfo.pUserData, - suballocType, - strategy, - pAllocation); - if(res == VK_SUCCESS) + // Forward order in m_Blocks - prefer blocks with smallest amount of free space. + for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) { - VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); - return VK_SUCCESS; + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pCurrBlock); + const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; + if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) + { + VkResult res = AllocateFromBlock( + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + } } } } - else // WORST_FIT, FIRST_FIT + else { - // Backward order in m_Blocks - prefer blocks with largest amount of free space. - for(size_t blockIndex = m_Blocks.size(); blockIndex--; ) + // Forward order in m_Blocks - prefer blocks with smallest amount of free space. + for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) { VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; VMA_ASSERT(pCurrBlock); VkResult res = AllocateFromBlock( - pCurrBlock, - currentFrameIndex, - size, - alignment, - allocFlagsCopy, - createInfo.pUserData, - suballocType, - strategy, - pAllocation); - if(res == VK_SUCCESS) + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); return VK_SUCCESS; } } } } - - // 2. Try to create new block. - if(canCreateNewBlock) + else // VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT { - // Calculate optimal size for new block. - VkDeviceSize newBlockSize = m_PreferredBlockSize; - uint32_t newBlockSizeShift = 0; - const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3; - - if(!m_ExplicitBlockSize) + // Backward order in m_Blocks - prefer blocks with largest amount of free space. + for (size_t blockIndex = m_Blocks.size(); blockIndex--; ) { - // Allocate 1/8, 1/4, 1/2 as first blocks. - const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize(); - for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i) + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pCurrBlock); + VkResult res = AllocateFromBlock(pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) { - const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; - if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2) - { - newBlockSize = smallerNewBlockSize; - ++newBlockSizeShift; - } - else - { - break; - } + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; } } + } + } - size_t newBlockIndex = 0; - VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? - CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; - // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. - if(!m_ExplicitBlockSize) - { - while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX) - { - const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; - if(smallerNewBlockSize >= size) - { - newBlockSize = smallerNewBlockSize; - ++newBlockSizeShift; - res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? - CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - else - { - break; - } - } - } + // 2. Try to create new block. + if (canCreateNewBlock) + { + // Calculate optimal size for new block. + VkDeviceSize newBlockSize = m_PreferredBlockSize; + uint32_t newBlockSizeShift = 0; + const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3; - if(res == VK_SUCCESS) + if (!m_ExplicitBlockSize) + { + // Allocate 1/8, 1/4, 1/2 as first blocks. + const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize(); + for (uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i) { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex]; - VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size); - - res = AllocateFromBlock( - pBlock, - currentFrameIndex, - size, - alignment, - allocFlagsCopy, - createInfo.pUserData, - suballocType, - strategy, - pAllocation); - if(res == VK_SUCCESS) + const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; + if (smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2) { - VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize); - return VK_SUCCESS; + newBlockSize = smallerNewBlockSize; + ++newBlockSizeShift; } else { - // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment. - return VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; } } } - } - // 3. Try to allocate from existing blocks with making other allocations lost. - if(canMakeOtherLost) - { - uint32_t tryIndex = 0; - for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex) + size_t newBlockIndex = 0; + VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? + CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; + // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. + if (!m_ExplicitBlockSize) { - VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL; - VmaAllocationRequest bestRequest = {}; - VkDeviceSize bestRequestCost = VK_WHOLE_SIZE; - - // 1. Search existing allocations. - if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT) + while (res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX) { - // Forward order in m_Blocks - prefer blocks with smallest amount of free space. - for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex ) + const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; + if (smallerNewBlockSize >= size) { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pCurrBlock); - VmaAllocationRequest currRequest = {}; - if(pCurrBlock->m_pMetadata->CreateAllocationRequest( - currentFrameIndex, - m_FrameInUseCount, - m_BufferImageGranularity, - size, - alignment, - (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0, - suballocType, - canMakeOtherLost, - strategy, - &currRequest)) - { - const VkDeviceSize currRequestCost = currRequest.CalcCost(); - if(pBestRequestBlock == VMA_NULL || - currRequestCost < bestRequestCost) - { - pBestRequestBlock = pCurrBlock; - bestRequest = currRequest; - bestRequestCost = currRequestCost; - - if(bestRequestCost == 0) - { - break; - } - } - } + newBlockSize = smallerNewBlockSize; + ++newBlockSizeShift; + res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? + CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; } - } - else // WORST_FIT, FIRST_FIT - { - // Backward order in m_Blocks - prefer blocks with largest amount of free space. - for(size_t blockIndex = m_Blocks.size(); blockIndex--; ) + else { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pCurrBlock); - VmaAllocationRequest currRequest = {}; - if(pCurrBlock->m_pMetadata->CreateAllocationRequest( - currentFrameIndex, - m_FrameInUseCount, - m_BufferImageGranularity, - size, - alignment, - (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0, - suballocType, - canMakeOtherLost, - strategy, - &currRequest)) - { - const VkDeviceSize currRequestCost = currRequest.CalcCost(); - if(pBestRequestBlock == VMA_NULL || - currRequestCost < bestRequestCost || - strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT) - { - pBestRequestBlock = pCurrBlock; - bestRequest = currRequest; - bestRequestCost = currRequestCost; - - if(bestRequestCost == 0 || - strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT) - { - break; - } - } - } + break; } } + } - if(pBestRequestBlock != VMA_NULL) - { - if(mapped) - { - VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } - } + if (res == VK_SUCCESS) + { + VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex]; + VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size); - if(pBestRequestBlock->m_pMetadata->MakeRequestedAllocationsLost( - currentFrameIndex, - m_FrameInUseCount, - &bestRequest)) - { - // Allocate from this pBlock. - *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString); - pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation); - UpdateHasEmptyBlock(); - (*pAllocation)->InitBlockAllocation( - pBestRequestBlock, - bestRequest.offset, - alignment, - size, - m_MemoryTypeIndex, - suballocType, - mapped, - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); - VMA_HEAVY_ASSERT(pBestRequestBlock->Validate()); - VMA_DEBUG_LOG(" Returned from existing block"); - (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData); - m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size); - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) - { - m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); - } - if(IsCorruptionDetectionEnabled()) - { - VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size); - VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value."); - } - return VK_SUCCESS; - } - // else: Some allocations must have been touched while we are here. Next try. + res = AllocateFromBlock( + pBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG_FORMAT(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize); + IncrementallySortBlocks(); + return VK_SUCCESS; } else { - // Could not find place in any of the blocks - break outer loop. - break; + // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment. + return VK_ERROR_OUT_OF_DEVICE_MEMORY; } } - /* Maximum number of tries exceeded - a very unlike event when many other - threads are simultaneously touching allocations making it impossible to make - lost at the same time as we try to allocate. */ - if(tryIndex == VMA_ALLOCATION_TRY_COUNT) - { - return VK_ERROR_TOO_MANY_OBJECTS; - } } return VK_ERROR_OUT_OF_DEVICE_MEMORY; } -void VmaBlockVector::Free( - const VmaAllocation hAllocation) +void VmaBlockVector::Free(const VmaAllocation hAllocation) { VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL; @@ -12536,7 +12609,7 @@ void VmaBlockVector::Free( { const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex); VmaBudget heapBudget = {}; - m_hAllocator->GetBudget(&heapBudget, heapIndex, 1); + m_hAllocator->GetHeapBudgets(&heapBudget, heapIndex, 1); budgetExceeded = heapBudget.usage >= heapBudget.budget; } @@ -12546,67 +12619,71 @@ void VmaBlockVector::Free( VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); - if(IsCorruptionDetectionEnabled()) + if (IsCorruptionDetectionEnabled()) { - VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize()); + VkResult res = pBlock->ValidateMagicValueAfterAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize()); VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value."); } - if(hAllocation->IsPersistentMap()) + if (hAllocation->IsPersistentMap()) { pBlock->Unmap(m_hAllocator, 1); } - pBlock->m_pMetadata->Free(hAllocation); + const bool hadEmptyBlockBeforeFree = HasEmptyBlock(); + pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle()); + pBlock->PostFree(m_hAllocator); VMA_HEAVY_ASSERT(pBlock->Validate()); - VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex); + VMA_DEBUG_LOG_FORMAT(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex); const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount; // pBlock became empty after this deallocation. - if(pBlock->m_pMetadata->IsEmpty()) + if (pBlock->m_pMetadata->IsEmpty()) { - // Already has empty block. We don't want to have two, so delete this one. - if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock) + // Already had empty block. We don't want to have two, so delete this one. + if ((hadEmptyBlockBeforeFree || budgetExceeded) && canDeleteBlock) { pBlockToDelete = pBlock; Remove(pBlock); } - // else: We now have an empty block - leave it. + // else: We now have one empty block - leave it. A hysteresis to avoid allocating whole block back and forth. } // pBlock didn't become empty, but we have another empty block - find and free that one. // (This is optional, heuristics.) - else if(m_HasEmptyBlock && canDeleteBlock) + else if (hadEmptyBlockBeforeFree && canDeleteBlock) { VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back(); - if(pLastBlock->m_pMetadata->IsEmpty()) + if (pLastBlock->m_pMetadata->IsEmpty()) { pBlockToDelete = pLastBlock; m_Blocks.pop_back(); } } - UpdateHasEmptyBlock(); IncrementallySortBlocks(); } // Destruction of a free block. Deferred until this point, outside of mutex // lock, for performance reason. - if(pBlockToDelete != VMA_NULL) + if (pBlockToDelete != VMA_NULL) { - VMA_DEBUG_LOG(" Deleted empty block"); + VMA_DEBUG_LOG_FORMAT(" Deleted empty block #%u", pBlockToDelete->GetId()); pBlockToDelete->Destroy(m_hAllocator); vma_delete(m_hAllocator, pBlockToDelete); } + + m_hAllocator->m_Budget.RemoveAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), hAllocation->GetSize()); + m_hAllocator->m_AllocationObjectAllocator.Free(hAllocation); } VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const { VkDeviceSize result = 0; - for(size_t i = m_Blocks.size(); i--; ) + for (size_t i = m_Blocks.size(); i--; ) { result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize()); - if(result >= m_PreferredBlockSize) + if (result >= m_PreferredBlockSize) { break; } @@ -12616,9 +12693,9 @@ VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock) { - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + for (uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) { - if(m_Blocks[blockIndex] == pBlock) + if (m_Blocks[blockIndex] == pBlock) { VmaVectorRemove(m_Blocks, blockIndex); return; @@ -12629,12 +12706,14 @@ void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock) void VmaBlockVector::IncrementallySortBlocks() { - if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + if (!m_IncrementalSort) + return; + if (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) { // Bubble sort only until first swap. - for(size_t i = 1; i < m_Blocks.size(); ++i) + for (size_t i = 1; i < m_Blocks.size(); ++i) { - if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize()) + if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize()) { VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]); return; @@ -12643,9 +12722,17 @@ void VmaBlockVector::IncrementallySortBlocks() } } +void VmaBlockVector::SortByFreeSize() +{ + VMA_SORT(m_Blocks.begin(), m_Blocks.end(), + [](VmaDeviceMemoryBlock* b1, VmaDeviceMemoryBlock* b2) -> bool + { + return b1->m_pMetadata->GetSumFreeSize() < b2->m_pMetadata->GetSumFreeSize(); + }); +} + VkResult VmaBlockVector::AllocateFromBlock( VmaDeviceMemoryBlock* pBlock, - uint32_t currentFrameIndex, VkDeviceSize size, VkDeviceSize alignment, VmaAllocationCreateFlags allocFlags, @@ -12654,84 +12741,115 @@ VkResult VmaBlockVector::AllocateFromBlock( uint32_t strategy, VmaAllocation* pAllocation) { - VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0); const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0; - const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; - const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0; VmaAllocationRequest currRequest = {}; - if(pBlock->m_pMetadata->CreateAllocationRequest( - currentFrameIndex, - m_FrameInUseCount, - m_BufferImageGranularity, + if (pBlock->m_pMetadata->CreateAllocationRequest( size, alignment, isUpperAddress, suballocType, - false, // canMakeOtherLost strategy, &currRequest)) { - // Allocate from pCurrBlock. - VMA_ASSERT(currRequest.itemsToMakeLostCount == 0); + return CommitAllocationRequest(currRequest, pBlock, alignment, allocFlags, pUserData, suballocType, pAllocation); + } + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} - if(mapped) +VkResult VmaBlockVector::CommitAllocationRequest( + VmaAllocationRequest& allocRequest, + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation) +{ + const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; + const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0; + const bool isMappingAllowed = (allocFlags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; + + pBlock->PostAlloc(m_hAllocator); + // Allocate from pCurrBlock. + if (mapped) + { + VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL); + if (res != VK_SUCCESS) { - VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } + return res; } - - *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString); - pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation); - UpdateHasEmptyBlock(); - (*pAllocation)->InitBlockAllocation( - pBlock, - currRequest.offset, - alignment, - size, - m_MemoryTypeIndex, - suballocType, - mapped, - (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); - VMA_HEAVY_ASSERT(pBlock->Validate()); + } + + *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(isMappingAllowed); + pBlock->m_pMetadata->Alloc(allocRequest, suballocType, *pAllocation); + (*pAllocation)->InitBlockAllocation( + pBlock, + allocRequest.allocHandle, + alignment, + allocRequest.size, // Not size, as actual allocation size may be larger than requested! + m_MemoryTypeIndex, + suballocType, + mapped); + VMA_HEAVY_ASSERT(pBlock->Validate()); + if (isUserDataString) + (*pAllocation)->SetName(m_hAllocator, (const char*)pUserData); + else (*pAllocation)->SetUserData(m_hAllocator, pUserData); - m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size); - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) - { - m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); - } - if(IsCorruptionDetectionEnabled()) - { - VkResult res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size); - VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value."); - } - return VK_SUCCESS; + m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), allocRequest.size); + if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) + { + m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); } - return VK_ERROR_OUT_OF_DEVICE_MEMORY; + if (IsCorruptionDetectionEnabled()) + { + VkResult res = pBlock->WriteMagicValueAfterAllocation(m_hAllocator, (*pAllocation)->GetOffset(), allocRequest.size); + VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value."); + } + return VK_SUCCESS; } VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex) { VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.pNext = m_pMemoryAllocateNext; allocInfo.memoryTypeIndex = m_MemoryTypeIndex; allocInfo.allocationSize = blockSize; #if VMA_BUFFER_DEVICE_ADDRESS // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature. VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; - if(m_hAllocator->m_UseKhrBufferDeviceAddress) + if (m_hAllocator->m_UseKhrBufferDeviceAddress) { allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); } -#endif // #if VMA_BUFFER_DEVICE_ADDRESS +#endif // VMA_BUFFER_DEVICE_ADDRESS + +#if VMA_MEMORY_PRIORITY + VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; + if (m_hAllocator->m_UseExtMemoryPriority) + { + VMA_ASSERT(m_Priority >= 0.f && m_Priority <= 1.f); + priorityInfo.priority = m_Priority; + VmaPnextChainPushFront(&allocInfo, &priorityInfo); + } +#endif // VMA_MEMORY_PRIORITY + +#if VMA_EXTERNAL_MEMORY + // Attach VkExportMemoryAllocateInfoKHR if necessary. + VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; + exportMemoryAllocInfo.handleTypes = m_hAllocator->GetExternalMemoryHandleTypeFlags(m_MemoryTypeIndex); + if (exportMemoryAllocInfo.handleTypes != 0) + { + VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); + } +#endif // VMA_EXTERNAL_MEMORY VkDeviceMemory mem = VK_NULL_HANDLE; VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem); - if(res < 0) + if (res < 0) { return res; } @@ -12747,10 +12865,11 @@ VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIn mem, allocInfo.allocationSize, m_NextBlockId++, - m_Algorithm); + m_Algorithm, + m_BufferImageGranularity); m_Blocks.push_back(pBlock); - if(pNewBlockIndex != VMA_NULL) + if (pNewBlockIndex != VMA_NULL) { *pNewBlockIndex = m_Blocks.size() - 1; } @@ -12758,5696 +12877,6736 @@ VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIn return VK_SUCCESS; } -void VmaBlockVector::ApplyDefragmentationMovesCpu( - class VmaBlockVectorDefragmentationContext* pDefragCtx, - const VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves) +bool VmaBlockVector::HasEmptyBlock() { - const size_t blockCount = m_Blocks.size(); - const bool isNonCoherent = m_hAllocator->IsMemoryTypeNonCoherent(m_MemoryTypeIndex); - - enum BLOCK_FLAG - { - BLOCK_FLAG_USED = 0x00000001, - BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION = 0x00000002, - }; - - struct BlockInfo - { - uint32_t flags; - void* pMappedData; - }; - VmaVector< BlockInfo, VmaStlAllocator > - blockInfo(blockCount, BlockInfo(), VmaStlAllocator(m_hAllocator->GetAllocationCallbacks())); - memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo)); - - // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED. - const size_t moveCount = moves.size(); - for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex) - { - const VmaDefragmentationMove& move = moves[moveIndex]; - blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED; - blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED; - } - - VMA_ASSERT(pDefragCtx->res == VK_SUCCESS); - - // Go over all blocks. Get mapped pointer or map if necessary. - for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex) + for (size_t index = 0, count = m_Blocks.size(); index < count; ++index) { - BlockInfo& currBlockInfo = blockInfo[blockIndex]; - VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex]; - if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0) + VmaDeviceMemoryBlock* const pBlock = m_Blocks[index]; + if (pBlock->m_pMetadata->IsEmpty()) { - currBlockInfo.pMappedData = pBlock->GetMappedData(); - // It is not originally mapped - map it. - if(currBlockInfo.pMappedData == VMA_NULL) - { - pDefragCtx->res = pBlock->Map(m_hAllocator, 1, &currBlockInfo.pMappedData); - if(pDefragCtx->res == VK_SUCCESS) - { - currBlockInfo.flags |= BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION; - } - } + return true; } } + return false; +} - // Go over all moves. Do actual data transfer. - if(pDefragCtx->res == VK_SUCCESS) - { - const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; - VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; - - for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex) - { - const VmaDefragmentationMove& move = moves[moveIndex]; - - const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex]; - const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex]; +#if VMA_STATS_STRING_ENABLED +void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json) +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); - VMA_ASSERT(srcBlockInfo.pMappedData && dstBlockInfo.pMappedData); - // Invalidate source. - if(isNonCoherent) - { - VmaDeviceMemoryBlock* const pSrcBlock = m_Blocks[move.srcBlockIndex]; - memRange.memory = pSrcBlock->GetDeviceMemory(); - memRange.offset = VmaAlignDown(move.srcOffset, nonCoherentAtomSize); - memRange.size = VMA_MIN( - VmaAlignUp(move.size + (move.srcOffset - memRange.offset), nonCoherentAtomSize), - pSrcBlock->m_pMetadata->GetSize() - memRange.offset); - (*m_hAllocator->GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange); - } + json.BeginObject(); + for (size_t i = 0; i < m_Blocks.size(); ++i) + { + json.BeginString(); + json.ContinueString(m_Blocks[i]->GetId()); + json.EndString(); - // THE PLACE WHERE ACTUAL DATA COPY HAPPENS. - memmove( - reinterpret_cast(dstBlockInfo.pMappedData) + move.dstOffset, - reinterpret_cast(srcBlockInfo.pMappedData) + move.srcOffset, - static_cast(move.size)); + json.BeginObject(); + json.WriteString("MapRefCount"); + json.WriteNumber(m_Blocks[i]->GetMapRefCount()); - if(IsCorruptionDetectionEnabled()) - { - VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset - VMA_DEBUG_MARGIN); - VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset + move.size); - } + m_Blocks[i]->m_pMetadata->PrintDetailedMap(json); + json.EndObject(); + } + json.EndObject(); +} +#endif // VMA_STATS_STRING_ENABLED - // Flush destination. - if(isNonCoherent) - { - VmaDeviceMemoryBlock* const pDstBlock = m_Blocks[move.dstBlockIndex]; - memRange.memory = pDstBlock->GetDeviceMemory(); - memRange.offset = VmaAlignDown(move.dstOffset, nonCoherentAtomSize); - memRange.size = VMA_MIN( - VmaAlignUp(move.size + (move.dstOffset - memRange.offset), nonCoherentAtomSize), - pDstBlock->m_pMetadata->GetSize() - memRange.offset); - (*m_hAllocator->GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange); - } - } +VkResult VmaBlockVector::CheckCorruption() +{ + if (!IsCorruptionDetectionEnabled()) + { + return VK_ERROR_FEATURE_NOT_PRESENT; } - // Go over all blocks in reverse order. Unmap those that were mapped just for defragmentation. - // Regardless of pCtx->res == VK_SUCCESS. - for(size_t blockIndex = blockCount; blockIndex--; ) + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + for (uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) { - const BlockInfo& currBlockInfo = blockInfo[blockIndex]; - if((currBlockInfo.flags & BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION) != 0) + VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pBlock); + VkResult res = pBlock->CheckCorruption(m_hAllocator); + if (res != VK_SUCCESS) { - VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex]; - pBlock->Unmap(m_hAllocator, 1); + return res; } } + return VK_SUCCESS; } -void VmaBlockVector::ApplyDefragmentationMovesGpu( - class VmaBlockVectorDefragmentationContext* pDefragCtx, - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkCommandBuffer commandBuffer) -{ - const size_t blockCount = m_Blocks.size(); +#endif // _VMA_BLOCK_VECTOR_FUNCTIONS - pDefragCtx->blockContexts.resize(blockCount); - memset(pDefragCtx->blockContexts.data(), 0, blockCount * sizeof(VmaBlockDefragmentationContext)); +#ifndef _VMA_DEFRAGMENTATION_CONTEXT_FUNCTIONS +VmaDefragmentationContext_T::VmaDefragmentationContext_T( + VmaAllocator hAllocator, + const VmaDefragmentationInfo& info) + : m_MaxPassBytes(info.maxBytesPerPass == 0 ? VK_WHOLE_SIZE : info.maxBytesPerPass), + m_MaxPassAllocations(info.maxAllocationsPerPass == 0 ? UINT32_MAX : info.maxAllocationsPerPass), + m_MoveAllocator(hAllocator->GetAllocationCallbacks()), + m_Moves(m_MoveAllocator) +{ + m_Algorithm = info.flags & VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK; - // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED. - const size_t moveCount = moves.size(); - for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex) + if (info.pool != VMA_NULL) { - const VmaDefragmentationMove& move = moves[moveIndex]; - - //if(move.type == VMA_ALLOCATION_TYPE_UNKNOWN) - { - // Old school move still require us to map the whole block - pDefragCtx->blockContexts[move.srcBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED; - pDefragCtx->blockContexts[move.dstBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED; - } + m_BlockVectorCount = 1; + m_PoolBlockVector = &info.pool->m_BlockVector; + m_pBlockVectors = &m_PoolBlockVector; + m_PoolBlockVector->SetIncrementalSort(false); + m_PoolBlockVector->SortByFreeSize(); } - - VMA_ASSERT(pDefragCtx->res == VK_SUCCESS); - - // Go over all blocks. Create and bind buffer for whole block if necessary. + else { - VkBufferCreateInfo bufCreateInfo; - VmaFillGpuDefragmentationBufferCreateInfo(bufCreateInfo); - - for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex) + m_BlockVectorCount = hAllocator->GetMemoryTypeCount(); + m_PoolBlockVector = VMA_NULL; + m_pBlockVectors = hAllocator->m_pBlockVectors; + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) { - VmaBlockDefragmentationContext& currBlockCtx = pDefragCtx->blockContexts[blockIndex]; - VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex]; - if((currBlockCtx.flags & VmaBlockDefragmentationContext::BLOCK_FLAG_USED) != 0) + VmaBlockVector* vector = m_pBlockVectors[i]; + if (vector != VMA_NULL) { - bufCreateInfo.size = pBlock->m_pMetadata->GetSize(); - pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)( - m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockCtx.hBuffer); - if(pDefragCtx->res == VK_SUCCESS) - { - pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)( - m_hAllocator->m_hDevice, currBlockCtx.hBuffer, pBlock->GetDeviceMemory(), 0); - } + vector->SetIncrementalSort(false); + vector->SortByFreeSize(); } } } - // Go over all moves. Post data transfer commands to command buffer. - if(pDefragCtx->res == VK_SUCCESS) + switch (m_Algorithm) { - for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex) + case 0: // Default algorithm + m_Algorithm = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT; + m_AlgorithmState = vma_new_array(hAllocator, StateBalanced, m_BlockVectorCount); + break; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + m_AlgorithmState = vma_new_array(hAllocator, StateBalanced, m_BlockVectorCount); + break; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + if (hAllocator->GetBufferImageGranularity() > 1) { - const VmaDefragmentationMove& move = moves[moveIndex]; - - const VmaBlockDefragmentationContext& srcBlockCtx = pDefragCtx->blockContexts[move.srcBlockIndex]; - const VmaBlockDefragmentationContext& dstBlockCtx = pDefragCtx->blockContexts[move.dstBlockIndex]; - - VMA_ASSERT(srcBlockCtx.hBuffer && dstBlockCtx.hBuffer); - - VkBufferCopy region = { - move.srcOffset, - move.dstOffset, - move.size }; - (*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)( - commandBuffer, srcBlockCtx.hBuffer, dstBlockCtx.hBuffer, 1, ®ion); + m_AlgorithmState = vma_new_array(hAllocator, StateExtensive, m_BlockVectorCount); } - } - - // Save buffers to defrag context for later destruction. - if(pDefragCtx->res == VK_SUCCESS && moveCount > 0) - { - pDefragCtx->res = VK_NOT_READY; + break; } } -void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats) +VmaDefragmentationContext_T::~VmaDefragmentationContext_T() { - for(size_t blockIndex = m_Blocks.size(); blockIndex--; ) + if (m_PoolBlockVector != VMA_NULL) + { + m_PoolBlockVector->SetIncrementalSort(true); + } + else { - VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex]; - if(pBlock->m_pMetadata->IsEmpty()) + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) { - if(m_Blocks.size() > m_MinBlockCount) - { - if(pDefragmentationStats != VMA_NULL) - { - ++pDefragmentationStats->deviceMemoryBlocksFreed; - pDefragmentationStats->bytesFreed += pBlock->m_pMetadata->GetSize(); - } - - VmaVectorRemove(m_Blocks, blockIndex); - pBlock->Destroy(m_hAllocator); - vma_delete(m_hAllocator, pBlock); - } - else - { - break; - } + VmaBlockVector* vector = m_pBlockVectors[i]; + if (vector != VMA_NULL) + vector->SetIncrementalSort(true); } } - UpdateHasEmptyBlock(); -} -void VmaBlockVector::UpdateHasEmptyBlock() -{ - m_HasEmptyBlock = false; - for(size_t index = 0, count = m_Blocks.size(); index < count; ++index) + if (m_AlgorithmState) { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[index]; - if(pBlock->m_pMetadata->IsEmpty()) + switch (m_Algorithm) { - m_HasEmptyBlock = true; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + vma_delete_array(m_MoveAllocator.m_pCallbacks, reinterpret_cast(m_AlgorithmState), m_BlockVectorCount); break; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + vma_delete_array(m_MoveAllocator.m_pCallbacks, reinterpret_cast(m_AlgorithmState), m_BlockVectorCount); + break; + default: + VMA_ASSERT(0); } } } -#if VMA_STATS_STRING_ENABLED - -void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json) +VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassMoveInfo& moveInfo) { - VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); - - json.BeginObject(); - - if(IsCustomPool()) + if (m_PoolBlockVector != VMA_NULL) { - const char* poolName = m_hParentPool->GetName(); - if(poolName != VMA_NULL && poolName[0] != '\0') - { - json.WriteString("Name"); - json.WriteString(poolName); - } - - json.WriteString("MemoryTypeIndex"); - json.WriteNumber(m_MemoryTypeIndex); - - json.WriteString("BlockSize"); - json.WriteNumber(m_PreferredBlockSize); - - json.WriteString("BlockCount"); - json.BeginObject(true); - if(m_MinBlockCount > 0) - { - json.WriteString("Min"); - json.WriteNumber((uint64_t)m_MinBlockCount); - } - if(m_MaxBlockCount < SIZE_MAX) - { - json.WriteString("Max"); - json.WriteNumber((uint64_t)m_MaxBlockCount); - } - json.WriteString("Cur"); - json.WriteNumber((uint64_t)m_Blocks.size()); - json.EndObject(); - - if(m_FrameInUseCount > 0) - { - json.WriteString("FrameInUseCount"); - json.WriteNumber(m_FrameInUseCount); - } + VmaMutexLockWrite lock(m_PoolBlockVector->GetMutex(), m_PoolBlockVector->GetAllocator()->m_UseMutex); - if(m_Algorithm != 0) - { - json.WriteString("Algorithm"); - json.WriteString(VmaAlgorithmToStr(m_Algorithm)); - } + if (m_PoolBlockVector->GetBlockCount() > 1) + ComputeDefragmentation(*m_PoolBlockVector, 0); + else if (m_PoolBlockVector->GetBlockCount() == 1) + ReallocWithinBlock(*m_PoolBlockVector, m_PoolBlockVector->GetBlock(0)); } else { - json.WriteString("PreferredBlockSize"); - json.WriteNumber(m_PreferredBlockSize); + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) + { + if (m_pBlockVectors[i] != VMA_NULL) + { + VmaMutexLockWrite lock(m_pBlockVectors[i]->GetMutex(), m_pBlockVectors[i]->GetAllocator()->m_UseMutex); + + if (m_pBlockVectors[i]->GetBlockCount() > 1) + { + if (ComputeDefragmentation(*m_pBlockVectors[i], i)) + break; + } + else if (m_pBlockVectors[i]->GetBlockCount() == 1) + { + if (ReallocWithinBlock(*m_pBlockVectors[i], m_pBlockVectors[i]->GetBlock(0))) + break; + } + } + } } - json.WriteString("Blocks"); - json.BeginObject(); - for(size_t i = 0; i < m_Blocks.size(); ++i) + moveInfo.moveCount = static_cast(m_Moves.size()); + if (moveInfo.moveCount > 0) { - json.BeginString(); - json.ContinueString(m_Blocks[i]->GetId()); - json.EndString(); - - m_Blocks[i]->m_pMetadata->PrintDetailedMap(json); + moveInfo.pMoves = m_Moves.data(); + return VK_INCOMPLETE; } - json.EndObject(); - json.EndObject(); + moveInfo.pMoves = VMA_NULL; + return VK_SUCCESS; } -#endif // #if VMA_STATS_STRING_ENABLED - -void VmaBlockVector::Defragment( - class VmaBlockVectorDefragmentationContext* pCtx, - VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags, - VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove, - VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove, - VkCommandBuffer commandBuffer) +VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMoveInfo& moveInfo) { - pCtx->res = VK_SUCCESS; - - const VkMemoryPropertyFlags memPropFlags = - m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags; - const bool isHostVisible = (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; + VMA_ASSERT(moveInfo.moveCount > 0 ? moveInfo.pMoves != VMA_NULL : true); - const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 && - isHostVisible; - const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0 && - !IsCorruptionDetectionEnabled() && - ((1u << m_MemoryTypeIndex) & m_hAllocator->GetGpuDefragmentationMemoryTypeBits()) != 0; + VkResult result = VK_SUCCESS; + VmaStlAllocator blockAllocator(m_MoveAllocator.m_pCallbacks); + VmaVector> immovableBlocks(blockAllocator); + VmaVector> mappedBlocks(blockAllocator); - // There are options to defragment this memory type. - if(canDefragmentOnCpu || canDefragmentOnGpu) + VmaAllocator allocator = VMA_NULL; + for (uint32_t i = 0; i < moveInfo.moveCount; ++i) { - bool defragmentOnGpu; - // There is only one option to defragment this memory type. - if(canDefragmentOnGpu != canDefragmentOnCpu) + VmaDefragmentationMove& move = moveInfo.pMoves[i]; + size_t prevCount = 0, currentCount = 0; + VkDeviceSize freedBlockSize = 0; + + uint32_t vectorIndex; + VmaBlockVector* vector; + if (m_PoolBlockVector != VMA_NULL) { - defragmentOnGpu = canDefragmentOnGpu; + vectorIndex = 0; + vector = m_PoolBlockVector; } - // Both options are available: Heuristics to choose the best one. else { - defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 || - m_hAllocator->IsIntegratedGpu(); + vectorIndex = move.srcAllocation->GetMemoryTypeIndex(); + vector = m_pBlockVectors[vectorIndex]; + VMA_ASSERT(vector != VMA_NULL); } - bool overlappingMoveSupported = !defragmentOnGpu; - - if(m_hAllocator->m_UseMutex) + switch (move.operation) { - if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL) + case VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY: + { + uint8_t mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + if (mapCount > 0) { - if(!m_Mutex.TryLockWrite()) + allocator = vector->m_hAllocator; + VmaDeviceMemoryBlock* newMapBlock = move.srcAllocation->GetBlock(); + bool notPresent = true; + for (FragmentedBlock& block : mappedBlocks) { - pCtx->res = VK_ERROR_INITIALIZATION_FAILED; - return; + if (block.block == newMapBlock) + { + notPresent = false; + block.data += mapCount; + break; + } } + if (notPresent) + mappedBlocks.push_back({ mapCount, newMapBlock }); } - else + + // Scope for locks, Free have it's own lock { - m_Mutex.LockWrite(); - pCtx->mutexLocked = true; + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + prevCount = vector->GetBlockCount(); + freedBlockSize = move.dstTmpAllocation->GetBlock()->m_pMetadata->GetSize(); + } + vector->Free(move.dstTmpAllocation); + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + currentCount = vector->GetBlockCount(); } - } - - pCtx->Begin(overlappingMoveSupported, flags); - - // Defragment. - const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove; - const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove; - pCtx->res = pCtx->GetAlgorithm()->Defragment(pCtx->defragmentationMoves, maxBytesToMove, maxAllocationsToMove, flags); + result = VK_INCOMPLETE; + break; + } + case VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE: + { + m_PassStats.bytesMoved -= move.srcAllocation->GetSize(); + --m_PassStats.allocationsMoved; + vector->Free(move.dstTmpAllocation); - // Accumulate statistics. - if(pStats != VMA_NULL) + VmaDeviceMemoryBlock* newBlock = move.srcAllocation->GetBlock(); + bool notPresent = true; + for (const FragmentedBlock& block : immovableBlocks) + { + if (block.block == newBlock) + { + notPresent = false; + break; + } + } + if (notPresent) + immovableBlocks.push_back({ vectorIndex, newBlock }); + break; + } + case VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY: { - const VkDeviceSize bytesMoved = pCtx->GetAlgorithm()->GetBytesMoved(); - const uint32_t allocationsMoved = pCtx->GetAlgorithm()->GetAllocationsMoved(); - pStats->bytesMoved += bytesMoved; - pStats->allocationsMoved += allocationsMoved; - VMA_ASSERT(bytesMoved <= maxBytesToMove); - VMA_ASSERT(allocationsMoved <= maxAllocationsToMove); - if(defragmentOnGpu) + m_PassStats.bytesMoved -= move.srcAllocation->GetSize(); + --m_PassStats.allocationsMoved; + // Scope for locks, Free have it's own lock { - maxGpuBytesToMove -= bytesMoved; - maxGpuAllocationsToMove -= allocationsMoved; + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + prevCount = vector->GetBlockCount(); + freedBlockSize = move.srcAllocation->GetBlock()->m_pMetadata->GetSize(); } - else + vector->Free(move.srcAllocation); + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + currentCount = vector->GetBlockCount(); + } + freedBlockSize *= prevCount - currentCount; + + VkDeviceSize dstBlockSize; + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + dstBlockSize = move.dstTmpAllocation->GetBlock()->m_pMetadata->GetSize(); + } + vector->Free(move.dstTmpAllocation); { - maxCpuBytesToMove -= bytesMoved; - maxCpuAllocationsToMove -= allocationsMoved; + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + freedBlockSize += dstBlockSize * (currentCount - vector->GetBlockCount()); + currentCount = vector->GetBlockCount(); } + + result = VK_INCOMPLETE; + break; + } + default: + VMA_ASSERT(0); } - if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL) + if (prevCount > currentCount) { - if(m_hAllocator->m_UseMutex) - m_Mutex.UnlockWrite(); - - if(pCtx->res >= VK_SUCCESS && !pCtx->defragmentationMoves.empty()) - pCtx->res = VK_NOT_READY; - - return; + size_t freedBlocks = prevCount - currentCount; + m_PassStats.deviceMemoryBlocksFreed += static_cast(freedBlocks); + m_PassStats.bytesFreed += freedBlockSize; } - - if(pCtx->res >= VK_SUCCESS) + + switch (m_Algorithm) { - if(defragmentOnGpu) - { - ApplyDefragmentationMovesGpu(pCtx, pCtx->defragmentationMoves, commandBuffer); - } - else + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + { + if (m_AlgorithmState != VMA_NULL) { - ApplyDefragmentationMovesCpu(pCtx, pCtx->defragmentationMoves); + // Avoid unnecessary tries to allocate when new free block is available + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[vectorIndex]; + if (state.firstFreeBlock != SIZE_MAX) + { + const size_t diff = prevCount - currentCount; + if (state.firstFreeBlock >= diff) + { + state.firstFreeBlock -= diff; + if (state.firstFreeBlock != 0) + state.firstFreeBlock -= vector->GetBlock(state.firstFreeBlock - 1)->m_pMetadata->IsEmpty(); + } + else + state.firstFreeBlock = 0; + } } } + } } -} + moveInfo.moveCount = 0; + moveInfo.pMoves = VMA_NULL; + m_Moves.clear(); -void VmaBlockVector::DefragmentationEnd( - class VmaBlockVectorDefragmentationContext* pCtx, - VmaDefragmentationStats* pStats) -{ - // Destroy buffers. - for(size_t blockIndex = pCtx->blockContexts.size(); blockIndex--; ) + // Update stats + m_GlobalStats.allocationsMoved += m_PassStats.allocationsMoved; + m_GlobalStats.bytesFreed += m_PassStats.bytesFreed; + m_GlobalStats.bytesMoved += m_PassStats.bytesMoved; + m_GlobalStats.deviceMemoryBlocksFreed += m_PassStats.deviceMemoryBlocksFreed; + m_PassStats = { 0 }; + + // Move blocks with immovable allocations according to algorithm + if (immovableBlocks.size() > 0) { - VmaBlockDefragmentationContext& blockCtx = pCtx->blockContexts[blockIndex]; - if(blockCtx.hBuffer) + do { - (*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)( - m_hAllocator->m_hDevice, blockCtx.hBuffer, m_hAllocator->GetAllocationCallbacks()); - } - } + if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) + { + if (m_AlgorithmState != VMA_NULL) + { + bool swapped = false; + // Move to the start of free blocks range + for (const FragmentedBlock& block : immovableBlocks) + { + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[block.data]; + if (state.operation != StateExtensive::Operation::Cleanup) + { + VmaBlockVector* vector = m_pBlockVectors[block.data]; + VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); - if(pCtx->res >= VK_SUCCESS) - { - FreeEmptyBlocks(pStats); + for (size_t i = 0, count = vector->GetBlockCount() - m_ImmovableBlockCount; i < count; ++i) + { + if (vector->GetBlock(i) == block.block) + { + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[vector->GetBlockCount() - ++m_ImmovableBlockCount]); + if (state.firstFreeBlock != SIZE_MAX) + { + if (i + 1 < state.firstFreeBlock) + { + if (state.firstFreeBlock > 1) + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[--state.firstFreeBlock]); + else + --state.firstFreeBlock; + } + } + swapped = true; + break; + } + } + } + } + if (swapped) + result = VK_INCOMPLETE; + break; + } + } + + // Move to the beginning + for (const FragmentedBlock& block : immovableBlocks) + { + VmaBlockVector* vector = m_pBlockVectors[block.data]; + VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + + for (size_t i = m_ImmovableBlockCount; i < vector->GetBlockCount(); ++i) + { + if (vector->GetBlock(i) == block.block) + { + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]); + break; + } + } + } + } while (false); } - if(pCtx->mutexLocked) + // Bulk-map destination blocks + for (const FragmentedBlock& block : mappedBlocks) { - VMA_ASSERT(m_hAllocator->m_UseMutex); - m_Mutex.UnlockWrite(); + VkResult res = block.block->Map(allocator, block.data, VMA_NULL); + VMA_ASSERT(res == VK_SUCCESS); } + return result; } -uint32_t VmaBlockVector::ProcessDefragmentations( - class VmaBlockVectorDefragmentationContext *pCtx, - VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves) +bool VmaDefragmentationContext_T::ComputeDefragmentation(VmaBlockVector& vector, size_t index) { - VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); - - const uint32_t moveCount = std::min(uint32_t(pCtx->defragmentationMoves.size()) - pCtx->defragmentationMovesProcessed, maxMoves); - - for(uint32_t i = 0; i < moveCount; ++ i) + switch (m_Algorithm) { - VmaDefragmentationMove& move = pCtx->defragmentationMoves[pCtx->defragmentationMovesProcessed + i]; - - pMove->allocation = move.hAllocation; - pMove->memory = move.pDstBlock->GetDeviceMemory(); - pMove->offset = move.dstOffset; - - ++ pMove; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT: + return ComputeDefragmentation_Fast(vector); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + return ComputeDefragmentation_Balanced(vector, index, true); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT: + return ComputeDefragmentation_Full(vector); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + return ComputeDefragmentation_Extensive(vector, index); + default: + VMA_ASSERT(0); + return ComputeDefragmentation_Balanced(vector, index, true); } - - pCtx->defragmentationMovesProcessed += moveCount; - - return moveCount; } -void VmaBlockVector::CommitDefragmentations( - class VmaBlockVectorDefragmentationContext *pCtx, - VmaDefragmentationStats* pStats) +VmaDefragmentationContext_T::MoveAllocationData VmaDefragmentationContext_T::GetMoveData( + VmaAllocHandle handle, VmaBlockMetadata* metadata) { - VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); - - for(uint32_t i = pCtx->defragmentationMovesCommitted; i < pCtx->defragmentationMovesProcessed; ++ i) - { - const VmaDefragmentationMove &move = pCtx->defragmentationMoves[i]; + MoveAllocationData moveData; + moveData.move.srcAllocation = (VmaAllocation)metadata->GetAllocationUserData(handle); + moveData.size = moveData.move.srcAllocation->GetSize(); + moveData.alignment = moveData.move.srcAllocation->GetAlignment(); + moveData.type = moveData.move.srcAllocation->GetSuballocationType(); + moveData.flags = 0; - move.pSrcBlock->m_pMetadata->FreeAtOffset(move.srcOffset); - move.hAllocation->ChangeBlockAllocation(m_hAllocator, move.pDstBlock, move.dstOffset); - } + if (moveData.move.srcAllocation->IsPersistentMap()) + moveData.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + if (moveData.move.srcAllocation->IsMappingAllowed()) + moveData.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - pCtx->defragmentationMovesCommitted = pCtx->defragmentationMovesProcessed; - FreeEmptyBlocks(pStats); + return moveData; } -size_t VmaBlockVector::CalcAllocationCount() const +VmaDefragmentationContext_T::CounterStatus VmaDefragmentationContext_T::CheckCounters(VkDeviceSize bytes) { - size_t result = 0; - for(size_t i = 0; i < m_Blocks.size(); ++i) + // Ignore allocation if will exceed max size for copy + if (m_PassStats.bytesMoved + bytes > m_MaxPassBytes) { - result += m_Blocks[i]->m_pMetadata->GetAllocationCount(); + if (++m_IgnoredAllocs < MAX_ALLOCS_TO_IGNORE) + return CounterStatus::Ignore; + else + return CounterStatus::End; } - return result; + return CounterStatus::Pass; } -bool VmaBlockVector::IsBufferImageGranularityConflictPossible() const +bool VmaDefragmentationContext_T::IncrementCounters(VkDeviceSize bytes) { - if(m_BufferImageGranularity == 1) + m_PassStats.bytesMoved += bytes; + // Early return when max found + if (++m_PassStats.allocationsMoved >= m_MaxPassAllocations || m_PassStats.bytesMoved >= m_MaxPassBytes) { - return false; + VMA_ASSERT(m_PassStats.allocationsMoved == m_MaxPassAllocations || + m_PassStats.bytesMoved == m_MaxPassBytes && "Exceeded maximal pass threshold!"); + return true; } - VmaSuballocationType lastSuballocType = VMA_SUBALLOCATION_TYPE_FREE; - for(size_t i = 0, count = m_Blocks.size(); i < count; ++i) + return false; +} + +bool VmaDefragmentationContext_T::ReallocWithinBlock(VmaBlockVector& vector, VmaDeviceMemoryBlock* block) +{ + VmaBlockMetadata* metadata = block->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[i]; - VMA_ASSERT(m_Algorithm == 0); - VmaBlockMetadata_Generic* const pMetadata = (VmaBlockMetadata_Generic*)pBlock->m_pMetadata; - if(pMetadata->IsBufferImageGranularityConflictPossible(m_BufferImageGranularity, lastSuballocType)) + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); + } + + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } } } return false; } -void VmaBlockVector::MakePoolAllocationsLost( - uint32_t currentFrameIndex, - size_t* pLostAllocationCount) +bool VmaDefragmentationContext_T::AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, VmaBlockVector& vector) { - VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); - size_t lostAllocationCount = 0; - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) - { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - lostAllocationCount += pBlock->m_pMetadata->MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount); - } - if(pLostAllocationCount != VMA_NULL) + for (; start < end; ++start) { - *pLostAllocationCount = lostAllocationCount; + VmaDeviceMemoryBlock* dstBlock = vector.GetBlock(start); + if (dstBlock->m_pMetadata->GetSumFreeSize() >= data.size) + { + if (vector.AllocateFromBlock(dstBlock, + data.size, + data.alignment, + data.flags, + this, + data.type, + 0, + &data.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(data.move); + if (IncrementCounters(data.size)) + return true; + break; + } + } } + return false; } -VkResult VmaBlockVector::CheckCorruption() +bool VmaDefragmentationContext_T::ComputeDefragmentation_Fast(VmaBlockVector& vector) { - if(!IsCorruptionDetectionEnabled()) - { - return VK_ERROR_FEATURE_NOT_PRESENT; - } + // Move only between blocks - VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + // Go through allocations in last blocks and try to fit them inside first ones + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - VkResult res = pBlock->CheckCorruption(m_hAllocator); - if(res != VK_SUCCESS) + VmaBlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) { - return res; + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); + } + + // Check all previous blocks for free space + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; } } - return VK_SUCCESS; + return false; } -void VmaBlockVector::AddStats(VmaStats* pStats) +bool VmaDefragmentationContext_T::ComputeDefragmentation_Balanced(VmaBlockVector& vector, size_t index, bool update) { - const uint32_t memTypeIndex = m_MemoryTypeIndex; - const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex); + // Go over every allocation and try to fit it in previous blocks at lowest offsets, + // if not possible: realloc within single block to minimize offset (exclude offset == 0), + // but only if there are noticeable gaps between them (some heuristic, ex. average size of allocation in block) + VMA_ASSERT(m_AlgorithmState != VMA_NULL); - VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + StateBalanced& vectorState = reinterpret_cast(m_AlgorithmState)[index]; + if (update && vectorState.avgAllocSize == UINT64_MAX) + UpdateVectorStatistics(vector, vectorState); - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + const size_t startMoveCount = m_Moves.size(); + VkDeviceSize minimalFreeRegion = vectorState.avgFreeSize / 2; + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) { - const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - VMA_HEAVY_ASSERT(pBlock->Validate()); - VmaStatInfo allocationStatInfo; - pBlock->m_pMetadata->CalcAllocationStatInfo(allocationStatInfo); - VmaAddStatInfo(pStats->total, allocationStatInfo); - VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo); - VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo); - } -} + VmaDeviceMemoryBlock* block = vector.GetBlock(i); + VmaBlockMetadata* metadata = block->m_pMetadata; + VkDeviceSize prevFreeRegionSize = 0; -//////////////////////////////////////////////////////////////////////////////// -// VmaDefragmentationAlgorithm_Generic members definition + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); + } -VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex, - bool overlappingMoveSupported) : - VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex), - m_AllocationCount(0), - m_AllAllocations(false), - m_BytesMoved(0), - m_AllocationsMoved(0), - m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ - // Create block info for each block. - const size_t blockCount = m_pBlockVector->m_Blocks.size(); - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) - { - BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks()); - pBlockInfo->m_OriginalBlockIndex = blockIndex; - pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex]; - m_Blocks.push_back(pBlockInfo); - } + // Check all previous blocks for free space + const size_t prevMoveCount = m_Moves.size(); + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; - // Sort them by m_pBlock pointer value. - VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess()); -} + VkDeviceSize nextFreeRegionSize = metadata->GetNextFreeRegionSize(handle); + // If no room found then realloc within block for lower offset + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + // Check if realloc will make sense + if (prevFreeRegionSize >= minimalFreeRegion || + nextFreeRegionSize >= minimalFreeRegion || + moveData.size <= vectorState.avgFreeSize || + moveData.size <= vectorState.avgAllocSize) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } + } + } + prevFreeRegionSize = nextFreeRegionSize; + } + } -VmaDefragmentationAlgorithm_Generic::~VmaDefragmentationAlgorithm_Generic() -{ - for(size_t i = m_Blocks.size(); i--; ) + // No moves performed, update statistics to current vector state + if (startMoveCount == m_Moves.size() && !update) { - vma_delete(m_hAllocator, m_Blocks[i]); + vectorState.avgAllocSize = UINT64_MAX; + return ComputeDefragmentation_Balanced(vector, index, false); } + return false; } -void VmaDefragmentationAlgorithm_Generic::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) +bool VmaDefragmentationContext_T::ComputeDefragmentation_Full(VmaBlockVector& vector) { - // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost. - if(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST) + // Go over every allocation and try to fit it in previous blocks at lowest offsets, + // if not possible: realloc within single block to minimize offset (exclude offset == 0) + + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) { - VmaDeviceMemoryBlock* pBlock = hAlloc->GetBlock(); - BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess()); - if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock) - { - AllocationInfo allocInfo = AllocationInfo(hAlloc, pChanged); - (*it)->m_Allocations.push_back(allocInfo); - } - else + VmaDeviceMemoryBlock* block = vector.GetBlock(i); + VmaBlockMetadata* metadata = block->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) { - VMA_ASSERT(0); - } + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); + } + + // Check all previous blocks for free space + const size_t prevMoveCount = m_Moves.size(); + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; - ++m_AllocationCount; + // If no room found then realloc within block for lower offset + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } + } + } } + return false; } -VkResult VmaDefragmentationAlgorithm_Generic::DefragmentRound( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - bool freeOldAllocations) +bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVector& vector, size_t index) { - if(m_Blocks.empty()) - { - return VK_SUCCESS; - } + // First free single block, then populate it to the brim, then free another block, and so on - // This is a choice based on research. - // Option 1: - uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT; - // Option 2: - //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT; - // Option 3: - //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT; + // Fallback to previous algorithm since without granularity conflicts it can achieve max packing + if (vector.m_BufferImageGranularity == 1) + return ComputeDefragmentation_Full(vector); - size_t srcBlockMinIndex = 0; - // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations. - /* - if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT) + VMA_ASSERT(m_AlgorithmState != VMA_NULL); + + StateExtensive& vectorState = reinterpret_cast(m_AlgorithmState)[index]; + + bool texturePresent = false, bufferPresent = false, otherPresent = false; + switch (vectorState.operation) { - const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount(); - if(blocksWithNonMovableCount > 0) - { - srcBlockMinIndex = blocksWithNonMovableCount - 1; + case StateExtensive::Operation::Done: // Vector defragmented + return false; + case StateExtensive::Operation::FindFreeBlockBuffer: + case StateExtensive::Operation::FindFreeBlockTexture: + case StateExtensive::Operation::FindFreeBlockAll: + { + // No more blocks to free, just perform fast realloc and move to cleanup + if (vectorState.firstFreeBlock == 0) + { + vectorState.operation = StateExtensive::Operation::Cleanup; + return ComputeDefragmentation_Fast(vector); } - } - */ - size_t srcBlockIndex = m_Blocks.size() - 1; - size_t srcAllocIndex = SIZE_MAX; - for(;;) - { - // 1. Find next allocation to move. - // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source". - // 1.2. Then start from last to first m_Allocations. - while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size()) + // No free blocks, have to clear last one + size_t last = (vectorState.firstFreeBlock == SIZE_MAX ? vector.GetBlockCount() : vectorState.firstFreeBlock) - 1; + VmaBlockMetadata* freeMetadata = vector.GetBlock(last)->m_pMetadata; + + const size_t prevMoveCount = m_Moves.size(); + for (VmaAllocHandle handle = freeMetadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = freeMetadata->GetNextAllocation(handle)) { - if(m_Blocks[srcBlockIndex]->m_Allocations.empty()) + MoveAllocationData moveData = GetMoveData(handle, freeMetadata); + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) { - // Finished: no more allocations to process. - if(srcBlockIndex == srcBlockMinIndex) - { - return VK_SUCCESS; - } - else - { - --srcBlockIndex; - srcAllocIndex = SIZE_MAX; - } + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); } - else + + // Check all previous blocks for free space + if (AllocInOtherBlock(0, last, moveData, vector)) { - srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1; + // Full clear performed already + if (prevMoveCount != m_Moves.size() && freeMetadata->GetNextAllocation(handle) == VK_NULL_HANDLE) + reinterpret_cast(m_AlgorithmState)[index] = last; + return true; } } - - BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex]; - AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex]; - - const VkDeviceSize size = allocInfo.m_hAllocation->GetSize(); - const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset(); - const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment(); - const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType(); - // 2. Try to find new place for this allocation in preceding or current block. - for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex) + if (prevMoveCount == m_Moves.size()) { - BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex]; - VmaAllocationRequest dstAllocRequest; - if(pDstBlockInfo->m_pBlock->m_pMetadata->CreateAllocationRequest( - m_CurrentFrameIndex, - m_pBlockVector->GetFrameInUseCount(), - m_pBlockVector->GetBufferImageGranularity(), - size, - alignment, - false, // upperAddress - suballocType, - false, // canMakeOtherLost - strategy, - &dstAllocRequest) && - MoveMakesSense( - dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset)) + // Cannot perform full clear, have to move data in other blocks around + if (last != 0) { - VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0); - - // Reached limit on number of allocations or bytes to move. - if((m_AllocationsMoved + 1 > maxAllocationsToMove) || - (m_BytesMoved + size > maxBytesToMove)) - { - return VK_SUCCESS; - } - - VmaDefragmentationMove move = {}; - move.srcBlockIndex = pSrcBlockInfo->m_OriginalBlockIndex; - move.dstBlockIndex = pDstBlockInfo->m_OriginalBlockIndex; - move.srcOffset = srcOffset; - move.dstOffset = dstAllocRequest.offset; - move.size = size; - move.hAllocation = allocInfo.m_hAllocation; - move.pSrcBlock = pSrcBlockInfo->m_pBlock; - move.pDstBlock = pDstBlockInfo->m_pBlock; - - moves.push_back(move); - - pDstBlockInfo->m_pBlock->m_pMetadata->Alloc( - dstAllocRequest, - suballocType, - size, - allocInfo.m_hAllocation); - - if(freeOldAllocations) - { - pSrcBlockInfo->m_pBlock->m_pMetadata->FreeAtOffset(srcOffset); - allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset); - } - - if(allocInfo.m_pChanged != VMA_NULL) + for (size_t i = last - 1; i; --i) { - *allocInfo.m_pChanged = VK_TRUE; + if (ReallocWithinBlock(vector, vector.GetBlock(i))) + return true; } + } - ++m_AllocationsMoved; - m_BytesMoved += size; - - VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex); - - break; + if (prevMoveCount == m_Moves.size()) + { + // No possible reallocs within blocks, try to move them around fast + return ComputeDefragmentation_Fast(vector); } } - - // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round. - - if(srcAllocIndex > 0) + else { - --srcAllocIndex; + switch (vectorState.operation) + { + case StateExtensive::Operation::FindFreeBlockBuffer: + vectorState.operation = StateExtensive::Operation::MoveBuffers; + break; + case StateExtensive::Operation::FindFreeBlockTexture: + vectorState.operation = StateExtensive::Operation::MoveTextures; + break; + case StateExtensive::Operation::FindFreeBlockAll: + vectorState.operation = StateExtensive::Operation::MoveAll; + break; + default: + VMA_ASSERT(0); + vectorState.operation = StateExtensive::Operation::MoveTextures; + } + vectorState.firstFreeBlock = last; + // Nothing done, block found without reallocations, can perform another reallocs in same pass + return ComputeDefragmentation_Extensive(vector, index); } - else + break; + } + case StateExtensive::Operation::MoveTextures: + { + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) { - if(srcBlockIndex > 0) + if (texturePresent) { - --srcBlockIndex; - srcAllocIndex = SIZE_MAX; + vectorState.operation = StateExtensive::Operation::FindFreeBlockTexture; + return ComputeDefragmentation_Extensive(vector, index); } - else + + if (!bufferPresent && !otherPresent) { - return VK_SUCCESS; + vectorState.operation = StateExtensive::Operation::Cleanup; + break; } + + // No more textures to move, check buffers + vectorState.operation = StateExtensive::Operation::MoveBuffers; + bufferPresent = false; + otherPresent = false; } + else + break; } -} - -size_t VmaDefragmentationAlgorithm_Generic::CalcBlocksWithNonMovableCount() const -{ - size_t result = 0; - for(size_t i = 0; i < m_Blocks.size(); ++i) + case StateExtensive::Operation::MoveBuffers: { - if(m_Blocks[i]->m_HasNonMovableAllocations) + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_BUFFER, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) { - ++result; - } - } - return result; -} + if (bufferPresent) + { + vectorState.operation = StateExtensive::Operation::FindFreeBlockBuffer; + return ComputeDefragmentation_Extensive(vector, index); + } -VkResult VmaDefragmentationAlgorithm_Generic::Defragment( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - VmaDefragmentationFlags flags) -{ - if(!m_AllAllocations && m_AllocationCount == 0) - { - return VK_SUCCESS; - } + if (!otherPresent) + { + vectorState.operation = StateExtensive::Operation::Cleanup; + break; + } - const size_t blockCount = m_Blocks.size(); - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + // No more buffers to move, check all others + vectorState.operation = StateExtensive::Operation::MoveAll; + otherPresent = false; + } + else + break; + } + case StateExtensive::Operation::MoveAll: { - BlockInfo* pBlockInfo = m_Blocks[blockIndex]; - - if(m_AllAllocations) + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_FREE, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) { - VmaBlockMetadata_Generic* pMetadata = (VmaBlockMetadata_Generic*)pBlockInfo->m_pBlock->m_pMetadata; - for(VmaSuballocationList::const_iterator it = pMetadata->m_Suballocations.begin(); - it != pMetadata->m_Suballocations.end(); - ++it) + if (otherPresent) { - if(it->type != VMA_SUBALLOCATION_TYPE_FREE) - { - AllocationInfo allocInfo = AllocationInfo(it->hAllocation, VMA_NULL); - pBlockInfo->m_Allocations.push_back(allocInfo); - } + vectorState.operation = StateExtensive::Operation::FindFreeBlockBuffer; + return ComputeDefragmentation_Extensive(vector, index); } + // Everything moved + vectorState.operation = StateExtensive::Operation::Cleanup; } - - pBlockInfo->CalcHasNonMovableAllocations(); - - // This is a choice based on research. - // Option 1: - pBlockInfo->SortAllocationsByOffsetDescending(); - // Option 2: - //pBlockInfo->SortAllocationsBySizeDescending(); + break; } - - // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks. - VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination()); - - // This is a choice based on research. - const uint32_t roundCount = 2; - - // Execute defragmentation rounds (the main part). - VkResult result = VK_SUCCESS; - for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round) - { - result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove, !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)); + case StateExtensive::Operation::Cleanup: + // Cleanup is handled below so that other operations may reuse the cleanup code. This case is here to prevent the unhandled enum value warning (C4062). + break; } - return result; -} - -bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense( - size_t dstBlockIndex, VkDeviceSize dstOffset, - size_t srcBlockIndex, VkDeviceSize srcOffset) -{ - if(dstBlockIndex < srcBlockIndex) - { - return true; - } - if(dstBlockIndex > srcBlockIndex) - { - return false; - } - if(dstOffset < srcOffset) + if (vectorState.operation == StateExtensive::Operation::Cleanup) { - return true; + // All other work done, pack data in blocks even tighter if possible + const size_t prevMoveCount = m_Moves.size(); + for (size_t i = 0; i < vector.GetBlockCount(); ++i) + { + if (ReallocWithinBlock(vector, vector.GetBlock(i))) + return true; + } + + if (prevMoveCount == m_Moves.size()) + vectorState.operation = StateExtensive::Operation::Done; } return false; } -//////////////////////////////////////////////////////////////////////////////// -// VmaDefragmentationAlgorithm_Fast - -VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex, - bool overlappingMoveSupported) : - VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex), - m_OverlappingMoveSupported(overlappingMoveSupported), - m_AllocationCount(0), - m_AllAllocations(false), - m_BytesMoved(0), - m_AllocationsMoved(0), - m_BlockInfos(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ - VMA_ASSERT(VMA_DEBUG_MARGIN == 0); - -} - -VmaDefragmentationAlgorithm_Fast::~VmaDefragmentationAlgorithm_Fast() -{ -} - -VkResult VmaDefragmentationAlgorithm_Fast::Defragment( - VmaVector< VmaDefragmentationMove, VmaStlAllocator >& moves, - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove, - VmaDefragmentationFlags flags) +void VmaDefragmentationContext_T::UpdateVectorStatistics(VmaBlockVector& vector, StateBalanced& state) { - VMA_ASSERT(m_AllAllocations || m_pBlockVector->CalcAllocationCount() == m_AllocationCount); - - const size_t blockCount = m_pBlockVector->GetBlockCount(); - if(blockCount == 0 || maxBytesToMove == 0 || maxAllocationsToMove == 0) - { - return VK_SUCCESS; - } - - PreprocessMetadata(); - - // Sort blocks in order from most destination. + size_t allocCount = 0; + size_t freeCount = 0; + state.avgFreeSize = 0; + state.avgAllocSize = 0; - m_BlockInfos.resize(blockCount); - for(size_t i = 0; i < blockCount; ++i) + for (size_t i = 0; i < vector.GetBlockCount(); ++i) { - m_BlockInfos[i].origBlockIndex = i; - } - - VMA_SORT(m_BlockInfos.begin(), m_BlockInfos.end(), [this](const BlockInfo& lhs, const BlockInfo& rhs) -> bool { - return m_pBlockVector->GetBlock(lhs.origBlockIndex)->m_pMetadata->GetSumFreeSize() < - m_pBlockVector->GetBlock(rhs.origBlockIndex)->m_pMetadata->GetSumFreeSize(); - }); - - // THE MAIN ALGORITHM - - FreeSpaceDatabase freeSpaceDb; - - size_t dstBlockInfoIndex = 0; - size_t dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex; - VmaDeviceMemoryBlock* pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex); - VmaBlockMetadata_Generic* pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata; - VkDeviceSize dstBlockSize = pDstMetadata->GetSize(); - VkDeviceSize dstOffset = 0; - - bool end = false; - for(size_t srcBlockInfoIndex = 0; !end && srcBlockInfoIndex < blockCount; ++srcBlockInfoIndex) - { - const size_t srcOrigBlockIndex = m_BlockInfos[srcBlockInfoIndex].origBlockIndex; - VmaDeviceMemoryBlock* const pSrcBlock = m_pBlockVector->GetBlock(srcOrigBlockIndex); - VmaBlockMetadata_Generic* const pSrcMetadata = (VmaBlockMetadata_Generic*)pSrcBlock->m_pMetadata; - for(VmaSuballocationList::iterator srcSuballocIt = pSrcMetadata->m_Suballocations.begin(); - !end && srcSuballocIt != pSrcMetadata->m_Suballocations.end(); ) - { - VmaAllocation_T* const pAlloc = srcSuballocIt->hAllocation; - const VkDeviceSize srcAllocAlignment = pAlloc->GetAlignment(); - const VkDeviceSize srcAllocSize = srcSuballocIt->size; - if(m_AllocationsMoved == maxAllocationsToMove || - m_BytesMoved + srcAllocSize > maxBytesToMove) - { - end = true; - break; - } - const VkDeviceSize srcAllocOffset = srcSuballocIt->offset; - - VmaDefragmentationMove move = {}; - // Try to place it in one of free spaces from the database. - size_t freeSpaceInfoIndex; - VkDeviceSize dstAllocOffset; - if(freeSpaceDb.Fetch(srcAllocAlignment, srcAllocSize, - freeSpaceInfoIndex, dstAllocOffset)) - { - size_t freeSpaceOrigBlockIndex = m_BlockInfos[freeSpaceInfoIndex].origBlockIndex; - VmaDeviceMemoryBlock* pFreeSpaceBlock = m_pBlockVector->GetBlock(freeSpaceOrigBlockIndex); - VmaBlockMetadata_Generic* pFreeSpaceMetadata = (VmaBlockMetadata_Generic*)pFreeSpaceBlock->m_pMetadata; - - // Same block - if(freeSpaceInfoIndex == srcBlockInfoIndex) - { - VMA_ASSERT(dstAllocOffset <= srcAllocOffset); - - // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset. - - VmaSuballocation suballoc = *srcSuballocIt; - suballoc.offset = dstAllocOffset; - suballoc.hAllocation->ChangeOffset(dstAllocOffset); - m_BytesMoved += srcAllocSize; - ++m_AllocationsMoved; - - VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt; - ++nextSuballocIt; - pSrcMetadata->m_Suballocations.erase(srcSuballocIt); - srcSuballocIt = nextSuballocIt; - - InsertSuballoc(pFreeSpaceMetadata, suballoc); - - move.srcBlockIndex = srcOrigBlockIndex; - move.dstBlockIndex = freeSpaceOrigBlockIndex; - move.srcOffset = srcAllocOffset; - move.dstOffset = dstAllocOffset; - move.size = srcAllocSize; - - moves.push_back(move); - } - // Different block - else - { - // MOVE OPTION 2: Move the allocation to a different block. - - VMA_ASSERT(freeSpaceInfoIndex < srcBlockInfoIndex); - - VmaSuballocation suballoc = *srcSuballocIt; - suballoc.offset = dstAllocOffset; - suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pFreeSpaceBlock, dstAllocOffset); - m_BytesMoved += srcAllocSize; - ++m_AllocationsMoved; - - VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt; - ++nextSuballocIt; - pSrcMetadata->m_Suballocations.erase(srcSuballocIt); - srcSuballocIt = nextSuballocIt; - - InsertSuballoc(pFreeSpaceMetadata, suballoc); - - move.srcBlockIndex = srcOrigBlockIndex; - move.dstBlockIndex = freeSpaceOrigBlockIndex; - move.srcOffset = srcAllocOffset; - move.dstOffset = dstAllocOffset; - move.size = srcAllocSize; - - moves.push_back(move); - } - } - else - { - dstAllocOffset = VmaAlignUp(dstOffset, srcAllocAlignment); - - // If the allocation doesn't fit before the end of dstBlock, forward to next block. - while(dstBlockInfoIndex < srcBlockInfoIndex && - dstAllocOffset + srcAllocSize > dstBlockSize) - { - // But before that, register remaining free space at the end of dst block. - freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, dstBlockSize - dstOffset); - - ++dstBlockInfoIndex; - dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex; - pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex); - pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata; - dstBlockSize = pDstMetadata->GetSize(); - dstOffset = 0; - dstAllocOffset = 0; - } - - // Same block - if(dstBlockInfoIndex == srcBlockInfoIndex) - { - VMA_ASSERT(dstAllocOffset <= srcAllocOffset); - - const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset; - - bool skipOver = overlap; - if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset) - { - // If destination and source place overlap, skip if it would move it - // by only < 1/64 of its size. - skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize; - } - - if(skipOver) - { - freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, srcAllocOffset - dstOffset); + VmaBlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata; - dstOffset = srcAllocOffset + srcAllocSize; - ++srcSuballocIt; - } - // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset. - else - { - srcSuballocIt->offset = dstAllocOffset; - srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset); - dstOffset = dstAllocOffset + srcAllocSize; - m_BytesMoved += srcAllocSize; - ++m_AllocationsMoved; - ++srcSuballocIt; - - move.srcBlockIndex = srcOrigBlockIndex; - move.dstBlockIndex = dstOrigBlockIndex; - move.srcOffset = srcAllocOffset; - move.dstOffset = dstAllocOffset; - move.size = srcAllocSize; - - moves.push_back(move); - } - } - // Different block - else - { - // MOVE OPTION 2: Move the allocation to a different block. - - VMA_ASSERT(dstBlockInfoIndex < srcBlockInfoIndex); - VMA_ASSERT(dstAllocOffset + srcAllocSize <= dstBlockSize); - - VmaSuballocation suballoc = *srcSuballocIt; - suballoc.offset = dstAllocOffset; - suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlock, dstAllocOffset); - dstOffset = dstAllocOffset + srcAllocSize; - m_BytesMoved += srcAllocSize; - ++m_AllocationsMoved; - - VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt; - ++nextSuballocIt; - pSrcMetadata->m_Suballocations.erase(srcSuballocIt); - srcSuballocIt = nextSuballocIt; - - pDstMetadata->m_Suballocations.push_back(suballoc); - - move.srcBlockIndex = srcOrigBlockIndex; - move.dstBlockIndex = dstOrigBlockIndex; - move.srcOffset = srcAllocOffset; - move.dstOffset = dstAllocOffset; - move.size = srcAllocSize; - - moves.push_back(move); - } - } - } + allocCount += metadata->GetAllocationCount(); + freeCount += metadata->GetFreeRegionsCount(); + state.avgFreeSize += metadata->GetSumFreeSize(); + state.avgAllocSize += metadata->GetSize(); } - m_BlockInfos.clear(); - - PostprocessMetadata(); - - return VK_SUCCESS; + state.avgAllocSize = (state.avgAllocSize - state.avgFreeSize) / allocCount; + state.avgFreeSize /= freeCount; } -void VmaDefragmentationAlgorithm_Fast::PreprocessMetadata() +bool VmaDefragmentationContext_T::MoveDataToFreeBlocks(VmaSuballocationType currentType, + VmaBlockVector& vector, size_t firstFreeBlock, + bool& texturePresent, bool& bufferPresent, bool& otherPresent) { - const size_t blockCount = m_pBlockVector->GetBlockCount(); - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + const size_t prevMoveCount = m_Moves.size(); + for (size_t i = firstFreeBlock ; i;) { - VmaBlockMetadata_Generic* const pMetadata = - (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata; - pMetadata->m_FreeCount = 0; - pMetadata->m_SumFreeSize = pMetadata->GetSize(); - pMetadata->m_FreeSuballocationsBySize.clear(); - for(VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin(); - it != pMetadata->m_Suballocations.end(); ) - { - if(it->type == VMA_SUBALLOCATION_TYPE_FREE) - { - VmaSuballocationList::iterator nextIt = it; - ++nextIt; - pMetadata->m_Suballocations.erase(it); - it = nextIt; - } - else - { - ++it; - } - } - } -} + VmaDeviceMemoryBlock* block = vector.GetBlock(--i); + VmaBlockMetadata* metadata = block->m_pMetadata; -void VmaDefragmentationAlgorithm_Fast::PostprocessMetadata() -{ - const size_t blockCount = m_pBlockVector->GetBlockCount(); - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) - { - VmaBlockMetadata_Generic* const pMetadata = - (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata; - const VkDeviceSize blockSize = pMetadata->GetSize(); - - // No allocations in this block - entire area is free. - if(pMetadata->m_Suballocations.empty()) - { - pMetadata->m_FreeCount = 1; - //pMetadata->m_SumFreeSize is already set to blockSize. - VmaSuballocation suballoc = { - 0, // offset - blockSize, // size - VMA_NULL, // hAllocation - VMA_SUBALLOCATION_TYPE_FREE }; - pMetadata->m_Suballocations.push_back(suballoc); - pMetadata->RegisterFreeSuballocation(pMetadata->m_Suballocations.begin()); - } - // There are some allocations in this block. - else + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) { - VkDeviceSize offset = 0; - VmaSuballocationList::iterator it; - for(it = pMetadata->m_Suballocations.begin(); - it != pMetadata->m_Suballocations.end(); - ++it) + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) { - VMA_ASSERT(it->type != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(it->offset >= offset); - - // Need to insert preceding free space. - if(it->offset > offset) - { - ++pMetadata->m_FreeCount; - const VkDeviceSize freeSize = it->offset - offset; - VmaSuballocation suballoc = { - offset, // offset - freeSize, // size - VMA_NULL, // hAllocation - VMA_SUBALLOCATION_TYPE_FREE }; - VmaSuballocationList::iterator precedingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc); - if(freeSize >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - pMetadata->m_FreeSuballocationsBySize.push_back(precedingFreeIt); - } - } - - pMetadata->m_SumFreeSize -= it->size; - offset = it->offset + it->size; + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + case CounterStatus::Pass: + break; + default: + VMA_ASSERT(0); } - // Need to insert trailing free space. - if(offset < blockSize) + // Move only single type of resources at once + if (!VmaIsBufferImageGranularityConflict(moveData.type, currentType)) { - ++pMetadata->m_FreeCount; - const VkDeviceSize freeSize = blockSize - offset; - VmaSuballocation suballoc = { - offset, // offset - freeSize, // size - VMA_NULL, // hAllocation - VMA_SUBALLOCATION_TYPE_FREE }; - VMA_ASSERT(it == pMetadata->m_Suballocations.end()); - VmaSuballocationList::iterator trailingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc); - if(freeSize > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - pMetadata->m_FreeSuballocationsBySize.push_back(trailingFreeIt); - } + // Try to fit allocation into free blocks + if (AllocInOtherBlock(firstFreeBlock, vector.GetBlockCount(), moveData, vector)) + return false; } - VMA_SORT( - pMetadata->m_FreeSuballocationsBySize.begin(), - pMetadata->m_FreeSuballocationsBySize.end(), - VmaSuballocationItemSizeLess()); - } - - VMA_HEAVY_ASSERT(pMetadata->Validate()); - } -} - -void VmaDefragmentationAlgorithm_Fast::InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc) -{ - // TODO: Optimize somehow. Remember iterator instead of searching for it linearly. - VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin(); - while(it != pMetadata->m_Suballocations.end()) - { - if(it->offset < suballoc.offset) - { - ++it; + if (!VmaIsBufferImageGranularityConflict(moveData.type, VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)) + texturePresent = true; + else if (!VmaIsBufferImageGranularityConflict(moveData.type, VMA_SUBALLOCATION_TYPE_BUFFER)) + bufferPresent = true; + else + otherPresent = true; } } - pMetadata->m_Suballocations.insert(it, suballoc); + return prevMoveCount == m_Moves.size(); } +#endif // _VMA_DEFRAGMENTATION_CONTEXT_FUNCTIONS -//////////////////////////////////////////////////////////////////////////////// -// VmaBlockVectorDefragmentationContext - -VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext( +#ifndef _VMA_POOL_T_FUNCTIONS +VmaPool_T::VmaPool_T( VmaAllocator hAllocator, - VmaPool hCustomPool, - VmaBlockVector* pBlockVector, - uint32_t currFrameIndex) : - res(VK_SUCCESS), - mutexLocked(false), - blockContexts(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - defragmentationMoves(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - defragmentationMovesProcessed(0), - defragmentationMovesCommitted(0), - hasDefragmentationPlan(0), - m_hAllocator(hAllocator), - m_hCustomPool(hCustomPool), - m_pBlockVector(pBlockVector), - m_CurrFrameIndex(currFrameIndex), - m_pAlgorithm(VMA_NULL), - m_Allocations(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_AllAllocations(false) -{ -} - -VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext() -{ - vma_delete(m_hAllocator, m_pAlgorithm); -} + const VmaPoolCreateInfo& createInfo, + VkDeviceSize preferredBlockSize) + : m_BlockVector( + hAllocator, + this, // hParentPool + createInfo.memoryTypeIndex, + createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize, + createInfo.minBlockCount, + createInfo.maxBlockCount, + (createInfo.flags& VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), + createInfo.blockSize != 0, // explicitBlockSize + createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm + createInfo.priority, + VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment), + createInfo.pMemoryAllocateNext), + m_Id(0), + m_Name(VMA_NULL) {} -void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) +VmaPool_T::~VmaPool_T() { - AllocInfo info = { hAlloc, pChanged }; - m_Allocations.push_back(info); + VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL); } -void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags) +void VmaPool_T::SetName(const char* pName) { - const bool allAllocations = m_AllAllocations || - m_Allocations.size() == m_pBlockVector->CalcAllocationCount(); - - /******************************** - HERE IS THE CHOICE OF DEFRAGMENTATION ALGORITHM. - ********************************/ - - /* - Fast algorithm is supported only when certain criteria are met: - - VMA_DEBUG_MARGIN is 0. - - All allocations in this block vector are moveable. - - There is no possibility of image/buffer granularity conflict. - - The defragmentation is not incremental - */ - if(VMA_DEBUG_MARGIN == 0 && - allAllocations && - !m_pBlockVector->IsBufferImageGranularityConflictPossible() && - !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)) - { - m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)( - m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported); - } - else - { - m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)( - m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported); - } + const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks(); + VmaFreeString(allocs, m_Name); - if(allAllocations) + if (pName != VMA_NULL) { - m_pAlgorithm->AddAll(); + m_Name = VmaCreateStringCopy(allocs, pName); } else { - for(size_t i = 0, count = m_Allocations.size(); i < count; ++i) - { - m_pAlgorithm->AddAllocation(m_Allocations[i].hAlloc, m_Allocations[i].pChanged); - } + m_Name = VMA_NULL; } } +#endif // _VMA_POOL_T_FUNCTIONS -//////////////////////////////////////////////////////////////////////////////// -// VmaDefragmentationContext - -VmaDefragmentationContext_T::VmaDefragmentationContext_T( - VmaAllocator hAllocator, - uint32_t currFrameIndex, - uint32_t flags, - VmaDefragmentationStats* pStats) : - m_hAllocator(hAllocator), - m_CurrFrameIndex(currFrameIndex), - m_Flags(flags), - m_pStats(pStats), - m_CustomPoolContexts(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ - memset(m_DefaultPoolContexts, 0, sizeof(m_DefaultPoolContexts)); -} - -VmaDefragmentationContext_T::~VmaDefragmentationContext_T() -{ - for(size_t i = m_CustomPoolContexts.size(); i--; ) - { - VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[i]; - pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_pStats); - vma_delete(m_hAllocator, pBlockVectorCtx); - } - for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; ) +#ifndef _VMA_ALLOCATOR_T_FUNCTIONS +VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : + m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), + m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0), + m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), + m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), + m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), + m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), + m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), + m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), + m_hDevice(pCreateInfo->device), + m_hInstance(pCreateInfo->instance), + m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), + m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ? + *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks), + m_AllocationObjectAllocator(&m_AllocationCallbacks), + m_HeapSizeLimitMask(0), + m_DeviceMemoryCount(0), + m_PreferredLargeHeapBlockSize(0), + m_PhysicalDevice(pCreateInfo->physicalDevice), + m_GpuDefragmentationMemoryTypeBits(UINT32_MAX), + m_NextPoolId(0), + m_GlobalMemoryTypeBits(UINT32_MAX) +{ + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[i]; - if(pBlockVectorCtx) - { - pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_pStats); - vma_delete(m_hAllocator, pBlockVectorCtx); - } + m_UseKhrDedicatedAllocation = false; + m_UseKhrBindMemory2 = false; } -} -void VmaDefragmentationContext_T::AddPools(uint32_t poolCount, VmaPool* pPools) -{ - for(uint32_t poolIndex = 0; poolIndex < poolCount; ++poolIndex) + if(VMA_DEBUG_DETECT_CORRUPTION) { - VmaPool pool = pPools[poolIndex]; - VMA_ASSERT(pool); - // Pools with algorithm other than default are not defragmented. - if(pool->m_BlockVector.GetAlgorithm() == 0) - { - VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL; - - for(size_t i = m_CustomPoolContexts.size(); i--; ) - { - if(m_CustomPoolContexts[i]->GetCustomPool() == pool) - { - pBlockVectorDefragCtx = m_CustomPoolContexts[i]; - break; - } - } - - if(!pBlockVectorDefragCtx) - { - pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)( - m_hAllocator, - pool, - &pool->m_BlockVector, - m_CurrFrameIndex); - m_CustomPoolContexts.push_back(pBlockVectorDefragCtx); - } - - pBlockVectorDefragCtx->AddAll(); - } + // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it. + VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0); } -} -void VmaDefragmentationContext_T::AddAllocations( - uint32_t allocationCount, - VmaAllocation* pAllocations, - VkBool32* pAllocationsChanged) -{ - // Dispatch pAllocations among defragmentators. Create them when necessary. - for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance); + + if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) { - const VmaAllocation hAlloc = pAllocations[allocIndex]; - VMA_ASSERT(hAlloc); - // DedicatedAlloc cannot be defragmented. - if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) && - // Lost allocation cannot be defragmented. - (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)) +#if !(VMA_DEDICATED_ALLOCATION) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) { - VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL; - - const VmaPool hAllocPool = hAlloc->GetBlock()->GetParentPool(); - // This allocation belongs to custom pool. - if(hAllocPool != VK_NULL_HANDLE) - { - // Pools with algorithm other than default are not defragmented. - if(hAllocPool->m_BlockVector.GetAlgorithm() == 0) - { - for(size_t i = m_CustomPoolContexts.size(); i--; ) - { - if(m_CustomPoolContexts[i]->GetCustomPool() == hAllocPool) - { - pBlockVectorDefragCtx = m_CustomPoolContexts[i]; - break; - } - } - if(!pBlockVectorDefragCtx) - { - pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)( - m_hAllocator, - hAllocPool, - &hAllocPool->m_BlockVector, - m_CurrFrameIndex); - m_CustomPoolContexts.push_back(pBlockVectorDefragCtx); - } - } - } - // This allocation belongs to default pool. - else - { - const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex(); - pBlockVectorDefragCtx = m_DefaultPoolContexts[memTypeIndex]; - if(!pBlockVectorDefragCtx) - { - pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)( - m_hAllocator, - VMA_NULL, // hCustomPool - m_hAllocator->m_pBlockVectors[memTypeIndex], - m_CurrFrameIndex); - m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx; - } - } - - if(pBlockVectorDefragCtx) - { - VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ? - &pAllocationsChanged[allocIndex] : VMA_NULL; - pBlockVectorDefragCtx->AddAllocation(hAlloc, pChanged); - } + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros."); + } +#endif +#if !(VMA_BIND_MEMORY2) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros."); } +#endif } -} - -VkResult VmaDefragmentationContext_T::Defragment( - VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove, - VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove, - VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags) -{ - if(pStats) +#if !(VMA_MEMORY_BUDGET) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) { - memset(pStats, 0, sizeof(VmaDefragmentationStats)); + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros."); } - - if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL) +#endif +#if !(VMA_BUFFER_DEVICE_ADDRESS) + if(m_UseKhrBufferDeviceAddress) { - // For incremental defragmetnations, we just earmark how much we can move - // The real meat is in the defragmentation steps - m_MaxCpuBytesToMove = maxCpuBytesToMove; - m_MaxCpuAllocationsToMove = maxCpuAllocationsToMove; - - m_MaxGpuBytesToMove = maxGpuBytesToMove; - m_MaxGpuAllocationsToMove = maxGpuAllocationsToMove; - - if(m_MaxCpuBytesToMove == 0 && m_MaxCpuAllocationsToMove == 0 && - m_MaxGpuBytesToMove == 0 && m_MaxGpuAllocationsToMove == 0) - return VK_SUCCESS; - - return VK_NOT_READY; + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } - - if(commandBuffer == VK_NULL_HANDLE) +#endif +#if VMA_VULKAN_VERSION < 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { - maxGpuBytesToMove = 0; - maxGpuAllocationsToMove = 0; + VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_3 but required Vulkan version is disabled by preprocessor macros."); } - - VkResult res = VK_SUCCESS; - - // Process default pools. - for(uint32_t memTypeIndex = 0; - memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS; - ++memTypeIndex) - { - VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex]; - if(pBlockVectorCtx) - { - VMA_ASSERT(pBlockVectorCtx->GetBlockVector()); - pBlockVectorCtx->GetBlockVector()->Defragment( - pBlockVectorCtx, - pStats, flags, - maxCpuBytesToMove, maxCpuAllocationsToMove, - maxGpuBytesToMove, maxGpuAllocationsToMove, - commandBuffer); - if(pBlockVectorCtx->res != VK_SUCCESS) - { - res = pBlockVectorCtx->res; - } - } +#endif +#if VMA_VULKAN_VERSION < 1002000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) + { + VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros."); } - - // Process custom pools. - for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size(); - customCtxIndex < customCtxCount && res >= VK_SUCCESS; - ++customCtxIndex) +#endif +#if VMA_VULKAN_VERSION < 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex]; - VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector()); - pBlockVectorCtx->GetBlockVector()->Defragment( - pBlockVectorCtx, - pStats, flags, - maxCpuBytesToMove, maxCpuAllocationsToMove, - maxGpuBytesToMove, maxGpuAllocationsToMove, - commandBuffer); - if(pBlockVectorCtx->res != VK_SUCCESS) - { - res = pBlockVectorCtx->res; - } + VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros."); } - - return res; -} - -VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo) -{ - VmaDefragmentationPassMoveInfo* pCurrentMove = pInfo->pMoves; - uint32_t movesLeft = pInfo->moveCount; - - // Process default pools. - for(uint32_t memTypeIndex = 0; - memTypeIndex < m_hAllocator->GetMemoryTypeCount(); - ++memTypeIndex) +#endif +#if !(VMA_MEMORY_PRIORITY) + if(m_UseExtMemoryPriority) { - VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex]; - if(pBlockVectorCtx) - { - VMA_ASSERT(pBlockVectorCtx->GetBlockVector()); - - if(!pBlockVectorCtx->hasDefragmentationPlan) - { - pBlockVectorCtx->GetBlockVector()->Defragment( - pBlockVectorCtx, - m_pStats, m_Flags, - m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove, - m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove, - VK_NULL_HANDLE); + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif - if(pBlockVectorCtx->res < VK_SUCCESS) - continue; + memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); + memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); + memset(&m_MemProps, 0, sizeof(m_MemProps)); - pBlockVectorCtx->hasDefragmentationPlan = true; - } + memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors)); + memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions)); - const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations( - pBlockVectorCtx, - pCurrentMove, movesLeft); +#if VMA_EXTERNAL_MEMORY + memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes)); +#endif // #if VMA_EXTERNAL_MEMORY - movesLeft -= processed; - pCurrentMove += processed; - } + if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) + { + m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; + m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; + m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree; } - // Process custom pools. - for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size(); - customCtxIndex < customCtxCount; - ++customCtxIndex) - { - VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex]; - VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector()); + ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); - if(!pBlockVectorCtx->hasDefragmentationPlan) - { - pBlockVectorCtx->GetBlockVector()->Defragment( - pBlockVectorCtx, - m_pStats, m_Flags, - m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove, - m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove, - VK_NULL_HANDLE); + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); - if(pBlockVectorCtx->res < VK_SUCCESS) - continue; + VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT)); + VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); + VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity)); + VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize)); - pBlockVectorCtx->hasDefragmentationPlan = true; - } + m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ? + pCreateInfo->preferredLargeHeapBlockSize : static_cast(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE); - const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations( - pBlockVectorCtx, - pCurrentMove, movesLeft); + m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); - movesLeft -= processed; - pCurrentMove += processed; +#if VMA_EXTERNAL_MEMORY + if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) + { + memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes, + sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount()); } +#endif // #if VMA_EXTERNAL_MEMORY - pInfo->moveCount = pInfo->moveCount - movesLeft; - - return VK_SUCCESS; -} -VkResult VmaDefragmentationContext_T::DefragmentPassEnd() -{ - VkResult res = VK_SUCCESS; - - // Process default pools. - for(uint32_t memTypeIndex = 0; - memTypeIndex < m_hAllocator->GetMemoryTypeCount(); - ++memTypeIndex) + if(pCreateInfo->pHeapSizeLimit != VMA_NULL) { - VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex]; - if(pBlockVectorCtx) + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) { - VMA_ASSERT(pBlockVectorCtx->GetBlockVector()); - - if(!pBlockVectorCtx->hasDefragmentationPlan) + const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; + if(limit != VK_WHOLE_SIZE) { - res = VK_NOT_READY; - continue; + m_HeapSizeLimitMask |= 1u << heapIndex; + if(limit < m_MemProps.memoryHeaps[heapIndex].size) + { + m_MemProps.memoryHeaps[heapIndex].size = limit; + } } - - pBlockVectorCtx->GetBlockVector()->CommitDefragmentations( - pBlockVectorCtx, m_pStats); - - if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted) - res = VK_NOT_READY; } } - // Process custom pools. - for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size(); - customCtxIndex < customCtxCount; - ++customCtxIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { - VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex]; - VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector()); - - if(!pBlockVectorCtx->hasDefragmentationPlan) + // Create only supported types + if((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) { - res = VK_NOT_READY; - continue; + const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); + m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( + this, + VK_NULL_HANDLE, // hParentPool + memTypeIndex, + preferredBlockSize, + 0, + SIZE_MAX, + GetBufferImageGranularity(), + false, // explicitBlockSize + 0, // algorithm + 0.5f, // priority (0.5 is the default per Vulkan spec) + GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment + VMA_NULL); // // pMemoryAllocateNext + // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, + // becase minBlockCount is 0. } + } +} - pBlockVectorCtx->GetBlockVector()->CommitDefragmentations( - pBlockVectorCtx, m_pStats); +VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo) +{ + VkResult res = VK_SUCCESS; - if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted) - res = VK_NOT_READY; +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + UpdateVulkanBudget(); } +#endif // #if VMA_MEMORY_BUDGET return res; } -//////////////////////////////////////////////////////////////////////////////// -// VmaRecorder - -#if VMA_RECORDING_ENABLED - -VmaRecorder::VmaRecorder() : - m_UseMutex(true), - m_Flags(0), - m_File(VMA_NULL), - m_Freq(INT64_MAX), - m_StartCounter(INT64_MAX) +VmaAllocator_T::~VmaAllocator_T() { + VMA_ASSERT(m_Pools.IsEmpty()); + + for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) + { + vma_delete(this, m_pBlockVectors[memTypeIndex]); + } } -VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex) +void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions) { - m_UseMutex = useMutex; - m_Flags = settings.flags; - - QueryPerformanceFrequency((LARGE_INTEGER*)&m_Freq); - QueryPerformanceCounter((LARGE_INTEGER*)&m_StartCounter); +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + ImportVulkanFunctions_Static(); +#endif - // Open file for writing. - errno_t err = fopen_s(&m_File, settings.pFilePath, "wb"); - if(err != 0) + if(pVulkanFunctions != VMA_NULL) { - return VK_ERROR_INITIALIZATION_FAILED; + ImportVulkanFunctions_Custom(pVulkanFunctions); } - // Write header. - fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording"); - fprintf(m_File, "%s\n", "1,8"); +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + ImportVulkanFunctions_Dynamic(); +#endif - return VK_SUCCESS; -} + ValidateVulkanFunctions(); +} + +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ImportVulkanFunctions_Static() +{ + // Vulkan 1.0 + m_VulkanFunctions.vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr; + m_VulkanFunctions.vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetDeviceProcAddr; + m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties; + m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties; + m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory; + m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory; + m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory; + m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory; + m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges; + m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges; + m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory; + m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory; + m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements; + m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements; + m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer; + m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer; + m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage; + m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage; + m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer; + + // Vulkan 1.1 +#if VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2; + m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2; + m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2; + m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2; + m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; + } +#endif -VmaRecorder::~VmaRecorder() -{ - if(m_File != VMA_NULL) +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { - fclose(m_File); + m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)vkGetDeviceBufferMemoryRequirements; + m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; } +#endif } -void VmaRecorder::RecordCreateAllocator(uint32_t frameIndex) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaCreateAllocator\n", callParams.threadId, callParams.time, frameIndex); - Flush(); -} +#endif // VMA_STATIC_VULKAN_FUNCTIONS == 1 -void VmaRecorder::RecordDestroyAllocator(uint32_t frameIndex) +void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions) { - CallParams callParams; - GetBasicParams(callParams); + VMA_ASSERT(pVulkanFunctions != VMA_NULL); - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDestroyAllocator\n", callParams.threadId, callParams.time, frameIndex); - Flush(); -} +#define VMA_COPY_IF_NOT_NULL(funcName) \ + if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName; -void VmaRecorder::RecordCreatePool(uint32_t frameIndex, const VmaPoolCreateInfo& createInfo, VmaPool pool) -{ - CallParams callParams; - GetBasicParams(callParams); + VMA_COPY_IF_NOT_NULL(vkGetInstanceProcAddr); + VMA_COPY_IF_NOT_NULL(vkGetDeviceProcAddr); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties); + VMA_COPY_IF_NOT_NULL(vkAllocateMemory); + VMA_COPY_IF_NOT_NULL(vkFreeMemory); + VMA_COPY_IF_NOT_NULL(vkMapMemory); + VMA_COPY_IF_NOT_NULL(vkUnmapMemory); + VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges); + VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges); + VMA_COPY_IF_NOT_NULL(vkBindBufferMemory); + VMA_COPY_IF_NOT_NULL(vkBindImageMemory); + VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkCreateBuffer); + VMA_COPY_IF_NOT_NULL(vkDestroyBuffer); + VMA_COPY_IF_NOT_NULL(vkCreateImage); + VMA_COPY_IF_NOT_NULL(vkDestroyImage); + VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer); - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaCreatePool,%u,%u,%llu,%llu,%llu,%u,%p\n", callParams.threadId, callParams.time, frameIndex, - createInfo.memoryTypeIndex, - createInfo.flags, - createInfo.blockSize, - (uint64_t)createInfo.minBlockCount, - (uint64_t)createInfo.maxBlockCount, - createInfo.frameInUseCount, - pool); - Flush(); -} +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR); + VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR); +#endif -void VmaRecorder::RecordDestroyPool(uint32_t frameIndex, VmaPool pool) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR); + VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDestroyPool,%p\n", callParams.threadId, callParams.time, frameIndex, - pool); - Flush(); -} +#if VMA_MEMORY_BUDGET + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); +#endif -void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(createInfo.flags, createInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemory,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - vkMemReq.size, - vkMemReq.alignment, - vkMemReq.memoryTypeBits, - createInfo.flags, - createInfo.usage, - createInfo.requiredFlags, - createInfo.preferredFlags, - createInfo.memoryTypeBits, - createInfo.pool, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - uint64_t allocationCount, - const VmaAllocation* pAllocations) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(createInfo.flags, createInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex, - vkMemReq.size, - vkMemReq.alignment, - vkMemReq.memoryTypeBits, - createInfo.flags, - createInfo.usage, - createInfo.requiredFlags, - createInfo.preferredFlags, - createInfo.memoryTypeBits, - createInfo.pool); - PrintPointerList(allocationCount, pAllocations); - fprintf(m_File, ",%s\n", userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(createInfo.flags, createInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForBuffer,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - vkMemReq.size, - vkMemReq.alignment, - vkMemReq.memoryTypeBits, - requiresDedicatedAllocation ? 1 : 0, - prefersDedicatedAllocation ? 1 : 0, - createInfo.flags, - createInfo.usage, - createInfo.requiredFlags, - createInfo.preferredFlags, - createInfo.memoryTypeBits, - createInfo.pool, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordAllocateMemoryForImage(uint32_t frameIndex, - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - const VmaAllocationCreateInfo& createInfo, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(createInfo.flags, createInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForImage,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - vkMemReq.size, - vkMemReq.alignment, - vkMemReq.memoryTypeBits, - requiresDedicatedAllocation ? 1 : 0, - prefersDedicatedAllocation ? 1 : 0, - createInfo.flags, - createInfo.usage, - createInfo.requiredFlags, - createInfo.preferredFlags, - createInfo.memoryTypeBits, - createInfo.pool, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordFreeMemory(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_VULKAN_VERSION >= 1003000 + VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaFreeMemory,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); +#undef VMA_COPY_IF_NOT_NULL } -void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex, - uint64_t allocationCount, - const VmaAllocation* pAllocations) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ImportVulkanFunctions_Dynamic() +{ + VMA_ASSERT(m_VulkanFunctions.vkGetInstanceProcAddr && m_VulkanFunctions.vkGetDeviceProcAddr && + "To use VMA_DYNAMIC_VULKAN_FUNCTIONS in new versions of VMA you now have to pass " + "VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as VmaAllocatorCreateInfo::pVulkanFunctions. " + "Other members can be null."); + +#define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \ + if(m_VulkanFunctions.memberName == VMA_NULL) \ + m_VulkanFunctions.memberName = \ + (functionPointerType)m_VulkanFunctions.vkGetInstanceProcAddr(m_hInstance, functionNameString); +#define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \ + if(m_VulkanFunctions.memberName == VMA_NULL) \ + m_VulkanFunctions.memberName = \ + (functionPointerType)m_VulkanFunctions.vkGetDeviceProcAddr(m_hDevice, functionNameString); + + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties"); + VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory"); + VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory"); + VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory"); + VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory"); + VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges"); + VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges"); + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory"); + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer"); + VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer"); + VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage"); + VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage"); + VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer"); - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex); - PrintPointerList(allocationCount, pAllocations); - fprintf(m_File, "\n"); - Flush(); -} - -void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex, - VmaAllocation allocation, - const void* pUserData) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr( - allocation->IsUserDataString() ? VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT : 0, - pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaSetAllocationUserData,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordCreateLostAllocation(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2"); + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2"); + } +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaCreateLostAllocation,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); -} +#if VMA_DEDICATED_ALLOCATION + if(m_UseKhrDedicatedAllocation) + { + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR"); + } +#endif -void VmaRecorder::RecordMapMemory(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_BIND_MEMORY2 + if(m_UseKhrBindMemory2) + { + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR"); + } +#endif // #if VMA_BIND_MEMORY2 - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaMapMemory,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); -} +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + } +#endif // #if VMA_MEMORY_BUDGET -void VmaRecorder::RecordUnmapMemory(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirements, "vkGetDeviceBufferMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements"); + } +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaUnmapMemory,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); +#undef VMA_FETCH_DEVICE_FUNC +#undef VMA_FETCH_INSTANCE_FUNC } -void VmaRecorder::RecordFlushAllocation(uint32_t frameIndex, - VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaFlushAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex, - allocation, - offset, - size); - Flush(); -} +#endif // VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 -void VmaRecorder::RecordInvalidateAllocation(uint32_t frameIndex, - VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size) +void VmaAllocator_T::ValidateVulkanFunctions() { - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaInvalidateAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex, - allocation, - offset, - size); - Flush(); -} + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL); -void VmaRecorder::RecordCreateBuffer(uint32_t frameIndex, - const VkBufferCreateInfo& bufCreateInfo, - const VmaAllocationCreateInfo& allocCreateInfo, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaCreateBuffer,%u,%llu,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - bufCreateInfo.flags, - bufCreateInfo.size, - bufCreateInfo.usage, - bufCreateInfo.sharingMode, - allocCreateInfo.flags, - allocCreateInfo.usage, - allocCreateInfo.requiredFlags, - allocCreateInfo.preferredFlags, - allocCreateInfo.memoryTypeBits, - allocCreateInfo.pool, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordCreateImage(uint32_t frameIndex, - const VkImageCreateInfo& imageCreateInfo, - const VmaAllocationCreateInfo& allocCreateInfo, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData); - fprintf(m_File, "%u,%.3f,%u,vmaCreateImage,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - imageCreateInfo.flags, - imageCreateInfo.imageType, - imageCreateInfo.format, - imageCreateInfo.extent.width, - imageCreateInfo.extent.height, - imageCreateInfo.extent.depth, - imageCreateInfo.mipLevels, - imageCreateInfo.arrayLayers, - imageCreateInfo.samples, - imageCreateInfo.tiling, - imageCreateInfo.usage, - imageCreateInfo.sharingMode, - imageCreateInfo.initialLayout, - allocCreateInfo.flags, - allocCreateInfo.usage, - allocCreateInfo.requiredFlags, - allocCreateInfo.preferredFlags, - allocCreateInfo.memoryTypeBits, - allocCreateInfo.pool, - allocation, - userDataStr.GetString()); - Flush(); -} - -void VmaRecorder::RecordDestroyBuffer(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) + { + VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); + } +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDestroyBuffer,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); -} +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) + { + VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL); + } +#endif -void VmaRecorder::RecordDestroyImage(uint32_t frameIndex, - VmaAllocation allocation) -{ - CallParams callParams; - GetBasicParams(callParams); +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); + } +#endif - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDestroyImage,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + VMA_ASSERT(m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetDeviceImageMemoryRequirements != VMA_NULL); + } +#endif } -void VmaRecorder::RecordTouchAllocation(uint32_t frameIndex, - VmaAllocation allocation) +VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex) { - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaTouchAllocation,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); + const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; + const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE; + return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32); } -void VmaRecorder::RecordGetAllocationInfo(uint32_t frameIndex, - VmaAllocation allocation) +VkResult VmaAllocator_T::AllocateMemoryOfType( + VmaPool pool, + VkDeviceSize size, + VkDeviceSize alignment, + bool dedicatedPreferred, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + const VmaAllocationCreateInfo& createInfo, + uint32_t memTypeIndex, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + VmaBlockVector& blockVector, + size_t allocationCount, + VmaAllocation* pAllocations) { - CallParams callParams; - GetBasicParams(callParams); - - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaGetAllocationInfo,%p\n", callParams.threadId, callParams.time, frameIndex, - allocation); - Flush(); -} + VMA_ASSERT(pAllocations != VMA_NULL); + VMA_DEBUG_LOG_FORMAT(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size); -void VmaRecorder::RecordMakePoolAllocationsLost(uint32_t frameIndex, - VmaPool pool) -{ - CallParams callParams; - GetBasicParams(callParams); + VmaAllocationCreateInfo finalCreateInfo = createInfo; + VkResult res = CalcMemTypeParams( + finalCreateInfo, + memTypeIndex, + size, + allocationCount); + if(res != VK_SUCCESS) + return res; - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaMakePoolAllocationsLost,%p\n", callParams.threadId, callParams.time, frameIndex, - pool); - Flush(); -} + if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + { + return AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + } + else + { + const bool canAllocateDedicated = + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && + (pool == VK_NULL_HANDLE || !blockVector.HasExplicitBlockSize()); -void VmaRecorder::RecordDefragmentationBegin(uint32_t frameIndex, - const VmaDefragmentationInfo2& info, - VmaDefragmentationContext ctx) -{ - CallParams callParams; - GetBasicParams(callParams); + if(canAllocateDedicated) + { + // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. + if(size > blockVector.GetPreferredBlockSize() / 2) + { + dedicatedPreferred = true; + } + // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget, + // which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above + // 3/4 of the maximum allocation count. + if(m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && + m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) + { + dedicatedPreferred = false; + } - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationBegin,%u,", callParams.threadId, callParams.time, frameIndex, - info.flags); - PrintPointerList(info.allocationCount, info.pAllocations); - fprintf(m_File, ","); - PrintPointerList(info.poolCount, info.pPools); - fprintf(m_File, ",%llu,%u,%llu,%u,%p,%p\n", - info.maxCpuBytesToMove, - info.maxCpuAllocationsToMove, - info.maxGpuBytesToMove, - info.maxGpuAllocationsToMove, - info.commandBuffer, - ctx); - Flush(); -} + if(dedicatedPreferred) + { + res = AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + if(res == VK_SUCCESS) + { + // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. + VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + return VK_SUCCESS; + } + } + } -void VmaRecorder::RecordDefragmentationEnd(uint32_t frameIndex, - VmaDefragmentationContext ctx) -{ - CallParams callParams; - GetBasicParams(callParams); + res = blockVector.Allocate( + size, + alignment, + finalCreateInfo, + suballocType, + allocationCount, + pAllocations); + if(res == VK_SUCCESS) + return VK_SUCCESS; - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationEnd,%p\n", callParams.threadId, callParams.time, frameIndex, - ctx); - Flush(); + // Try dedicated memory. + if(canAllocateDedicated && !dedicatedPreferred) + { + res = AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + if(res == VK_SUCCESS) + { + // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. + VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + return VK_SUCCESS; + } + } + // Everything failed: Return error code. + VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + return res; + } } -void VmaRecorder::RecordSetPoolName(uint32_t frameIndex, +VkResult VmaAllocator_T::AllocateDedicatedMemory( VmaPool pool, - const char* name) + VkDeviceSize size, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + uint32_t memTypeIndex, + bool map, + bool isUserDataString, + bool isMappingAllowed, + bool canAliasMemory, + void* pUserData, + float priority, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + size_t allocationCount, + VmaAllocation* pAllocations, + const void* pNextChain) { - CallParams callParams; - GetBasicParams(callParams); + VMA_ASSERT(allocationCount > 0 && pAllocations); - VmaMutexLock lock(m_FileMutex, m_UseMutex); - fprintf(m_File, "%u,%.3f,%u,vmaSetPoolName,%p,%s\n", callParams.threadId, callParams.time, frameIndex, - pool, name != VMA_NULL ? name : ""); - Flush(); -} + VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.memoryTypeIndex = memTypeIndex; + allocInfo.allocationSize = size; + allocInfo.pNext = pNextChain; -VmaRecorder::UserDataString::UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData) -{ - if(pUserData != VMA_NULL) +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; + if(!canAliasMemory) { - if((allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0) + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - m_Str = (const char*)pUserData; - } - else - { - sprintf_s(m_PtrStr, "%p", pUserData); - m_Str = m_PtrStr; + if(dedicatedBuffer != VK_NULL_HANDLE) + { + VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); + dedicatedAllocInfo.buffer = dedicatedBuffer; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } + else if(dedicatedImage != VK_NULL_HANDLE) + { + dedicatedAllocInfo.image = dedicatedImage; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } } } - else +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + +#if VMA_BUFFER_DEVICE_ADDRESS + VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; + if(m_UseKhrBufferDeviceAddress) { - m_Str = ""; + bool canContainBufferWithDeviceAddress = true; + if(dedicatedBuffer != VK_NULL_HANDLE) + { + canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == UINT32_MAX || // Usage flags unknown + (dedicatedBufferImageUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0; + } + else if(dedicatedImage != VK_NULL_HANDLE) + { + canContainBufferWithDeviceAddress = false; + } + if(canContainBufferWithDeviceAddress) + { + allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); + } } -} - -void VmaRecorder::WriteConfiguration( - const VkPhysicalDeviceProperties& devProps, - const VkPhysicalDeviceMemoryProperties& memProps, - uint32_t vulkanApiVersion, - bool dedicatedAllocationExtensionEnabled, - bool bindMemory2ExtensionEnabled, - bool memoryBudgetExtensionEnabled, - bool deviceCoherentMemoryExtensionEnabled) -{ - fprintf(m_File, "Config,Begin\n"); - - fprintf(m_File, "VulkanApiVersion,%u,%u\n", VK_VERSION_MAJOR(vulkanApiVersion), VK_VERSION_MINOR(vulkanApiVersion)); - - fprintf(m_File, "PhysicalDevice,apiVersion,%u\n", devProps.apiVersion); - fprintf(m_File, "PhysicalDevice,driverVersion,%u\n", devProps.driverVersion); - fprintf(m_File, "PhysicalDevice,vendorID,%u\n", devProps.vendorID); - fprintf(m_File, "PhysicalDevice,deviceID,%u\n", devProps.deviceID); - fprintf(m_File, "PhysicalDevice,deviceType,%u\n", devProps.deviceType); - fprintf(m_File, "PhysicalDevice,deviceName,%s\n", devProps.deviceName); - - fprintf(m_File, "PhysicalDeviceLimits,maxMemoryAllocationCount,%u\n", devProps.limits.maxMemoryAllocationCount); - fprintf(m_File, "PhysicalDeviceLimits,bufferImageGranularity,%llu\n", devProps.limits.bufferImageGranularity); - fprintf(m_File, "PhysicalDeviceLimits,nonCoherentAtomSize,%llu\n", devProps.limits.nonCoherentAtomSize); +#endif // #if VMA_BUFFER_DEVICE_ADDRESS - fprintf(m_File, "PhysicalDeviceMemory,HeapCount,%u\n", memProps.memoryHeapCount); - for(uint32_t i = 0; i < memProps.memoryHeapCount; ++i) +#if VMA_MEMORY_PRIORITY + VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; + if(m_UseExtMemoryPriority) { - fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,size,%llu\n", i, memProps.memoryHeaps[i].size); - fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,flags,%u\n", i, memProps.memoryHeaps[i].flags); + VMA_ASSERT(priority >= 0.f && priority <= 1.f); + priorityInfo.priority = priority; + VmaPnextChainPushFront(&allocInfo, &priorityInfo); } - fprintf(m_File, "PhysicalDeviceMemory,TypeCount,%u\n", memProps.memoryTypeCount); - for(uint32_t i = 0; i < memProps.memoryTypeCount; ++i) +#endif // #if VMA_MEMORY_PRIORITY + +#if VMA_EXTERNAL_MEMORY + // Attach VkExportMemoryAllocateInfoKHR if necessary. + VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; + exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex); + if(exportMemoryAllocInfo.handleTypes != 0) { - fprintf(m_File, "PhysicalDeviceMemory,Type,%u,heapIndex,%u\n", i, memProps.memoryTypes[i].heapIndex); - fprintf(m_File, "PhysicalDeviceMemory,Type,%u,propertyFlags,%u\n", i, memProps.memoryTypes[i].propertyFlags); + VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); } +#endif // #if VMA_EXTERNAL_MEMORY - fprintf(m_File, "Extension,VK_KHR_dedicated_allocation,%u\n", dedicatedAllocationExtensionEnabled ? 1 : 0); - fprintf(m_File, "Extension,VK_KHR_bind_memory2,%u\n", bindMemory2ExtensionEnabled ? 1 : 0); - fprintf(m_File, "Extension,VK_EXT_memory_budget,%u\n", memoryBudgetExtensionEnabled ? 1 : 0); - fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0); - - fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0); - fprintf(m_File, "Macro,VMA_DEBUG_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_DEBUG_ALIGNMENT); - fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN); - fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0); - fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0); - fprintf(m_File, "Macro,VMA_DEBUG_GLOBAL_MUTEX,%u\n", VMA_DEBUG_GLOBAL_MUTEX ? 1 : 0); - fprintf(m_File, "Macro,VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY,%llu\n", (VkDeviceSize)VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY); - fprintf(m_File, "Macro,VMA_SMALL_HEAP_MAX_SIZE,%llu\n", (VkDeviceSize)VMA_SMALL_HEAP_MAX_SIZE); - fprintf(m_File, "Macro,VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE,%llu\n", (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE); - - fprintf(m_File, "Config,End\n"); -} - -void VmaRecorder::GetBasicParams(CallParams& outParams) -{ - outParams.threadId = GetCurrentThreadId(); - - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - outParams.time = (double)(counter.QuadPart - m_StartCounter) / (double)m_Freq; -} - -void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems) -{ - if(count) + size_t allocIndex; + VkResult res = VK_SUCCESS; + for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { - fprintf(m_File, "%p", pItems[0]); - for(uint64_t i = 1; i < count; ++i) + res = AllocateDedicatedMemoryPage( + pool, + size, + suballocType, + memTypeIndex, + allocInfo, + map, + isUserDataString, + isMappingAllowed, + pUserData, + pAllocations + allocIndex); + if(res != VK_SUCCESS) { - fprintf(m_File, " %p", pItems[i]); + break; } } -} -void VmaRecorder::Flush() -{ - if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0) + if(res == VK_SUCCESS) { - fflush(m_File); + for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + dedicatedAllocations.Register(pAllocations[allocIndex]); + } + VMA_DEBUG_LOG_FORMAT(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex); } -} + else + { + // Free all already created allocations. + while(allocIndex--) + { + VmaAllocation currAlloc = pAllocations[allocIndex]; + VkDeviceMemory hMemory = currAlloc->GetMemory(); -#endif // #if VMA_RECORDING_ENABLED + /* + There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory + before vkFreeMemory. -//////////////////////////////////////////////////////////////////////////////// -// VmaAllocationObjectAllocator + if(currAlloc->GetMappedData() != VMA_NULL) + { + (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); + } + */ -VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) : - m_Allocator(pAllocationCallbacks, 1024) -{ -} + FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory); + m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize()); + m_AllocationObjectAllocator.Free(currAlloc); + } -template VmaAllocation VmaAllocationObjectAllocator::Allocate(Types... args) -{ - VmaMutexLock mutexLock(m_Mutex); - return m_Allocator.Alloc(std::forward(args)...); -} + memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); + } -void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc) -{ - VmaMutexLock mutexLock(m_Mutex); - m_Allocator.Free(hAlloc); + return res; } -//////////////////////////////////////////////////////////////////////////////// -// VmaAllocator_T - -VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : - m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), - m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0), - m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), - m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), - m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), - m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), - m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), - m_hDevice(pCreateInfo->device), - m_hInstance(pCreateInfo->instance), - m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), - m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ? - *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks), - m_AllocationObjectAllocator(&m_AllocationCallbacks), - m_HeapSizeLimitMask(0), - m_PreferredLargeHeapBlockSize(0), - m_PhysicalDevice(pCreateInfo->physicalDevice), - m_CurrentFrameIndex(0), - m_GpuDefragmentationMemoryTypeBits(UINT32_MAX), - m_Pools(VmaStlAllocator(GetAllocationCallbacks())), - m_NextPoolId(0), - m_GlobalMemoryTypeBits(UINT32_MAX) -#if VMA_RECORDING_ENABLED - ,m_pRecorder(VMA_NULL) -#endif +VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + uint32_t memTypeIndex, + const VkMemoryAllocateInfo& allocInfo, + bool map, + bool isUserDataString, + bool isMappingAllowed, + void* pUserData, + VmaAllocation* pAllocation) { - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) - { - m_UseKhrDedicatedAllocation = false; - m_UseKhrBindMemory2 = false; - } - - if(VMA_DEBUG_DETECT_CORRUPTION) + VkDeviceMemory hMemory = VK_NULL_HANDLE; + VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); + if(res < 0) { - // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it. - VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0); + VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + return res; } - VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance); - - if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) + void* pMappedData = VMA_NULL; + if(map) { -#if !(VMA_DEDICATED_ALLOCATION) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) - { - VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros."); - } -#endif -#if !(VMA_BIND_MEMORY2) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + res = (*m_VulkanFunctions.vkMapMemory)( + m_hDevice, + hMemory, + 0, + VK_WHOLE_SIZE, + 0, + &pMappedData); + if(res < 0) { - VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros."); + VMA_DEBUG_LOG(" vkMapMemory FAILED"); + FreeVulkanMemory(memTypeIndex, size, hMemory); + return res; } -#endif - } -#if !(VMA_MEMORY_BUDGET) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) - { - VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros."); - } -#endif -#if !(VMA_BUFFER_DEVICE_ADDRESS) - if(m_UseKhrBufferDeviceAddress) - { - VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); - } -#endif -#if VMA_VULKAN_VERSION < 1002000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) - { - VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros."); - } -#endif -#if VMA_VULKAN_VERSION < 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) - { - VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros."); } -#endif - - memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); - memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); - memset(&m_MemProps, 0, sizeof(m_MemProps)); - - memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors)); - memset(&m_pDedicatedAllocations, 0, sizeof(m_pDedicatedAllocations)); - memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions)); - if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) + *pAllocation = m_AllocationObjectAllocator.Allocate(isMappingAllowed); + (*pAllocation)->InitDedicatedAllocation(pool, memTypeIndex, hMemory, suballocType, pMappedData, size); + if (isUserDataString) + (*pAllocation)->SetName(this, (const char*)pUserData); + else + (*pAllocation)->SetUserData(this, pUserData); + m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size); + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) { - m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; - m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; - m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree; + FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); } - ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); + return VK_SUCCESS; +} - (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); - (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); +void VmaAllocator_T::GetBufferMemoryRequirements( + VkBuffer hBuffer, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const +{ +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; + memReqInfo.buffer = hBuffer; - VMA_ASSERT(VmaIsPow2(VMA_DEBUG_ALIGNMENT)); - VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); - VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity)); - VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize)); + VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; - m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ? - pCreateInfo->preferredLargeHeapBlockSize : static_cast(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE); + VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; + VmaPnextChainPushFront(&memReq2, &memDedicatedReq); - m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); + (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); - if(pCreateInfo->pHeapSizeLimit != VMA_NULL) + memReq = memReq2.memoryRequirements; + requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } + else +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { - for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) - { - const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; - if(limit != VK_WHOLE_SIZE) - { - m_HeapSizeLimitMask |= 1u << heapIndex; - if(limit < m_MemProps.memoryHeaps[heapIndex].size) - { - m_MemProps.memoryHeaps[heapIndex].size = limit; - } - } - } + (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); + requiresDedicatedAllocation = false; + prefersDedicatedAllocation = false; } +} - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) +void VmaAllocator_T::GetImageMemoryRequirements( + VkImage hImage, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const +{ +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); + VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; + memReqInfo.image = hImage; - m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( - this, - VK_NULL_HANDLE, // hParentPool - memTypeIndex, - preferredBlockSize, - 0, - SIZE_MAX, - GetBufferImageGranularity(), - pCreateInfo->frameInUseCount, - false, // explicitBlockSize - false); // linearAlgorithm - // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, - // becase minBlockCount is 0. - m_pDedicatedAllocations[memTypeIndex] = vma_new(this, AllocationVectorType)(VmaStlAllocator(GetAllocationCallbacks())); + VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; - } -} + VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; + VmaPnextChainPushFront(&memReq2, &memDedicatedReq); -VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo) -{ - VkResult res = VK_SUCCESS; + (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); - if(pCreateInfo->pRecordSettings != VMA_NULL && - !VmaStrIsEmpty(pCreateInfo->pRecordSettings->pFilePath)) - { -#if VMA_RECORDING_ENABLED - m_pRecorder = vma_new(this, VmaRecorder)(); - res = m_pRecorder->Init(*pCreateInfo->pRecordSettings, m_UseMutex); - if(res != VK_SUCCESS) - { - return res; - } - m_pRecorder->WriteConfiguration( - m_PhysicalDeviceProperties, - m_MemProps, - m_VulkanApiVersion, - m_UseKhrDedicatedAllocation, - m_UseKhrBindMemory2, - m_UseExtMemoryBudget, - m_UseAmdDeviceCoherentMemory); - m_pRecorder->RecordCreateAllocator(GetCurrentFrameIndex()); -#else - VMA_ASSERT(0 && "VmaAllocatorCreateInfo::pRecordSettings used, but not supported due to VMA_RECORDING_ENABLED not defined to 1."); - return VK_ERROR_FEATURE_NOT_PRESENT; -#endif + memReq = memReq2.memoryRequirements; + requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); } - -#if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) + else +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { - UpdateVulkanBudget(); + (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); + requiresDedicatedAllocation = false; + prefersDedicatedAllocation = false; } -#endif // #if VMA_MEMORY_BUDGET - - return res; } -VmaAllocator_T::~VmaAllocator_T() +VkResult VmaAllocator_T::FindMemoryTypeIndex( + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkFlags bufImgUsage, + uint32_t* pMemoryTypeIndex) const { -#if VMA_RECORDING_ENABLED - if(m_pRecorder != VMA_NULL) + memoryTypeBits &= GetGlobalMemoryTypeBits(); + + if(pAllocationCreateInfo->memoryTypeBits != 0) { - m_pRecorder->RecordDestroyAllocator(GetCurrentFrameIndex()); - vma_delete(this, m_pRecorder); + memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; } -#endif - - VMA_ASSERT(m_Pools.empty()); - for(size_t i = GetMemoryTypeCount(); i--; ) + VkMemoryPropertyFlags requiredFlags = 0, preferredFlags = 0, notPreferredFlags = 0; + if(!FindMemoryPreferences( + IsIntegratedGpu(), + *pAllocationCreateInfo, + bufImgUsage, + requiredFlags, preferredFlags, notPreferredFlags)) { - if(m_pDedicatedAllocations[i] != VMA_NULL && !m_pDedicatedAllocations[i]->empty()) - { - VMA_ASSERT(0 && "Unfreed dedicated allocations found."); - } - - vma_delete(this, m_pDedicatedAllocations[i]); - vma_delete(this, m_pBlockVectors[i]); + return VK_ERROR_FEATURE_NOT_PRESENT; } -} -void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions) -{ - m_VulkanFunctions.vkGetPhysicalDeviceProperties = - (PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr(m_hInstance, "vkGetPhysicalDeviceProperties"); - m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = - (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetInstanceProcAddr(m_hInstance, "vkGetPhysicalDeviceMemoryProperties"); - m_VulkanFunctions.vkAllocateMemory = - (PFN_vkAllocateMemory)vkGetDeviceProcAddr(m_hDevice, "vkAllocateMemory"); - m_VulkanFunctions.vkFreeMemory = - (PFN_vkFreeMemory)vkGetDeviceProcAddr(m_hDevice, "vkFreeMemory"); - m_VulkanFunctions.vkMapMemory = - (PFN_vkMapMemory)vkGetDeviceProcAddr(m_hDevice, "vkMapMemory"); - m_VulkanFunctions.vkUnmapMemory = - (PFN_vkUnmapMemory)vkGetDeviceProcAddr(m_hDevice, "vkUnmapMemory"); - m_VulkanFunctions.vkFlushMappedMemoryRanges = - (PFN_vkFlushMappedMemoryRanges)vkGetDeviceProcAddr(m_hDevice, "vkFlushMappedMemoryRanges"); - m_VulkanFunctions.vkInvalidateMappedMemoryRanges = - (PFN_vkInvalidateMappedMemoryRanges)vkGetDeviceProcAddr(m_hDevice, "vkInvalidateMappedMemoryRanges"); - m_VulkanFunctions.vkBindBufferMemory = - (PFN_vkBindBufferMemory)vkGetDeviceProcAddr(m_hDevice, "vkBindBufferMemory"); - m_VulkanFunctions.vkBindImageMemory = - (PFN_vkBindImageMemory)vkGetDeviceProcAddr(m_hDevice, "vkBindImageMemory"); - m_VulkanFunctions.vkGetBufferMemoryRequirements = - (PFN_vkGetBufferMemoryRequirements)vkGetDeviceProcAddr(m_hDevice, "vkGetBufferMemoryRequirements"); - m_VulkanFunctions.vkGetImageMemoryRequirements = - (PFN_vkGetImageMemoryRequirements)vkGetDeviceProcAddr(m_hDevice, "vkGetImageMemoryRequirements"); - m_VulkanFunctions.vkCreateBuffer = - (PFN_vkCreateBuffer)vkGetDeviceProcAddr(m_hDevice, "vkCreateBuffer"); - m_VulkanFunctions.vkDestroyBuffer = - (PFN_vkDestroyBuffer)vkGetDeviceProcAddr(m_hDevice, "vkDestroyBuffer"); - m_VulkanFunctions.vkCreateImage = - (PFN_vkCreateImage)vkGetDeviceProcAddr(m_hDevice, "vkCreateImage"); - m_VulkanFunctions.vkDestroyImage = - (PFN_vkDestroyImage)vkGetDeviceProcAddr(m_hDevice, "vkDestroyImage"); - m_VulkanFunctions.vkCmdCopyBuffer = - (PFN_vkCmdCopyBuffer)vkGetDeviceProcAddr(m_hDevice, "vkCmdCopyBuffer"); -#if VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) - { - VMA_ASSERT(m_hInstance != VK_NULL_HANDLE); - m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = - (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetBufferMemoryRequirements2"); - m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = - (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetImageMemoryRequirements2"); - m_VulkanFunctions.vkBindBufferMemory2KHR = - (PFN_vkBindBufferMemory2KHR)vkGetDeviceProcAddr(m_hDevice, "vkBindBufferMemory2"); - m_VulkanFunctions.vkBindImageMemory2KHR = - (PFN_vkBindImageMemory2KHR)vkGetDeviceProcAddr(m_hDevice, "vkBindImageMemory2"); - m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = - (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(m_hInstance, "vkGetPhysicalDeviceMemoryProperties2"); - } -#endif -#if VMA_DEDICATED_ALLOCATION - if(m_UseKhrDedicatedAllocation) + *pMemoryTypeIndex = UINT32_MAX; + uint32_t minCost = UINT32_MAX; + for(uint32_t memTypeIndex = 0, memTypeBit = 1; + memTypeIndex < GetMemoryTypeCount(); + ++memTypeIndex, memTypeBit <<= 1) { - if(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR == nullptr) - { - m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = - (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetBufferMemoryRequirements2KHR"); - } - if(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR == nullptr) + // This memory type is acceptable according to memoryTypeBits bitmask. + if((memTypeBit & memoryTypeBits) != 0) { - m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = - (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetImageMemoryRequirements2KHR"); + const VkMemoryPropertyFlags currFlags = + m_MemProps.memoryTypes[memTypeIndex].propertyFlags; + // This memory type contains requiredFlags. + if((requiredFlags & ~currFlags) == 0) + { + // Calculate cost as number of bits from preferredFlags not present in this memory type. + uint32_t currCost = VMA_COUNT_BITS_SET(preferredFlags & ~currFlags) + + VMA_COUNT_BITS_SET(currFlags & notPreferredFlags); + // Remember memory type with lowest cost. + if(currCost < minCost) + { + *pMemoryTypeIndex = memTypeIndex; + if(currCost == 0) + { + return VK_SUCCESS; + } + minCost = currCost; + } + } } } -#endif -#if VMA_BIND_MEMORY2 - if(m_UseKhrBindMemory2) + return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT; +} + +VkResult VmaAllocator_T::CalcMemTypeParams( + VmaAllocationCreateInfo& inoutCreateInfo, + uint32_t memTypeIndex, + VkDeviceSize size, + size_t allocationCount) +{ + // If memory type is not HOST_VISIBLE, disable MAPPED. + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && + (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { - if(m_VulkanFunctions.vkBindBufferMemory2KHR == nullptr) - { - m_VulkanFunctions.vkBindBufferMemory2KHR = - (PFN_vkBindBufferMemory2KHR)vkGetDeviceProcAddr(m_hDevice, "vkBindBufferMemory2KHR"); - } - if(m_VulkanFunctions.vkBindImageMemory2KHR == nullptr) + inoutCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; + } + + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0) + { + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); + VmaBudget heapBudget = {}; + GetHeapBudgets(&heapBudget, heapIndex, 1); + if(heapBudget.usage + size * allocationCount > heapBudget.budget) { - m_VulkanFunctions.vkBindImageMemory2KHR = - (PFN_vkBindImageMemory2KHR)vkGetDeviceProcAddr(m_hDevice, "vkBindImageMemory2KHR"); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; } } -#endif // #if VMA_BIND_MEMORY2 -#if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget && m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) + return VK_SUCCESS; +} + +VkResult VmaAllocator_T::CalcAllocationParams( + VmaAllocationCreateInfo& inoutCreateInfo, + bool dedicatedRequired, + bool dedicatedPreferred) +{ + VMA_ASSERT((inoutCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT) && + "Specifying both flags VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT and VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT is incorrect."); + VMA_ASSERT((((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) == 0 || + (inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0)) && + "Specifying VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT requires also VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); + if(inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - VMA_ASSERT(m_hInstance != VK_NULL_HANDLE); - if(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR == nullptr) + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) { - m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = - (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(m_hInstance, "vkGetPhysicalDeviceMemoryProperties2KHR"); + VMA_ASSERT((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0 && + "When using VMA_ALLOCATION_CREATE_MAPPED_BIT and usage = VMA_MEMORY_USAGE_AUTO*, you must also specify VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); } } -#endif // #if VMA_MEMORY_BUDGET - -#define VMA_COPY_IF_NOT_NULL(funcName) \ - if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName; - if(pVulkanFunctions != VMA_NULL) + // If memory is lazily allocated, it should be always dedicated. + if(dedicatedRequired || + inoutCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED) { - VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties); - VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties); - VMA_COPY_IF_NOT_NULL(vkAllocateMemory); - VMA_COPY_IF_NOT_NULL(vkFreeMemory); - VMA_COPY_IF_NOT_NULL(vkMapMemory); - VMA_COPY_IF_NOT_NULL(vkUnmapMemory); - VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges); - VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges); - VMA_COPY_IF_NOT_NULL(vkBindBufferMemory); - VMA_COPY_IF_NOT_NULL(vkBindImageMemory); - VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements); - VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements); - VMA_COPY_IF_NOT_NULL(vkCreateBuffer); - VMA_COPY_IF_NOT_NULL(vkDestroyBuffer); - VMA_COPY_IF_NOT_NULL(vkCreateImage); - VMA_COPY_IF_NOT_NULL(vkDestroyImage); - VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer); -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR); - VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR); -#endif -#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR); - VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); -#endif -#if VMA_MEMORY_BUDGET - VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); -#endif + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } -#undef VMA_COPY_IF_NOT_NULL + if(inoutCreateInfo.pool != VK_NULL_HANDLE) + { + if(inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + { + VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT while current custom pool doesn't support dedicated allocations."); + return VK_ERROR_FEATURE_NOT_PRESENT; + } + inoutCreateInfo.priority = inoutCreateInfo.pool->m_BlockVector.GetPriority(); + } - VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL); -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { - VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); + VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); + return VK_ERROR_FEATURE_NOT_PRESENT; } -#endif -#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) + + if(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { - VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL); + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } -#endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + + // Non-auto USAGE values imply HOST_ACCESS flags. + // And so does VMA_MEMORY_USAGE_UNKNOWN because it is used with custom pools. + // Which specific flag is used doesn't matter. They change things only when used with VMA_MEMORY_USAGE_AUTO*. + // Otherwise they just protect from assert on mapping. + if(inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && + inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE && + inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); + if((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) + { + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + } } -#endif -} -VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex) -{ - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); - const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; - const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE; - return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32); + return VK_SUCCESS; } -VkResult VmaAllocator_T::AllocateMemoryOfType( - VkDeviceSize size, - VkDeviceSize alignment, - bool dedicatedAllocation, +VkResult VmaAllocator_T::AllocateMemory( + const VkMemoryRequirements& vkMemReq, + bool requiresDedicatedAllocation, + bool prefersDedicatedAllocation, VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, const VmaAllocationCreateInfo& createInfo, - uint32_t memTypeIndex, VmaSuballocationType suballocType, size_t allocationCount, VmaAllocation* pAllocations) { - VMA_ASSERT(pAllocations != VMA_NULL); - VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size); + memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); - VmaAllocationCreateInfo finalCreateInfo = createInfo; + VMA_ASSERT(VmaIsPow2(vkMemReq.alignment)); - // If memory type is not HOST_VISIBLE, disable MAPPED. - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && - (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) - { - finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; - } - // If memory is lazily allocated, it should be always dedicated. - if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED) + if(vkMemReq.size == 0) { - finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + return VK_ERROR_INITIALIZATION_FAILED; } - VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(blockVector); - - const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize(); - bool preferDedicatedMemory = - VMA_DEBUG_ALWAYS_DEDICATED_MEMORY || - dedicatedAllocation || - // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. - size > preferredBlockSize / 2; + VmaAllocationCreateInfo createInfoFinal = createInfo; + VkResult res = CalcAllocationParams(createInfoFinal, requiresDedicatedAllocation, prefersDedicatedAllocation); + if(res != VK_SUCCESS) + return res; - if(preferDedicatedMemory && - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && - finalCreateInfo.pool == VK_NULL_HANDLE) + if(createInfoFinal.pool != VK_NULL_HANDLE) { - finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + VmaBlockVector& blockVector = createInfoFinal.pool->m_BlockVector; + return AllocateMemoryOfType( + createInfoFinal.pool, + vkMemReq.size, + vkMemReq.alignment, + prefersDedicatedAllocation, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + createInfoFinal, + blockVector.GetMemoryTypeIndex(), + suballocType, + createInfoFinal.pool->m_DedicatedAllocations, + blockVector, + allocationCount, + pAllocations); } - - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + else { - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - else + // Bit mask of memory Vulkan types acceptable for this allocation. + uint32_t memoryTypeBits = vkMemReq.memoryTypeBits; + uint32_t memTypeIndex = UINT32_MAX; + res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); + // Can't find any single memory type matching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. + if(res != VK_SUCCESS) + return res; + do { - return AllocateDedicatedMemory( - size, - suballocType, - memTypeIndex, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, - finalCreateInfo.pUserData, + VmaBlockVector* blockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(blockVector && "Trying to use unsupported memory type!"); + res = AllocateMemoryOfType( + VK_NULL_HANDLE, + vkMemReq.size, + vkMemReq.alignment, + requiresDedicatedAllocation || prefersDedicatedAllocation, dedicatedBuffer, - dedicatedBufferUsage, dedicatedImage, + dedicatedBufferImageUsage, + createInfoFinal, + memTypeIndex, + suballocType, + m_DedicatedAllocations[memTypeIndex], + *blockVector, allocationCount, pAllocations); - } + // Allocation succeeded + if(res == VK_SUCCESS) + return VK_SUCCESS; + + // Remove old memTypeIndex from list of possibilities. + memoryTypeBits &= ~(1u << memTypeIndex); + // Find alternative memTypeIndex. + res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); + } while(res == VK_SUCCESS); + + // No other matching memory type index could be found. + // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. + return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - else +} + +void VmaAllocator_T::FreeMemory( + size_t allocationCount, + const VmaAllocation* pAllocations) +{ + VMA_ASSERT(pAllocations); + + for(size_t allocIndex = allocationCount; allocIndex--; ) { - VkResult res = blockVector->Allocate( - m_CurrentFrameIndex.load(), - size, - alignment, - finalCreateInfo, - suballocType, - allocationCount, - pAllocations); - if(res == VK_SUCCESS) - { - return res; - } + VmaAllocation allocation = pAllocations[allocIndex]; - // 5. Try dedicated memory. - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - else + if(allocation != VK_NULL_HANDLE) { - res = AllocateDedicatedMemory( - size, - suballocType, - memTypeIndex, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, - finalCreateInfo.pUserData, - dedicatedBuffer, - dedicatedBufferUsage, - dedicatedImage, - allocationCount, - pAllocations); - if(res == VK_SUCCESS) + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) { - // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here. - VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); - return VK_SUCCESS; + FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); } - else + + allocation->FreeName(this); + + switch(allocation->GetType()) { - // Everything failed: Return error code. - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); - return res; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaBlockVector* pBlockVector = VMA_NULL; + VmaPool hPool = allocation->GetParentPool(); + if(hPool != VK_NULL_HANDLE) + { + pBlockVector = &hPool->m_BlockVector; + } + else + { + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + pBlockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); + } + pBlockVector->Free(allocation); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + FreeDedicatedMemory(allocation); + break; + default: + VMA_ASSERT(0); } } } } -VkResult VmaAllocator_T::AllocateDedicatedMemory( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - bool withinBudget, - bool map, - bool isUserDataString, - void* pUserData, - VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, - VkImage dedicatedImage, - size_t allocationCount, - VmaAllocation* pAllocations) +void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) { - VMA_ASSERT(allocationCount > 0 && pAllocations); + // Initialize. + VmaClearDetailedStatistics(pStats->total); + for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) + VmaClearDetailedStatistics(pStats->memoryType[i]); + for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) + VmaClearDetailedStatistics(pStats->memoryHeap[i]); - if(withinBudget) + // Process default pools. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); - VmaBudget heapBudget = {}; - GetBudget(&heapBudget, heapIndex, 1); - if(heapBudget.usage + size * allocationCount > heapBudget.budget) + VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; + if (pBlockVector != VMA_NULL) + pBlockVector->AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + } + + // Process custom pools. + { + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; + VmaBlockVector& blockVector = pool->m_BlockVector; + const uint32_t memTypeIndex = blockVector.GetMemoryTypeIndex(); + blockVector.AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + pool->m_DedicatedAllocations.AddDetailedStatistics(pStats->memoryType[memTypeIndex]); } } - VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocInfo.memoryTypeIndex = memTypeIndex; - allocInfo.allocationSize = size; + // Process dedicated allocations. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + m_DedicatedAllocations[memTypeIndex].AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + } -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + // Sum from memory types to memory heaps. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { - if(dedicatedBuffer != VK_NULL_HANDLE) - { - VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); - dedicatedAllocInfo.buffer = dedicatedBuffer; - VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); - } - else if(dedicatedImage != VK_NULL_HANDLE) - { - dedicatedAllocInfo.image = dedicatedImage; - VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); - } + const uint32_t memHeapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex; + VmaAddDetailedStatistics(pStats->memoryHeap[memHeapIndex], pStats->memoryType[memTypeIndex]); } -#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 -#if VMA_BUFFER_DEVICE_ADDRESS - VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; - if(m_UseKhrBufferDeviceAddress) + // Sum from memory heaps to total. + for(uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) + VmaAddDetailedStatistics(pStats->total, pStats->memoryHeap[memHeapIndex]); + + VMA_ASSERT(pStats->total.statistics.allocationCount == 0 || + pStats->total.allocationSizeMax >= pStats->total.allocationSizeMin); + VMA_ASSERT(pStats->total.unusedRangeCount == 0 || + pStats->total.unusedRangeSizeMax >= pStats->total.unusedRangeSizeMin); +} + +void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount) +{ +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) { - bool canContainBufferWithDeviceAddress = true; - if(dedicatedBuffer != VK_NULL_HANDLE) + if(m_Budget.m_OperationsSinceBudgetFetch < 30) { - canContainBufferWithDeviceAddress = dedicatedBufferUsage == UINT32_MAX || // Usage flags unknown - (dedicatedBufferUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0; + VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex); + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + { + const uint32_t heapIndex = firstHeap + i; + + outBudgets->statistics.blockCount = m_Budget.m_BlockCount[heapIndex]; + outBudgets->statistics.allocationCount = m_Budget.m_AllocationCount[heapIndex]; + outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; + outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; + + if(m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) + { + outBudgets->usage = m_Budget.m_VulkanUsage[heapIndex] + + outBudgets->statistics.blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; + } + else + { + outBudgets->usage = 0; + } + + // Have to take MIN with heap size because explicit HeapSizeLimit is included in it. + outBudgets->budget = VMA_MIN( + m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size); + } } - else if(dedicatedImage != VK_NULL_HANDLE) + else { - canContainBufferWithDeviceAddress = false; + UpdateVulkanBudget(); // Outside of mutex lock + GetHeapBudgets(outBudgets, firstHeap, heapCount); // Recursion } - if(canContainBufferWithDeviceAddress) + } + else +#endif + { + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) { - allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); + const uint32_t heapIndex = firstHeap + i; + + outBudgets->statistics.blockCount = m_Budget.m_BlockCount[heapIndex]; + outBudgets->statistics.allocationCount = m_Budget.m_AllocationCount[heapIndex]; + outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; + outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; + + outBudgets->usage = outBudgets->statistics.blockBytes; + outBudgets->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. } } -#endif // #if VMA_BUFFER_DEVICE_ADDRESS +} - size_t allocIndex; - VkResult res = VK_SUCCESS; - for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) +void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo) +{ + pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); + pAllocationInfo->deviceMemory = hAllocation->GetMemory(); + pAllocationInfo->offset = hAllocation->GetOffset(); + pAllocationInfo->size = hAllocation->GetSize(); + pAllocationInfo->pMappedData = hAllocation->GetMappedData(); + pAllocationInfo->pUserData = hAllocation->GetUserData(); + pAllocationInfo->pName = hAllocation->GetName(); +} + +VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool) +{ + VMA_DEBUG_LOG_FORMAT(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags); + + VmaPoolCreateInfo newCreateInfo = *pCreateInfo; + + // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash. + if(pCreateInfo->pMemoryAllocateNext) { - res = AllocateDedicatedMemoryPage( - size, - suballocType, - memTypeIndex, - allocInfo, - map, - isUserDataString, - pUserData, - pAllocations + allocIndex); - if(res != VK_SUCCESS) + VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0); + } + + if(newCreateInfo.maxBlockCount == 0) + { + newCreateInfo.maxBlockCount = SIZE_MAX; + } + if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + // Memory type index out of range or forbidden. + if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || + ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + if(newCreateInfo.minAllocationAlignment > 0) + { + VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment)); + } + + const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex); + + *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize); + + VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); + if(res != VK_SUCCESS) + { + vma_delete(this, *pPool); + *pPool = VMA_NULL; + return res; + } + + // Add to m_Pools. + { + VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); + (*pPool)->SetId(m_NextPoolId++); + m_Pools.PushBack(*pPool); + } + + return VK_SUCCESS; +} + +void VmaAllocator_T::DestroyPool(VmaPool pool) +{ + // Remove from m_Pools. + { + VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); + m_Pools.Remove(pool); + } + + vma_delete(this, pool); +} + +void VmaAllocator_T::GetPoolStatistics(VmaPool pool, VmaStatistics* pPoolStats) +{ + VmaClearStatistics(*pPoolStats); + pool->m_BlockVector.AddStatistics(*pPoolStats); + pool->m_DedicatedAllocations.AddStatistics(*pPoolStats); +} + +void VmaAllocator_T::CalculatePoolStatistics(VmaPool pool, VmaDetailedStatistics* pPoolStats) +{ + VmaClearDetailedStatistics(*pPoolStats); + pool->m_BlockVector.AddDetailedStatistics(*pPoolStats); + pool->m_DedicatedAllocations.AddDetailedStatistics(*pPoolStats); +} + +void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) +{ + m_CurrentFrameIndex.store(frameIndex); + +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + UpdateVulkanBudget(); + } +#endif // #if VMA_MEMORY_BUDGET +} + +VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool) +{ + return hPool->m_BlockVector.CheckCorruption(); +} + +VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) +{ + VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT; + + // Process default pools. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; + if(pBlockVector != VMA_NULL) { - break; + VkResult localRes = pBlockVector->CheckCorruption(); + switch(localRes) + { + case VK_ERROR_FEATURE_NOT_PRESENT: + break; + case VK_SUCCESS: + finalRes = VK_SUCCESS; + break; + default: + return localRes; + } } } - if(res == VK_SUCCESS) + // Process custom pools. { - // Register them in m_pDedicatedAllocations. + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { - VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocations); - for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) { - VmaVectorInsertSorted(*pDedicatedAllocations, pAllocations[allocIndex]); + VkResult localRes = pool->m_BlockVector.CheckCorruption(); + switch(localRes) + { + case VK_ERROR_FEATURE_NOT_PRESENT: + break; + case VK_SUCCESS: + finalRes = VK_SUCCESS; + break; + default: + return localRes; + } } } + } - VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex); + return finalRes; +} + +VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory) +{ + AtomicTransactionalIncrement deviceMemoryCountIncrement; + const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount); +#if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT + if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) + { + return VK_ERROR_TOO_MANY_OBJECTS; } - else +#endif + + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); + + // HeapSizeLimit is in effect for this heap. + if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) { - // Free all already created allocations. - while(allocIndex--) + const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; + VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; + for(;;) { - VmaAllocation currAlloc = pAllocations[allocIndex]; - VkDeviceMemory hMemory = currAlloc->GetMemory(); - - /* - There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory - before vkFreeMemory. - - if(currAlloc->GetMappedData() != VMA_NULL) + const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize; + if(blockBytesAfterAllocation > heapSize) { - (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - */ - - FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory); - m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize()); - currAlloc->SetUserData(this, VMA_NULL); - m_AllocationObjectAllocator.Free(currAlloc); + if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) + { + break; + } + } + } + else + { + m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize; + } + ++m_Budget.m_BlockCount[heapIndex]; + + // VULKAN CALL vkAllocateMemory. + VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); + + if(res == VK_SUCCESS) + { +#if VMA_MEMORY_BUDGET + ++m_Budget.m_OperationsSinceBudgetFetch; +#endif + + // Informative callback. + if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) + { + (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData); } - memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); - } + deviceMemoryCountIncrement.Commit(); + } + else + { + --m_Budget.m_BlockCount[heapIndex]; + m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize; + } + + return res; +} + +void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) +{ + // Informative callback. + if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) + { + (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData); + } + + // VULKAN CALL vkFreeMemory. + (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks()); + + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType); + --m_Budget.m_BlockCount[heapIndex]; + m_Budget.m_BlockBytes[heapIndex] -= size; + + --m_DeviceMemoryCount; +} + +VkResult VmaAllocator_T::BindVulkanBuffer( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkBuffer buffer, + const void* pNext) +{ + if(pNext != VMA_NULL) + { +#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL) + { + VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR }; + bindBufferMemoryInfo.pNext = pNext; + bindBufferMemoryInfo.buffer = buffer; + bindBufferMemoryInfo.memory = memory; + bindBufferMemoryInfo.memoryOffset = memoryOffset; + return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + } + else + { + return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset); + } +} + +VkResult VmaAllocator_T::BindVulkanImage( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkImage image, + const void* pNext) +{ + if(pNext != VMA_NULL) + { +#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL) + { + VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR }; + bindBufferMemoryInfo.pNext = pNext; + bindBufferMemoryInfo.image = image; + bindBufferMemoryInfo.memory = memory; + bindBufferMemoryInfo.memoryOffset = memoryOffset; + return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); + } + else +#endif // #if VMA_BIND_MEMORY2 + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + } + else + { + return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset); + } +} + +VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) +{ + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + char *pBytes = VMA_NULL; + VkResult res = pBlock->Map(this, 1, (void**)&pBytes); + if(res == VK_SUCCESS) + { + *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); + hAllocation->BlockAllocMap(); + } + return res; + } + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + return hAllocation->DedicatedAllocMap(this, ppData); + default: + VMA_ASSERT(0); + return VK_ERROR_MEMORY_MAP_FAILED; + } +} + +void VmaAllocator_T::Unmap(VmaAllocation hAllocation) +{ + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + hAllocation->BlockAllocUnmap(); + pBlock->Unmap(this, 1); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + hAllocation->DedicatedAllocUnmap(this); + break; + default: + VMA_ASSERT(0); + } +} + +VkResult VmaAllocator_T::BindBufferMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext) +{ + VkResult res = VK_ERROR_UNKNOWN; + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext); + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block."); + res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext); + break; + } + default: + VMA_ASSERT(0); + } + return res; +} + +VkResult VmaAllocator_T::BindImageMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext) +{ + VkResult res = VK_ERROR_UNKNOWN; + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext); + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); + VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block."); + res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext); + break; + } + default: + VMA_ASSERT(0); + } + return res; +} + +VkResult VmaAllocator_T::FlushOrInvalidateAllocation( + VmaAllocation hAllocation, + VkDeviceSize offset, VkDeviceSize size, + VMA_CACHE_OPERATION op) +{ + VkResult res = VK_SUCCESS; + + VkMappedMemoryRange memRange = {}; + if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) + { + switch(op) + { + case VMA_CACHE_FLUSH: + res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange); + break; + case VMA_CACHE_INVALIDATE: + res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange); + break; + default: + VMA_ASSERT(0); + } + } + // else: Just ignore this call. + return res; +} + +VkResult VmaAllocator_T::FlushOrInvalidateAllocations( + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, const VkDeviceSize* sizes, + VMA_CACHE_OPERATION op) +{ + typedef VmaStlAllocator RangeAllocator; + typedef VmaSmallVector RangeVector; + RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks())); + + for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + const VmaAllocation alloc = allocations[allocIndex]; + const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0; + const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE; + VkMappedMemoryRange newRange; + if(GetFlushOrInvalidateRange(alloc, offset, size, newRange)) + { + ranges.push_back(newRange); + } + } + + VkResult res = VK_SUCCESS; + if(!ranges.empty()) + { + switch(op) + { + case VMA_CACHE_FLUSH: + res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); + break; + case VMA_CACHE_INVALIDATE: + res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); + break; + default: + VMA_ASSERT(0); + } + } + // else: Just ignore this call. + return res; +} + +void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) +{ + VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + VmaPool parentPool = allocation->GetParentPool(); + if(parentPool == VK_NULL_HANDLE) + { + // Default pool + m_DedicatedAllocations[memTypeIndex].Unregister(allocation); + } + else + { + // Custom pool + parentPool->m_DedicatedAllocations.Unregister(allocation); + } + + VkDeviceMemory hMemory = allocation->GetMemory(); + + /* + There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory + before vkFreeMemory. + + if(allocation->GetMappedData() != VMA_NULL) + { + (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); + } + */ + + FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory); + + m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize()); + m_AllocationObjectAllocator.Free(allocation); + + VMA_DEBUG_LOG_FORMAT(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex); +} + +uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const +{ + VkBufferCreateInfo dummyBufCreateInfo; + VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo); + + uint32_t memoryTypeBits = 0; + + // Create buffer. + VkBuffer buf = VK_NULL_HANDLE; + VkResult res = (*GetVulkanFunctions().vkCreateBuffer)( + m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf); + if(res == VK_SUCCESS) + { + // Query for supported memory types. + VkMemoryRequirements memReq; + (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq); + memoryTypeBits = memReq.memoryTypeBits; + + // Destroy buffer. + (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks()); + } + + return memoryTypeBits; +} + +uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const +{ + // Make sure memory information is already fetched. + VMA_ASSERT(GetMemoryTypeCount() > 0); + + uint32_t memoryTypeBits = UINT32_MAX; + + if(!m_UseAmdDeviceCoherentMemory) + { + // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) + { + memoryTypeBits &= ~(1u << memTypeIndex); + } + } + } + + return memoryTypeBits; +} + +bool VmaAllocator_T::GetFlushOrInvalidateRange( + VmaAllocation allocation, + VkDeviceSize offset, VkDeviceSize size, + VkMappedMemoryRange& outRange) const +{ + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) + { + const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; + const VkDeviceSize allocationSize = allocation->GetSize(); + VMA_ASSERT(offset <= allocationSize); + + outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + outRange.pNext = VMA_NULL; + outRange.memory = allocation->GetMemory(); + + switch(allocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); + if(size == VK_WHOLE_SIZE) + { + outRange.size = allocationSize - outRange.offset; + } + else + { + VMA_ASSERT(offset + size <= allocationSize); + outRange.size = VMA_MIN( + VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize), + allocationSize - outRange.offset); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + // 1. Still within this allocation. + outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); + if(size == VK_WHOLE_SIZE) + { + size = allocationSize - offset; + } + else + { + VMA_ASSERT(offset + size <= allocationSize); + } + outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize); + + // 2. Adjust to whole block. + const VkDeviceSize allocationOffset = allocation->GetOffset(); + VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0); + const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize(); + outRange.offset += allocationOffset; + outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset); + + break; + } + default: + VMA_ASSERT(0); + } + return true; + } + return false; +} + +#if VMA_MEMORY_BUDGET +void VmaAllocator_T::UpdateVulkanBudget() +{ + VMA_ASSERT(m_UseExtMemoryBudget); + + VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR }; + + VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT }; + VmaPnextChainPushFront(&memProps, &budgetProps); + + GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps); + + { + VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex); + + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + { + m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex]; + m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex]; + m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load(); + + // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size. + if(m_Budget.m_VulkanBudget[heapIndex] == 0) + { + m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. + } + else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) + { + m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size; + } + if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) + { + m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; + } + } + m_Budget.m_OperationsSinceBudgetFetch = 0; + } +} +#endif // VMA_MEMORY_BUDGET + +void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern) +{ + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS && + hAllocation->IsMappingAllowed() && + (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) + { + void* pData = VMA_NULL; + VkResult res = Map(hAllocation, &pData); + if(res == VK_SUCCESS) + { + memset(pData, (int)pattern, (size_t)hAllocation->GetSize()); + FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH); + Unmap(hAllocation); + } + else + { + VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation."); + } + } +} + +uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits() +{ + uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load(); + if(memoryTypeBits == UINT32_MAX) + { + memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits(); + m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits); + } + return memoryTypeBits; +} + +#if VMA_STATS_STRING_ENABLED +void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) +{ + json.WriteString("DefaultPools"); + json.BeginObject(); + { + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex]; + VmaDedicatedAllocationList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex]; + if (pBlockVector != VMA_NULL) + { + json.BeginString("Type "); + json.ContinueString(memTypeIndex); + json.EndString(); + json.BeginObject(); + { + json.WriteString("PreferredBlockSize"); + json.WriteNumber(pBlockVector->GetPreferredBlockSize()); + + json.WriteString("Blocks"); + pBlockVector->PrintDetailedMap(json); + + json.WriteString("DedicatedAllocations"); + dedicatedAllocList.BuildStatsString(json); + } + json.EndObject(); + } + } + } + json.EndObject(); + + json.WriteString("CustomPools"); + json.BeginObject(); + { + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + if (!m_Pools.IsEmpty()) + { + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + bool displayType = true; + size_t index = 0; + for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + { + VmaBlockVector& blockVector = pool->m_BlockVector; + if (blockVector.GetMemoryTypeIndex() == memTypeIndex) + { + if (displayType) + { + json.BeginString("Type "); + json.ContinueString(memTypeIndex); + json.EndString(); + json.BeginArray(); + displayType = false; + } + + json.BeginObject(); + { + json.WriteString("Name"); + json.BeginString(); + json.ContinueString((uint64_t)index++); + if (pool->GetName()) + { + json.ContinueString(" - "); + json.ContinueString(pool->GetName()); + } + json.EndString(); + + json.WriteString("PreferredBlockSize"); + json.WriteNumber(blockVector.GetPreferredBlockSize()); + + json.WriteString("Blocks"); + blockVector.PrintDetailedMap(json); + + json.WriteString("DedicatedAllocations"); + pool->m_DedicatedAllocations.BuildStatsString(json); + } + json.EndObject(); + } + } + + if (!displayType) + json.EndArray(); + } + } + } + json.EndObject(); +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_ALLOCATOR_T_FUNCTIONS + + +#ifndef _VMA_PUBLIC_INTERFACE +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* pCreateInfo, + VmaAllocator* pAllocator) +{ + VMA_ASSERT(pCreateInfo && pAllocator); + VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 || + (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 3)); + VMA_DEBUG_LOG("vmaCreateAllocator"); + *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); + VkResult result = (*pAllocator)->Init(pCreateInfo); + if(result < 0) + { + vma_delete(pCreateInfo->pAllocationCallbacks, *pAllocator); + *pAllocator = VK_NULL_HANDLE; + } + return result; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator allocator) +{ + if(allocator != VK_NULL_HANDLE) + { + VMA_DEBUG_LOG("vmaDestroyAllocator"); + VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; // Have to copy the callbacks when destroying. + vma_delete(&allocationCallbacks, allocator); + } +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo) +{ + VMA_ASSERT(allocator && pAllocatorInfo); + pAllocatorInfo->instance = allocator->m_hInstance; + pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice(); + pAllocatorInfo->device = allocator->m_hDevice; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator allocator, + const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) +{ + VMA_ASSERT(allocator && ppPhysicalDeviceProperties); + *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator allocator, + const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties) +{ + VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties); + *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* pFlags) +{ + VMA_ASSERT(allocator && pFlags); + VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount()); + *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator allocator, + uint32_t frameIndex) +{ + VMA_ASSERT(allocator); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->SetCurrentFrameIndex(frameIndex); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator allocator, + VmaTotalStatistics* pStats) +{ + VMA_ASSERT(allocator && pStats); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + allocator->CalculateStatistics(pStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator allocator, + VmaBudget* pBudgets) +{ + VMA_ASSERT(allocator && pBudgets); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); +} + +#if VMA_STATS_STRING_ENABLED + +VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator allocator, + char** ppStatsString, + VkBool32 detailedMap) +{ + VMA_ASSERT(allocator && ppStatsString); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VmaStringBuilder sb(allocator->GetAllocationCallbacks()); + { + VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; + allocator->GetHeapBudgets(budgets, 0, allocator->GetMemoryHeapCount()); + + VmaTotalStatistics stats; + allocator->CalculateStatistics(&stats); + + VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb); + json.BeginObject(); + { + json.WriteString("General"); + json.BeginObject(); + { + const VkPhysicalDeviceProperties& deviceProperties = allocator->m_PhysicalDeviceProperties; + const VkPhysicalDeviceMemoryProperties& memoryProperties = allocator->m_MemProps; + + json.WriteString("API"); + json.WriteString("Vulkan"); + + json.WriteString("apiVersion"); + json.BeginString(); + json.ContinueString(VK_VERSION_MAJOR(deviceProperties.apiVersion)); + json.ContinueString("."); + json.ContinueString(VK_VERSION_MINOR(deviceProperties.apiVersion)); + json.ContinueString("."); + json.ContinueString(VK_VERSION_PATCH(deviceProperties.apiVersion)); + json.EndString(); + + json.WriteString("GPU"); + json.WriteString(deviceProperties.deviceName); + json.WriteString("deviceType"); + json.WriteNumber(static_cast(deviceProperties.deviceType)); + + json.WriteString("maxMemoryAllocationCount"); + json.WriteNumber(deviceProperties.limits.maxMemoryAllocationCount); + json.WriteString("bufferImageGranularity"); + json.WriteNumber(deviceProperties.limits.bufferImageGranularity); + json.WriteString("nonCoherentAtomSize"); + json.WriteNumber(deviceProperties.limits.nonCoherentAtomSize); + + json.WriteString("memoryHeapCount"); + json.WriteNumber(memoryProperties.memoryHeapCount); + json.WriteString("memoryTypeCount"); + json.WriteNumber(memoryProperties.memoryTypeCount); + } + json.EndObject(); + } + { + json.WriteString("Total"); + VmaPrintDetailedStatistics(json, stats.total); + } + { + json.WriteString("MemoryInfo"); + json.BeginObject(); + { + for (uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex) + { + json.BeginString("Heap "); + json.ContinueString(heapIndex); + json.EndString(); + json.BeginObject(); + { + const VkMemoryHeap& heapInfo = allocator->m_MemProps.memoryHeaps[heapIndex]; + json.WriteString("Flags"); + json.BeginArray(true); + { + if (heapInfo.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + json.WriteString("DEVICE_LOCAL"); + #if VMA_VULKAN_VERSION >= 1001000 + if (heapInfo.flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT) + json.WriteString("MULTI_INSTANCE"); + #endif + + VkMemoryHeapFlags flags = heapInfo.flags & + ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT + #if VMA_VULKAN_VERSION >= 1001000 + | VK_MEMORY_HEAP_MULTI_INSTANCE_BIT + #endif + ); + if (flags != 0) + json.WriteNumber(flags); + } + json.EndArray(); + + json.WriteString("Size"); + json.WriteNumber(heapInfo.size); + + json.WriteString("Budget"); + json.BeginObject(); + { + json.WriteString("BudgetBytes"); + json.WriteNumber(budgets[heapIndex].budget); + json.WriteString("UsageBytes"); + json.WriteNumber(budgets[heapIndex].usage); + } + json.EndObject(); + + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats.memoryHeap[heapIndex]); + + json.WriteString("MemoryPools"); + json.BeginObject(); + { + for (uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex) + { + if (allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex) + { + json.BeginString("Type "); + json.ContinueString(typeIndex); + json.EndString(); + json.BeginObject(); + { + json.WriteString("Flags"); + json.BeginArray(true); + { + VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags; + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + json.WriteString("DEVICE_LOCAL"); + if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + json.WriteString("HOST_VISIBLE"); + if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + json.WriteString("HOST_COHERENT"); + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + json.WriteString("HOST_CACHED"); + if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) + json.WriteString("LAZILY_ALLOCATED"); + #if VMA_VULKAN_VERSION >= 1001000 + if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) + json.WriteString("PROTECTED"); + #endif + #if VK_AMD_device_coherent_memory + if (flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) + json.WriteString("DEVICE_COHERENT_AMD"); + if (flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) + json.WriteString("DEVICE_UNCACHED_AMD"); + #endif + + flags &= ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + #if VMA_VULKAN_VERSION >= 1001000 + | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT + #endif + #if VK_AMD_device_coherent_memory + | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY + | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY + #endif + | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + if (flags != 0) + json.WriteNumber(flags); + } + json.EndArray(); + + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats.memoryType[typeIndex]); + } + json.EndObject(); + } + } + + } + json.EndObject(); + } + json.EndObject(); + } + } + json.EndObject(); + } + + if (detailedMap == VK_TRUE) + allocator->PrintDetailedMap(json); + + json.EndObject(); + } + + *ppStatsString = VmaCreateStringCopy(allocator->GetAllocationCallbacks(), sb.GetData(), sb.GetLength()); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator allocator, + char* pStatsString) +{ + if(pStatsString != VMA_NULL) + { + VMA_ASSERT(allocator); + VmaFreeString(allocator->GetAllocationCallbacks(), pStatsString); + } +} + +#endif // VMA_STATS_STRING_ENABLED + +/* +This function is not protected by any mutex because it just reads immutable data. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + return allocator->FindMemoryTypeIndex(memoryTypeBits, pAllocationCreateInfo, UINT32_MAX, pMemoryTypeIndex); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pBufferCreateInfo != VMA_NULL); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + const VkDevice hDev = allocator->m_hDevice; + const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); + VkResult res; + +#if VMA_VULKAN_VERSION >= 1003000 + if(funcs->vkGetDeviceBufferMemoryRequirements) + { + // Can query straight from VkBufferCreateInfo :) + VkDeviceBufferMemoryRequirements devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS}; + devBufMemReq.pCreateInfo = pBufferCreateInfo; + + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + (*funcs->vkGetDeviceBufferMemoryRequirements)(hDev, &devBufMemReq, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1003000 + { + // Must create a dummy buffer to query :( + VkBuffer hBuffer = VK_NULL_HANDLE; + res = funcs->vkCreateBuffer( + hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); + if(res == VK_SUCCESS) + { + VkMemoryRequirements memReq = {}; + funcs->vkGetBufferMemoryRequirements(hDev, hBuffer, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + + funcs->vkDestroyBuffer( + hDev, hBuffer, allocator->GetAllocationCallbacks()); + } + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pImageCreateInfo != VMA_NULL); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + const VkDevice hDev = allocator->m_hDevice; + const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); + VkResult res; + +#if VMA_VULKAN_VERSION >= 1003000 + if(funcs->vkGetDeviceImageMemoryRequirements) + { + // Can query straight from VkImageCreateInfo :) + VkDeviceImageMemoryRequirements devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS}; + devImgMemReq.pCreateInfo = pImageCreateInfo; + VMA_ASSERT(pImageCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY && (pImageCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT_COPY) == 0 && + "Cannot use this VkImageCreateInfo with vmaFindMemoryTypeIndexForImageInfo as I don't know what to pass as VkDeviceImageMemoryRequirements::planeAspect."); + + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + (*funcs->vkGetDeviceImageMemoryRequirements)(hDev, &devImgMemReq, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1003000 + { + // Must create a dummy image to query :( + VkImage hImage = VK_NULL_HANDLE; + res = funcs->vkCreateImage( + hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); + if(res == VK_SUCCESS) + { + VkMemoryRequirements memReq = {}; + funcs->vkGetImageMemoryRequirements(hDev, hImage, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + + funcs->vkDestroyImage( + hDev, hImage, allocator->GetAllocationCallbacks()); + } + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator allocator, + const VmaPoolCreateInfo* pCreateInfo, + VmaPool* pPool) +{ + VMA_ASSERT(allocator && pCreateInfo && pPool); + + VMA_DEBUG_LOG("vmaCreatePool"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CreatePool(pCreateInfo, pPool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator allocator, + VmaPool pool) +{ + VMA_ASSERT(allocator); + + if(pool == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyPool"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->DestroyPool(pool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator allocator, + VmaPool pool, + VmaStatistics* pPoolStats) +{ + VMA_ASSERT(allocator && pool && pPoolStats); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->GetPoolStatistics(pool, pPoolStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator allocator, + VmaPool pool, + VmaDetailedStatistics* pPoolStats) +{ + VMA_ASSERT(allocator && pool && pPoolStats); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->CalculatePoolStatistics(pool, pPoolStats); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool) +{ + VMA_ASSERT(allocator && pool); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VMA_DEBUG_LOG("vmaCheckPoolCorruption"); + + return allocator->CheckPoolCorruption(pool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator allocator, + VmaPool pool, + const char** ppName) +{ + VMA_ASSERT(allocator && pool && ppName); + + VMA_DEBUG_LOG("vmaGetPoolName"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *ppName = pool->GetName(); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator allocator, + VmaPool pool, + const char* pName) +{ + VMA_ASSERT(allocator && pool); + + VMA_DEBUG_LOG("vmaSetPoolName"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + pool->SetName(pName); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator allocator, + const VkMemoryRequirements* pVkMemoryRequirements, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator allocator, + const VkMemoryRequirements* pVkMemoryRequirements, + const VmaAllocationCreateInfo* pCreateInfo, + size_t allocationCount, + VmaAllocation* pAllocations, + VmaAllocationInfo* pAllocationInfo) +{ + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations); + + VMA_DEBUG_LOG("vmaAllocateMemoryPages"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + allocationCount, + pAllocations); + + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + { + for(size_t i = 0; i < allocationCount; ++i) + { + allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i); + } + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator allocator, + VkBuffer buffer, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(buffer, vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation); + + VkResult result = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + buffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator allocator, + VkImage image, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemoryForImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetImageMemoryRequirements(image, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + VkResult result = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + VK_NULL_HANDLE, // dedicatedBuffer + image, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator allocator, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator); + + if(allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaFreeMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->FreeMemory( + 1, // allocationCount + &allocation); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator allocator, + size_t allocationCount, + const VmaAllocation* pAllocations) +{ + if(allocationCount == 0) + { + return; + } + + VMA_ASSERT(allocator); + + VMA_DEBUG_LOG("vmaFreeMemoryPages"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->FreeMemory(allocationCount, pAllocations); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator allocator, + VmaAllocation allocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && allocation && pAllocationInfo); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->GetAllocationInfo(allocation, pAllocationInfo); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator allocator, + VmaAllocation allocation, + void* pUserData) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocation->SetUserData(allocator, pUserData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName) +{ + allocation->SetName(allocator, pName); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags) +{ + VMA_ASSERT(allocator && allocation && pFlags); + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + *pFlags = allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator allocator, + VmaAllocation allocation, + void** ppData) +{ + VMA_ASSERT(allocator && allocation && ppData); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->Map(allocation, ppData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator allocator, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->Unmap(allocation); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize offset, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_LOG("vmaFlushAllocation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize offset, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_LOG("vmaInvalidateAllocation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator allocator, + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, + const VkDeviceSize* sizes) +{ + VMA_ASSERT(allocator); + + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocations); + + VMA_DEBUG_LOG("vmaFlushAllocations"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator allocator, + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, + const VkDeviceSize* sizes) +{ + VMA_ASSERT(allocator); + + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocations); + + VMA_DEBUG_LOG("vmaInvalidateAllocations"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator allocator, + uint32_t memoryTypeBits) +{ + VMA_ASSERT(allocator); + + VMA_DEBUG_LOG("vmaCheckCorruption"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CheckCorruption(memoryTypeBits); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator allocator, + const VmaDefragmentationInfo* pInfo, + VmaDefragmentationContext* pContext) +{ + VMA_ASSERT(allocator && pInfo && pContext); + + VMA_DEBUG_LOG("vmaBeginDefragmentation"); + + if (pInfo->pool != VMA_NULL) + { + // Check if run on supported algorithms + if (pInfo->pool->m_BlockVector.GetAlgorithm() & VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); + return VK_SUCCESS; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator allocator, + VmaDefragmentationContext context, + VmaDefragmentationStats* pStats) +{ + VMA_ASSERT(allocator && context); + + VMA_DEBUG_LOG("vmaEndDefragmentation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if (pStats) + context->GetStats(*pStats); + vma_delete(allocator, context); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo) +{ + VMA_ASSERT(context && pPassInfo); + + VMA_DEBUG_LOG("vmaBeginDefragmentationPass"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return context->DefragmentPassBegin(*pPassInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo) +{ + VMA_ASSERT(context && pPassInfo); + + VMA_DEBUG_LOG("vmaEndDefragmentationPass"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return context->DefragmentPassEnd(*pPassInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator allocator, + VmaAllocation allocation, + VkBuffer buffer) +{ + VMA_ASSERT(allocator && allocation && buffer); + + VMA_DEBUG_LOG("vmaBindBufferMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer buffer, + const void* pNext) +{ + VMA_ASSERT(allocator && allocation && buffer); + + VMA_DEBUG_LOG("vmaBindBufferMemory2"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator allocator, + VmaAllocation allocation, + VkImage image) +{ + VMA_ASSERT(allocator && allocation && image); + + VMA_DEBUG_LOG("vmaBindImageMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize allocationLocalOffset, + VkImage image, + const void* pNext) +{ + VMA_ASSERT(allocator && allocation && image); + + VMA_DEBUG_LOG("vmaBindImageMemory2"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkBuffer* pBuffer, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); + + if(pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pBuffer = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if(res >= 0) + { + // 2. vkGetBufferMemoryRequirements. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + // 3. Allocate memory using allocator. + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + *pBuffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + pBufferCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind buffer with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer* pBuffer, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && VmaIsPow2(minAlignment) && pBuffer && pAllocation); + + if(pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateBufferWithAlignment"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pBuffer = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if(res >= 0) + { + // 2. vkGetBufferMemoryRequirements. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + // 2a. Include minAlignment + vkMemReq.alignment = VMA_MAX(vkMemReq.alignment, minAlignment); + + // 3. Allocate memory using allocator. + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + *pBuffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + pBufferCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind buffer with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer) +{ + return vmaCreateAliasingBuffer2(allocator, allocation, 0, pBufferCreateInfo, pBuffer); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pBuffer && allocation); + VMA_ASSERT(allocationLocalOffset + pBufferCreateInfo->size <= allocation->GetSize()); + + VMA_DEBUG_LOG("vmaCreateAliasingBuffer2"); + + *pBuffer = VK_NULL_HANDLE; + + if (pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if (res >= 0) + { + // 2. Bind buffer with memory. + res = allocator->BindBufferMemory(allocation, allocationLocalOffset, *pBuffer, VMA_NULL); + if (res >= 0) + { + return VK_SUCCESS; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator allocator, + VkBuffer buffer, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator); + + if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if(buffer != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); + } + + if(allocation != VK_NULL_HANDLE) + { + allocator->FreeMemory( + 1, // allocationCount + &allocation); + } +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkImage* pImage, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); + + if(pImageCreateInfo->extent.width == 0 || + pImageCreateInfo->extent.height == 0 || + pImageCreateInfo->extent.depth == 0 || + pImageCreateInfo->mipLevels == 0 || + pImageCreateInfo->arrayLayers == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pImage = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); + if(res >= 0) + { + VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? + VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : + VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR; + + // 2. Allocate memory using allocator. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetImageMemoryRequirements(*pImage, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + VK_NULL_HANDLE, // dedicatedBuffer + *pImage, // dedicatedImage + pImageCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + suballocType, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind image with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + *pImage = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + *pImage = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage) +{ + return vmaCreateAliasingImage2(allocator, allocation, 0, pImageCreateInfo, pImage); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage) +{ + VMA_ASSERT(allocator && pImageCreateInfo && pImage && allocation); + + *pImage = VK_NULL_HANDLE; + + VMA_DEBUG_LOG("vmaCreateImage2"); + + if (pImageCreateInfo->extent.width == 0 || + pImageCreateInfo->extent.height == 0 || + pImageCreateInfo->extent.depth == 0 || + pImageCreateInfo->mipLevels == 0 || + pImageCreateInfo->arrayLayers == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); + if (res >= 0) + { + // 2. Bind image with memory. + res = allocator->BindImageMemory(allocation, allocationLocalOffset, *pImage, VMA_NULL); + if (res >= 0) + { + return VK_SUCCESS; + } + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation) +{ + VMA_ASSERT(allocator); + + if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if(image != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); + } + if(allocation != VK_NULL_HANDLE) + { + allocator->FreeMemory( + 1, // allocationCount + &allocation); + } +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE * VMA_NOT_NULL pVirtualBlock) +{ + VMA_ASSERT(pCreateInfo && pVirtualBlock); + VMA_ASSERT(pCreateInfo->size > 0); + VMA_DEBUG_LOG("vmaCreateVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + *pVirtualBlock = vma_new(pCreateInfo->pAllocationCallbacks, VmaVirtualBlock_T)(*pCreateInfo); + VkResult res = (*pVirtualBlock)->Init(); + if(res < 0) + { + vma_delete(pCreateInfo->pAllocationCallbacks, *pVirtualBlock); + *pVirtualBlock = VK_NULL_HANDLE; + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLABLE virtualBlock) +{ + if(virtualBlock != VK_NULL_HANDLE) + { + VMA_DEBUG_LOG("vmaDestroyVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + VkAllocationCallbacks allocationCallbacks = virtualBlock->m_AllocationCallbacks; // Have to copy the callbacks when destroying. + vma_delete(&allocationCallbacks, virtualBlock); + } +} + +VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty(VmaVirtualBlock VMA_NOT_NULL virtualBlock) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaIsVirtualBlockEmpty"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + return virtualBlock->IsEmpty() ? VK_TRUE : VK_FALSE; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pVirtualAllocInfo != VMA_NULL); + VMA_DEBUG_LOG("vmaGetVirtualAllocationInfo"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->GetAllocationInfo(allocation, *pVirtualAllocInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pCreateInfo != VMA_NULL && pAllocation != VMA_NULL); + VMA_DEBUG_LOG("vmaVirtualAllocate"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + return virtualBlock->Allocate(*pCreateInfo, *pAllocation, pOffset); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation) +{ + if(allocation != VK_NULL_HANDLE) + { + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaVirtualFree"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->Free(allocation); + } +} + +VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock(VmaVirtualBlock VMA_NOT_NULL virtualBlock) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaClearVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->Clear(); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, void* VMA_NULLABLE pUserData) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaSetVirtualAllocationUserData"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->SetAllocationUserData(allocation, pUserData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); + VMA_DEBUG_LOG("vmaGetVirtualBlockStatistics"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->GetStatistics(*pStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); + VMA_DEBUG_LOG("vmaCalculateVirtualBlockStatistics"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->CalculateDetailedStatistics(*pStats); +} + +#if VMA_STATS_STRING_ENABLED + +VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && ppStatsString != VMA_NULL); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + const VkAllocationCallbacks* allocationCallbacks = virtualBlock->GetAllocationCallbacks(); + VmaStringBuilder sb(allocationCallbacks); + virtualBlock->BuildStatsString(detailedMap != VK_FALSE, sb); + *ppStatsString = VmaCreateStringCopy(allocationCallbacks, sb.GetData(), sb.GetLength()); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString) +{ + if(pStatsString != VMA_NULL) + { + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString); + } +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_PUBLIC_INTERFACE +#endif // VMA_IMPLEMENTATION + +/** +\page quick_start Quick start + +\section quick_start_project_setup Project setup + +Vulkan Memory Allocator comes in form of a "stb-style" single header file. +You don't need to build it as a separate library project. +You can add this file directly to your project and submit it to code repository next to your other source files. + +"Single header" doesn't mean that everything is contained in C/C++ declarations, +like it tends to be in case of inline functions or C++ templates. +It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. +If you don't do it properly, you will get linker errors. + +To do it properly: + +-# Include "vk_mem_alloc.h" file in each CPP file where you want to use the library. + This includes declarations of all members of the library. +-# In exactly one CPP file define following macro before this include. + It enables also internal definitions. + +\code +#define VMA_IMPLEMENTATION +#include "vk_mem_alloc.h" +\endcode + +It may be a good idea to create dedicated CPP file just for this purpose. + +This library includes header ``, which in turn +includes `` on Windows. If you need some specific macros defined +before including these headers (like `WIN32_LEAN_AND_MEAN` or +`WINVER` for Windows, `VK_USE_PLATFORM_WIN32_KHR` for Vulkan), you must define +them before every `#include` of this library. + +This library is written in C++, but has C-compatible interface. +Thus you can include and use vk_mem_alloc.h in C or C++ code, but full +implementation with `VMA_IMPLEMENTATION` macro must be compiled as C++, NOT as C. +Some features of C++14 are used. STL containers, RTTI, or C++ exceptions are not used. + + +\section quick_start_initialization Initialization + +At program startup: + +-# Initialize Vulkan to have `VkPhysicalDevice`, `VkDevice` and `VkInstance` object. +-# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by + calling vmaCreateAllocator(). + +Only members `physicalDevice`, `device`, `instance` are required. +However, you should inform the library which Vulkan version do you use by setting +VmaAllocatorCreateInfo::vulkanApiVersion and which extensions did you enable +by setting VmaAllocatorCreateInfo::flags (like #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT for VK_KHR_buffer_device_address). +Otherwise, VMA would use only features of Vulkan 1.0 core with no extensions. + +\subsection quick_start_initialization_selecting_vulkan_version Selecting Vulkan version + +VMA supports Vulkan version down to 1.0, for backward compatibility. +If you want to use higher version, you need to inform the library about it. +This is a two-step process. + +Step 1: Compile time. By default, VMA compiles with code supporting the highest +Vulkan version found in the included `` that is also supported by the library. +If this is OK, you don't need to do anything. +However, if you want to compile VMA as if only some lower Vulkan version was available, +define macro `VMA_VULKAN_VERSION` before every `#include "vk_mem_alloc.h"`. +It should have decimal numeric value in form of ABBBCCC, where A = major, BBB = minor, CCC = patch Vulkan version. +For example, to compile against Vulkan 1.2: + +\code +#define VMA_VULKAN_VERSION 1002000 // Vulkan 1.2 +#include "vk_mem_alloc.h" +\endcode + +Step 2: Runtime. Even when compiled with higher Vulkan version available, +VMA can use only features of a lower version, which is configurable during creation of the #VmaAllocator object. +By default, only Vulkan 1.0 is used. +To initialize the allocator with support for higher Vulkan version, you need to set member +VmaAllocatorCreateInfo::vulkanApiVersion to an appropriate value, e.g. using constants like `VK_API_VERSION_1_2`. +See code sample below. + +\subsection quick_start_initialization_importing_vulkan_functions Importing Vulkan functions + +You may need to configure importing Vulkan functions. There are 3 ways to do this: + +-# **If you link with Vulkan static library** (e.g. "vulkan-1.lib" on Windows): + - You don't need to do anything. + - VMA will use these, as macro `VMA_STATIC_VULKAN_FUNCTIONS` is defined to 1 by default. +-# **If you want VMA to fetch pointers to Vulkan functions dynamically** using `vkGetInstanceProcAddr`, + `vkGetDeviceProcAddr` (this is the option presented in the example below): + - Define `VMA_STATIC_VULKAN_FUNCTIONS` to 0, `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 1. + - Provide pointers to these two functions via VmaVulkanFunctions::vkGetInstanceProcAddr, + VmaVulkanFunctions::vkGetDeviceProcAddr. + - The library will fetch pointers to all other functions it needs internally. +-# **If you fetch pointers to all Vulkan functions in a custom way**, e.g. using some loader like + [Volk](https://github.com/zeux/volk): + - Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0. + - Pass these pointers via structure #VmaVulkanFunctions. + +Example for case 2: + +\code +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include "vk_mem_alloc.h" + +... + +VmaVulkanFunctions vulkanFunctions = {}; +vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr; +vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr; + +VmaAllocatorCreateInfo allocatorCreateInfo = {}; +allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2; +allocatorCreateInfo.physicalDevice = physicalDevice; +allocatorCreateInfo.device = device; +allocatorCreateInfo.instance = instance; +allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; + +VmaAllocator allocator; +vmaCreateAllocator(&allocatorCreateInfo, &allocator); +\endcode + + +\section quick_start_resource_allocation Resource allocation + +When you want to create a buffer or image: + +-# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure. +-# Fill VmaAllocationCreateInfo structure. +-# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory + already allocated and bound to it, plus #VmaAllocation objects that represents its underlying memory. + +\code +VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufferInfo.size = 65536; +bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +Don't forget to destroy your objects when no longer needed: + +\code +vmaDestroyBuffer(allocator, buffer, allocation); +vmaDestroyAllocator(allocator); +\endcode + + +\page choosing_memory_type Choosing memory type + +Physical devices in Vulkan support various combinations of memory heaps and +types. Help with choosing correct and optimal memory type for your specific +resource is one of the key features of this library. You can use it by filling +appropriate members of VmaAllocationCreateInfo structure, as described below. +You can also combine multiple methods. + +-# If you just want to find memory type index that meets your requirements, you + can use function: vmaFindMemoryTypeIndexForBufferInfo(), + vmaFindMemoryTypeIndexForImageInfo(), vmaFindMemoryTypeIndex(). +-# If you want to allocate a region of device memory without association with any + specific image or buffer, you can use function vmaAllocateMemory(). Usage of + this function is not recommended and usually not needed. + vmaAllocateMemoryPages() function is also provided for creating multiple allocations at once, + which may be useful for sparse binding. +-# If you already have a buffer or an image created, you want to allocate memory + for it and then you will bind it yourself, you can use function + vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). + For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory() + or their extended versions: vmaBindBufferMemory2(), vmaBindImageMemory2(). +-# **This is the easiest and recommended way to use this library:** + If you want to create a buffer or an image, allocate memory for it and bind + them together, all in one call, you can use function vmaCreateBuffer(), + vmaCreateImage(). + +When using 3. or 4., the library internally queries Vulkan for memory types +supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) +and uses only one of these types. + +If no memory type can be found that meets all the requirements, these functions +return `VK_ERROR_FEATURE_NOT_PRESENT`. + +You can leave VmaAllocationCreateInfo structure completely filled with zeros. +It means no requirements are specified for memory type. +It is valid, although not very useful. + +\section choosing_memory_type_usage Usage + +The easiest way to specify memory requirements is to fill member +VmaAllocationCreateInfo::usage using one of the values of enum #VmaMemoryUsage. +It defines high level, common usage types. +Since version 3 of the library, it is recommended to use #VMA_MEMORY_USAGE_AUTO to let it select best memory type for your resource automatically. + +For example, if you want to create a uniform buffer that will be filled using +transfer only once or infrequently and then used for rendering every frame as a uniform buffer, you can +do it using following code. The buffer will most likely end up in a memory type with +`VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT` to be fast to access by the GPU device. + +\code +VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufferInfo.size = 65536; +bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +If you have a preference for putting the resource in GPU (device) memory or CPU (host) memory +on systems with discrete graphics card that have the memories separate, you can use +#VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE or #VMA_MEMORY_USAGE_AUTO_PREFER_HOST. + +When using `VMA_MEMORY_USAGE_AUTO*` while you want to map the allocated memory, +you also need to specify one of the host access flags: +#VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +This will help the library decide about preferred memory type to ensure it has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +so you can map it. + +For example, a staging buffer that will be filled via mapped pointer and then +used as a source of transfer to the buffer described previously can be created like this. +It will likely end up in a memory type that is `HOST_VISIBLE` and `HOST_COHERENT` +but not `HOST_CACHED` (meaning uncached, write-combined) and not `DEVICE_LOCAL` (meaning system RAM). + +\code +VkBufferCreateInfo stagingBufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +stagingBufferInfo.size = 65536; +stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo stagingAllocInfo = {}; +stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO; +stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + +VkBuffer stagingBuffer; +VmaAllocation stagingAllocation; +vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer, &stagingAllocation, nullptr); +\endcode + +For more examples of creating different kinds of resources, see chapter \ref usage_patterns. + +Usage values `VMA_MEMORY_USAGE_AUTO*` are legal to use only when the library knows +about the resource being created by having `VkBufferCreateInfo` / `VkImageCreateInfo` passed, +so they work with functions like: vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo() etc. +If you allocate raw memory using function vmaAllocateMemory(), you have to use other means of selecting +memory type, as described below. + +\note +Old usage values (`VMA_MEMORY_USAGE_GPU_ONLY`, `VMA_MEMORY_USAGE_CPU_ONLY`, +`VMA_MEMORY_USAGE_CPU_TO_GPU`, `VMA_MEMORY_USAGE_GPU_TO_CPU`, `VMA_MEMORY_USAGE_CPU_COPY`) +are still available and work same way as in previous versions of the library +for backward compatibility, but they are not recommended. + +\section choosing_memory_type_required_preferred_flags Required and preferred flags + +You can specify more detailed requirements by filling members +VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags +with a combination of bits from enum `VkMemoryPropertyFlags`. For example, +if you want to create a buffer that will be persistently mapped on host (so it +must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`, +use following code: + +\code +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; +allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; +allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +A memory type is chosen that has all the required flags and as many preferred +flags set as possible. + +Value passed in VmaAllocationCreateInfo::usage is internally converted to a set of required and preferred flags, +plus some extra "magic" (heuristics). + +\section choosing_memory_type_explicit_memory_types Explicit memory types + +If you inspected memory types available on the physical device and you have +a preference for memory types that you want to use, you can fill member +VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set +means that a memory type with that index is allowed to be used for the +allocation. Special value 0, just like `UINT32_MAX`, means there are no +restrictions to memory type index. + +Please note that this member is NOT just a memory type index. +Still you can use it to choose just one, specific memory type. +For example, if you already determined that your buffer should be created in +memory type 2, use following code: + +\code +uint32_t memoryTypeIndex = 2; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.memoryTypeBits = 1u << memoryTypeIndex; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + + +\section choosing_memory_type_custom_memory_pools Custom memory pools + +If you allocate from custom memory pool, all the ways of specifying memory +requirements described above are not applicable and the aforementioned members +of VmaAllocationCreateInfo structure are ignored. Memory type is selected +explicitly when creating the pool and then used to make all the allocations from +that pool. For further details, see \ref custom_memory_pools. + +\section choosing_memory_type_dedicated_allocations Dedicated allocations + +Memory for allocations is reserved out of larger block of `VkDeviceMemory` +allocated from Vulkan internally. That is the main feature of this whole library. +You can still request a separate memory block to be created for an allocation, +just like you would do in a trivial solution without using any allocator. +In that case, a buffer or image is always bound to that memory at offset 0. +This is called a "dedicated allocation". +You can explicitly request it by using flag #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +The library can also internally decide to use dedicated allocation in some cases, e.g.: + +- When the size of the allocation is large. +- When [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension is enabled + and it reports that dedicated allocation is required or recommended for the resource. +- When allocation of next big memory block fails due to not enough device memory, + but allocation with the exact requested size succeeds. + + +\page memory_mapping Memory mapping + +To "map memory" in Vulkan means to obtain a CPU pointer to `VkDeviceMemory`, +to be able to read from it or write to it in CPU code. +Mapping is possible only of memory allocated from a memory type that has +`VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. +Functions `vkMapMemory()`, `vkUnmapMemory()` are designed for this purpose. +You can use them directly with memory allocated by this library, +but it is not recommended because of following issue: +Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. +This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. +Because of this, Vulkan Memory Allocator provides following facilities: + +\note If you want to be able to map an allocation, you need to specify one of the flags +#VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT +in VmaAllocationCreateInfo::flags. These flags are required for an allocation to be mappable +when using #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` enum values. +For other usage values they are ignored and every such allocation made in `HOST_VISIBLE` memory type is mappable, +but they can still be used for consistency. + +\section memory_mapping_mapping_functions Mapping functions + +The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). +They are safer and more convenient to use than standard Vulkan functions. +You can map an allocation multiple times simultaneously - mapping is reference-counted internally. +You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. +The way it is implemented is that the library always maps entire memory block, not just region of the allocation. +For further details, see description of vmaMapMemory() function. +Example: + +\code +// Having these objects initialized: +struct ConstantBuffer +{ + ... +}; +ConstantBuffer constantBufferData = ... + +VmaAllocator allocator = ... +VkBuffer constantBuffer = ... +VmaAllocation constantBufferAllocation = ... + +// You can map and fill your buffer using following code: + +void* mappedData; +vmaMapMemory(allocator, constantBufferAllocation, &mappedData); +memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); +vmaUnmapMemory(allocator, constantBufferAllocation); +\endcode + +When mapping, you may see a warning from Vulkan validation layer similar to this one: + +Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used. + +It happens because the library maps entire `VkDeviceMemory` block, where different +types of images and buffers may end up together, especially on GPUs with unified memory like Intel. +You can safely ignore it if you are sure you access only memory of the intended +object that you wanted to map. + + +\section memory_mapping_persistently_mapped_memory Persistently mapped memory + +Keeping your memory persistently mapped is generally OK in Vulkan. +You don't need to unmap it before using its data on the GPU. +The library provides a special feature designed for that: +Allocations made with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in +VmaAllocationCreateInfo::flags stay mapped all the time, +so you can just access CPU pointer to it any time +without a need to call any "map" or "unmap" function. +Example: + +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = sizeof(ConstantBuffer); +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + +// Buffer is already mapped. You can access its memory. +memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); +\endcode + +\note #VMA_ALLOCATION_CREATE_MAPPED_BIT by itself doesn't guarantee that the allocation will end up +in a mappable memory type. +For this, you need to also specify #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or +#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +#VMA_ALLOCATION_CREATE_MAPPED_BIT only guarantees that if the memory is `HOST_VISIBLE`, the allocation will be mapped on creation. +For an example of how to make use of this fact, see section \ref usage_patterns_advanced_data_uploading. + +\section memory_mapping_cache_control Cache flush and invalidate + +Memory in Vulkan doesn't need to be unmapped before using it on GPU, +but unless a memory types has `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag set, +you need to manually **invalidate** cache before reading of mapped pointer +and **flush** cache after writing to mapped pointer. +Map/unmap operations don't do that automatically. +Vulkan provides following functions for this purpose `vkFlushMappedMemoryRanges()`, +`vkInvalidateMappedMemoryRanges()`, but this library provides more convenient +functions that refer to given allocation object: vmaFlushAllocation(), +vmaInvalidateAllocation(), +or multiple objects at once: vmaFlushAllocations(), vmaInvalidateAllocations(). + +Regions of memory specified for flush/invalidate must be aligned to +`VkPhysicalDeviceLimits::nonCoherentAtomSize`. This is automatically ensured by the library. +In any memory type that is `HOST_VISIBLE` but not `HOST_COHERENT`, all allocations +within blocks are aligned to this value, so their offsets are always multiply of +`nonCoherentAtomSize` and two different allocations never share same "line" of this size. + +Also, Windows drivers from all 3 PC GPU vendors (AMD, Intel, NVIDIA) +currently provide `HOST_COHERENT` flag on all memory types that are +`HOST_VISIBLE`, so on PC you may not need to bother. + + +\page staying_within_budget Staying within budget + +When developing a graphics-intensive game or program, it is important to avoid allocating +more GPU memory than it is physically available. When the memory is over-committed, +various bad things can happen, depending on the specific GPU, graphics driver, and +operating system: - return res; -} +- It may just work without any problems. +- The application may slow down because some memory blocks are moved to system RAM + and the GPU has to access them through PCI Express bus. +- A new allocation may take very long time to complete, even few seconds, and possibly + freeze entire system. +- The new allocation may fail with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +- It may even result in GPU crash (TDR), observed as `VK_ERROR_DEVICE_LOST` + returned somewhere later. -VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - const VkMemoryAllocateInfo& allocInfo, - bool map, - bool isUserDataString, - void* pUserData, - VmaAllocation* pAllocation) -{ - VkDeviceMemory hMemory = VK_NULL_HANDLE; - VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); - if(res < 0) - { - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); - return res; - } +\section staying_within_budget_querying_for_budget Querying for budget - void* pMappedData = VMA_NULL; - if(map) - { - res = (*m_VulkanFunctions.vkMapMemory)( - m_hDevice, - hMemory, - 0, - VK_WHOLE_SIZE, - 0, - &pMappedData); - if(res < 0) - { - VMA_DEBUG_LOG(" vkMapMemory FAILED"); - FreeVulkanMemory(memTypeIndex, size, hMemory); - return res; - } - } +To query for current memory usage and available budget, use function vmaGetHeapBudgets(). +Returned structure #VmaBudget contains quantities expressed in bytes, per Vulkan memory heap. - *pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString); - (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size); - (*pAllocation)->SetUserData(this, pUserData); - m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size); - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) - { - FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); - } +Please note that this function returns different information and works faster than +vmaCalculateStatistics(). vmaGetHeapBudgets() can be called every frame or even before every +allocation, while vmaCalculateStatistics() is intended to be used rarely, +only to obtain statistical information, e.g. for debugging purposes. - return VK_SUCCESS; -} +It is recommended to use VK_EXT_memory_budget device extension to obtain information +about the budget from Vulkan device. VMA is able to use this extension automatically. +When not enabled, the allocator behaves same way, but then it estimates current usage +and available budget based on its internal information and Vulkan memory heap sizes, +which may be less precise. In order to use this extension: -void VmaAllocator_T::GetBufferMemoryRequirements( - VkBuffer hBuffer, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const -{ -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) - { - VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; - memReqInfo.buffer = hBuffer; +1. Make sure extensions VK_EXT_memory_budget and VK_KHR_get_physical_device_properties2 + required by it are available and enable them. Please note that the first is a device + extension and the second is instance extension! +2. Use flag #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT when creating #VmaAllocator object. +3. Make sure to call vmaSetCurrentFrameIndex() every frame. Budget is queried from + Vulkan inside of it to avoid overhead of querying it with every allocation. - VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; +\section staying_within_budget_controlling_memory_usage Controlling memory usage - VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; - VmaPnextChainPushFront(&memReq2, &memDedicatedReq); +There are many ways in which you can try to stay within the budget. - (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); +First, when making new allocation requires allocating a new memory block, the library +tries not to exceed the budget automatically. If a block with default recommended size +(e.g. 256 MB) would go over budget, a smaller block is allocated, possibly even +dedicated memory for just this resource. - memReq = memReq2.memoryRequirements; - requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } - else -#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - { - (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); - requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; - } -} +If the size of the requested resource plus current memory usage is more than the +budget, by default the library still tries to create it, leaving it to the Vulkan +implementation whether the allocation succeeds or fails. You can change this behavior +by using #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag. With it, the allocation is +not made if it would exceed the budget or if the budget is already exceeded. +VMA then tries to make the allocation from the next eligible Vulkan memory type. +The all of them fail, the call then fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +Example usage pattern may be to pass the #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag +when creating resources that are not essential for the application (e.g. the texture +of a specific object) and not to pass it when creating critically important resources +(e.g. render targets). -void VmaAllocator_T::GetImageMemoryRequirements( - VkImage hImage, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const -{ -#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) - { - VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; - memReqInfo.image = hImage; +On AMD graphics cards there is a custom vendor extension available: VK_AMD_memory_overallocation_behavior +that allows to control the behavior of the Vulkan implementation in out-of-memory cases - +whether it should fail with an error code or still allow the allocation. +Usage of this extension involves only passing extra structure on Vulkan device creation, +so it is out of scope of this library. - VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; +Finally, you can also use #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT flag to make sure +a new allocation is created only when it fits inside one of the existing memory blocks. +If it would require to allocate a new block, if fails instead with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +This also ensures that the function call is very fast because it never goes to Vulkan +to obtain a new block. - VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; - VmaPnextChainPushFront(&memReq2, &memDedicatedReq); +\note Creating \ref custom_memory_pools with VmaPoolCreateInfo::minBlockCount +set to more than 0 will currently try to allocate memory blocks without checking whether they +fit within budget. - (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); - memReq = memReq2.memoryRequirements; - requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } - else -#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - { - (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); - requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; - } -} +\page resource_aliasing Resource aliasing (overlap) -VkResult VmaAllocator_T::AllocateMemory( - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - VkBuffer dedicatedBuffer, - VkBufferUsageFlags dedicatedBufferUsage, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - size_t allocationCount, - VmaAllocation* pAllocations) -{ - memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); +New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory +management, give an opportunity to alias (overlap) multiple resources in the +same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL). +It can be useful to save video memory, but it must be used with caution. - VMA_ASSERT(VmaIsPow2(vkMemReq.alignment)); +For example, if you know the flow of your whole render frame in advance, you +are going to use some intermediate textures or buffers only during a small range of render passes, +and you know these ranges don't overlap in time, you can bind these resources to +the same place in memory, even if they have completely different parameters (width, height, format etc.). - if(vkMemReq.size == 0) - { - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && - (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(requiresDedicatedAllocation) - { - if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(createInfo.pool != VK_NULL_HANDLE) - { - VMA_ASSERT(0 && "Pool specified while dedicated allocation is required."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } - if((createInfo.pool != VK_NULL_HANDLE) && - ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0)) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } +![Resource aliasing (overlap)](../gfx/Aliasing.png) - if(createInfo.pool != VK_NULL_HANDLE) - { - const VkDeviceSize alignmentForPool = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(createInfo.pool->m_BlockVector.GetMemoryTypeIndex())); +Such scenario is possible using VMA, but you need to create your images manually. +Then you need to calculate parameters of an allocation to be made using formula: - VmaAllocationCreateInfo createInfoForPool = createInfo; - // If memory type is not HOST_VISIBLE, disable MAPPED. - if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && - (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) - { - createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; - } +- allocation size = max(size of each image) +- allocation alignment = max(alignment of each image) +- allocation memoryTypeBits = bitwise AND(memoryTypeBits of each image) - return createInfo.pool->m_BlockVector.Allocate( - m_CurrentFrameIndex.load(), - vkMemReq.size, - alignmentForPool, - createInfoForPool, - suballocType, - allocationCount, - pAllocations); - } - else - { - // Bit mask of memory Vulkan types acceptable for this allocation. - uint32_t memoryTypeBits = vkMemReq.memoryTypeBits; - uint32_t memTypeIndex = UINT32_MAX; - VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); - if(res == VK_SUCCESS) - { - VkDeviceSize alignmentForMemType = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(memTypeIndex)); +Following example shows two different images bound to the same place in memory, +allocated to fit largest of them. - res = AllocateMemoryOfType( - vkMemReq.size, - alignmentForMemType, - requiresDedicatedAllocation || prefersDedicatedAllocation, - dedicatedBuffer, - dedicatedBufferUsage, - dedicatedImage, - createInfo, - memTypeIndex, - suballocType, - allocationCount, - pAllocations); - // Succeeded on first try. - if(res == VK_SUCCESS) - { - return res; - } - // Allocation from this memory type failed. Try other compatible memory types. - else - { - for(;;) - { - // Remove old memTypeIndex from list of possibilities. - memoryTypeBits &= ~(1u << memTypeIndex); - // Find alternative memTypeIndex. - res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); - if(res == VK_SUCCESS) - { - alignmentForMemType = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(memTypeIndex)); - - res = AllocateMemoryOfType( - vkMemReq.size, - alignmentForMemType, - requiresDedicatedAllocation || prefersDedicatedAllocation, - dedicatedBuffer, - dedicatedBufferUsage, - dedicatedImage, - createInfo, - memTypeIndex, - suballocType, - allocationCount, - pAllocations); - // Allocation from this alternative memory type succeeded. - if(res == VK_SUCCESS) - { - return res; - } - // else: Allocation from this memory type failed. Try next one - next loop iteration. - } - // No other matching memory type index could be found. - else - { - // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } - } - } - // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. - else - return res; - } -} +\code +// A 512x512 texture to be sampled. +VkImageCreateInfo img1CreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +img1CreateInfo.imageType = VK_IMAGE_TYPE_2D; +img1CreateInfo.extent.width = 512; +img1CreateInfo.extent.height = 512; +img1CreateInfo.extent.depth = 1; +img1CreateInfo.mipLevels = 10; +img1CreateInfo.arrayLayers = 1; +img1CreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; +img1CreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +img1CreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +img1CreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; +img1CreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +// A full screen texture to be used as color attachment. +VkImageCreateInfo img2CreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +img2CreateInfo.imageType = VK_IMAGE_TYPE_2D; +img2CreateInfo.extent.width = 1920; +img2CreateInfo.extent.height = 1080; +img2CreateInfo.extent.depth = 1; +img2CreateInfo.mipLevels = 1; +img2CreateInfo.arrayLayers = 1; +img2CreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +img2CreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +img2CreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +img2CreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +img2CreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +VkImage img1; +res = vkCreateImage(device, &img1CreateInfo, nullptr, &img1); +VkImage img2; +res = vkCreateImage(device, &img2CreateInfo, nullptr, &img2); + +VkMemoryRequirements img1MemReq; +vkGetImageMemoryRequirements(device, img1, &img1MemReq); +VkMemoryRequirements img2MemReq; +vkGetImageMemoryRequirements(device, img2, &img2MemReq); + +VkMemoryRequirements finalMemReq = {}; +finalMemReq.size = std::max(img1MemReq.size, img2MemReq.size); +finalMemReq.alignment = std::max(img1MemReq.alignment, img2MemReq.alignment); +finalMemReq.memoryTypeBits = img1MemReq.memoryTypeBits & img2MemReq.memoryTypeBits; +// Validate if(finalMemReq.memoryTypeBits != 0) -void VmaAllocator_T::FreeMemory( - size_t allocationCount, - const VmaAllocation* pAllocations) -{ - VMA_ASSERT(pAllocations); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - for(size_t allocIndex = allocationCount; allocIndex--; ) - { - VmaAllocation allocation = pAllocations[allocIndex]; +VmaAllocation alloc; +res = vmaAllocateMemory(allocator, &finalMemReq, &allocCreateInfo, &alloc, nullptr); - if(allocation != VK_NULL_HANDLE) - { - if(TouchAllocation(allocation)) - { - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) - { - FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); - } +res = vmaBindImageMemory(allocator, alloc, img1); +res = vmaBindImageMemory(allocator, alloc, img2); - switch(allocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaBlockVector* pBlockVector = VMA_NULL; - VmaPool hPool = allocation->GetBlock()->GetParentPool(); - if(hPool != VK_NULL_HANDLE) - { - pBlockVector = &hPool->m_BlockVector; - } - else - { - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - pBlockVector = m_pBlockVectors[memTypeIndex]; - } - pBlockVector->Free(allocation); - } - break; - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - FreeDedicatedMemory(allocation); - break; - default: - VMA_ASSERT(0); - } - } +// You can use img1, img2 here, but not at the same time! + +vmaFreeMemory(allocator, alloc); +vkDestroyImage(allocator, img2, nullptr); +vkDestroyImage(allocator, img1, nullptr); +\endcode - // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes. - m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize()); - allocation->SetUserData(this, VMA_NULL); - m_AllocationObjectAllocator.Free(allocation); - } - } -} +Remember that using resources that alias in memory requires proper synchronization. +You need to issue a memory barrier to make sure commands that use `img1` and `img2` +don't overlap on GPU timeline. +You also need to treat a resource after aliasing as uninitialized - containing garbage data. +For example, if you use `img1` and then want to use `img2`, you need to issue +an image memory barrier for `img2` with `oldLayout` = `VK_IMAGE_LAYOUT_UNDEFINED`. + +Additional considerations: + +- Vulkan also allows to interpret contents of memory between aliasing resources consistently in some cases. +See chapter 11.8. "Memory Aliasing" of Vulkan specification or `VK_IMAGE_CREATE_ALIAS_BIT` flag. +- You can create more complex layout where different images and buffers are bound +at different offsets inside one large allocation. For example, one can imagine +a big texture used in some render passes, aliasing with a set of many small buffers +used between in some further passes. To bind a resource at non-zero offset in an allocation, +use vmaBindBufferMemory2() / vmaBindImageMemory2(). +- Before allocating memory for the resources you want to alias, check `memoryTypeBits` +returned in memory requirements of each resource to make sure the bits overlap. +Some GPUs may expose multiple memory types suitable e.g. only for buffers or +images with `COLOR_ATTACHMENT` usage, so the sets of memory types supported by your +resources may be disjoint. Aliasing them is not possible in that case. -VkResult VmaAllocator_T::ResizeAllocation( - const VmaAllocation alloc, - VkDeviceSize newSize) -{ - // This function is deprecated and so it does nothing. It's left for backward compatibility. - if(newSize == 0 || alloc->GetLastUseFrameIndex() == VMA_FRAME_INDEX_LOST) - { - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if(newSize == alloc->GetSize()) - { - return VK_SUCCESS; - } - return VK_ERROR_OUT_OF_POOL_MEMORY; -} -void VmaAllocator_T::CalculateStats(VmaStats* pStats) -{ - // Initialize. - InitStatInfo(pStats->total); - for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) - InitStatInfo(pStats->memoryType[i]); - for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) - InitStatInfo(pStats->memoryHeap[i]); - - // Process default pools. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(pBlockVector); - pBlockVector->AddStats(pStats); - } +\page custom_memory_pools Custom memory pools - // Process custom pools. - { - VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex) - { - m_Pools[poolIndex]->m_BlockVector.AddStats(pStats); - } - } +A memory pool contains a number of `VkDeviceMemory` blocks. +The library automatically creates and manages default pool for each memory type available on the device. +Default memory pool automatically grows in size. +Size of allocated blocks is also variable and managed automatically. - // Process dedicated allocations. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); - VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocVector); - for(size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex) - { - VmaStatInfo allocationStatInfo; - (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo); - VmaAddStatInfo(pStats->total, allocationStatInfo); - VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo); - VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo); - } - } +You can create custom pool and allocate memory out of it. +It can be useful if you want to: - // Postprocess. - VmaPostprocessCalcStatInfo(pStats->total); - for(size_t i = 0; i < GetMemoryTypeCount(); ++i) - VmaPostprocessCalcStatInfo(pStats->memoryType[i]); - for(size_t i = 0; i < GetMemoryHeapCount(); ++i) - VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]); -} +- Keep certain kind of allocations separate from others. +- Enforce particular, fixed size of Vulkan memory blocks. +- Limit maximum amount of Vulkan memory allocated for that pool. +- Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool. +- Use extra parameters for a set of your allocations that are available in #VmaPoolCreateInfo but not in + #VmaAllocationCreateInfo - e.g., custom minimum alignment, custom `pNext` chain. +- Perform defragmentation on a specific subset of your allocations. -void VmaAllocator_T::GetBudget(VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount) -{ -#if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) - { - if(m_Budget.m_OperationsSinceBudgetFetch < 30) - { - VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex); - for(uint32_t i = 0; i < heapCount; ++i, ++outBudget) - { - const uint32_t heapIndex = firstHeap + i; +To use custom memory pools: - outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex]; - outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; +-# Fill VmaPoolCreateInfo structure. +-# Call vmaCreatePool() to obtain #VmaPool handle. +-# When making an allocation, set VmaAllocationCreateInfo::pool to this handle. + You don't need to specify any other parameters of this structure, like `usage`. - if(m_Budget.m_VulkanUsage[heapIndex] + outBudget->blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) - { - outBudget->usage = m_Budget.m_VulkanUsage[heapIndex] + - outBudget->blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; - } - else - { - outBudget->usage = 0; - } +Example: - // Have to take MIN with heap size because explicit HeapSizeLimit is included in it. - outBudget->budget = VMA_MIN( - m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size); - } - } - else - { - UpdateVulkanBudget(); // Outside of mutex lock - GetBudget(outBudget, firstHeap, heapCount); // Recursion - } - } - else -#endif - { - for(uint32_t i = 0; i < heapCount; ++i, ++outBudget) - { - const uint32_t heapIndex = firstHeap + i; +\code +// Find memoryTypeIndex for the pool. +VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +sampleBufCreateInfo.size = 0x10000; // Doesn't matter. +sampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex]; - outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; +VmaAllocationCreateInfo sampleAllocCreateInfo = {}; +sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; - outBudget->usage = outBudget->blockBytes; - outBudget->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. - } - } -} +uint32_t memTypeIndex; +VkResult res = vmaFindMemoryTypeIndexForBufferInfo(allocator, + &sampleBufCreateInfo, &sampleAllocCreateInfo, &memTypeIndex); +// Check res... -static const uint32_t VMA_VENDOR_ID_AMD = 4098; +// Create a pool that can have at most 2 blocks, 128 MiB each. +VmaPoolCreateInfo poolCreateInfo = {}; +poolCreateInfo.memoryTypeIndex = memTypeIndex; +poolCreateInfo.blockSize = 128ull * 1024 * 1024; +poolCreateInfo.maxBlockCount = 2; -VkResult VmaAllocator_T::DefragmentationBegin( - const VmaDefragmentationInfo2& info, - VmaDefragmentationStats* pStats, - VmaDefragmentationContext* pContext) -{ - if(info.pAllocationsChanged != VMA_NULL) - { - memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32)); - } +VmaPool pool; +res = vmaCreatePool(allocator, &poolCreateInfo, &pool); +// Check res... - *pContext = vma_new(this, VmaDefragmentationContext_T)( - this, m_CurrentFrameIndex.load(), info.flags, pStats); +// Allocate a buffer out of it. +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 1024; +bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - (*pContext)->AddPools(info.poolCount, info.pPools); - (*pContext)->AddAllocations( - info.allocationCount, info.pAllocations, info.pAllocationsChanged); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.pool = pool; - VkResult res = (*pContext)->Defragment( - info.maxCpuBytesToMove, info.maxCpuAllocationsToMove, - info.maxGpuBytesToMove, info.maxGpuAllocationsToMove, - info.commandBuffer, pStats, info.flags); +VkBuffer buf; +VmaAllocation alloc; +res = vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr); +// Check res... +\endcode - if(res != VK_NOT_READY) - { - vma_delete(this, *pContext); - *pContext = VMA_NULL; - } +You have to free all allocations made from this pool before destroying it. - return res; -} +\code +vmaDestroyBuffer(allocator, buf, alloc); +vmaDestroyPool(allocator, pool); +\endcode -VkResult VmaAllocator_T::DefragmentationEnd( - VmaDefragmentationContext context) -{ - vma_delete(this, context); - return VK_SUCCESS; -} +New versions of this library support creating dedicated allocations in custom pools. +It is supported only when VmaPoolCreateInfo::blockSize = 0. +To use this feature, set VmaAllocationCreateInfo::pool to the pointer to your custom pool and +VmaAllocationCreateInfo::flags to #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. -VkResult VmaAllocator_T::DefragmentationPassBegin( - VmaDefragmentationPassInfo* pInfo, - VmaDefragmentationContext context) -{ - return context->DefragmentPassBegin(pInfo); -} -VkResult VmaAllocator_T::DefragmentationPassEnd( - VmaDefragmentationContext context) -{ - return context->DefragmentPassEnd(); - -} +\note Excessive use of custom pools is a common mistake when using this library. +Custom pools may be useful for special purposes - when you want to +keep certain type of resources separate e.g. to reserve minimum amount of memory +for them or limit maximum amount of memory they can occupy. For most +resources this is not needed and so it is not recommended to create #VmaPool +objects and allocations out of them. Allocating from the default pool is sufficient. -void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo) -{ - if(hAllocation->CanBecomeLost()) - { - /* - Warning: This is a carefully designed algorithm. - Do not modify unless you really know what you're doing :) - */ - const uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - pAllocationInfo->memoryType = UINT32_MAX; - pAllocationInfo->deviceMemory = VK_NULL_HANDLE; - pAllocationInfo->offset = 0; - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = VMA_NULL; - pAllocationInfo->pUserData = hAllocation->GetUserData(); - return; - } - else if(localLastUseFrameIndex == localCurrFrameIndex) - { - pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); - pAllocationInfo->deviceMemory = hAllocation->GetMemory(); - pAllocationInfo->offset = hAllocation->GetOffset(); - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = VMA_NULL; - pAllocationInfo->pUserData = hAllocation->GetUserData(); - return; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } - } - else - { -#if VMA_STATS_STRING_ENABLED - uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST); - if(localLastUseFrameIndex == localCurrFrameIndex) - { - break; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } -#endif - pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); - pAllocationInfo->deviceMemory = hAllocation->GetMemory(); - pAllocationInfo->offset = hAllocation->GetOffset(); - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = hAllocation->GetMappedData(); - pAllocationInfo->pUserData = hAllocation->GetUserData(); - } -} +\section custom_memory_pools_MemTypeIndex Choosing memory type index -bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation) -{ - // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo. - if(hAllocation->CanBecomeLost()) - { - uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - return false; - } - else if(localLastUseFrameIndex == localCurrFrameIndex) - { - return true; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } - } - else - { -#if VMA_STATS_STRING_ENABLED - uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST); - if(localLastUseFrameIndex == localCurrFrameIndex) - { - break; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } -#endif +When creating a pool, you must explicitly specify memory type index. +To find the one suitable for your buffers or images, you can use helper functions +vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo(). +You need to provide structures with example parameters of buffers or images +that you are going to create in that pool. - return true; - } -} +\code +VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +exampleBufCreateInfo.size = 1024; // Doesn't matter +exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; -VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool) -{ - VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; - VmaPoolCreateInfo newCreateInfo = *pCreateInfo; +uint32_t memTypeIndex; +vmaFindMemoryTypeIndexForBufferInfo(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); - if(newCreateInfo.maxBlockCount == 0) - { - newCreateInfo.maxBlockCount = SIZE_MAX; - } - if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) - { - return VK_ERROR_INITIALIZATION_FAILED; - } - // Memory type index out of range or forbidden. - if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || - ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) - { - return VK_ERROR_FEATURE_NOT_PRESENT; - } +VmaPoolCreateInfo poolCreateInfo = {}; +poolCreateInfo.memoryTypeIndex = memTypeIndex; +// ... +\endcode - const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex); +When creating buffers/images allocated in that pool, provide following parameters: - *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize); +- `VkBufferCreateInfo`: Prefer to pass same parameters as above. + Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. + Using different `VK_BUFFER_USAGE_` flags may work, but you shouldn't create images in a pool intended for buffers + or the other way around. +- VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. + Other members are ignored anyway. - VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); - if(res != VK_SUCCESS) - { - vma_delete(this, *pPool); - *pPool = VMA_NULL; - return res; - } +\section linear_algorithm Linear allocation algorithm - // Add to m_Pools. - { - VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); - (*pPool)->SetId(m_NextPoolId++); - VmaVectorInsertSorted(m_Pools, *pPool); - } +Each Vulkan memory block managed by this library has accompanying metadata that +keeps track of used and unused regions. By default, the metadata structure and +algorithm tries to find best place for new allocations among free regions to +optimize memory usage. This way you can allocate and free objects in any order. - return VK_SUCCESS; -} +![Default allocation algorithm](../gfx/Linear_allocator_1_algo_default.png) + +Sometimes there is a need to use simpler, linear allocation algorithm. You can +create custom pool that uses such algorithm by adding flag +#VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating +#VmaPool object. Then an alternative metadata management is used. It always +creates new allocations after last one and doesn't reuse free regions after +allocations freed in the middle. It results in better allocation performance and +less memory consumed by metadata. -void VmaAllocator_T::DestroyPool(VmaPool pool) -{ - // Remove from m_Pools. - { - VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); - bool success = VmaVectorRemoveSorted(m_Pools, pool); - VMA_ASSERT(success && "Pool not found in Allocator."); - } +![Linear allocation algorithm](../gfx/Linear_allocator_2_algo_linear.png) - vma_delete(this, pool); -} +With this one flag, you can create a custom pool that can be used in many ways: +free-at-once, stack, double stack, and ring buffer. See below for details. +You don't need to specify explicitly which of these options you are going to use - it is detected automatically. -void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats) -{ - pool->m_BlockVector.GetPoolStats(pPoolStats); -} +\subsection linear_algorithm_free_at_once Free-at-once -void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) -{ - m_CurrentFrameIndex.store(frameIndex); +In a pool that uses linear algorithm, you still need to free all the allocations +individually, e.g. by using vmaFreeMemory() or vmaDestroyBuffer(). You can free +them in any order. New allocations are always made after last one - free space +in the middle is not reused. However, when you release all the allocation and +the pool becomes empty, allocation starts from the beginning again. This way you +can use linear algorithm to speed up creation of allocations that you are going +to release all at once. -#if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) - { - UpdateVulkanBudget(); - } -#endif // #if VMA_MEMORY_BUDGET -} +![Free-at-once](../gfx/Linear_allocator_3_free_at_once.png) -void VmaAllocator_T::MakePoolAllocationsLost( - VmaPool hPool, - size_t* pLostAllocationCount) -{ - hPool->m_BlockVector.MakePoolAllocationsLost( - m_CurrentFrameIndex.load(), - pLostAllocationCount); -} +This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount +value that allows multiple memory blocks. -VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool) -{ - return hPool->m_BlockVector.CheckCorruption(); -} +\subsection linear_algorithm_stack Stack -VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) -{ - VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT; +When you free an allocation that was created last, its space can be reused. +Thanks to this, if you always release allocations in the order opposite to their +creation (LIFO - Last In First Out), you can achieve behavior of a stack. - // Process default pools. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - if(((1u << memTypeIndex) & memoryTypeBits) != 0) - { - VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(pBlockVector); - VkResult localRes = pBlockVector->CheckCorruption(); - switch(localRes) - { - case VK_ERROR_FEATURE_NOT_PRESENT: - break; - case VK_SUCCESS: - finalRes = VK_SUCCESS; - break; - default: - return localRes; - } - } - } +![Stack](../gfx/Linear_allocator_4_stack.png) - // Process custom pools. - { - VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex) - { - if(((1u << m_Pools[poolIndex]->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) - { - VkResult localRes = m_Pools[poolIndex]->m_BlockVector.CheckCorruption(); - switch(localRes) - { - case VK_ERROR_FEATURE_NOT_PRESENT: - break; - case VK_SUCCESS: - finalRes = VK_SUCCESS; - break; - default: - return localRes; - } - } - } - } +This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount +value that allows multiple memory blocks. - return finalRes; -} +\subsection linear_algorithm_double_stack Double stack -void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation) -{ - *pAllocation = m_AllocationObjectAllocator.Allocate(VMA_FRAME_INDEX_LOST, false); - (*pAllocation)->InitLost(); -} +The space reserved by a custom pool with linear algorithm may be used by two +stacks: -VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory) -{ - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); +- First, default one, growing up from offset 0. +- Second, "upper" one, growing down from the end towards lower offsets. - // HeapSizeLimit is in effect for this heap. - if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) - { - const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; - VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; - for(;;) - { - const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize; - if(blockBytesAfterAllocation > heapSize) - { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) - { - break; - } - } - } - else - { - m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize; - } +To make allocation from the upper stack, add flag #VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT +to VmaAllocationCreateInfo::flags. - // VULKAN CALL vkAllocateMemory. - VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); +![Double stack](../gfx/Linear_allocator_7_double_stack.png) - if(res == VK_SUCCESS) - { -#if VMA_MEMORY_BUDGET - ++m_Budget.m_OperationsSinceBudgetFetch; -#endif +Double stack is available only in pools with one memory block - +VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. - // Informative callback. - if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) - { - (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData); - } - } - else - { - m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize; - } +When the two stacks' ends meet so there is not enough space between them for a +new allocation, such allocation fails with usual +`VK_ERROR_OUT_OF_DEVICE_MEMORY` error. - return res; -} +\subsection linear_algorithm_ring_buffer Ring buffer -void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) -{ - // Informative callback. - if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) - { - (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData); - } +When you free some allocations from the beginning and there is not enough free space +for a new one at the end of a pool, allocator's "cursor" wraps around to the +beginning and starts allocation there. Thanks to this, if you always release +allocations in the same order as you created them (FIFO - First In First Out), +you can achieve behavior of a ring buffer / queue. - // VULKAN CALL vkFreeMemory. - (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks()); +![Ring buffer](../gfx/Linear_allocator_5_ring_buffer.png) - m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size; -} +Ring buffer is available only in pools with one memory block - +VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. -VkResult VmaAllocator_T::BindVulkanBuffer( - VkDeviceMemory memory, - VkDeviceSize memoryOffset, - VkBuffer buffer, - const void* pNext) -{ - if(pNext != VMA_NULL) - { -#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && - m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL) - { - VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR }; - bindBufferMemoryInfo.pNext = pNext; - bindBufferMemoryInfo.buffer = buffer; - bindBufferMemoryInfo.memory = memory; - bindBufferMemoryInfo.memoryOffset = memoryOffset; - return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); - } - else -#endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - } - else - { - return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset); - } -} +\note \ref defragmentation is not supported in custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT. -VkResult VmaAllocator_T::BindVulkanImage( - VkDeviceMemory memory, - VkDeviceSize memoryOffset, - VkImage image, - const void* pNext) -{ - if(pNext != VMA_NULL) - { -#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && - m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL) - { - VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR }; - bindBufferMemoryInfo.pNext = pNext; - bindBufferMemoryInfo.image = image; - bindBufferMemoryInfo.memory = memory; - bindBufferMemoryInfo.memoryOffset = memoryOffset; - return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); - } - else -#endif // #if VMA_BIND_MEMORY2 - { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - } - else - { - return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset); - } -} -VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) -{ - if(hAllocation->CanBecomeLost()) - { - return VK_ERROR_MEMORY_MAP_FAILED; - } +\page defragmentation Defragmentation - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - char *pBytes = VMA_NULL; - VkResult res = pBlock->Map(this, 1, (void**)&pBytes); - if(res == VK_SUCCESS) - { - *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); - hAllocation->BlockAllocMap(); - } - return res; - } - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - return hAllocation->DedicatedAllocMap(this, ppData); - default: - VMA_ASSERT(0); - return VK_ERROR_MEMORY_MAP_FAILED; - } -} +Interleaved allocations and deallocations of many objects of varying size can +cause fragmentation over time, which can lead to a situation where the library is unable +to find a continuous range of free memory for a new allocation despite there is +enough free space, just scattered across many small free ranges between existing +allocations. -void VmaAllocator_T::Unmap(VmaAllocation hAllocation) -{ - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - hAllocation->BlockAllocUnmap(); - pBlock->Unmap(this, 1); - } - break; - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - hAllocation->DedicatedAllocUnmap(this); - break; - default: - VMA_ASSERT(0); - } -} +To mitigate this problem, you can use defragmentation feature. +It doesn't happen automatically though and needs your cooperation, +because VMA is a low level library that only allocates memory. +It cannot recreate buffers and images in a new place as it doesn't remember the contents of `VkBufferCreateInfo` / `VkImageCreateInfo` structures. +It cannot copy their contents as it doesn't record any commands to a command buffer. -VkResult VmaAllocator_T::BindBufferMemory( - VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkBuffer hBuffer, - const void* pNext) +Example: + +\code +VmaDefragmentationInfo defragInfo = {}; +defragInfo.pool = myPool; +defragInfo.flags = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT; + +VmaDefragmentationContext defragCtx; +VkResult res = vmaBeginDefragmentation(allocator, &defragInfo, &defragCtx); +// Check res... + +for(;;) { - VkResult res = VK_SUCCESS; - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext); + VmaDefragmentationPassMoveInfo pass; + res = vmaBeginDefragmentationPass(allocator, defragCtx, &pass); + if(res == VK_SUCCESS) break; - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + else if(res != VK_INCOMPLETE) + // Handle error... + + for(uint32_t i = 0; i < pass.moveCount; ++i) { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?"); - res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext); - break; - } - default: - VMA_ASSERT(0); + // Inspect pass.pMoves[i].srcAllocation, identify what buffer/image it represents. + VmaAllocationInfo allocInfo; + vmaGetAllocationInfo(allocator, pass.pMoves[i].srcAllocation, &allocInfo); + MyEngineResourceData* resData = (MyEngineResourceData*)allocInfo.pUserData; + + // Recreate and bind this buffer/image at: pass.pMoves[i].dstMemory, pass.pMoves[i].dstOffset. + VkImageCreateInfo imgCreateInfo = ... + VkImage newImg; + res = vkCreateImage(device, &imgCreateInfo, nullptr, &newImg); + // Check res... + res = vmaBindImageMemory(allocator, pass.pMoves[i].dstTmpAllocation, newImg); + // Check res... + + // Issue a vkCmdCopyBuffer/vkCmdCopyImage to copy its content to the new place. + vkCmdCopyImage(cmdBuf, resData->img, ..., newImg, ...); } - return res; -} -VkResult VmaAllocator_T::BindImageMemory( - VmaAllocation hAllocation, - VkDeviceSize allocationLocalOffset, - VkImage hImage, - const void* pNext) -{ - VkResult res = VK_SUCCESS; - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext); - break; - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + // Make sure the copy commands finished executing. + vkWaitForFences(...); + + // Destroy old buffers/images bound with pass.pMoves[i].srcAllocation. + for(uint32_t i = 0; i < pass.moveCount; ++i) { - VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); - VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?"); - res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext); - break; - } - default: - VMA_ASSERT(0); + // ... + vkDestroyImage(device, resData->img, nullptr); } - return res; + + // Update appropriate descriptors to point to the new places... + + res = vmaEndDefragmentationPass(allocator, defragCtx, &pass); + if(res == VK_SUCCESS) + break; + else if(res != VK_INCOMPLETE) + // Handle error... } -void VmaAllocator_T::FlushOrInvalidateAllocation( - VmaAllocation hAllocation, - VkDeviceSize offset, VkDeviceSize size, - VMA_CACHE_OPERATION op) -{ - const uint32_t memTypeIndex = hAllocation->GetMemoryTypeIndex(); - if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) - { - const VkDeviceSize allocationSize = hAllocation->GetSize(); - VMA_ASSERT(offset <= allocationSize); +vmaEndDefragmentation(allocator, defragCtx, nullptr); +\endcode - const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; +Although functions like vmaCreateBuffer(), vmaCreateImage(), vmaDestroyBuffer(), vmaDestroyImage() +create/destroy an allocation and a buffer/image at once, these are just a shortcut for +creating the resource, allocating memory, and binding them together. +Defragmentation works on memory allocations only. You must handle the rest manually. +Defragmentation is an iterative process that should repreat "passes" as long as related functions +return `VK_INCOMPLETE` not `VK_SUCCESS`. +In each pass: + +1. vmaBeginDefragmentationPass() function call: + - Calculates and returns the list of allocations to be moved in this pass. + Note this can be a time-consuming process. + - Reserves destination memory for them by creating temporary destination allocations + that you can query for their `VkDeviceMemory` + offset using vmaGetAllocationInfo(). +2. Inside the pass, **you should**: + - Inspect the returned list of allocations to be moved. + - Create new buffers/images and bind them at the returned destination temporary allocations. + - Copy data from source to destination resources if necessary. + - Destroy the source buffers/images, but NOT their allocations. +3. vmaEndDefragmentationPass() function call: + - Frees the source memory reserved for the allocations that are moved. + - Modifies source #VmaAllocation objects that are moved to point to the destination reserved memory. + - Frees `VkDeviceMemory` blocks that became empty. + +Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter. +Defragmentation algorithm tries to move all suitable allocations. +You can, however, refuse to move some of them inside a defragmentation pass, by setting +`pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. +This is not recommended and may result in suboptimal packing of the allocations after defragmentation. +If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool. + +Inside a pass, for each allocation that should be moved: + +- You should copy its data from the source to the destination place by calling e.g. `vkCmdCopyBuffer()`, `vkCmdCopyImage()`. + - You need to make sure these commands finished executing before destroying the source buffers/images and before calling vmaEndDefragmentationPass(). +- If a resource doesn't contain any meaningful data, e.g. it is a transient color attachment image to be cleared, + filled, and used temporarily in each rendering frame, you can just recreate this image + without copying its data. +- If the resource is in `HOST_VISIBLE` and `HOST_CACHED` memory, you can copy its data on the CPU + using `memcpy()`. +- If you cannot move the allocation, you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. + This will cancel the move. + - vmaEndDefragmentationPass() will then free the destination memory + not the source memory of the allocation, leaving it unchanged. +- If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time), + you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. + - vmaEndDefragmentationPass() will then free both source and destination memory, and will destroy the source #VmaAllocation object. + +You can defragment a specific custom pool by setting VmaDefragmentationInfo::pool +(like in the example above) or all the default pools by setting this member to null. + +Defragmentation is always performed in each pool separately. +Allocations are never moved between different Vulkan memory types. +The size of the destination memory reserved for a moved allocation is the same as the original one. +Alignment of an allocation as it was determined using `vkGetBufferMemoryRequirements()` etc. is also respected after defragmentation. +Buffers/images should be recreated with the same `VkBufferCreateInfo` / `VkImageCreateInfo` parameters as the original ones. + +You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved +in each pass, e.g. to call it in sync with render frames and not to experience too big hitches. +See members: VmaDefragmentationInfo::maxBytesPerPass, VmaDefragmentationInfo::maxAllocationsPerPass. + +It is also safe to perform the defragmentation asynchronously to render frames and other Vulkan and VMA +usage, possibly from multiple threads, with the exception that allocations +returned in VmaDefragmentationPassMoveInfo::pMoves shouldn't be destroyed until the defragmentation pass is ended. + +Mapping is preserved on allocations that are moved during defragmentation. +Whether through #VMA_ALLOCATION_CREATE_MAPPED_BIT or vmaMapMemory(), the allocations +are mapped at their new place. Of course, pointer to the mapped data changes, so it needs to be queried +using VmaAllocationInfo::pMappedData. + +\note Defragmentation is not supported in custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT. - VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; - memRange.memory = hAllocation->GetMemory(); - - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - memRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if(size == VK_WHOLE_SIZE) - { - memRange.size = allocationSize - memRange.offset; - } - else - { - VMA_ASSERT(offset + size <= allocationSize); - memRange.size = VMA_MIN( - VmaAlignUp(size + (offset - memRange.offset), nonCoherentAtomSize), - allocationSize - memRange.offset); - } - break; - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - // 1. Still within this allocation. - memRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if(size == VK_WHOLE_SIZE) - { - size = allocationSize - offset; - } - else - { - VMA_ASSERT(offset + size <= allocationSize); - } - memRange.size = VmaAlignUp(size + (offset - memRange.offset), nonCoherentAtomSize); +\page statistics Statistics - // 2. Adjust to whole block. - const VkDeviceSize allocationOffset = hAllocation->GetOffset(); - VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0); - const VkDeviceSize blockSize = hAllocation->GetBlock()->m_pMetadata->GetSize(); - memRange.offset += allocationOffset; - memRange.size = VMA_MIN(memRange.size, blockSize - memRange.offset); - - break; - } - - default: - VMA_ASSERT(0); - } +This library contains several functions that return information about its internal state, +especially the amount of memory allocated from Vulkan. - switch(op) - { - case VMA_CACHE_FLUSH: - (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange); - break; - case VMA_CACHE_INVALIDATE: - (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange); - break; - default: - VMA_ASSERT(0); - } - } - // else: Just ignore this call. -} +\section statistics_numeric_statistics Numeric statistics -void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) -{ - VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); +If you need to obtain basic statistics about memory usage per heap, together with current budget, +you can call function vmaGetHeapBudgets() and inspect structure #VmaBudget. +This is useful to keep track of memory usage and stay within budget +(see also \ref staying_within_budget). +Example: - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - { - VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocations); - bool success = VmaVectorRemoveSorted(*pDedicatedAllocations, allocation); - VMA_ASSERT(success); - } +\code +uint32_t heapIndex = ... + +VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; +vmaGetHeapBudgets(allocator, budgets); + +printf("My heap currently has %u allocations taking %llu B,\n", + budgets[heapIndex].statistics.allocationCount, + budgets[heapIndex].statistics.allocationBytes); +printf("allocated out of %u Vulkan device memory blocks taking %llu B,\n", + budgets[heapIndex].statistics.blockCount, + budgets[heapIndex].statistics.blockBytes); +printf("Vulkan reports total usage %llu B with budget %llu B.\n", + budgets[heapIndex].usage, + budgets[heapIndex].budget); +\endcode - VkDeviceMemory hMemory = allocation->GetMemory(); - - /* - There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory - before vkFreeMemory. +You can query for more detailed statistics per memory heap, type, and totals, +including minimum and maximum allocation size and unused range size, +by calling function vmaCalculateStatistics() and inspecting structure #VmaTotalStatistics. +This function is slower though, as it has to traverse all the internal data structures, +so it should be used only for debugging purposes. - if(allocation->GetMappedData() != VMA_NULL) - { - (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); - } - */ - - FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory); +You can query for statistics of a custom pool using function vmaGetPoolStatistics() +or vmaCalculatePoolStatistics(). - VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex); -} +You can query for information about a specific allocation using function vmaGetAllocationInfo(). +It fill structure #VmaAllocationInfo. -uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const -{ - VkBufferCreateInfo dummyBufCreateInfo; - VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo); +\section statistics_json_dump JSON dump - uint32_t memoryTypeBits = 0; +You can dump internal state of the allocator to a string in JSON format using function vmaBuildStatsString(). +The result is guaranteed to be correct JSON. +It uses ANSI encoding. +Any strings provided by user (see [Allocation names](@ref allocation_names)) +are copied as-is and properly escaped for JSON, so if they use UTF-8, ISO-8859-2 or any other encoding, +this JSON string can be treated as using this encoding. +It must be freed using function vmaFreeStatsString(). - // Create buffer. - VkBuffer buf = VK_NULL_HANDLE; - VkResult res = (*GetVulkanFunctions().vkCreateBuffer)( - m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf); - if(res == VK_SUCCESS) - { - // Query for supported memory types. - VkMemoryRequirements memReq; - (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq); - memoryTypeBits = memReq.memoryTypeBits; +The format of this JSON string is not part of official documentation of the library, +but it will not change in backward-incompatible way without increasing library major version number +and appropriate mention in changelog. - // Destroy buffer. - (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks()); - } +The JSON string contains all the data that can be obtained using vmaCalculateStatistics(). +It can also contain detailed map of allocated memory blocks and their regions - +free and occupied by allocations. +This allows e.g. to visualize the memory or assess fragmentation. - return memoryTypeBits; -} -uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const -{ - // Make sure memory information is already fetched. - VMA_ASSERT(GetMemoryTypeCount() > 0); +\page allocation_annotation Allocation names and user data - uint32_t memoryTypeBits = UINT32_MAX; +\section allocation_user_data Allocation user data - if(!m_UseAmdDeviceCoherentMemory) - { - // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) - { - memoryTypeBits &= ~(1u << memTypeIndex); - } - } - } +You can annotate allocations with your own information, e.g. for debugging purposes. +To do that, fill VmaAllocationCreateInfo::pUserData field when creating +an allocation. It is an opaque `void*` pointer. You can use it e.g. as a pointer, +some handle, index, key, ordinal number or any other value that would associate +the allocation with your custom metadata. +It is useful to identify appropriate data structures in your engine given #VmaAllocation, +e.g. when doing \ref defragmentation. - return memoryTypeBits; -} +\code +VkBufferCreateInfo bufCreateInfo = ... -#if VMA_MEMORY_BUDGET +MyBufferMetadata* pMetadata = CreateBufferMetadata(); -void VmaAllocator_T::UpdateVulkanBudget() -{ - VMA_ASSERT(m_UseExtMemoryBudget); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.pUserData = pMetadata; - VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR }; +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buffer, &allocation, nullptr); +\endcode - VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT }; - VmaPnextChainPushFront(&memProps, &budgetProps); +The pointer may be later retrieved as VmaAllocationInfo::pUserData: - GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps); +\code +VmaAllocationInfo allocInfo; +vmaGetAllocationInfo(allocator, allocation, &allocInfo); +MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData; +\endcode - { - VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex); +It can also be changed using function vmaSetAllocationUserData(). - for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) - { - m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex]; - m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex]; - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load(); +Values of (non-zero) allocations' `pUserData` are printed in JSON report created by +vmaBuildStatsString() in hexadecimal form. - // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size. - if(m_Budget.m_VulkanBudget[heapIndex] == 0) - { - m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. - } - else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) - { - m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size; - } - if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) - { - m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; - } - } - m_Budget.m_OperationsSinceBudgetFetch = 0; - } -} +\section allocation_names Allocation names + +An allocation can also carry a null-terminated string, giving a name to the allocation. +To set it, call vmaSetAllocationName(). +The library creates internal copy of the string, so the pointer you pass doesn't need +to be valid for whole lifetime of the allocation. You can free it after the call. -#endif // #if VMA_MEMORY_BUDGET +\code +std::string imageName = "Texture: "; +imageName += fileName; +vmaSetAllocationName(allocator, allocation, imageName.c_str()); +\endcode -void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern) -{ - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS && - !hAllocation->CanBecomeLost() && - (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) - { - void* pData = VMA_NULL; - VkResult res = Map(hAllocation, &pData); - if(res == VK_SUCCESS) - { - memset(pData, (int)pattern, (size_t)hAllocation->GetSize()); - FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH); - Unmap(hAllocation); - } - else - { - VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation."); - } - } -} +The string can be later retrieved by inspecting VmaAllocationInfo::pName. +It is also printed in JSON report created by vmaBuildStatsString(). -uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits() -{ - uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load(); - if(memoryTypeBits == UINT32_MAX) - { - memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits(); - m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits); - } - return memoryTypeBits; -} +\note Setting string name to VMA allocation doesn't automatically set it to the Vulkan buffer or image created with it. +You must do it manually using an extension like VK_EXT_debug_utils, which is independent of this library. -#if VMA_STATS_STRING_ENABLED -void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) -{ - bool dedicatedAllocationsStarted = false; - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocVector); - if(pDedicatedAllocVector->empty() == false) - { - if(dedicatedAllocationsStarted == false) - { - dedicatedAllocationsStarted = true; - json.WriteString("DedicatedAllocations"); - json.BeginObject(); - } +\page virtual_allocator Virtual allocator - json.BeginString("Type "); - json.ContinueString(memTypeIndex); - json.EndString(); - - json.BeginArray(); +As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator". +It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block". +You can use it to allocate your own memory or other objects, even completely unrelated to Vulkan. +A common use case is sub-allocation of pieces of one large GPU buffer. - for(size_t i = 0; i < pDedicatedAllocVector->size(); ++i) - { - json.BeginObject(true); - const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i]; - hAlloc->PrintParameters(json); - json.EndObject(); - } +\section virtual_allocator_creating_virtual_block Creating virtual block - json.EndArray(); - } - } - if(dedicatedAllocationsStarted) - { - json.EndObject(); - } +To use this functionality, there is no main "allocator" object. +You don't need to have #VmaAllocator object created. +All you need to do is to create a separate #VmaVirtualBlock object for each block of memory you want to be managed by the allocator: - { - bool allocationsStarted = false; - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false) - { - if(allocationsStarted == false) - { - allocationsStarted = true; - json.WriteString("DefaultPools"); - json.BeginObject(); - } +-# Fill in #VmaVirtualBlockCreateInfo structure. +-# Call vmaCreateVirtualBlock(). Get new #VmaVirtualBlock object. - json.BeginString("Type "); - json.ContinueString(memTypeIndex); - json.EndString(); +Example: - m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json); - } - } - if(allocationsStarted) - { - json.EndObject(); - } - } +\code +VmaVirtualBlockCreateInfo blockCreateInfo = {}; +blockCreateInfo.size = 1048576; // 1 MB - // Custom pools - { - VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - const size_t poolCount = m_Pools.size(); - if(poolCount > 0) - { - json.WriteString("Pools"); - json.BeginObject(); - for(size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex) - { - json.BeginString(); - json.ContinueString(m_Pools[poolIndex]->GetId()); - json.EndString(); +VmaVirtualBlock block; +VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &block); +\endcode - m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json); - } - json.EndObject(); - } - } -} +\section virtual_allocator_making_virtual_allocations Making virtual allocations -#endif // #if VMA_STATS_STRING_ENABLED +#VmaVirtualBlock object contains internal data structure that keeps track of free and occupied regions +using the same code as the main Vulkan memory allocator. +Similarly to #VmaAllocation for standard GPU allocations, there is #VmaVirtualAllocation type +that represents an opaque handle to an allocation within the virtual block. -//////////////////////////////////////////////////////////////////////////////// -// Public interface +In order to make such allocation: -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( - const VmaAllocatorCreateInfo* pCreateInfo, - VmaAllocator* pAllocator) -{ - VMA_ASSERT(pCreateInfo && pAllocator); - VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 || - (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 2)); - VMA_DEBUG_LOG("vmaCreateAllocator"); - *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); - return (*pAllocator)->Init(pCreateInfo); -} +-# Fill in #VmaVirtualAllocationCreateInfo structure. +-# Call vmaVirtualAllocate(). Get new #VmaVirtualAllocation object that represents the allocation. + You can also receive `VkDeviceSize offset` that was assigned to the allocation. -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( - VmaAllocator allocator) -{ - if(allocator != VK_NULL_HANDLE) - { - VMA_DEBUG_LOG("vmaDestroyAllocator"); - VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; - vma_delete(&allocationCallbacks, allocator); - } -} +Example: -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo) -{ - VMA_ASSERT(allocator && pAllocatorInfo); - pAllocatorInfo->instance = allocator->m_hInstance; - pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice(); - pAllocatorInfo->device = allocator->m_hDevice; -} +\code +VmaVirtualAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.size = 4096; // 4 KB -VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( - VmaAllocator allocator, - const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) +VmaVirtualAllocation alloc; +VkDeviceSize offset; +res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc, &offset); +if(res == VK_SUCCESS) { - VMA_ASSERT(allocator && ppPhysicalDeviceProperties); - *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; + // Use the 4 KB of your memory starting at offset. } - -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( - VmaAllocator allocator, - const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties) +else { - VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties); - *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps; + // Allocation failed - no space for it could be found. Handle this error! } +\endcode -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( - VmaAllocator allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* pFlags) -{ - VMA_ASSERT(allocator && pFlags); - VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount()); - *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags; -} +\section virtual_allocator_deallocation Deallocation -VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( - VmaAllocator allocator, - uint32_t frameIndex) -{ - VMA_ASSERT(allocator); - VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST); +When no longer needed, an allocation can be freed by calling vmaVirtualFree(). +You can only pass to this function an allocation that was previously returned by vmaVirtualAllocate() +called for the same #VmaVirtualBlock. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +When whole block is no longer needed, the block object can be released by calling vmaDestroyVirtualBlock(). +All allocations must be freed before the block is destroyed, which is checked internally by an assert. +However, if you don't want to call vmaVirtualFree() for each allocation, you can use vmaClearVirtualBlock() to free them all at once - +a feature not available in normal Vulkan memory allocator. Example: - allocator->SetCurrentFrameIndex(frameIndex); -} +\code +vmaVirtualFree(block, alloc); +vmaDestroyVirtualBlock(block); +\endcode -VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats( - VmaAllocator allocator, - VmaStats* pStats) -{ - VMA_ASSERT(allocator && pStats); - VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculateStats(pStats); -} +\section virtual_allocator_allocation_parameters Allocation parameters -VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget( - VmaAllocator allocator, - VmaBudget* pBudget) +You can attach a custom pointer to each allocation by using vmaSetVirtualAllocationUserData(). +Its default value is null. +It can be used to store any data that needs to be associated with that allocation - e.g. an index, a handle, or a pointer to some +larger data structure containing more information. Example: + +\code +struct CustomAllocData { - VMA_ASSERT(allocator && pBudget); - VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetBudget(pBudget, 0, allocator->GetMemoryHeapCount()); -} + std::string m_AllocName; +}; +CustomAllocData* allocData = new CustomAllocData(); +allocData->m_AllocName = "My allocation 1"; +vmaSetVirtualAllocationUserData(block, alloc, allocData); +\endcode -#if VMA_STATS_STRING_ENABLED +The pointer can later be fetched, along with allocation offset and size, by passing the allocation handle to function +vmaGetVirtualAllocationInfo() and inspecting returned structure #VmaVirtualAllocationInfo. +If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation! +Example: -VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( - VmaAllocator allocator, - char** ppStatsString, - VkBool32 detailedMap) -{ - VMA_ASSERT(allocator && ppStatsString); - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\code +VmaVirtualAllocationInfo allocInfo; +vmaGetVirtualAllocationInfo(block, alloc, &allocInfo); +delete (CustomAllocData*)allocInfo.pUserData; - VmaStringBuilder sb(allocator); - { - VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb); - json.BeginObject(); +vmaVirtualFree(block, alloc); +\endcode - VmaBudget budget[VK_MAX_MEMORY_HEAPS]; - allocator->GetBudget(budget, 0, allocator->GetMemoryHeapCount()); +\section virtual_allocator_alignment_and_units Alignment and units - VmaStats stats; - allocator->CalculateStats(&stats); +It feels natural to express sizes and offsets in bytes. +If an offset of an allocation needs to be aligned to a multiply of some number (e.g. 4 bytes), you can fill optional member +VmaVirtualAllocationCreateInfo::alignment to request it. Example: - json.WriteString("Total"); - VmaPrintStatInfo(json, stats.total); - - for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex) - { - json.BeginString("Heap "); - json.ContinueString(heapIndex); - json.EndString(); - json.BeginObject(); +\code +VmaVirtualAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.size = 4096; // 4 KB +allocCreateInfo.alignment = 4; // Returned offset must be a multiply of 4 B - json.WriteString("Size"); - json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size); +VmaVirtualAllocation alloc; +res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc, nullptr); +\endcode - json.WriteString("Flags"); - json.BeginArray(true); - if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) - { - json.WriteString("DEVICE_LOCAL"); - } - json.EndArray(); +Alignments of different allocations made from one block may vary. +However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`, +you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes. +It might be more convenient, but you need to make sure to use this new unit consistently in all the places: - json.WriteString("Budget"); - json.BeginObject(); - { - json.WriteString("BlockBytes"); - json.WriteNumber(budget[heapIndex].blockBytes); - json.WriteString("AllocationBytes"); - json.WriteNumber(budget[heapIndex].allocationBytes); - json.WriteString("Usage"); - json.WriteNumber(budget[heapIndex].usage); - json.WriteString("Budget"); - json.WriteNumber(budget[heapIndex].budget); - } - json.EndObject(); +- VmaVirtualBlockCreateInfo::size +- VmaVirtualAllocationCreateInfo::size and VmaVirtualAllocationCreateInfo::alignment +- Using offset returned by vmaVirtualAllocate() or in VmaVirtualAllocationInfo::offset - if(stats.memoryHeap[heapIndex].blockCount > 0) - { - json.WriteString("Stats"); - VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]); - } +\section virtual_allocator_statistics Statistics - for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex) - { - if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex) - { - json.BeginString("Type "); - json.ContinueString(typeIndex); - json.EndString(); +You can obtain statistics of a virtual block using vmaGetVirtualBlockStatistics() +(to get brief statistics that are fast to calculate) +or vmaCalculateVirtualBlockStatistics() (to get more detailed statistics, slower to calculate). +The functions fill structures #VmaStatistics, #VmaDetailedStatistics respectively - same as used by the normal Vulkan memory allocator. +Example: - json.BeginObject(); +\code +VmaStatistics stats; +vmaGetVirtualBlockStatistics(block, &stats); +printf("My virtual block has %llu bytes used by %u virtual allocations\n", + stats.allocationBytes, stats.allocationCount); +\endcode - json.WriteString("Flags"); - json.BeginArray(true); - VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags; - if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) - { - json.WriteString("DEVICE_LOCAL"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) - { - json.WriteString("HOST_VISIBLE"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0) - { - json.WriteString("HOST_COHERENT"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) - { - json.WriteString("HOST_CACHED"); - } - if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0) - { - json.WriteString("LAZILY_ALLOCATED"); - } - if((flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0) - { - json.WriteString(" PROTECTED"); - } - if((flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) - { - json.WriteString(" DEVICE_COHERENT"); - } - if((flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) != 0) - { - json.WriteString(" DEVICE_UNCACHED"); - } - json.EndArray(); +You can also request a full list of allocations and free regions as a string in JSON format by calling +vmaBuildVirtualBlockStatsString(). +Returned string must be later freed using vmaFreeVirtualBlockStatsString(). +The format of this string differs from the one returned by the main Vulkan allocator, but it is similar. - if(stats.memoryType[typeIndex].blockCount > 0) - { - json.WriteString("Stats"); - VmaPrintStatInfo(json, stats.memoryType[typeIndex]); - } +\section virtual_allocator_additional_considerations Additional considerations - json.EndObject(); - } - } +The "virtual allocator" functionality is implemented on a level of individual memory blocks. +Keeping track of a whole collection of blocks, allocating new ones when out of free space, +deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user. - json.EndObject(); - } - if(detailedMap == VK_TRUE) - { - allocator->PrintDetailedMap(json); - } +Alternative allocation algorithms are supported, just like in custom pools of the real GPU memory. +See enum #VmaVirtualBlockCreateFlagBits to learn how to specify them (e.g. #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT). +You can find their description in chapter \ref custom_memory_pools. +Allocation strategies are also supported. +See enum #VmaVirtualAllocationCreateFlagBits to learn how to specify them (e.g. #VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT). - json.EndObject(); - } +Following features are supported only by the allocator of the real GPU memory and not by virtual allocations: +buffer-image granularity, `VMA_DEBUG_MARGIN`, `VMA_MIN_ALIGNMENT`. - const size_t len = sb.GetLength(); - char* const pChars = vma_new_array(allocator, char, len + 1); - if(len > 0) - { - memcpy(pChars, sb.GetData(), len); - } - pChars[len] = '\0'; - *ppStatsString = pChars; -} -VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( - VmaAllocator allocator, - char* pStatsString) -{ - if(pStatsString != VMA_NULL) - { - VMA_ASSERT(allocator); - size_t len = strlen(pStatsString); - vma_delete_array(allocator, pStatsString, len + 1); - } -} +\page debugging_memory_usage Debugging incorrect memory usage -#endif // #if VMA_STATS_STRING_ENABLED +If you suspect a bug with memory usage, like usage of uninitialized memory or +memory being overwritten out of bounds of an allocation, +you can use debug features of this library to verify this. -/* -This function is not protected by any mutex because it just reads immutable data. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( - VmaAllocator allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); +\section debugging_memory_usage_initialization Memory initialization + +If you experience a bug with incorrect and nondeterministic data in your program and you suspect uninitialized memory to be used, +you can enable automatic memory initialization to verify this. +To do it, define macro `VMA_DEBUG_INITIALIZE_ALLOCATIONS` to 1. + +\code +#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1 +#include "vk_mem_alloc.h" +\endcode - memoryTypeBits &= allocator->GetGlobalMemoryTypeBits(); +It makes memory of new allocations initialized to bit pattern `0xDCDCDCDC`. +Before an allocation is destroyed, its memory is filled with bit pattern `0xEFEFEFEF`. +Memory is automatically mapped and unmapped if necessary. - if(pAllocationCreateInfo->memoryTypeBits != 0) - { - memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; - } - - uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags; - uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags; - uint32_t notPreferredFlags = 0; +If you find these values while debugging your program, good chances are that you incorrectly +read Vulkan memory that is allocated but not initialized, or already freed, respectively. - // Convert usage to requiredFlags and preferredFlags. - switch(pAllocationCreateInfo->usage) - { - case VMA_MEMORY_USAGE_UNKNOWN: - break; - case VMA_MEMORY_USAGE_GPU_ONLY: - if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) - { - preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } - break; - case VMA_MEMORY_USAGE_CPU_ONLY: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; - case VMA_MEMORY_USAGE_CPU_TO_GPU: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) - { - preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } - break; - case VMA_MEMORY_USAGE_GPU_TO_CPU: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - break; - case VMA_MEMORY_USAGE_CPU_COPY: - notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - break; - case VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED: - requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - break; - default: - VMA_ASSERT(0); - break; - } +Memory initialization works only with memory types that are `HOST_VISIBLE` and with allocations that can be mapped. +It works also with dedicated allocations. - // Avoid DEVICE_COHERENT unless explicitly requested. - if(((pAllocationCreateInfo->requiredFlags | pAllocationCreateInfo->preferredFlags) & - (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0) - { - notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY; - } +\section debugging_memory_usage_margins Margins - *pMemoryTypeIndex = UINT32_MAX; - uint32_t minCost = UINT32_MAX; - for(uint32_t memTypeIndex = 0, memTypeBit = 1; - memTypeIndex < allocator->GetMemoryTypeCount(); - ++memTypeIndex, memTypeBit <<= 1) - { - // This memory type is acceptable according to memoryTypeBits bitmask. - if((memTypeBit & memoryTypeBits) != 0) - { - const VkMemoryPropertyFlags currFlags = - allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags; - // This memory type contains requiredFlags. - if((requiredFlags & ~currFlags) == 0) - { - // Calculate cost as number of bits from preferredFlags not present in this memory type. - uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) + - VmaCountBitsSet(currFlags & notPreferredFlags); - // Remember memory type with lowest cost. - if(currCost < minCost) - { - *pMemoryTypeIndex = memTypeIndex; - if(currCost == 0) - { - return VK_SUCCESS; - } - minCost = currCost; - } - } - } - } - return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT; -} +By default, allocations are laid out in memory blocks next to each other if possible +(considering required alignment, `bufferImageGranularity`, and `nonCoherentAtomSize`). -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pBufferCreateInfo != VMA_NULL); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); +![Allocations without margin](../gfx/Margins_1.png) - const VkDevice hDev = allocator->m_hDevice; - VkBuffer hBuffer = VK_NULL_HANDLE; - VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer( - hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); - if(res == VK_SUCCESS) - { - VkMemoryRequirements memReq = {}; - allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements( - hDev, hBuffer, &memReq); +Define macro `VMA_DEBUG_MARGIN` to some non-zero value (e.g. 16) to enforce specified +number of bytes as a margin after every allocation. - res = vmaFindMemoryTypeIndex( - allocator, - memReq.memoryTypeBits, - pAllocationCreateInfo, - pMemoryTypeIndex); +\code +#define VMA_DEBUG_MARGIN 16 +#include "vk_mem_alloc.h" +\endcode - allocator->GetVulkanFunctions().vkDestroyBuffer( - hDev, hBuffer, allocator->GetAllocationCallbacks()); - } - return res; -} +![Allocations with margin](../gfx/Margins_2.png) -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pImageCreateInfo != VMA_NULL); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); +If your bug goes away after enabling margins, it means it may be caused by memory +being overwritten outside of allocation boundaries. It is not 100% certain though. +Change in application behavior may also be caused by different order and distribution +of allocations across memory blocks after margins are applied. - const VkDevice hDev = allocator->m_hDevice; - VkImage hImage = VK_NULL_HANDLE; - VkResult res = allocator->GetVulkanFunctions().vkCreateImage( - hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); - if(res == VK_SUCCESS) - { - VkMemoryRequirements memReq = {}; - allocator->GetVulkanFunctions().vkGetImageMemoryRequirements( - hDev, hImage, &memReq); +Margins work with all types of memory. - res = vmaFindMemoryTypeIndex( - allocator, - memReq.memoryTypeBits, - pAllocationCreateInfo, - pMemoryTypeIndex); +Margin is applied only to allocations made out of memory blocks and not to dedicated +allocations, which have their own memory block of specific size. +It is thus not applied to allocations made using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT flag +or those automatically decided to put into dedicated allocations, e.g. due to its +large size or recommended by VK_KHR_dedicated_allocation extension. - allocator->GetVulkanFunctions().vkDestroyImage( - hDev, hImage, allocator->GetAllocationCallbacks()); - } - return res; -} +Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( - VmaAllocator allocator, - const VmaPoolCreateInfo* pCreateInfo, - VmaPool* pPool) -{ - VMA_ASSERT(allocator && pCreateInfo && pPool); - - VMA_DEBUG_LOG("vmaCreatePool"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - VkResult res = allocator->CreatePool(pCreateInfo, pPool); - -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordCreatePool(allocator->GetCurrentFrameIndex(), *pCreateInfo, *pPool); - } -#endif - - return res; -} +Note that enabling margins increases memory usage and fragmentation. -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( - VmaAllocator allocator, - VmaPool pool) -{ - VMA_ASSERT(allocator); - - if(pool == VK_NULL_HANDLE) - { - return; - } - - VMA_DEBUG_LOG("vmaDestroyPool"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordDestroyPool(allocator->GetCurrentFrameIndex(), pool); - } -#endif +Margins do not apply to \ref virtual_allocator. - allocator->DestroyPool(pool); -} +\section debugging_memory_usage_corruption_detection Corruption detection -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats( - VmaAllocator allocator, - VmaPool pool, - VmaPoolStats* pPoolStats) -{ - VMA_ASSERT(allocator && pool && pPoolStats); +You can additionally define macro `VMA_DEBUG_DETECT_CORRUPTION` to 1 to enable validation +of contents of the margins. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\code +#define VMA_DEBUG_MARGIN 16 +#define VMA_DEBUG_DETECT_CORRUPTION 1 +#include "vk_mem_alloc.h" +\endcode - allocator->GetPoolStats(pool, pPoolStats); -} +When this feature is enabled, number of bytes specified as `VMA_DEBUG_MARGIN` +(it must be multiply of 4) after every allocation is filled with a magic number. +This idea is also know as "canary". +Memory is automatically mapped and unmapped if necessary. -VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost( - VmaAllocator allocator, - VmaPool pool, - size_t* pLostAllocationCount) -{ - VMA_ASSERT(allocator && pool); +This number is validated automatically when the allocation is destroyed. +If it is not equal to the expected value, `VMA_ASSERT()` is executed. +It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation, +which indicates a serious bug. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +You can also explicitly request checking margins of all allocations in all memory blocks +that belong to specified memory types by using function vmaCheckCorruption(), +or in memory blocks that belong to specified custom pool, by using function +vmaCheckPoolCorruption(). -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordMakePoolAllocationsLost(allocator->GetCurrentFrameIndex(), pool); - } -#endif +Margin validation (corruption detection) works only for memory types that are +`HOST_VISIBLE` and `HOST_COHERENT`. - allocator->MakePoolAllocationsLost(pool, pLostAllocationCount); -} -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool) -{ - VMA_ASSERT(allocator && pool); +\page opengl_interop OpenGL Interop - VMA_DEBUG_GLOBAL_MUTEX_LOCK +VMA provides some features that help with interoperability with OpenGL. - VMA_DEBUG_LOG("vmaCheckPoolCorruption"); +\section opengl_interop_exporting_memory Exporting memory - return allocator->CheckPoolCorruption(pool); -} +If you want to attach `VkExportMemoryAllocateInfoKHR` structure to `pNext` chain of memory allocations made by the library: -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( - VmaAllocator allocator, - VmaPool pool, - const char** ppName) -{ - VMA_ASSERT(allocator && pool); - - VMA_DEBUG_LOG("vmaGetPoolName"); +It is recommended to create \ref custom_memory_pools for such allocations. +Define and fill in your `VkExportMemoryAllocateInfoKHR` structure and attach it to VmaPoolCreateInfo::pMemoryAllocateNext +while creating the custom pool. +Please note that the structure must remain alive and unchanged for the whole lifetime of the #VmaPool, +not only while creating it, as no copy of the structure is made, +but its original pointer is used for each allocation instead. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +If you want to export all memory allocated by the library from certain memory types, +also dedicated allocations or other allocations made from default pools, +an alternative solution is to fill in VmaAllocatorCreateInfo::pTypeExternalMemoryHandleTypes. +It should point to an array with `VkExternalMemoryHandleTypeFlagsKHR` to be automatically passed by the library +through `VkExportMemoryAllocateInfoKHR` on each allocation made from a specific memory type. +Please note that new versions of the library also support dedicated allocations created in custom pools. - *ppName = pool->GetName(); -} +You should not mix these two methods in a way that allows to apply both to the same memory type. +Otherwise, `VkExportMemoryAllocateInfoKHR` structure would be attached twice to the `pNext` chain of `VkMemoryAllocateInfo`. -VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( - VmaAllocator allocator, - VmaPool pool, - const char* pName) -{ - VMA_ASSERT(allocator && pool); - VMA_DEBUG_LOG("vmaSetPoolName"); +\section opengl_interop_custom_alignment Custom alignment - VMA_DEBUG_GLOBAL_MUTEX_LOCK +Buffers or images exported to a different API like OpenGL may require a different alignment, +higher than the one used by the library automatically, queried from functions like `vkGetBufferMemoryRequirements`. +To impose such alignment: - pool->SetName(pName); +It is recommended to create \ref custom_memory_pools for such allocations. +Set VmaPoolCreateInfo::minAllocationAlignment member to the minimum alignment required for each allocation +to be made out of this pool. +The alignment actually used will be the maximum of this member and the alignment returned for the specific buffer or image +from a function like `vkGetBufferMemoryRequirements`, which is called by VMA automatically. -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordSetPoolName(allocator->GetCurrentFrameIndex(), pool, pName); - } -#endif -} +If you want to create a buffer with a specific minimum alignment out of default pools, +use special function vmaCreateBufferWithAlignment(), which takes additional parameter `minAlignment`. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation); +Note the problem of alignment affects only resources placed inside bigger `VkDeviceMemory` blocks and not dedicated +allocations, as these, by definition, always have alignment = 0 because the resource is bound to the beginning of its dedicated block. +Contrary to Direct3D 12, Vulkan doesn't have a concept of alignment of the entire memory block passed on its allocation. - VMA_DEBUG_LOG("vmaAllocateMemory"); - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\page usage_patterns Recommended usage patterns - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - UINT32_MAX, // dedicatedBufferUsage - VK_NULL_HANDLE, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - 1, // allocationCount - pAllocation); +Vulkan gives great flexibility in memory allocation. +This chapter shows the most common patterns. -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordAllocateMemory( - allocator->GetCurrentFrameIndex(), - *pVkMemoryRequirements, - *pCreateInfo, - *pAllocation); - } -#endif - - if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } +See also slides from talk: +[Sawicki, Adam. Advanced Graphics Techniques Tutorial: Memory management in Vulkan and DX12. Game Developers Conference, 2018](https://www.gdcvault.com/play/1025458/Advanced-Graphics-Techniques-Tutorial-New) - return result; -} -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - size_t allocationCount, - VmaAllocation* pAllocations, - VmaAllocationInfo* pAllocationInfo) -{ - if(allocationCount == 0) - { - return VK_SUCCESS; - } +\section usage_patterns_gpu_only GPU-only resource + +When: +Any resources that you frequently write and read on GPU, +e.g. images used as color attachments (aka "render targets"), depth-stencil attachments, +images/buffers used as storage image/buffer (aka "Unordered Access View (UAV)"). - VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations); +What to do: +Let the library select the optimal memory type, which will likely have `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - VMA_DEBUG_LOG("vmaAllocateMemoryPages"); +\code +VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; +imgCreateInfo.extent.width = 3840; +imgCreateInfo.extent.height = 2160; +imgCreateInfo.extent.depth = 1; +imgCreateInfo.mipLevels = 1; +imgCreateInfo.arrayLayers = 1; +imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - VMA_DEBUG_GLOBAL_MUTEX_LOCK +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; +allocCreateInfo.priority = 1.0f; - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - UINT32_MAX, // dedicatedBufferUsage - VK_NULL_HANDLE, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - allocationCount, - pAllocations); +VkImage img; +VmaAllocation alloc; +vmaCreateImage(allocator, &imgCreateInfo, &allocCreateInfo, &img, &alloc, nullptr); +\endcode -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordAllocateMemoryPages( - allocator->GetCurrentFrameIndex(), - *pVkMemoryRequirements, - *pCreateInfo, - (uint64_t)allocationCount, - pAllocations); - } -#endif - - if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) - { - for(size_t i = 0; i < allocationCount; ++i) - { - allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i); - } - } +Also consider: +Consider creating them as dedicated allocations using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, +especially if they are large or if you plan to destroy and recreate them with different sizes +e.g. when display resolution changes. +Prefer to create such resources first and all other GPU resources (like textures and vertex buffers) later. +When VK_EXT_memory_priority extension is enabled, it is also worth setting high priority to such allocation +to decrease chances to be evicted to system memory by the operating system. - return result; -} +\section usage_patterns_staging_copy_upload Staging copy for upload -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( - VmaAllocator allocator, - VkBuffer buffer, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation); +When: +A "staging" buffer than you want to map and fill from CPU code, then use as a source of transfer +to some GPU resource. - VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer"); +What to do: +Use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT. +Let the library select the optimal memory type, which will always have `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetBufferMemoryRequirements(buffer, vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; - VkResult result = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - buffer, // dedicatedBuffer - UINT32_MAX, // dedicatedBufferUsage - VK_NULL_HANDLE, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_BUFFER, - 1, // allocationCount - pAllocation); +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordAllocateMemoryForBuffer( - allocator->GetCurrentFrameIndex(), - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - *pCreateInfo, - *pAllocation); - } -#endif +... - if(pAllocationInfo && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } +memcpy(allocInfo.pMappedData, myData, myDataSize); +\endcode - return result; -} +Also consider: +You can map the allocation using vmaMapMemory() or you can create it as persistenly mapped +using #VMA_ALLOCATION_CREATE_MAPPED_BIT, as in the example above. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( - VmaAllocator allocator, - VkImage image, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation); - VMA_DEBUG_LOG("vmaAllocateMemoryForImage"); +\section usage_patterns_readback Readback - VMA_DEBUG_GLOBAL_MUTEX_LOCK +When: +Buffers for data written by or transferred from the GPU that you want to read back on the CPU, +e.g. results of some computations. - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetImageMemoryRequirements(image, vkMemReq, - requiresDedicatedAllocation, prefersDedicatedAllocation); +What to do: +Use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Let the library select the optimal memory type, which will always have `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. - VkResult result = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - VK_NULL_HANDLE, // dedicatedBuffer - UINT32_MAX, // dedicatedBufferUsage - image, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN, - 1, // allocationCount - pAllocation); +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordAllocateMemoryForImage( - allocator->GetCurrentFrameIndex(), - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - *pCreateInfo, - *pAllocation); - } -#endif +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; - if(pAllocationInfo && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - return result; -} +... -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( - VmaAllocator allocator, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator); - - if(allocation == VK_NULL_HANDLE) - { - return; - } - - VMA_DEBUG_LOG("vmaFreeMemory"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK +const float* downloadedData = (const float*)allocInfo.pMappedData; +\endcode -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordFreeMemory( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif - - allocator->FreeMemory( - 1, // allocationCount - &allocation); -} -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( - VmaAllocator allocator, - size_t allocationCount, - VmaAllocation* pAllocations) -{ - if(allocationCount == 0) - { - return; - } +\section usage_patterns_advanced_data_uploading Advanced data uploading + +For resources that you frequently write on CPU via mapped pointer and +frequently read on GPU e.g. as a uniform buffer (also called "dynamic"), multiple options are possible: + +-# Easiest solution is to have one copy of the resource in `HOST_VISIBLE` memory, + even if it means system RAM (not `DEVICE_LOCAL`) on systems with a discrete graphics card, + and make the device reach out to that resource directly. + - Reads performed by the device will then go through PCI Express bus. + The performance of this access may be limited, but it may be fine depending on the size + of this resource (whether it is small enough to quickly end up in GPU cache) and the sparsity + of access. +-# On systems with unified memory (e.g. AMD APU or Intel integrated graphics, mobile chips), + a memory type may be available that is both `HOST_VISIBLE` (available for mapping) and `DEVICE_LOCAL` + (fast to access from the GPU). Then, it is likely the best choice for such type of resource. +-# Systems with a discrete graphics card and separate video memory may or may not expose + a memory type that is both `HOST_VISIBLE` and `DEVICE_LOCAL`, also known as Base Address Register (BAR). + If they do, it represents a piece of VRAM (or entire VRAM, if ReBAR is enabled in the motherboard BIOS) + that is available to CPU for mapping. + - Writes performed by the host to that memory go through PCI Express bus. + The performance of these writes may be limited, but it may be fine, especially on PCIe 4.0, + as long as rules of using uncached and write-combined memory are followed - only sequential writes and no reads. +-# Finally, you may need or prefer to create a separate copy of the resource in `DEVICE_LOCAL` memory, + a separate "staging" copy in `HOST_VISIBLE` memory and perform an explicit transfer command between them. + +Thankfully, VMA offers an aid to create and use such resources in the the way optimal +for the current Vulkan device. To help the library make the best choice, +use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT together with +#VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT. +It will then prefer a memory type that is both `DEVICE_LOCAL` and `HOST_VISIBLE` (integrated memory or BAR), +but if no such memory type is available or allocation from it fails +(PC graphics cards have only 256 MB of BAR by default, unless ReBAR is supported and enabled in BIOS), +it will fall back to `DEVICE_LOCAL` memory for fast GPU access. +It is then up to you to detect that the allocation ended up in a memory type that is not `HOST_VISIBLE`, +so you need to create another "staging" allocation and perform explicit transfers. - VMA_ASSERT(allocator); - - VMA_DEBUG_LOG("vmaFreeMemoryPages"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordFreeMemoryPages( - allocator->GetCurrentFrameIndex(), - (uint64_t)allocationCount, - pAllocations); - } -#endif - - allocator->FreeMemory(allocationCount, pAllocations); -} +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; -VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeAllocation( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize newSize) -{ - VMA_ASSERT(allocator && allocation); - - VMA_DEBUG_LOG("vmaResizeAllocation"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - return allocator->ResizeAllocation(allocation, newSize); -} +VkMemoryPropertyFlags memPropFlags; +vmaGetAllocationMemoryProperties(allocator, alloc, &memPropFlags); -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( - VmaAllocator allocator, - VmaAllocation allocation, - VmaAllocationInfo* pAllocationInfo) +if(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - VMA_ASSERT(allocator && allocation && pAllocationInfo); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordGetAllocationInfo( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif + // Allocation ended up in a mappable memory and is already mapped - write to it directly. - allocator->GetAllocationInfo(allocation, pAllocationInfo); + // [Executed in runtime]: + memcpy(allocInfo.pMappedData, myData, myDataSize); } - -VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation( - VmaAllocator allocator, - VmaAllocation allocation) +else { - VMA_ASSERT(allocator && allocation); + // Allocation ended up in a non-mappable memory - need to transfer. + VkBufferCreateInfo stagingBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + stagingBufCreateInfo.size = 65536; + stagingBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VmaAllocationCreateInfo stagingAllocCreateInfo = {}; + stagingAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + stagingAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VkBuffer stagingBuf; + VmaAllocation stagingAlloc; + VmaAllocationInfo stagingAllocInfo; + vmaCreateBuffer(allocator, &stagingBufCreateInfo, &stagingAllocCreateInfo, + &stagingBuf, &stagingAlloc, stagingAllocInfo); + + // [Executed in runtime]: + memcpy(stagingAllocInfo.pMappedData, myData, myDataSize); + //vkCmdPipelineBarrier: VK_ACCESS_HOST_WRITE_BIT --> VK_ACCESS_TRANSFER_READ_BIT + VkBufferCopy bufCopy = { + 0, // srcOffset + 0, // dstOffset, + myDataSize); // size + vkCmdCopyBuffer(cmdBuf, stagingBuf, buf, 1, &bufCopy); +} +\endcode - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\section usage_patterns_other_use_cases Other use cases + +Here are some other, less obvious use cases and their recommended settings: + +- An image that is used only as transfer source and destination, but it should stay on the device, + as it is used to temporarily store a copy of some texture, e.g. from the current to the next frame, + for temporal antialiasing or other temporal effects. + - Use `VkImageCreateInfo::usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO +- An image that is used only as transfer source and destination, but it should be placed + in the system RAM despite it doesn't need to be mapped, because it serves as a "swap" copy to evict + least recently used textures from VRAM. + - Use `VkImageCreateInfo::usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO_PREFER_HOST, + as VMA needs a hint here to differentiate from the previous case. +- A buffer that you want to map and write from the CPU, directly read from the GPU + (e.g. as a uniform or vertex buffer), but you have a clear preference to place it in device or + host memory due to its large size. + - Use `VkBufferCreateInfo::usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE or #VMA_MEMORY_USAGE_AUTO_PREFER_HOST + - Use VmaAllocationCreateInfo::flags = #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordTouchAllocation( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif - return allocator->TouchAllocation(allocation); -} +\page configuration Configuration -VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( - VmaAllocator allocator, - VmaAllocation allocation, - void* pUserData) -{ - VMA_ASSERT(allocator && allocation); +Please check "CONFIGURATION SECTION" in the code to find macros that you can define +before each include of this file or change directly in this file to provide +your own implementation of basic facilities like assert, `min()` and `max()` functions, +mutex, atomic etc. +The library uses its own implementation of containers by default, but you can switch to using +STL containers instead. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +For example, define `VMA_ASSERT(expr)` before including the library to provide +custom implementation of the assertion, compatible with your project. +By default it is defined to standard C `assert(expr)` in `_DEBUG` configuration +and empty otherwise. - allocation->SetUserData(allocator, pUserData); +\section config_Vulkan_functions Pointers to Vulkan functions -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordSetAllocationUserData( - allocator->GetCurrentFrameIndex(), - allocation, - pUserData); - } -#endif -} +There are multiple ways to import pointers to Vulkan functions in the library. +In the simplest case you don't need to do anything. +If the compilation or linking of your program or the initialization of the #VmaAllocator +doesn't work for you, you can try to reconfigure it. -VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation( - VmaAllocator allocator, - VmaAllocation* pAllocation) -{ - VMA_ASSERT(allocator && pAllocation); +First, the allocator tries to fetch pointers to Vulkan functions linked statically, +like this: - VMA_DEBUG_GLOBAL_MUTEX_LOCK; +\code +m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory; +\endcode - allocator->CreateLostAllocation(pAllocation); +If you want to disable this feature, set configuration macro: `#define VMA_STATIC_VULKAN_FUNCTIONS 0`. -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordCreateLostAllocation( - allocator->GetCurrentFrameIndex(), - *pAllocation); - } -#endif -} +Second, you can provide the pointers yourself by setting member VmaAllocatorCreateInfo::pVulkanFunctions. +You can fetch them e.g. using functions `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` or +by using a helper library like [volk](https://github.com/zeux/volk). -VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( - VmaAllocator allocator, - VmaAllocation allocation, - void** ppData) -{ - VMA_ASSERT(allocator && allocation && ppData); +Third, VMA tries to fetch remaining pointers that are still null by calling +`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` on its own. +You need to only fill in VmaVulkanFunctions::vkGetInstanceProcAddr and VmaVulkanFunctions::vkGetDeviceProcAddr. +Other pointers will be fetched automatically. +If you want to disable this feature, set configuration macro: `#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0`. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +Finally, all the function pointers required by the library (considering selected +Vulkan version and enabled extensions) are checked with `VMA_ASSERT` if they are not null. - VkResult res = allocator->Map(allocation, ppData); -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordMapMemory( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif +\section custom_memory_allocator Custom host memory allocator - return res; -} +If you use custom allocator for CPU memory rather than default operator `new` +and `delete` from C++, you can make this library using your allocator as well +by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These +functions will be passed to Vulkan, as well as used by the library itself to +make any CPU-side allocations. -VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( - VmaAllocator allocator, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator && allocation); +\section allocation_callbacks Device memory allocation callbacks - VMA_DEBUG_GLOBAL_MUTEX_LOCK +The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally. +You can setup callbacks to be informed about these calls, e.g. for the purpose +of gathering some statistics. To do it, fill optional member +VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordUnmapMemory( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif +\section heap_memory_limit Device heap memory limit - allocator->Unmap(allocation); -} +When device memory of certain heap runs out of free space, new allocations may +fail (returning error code) or they may succeed, silently pushing some existing_ +memory blocks from GPU VRAM to system RAM (which degrades performance). This +behavior is implementation-dependent - it depends on GPU vendor and graphics +driver. -VMA_CALL_PRE void VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size) -{ - VMA_ASSERT(allocator && allocation); +On AMD cards it can be controlled while creating Vulkan device object by using +VK_AMD_memory_overallocation_behavior extension, if available. - VMA_DEBUG_LOG("vmaFlushAllocation"); +Alternatively, if you want to test how your program behaves with limited amount of Vulkan device +memory available without switching your graphics card to one that really has +smaller VRAM, you can use a feature of this library intended for this purpose. +To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit. - VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordFlushAllocation( - allocator->GetCurrentFrameIndex(), - allocation, offset, size); - } -#endif -} +\page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation -VMA_CALL_PRE void VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size) -{ - VMA_ASSERT(allocator && allocation); +VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve +performance on some GPUs. It augments Vulkan API with possibility to query +driver whether it prefers particular buffer or image to have its own, dedicated +allocation (separate `VkDeviceMemory` block) for better efficiency - to be able +to do some internal optimizations. The extension is supported by this library. +It will be used automatically when enabled. - VMA_DEBUG_LOG("vmaInvalidateAllocation"); +It has been promoted to core Vulkan 1.1, so if you use eligible Vulkan version +and inform VMA about it by setting VmaAllocatorCreateInfo::vulkanApiVersion, +you are all set. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +Otherwise, if you want to use it as an extension: - allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); +1 . When creating Vulkan device, check if following 2 device extensions are +supported (call `vkEnumerateDeviceExtensionProperties()`). +If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`). -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordInvalidateAllocation( - allocator->GetCurrentFrameIndex(), - allocation, offset, size); - } -#endif -} +- VK_KHR_get_memory_requirements2 +- VK_KHR_dedicated_allocation -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits) -{ - VMA_ASSERT(allocator); +If you enabled these extensions: - VMA_DEBUG_LOG("vmaCheckCorruption"); +2 . Use #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag when creating +your #VmaAllocator to inform the library that you enabled required extensions +and you want the library to use them. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\code +allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - return allocator->CheckCorruption(memoryTypeBits); -} +vmaCreateAllocator(&allocatorInfo, &allocator); +\endcode -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment( - VmaAllocator allocator, - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo *pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats) -{ - // Deprecated interface, reimplemented using new one. +That is all. The extension will be automatically used whenever you create a +buffer using vmaCreateBuffer() or image using vmaCreateImage(). - VmaDefragmentationInfo2 info2 = {}; - info2.allocationCount = (uint32_t)allocationCount; - info2.pAllocations = pAllocations; - info2.pAllocationsChanged = pAllocationsChanged; - if(pDefragmentationInfo != VMA_NULL) - { - info2.maxCpuAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove; - info2.maxCpuBytesToMove = pDefragmentationInfo->maxBytesToMove; - } - else - { - info2.maxCpuAllocationsToMove = UINT32_MAX; - info2.maxCpuBytesToMove = VK_WHOLE_SIZE; - } - // info2.flags, maxGpuAllocationsToMove, maxGpuBytesToMove, commandBuffer deliberately left zero. +When using the extension together with Vulkan Validation Layer, you will receive +warnings like this: - VmaDefragmentationContext ctx; - VkResult res = vmaDefragmentationBegin(allocator, &info2, pDefragmentationStats, &ctx); - if(res == VK_NOT_READY) - { - res = vmaDefragmentationEnd( allocator, ctx); - } - return res; -} +_vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer._ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin( - VmaAllocator allocator, - const VmaDefragmentationInfo2* pInfo, - VmaDefragmentationStats* pStats, - VmaDefragmentationContext *pContext) -{ - VMA_ASSERT(allocator && pInfo && pContext); +It is OK, you should just ignore it. It happens because you use function +`vkGetBufferMemoryRequirements2KHR()` instead of standard +`vkGetBufferMemoryRequirements()`, while the validation layer seems to be +unaware of it. - // Degenerate case: Nothing to defragment. - if(pInfo->allocationCount == 0 && pInfo->poolCount == 0) - { - return VK_SUCCESS; - } +To learn more about this extension, see: - VMA_ASSERT(pInfo->allocationCount == 0 || pInfo->pAllocations != VMA_NULL); - VMA_ASSERT(pInfo->poolCount == 0 || pInfo->pPools != VMA_NULL); - VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->allocationCount, pInfo->pAllocations)); - VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->poolCount, pInfo->pPools)); +- [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap50.html#VK_KHR_dedicated_allocation) +- [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5) - VMA_DEBUG_LOG("vmaDefragmentationBegin"); - VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkResult res = allocator->DefragmentationBegin(*pInfo, pStats, pContext); +\page vk_ext_memory_priority VK_EXT_memory_priority -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordDefragmentationBegin( - allocator->GetCurrentFrameIndex(), *pInfo, *pContext); - } -#endif +VK_EXT_memory_priority is a device extension that allows to pass additional "priority" +value to Vulkan memory allocations that the implementation may use prefer certain +buffers and images that are critical for performance to stay in device-local memory +in cases when the memory is over-subscribed, while some others may be moved to the system memory. - return res; -} +VMA offers convenient usage of this extension. +If you enable it, you can pass "priority" parameter when creating allocations or custom pools +and the library automatically passes the value to Vulkan using this extension. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd( - VmaAllocator allocator, - VmaDefragmentationContext context) -{ - VMA_ASSERT(allocator); +If you want to use this extension in connection with VMA, follow these steps: - VMA_DEBUG_LOG("vmaDefragmentationEnd"); +\section vk_ext_memory_priority_initialization Initialization - if(context != VK_NULL_HANDLE) - { - VMA_DEBUG_GLOBAL_MUTEX_LOCK +1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_EXT_memory_priority". -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordDefragmentationEnd( - allocator->GetCurrentFrameIndex(), context); - } -#endif +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceMemoryPriorityFeaturesEXT` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority` is true. - return allocator->DefragmentationEnd(context); - } - else - { - return VK_SUCCESS; - } -} +3) While creating device with `vkCreateDevice`, enable this extension - add "VK_EXT_memory_priority" +to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( - VmaAllocator allocator, - VmaDefragmentationContext context, - VmaDefragmentationPassInfo* pInfo - ) -{ - VMA_ASSERT(allocator); - VMA_ASSERT(pInfo); - VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->moveCount, pInfo->pMoves)); +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceMemoryPriorityFeaturesEXT` to +`VkPhysicalDeviceFeatures2::pNext` chain and set its member `memoryPriority` to `VK_TRUE`. - VMA_DEBUG_LOG("vmaBeginDefragmentationPass"); +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT +to VmaAllocatorCreateInfo::flags. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\section vk_ext_memory_priority_usage Usage - if(context == VK_NULL_HANDLE) - { - pInfo->moveCount = 0; - return VK_SUCCESS; - } +When using this extension, you should initialize following member: - return allocator->DefragmentationPassBegin(pInfo, context); -} -VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( - VmaAllocator allocator, - VmaDefragmentationContext context) -{ - VMA_ASSERT(allocator); +- VmaAllocationCreateInfo::priority when creating a dedicated allocation with #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +- VmaPoolCreateInfo::priority when creating a custom pool. - VMA_DEBUG_LOG("vmaEndDefragmentationPass"); - VMA_DEBUG_GLOBAL_MUTEX_LOCK +It should be a floating-point value between `0.0f` and `1.0f`, where recommended default is `0.5f`. +Memory allocated with higher value can be treated by the Vulkan implementation as higher priority +and so it can have lower chances of being pushed out to system memory, experiencing degraded performance. - if(context == VK_NULL_HANDLE) - return VK_SUCCESS; +It might be a good idea to create performance-critical resources like color-attachment or depth-stencil images +as dedicated and set high priority to them. For example: - return allocator->DefragmentationPassEnd(context); -} +\code +VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; +imgCreateInfo.extent.width = 3840; +imgCreateInfo.extent.height = 2160; +imgCreateInfo.extent.depth = 1; +imgCreateInfo.mipLevels = 1; +imgCreateInfo.arrayLayers = 1; +imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkBuffer buffer) -{ - VMA_ASSERT(allocator && allocation && buffer); +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; +allocCreateInfo.priority = 1.0f; - VMA_DEBUG_LOG("vmaBindBufferMemory"); +VkImage img; +VmaAllocation alloc; +vmaCreateImage(allocator, &imgCreateInfo, &allocCreateInfo, &img, &alloc, nullptr); +\endcode - VMA_DEBUG_GLOBAL_MUTEX_LOCK +`priority` member is ignored in the following situations: - return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); -} +- Allocations created in custom pools: They inherit the priority, along with all other allocation parameters + from the parametrs passed in #VmaPoolCreateInfo when the pool was created. +- Allocations created in default pools: They inherit the priority from the parameters + VMA used when creating default pools, which means `priority == 0.5f`. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize allocationLocalOffset, - VkBuffer buffer, - const void* pNext) -{ - VMA_ASSERT(allocator && allocation && buffer); - VMA_DEBUG_LOG("vmaBindBufferMemory2"); +\page vk_amd_device_coherent_memory VK_AMD_device_coherent_memory - VMA_DEBUG_GLOBAL_MUTEX_LOCK +VK_AMD_device_coherent_memory is a device extension that enables access to +additional memory types with `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and +`VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flag. It is useful mostly for +allocation of buffers intended for writing "breadcrumb markers" in between passes +or draw calls, which in turn are useful for debugging GPU crash/hang/TDR cases. - return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); -} +When the extension is available but has not been enabled, Vulkan physical device +still exposes those memory types, but their usage is forbidden. VMA automatically +takes care of that - it returns `VK_ERROR_FEATURE_NOT_PRESENT` when an attempt +to allocate memory of such type is made. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkImage image) -{ - VMA_ASSERT(allocator && allocation && image); +If you want to use this extension in connection with VMA, follow these steps: - VMA_DEBUG_LOG("vmaBindImageMemory"); +\section vk_amd_device_coherent_memory_initialization Initialization - VMA_DEBUG_GLOBAL_MUTEX_LOCK +1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_AMD_device_coherent_memory". - return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); -} +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( - VmaAllocator allocator, - VmaAllocation allocation, - VkDeviceSize allocationLocalOffset, - VkImage image, - const void* pNext) -{ - VMA_ASSERT(allocator && allocation && image); +3) While creating device with `vkCreateDevice`, enable this extension - add "VK_AMD_device_coherent_memory" +to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. - VMA_DEBUG_LOG("vmaBindImageMemory2"); +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to +`VkPhysicalDeviceFeatures2::pNext` and set its member `deviceCoherentMemory` to `VK_TRUE`. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT +to VmaAllocatorCreateInfo::flags. - return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext); -} +\section vk_amd_device_coherent_memory_usage Usage -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkBuffer* pBuffer, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); +After following steps described above, you can create VMA allocations and custom pools +out of the special `DEVICE_COHERENT` and `DEVICE_UNCACHED` memory types on eligible +devices. There are multiple ways to do it, for example: - if(pBufferCreateInfo->size == 0) - { - return VK_ERROR_VALIDATION_FAILED_EXT; - } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && - !allocator->m_UseKhrBufferDeviceAddress) - { - VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - - VMA_DEBUG_LOG("vmaCreateBuffer"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK +- You can request or prefer to allocate out of such memory types by adding + `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` to VmaAllocationCreateInfo::requiredFlags + or VmaAllocationCreateInfo::preferredFlags. Those flags can be freely mixed with + other ways of \ref choosing_memory_type, like setting VmaAllocationCreateInfo::usage. +- If you manually found memory type index to use for this purpose, force allocation + from this specific index by setting VmaAllocationCreateInfo::memoryTypeBits `= 1u << index`. - *pBuffer = VK_NULL_HANDLE; - *pAllocation = VK_NULL_HANDLE; +\section vk_amd_device_coherent_memory_more_information More information - // 1. Create VkBuffer. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( - allocator->m_hDevice, - pBufferCreateInfo, - allocator->GetAllocationCallbacks(), - pBuffer); - if(res >= 0) - { - // 2. vkGetBufferMemoryRequirements. - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, - requiresDedicatedAllocation, prefersDedicatedAllocation); +To learn more about this extension, see [VK_AMD_device_coherent_memory in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_device_coherent_memory.html) + +Example use of this extension can be found in the code of the sample and test suite +accompanying this library. - // 3. Allocate memory using allocator. - res = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - *pBuffer, // dedicatedBuffer - pBufferCreateInfo->usage, // dedicatedBufferUsage - VK_NULL_HANDLE, // dedicatedImage - *pAllocationCreateInfo, - VMA_SUBALLOCATION_TYPE_BUFFER, - 1, // allocationCount - pAllocation); -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordCreateBuffer( - allocator->GetCurrentFrameIndex(), - *pBufferCreateInfo, - *pAllocationCreateInfo, - *pAllocation); - } -#endif +\page enabling_buffer_device_address Enabling buffer device address - if(res >= 0) - { - // 3. Bind buffer with memory. - if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) - { - res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); - } - if(res >= 0) - { - // All steps succeeded. - #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); - #endif - if(pAllocationInfo != VMA_NULL) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } +Device extension VK_KHR_buffer_device_address +allow to fetch raw GPU pointer to a buffer and pass it for usage in a shader code. +It has been promoted to core Vulkan 1.2. - return VK_SUCCESS; - } - allocator->FreeMemory( - 1, // allocationCount - pAllocation); - *pAllocation = VK_NULL_HANDLE; - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); - *pBuffer = VK_NULL_HANDLE; - return res; - } - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); - *pBuffer = VK_NULL_HANDLE; - return res; - } - return res; -} +If you want to use this feature in connection with VMA, follow these steps: -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( - VmaAllocator allocator, - VkBuffer buffer, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator); +\section enabling_buffer_device_address_initialization Initialization - if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) - { - return; - } +1) (For Vulkan version < 1.2) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains +"VK_KHR_buffer_device_address". - VMA_DEBUG_LOG("vmaDestroyBuffer"); +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress` is true. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +3) (For Vulkan version < 1.2) While creating device with `vkCreateDevice`, enable this extension - add +"VK_KHR_buffer_device_address" to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordDestroyBuffer( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to +`VkPhysicalDeviceFeatures2::pNext` and set its member `bufferDeviceAddress` to `VK_TRUE`. - if(buffer != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); - } +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this feature - add #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT +to VmaAllocatorCreateInfo::flags. - if(allocation != VK_NULL_HANDLE) - { - allocator->FreeMemory( - 1, // allocationCount - &allocation); - } -} +\section enabling_buffer_device_address_usage Usage -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkImage* pImage, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); +After following steps described above, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. +The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to +allocated memory blocks wherever it might be needed. - if(pImageCreateInfo->extent.width == 0 || - pImageCreateInfo->extent.height == 0 || - pImageCreateInfo->extent.depth == 0 || - pImageCreateInfo->mipLevels == 0 || - pImageCreateInfo->arrayLayers == 0) - { - return VK_ERROR_VALIDATION_FAILED_EXT; - } +Please note that the library supports only `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*`. +The second part of this functionality related to "capture and replay" is not supported, +as it is intended for usage in debugging tools like RenderDoc, not in everyday Vulkan usage. - VMA_DEBUG_LOG("vmaCreateImage"); +\section enabling_buffer_device_address_more_information More information - VMA_DEBUG_GLOBAL_MUTEX_LOCK +To learn more about this extension, see [VK_KHR_buffer_device_address in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap46.html#VK_KHR_buffer_device_address) - *pImage = VK_NULL_HANDLE; - *pAllocation = VK_NULL_HANDLE; +Example use of this extension can be found in the code of the sample and test suite +accompanying this library. - // 1. Create VkImage. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( - allocator->m_hDevice, - pImageCreateInfo, - allocator->GetAllocationCallbacks(), - pImage); - if(res >= 0) - { - VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? - VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : - VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR; - - // 2. Allocate memory using allocator. - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetImageMemoryRequirements(*pImage, vkMemReq, - requiresDedicatedAllocation, prefersDedicatedAllocation); +\page general_considerations General considerations - res = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - VK_NULL_HANDLE, // dedicatedBuffer - UINT32_MAX, // dedicatedBufferUsage - *pImage, // dedicatedImage - *pAllocationCreateInfo, - suballocType, - 1, // allocationCount - pAllocation); +\section general_considerations_thread_safety Thread safety -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordCreateImage( - allocator->GetCurrentFrameIndex(), - *pImageCreateInfo, - *pAllocationCreateInfo, - *pAllocation); - } -#endif +- The library has no global state, so separate #VmaAllocator objects can be used + independently. + There should be no need to create multiple such objects though - one per `VkDevice` is enough. +- By default, all calls to functions that take #VmaAllocator as first parameter + are safe to call from multiple threads simultaneously because they are + synchronized internally when needed. + This includes allocation and deallocation from default memory pool, as well as custom #VmaPool. +- When the allocator is created with #VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT + flag, calls to functions that take such #VmaAllocator object must be + synchronized externally. +- Access to a #VmaAllocation object must be externally synchronized. For example, + you must not call vmaGetAllocationInfo() and vmaMapMemory() from different + threads at the same time if you pass the same #VmaAllocation object to these + functions. +- #VmaVirtualBlock is not safe to be used from multiple threads simultaneously. - if(res >= 0) - { - // 3. Bind image with memory. - if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) - { - res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL); - } - if(res >= 0) - { - // All steps succeeded. - #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage); - #endif - if(pAllocationInfo != VMA_NULL) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } +\section general_considerations_versioning_and_compatibility Versioning and compatibility - return VK_SUCCESS; - } - allocator->FreeMemory( - 1, // allocationCount - pAllocation); - *pAllocation = VK_NULL_HANDLE; - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); - *pImage = VK_NULL_HANDLE; - return res; - } - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); - *pImage = VK_NULL_HANDLE; - return res; - } - return res; -} +The library uses [**Semantic Versioning**](https://semver.org/), +which means version numbers follow convention: Major.Minor.Patch (e.g. 2.3.0), where: -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( - VmaAllocator allocator, - VkImage image, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator); +- Incremented Patch version means a release is backward- and forward-compatible, + introducing only some internal improvements, bug fixes, optimizations etc. + or changes that are out of scope of the official API described in this documentation. +- Incremented Minor version means a release is backward-compatible, + so existing code that uses the library should continue to work, while some new + symbols could have been added: new structures, functions, new values in existing + enums and bit flags, new structure members, but not new function parameters. +- Incrementing Major version means a release could break some backward compatibility. - if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) - { - return; - } +All changes between official releases are documented in file "CHANGELOG.md". - VMA_DEBUG_LOG("vmaDestroyImage"); +\warning Backward compatibility is considered on the level of C++ source code, not binary linkage. +Adding new members to existing structures is treated as backward compatible if initializing +the new members to binary zero results in the old behavior. +You should always fully initialize all library structures to zeros and not rely on their +exact binary size. - VMA_DEBUG_GLOBAL_MUTEX_LOCK +\section general_considerations_validation_layer_warnings Validation layer warnings -#if VMA_RECORDING_ENABLED - if(allocator->GetRecorder() != VMA_NULL) - { - allocator->GetRecorder()->RecordDestroyImage( - allocator->GetCurrentFrameIndex(), - allocation); - } -#endif +When using this library, you can meet following types of warnings issued by +Vulkan validation layer. They don't necessarily indicate a bug, so you may need +to just ignore them. - if(image != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); - } - if(allocation != VK_NULL_HANDLE) - { - allocator->FreeMemory( - 1, // allocationCount - &allocation); - } -} +- *vkBindBufferMemory(): Binding memory to buffer 0xeb8e4 but vkGetBufferMemoryRequirements() has not been called on that buffer.* + - It happens when VK_KHR_dedicated_allocation extension is enabled. + `vkGetBufferMemoryRequirements2KHR` function is used instead, while validation layer seems to be unaware of it. +- *Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used.* + - It happens when you map a buffer or image, because the library maps entire + `VkDeviceMemory` block, where different types of images and buffers may end + up together, especially on GPUs with unified memory like Intel. +- *Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug.* + - It may happen when you use [defragmentation](@ref defragmentation). + +\section general_considerations_allocation_algorithm Allocation algorithm + +The library uses following algorithm for allocation, in order: + +-# Try to find free range of memory in existing blocks. +-# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size. +-# If failed, try to create such block with size / 2, size / 4, size / 8. +-# If failed, try to allocate separate `VkDeviceMemory` for this allocation, + just like when you use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +-# If failed, choose other memory type that meets the requirements specified in + VmaAllocationCreateInfo and go to point 1. +-# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + +\section general_considerations_features_not_supported Features not supported + +Features deliberately excluded from the scope of this library: -#endif // #ifdef VMA_IMPLEMENTATION +-# **Data transfer.** Uploading (streaming) and downloading data of buffers and images + between CPU and GPU memory and related synchronization is responsibility of the user. + Defining some "texture" object that would automatically stream its data from a + staging copy in CPU memory to GPU memory would rather be a feature of another, + higher-level library implemented on top of VMA. + VMA doesn't record any commands to a `VkCommandBuffer`. It just allocates memory. +-# **Recreation of buffers and images.** Although the library has functions for + buffer and image creation: vmaCreateBuffer(), vmaCreateImage(), you need to + recreate these objects yourself after defragmentation. That is because the big + structures `VkBufferCreateInfo`, `VkImageCreateInfo` are not stored in + #VmaAllocation object. +-# **Handling CPU memory allocation failures.** When dynamically creating small C++ + objects in CPU memory (not Vulkan memory), allocation failures are not checked + and handled gracefully, because that would complicate code significantly and + is usually not needed in desktop PC applications anyway. + Success of an allocation is just checked with an assert. +-# **Code free of any compiler warnings.** Maintaining the library to compile and + work correctly on so many different platforms is hard enough. Being free of + any warnings, on any version of any compiler, is simply not feasible. + There are many preprocessor macros that make some variables unused, function parameters unreferenced, + or conditional expressions constant in some configurations. + The code of this library should not be bigger or more complicated just to silence these warnings. + It is recommended to disable such warnings instead. +-# This is a C++ library with C interface. **Bindings or ports to any other programming languages** are welcome as external projects but + are not going to be included into this repository. +*/ diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h new file mode 100644 index 000000000..f537c0f98 --- /dev/null +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -0,0 +1,16 @@ +// +// Created by Deamon on 11.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H +#define AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H + +#include "frame/FrameInputParams.h" + +template +class IRendererParameters { + virtual void putIntoQueue(std::shared_ptr> &frameInputParams) = 0; + +}; + +#endif //AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H diff --git a/wowViewerLib/src/renderer/IRenderer.h b/wowViewerLib/src/renderer/IRenderer.h new file mode 100644 index 000000000..ce53f1392 --- /dev/null +++ b/wowViewerLib/src/renderer/IRenderer.h @@ -0,0 +1,17 @@ +// +// Created by Deamon on 06.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IRENDERER_H +#define AWEBWOWVIEWERCPP_IRENDERER_H + +#include + +class IRenderer { +public: + virtual ~IRenderer() = 0; +}; + +typedef std::shared_ptr HIRenderer; + +#endif //AWEBWOWVIEWERCPP_IRENDERER_H diff --git a/wowViewerLib/src/renderer/MapSceneRenderer.h b/wowViewerLib/src/renderer/MapSceneRenderer.h deleted file mode 100644 index cb73606b6..000000000 --- a/wowViewerLib/src/renderer/MapSceneRenderer.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Created by Deamon on 11/26/2022. -// - -#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERER_H -#define AWEBWOWVIEWERCPP_MAPSCENERENDERER_H - - -#include "../engine/objects/scenes/map.h" - -class MapSceneRenderer { -public: - MapSceneRenderer() = default; - virtual ~MapSceneRenderer() = 0; - - virtual HFrameBuffer putIntoQueue(HCullStage &cullStage) = 0; - -}; - - -#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERER_H diff --git a/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.cpp b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.cpp new file mode 100644 index 000000000..837118d61 --- /dev/null +++ b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 14.12.22. +// + +#include "IVertexBufferDynamicTemplate.h" diff --git a/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h new file mode 100644 index 000000000..200f28204 --- /dev/null +++ b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h @@ -0,0 +1,20 @@ +// +// Created by Deamon on 14.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICTEMPLATE_H +#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICTEMPLATE_H + +#include + +template +class IVertexBufferDynamicTemplate { +public: + virtual ~IVertexBufferDynamicTemplate() = 0; + + virtual const std::vector &getBuffer() = 0; + virtual void save(size_t sizeToSave) = 0; +}; + + +#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICTEMPLATE_H diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h new file mode 100644 index 000000000..3150c090d --- /dev/null +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -0,0 +1,39 @@ +// +// Created by Deamon on 11.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H +#define AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H + +#include "../../engine/CameraMatrices.h" +#include "../../engine/objects/iScene.h" +#include "../../include/iostuff.h" + +struct ViewPortDimensions{ + std::array mins; + std::array maxs; +}; + +template +struct FrameInputParams { + HCameraMatrices matricesForCulling; + HCameraMatrices cameraMatricesForRendering; + HCameraMatrices cameraMatricesForDebugCamera; + HScene scene; + + std::shared_ptr additionalData; + + //Time advance + animTime_t delta = 0; + + //Parameters for framebuffer + ViewPortDimensions viewPortDimensions = {{0,0}, {64, 64}}; + bool invertedZ = false; + bool clearScreen = false; + + //Callback for culling stuff + std::function cullingDataCallback; + std::function frameBufferCallback; +}; + +#endif //AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp new file mode 100644 index 000000000..2be5a8fde --- /dev/null +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -0,0 +1,123 @@ +// +// Created by deamon on 15.01.20. +// + +#include +#include +#include "SceneComposer.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + +void SceneComposer::processCaches(int limit) { + if (m_apiContainer->cacheStorage) { + m_apiContainer->cacheStorage->processCaches(limit); + } +} + +SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiContainer) { +#ifdef __EMSCRIPTEN__ + m_supportThreads = false; +// m_supportThreads = emscripten_run_script_int("(SharedArrayBuffer != null) ? 1 : 0") == 1; +#endif + + if (m_supportThreads) { + loadingResourcesThread = std::thread([&]() { + using namespace std::chrono_literals; + while (!this->m_isTerminating) { + std::this_thread::sleep_for(1ms); + processCaches(1000); + } + }); + + + cullingThread = std::thread(([&]() { + using namespace std::chrono_literals; + while (!this->m_isTerminating) { + DoCulling(); + } + })); + + if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { + updateThread = std::thread(([&]() { + this->m_apiContainer->hDevice->initUploadThread(); + while (!this->m_isTerminating) { + + + updateTimePerFrame.beginMeasurement(); + DoUpdate(); + updateTimePerFrame.endMeasurement(); + } + })); + } + } +} + +void SceneComposer::DoCulling() { +// for (int i = 0; i < frameScenario->cullStages.size(); i++) { +// auto cullStage = frameScenario->cullStages[i]; +// +// cullStage->scene->checkCulling(cullStage); +// } +} + + +void SceneComposer::DoUpdate() { +// auto device = m_apiContainer->hDevice; +// +// +// auto frameScenario = m_frameScenarios[updateObjFrame]; +// if (frameScenario == nullptr) return; +// device->startUpdateForNextFrame(); +// for (auto updateStage : frameScenario->updateStages) { +// updateStage->cullResult->scene->produceUpdateStage(updateStage); +// } +// std::vector meshes; +// collectMeshes(frameScenario->getDrawStage(), meshes); +// +// for (auto updateStage : frameScenario->updateStages) { +// updateStage->cullResult->scene->updateBuffers(updateStage); +// } +// +// std::vector*> uniformChunkVec; +// std::vector frameDepDataVec; +// +// for (auto &updateStage : frameScenario->updateStages) { +// frameDepDataVec.push_back(updateStage->cullResult->frameDependentData); +// uniformChunkVec.push_back(&updateStage->uniformBufferChunks); +// } +// device->updateBuffers(uniformChunkVec, frameDepDataVec); +// for (auto cullStage : frameScenario->cullStages) { +// cullStage->scene->doPostLoad(cullStage); //Do post load after rendering is done! +// } +// device->uploadTextureForMeshes(meshes); +// +// if (device->getIsVulkanAxisSystem()) { +// if (frameScenario != nullptr) { +// m_apiContainer->hDevice->drawStageAndDeps(frameScenario->getDrawStage()); +// } +// } +// device->endUpdateForNextFrame(); +} +#define logExecution {} +//#define logExecution { \ +// std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ +//} + + +void SceneComposer::draw(HFrameScenario frameScenario) { + std::future cullingFuture; + std::future updateFuture; + + m_apiContainer->hDevice->reset(); + + if (!m_supportThreads) { + processCaches(10); + DoCulling(); + DoUpdate(); + } + m_apiContainer->hDevice->beginFrame(); + + m_apiContainer->hDevice->commitFrame(); + m_apiContainer->hDevice->increaseFrameNumber(); +} diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h new file mode 100644 index 000000000..6238942e3 --- /dev/null +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -0,0 +1,66 @@ +// +// Created by deamon on 15.01.20. +// + +#ifndef AWEBWOWVIEWERCPP_SCENECOMPOSER_H +#define AWEBWOWVIEWERCPP_SCENECOMPOSER_H + + +#include +#include +#include +#include "../../include/iostuff.h" +#include "SceneScenario.h" +#include "../../engine/algorithms/FrameCounter.h" +#include "../../engine/ApiContainer.h" + +class SceneComposer { +private: + HApiContainer m_apiContainer = nullptr; +private: + std::thread cullingThread; + std::thread updateThread; + std::thread loadingResourcesThread; + + bool m_supportThreads = true; + bool m_isTerminating = false; + + FrameCounter updateTimePerFrame; + + void DoCulling(); + void DoUpdate(); + void processCaches(int limit); + + //Flip-flop delta promises + int frameMod = 0; + + std::queue m_cullingQueue; + std::queue m_updateQueue; + std::queue m_render; + + std::condition_variable startCulling; + std::mutex cullingMutex; + + std::condition_variable startUpdate; + std::mutex cullingUpdate; +public: + SceneComposer(HApiContainer apiContainer); + ~SceneComposer() { + m_isTerminating = true; + + cullingThread.join(); + + if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { + updateThread.join(); + } + + loadingResourcesThread.join(); + } + + void draw(HFrameScenario frameScenario); + + void addInputParams(HFrameScenario rendererAndInput){}; +}; + + +#endif //AWEBWOWVIEWERCPP_SCENECOMPOSER_H diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.cpp b/wowViewerLib/src/renderer/frame/SceneScenario.cpp new file mode 100644 index 000000000..0d634c09b --- /dev/null +++ b/wowViewerLib/src/renderer/frame/SceneScenario.cpp @@ -0,0 +1,6 @@ +// +// Created by deamon on 30.01.20. +// + +#include "SceneScenario.h" + diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h new file mode 100644 index 000000000..80adf7f5f --- /dev/null +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -0,0 +1,45 @@ +// +// Created by deamon on 15.01.20. +// + +#ifndef AWEBWOWVIEWERCPP_SCENESCENARIO_H +#define AWEBWOWVIEWERCPP_SCENESCENARIO_H + +#include +#include "../IRenderParameters.h" + +struct CameraMatrices; + +//Holds dependency graph for different scenes +class FrameScenario; + +#include +class SceneComposer; + +#include "../IRenderer.h" + +class FrameScenarioBuilder { +private: + template + class RendererSpecificData { + private: + FrameScenarioBuilder &m_builder; + public: + RendererSpecificData(FrameScenarioBuilder &builder) : m_builder(builder) { + } + }; + +public: + template , T>>> + RendererSpecificData withSceneRenderer(T renderer) { + return RendererSpecificData(this, renderer); + } +}; + +struct FrameScenario { + std::vector renderer; +}; +typedef std::shared_ptr HFrameScenario; + + +#endif //AWEBWOWVIEWERCPP_SCENESCENARIO_H diff --git a/wowViewerLib/src/engine/DrawStage.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h similarity index 61% rename from wowViewerLib/src/engine/DrawStage.h rename to wowViewerLib/src/renderer/mapScene/FrameDependentData.h index e96695cbb..8a420e9b3 100644 --- a/wowViewerLib/src/engine/DrawStage.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -1,39 +1,14 @@ // -// Created by Deamon on 2/2/2020. +// Created by Deamon on 11.12.22. // -#ifndef AWEBWOWVIEWERCPP_DRAWSTAGE_H -#define AWEBWOWVIEWERCPP_DRAWSTAGE_H +#ifndef AWEBWOWVIEWERCPP_FRAMEDEPENDENTDATA_H +#define AWEBWOWVIEWERCPP_FRAMEDEPENDENTDATA_H -#include +#include +#include "mathfu/glsl_mappings.h" -struct DrawStage; -struct CameraMatrices; -struct ViewPortDimensions; - -struct FrameDepedantData; - -typedef std::shared_ptr HDrawStage; -typedef std::shared_ptr HFrameDepedantData; - -#include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif -#include -#include "../gapi/interface/IDevice.h" -#include "CameraMatrices.h" - - -struct ViewPortDimensions{ - std::array mins; - std::array maxs; -}; - -struct MeshesToRender {std::vector meshes;} ; -typedef std::shared_ptr HMeshesToRender; - -struct FrameDepedantData { +struct FrameDependantData { //Glow float currentGlow; @@ -81,14 +56,6 @@ struct FrameDepedantData { mathfu::vec4 closeOceanColor = mathfu::vec4(0,0,0,0); mathfu::vec4 farOceanColor = mathfu::vec4(0,0,0,0); }; +typedef std::shared_ptr HFrameDependantData; - -struct DrawStage { - std::vector drawStageDependencies; - - mathfu::vec4 clearColor; - -}; -typedef std::shared_ptr HDrawStage; - -#endif //AWEBWOWVIEWERCPP_DRAWSTAGE_H +#endif //AWEBWOWVIEWERCPP_FRAMEDEPENDENTDATA_H diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h new file mode 100644 index 000000000..994e3c365 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -0,0 +1,41 @@ +// +// Created by Deamon on 11.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENEPLAN_H +#define AWEBWOWVIEWERCPP_MAPSCENEPLAN_H + +#include +#include "../../engine/objects/iWmoApi.h" +#include "FrameDependentData.h" +#include "../../engine/objects/ViewsObjects.h" +#include "../../engine/objects/wmo/wmoObject.h" + +struct MapRenderPlan { + int adtAreadId = -1; + int areaId = -1; + int parentAreaId = -1; + + HCameraMatrices renderingMatrices; + + //Result of culling test + std::vector m_currentInteriorGroups = {}; + bool currentWmoGroupIsExtLit = false; + bool currentWmoGroupShowExtSkybox = false; + std::shared_ptr m_currentWMO = nullptr; + int m_currentWmoGroup = -1; + + FrameViewsHolder viewsHolder; + + HFrameDependantData frameDependentData = std::make_shared(); + + //Objects for update and rendering + std::vector> adtArray = {}; + M2ObjectListContainer m2Array; + WMOListContainer wmoArray; + WMOGroupListContainer wmoGroupArray; + + //Settings for the frame +}; +typedef std::shared_ptr HMapRenderPlan; +#endif //AWEBWOWVIEWERCPP_MAPSCENEPLAN_H diff --git a/wowViewerLib/src/renderer/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp similarity index 100% rename from wowViewerLib/src/renderer/MapSceneRenderer.cpp rename to wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h new file mode 100644 index 000000000..23c48336e --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -0,0 +1,22 @@ +// +// Created by Deamon on 11/26/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERER_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERER_H + + +#include "../../engine/objects/scenes/map.h" +#include "../IRenderer.h" +#include "../IRenderParameters.h" + +class MapSceneRenderer : public IRenderer, public IRendererParameters { +public: + MapSceneRenderer() = default; + ~MapSceneRenderer() override = 0; + + void putIntoQueue(FrameInputParams &cullStage) override = 0 ; +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERER_H diff --git a/wowViewerLib/src/renderer/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp similarity index 69% rename from wowViewerLib/src/renderer/MapSceneRendererFactory.cpp rename to wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index afd83afb4..2bebc03c5 100644 --- a/wowViewerLib/src/renderer/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -5,11 +5,10 @@ #include "MapSceneRendererFactory.h" #include "vulkan/MapSceneRenderForwardVLK.h" -std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device) { - +std::shared_ptr MapSceneRendererFactory::createForwardRenderer(HGDevice &device) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - return std::make_shared(); + return std::make_shared(std::dynamic_pointer_cast(device)); default: return nullptr; } diff --git a/wowViewerLib/src/renderer/MapSceneRendererFactory.h b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h similarity index 92% rename from wowViewerLib/src/renderer/MapSceneRendererFactory.h rename to wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h index a3af0f81d..ee1fe9f96 100644 --- a/wowViewerLib/src/renderer/MapSceneRendererFactory.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h @@ -10,7 +10,7 @@ #include "MapSceneRenderer.h" class MapSceneRendererFactory { - static std::shared_ptr createForwardRenderer(HGDevice const &device); + static std::shared_ptr createForwardRenderer(HGDevice &device); }; diff --git a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp similarity index 65% rename from wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp rename to wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 3ff3e5070..4334a0935 100644 --- a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -8,6 +8,6 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_devi } -HFrameBuffer MapSceneRenderForwardVLK::putIntoQueue(HCullStage &cullStage) { +void MapSceneRenderForwardVLK::putIntoQueue(FrameInputParams &frameInputParams) { } diff --git a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h similarity index 64% rename from wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h rename to wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 447822a94..5fe062226 100644 --- a/wowViewerLib/src/renderer/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -7,14 +7,13 @@ #include "../MapSceneRenderer.h" -#include "../../gapi/vulkan/GDeviceVulkan.h" +#include "../../../gapi/vulkan/GDeviceVulkan.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { public: - MapSceneRenderForwardVLK(HGDeviceVLK hDevice); - - HFrameBuffer putIntoQueue(HCullStage &cullStage) override; + explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); + void putIntoQueue(FrameInputParams &frameInputParams) override; private: HGDeviceVLK m_device; From fffea4ed0af5243799c5b71f79f040b14fb1b64b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 25 Dec 2022 11:09:50 +0200 Subject: [PATCH 011/212] a lot of is commented, but application is compilable now --- CMakeLists.txt | 7 +- src/exporters/gltfExporter/GLTFExporter.cpp | 3 +- src/ui/FrontendUI.cpp | 176 ++++++++++- src/ui/renderer/uiScene/FrontendUIRenderer.h | 16 +- src/ui/renderer/uiScene/ImGUIPlan.h | 14 +- .../buffers/IVertexBufferDynamicImgui.cpp | 5 - .../buffers/IVertexBufferDynamicImgui.h | 18 -- .../vulkan/FrontendUIRenderForwardVLK.cpp | 161 +++------- .../vulkan/FrontendUIRenderForwardVLK.h | 31 +- .../buffers/IVertexBufferDynamicImguiVLK.cpp | 15 - .../buffers/IVertexBufferDynamicImguiVLK.h | 33 -- wowViewerLib/CMakeLists.txt | 18 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 19 +- wowViewerLib/src/engine/geometry/m2Geom.h | 8 +- wowViewerLib/src/engine/geometry/skinGeom.cpp | 35 ++- wowViewerLib/src/engine/geometry/skinGeom.h | 22 +- .../src/engine/geometry/wmoGroupGeom.cpp | 52 ++-- .../src/engine/geometry/wmoGroupGeom.h | 7 +- .../src/engine/managers/CRibbonEmitter.cpp | 9 +- .../managers/particles/particleEmitter.cpp | 64 ++-- .../src/engine/objects/ViewsObjects.cpp | 11 +- .../src/engine/objects/adt/adtObject.cpp | 31 +- wowViewerLib/src/engine/objects/iMapApi.h | 2 + wowViewerLib/src/engine/objects/iScene.h | 1 + wowViewerLib/src/engine/objects/iWmoApi.h | 3 +- .../src/engine/objects/m2/m2Object.cpp | 46 ++- wowViewerLib/src/engine/objects/m2/m2Object.h | 18 +- .../src/engine/objects/scenes/map.cpp | 14 +- wowViewerLib/src/engine/objects/scenes/map.h | 2 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 18 +- .../src/engine/objects/wmo/wmoGroupObject.h | 1 + .../src/engine/objects/wmo/wmoObject.h | 1 + wowViewerLib/src/gapi/interface/IDevice.h | 55 +--- .../src/gapi/interface/IRendererProxy.h | 13 + .../src/gapi/interface/buffers/IBuffer.h | 17 + .../src/gapi/interface/buffers/IIndexBuffer.h | 13 - .../gapi/interface/buffers/IUniformBuffer.h | 17 - .../gapi/interface/buffers/IVertexBuffer.h | 16 - .../interface/buffers/IVertexBufferDynamic.h | 25 -- .../src/gapi/interface/meshes/IM2Mesh.h | 18 ++ .../src/gapi/interface/meshes/IMesh.h | 39 +-- .../gapi/interface/meshes/ITransparentMesh.h | 22 ++ wowViewerLib/src/gapi/interface/sortLambda.h | 13 - wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp | 2 +- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h | 2 +- .../gapi/ogl2.0/buffers/GIndexBufferGL20.h | 4 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp | 2 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h | 2 +- .../gapi/ogl3.3/buffers/GIndexBufferGL33.h | 4 +- .../buffers/GVertexBufferDynamicGL33.cpp | 6 +- wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp | 2 +- wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.h | 2 +- .../gapi/ogl4.x/buffers/GIndexBufferGL4x.h | 4 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 294 +++++------------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 82 +---- .../gapi/vulkan/GVertexBufferBindingsVLK.h | 1 - .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 212 +++++++++++++ .../src/gapi/vulkan/buffers/GBufferVLK.h | 101 ++++++ .../gapi/vulkan/buffers/GIndexBufferVLK.cpp | 107 ------- .../src/gapi/vulkan/buffers/GIndexBufferVLK.h | 45 --- .../gapi/vulkan/buffers/GUniformBufferVLK.cpp | 132 -------- .../gapi/vulkan/buffers/GUniformBufferVLK.h | 54 ---- .../buffers/GVertexBufferDynamicVLK.cpp | 14 +- .../vulkan/buffers/GVertexBufferDynamicVLK.h | 11 +- .../gapi/vulkan/buffers/GVertexBufferVLK.cpp | 113 ------- .../gapi/vulkan/buffers/GVertexBufferVLK.h | 46 --- .../src/gapi/vulkan/buffers/IBufferVLK.h | 16 + .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 15 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 8 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 16 - .../src/gapi/vulkan/meshes/GMeshVLK.h | 22 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 9 +- .../vulkan/shaders/GShaderPermutationVLK.h | 4 +- wowViewerLib/src/renderer/IRenderParameters.h | 2 +- .../src/renderer/frame/FrameInputParams.h | 8 +- .../src/renderer/frame/SceneComposer.cpp | 6 +- .../src/renderer/frame/SceneScenario.h | 2 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 27 ++ .../src/renderer/mapScene/MapScenePlan.h | 1 - .../src/renderer/mapScene/MapSceneRenderer.h | 10 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 36 ++- .../vulkan/MapSceneRenderForwardVLK.h | 15 +- 82 files changed, 1048 insertions(+), 1500 deletions(-) delete mode 100644 src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp delete mode 100644 src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h delete mode 100644 src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp delete mode 100644 src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h create mode 100644 wowViewerLib/src/gapi/interface/IRendererProxy.h create mode 100644 wowViewerLib/src/gapi/interface/buffers/IBuffer.h delete mode 100644 wowViewerLib/src/gapi/interface/buffers/IIndexBuffer.h delete mode 100644 wowViewerLib/src/gapi/interface/buffers/IUniformBuffer.h delete mode 100644 wowViewerLib/src/gapi/interface/buffers/IVertexBuffer.h delete mode 100644 wowViewerLib/src/gapi/interface/buffers/IVertexBufferDynamic.h create mode 100644 wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h create mode 100644 wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c89685483..6fafb06f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,15 +233,12 @@ set(SOURCE_FILES src/ui/renderer/uiScene/FrontendUIRendererFactory.h src/ui/renderer/uiScene/ImGUIPlan.cpp src/ui/renderer/uiScene/ImGUIPlan.h - src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp - src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h) + ) set(SOURCE_FILES_VULKAN src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp - src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h - src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp - src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h) + src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h) ######################################################### # FIND OPENGL diff --git a/src/exporters/gltfExporter/GLTFExporter.cpp b/src/exporters/gltfExporter/GLTFExporter.cpp index e1844c920..e978e0ce4 100644 --- a/src/exporters/gltfExporter/GLTFExporter.cpp +++ b/src/exporters/gltfExporter/GLTFExporter.cpp @@ -656,7 +656,8 @@ void GLTFExporter::createVboAndIbo(M2ModelData &m2ModelData, std::shared_ptrgenerateIndexBuffer(); + std::vector indicies = {}; + getSkinGeom(m2Object)->generateIndexBuffer(indicies); modelIBO.data = std::vector((uint8_t *) indicies.data(), (uint8_t *) (indicies.data() + indicies.size())); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index a91e8f256..e59675fbb 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -34,12 +34,6 @@ #include "../database/CEmptySqliteDB.h" #include "../../wowViewerLib/src/gapi/UniformBufferStructures.h" -static const GBufferBinding imguiBindings[3] = { - {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, - {+imguiShader::Attribute::UV, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, uv)}, - {+imguiShader::Attribute::Color, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, col)}, -}; - void FrontendUI::composeUI() { if (this->fontTexture == nullptr) return; @@ -1260,6 +1254,8 @@ void FrontendUI::showSettingsDialog() { glowSource = 1; break; } + default: + glowSource = 1; } if (ImGui::RadioButton("Use glow from database", &glowSource, 0)) { @@ -1739,3 +1735,171 @@ void FrontendUI::createDatabaseHandler() { mapListStringMap = {}; filteredMapList = {}; } + +//void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { +// auto m_device = m_api->hDevice; +// +// if (this->fontTexture == nullptr) { +// ImGuiIO& io = ImGui::GetIO(); +// unsigned char* pixels; +// int width, height; +// io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. +// // Upload texture to graphics system +// this->fontTexture = m_device->createTexture(false, false); +// this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); +// // Store our identifier +// io.Fonts->TexID = this->fontTexture; +// return; +// } +//// if (exporter != nullptr) { +//// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { +//// exporterFramesReady++; +//// } +//// if (exporterFramesReady > 5) { +//// exporter->saveToFile("model.gltf"); +//// exporter = nullptr; +//// } +//// } +// +// lastWidth = resultDrawStage->viewPortDimensions.maxs[0]; +// lastHeight = resultDrawStage->viewPortDimensions.maxs[1]; +// +// resultDrawStage->opaqueMeshes = std::make_shared(); +// auto *draw_data = ImGui::GetDrawData(); +// if (draw_data == nullptr) +// return; +// +// int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); +// int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); +// if (fb_width <= 0 || fb_height <= 0) { +// return; +// } +// ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports +// ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) +// //Create projection matrix: +// auto uiScale = ImGui::GetIO().uiScale; +// float L = draw_data->DisplayPos.x * uiScale; +// float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; +// float T = draw_data->DisplayPos.y * uiScale; +// float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; +// mathfu::mat4 ortho_projection = +// { +// { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, +// { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, +// { 0.0f, 0.0f, -1.0f, 0.0f }, +// { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, +// }; +// +// if (m_device->getIsVulkanAxisSystem()) { +// static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, +// 0, -1, 0, 0, +// 0, 0, 1.0/2.0, 1/2.0, +// 0, 0, 0, 1).Transpose(); +// ortho_projection = vulkanMatrixFix1 * ortho_projection; +// } +// auto uboPart = m_device->createUniformBufferChunk(sizeof(ImgUI::modelWideBlockVS)); +// +// +// uboPart->setUpdateHandler([ortho_projection,uiScale](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData) { +// auto &uni = self->getObject(); +// uni.projectionMat = ortho_projection; +// uni.scale[0] = uiScale; +// }); +// +// auto shaderPermute = m_device->getShader("imguiShader", nullptr); +// // Render command lists +// for (int n = 0; n < draw_data->CmdListsCount; n++) +// { +// const ImDrawList* cmd_list = draw_data->CmdLists[n]; +// +// // Upload vertex/index buffers +// auto vertexBufferBindings = m_device->createVertexBufferBindings(); +// auto vboBuffer = m_device->createVertexBuffer(); +// auto iboBuffer = m_device->createIndexBuffer(); +// +// vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); +// iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); +// +// //Create vao +// GVertexBufferBinding vertexBufferBinding; +// vertexBufferBinding.bindings = std::vector(&imguiBindings[0], &imguiBindings[3]); +// vertexBufferBinding.vertexBuffer = vboBuffer; +// +// vertexBufferBindings->setIndexBuffer(iboBuffer); +// vertexBufferBindings->addVertexBufferBinding(vertexBufferBinding); +// vertexBufferBindings->save(); +// +// for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) +// { +// +// +// const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; +// if (pcmd->UserCallback != NULL) +// { +// // User callback, registered via ImDrawList::AddCallback() +// // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) +//// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) +//// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); +//// else +//// pcmd->UserCallback(cmd_list, pcmd); +// assert(pcmd->UserCallback == NULL); +// } +// else +// { +// // Project scissor/clipping rectangles into framebuffer space +// ImVec4 clip_rect; +// clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; +// clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; +// clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; +// clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; +// +// if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) +// { +// // Apply scissor/clipping rectangle +// // Create mesh add add it to collected meshes +// gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); +// meshTemplate.element = DrawElementMode::TRIANGLES; +// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; +// meshTemplate.backFaceCulling = false; +// meshTemplate.depthCulling = false; +////void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { +// +// meshTemplate.scissorEnabled = true; +// //Vulkan has different clip offset compared to OGL +// if (!m_device->getIsVulkanAxisSystem()) { +// meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; +// meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; +// } else { +// meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; +// meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; +// } +// +// meshTemplate.ubo[1] = uboPart; +// meshTemplate.textureCount = 1; +// meshTemplate.texture[0] = pcmd->TextureId; +// +// meshTemplate.start = pcmd->IdxOffset * 2; +// meshTemplate.end = pcmd->ElemCount; +// +// resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); +// } +// } +// } +// } +// +// //1. Collect buffers +// auto &bufferChunks = updateStages[0]->uniformBufferChunks; +// int renderIndex = 0; +// for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { +// for (int i = 0; i < 5; i++ ) { +// auto bufferChunk = mesh->getUniformBuffer(i); +// +// if (bufferChunk != nullptr) { +// bufferChunks.push_back(bufferChunk); +// } +// } +// } +// +// std::sort( bufferChunks.begin(), bufferChunks.end()); +// bufferChunks.erase( unique( bufferChunks.begin(), bufferChunks.end() ), bufferChunks.end() ); +//} \ No newline at end of file diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index a693a6e4c..7db648b66 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -7,16 +7,20 @@ #include "../../../../wowViewerLib/src/renderer/IRenderParameters.h" #include "ImGUIPlan.h" -#include "buffers/IVertexBufferDynamicImgui.h" +#include "../../../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" + +static const std::array imguiBindings = {{ + {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, + {+imguiShader::Attribute::UV, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, uv)}, + {+imguiShader::Attribute::Color, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, col)}, +}}; + class FrontendUIRenderer : public IRendererParameters { public: - virtual HIVertexBufferDynamicImgui allocateDynamicVertexBuffer(int size) = 0; - virtual HIVertexBufferDynamicImgui allocateDynamicIndexBuffer(int size) = 0; - -// virtual HGMesh allocateImguiMesh(eshTemplate) }; -typedef FrameInputParams FrontendUIInputParams; +//typedef FrameInputParams FrontendUIInputParams; +typedef FrameInputParams FrontendUIInputParams; #endif //AWEBWOWVIEWERCPP_FRONTENDUIRENDERER_H diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index 3288951ef..9cf97bb8b 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -13,16 +13,20 @@ namespace ImGuiFramePlan { class ImGUIParam { public: + explicit ImGUIParam(ImDrawData *imData) { + //Do copy of imData into local copy + + + } ~ImGUIParam() { - if (imData != nullptr) { - for (int i = 0; i < imData->CmdListsCount; i++ ) { - IM_FREE(imData->CmdLists[i]); - } + for (int i = 0; i < imData.CmdListsCount; i++ ) { + IM_FREE(imData.CmdLists[i]); } + } public: - ImDrawData *imData = nullptr; + ImDrawData imData; }; } diff --git a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp deleted file mode 100644 index 1480caa9d..000000000 --- a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by Deamon on 14.12.22. -// - -#include "IVertexBufferDynamicImgui.h" diff --git a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h b/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h deleted file mode 100644 index 0b8349c66..000000000 --- a/src/ui/renderer/uiScene/buffers/IVertexBufferDynamicImgui.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by Deamon on 14.12.22. -// - -#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H -#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H - - -#include "imgui.h" -#include "../../../../../wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h" - -class IVertexBufferDynamicImgui : public IVertexBufferDynamicTemplate{ -public: - ~IVertexBufferDynamicImgui() override = default ; -}; -typedef std::shared_ptr HIVertexBufferDynamicImgui; - -#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUI_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 6c1145cc6..e5dd48dfb 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -4,14 +4,8 @@ #include "FrontendUIRenderForwardVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" -#include "buffers/IVertexBufferDynamicImguiVLK.h" FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - createBuffer(vertexBuffers[i], 1024*1024*1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - createBuffer(indexBuffers[i], 1024*1024*1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); } void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptr &frameInputParams) { @@ -20,81 +14,7 @@ void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptrgetVMAAllocator(), &vbInfo, &ibAllocCreateInfo, - &buffer.stagingBuffer, - &buffer.stagingBufferAlloc, - &buffer.stagingBufferAllocInfo)); - - // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT. - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | bufferUsageFlags; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ibAllocCreateInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, - &buffer.g_hBuffer, - &buffer.g_hBufferAlloc, nullptr)); - - //Create virtual buffer off this native buffer - VmaVirtualBlockCreateInfo blockCreateInfo = {}; - blockCreateInfo.size = bufferSize; - - VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &buffer.virtualBlock); - if(res != VK_SUCCESS) - { - std::cerr << "Failed to create virtual buffer" << std::endl; - } - //memcpy(bufferInfo.stagingVertexBufferAllocInfo.pMappedData, data, length); -} - -void FrontendUIRenderForwardVLK::destroyBuffer(FrontendUIRenderForwardVLK::Buffer &buffer) { - auto l_device = m_device; - - m_device->addDeallocationRecord( - [buffer, l_device]() { - vmaClearVirtualBlock(buffer.virtualBlock); - vmaDestroyVirtualBlock(buffer.virtualBlock); - - vmaDestroyBuffer(l_device->getVMAAllocator(), buffer.stagingBuffer, buffer.stagingBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), buffer.g_hBuffer, buffer.g_hBufferAlloc); - - } - ); -} - -HIVertexBufferDynamicImgui FrontendUIRenderForwardVLK::allocateDynamicVertexBuffer(int maxSize) { - VmaVirtualAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.size = maxSize; //Size in bytes - - VmaVirtualAllocation alloc; - VkDeviceSize offset; - - VkResult res = vmaVirtualAllocate(vertexBuffers[0].virtualBlock, &allocCreateInfo, &alloc, &offset); - if(res == VK_SUCCESS) - { - return std::make_shared(this, maxSize, alloc, offset); - } - else - { - // Allocation failed - no space for it could be found. Handle this error! - return nullptr; - } -} - -void FrontendUIRenderForwardVLK::update() { +void FrontendUIRenderForwardVLK::update(VkCommandBuffer updateBuffer, VkCommandBuffer swapChainDraw) { std::unique_lock guard(m_inputParamsMtx); @@ -127,7 +47,7 @@ void FrontendUIRenderForwardVLK::update() { int lastWidth = frameParams->viewPortDimensions.maxs[0]; int lastHeight = frameParams->viewPortDimensions.maxs[1]; - auto *draw_data = frameParams->additionalData->imData; + ImDrawData *draw_data = nullptr; //frameParams->additionalData->imData; if (draw_data == nullptr) return; @@ -136,6 +56,7 @@ void FrontendUIRenderForwardVLK::update() { if (fb_width <= 0 || fb_height <= 0) { return; } + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) //Create projection matrix: @@ -152,7 +73,8 @@ void FrontendUIRenderForwardVLK::update() { { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, }; - if (m_device->getIsVulkanAxisSystem()) { + //Apply vulkan Matrix fix + if (true) { static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1.0/2.0, 1/2.0, @@ -169,7 +91,35 @@ void FrontendUIRenderForwardVLK::update() { uni.scale[0] = uiScale; }); - auto shaderPermute = m_device->getShader("imguiShader", nullptr); + auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); + + //Calc total size of index/vertex buffers needed + int vertexBufferSize = 0; + int indexBufferSize = 0; + for (int i = 0; i < draw_data->CmdListsCount; i++) { + const ImDrawList* cmd_list = draw_data->CmdLists[i]; + vertexBufferSize += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); + indexBufferSize += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); + } + + auto vboSubBuf = vboBuffer->getSubBuffer(vertexBufferSize); + auto iboSubBuf = iboBuffer->getSubBuffer(indexBufferSize); + + int vboOffset = 0; + int iboOffset = 0; + for (int i = 0; i < draw_data->CmdListsCount; i++) { + const ImDrawList* cmd_list = draw_data->CmdLists[i]; + + vboSubBuf->subUploadData(cmd_list->VtxBuffer.Data, vboOffset, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + iboSubBuf->subUploadData(cmd_list->IdxBuffer.Data, iboOffset, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + + vboOffset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); + iboOffset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); + } + + + + // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -177,11 +127,6 @@ void FrontendUIRenderForwardVLK::update() { // Upload vertex/index buffers auto vertexBufferBindings = m_device->createVertexBufferBindings(); - auto vboBuffer = m_device->createVertexBuffer(); - auto iboBuffer = m_device->createIndexBuffer(); - - vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); //Create vao GVertexBufferBinding vertexBufferBinding; @@ -194,8 +139,6 @@ void FrontendUIRenderForwardVLK::update() { for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != NULL) { @@ -236,32 +179,22 @@ void FrontendUIRenderForwardVLK::update() { meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; } - meshTemplate.ubo[1] = uboPart; - meshTemplate.textureCount = 1; - meshTemplate.texture[0] = pcmd->TextureId; - - meshTemplate.start = pcmd->IdxOffset * 2; - meshTemplate.end = pcmd->ElemCount; - - resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); +// meshTemplate.ubo[1] = uboPart; +// meshTemplate.textureCount = 1; +// meshTemplate.texture[0] = pcmd->TextureId; +// +// meshTemplate.start = pcmd->IdxOffset * 2; +// meshTemplate.end = pcmd->ElemCount; +// +// resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); } } } } +} -// //1. Collect buffers -// auto &bufferChunks = updateStages[0]->uniformBufferChunks; -// int renderIndex = 0; -// for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { -// for (int i = 0; i < 5; i++ ) { -// auto bufferChunk = mesh->getUniformBuffer(i); -// -// if (bufferChunk != nullptr) { -// bufferChunks.push_back(bufferChunk); -// } -// } -// } -// -// std::sort( bufferChunks.begin(), bufferChunks.end()); -// bufferChunks.erase( unique( bufferChunks.begin(), bufferChunks.end() ), bufferChunks.end() ); +void FrontendUIRenderForwardVLK::createBuffers() { + vboBuffer = m_device->createIndexBuffer(1024*1024); + iboBuffer = m_device->createVertexBuffer(1024*1024); + uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 2967eb4a7..69f5b8306 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -9,48 +9,31 @@ #include #include "../FrontendUIRenderer.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h" - -const int MAX_FRAMES_IN_FLIGHT = 2; +#include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: explicit FrontendUIRenderForwardVLK(HGDeviceVLK hDevice); - void putIntoQueue(std::shared_ptr &frameInputParams) override; - void render(); - HIVertexBufferDynamicImgui allocateDynamicVertexBuffer(int size) override; -// HGVertexBufferDynamic allocateDynamicIndexBuffer() = 0; + void update(VkCommandBuffer udBuffer, VkCommandBuffer swapChainDraw); private: HGDeviceVLK m_device; //Frame counter int m_frame = 0; - //Buffers - struct Buffer { - VkBuffer g_hBuffer = VK_NULL_HANDLE; - VmaAllocation g_hBufferAlloc = VK_NULL_HANDLE; - - VkBuffer stagingBuffer = VK_NULL_HANDLE; - VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingBufferAllocInfo; - - //Virtual block for suballocations - VmaVirtualBlock virtualBlock; - }; - - std::array vertexBuffers; //Both vertexes here are of exact size - std::array indexBuffers; - //Rendering pipelining std::mutex m_inputParamsMtx; std::queue> m_inputParams; std::queue> m_updateParams; private: - void createBuffer(Buffer &buffer, int bufferSize, VkBufferUsageFlags bufferUsageFlags); - void destroyBuffer(Buffer &buffer); + HGBufferVLK vboBuffer; + HGBufferVLK iboBuffer; + HGBufferVLK uboBuffer; + + void createBuffers(); }; diff --git a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp deleted file mode 100644 index 4c7be8cd9..000000000 --- a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Deamon on 14.12.22. -// - -#include "IVertexBufferDynamicImguiVLK.h" - -RVertexBufferDynamicImguiVLK::RVertexBufferDynamicImguiVLK(FrontendUIRenderer &renderer, VmaVirtualAllocation alloc, VkDeviceSize offset, int size) : m_renderer(renderer) { - m_alloc = alloc; - m_offset = offset; - m_size = size; -} - -RVertexBufferDynamicImguiVLK::~RVertexBufferDynamicImguiVLK() { - -} diff --git a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h b/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h deleted file mode 100644 index 6cf919454..000000000 --- a/src/ui/renderer/uiScene/vulkan/buffers/IVertexBufferDynamicImguiVLK.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by Deamon on 14.12.22. -// - -#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H -#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H - -#include "../../buffers/IVertexBufferDynamicImgui.h" -#include "../../FrontendUIRenderer.h" -#include "../../../../../../wowViewerLib/src/gapi/vulkan/vk_mem_alloc.h" - -class RVertexBufferDynamicImguiVLK : public IVertexBufferDynamicImgui { - friend class FrontendUIRenderer; -private: - VmaVirtualAllocation m_alloc; - VkDeviceSize m_offset; - int m_size; - - FrontendUIRenderer &m_renderer; -public: - RVertexBufferDynamicImguiVLK(FrontendUIRenderer &renderer, VmaVirtualAllocation alloc, VkDeviceSize offset, int size); - ~RVertexBufferDynamicImguiVLK() override; - - const std::vector &getBuffer() override { - return stagingVertexBuffer; - }; - void save(size_t sizeToSave) override { - m_renderer.planUpload() - }; -}; - - -#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMICIMGUIVLK_H diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 798acad82..7fe3b9d7a 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -261,9 +261,7 @@ set(SOURCE_FILES src/engine/persistance/m2File.h src/gapi/interface/IDevice.cpp src/gapi/interface/textures/ITexture.h - src/gapi/interface/buffers/IIndexBuffer.h - src/gapi/interface/buffers/IUniformBuffer.h - src/gapi/interface/buffers/IVertexBuffer.h + src/gapi/interface/buffers/IBuffer.h src/gapi/interface/IOcclusionQuery.h src/gapi/interface/IShaderPermutation.h src/gapi/interface/IVertexBufferBindings.h @@ -326,7 +324,9 @@ set(SOURCE_FILES src/renderer/IRenderParameters.h src/renderer/frame/FrameInputParams.h src/renderer/mapScene/FrameDependentData.h - src/renderer/buffers/IVertexBufferDynamicTemplate.cpp src/renderer/buffers/IVertexBufferDynamicTemplate.h) + src/renderer/buffers/IVertexBufferDynamicTemplate.cpp + src/renderer/buffers/IVertexBufferDynamicTemplate.h + src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -476,10 +476,7 @@ if (LINK_VULKAN) src/gapi/vulkan/meshes/GMeshVLK.cpp src/gapi/vulkan/textures/GTextureVLK.cpp src/gapi/vulkan/textures/GBlpTextureVLK.cpp - src/gapi/vulkan/buffers/GUniformBufferVLK.cpp src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp - src/gapi/vulkan/buffers/GVertexBufferVLK.cpp - src/gapi/vulkan/buffers/GIndexBufferVLK.cpp src/gapi/vulkan/GPipelineVLK.cpp src/gapi/vulkan/GPipelineVLK.h src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -504,7 +501,10 @@ if (LINK_VULKAN) src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp src/gapi/vulkan/shaders/GWaterfallShaderVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp - src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h) + src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h + src/gapi/vulkan/buffers/GBufferVLK.cpp + src/gapi/vulkan/buffers/GBufferVLK.h + src/gapi/vulkan/buffers/IBufferVLK.h) if (NOT Vulkan_SDK_DIR) set(Vulkan_SDK_DIR $ENV{VULKAN_SDK}) endif() @@ -530,7 +530,7 @@ if (LINK_VULKAN) MESSAGE("Using bundled Vulkan library version non-win32") ELSE() set(LINK_VULKAN OFF) - set(VULKAN_IMPLEMENTATION "") + set(VULKAN_IMPLEMENTATION "" src/gapi/vulkan/buffers/GBufferSuballocation.cpp src/gapi/vulkan/buffers/GBufferSuballocation.h) ENDIF() ENDIF() ENDIF() diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 681f86848..a2e9f443f 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -322,13 +322,13 @@ void M2Geom::initTracks(CM2SequenceLoad * cm2SequenceLoad) { initM2Camera(m2Header, &m2Header->sequences, cm2SequenceLoad); } -HGVertexBuffer M2Geom::getVBO(const HGDevice &device) { +HGVertexBuffer M2Geom::getVBO(const HMapSceneBufferCreate &sceneRenderer) { if (vertexVbo.get() == nullptr) { if (m_m2Data->vertices.size == 0) { return nullptr; } - vertexVbo = device->createVertexBuffer(); + vertexVbo = sceneRenderer->createM2VertexBuffer(m_m2Data->vertices.size*sizeof(M2Vertex)); vertexVbo->uploadData( m_m2Data->vertices.getElement(0), m_m2Data->vertices.size*sizeof(M2Vertex)); @@ -364,6 +364,8 @@ std::array M2Geom::createDynamicVao( // << " vertexCount = " << skinSection->vertexCount // << std::endl; +//TODO: +/* auto indexIbo = device.createIndexBuffer(); indexIbo->uploadData( @@ -390,23 +392,29 @@ std::array M2Geom::createDynamicVao( result[i] = bufferBindings; } + return result; + */ + + return {nullptr, nullptr, nullptr, nullptr}; } -HGVertexBufferBindings M2Geom::getVAO(const HGDevice& device, SkinGeom *skinGeom) { +HGVertexBufferBindings M2Geom::getVAO(const HMapSceneBufferCreate &sceneRenderer, SkinGeom *skinGeom) { HGVertexBufferBindings bufferBindings = nullptr; if (vaoMap.find(skinGeom) != vaoMap.end()) { bufferBindings = vaoMap.at(skinGeom); } else { - HGVertexBuffer vboBuffer = this->getVBO(device); + HGVertexBuffer vboBuffer = this->getVBO(sceneRenderer); if (vboBuffer == nullptr) { vaoMap[skinGeom] = nullptr; return nullptr; } - HGIndexBuffer iboBuffer = skinGeom->getIBO(device); + HGIndexBuffer iboBuffer = skinGeom->getIBO(sceneRenderer); //2. Create buffer binding and fill it + //TODO: + /* bufferBindings = device->createVertexBufferBindings(); bufferBindings->setIndexBuffer(iboBuffer); @@ -418,6 +426,7 @@ HGVertexBufferBindings M2Geom::getVAO(const HGDevice& device, SkinGeom *skinGeom bufferBindings->save(); vaoMap[skinGeom] = bufferBindings; + */ } return bufferBindings; diff --git a/wowViewerLib/src/engine/geometry/m2Geom.h b/wowViewerLib/src/engine/geometry/m2Geom.h index db2f10b3b..ce0008942 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.h +++ b/wowViewerLib/src/engine/geometry/m2Geom.h @@ -35,8 +35,8 @@ class M2Geom : public PersistentFile { } void process(HFileContent m2File, const std::string &fileName) override; - HGVertexBuffer getVBO(const HGDevice &device); - HGVertexBufferBindings getVAO(const HGDevice& device, SkinGeom *skinGeom); + HGVertexBuffer getVBO(const HMapSceneBufferCreate &sceneRenderer); + HGVertexBufferBindings getVAO(const HMapSceneBufferCreate &sceneRenderer, SkinGeom *skinGeom); std::array createDynamicVao(IDevice &device, std::array &dynVBOs, SkinGeom *skinGeom, M2SkinSection *skinSection); void loadLowPriority(const HApiContainer& m_api, uint32_t animationId, uint32_t subAnimationId); @@ -59,8 +59,8 @@ class M2Geom : public PersistentFile { std::vector txacMParticle = {}; int m_skid = -1; - WaterFallDataV3 *m_wfv3 = 0; - WaterFallDataV3 *m_wfv1 = 0; + WaterFallDataV3 *m_wfv3 = nullptr; + WaterFallDataV3 *m_wfv1 = nullptr; private: diff --git a/wowViewerLib/src/engine/geometry/skinGeom.cpp b/wowViewerLib/src/engine/geometry/skinGeom.cpp index 85e90bb24..23388dfb7 100644 --- a/wowViewerLib/src/engine/geometry/skinGeom.cpp +++ b/wowViewerLib/src/engine/geometry/skinGeom.cpp @@ -21,19 +21,6 @@ void SkinGeom::process(HFileContent skinFile, const std::string &fileName) { fsStatus = FileStatus::FSLoaded; } -HGIndexBuffer SkinGeom::getIBO(const HGDevice &device) { - if (indexVbo == nullptr) { - auto indicies = generateIndexBuffer(); - - indexVbo = device->createIndexBuffer(); - indexVbo->uploadData( - &indicies[0], - indicies.size() * sizeof(uint16_t)); - } - - return indexVbo; -} - void SkinGeom::fixShaderIdBasedOnBlendOverride(M2Data *m2File) { M2SkinProfile* skinFileData = this->m_skinData; @@ -212,14 +199,28 @@ void SkinGeom::fixShaderIdBasedOnLayer(M2Data *m2File) { */ } -std::vector SkinGeom::generateIndexBuffer() { +void SkinGeom::generateIndexBuffer(std::vector &buffer) { int indiciesLength = this->m_skinData->indices.size; - std::vector indicies = std::vector(indiciesLength); + buffer = std::vector(indiciesLength); for (int i = 0; i < indiciesLength; i++) { - indicies[i] = *this->m_skinData->vertices.getElement(*this->m_skinData->indices.getElement(i)); + buffer[i] = *this->m_skinData->vertices.getElement(*this->m_skinData->indices.getElement(i)); + } +} + +#ifndef WOWLIB_EXCLUDE_RENDERER +HGIndexBuffer SkinGeom::getIBO(const HMapSceneBufferCreate &renderer) { + if (m_IBO == nullptr) { + std::vector indicies; + generateIndexBuffer(indicies); + + m_IBO = renderer->createM2IndexBuffer(indicies.size() * sizeof(uint16_t)); + m_IBO->uploadData( + &indicies[0], + indicies.size() * sizeof(uint16_t)); } - return indicies; + return m_IBO; } +#endif \ No newline at end of file diff --git a/wowViewerLib/src/engine/geometry/skinGeom.h b/wowViewerLib/src/engine/geometry/skinGeom.h index b73677c20..2ca4d15fc 100644 --- a/wowViewerLib/src/engine/geometry/skinGeom.h +++ b/wowViewerLib/src/engine/geometry/skinGeom.h @@ -8,7 +8,10 @@ #include #include "../persistance/header/skinFileHeader.h" #include "../persistance/header/M2FileHeader.h" -#include "../../gapi/interface/IDevice.h" + +#ifndef WOWLIB_EXCLUDE_RENDERER +#include "../../renderer/mapScene/IMapSceneBufferCreate.h" +#endif class SkinGeom : public PersistentFile { public: @@ -16,9 +19,7 @@ class SkinGeom : public PersistentFile { SkinGeom(int fileDataId){}; void process(HFileContent skinFile, const std::string &fileName) override; - HGIndexBuffer getIBO(const HGDevice &device); - - std::vector generateIndexBuffer(); + void generateIndexBuffer(std::vector &buffer); M2SkinProfile * getSkinData(){ if (fsStatus == FileStatus::FSLoaded) {return m_skinData;} else {return nullptr;}}; @@ -27,12 +28,17 @@ class SkinGeom : public PersistentFile { HFileContent m2Skin; M2SkinProfile *m_skinData = nullptr; - HGIndexBuffer indexVbo = HGIndexBuffer(nullptr); bool m_fixed = false; + void fixShaderIdBasedOnLayer(M2Data *m2Data); + void fixShaderIdBasedOnBlendOverride(M2Data *m2Data); +#ifndef WOWLIB_EXCLUDE_RENDERER +public: + HGIndexBuffer getIBO(const HMapSceneBufferCreate &renderer); +private: + //This is being stored here, to prevent from IBO being created for same skin several times + HGIndexBuffer m_IBO = nullptr; +#endif - void fixShaderIdBasedOnLayer(M2Data *m2Filem2File); - - void fixShaderIdBasedOnBlendOverride(M2Data *m2File); }; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index f6dd6c896..80aed2501 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -304,14 +304,15 @@ void WmoGroupGeom::fixColorVertexAlpha(SMOHeader *mohd) { } -HGVertexBuffer WmoGroupGeom::getVBO(const HGDevice &device) { +HGVertexBuffer WmoGroupGeom::getVBO(const HMapSceneBufferCreate &sceneRenderer) { if (combinedVBO == nullptr) { - combinedVBO = device->createVertexBuffer(); + combinedVBO = sceneRenderer->createWMOVertexBuffer(verticesLen * sizeof(WMOVertex)); + + WMOVertex * buffer = static_cast(combinedVBO->getPointer()); static const C2Vector c2ones = C2Vector(mathfu::vec2(1.0, 1.0)); static const C3Vector c3zeros = C3Vector(mathfu::vec3(0, 0, 0)); - std::vector buffer (verticesLen); for (int i = 0; i < verticesLen; i++) { WMOVertex &format = buffer[i]; format.pos = verticles[i]; @@ -372,9 +373,9 @@ HGVertexBuffer WmoGroupGeom::getVBO(const HGDevice &device) { return combinedVBO; } -HGIndexBuffer WmoGroupGeom::getIBO(const HGDevice &device) { +HGIndexBuffer WmoGroupGeom::getIBO(const HMapSceneBufferCreate &sceneRenderer) { if (indexVBO == nullptr) { - indexVBO = device->createIndexBuffer(); + indexVBO = sceneRenderer->createWMOIndexBuffer(indicesLen * sizeof(uint16_t)); indexVBO->uploadData( &indicies[0], indicesLen * sizeof(uint16_t)); @@ -395,28 +396,17 @@ static const std::array staticWMOBindings = {{ {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; +PACK( +struct LiquidVertexFormat { + mathfu::vec4_packed pos_transp; + mathfu::vec2_packed uv; +}); + static GBufferBinding staticWMOWaterBindings[2] = { - {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, 24, 0}, - {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 24, 16} + {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, + {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)} }; -HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HGDevice &device) { - if (vertexBufferBindings == nullptr) { - vertexBufferBindings = device->createVertexBufferBindings(); - vertexBufferBindings->setIndexBuffer(getIBO(device)); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = getVBO(device); - - vertexBinding.bindings = std::vector(staticWMOBindings.begin(), staticWMOBindings.end()); - - vertexBufferBindings->addVertexBufferBinding(vertexBinding); - vertexBufferBindings->save(); - } - - return vertexBufferBindings; -} - int WmoGroupGeom::getLegacyWaterType(int a) { a = a + 1; @@ -446,14 +436,12 @@ int WmoGroupGeom::getLegacyWaterType(int a) { } HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &device) { + return nullptr; + //TODO: + /* if (vertexWaterBufferBindings == nullptr) { if (this->m_mliq == nullptr) return nullptr; - PACK( - struct LiquidVertexFormat { - mathfu::vec4_packed pos_transp; - mathfu::vec2_packed uv; - }); std::vector lVertices; // lVertices.reserve((m_mliq->xverts)*(m_mliq->yverts)*3); @@ -481,8 +469,7 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi std::vector iboBuffer; - for (int j = 0; j < m_mliq->ytiles; j++) - { + for (int j = 0; j < m_mliq->ytiles; j++) { for (int i = 0; i < m_mliq->xtiles; i++) { int tileIndex = j*m_mliq->xtiles + i; assert(tileIndex < m_liquidTiles_len); @@ -494,8 +481,6 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi liquidType = getLegacyWaterType(tile.legacyLiquidType); } - - int16_t vertindexes[4] = { (int16_t) (j * (m_mliq->xverts) + i), (int16_t) (j * (m_mliq->xverts) + i + 1), @@ -540,4 +525,5 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi } return vertexWaterBufferBindings; + */ } diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index 255663bce..5058c14b2 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -10,7 +10,7 @@ #include "../persistance/header/wmoFileHeader.h" #include "../persistance/helper/ChunkFileReader.h" #include "../../include/sharedFile.h" -#include "../../gapi/interface/IDevice.h" +#include "../../renderer/mapScene/IMapSceneBufferCreate.h" PACK( struct WMOVertex { @@ -40,7 +40,6 @@ class WmoGroupGeom : public PersistentFile { bool hasWater() const {return m_mliq != nullptr; }; - HGVertexBufferBindings getVertexBindings(const HGDevice &device); HGVertexBufferBindings getWaterVertexBindings(const HGDevice &device); int getFileDataId() const {return m_fileDataId;} @@ -49,8 +48,8 @@ class WmoGroupGeom : public PersistentFile { std::function m_attenuateFunc; int getLegacyWaterType(int a); - HGVertexBuffer getVBO(const HGDevice &device); - HGIndexBuffer getIBO(const HGDevice &device); + HGVertexBuffer getVBO(const HMapSceneBufferCreate &sceneRenderer); + HGIndexBuffer getIBO(const HMapSceneBufferCreate &sceneRenderer); public: std::string m_fileName = ""; int m_fileDataId = 0; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 32fa572ed..576a2102f 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -93,8 +93,11 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat //Create Buffers for (int k = 0; k < 4; k++) { + //TODO: + /* frame[k].m_indexVBO = device->createIndexBuffer(); frame[k].m_bufferVBO = device->createVertexBuffer(); + */ frame[k].m_bindings = device->createVertexBufferBindings(); frame[k].m_bindings->setIndexBuffer(frame[k].m_indexVBO); @@ -112,7 +115,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat auto &material = materials[i]; auto &textureIndex = textureIndicies[i]; - HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", nullptr); + HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); //Create mesh gMeshTemplate meshTemplate(frame[k].m_bindings, shaderPermutation); @@ -133,8 +136,6 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat meshTemplate.end = 0; meshTemplate.element = DrawElementMode::TRIANGLE_STRIP; - - meshTemplate.textureCount = 1; meshTemplate.texture = std::vector(1, nullptr); HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); @@ -172,7 +173,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat }); - frame[k].m_meshes.push_back(device->createParticleMesh(meshTemplate)); + frame[k].m_meshes.push_back(device->createMesh(meshTemplate)); } } } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 6e3e090c6..3d1f2e1b8 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -21,11 +21,11 @@ HGIndexBuffer ParticleEmitter::m_indexVBO = nullptr; static const size_t MAX_PARTICLES_PER_EMITTER = 2000; static GBufferBinding staticM2ParticleBindings[5] = { - {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 13*4, 0 }, - {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, 13*4, 12}, - {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, 13*4, 28}, - {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, 13*4, 36}, - {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, 13*4, 44}, + {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, + {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, + {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, + {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, + {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, }; @@ -217,7 +217,6 @@ ParticleEmitter::ParticleEmitter(HApiContainer api, M2Particle *particle, M2Obje } selectShaderId(); - createMesh(); } void ParticleEmitter::selectShaderId() { @@ -269,7 +268,8 @@ void ParticleEmitter::createMesh() { HGDevice device = m_api->hDevice; if (m_indexVBO == nullptr) { - m_indexVBO = device->createIndexBuffer(); + //TODO: + //m_indexVBO = device->createIndexBuffer(); int vo = 0; for (int i = 0; i < MAX_PARTICLES_PER_EMITTER; i++) { szIndexBuff.push_back(vo + 0); @@ -285,7 +285,8 @@ void ParticleEmitter::createMesh() { //Create Buffers for (int i = 0; i < 4; i++) { - frame[i].m_bufferVBO = device->createVertexBufferDynamic(10 * sizeof(ParticleBuffStructQuad)); + //TODO: +// frame[i].m_bufferVBO = device->createVertexBufferDynamic(10 * sizeof(ParticleBuffStructQuad)); frame[i].m_bindings = device->createVertexBufferBindings(); frame[i].m_bindings->setIndexBuffer(m_indexVBO); @@ -300,7 +301,7 @@ void ParticleEmitter::createMesh() { //Get shader - HGShaderPermutation shaderPermutation = device->getShader("m2ParticleShader", nullptr); + HGShaderPermutation shaderPermutation = device->getShader("m2ParticleShader", "m2ParticleShader", nullptr); //Create mesh gMeshTemplate meshTemplate(frame[i].m_bindings, shaderPermutation); @@ -336,8 +337,7 @@ void ParticleEmitter::createMesh() { meshTemplate.texture[1] = device->createBlpTexture(tex1, true, true); meshTemplate.texture[2] = device->createBlpTexture(tex2, true, true); } - meshTemplate.texture.resize(3); - meshTemplate.textureCount = (multitex) ? 3 : 1; + meshTemplate.texture.resize((multitex) ? 3 : 1); meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); meshTemplate.ubo[1] = nullptr; @@ -364,7 +364,7 @@ void ParticleEmitter::createMesh() { blockPS.uBlendMode = static_cast(l_blendMode); }); - frame[i].m_mesh = device->createParticleMesh(meshTemplate); + frame[i].m_mesh = device->createMesh(meshTemplate); } } @@ -373,13 +373,6 @@ void ParticleEmitter::createMesh() { bool ParticleEmitter::randTableInited = false; float ParticleEmitter::RandTable[128] = {}; -const mathfu::mat4 strangeMat = { - 1.0f, 0, 0, 0, - 0, 1.0f, 0, 0, - 0, 0, 1.0f, 0, - 0, 0, -1.0f, 0.0 -}; - void ParticleEmitter::calculateQuadToViewEtc(mathfu::mat4 *a1, mathfu::mat4 &translatedViewMat) { if ((this->m_data->old.flags & 0x10)) { s_particleToView = translatedViewMat * m_emitterModelMatrix ; @@ -451,6 +444,11 @@ void ParticleEmitter::InternalUpdate(animTime_t delta) { void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathfu::vec3 invMatTransl, mathfu::mat4 *frameOfReference, mathfu::mat4 &viewMatrix) { if (getGenerator() == nullptr) return; + //TODO: +// if () { +// createMesh(); +// } + // if (this->particles.size() <= 0 && !isEnabled) return; m_prevPosition = m_emitterModelMatrix.TranslationVector3D(); @@ -676,9 +674,10 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { maxFutureSize *= 2; } - vboBufferDynamic->resize(maxFutureSize); + //TODO: + //vboBufferDynamic->resize(maxFutureSize); - szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointerForModification(); + szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); szVertexCnt = 0; for (int i = 0; i < particles.size(); i++) { CParticle2 &p = this->particles[i]; @@ -692,29 +691,6 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { } } } - -// std::sort(szVertexBuf.begin(), szVertexBuf.end(), [](const ParticleBuffStructQuad &a, const ParticleBuffStructQuad &b) -> bool { -// return -// fminf( -// fminf( -// fminf( -// a.particle[0].position.z, -// a.particle[1].position.z -// ), -// a.particle[2].position.z -// ), -// a.particle[0].position.z -// ) < fminf( -// fminf( -// fminf( -// b.particle[0].position.z, -// b.particle[1].position.z -// ), -// b.particle[2].position.z -// ), -// b.particle[0].position.z -// ); -// }); } int ParticleEmitter::buildVertex1(CParticle2 &p, ParticlePreRenderData &particlePreRenderData) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 138212dd1..7441c859f 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -121,8 +121,9 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st auto hDevice = apiContainer->hDevice; - portalPointsFrame.m_indexVBO = hDevice->createIndexBuffer(); - portalPointsFrame.m_bufferVBO = hDevice->createVertexBuffer(); + //TODO: +// portalPointsFrame.m_indexVBO = hDevice->createIndexBuffer(); +// portalPointsFrame.m_bufferVBO = hDevice->createVertexBuffer(); portalPointsFrame.m_bindings = hDevice->createVertexBufferBindings(); portalPointsFrame.m_bindings->setIndexBuffer(portalPointsFrame.m_indexVBO); @@ -139,7 +140,7 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st portalPointsFrame.m_bufferVBO->uploadData((void *) verticles.data(), (int) (verticles.size() * sizeof(float))); { - HGShaderPermutation shaderPermutation = hDevice->getShader("drawPortalShader", nullptr); + HGShaderPermutation shaderPermutation = hDevice->getShader("drawPortalShader", "drawPortalShader", nullptr); //Create mesh gMeshTemplate meshTemplate(portalPointsFrame.m_bindings, shaderPermutation); @@ -159,8 +160,6 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st meshTemplate.end = indiciesArray.size(); meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.textureCount = 0; - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); meshTemplate.ubo[1] = nullptr; meshTemplate.ubo[2] = nullptr; @@ -175,7 +174,7 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st }); - transparentMeshes.push_back(hDevice->createParticleMesh(meshTemplate)); + transparentMeshes.push_back(hDevice->createMesh(meshTemplate)); } } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 2f98d45a8..1826041ee 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -318,6 +318,8 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid HGDevice device = m_api->hDevice; + //TODO: + /* auto waterIBO = device->createIndexBuffer(); waterIBO->uploadData( indexBuffer.data(), @@ -329,6 +331,7 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid vertexBuffer.size() * sizeof(LiquidVertexFormat) ); + auto vertexWaterBufferBindings = device->createVertexBufferBindings(); vertexWaterBufferBindings->setIndexBuffer(waterIBO); @@ -341,6 +344,7 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid vertexWaterBufferBindings->save(); + //Create mesh(es) HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterShader", nullptr); @@ -353,7 +357,7 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.textureCount = 1; + meshTemplate.texture = {nullptr}; if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); meshTemplate.texture[0] = m_api->hDevice->createBlpTexture(htext, true, true); @@ -397,8 +401,9 @@ HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquid }); auto mesh = m_api->hDevice->createMesh(meshTemplate); - mesh->setSortDistance(0); return mesh; + */ + return nullptr; } void AdtObject::loadWater() { if (m_adtFile->mH2OHeader == nullptr) return; @@ -524,14 +529,15 @@ void AdtObject::createVBO() { /* 1.3 Make combinedVbo */ HGDevice device = m_api->hDevice; - combinedVbo = device->createVertexBuffer(); - combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(AdtVertex)); + //TODO: +// combinedVbo = device->createVertexBuffer(); +// combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(AdtVertex)); /* 2. Strips */ if (m_adtFile->strips.size() > 0) { - stripIBO = device->createIndexBuffer(); - stripIBO->uploadData(m_adtFile->strips.data(), m_adtFile->strips.size() * sizeof(int16_t)); +// stripIBO = device->createIndexBuffer(); +// stripIBO->uploadData(m_adtFile->strips.data(), m_adtFile->strips.size() * sizeof(int16_t)); adtVertexBindings = device->createVertexBufferBindings(); adtVertexBindings->setIndexBuffer(stripIBO); @@ -564,12 +570,14 @@ void AdtObject::createVBO() { vboLod.push_back((float) i); } + //TODO: + /* heightVboLod = device->createVertexBuffer(); heightVboLod->uploadData(&vboLod[0], vboLod.size()*sizeof(float)); /* 2. Index buffer */ - stripVBOLod = device->createIndexBuffer(); - stripVBOLod->uploadData(&m_adtFileLod->mvli_indicies[0], m_adtFileLod->mvli_len * sizeof(int16_t)); +// stripVBOLod = device->createIndexBuffer(); +// stripVBOLod->uploadData(&m_adtFileLod->mvli_indicies[0], m_adtFileLod->mvli_len * sizeof(int16_t)); lodVertexBindings = device->createVertexBufferBindings(); @@ -643,7 +651,7 @@ void AdtObject::createMeshes() { //if (m_adtFile->mapTile[i].nLayers <= 0) continue; bool noLayers = m_adtFileTex->mcnkStructs[i].mcly == nullptr || m_adtFileTex->mcnkStructs[i].mclyCnt <= 0; - HGShaderPermutation hgShaderPermutation = device->getShader("adtShader", nullptr); + HGShaderPermutation hgShaderPermutation = device->getShader("adtShader", "adtShader", nullptr); gMeshTemplate aTemplate(adtVertexBindings, hgShaderPermutation); aTemplate.meshType = MeshType::eAdtMesh; @@ -663,9 +671,7 @@ void AdtObject::createMeshes() { aTemplate.ubo[3] = adtWideBlockPS; aTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockPS)); - aTemplate.textureCount = 9; - - aTemplate.texture = std::vector(aTemplate.textureCount, nullptr); + aTemplate.texture = std::vector(9, nullptr); int chunkIndex = i; aTemplate.ubo[4]->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { @@ -778,7 +784,6 @@ void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaq transparentMeshes.reserve(transparentMeshes.size() + waterMeshes.size()); for (int i = 0; i < meshCount; i++) { if (adtRes.drawChunk[i] && (adtMeshes[i] != nullptr)) { - adtMeshes[i]->setRenderOrder(renderOrder); opaqueMeshes.push_back(adtMeshes[i]); } if (adtRes.drawWaterChunk[i]) { diff --git a/wowViewerLib/src/engine/objects/iMapApi.h b/wowViewerLib/src/engine/objects/iMapApi.h index de8d26022..0b36d93c3 100644 --- a/wowViewerLib/src/engine/objects/iMapApi.h +++ b/wowViewerLib/src/engine/objects/iMapApi.h @@ -8,6 +8,8 @@ class IMapApi; #include "m2/m2Object.h" #include "wmo/wmoObject.h" +#include "../../include/database/dbStructs.h" +#include "../../include/config.h" struct StateForConditions { int currentAreaId = 0; diff --git a/wowViewerLib/src/engine/objects/iScene.h b/wowViewerLib/src/engine/objects/iScene.h index 171c06158..e357270ef 100644 --- a/wowViewerLib/src/engine/objects/iScene.h +++ b/wowViewerLib/src/engine/objects/iScene.h @@ -10,6 +10,7 @@ class IScene { public: virtual ~IScene() = 0; + }; typedef std::shared_ptr HScene; diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index 5f0d5fb81..bcd2be59b 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -6,9 +6,8 @@ #define WOWVIEWERLIB_IWMOAPI_H #include -#include "m2/m2Object.h" #include "../engineClassList.h" -#include +#include "m2/m2Object.h" struct PortalInfo_t { std::vector sortedVericles; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 4091eb9e7..c2819da9c 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1253,9 +1253,10 @@ bool M2Object::prepearMaterial(M2MaterialInst &materialData, int batchIndex) { void M2Object::createBoundingBoxMesh() { //Create bounding box mesh - HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", nullptr); + HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", nullptr); - gMeshTemplate meshTemplate(m_api->hDevice->getBBVertexBinding(), boundingBoxshaderPermutation); + //TODO: + gMeshTemplate meshTemplate(/*m_api->hDevice->getBBVertexBinding()*/ nullptr, boundingBoxshaderPermutation); meshTemplate.depthWrite = false; meshTemplate.depthCulling = true; @@ -1267,7 +1268,6 @@ void M2Object::createBoundingBoxMesh() { meshTemplate.blendMode = EGxBlendEnum ::GxBlend_Alpha; meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.textureCount = 0; HGUniformBufferChunk bbBlockVS = m_api->hDevice->createUniformBufferChunk(sizeof(bbModelWideBlockVS)); @@ -1303,10 +1303,6 @@ void M2Object::createBoundingBoxMesh() { }); boundingBoxMesh = m_api->hDevice->createMesh(meshTemplate); - boundingBoxMesh->setRenderOrder(1000); - - for (auto &a : occlusionQueries) - a = m_api->hDevice->createQuery(boundingBoxMesh); } bool M2Object::checkifBonesAreInRange(M2SkinProfile *skinProfile, M2SkinSection *skinSection) { @@ -1349,7 +1345,7 @@ float wfv_convert(float value, int16_t random) { } HGM2Mesh M2Object::createWaterfallMesh() { - HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterfallShader", nullptr); + HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterfallShader", "waterfallShader", nullptr); gMeshTemplate meshTemplate(bufferBindings, shaderPermutation); @@ -1376,7 +1372,6 @@ HGM2Mesh M2Object::createWaterfallMesh() { HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; meshTemplate.texture.resize(5); - meshTemplate.textureCount = 5; meshTemplate.texture[0] = getTexture(0); //mask meshTemplate.texture[1] = getTexture(1); //whiteWater meshTemplate.texture[2] = getTexture(2); //noise @@ -1430,13 +1425,10 @@ HGM2Mesh M2Object::createWaterfallMesh() { }); //Make mesh - auto hmesh = m_api->hDevice->createM2Mesh(meshTemplate); - hmesh->setM2Object(this); - hmesh->setLayer(0); - hmesh->setPriorityPlane(0); - hmesh->setQuery(nullptr); + //TODO: + auto hmesh = m_api->hDevice->createMesh(meshTemplate); - return hmesh; + return nullptr; } void M2Object::createMeshes() { @@ -1554,7 +1546,7 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti } else { cacheRecord.boneInfluences = skinSection->boneCount > 0 ? 1 : 0; } - HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", &cacheRecord); + HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", "m2Shader", &cacheRecord); gMeshTemplate meshTemplate(finalBufferBindings, shaderPermutation); @@ -1580,7 +1572,7 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; meshTemplate.texture.resize(4); - meshTemplate.textureCount = 4; + for (int j = 0; j < material.textureCount; j++) { meshTemplate.texture[j] = material.textures[j]; } @@ -1592,13 +1584,11 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti meshTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::meshWideBlockPS)); //Make mesh - auto hmesh = m_api->hDevice->createM2Mesh(meshTemplate); - hmesh->setM2Object(this); - hmesh->setLayer(m2Batch->materialLayer); - hmesh->setPriorityPlane(m2Batch->priorityPlane); - hmesh->setQuery(nullptr); + //TODO: + auto hmesh = m_api->hDevice->createMesh(meshTemplate); + - return hmesh; + return nullptr; } void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { @@ -1619,7 +1609,6 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorm_meshForcedTranspArray[i]; } - mesh->setRenderOrder(renderOrder); if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { @@ -1631,7 +1620,6 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorhDevice->getUpdateFrameNumber(); int frame = 0; HGParticleMesh mesh = dynMesh[frame].m_mesh; - mesh->setRenderOrder(renderOrder); if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { @@ -1918,7 +1906,8 @@ void M2Object::createVertexBindings() { HGDevice device = m_api->hDevice; //2. Create buffer binding and fill it - bufferBindings = m_m2Geom->getVAO(device, m_skinGeom.get()); + //TODO: + //bufferBindings = m_m2Geom->getVAO(device, m_skinGeom.get()); //3. Create model wide uniform buffer // vertexModelWideUniformBuffer = device->createUniformBuffer(sizeof(mathfu::mat4) * (m_m2Geom->m_m2Data->bones.size + 1)); @@ -1978,7 +1967,7 @@ void M2Object::updateDynamicMeshes() { auto m2Batch = skinProfile->batches[dynMeshData.batchIndex]; auto skinSection = skinProfile->skinSections[m2Batch->skinSectionIndex]; - M2Vertex *overrideVertexes = (M2Vertex *)dynMeshData.m_bufferVBO->getPointerForModification(); + M2Vertex *overrideVertexes = (M2Vertex *)dynMeshData.m_bufferVBO->getPointer(); for (int vertIndex = skinSection->vertexStart; vertIndex < (skinSection->vertexStart + skinSection->vertexCount); ++vertIndex) { @@ -2005,7 +1994,8 @@ void M2Object::updateDynamicMeshes() { overrideVert.bone_indices[3] = 0; } - dynMeshData.m_bufferVBO->save(skinSection->vertexCount*sizeof(M2Vertex)); + //TODO: + //dynMeshData.m_bufferVBO->save(skinSection->vertexCount*sizeof(M2Vertex)); // std::cout << "Saved " << skinSection->vertexCount << " vertices " << "at update frame =" << frameNum << std::endl; } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index fe0fdfba3..c17147e80 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -6,6 +6,7 @@ #define WOWVIEWERLIB_M2OBJECT_H class M2Object; +class M2ObjectListContainer; #define _USE_MATH_DEFINES #include @@ -61,7 +62,7 @@ class M2Object { int batchIndex = -1; HGVertexBufferDynamic m_bufferVBO = nullptr; HGVertexBufferBindings m_bindings = nullptr; - HGParticleMesh m_mesh = nullptr; + HGM2Mesh m_mesh = nullptr; }; private: @@ -90,8 +91,7 @@ class M2Object { HGUniformBufferChunk fragmentModelWideUniformBuffer = nullptr; HGMesh boundingBoxMesh = nullptr; - std::array occlusionQueries = {nullptr}; - + mathfu::vec4 m_ambientColorOverride; bool m_setAmbientColor = false; @@ -309,18 +309,6 @@ inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { return object->getAABB(); } - -struct M2ObjectHasher -{ - size_t operator()(const std::shared_ptr& val)const - { - return std::hash>()(val); - } -}; - -//typedef oneapi::tbb::concurrent_unordered_set, M2ObjectHasher> M2ObjectListContainer; -//typedef std::unordered_set> M2ObjectListContainer; - class M2ObjectListContainer { private: std::vector> candidates; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 44334f98c..4cd98c732 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -261,6 +261,8 @@ std::array skyConusIBO = { }; HGVertexBufferBindings createSkyBindings(IDevice *device) { + //TODO: + /* auto skyIBO = device->createIndexBuffer(); skyIBO->uploadData( skyConusIBO.data(), @@ -282,8 +284,9 @@ HGVertexBufferBindings createSkyBindings(IDevice *device) { skyBindings->addVertexBufferBinding(vertexBinding); skyBindings->save(); +*/ - return skyBindings; + return nullptr; } Map::Map(HApiContainer api, int mapId, std::string mapName) { @@ -332,7 +335,7 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config //TODO: Pass m_skyConeAlpha to fragment shader ///2. Create mesh - auto shader = device->getShader("skyConus", nullptr); + auto shader = device->getShader("skyConus", "skyConus", nullptr); gMeshTemplate meshTemplate(skyBindings, shader); meshTemplate.meshType = MeshType::eGeneralMesh; meshTemplate.depthWrite = false; @@ -343,8 +346,6 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config meshTemplate.texture.resize(0); - meshTemplate.textureCount = 0; - meshTemplate.ubo[0] = nullptr; meshTemplate.ubo[1] = nullptr; meshTemplate.ubo[2] = skyVs; @@ -366,7 +367,7 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config return hmesh; } -void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { +void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { // std::cout << "Map::checkCulling finished called" << std::endl; // std::cout << "m_wdtfile->getIsLoaded() = " << m_wdtfile->getIsLoaded() << std::endl; cullCreateVarsCounter.beginMeasurement(); @@ -1382,6 +1383,8 @@ void Map::doPostLoad(const HMapRenderPlan &renderPlan) { // std::cout << "indexBuffer.size = " << indexBuffer.size() << std::endl; +//TODO: +/* auto quadIBO = m_api->hDevice->createIndexBuffer(); quadIBO->uploadData( indexBuffer.data(), @@ -1403,6 +1406,7 @@ void Map::doPostLoad(const HMapRenderPlan &renderPlan) { quadBindings->addVertexBufferBinding(vertexBinding); quadBindings->save(); + */ } if (skyMesh == nullptr) { auto skyMeshBinding = createSkyBindings(m_api->hDevice.get()); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index ae41b2454..25f81531b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -202,7 +202,7 @@ class Map : public IScene, public IMapApi { // std::cout << "Map destroyed " << std::endl; }; - void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); + void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); void setMandatoryADTs(std::vector> &mandatoryADTs) { m_mandatoryADT = mandatoryADTs; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 4f7016f78..aa0805f50 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -410,7 +410,8 @@ void WmoGroupObject::createMeshes() { PointerChecker &materials = m_wmoApi->getMaterials(); HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getVertexBindings(device); + //TODO: + HGVertexBufferBindings binding = nullptr; //m_geom->getVertexBindings(device); vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); @@ -469,7 +470,7 @@ void WmoGroupObject::createMeshes() { cacheRecord.unFogged = true; cacheRecord.unShadowed = true; - HGShaderPermutation shaderPermutation = device->getShader("wmoShader", &cacheRecord); + HGShaderPermutation shaderPermutation = device->getShader("wmoShader", "wmoShader", &cacheRecord); gMeshTemplate meshTemplate(binding, shaderPermutation); @@ -499,21 +500,20 @@ void WmoGroupObject::createMeshes() { meshTemplate.texture[1] = texture2; meshTemplate.texture[2] = texture3; - meshTemplate.textureCount = 9; if (pixelShader == (int)WmoPixelShader::MapObjParallax) { meshTemplate.texture[3] = m_wmoApi->getTexture(material.color_2, false); meshTemplate.texture[4] = m_wmoApi->getTexture(material.flags_2, false); meshTemplate.texture[5] = m_wmoApi->getTexture(material.runTimeData[0], false); + meshTemplate.texture.resize(6); } else if (pixelShader == (int)WmoPixelShader::MapObjUnkShader) { -// meshTemplate.texture.resize(9); -// meshTemplate.textureCount = 9; - meshTemplate.texture[3] = m_wmoApi->getTexture(material.color_2, false); meshTemplate.texture[4] = m_wmoApi->getTexture(material.flags_2, false); meshTemplate.texture[5] = m_wmoApi->getTexture(material.runTimeData[0], false); meshTemplate.texture[6] = m_wmoApi->getTexture(material.runTimeData[1], false); meshTemplate.texture[7] = m_wmoApi->getTexture(material.runTimeData[2], false); meshTemplate.texture[8] = m_wmoApi->getTexture(material.runTimeData[3], false); + } else { + meshTemplate.texture.resize(3); } @@ -641,7 +641,7 @@ void WmoGroupObject::createWaterMeshes() { shaderId = 0; } - HGShaderPermutation shaderPermutation = device->getShader("waterShader", nullptr); + HGShaderPermutation shaderPermutation = device->getShader("waterShader", "waterShader", nullptr); gMeshTemplate meshTemplate(binding, shaderPermutation); @@ -673,7 +673,7 @@ void WmoGroupObject::createWaterMeshes() { break; } } - meshTemplate.textureCount = 1; + if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); meshTemplate.texture[0] = m_api->hDevice->createBlpTexture(htext, true, true); @@ -1218,7 +1218,6 @@ void WmoGroupObject::setModelFileId(int fileId) { void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { if (!m_loaded) return; for (auto &i : this->m_meshArray) { - i->setRenderOrder(renderOrder); if (i->getIsTransparent()) { opaqueMeshes.push_back(i); } else { @@ -1227,7 +1226,6 @@ void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vecto } for (auto &i : this->m_waterMeshArray) { - i->setRenderOrder(renderOrder); transparentMeshes.push_back(i); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 3cbb60854..1b244d879 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -10,6 +10,7 @@ class WMOGroupListContainer; #include "../../persistance/header/wmoFileHeader.h" #include "../iWmoApi.h" +#include "../m2/m2Object.h" #include "../../../gapi/interface/meshes/IMesh.h" class WmoGroupObject { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index c15b11f39..eeab79280 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -21,6 +21,7 @@ class WmoGroupObject; #include "../iWmoApi.h" #include "../../persistance/header/wmoFileHeader.h" #include "../ViewsObjects.h" +#include "../../../include/database/dbStructs.h" class WmoObject : public IWmoApi { diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 7dd8fed0c..be8727441 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -8,12 +8,13 @@ class IVertexBuffer; class IVertexBufferDynamic; class IVertexBufferBindings; -class IIndexBuffer; +class IBuffer; class IUniformBuffer; class IUniformBufferChunk; class ITexture; class IShaderPermutation; class IMesh; +class IM2Mesh; class IDevice; class IGPUFence; class IFrameBuffer; @@ -27,15 +28,15 @@ class gMeshTemplate; #include #endif -typedef std::shared_ptr HGVertexBufferDynamic; -typedef std::shared_ptr HGVertexBuffer; -typedef std::shared_ptr HGIndexBuffer; +typedef std::shared_ptr HGVertexBufferDynamic; +typedef std::shared_ptr HGVertexBuffer; +typedef std::shared_ptr HGIndexBuffer; typedef std::shared_ptr HGVertexBufferBindings; -typedef std::shared_ptr HGUniformBuffer; +typedef std::shared_ptr HGUniformBuffer; typedef std::shared_ptr HGUniformBufferChunk; typedef std::shared_ptr HGShaderPermutation; typedef std::shared_ptr HGMesh; -typedef std::shared_ptr HGM2Mesh; +typedef std::shared_ptr HGM2Mesh; typedef std::shared_ptr HGParticleMesh; typedef std::shared_ptr HGOcclusionQuery; typedef std::shared_ptr HGTexture; @@ -46,11 +47,8 @@ typedef std::shared_ptr HFrameBuffer; #include "meshes/IM2Mesh.h" #include "IOcclusionQuery.h" #include "IShaderPermutation.h" -#include "buffers/IIndexBuffer.h" -#include "buffers/IVertexBuffer.h" -#include "buffers/IVertexBufferDynamic.h" +#include "buffers/IBuffer.h" #include "IVertexBufferBindings.h" -#include "buffers/IUniformBuffer.h" #include "buffers/IUniformBufferChunk.h" #include "../../engine/wowCommonClasses.h" #include "../../engine/texture/BlpTexture.h" @@ -143,12 +141,13 @@ enum class GDeviceType { class IDevice { public: + static constexpr uint8_t MAX_FRAMES_IN_FLIGHT = 3; + virtual ~IDevice() {}; virtual GDeviceType getDeviceType() = 0; virtual void initialize() = 0; - virtual void reset() = 0; virtual bool getIsAsynBuffUploadSupported() = 0; virtual int getMaxSamplesCnt() = 0; @@ -156,15 +155,7 @@ class IDevice { virtual void increaseFrameNumber() = 0; - virtual void bindProgram(IShaderPermutation *program) = 0; - - virtual void bindIndexBuffer(IIndexBuffer *buffer) = 0; - virtual void bindVertexBuffer(IVertexBuffer *buffer) = 0; - virtual void bindUniformBuffer(IUniformBuffer *buffer, int slot, int offset, int length) = 0; - virtual void bindVertexBufferBindings(IVertexBufferBindings *buffer) = 0; - - virtual void bindTexture(ITexture *texture, int slot) = 0; - + virtual void drawScenario() {}; virtual void startUpdateForNextFrame() {}; virtual void endUpdateForNextFrame() {}; @@ -184,20 +175,16 @@ class IDevice { virtual double getWaitForUpdate() {return 0;} public: - virtual HGShaderPermutation getShader(std::string shaderName, void *permutationDescriptor) = 0; + virtual HGShaderPermutation getShader(std::string shaderName, std::string fragmentName, void *permutationDescriptor) = 0; virtual HGPUFence createFence() = 0; - virtual HGUniformBuffer createUniformBuffer(size_t size) = 0; virtual HGUniformBufferChunk createUniformBufferChunk(size_t size, size_t realSize = 0) { HGUniformBufferChunk h_uniformBuffer; h_uniformBuffer.reset(new IUniformBufferChunk(size, realSize)); return h_uniformBuffer; }; - virtual HGVertexBufferDynamic createVertexBufferDynamic(size_t size) = 0; - virtual HGVertexBuffer createVertexBuffer() = 0; - virtual HGIndexBuffer createIndexBuffer() = 0; virtual HGVertexBufferBindings createVertexBufferBindings() = 0; //Creates or receives framebuffer and tells it would be occupied for frameNumber frames virtual HFrameBuffer createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) = 0; @@ -205,26 +192,10 @@ class IDevice { virtual HGTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) = 0; virtual HGTexture createTexture(bool xWrapTex, bool yWrapTex) = 0; virtual HGTexture getWhiteTexturePixel() = 0; - virtual HGTexture getBlackTexturePixel() {return nullptr;}; + virtual HGTexture getBlackTexturePixel() = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate) = 0; - virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate) = 0; - virtual HGParticleMesh createParticleMesh(gMeshTemplate &meshTemplate) = 0; - - virtual HGOcclusionQuery createQuery(HGMesh boundingBoxMesh) = 0; - - virtual HGVertexBufferBindings getBBVertexBinding() = 0; - virtual HGVertexBufferBindings getBBLinearBinding() = 0; - virtual std::string loadShader(std::string fileName, IShaderType shaderType) = 0; - virtual void clearScreen() = 0; - virtual void setClearScreenColor(float r, float g, float b) = 0; - virtual void setViewPortDimensions(float x, float y, float width, float height) = 0; - virtual void setInvertZ(bool value) = 0; - - virtual void beginFrame() = 0; - virtual void commitFrame() = 0; virtual void shrinkData() {}; - virtual bool wasTexturesUploaded() = 0; static std::string insertAfterVersion(std::string &glslShaderString, std::string stringToPaste); virtual void addDeallocationRecord(std::function callback) {}; diff --git a/wowViewerLib/src/gapi/interface/IRendererProxy.h b/wowViewerLib/src/gapi/interface/IRendererProxy.h new file mode 100644 index 000000000..edc02becc --- /dev/null +++ b/wowViewerLib/src/gapi/interface/IRendererProxy.h @@ -0,0 +1,13 @@ +// +// Created by Deamon on 16.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IRENDERERPROXY_H +#define AWEBWOWVIEWERCPP_IRENDERERPROXY_H + +class IRendererProxy { +public: + virtual ~IRendererProxy() = 0; +}; + +#endif //AWEBWOWVIEWERCPP_IRENDERERPROXY_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h new file mode 100644 index 000000000..77f92a215 --- /dev/null +++ b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h @@ -0,0 +1,17 @@ +// +// Created by Deamon on 8/27/2018. +// + +#ifndef AWEBWOWVIEWERCPP_IBUFFER_H +#define AWEBWOWVIEWERCPP_IBUFFER_H +class IBuffer { +public: + virtual ~IBuffer() = default; + virtual void uploadData(void *, int length) = 0; + virtual void subUploadData(void *, int offset, int length) = 0; + virtual void *getPointer() = 0; + virtual size_t getSize() = 0; +}; + +typedef std::shared_ptr HGBuffer; +#endif //AWEBWOWVIEWERCPP_IBUFFER_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IIndexBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IIndexBuffer.h deleted file mode 100644 index c70e98891..000000000 --- a/wowViewerLib/src/gapi/interface/buffers/IIndexBuffer.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by Deamon on 8/27/2018. -// - -#ifndef AWEBWOWVIEWERCPP_IINDEXBUFFER_H -#define AWEBWOWVIEWERCPP_IINDEXBUFFER_H -class IIndexBuffer { -public: - virtual ~IIndexBuffer() {}; - virtual void uploadData(void *, int length) = 0; - -}; -#endif //AWEBWOWVIEWERCPP_IINDEXBUFFER_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IUniformBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IUniformBuffer.h deleted file mode 100644 index f0a2d3dfd..000000000 --- a/wowViewerLib/src/gapi/interface/buffers/IUniformBuffer.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created by Deamon on 8/27/2018. -// - -#ifndef AWEBWOWVIEWERCPP_IUNIFORMBUFFER_H -#define AWEBWOWVIEWERCPP_IUNIFORMBUFFER_H - -class IUniformBuffer { -private: - void bind(int bindingPoint, int offset, int length); //Should be called only by GDevice - -public: - virtual ~IUniformBuffer() {}; - virtual void createBuffer() = 0; -}; - -#endif //AWEBWOWVIEWERCPP_IUNIFORMBUFFER_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IVertexBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IVertexBuffer.h deleted file mode 100644 index 36c2c238f..000000000 --- a/wowViewerLib/src/gapi/interface/buffers/IVertexBuffer.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by Deamon on 8/27/2018. -// - -#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFER_H -#define AWEBWOWVIEWERCPP_IVERTEXBUFFER_H -class IVertexBuffer { -public: - virtual ~IVertexBuffer() {}; - virtual void uploadData(void *, int length) = 0; - - virtual void bind() = 0; - virtual void unbind() = 0; - -}; -#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFER_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IVertexBufferDynamic.h b/wowViewerLib/src/gapi/interface/buffers/IVertexBufferDynamic.h deleted file mode 100644 index fbc9da30c..000000000 --- a/wowViewerLib/src/gapi/interface/buffers/IVertexBufferDynamic.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Created by deamon on 31.10.19. -// - -#ifndef AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMIC_H -#define AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMIC_H - -#include -#include "IVertexBuffer.h" - -class IVertexBufferDynamic : public IVertexBuffer { -public: - ~IVertexBufferDynamic() override = default; - - template - T &getObject() { -// assert(sizeof(T) == m_size); - return *(T *) getPointerForModification(); - } - virtual void *getPointerForModification() = 0; - - virtual void save(size_t sizeToSave) = 0; - virtual void resize(size_t size) = 0; -}; -#endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERDYNAMIC_H diff --git a/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h b/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h index 4fbf0c3c9..910339748 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h @@ -4,4 +4,22 @@ #ifndef AWEBWOWVIEWERCPP_IM2MESH_H #define AWEBWOWVIEWERCPP_IM2MESH_H + +#include "ITransparentMesh.h" + +class IM2Mesh : public ITransparentMesh { +protected: + int m_priorityPlane = 0; + int m_layer = 0; +public: + ~IM2Mesh() override = default; + + auto priorityPlane() -> int { return m_priorityPlane; } + auto layer() -> int& { return m_layer; } + + virtual void setPriorityPlane(int priorityPlane) = 0; + virtual void setLayer(int layer) = 0; + virtual EGxBlendEnum getGxBlendMode() = 0; +}; + #endif //AWEBWOWVIEWERCPP_IM2MESH_H diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 90d55113c..d9b06efcb 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -70,8 +70,7 @@ class gMeshTemplate { int start; int end; DrawElementMode element; - unsigned int textureCount; - std::vector texture = std::vector(6, nullptr); + std::vector texture = {}; std::array ubo = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}; bool scissorEnabled = false; @@ -84,36 +83,20 @@ class IMesh { friend class IDevice; public: - auto renderOrder() -> int& { return m_renderOrder; } - auto sortDistance() -> float { return m_sortDistance; } - auto priorityPlane() -> int { return m_priorityPlane; } - auto layer() -> int& { return m_layer; } - auto isSkyBox() -> bool& { return m_isSkyBox; } auto start() -> int& { return m_start; } auto end() -> int& { return m_end; } - auto textureCount() -> int& { return m_textureCount; } + auto textureCount() -> int { return m_texture.size(); } auto bindings() const -> const HGVertexBufferBindings& { return m_bindings; } auto texture() const -> const std::vector& { return m_texture; } // auto texture() const -> const HGVertexBufferBindings& { return m_bindings; } protected: - int m_renderOrder = 0; - - float m_sortDistance = 0; - - int m_priorityPlane = 0; - int m_layer = 0; - void *m_m2Object = nullptr; - - bool m_isSkyBox = false; - HGVertexBufferBindings m_bindings; int m_start; int m_end; std::vector m_texture = {}; - int m_textureCount; std::array m_UniformBuffer = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; @@ -123,23 +106,11 @@ class IMesh { }; virtual inline HGUniformBufferChunk getUniformBuffer(int slot) = 0; - virtual EGxBlendEnum getGxBlendMode() = 0; + virtual bool getIsTransparent() = 0; virtual MeshType getMeshType() = 0; - virtual void setRenderOrder(int renderOrder) = 0; - virtual bool getIsSkyBox() { return m_isSkyBox; } - - virtual void setStart(int start) = 0; - virtual void setEnd(int end) = 0; - -public: - virtual void * getM2Object() = 0; - virtual void setM2Object(void * m2Object) = 0; - virtual void setLayer(int layer) = 0; - virtual void setPriorityPlane(int priorityPlane) = 0; - virtual void setQuery(const HGOcclusionQuery &query) = 0; - virtual void setSortDistance(float distance) = 0; - virtual float getSortDistance() = 0; + void setStart(int start) {m_start = start; } + void setEnd(int end) {m_end = end; } }; #endif //AWEBWOWVIEWERCPP_IMESH_H diff --git a/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h b/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h new file mode 100644 index 000000000..cd31190c3 --- /dev/null +++ b/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h @@ -0,0 +1,22 @@ +// +// Created by Deamon on 19.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H +#define AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H + +#include "IMesh.h" + +class ITransparentMesh : public IMesh { + friend class IDevice; +protected: + float m_sortDistance = 0; +public: + ~ITransparentMesh() override = default; + + auto sortDistance() -> float { return m_sortDistance; } + + virtual void setSortDistance(float distance) = 0; + virtual float getSortDistance() = 0; +}; +#endif //AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index 6e746978f..fa64b141a 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -7,13 +7,6 @@ if (pA == nullptr) return false; if (pB == nullptr) return true; - if (pA->getIsTransparent() > pB->getIsTransparent()) { - return false; - } - if (pA->getIsTransparent() < pB->getIsTransparent()) { - return true; -} - // if (pA->getMeshType() > pB->getMeshType()) { // return false; // } @@ -29,12 +22,6 @@ // } // } - if (pA->isSkyBox() > pB->isSkyBox()) { - return true; - } - if (pA->isSkyBox() < pB->isSkyBox()) { - return false; - } if (pA->getIsTransparent() && pB->getIsTransparent()) { if (((pA->getMeshType() == MeshType::eM2Mesh || pA->getMeshType() == MeshType::eParticleMesh) && diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp index 912b4f377..657439d93 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp @@ -66,7 +66,7 @@ void debug_func(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei // } } -void GDeviceGL20::bindIndexBuffer(IIndexBuffer *buffer) { +void GDeviceGL20::bindIndexBuffer(IBuffer *buffer) { GIndexBufferGL20 * gBuffer = (GIndexBufferGL20 *) buffer; if (gBuffer == nullptr ) { if (m_lastBindIndexBuffer != nullptr) { diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h index 6ba7c4750..c088f8f21 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h @@ -69,7 +69,7 @@ class GDeviceGL20 : public IDevice { void bindProgram(IShaderPermutation *program) override; - void bindIndexBuffer(IIndexBuffer *buffer) override; + void bindIndexBuffer(IBuffer *buffer) override; void bindVertexBuffer(IVertexBuffer *buffer) override; void bindUniformBuffer(IUniformBuffer *buffer, int slot, int offset, int length) override; void bindVertexBufferBindings(IVertexBufferBindings *buffer) override; diff --git a/wowViewerLib/src/gapi/ogl2.0/buffers/GIndexBufferGL20.h b/wowViewerLib/src/gapi/ogl2.0/buffers/GIndexBufferGL20.h index 02d9f7404..526699a3d 100644 --- a/wowViewerLib/src/gapi/ogl2.0/buffers/GIndexBufferGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/buffers/GIndexBufferGL20.h @@ -5,12 +5,12 @@ #ifndef WEBWOWVIEWERCPP_GINDEXBUFFER20_H #define WEBWOWVIEWERCPP_GINDEXBUFFER20_H -#include "../../interface/buffers/IIndexBuffer.h" +#include "../../interface/buffers/IBuffer.h" #include "../../interface/IDevice.h" #include "../GDeviceGL20.h" -class GIndexBufferGL20 : public IIndexBuffer{ +class GIndexBufferGL20 : public IBuffer{ friend class GDeviceGL20; explicit GIndexBufferGL20(IDevice &device); diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp index 31d41cffc..22bd75a7e 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp @@ -78,7 +78,7 @@ namespace GL33 { } } -void GDeviceGL33::bindIndexBuffer(IIndexBuffer *buffer) { +void GDeviceGL33::bindIndexBuffer(IBuffer *buffer) { GIndexBufferGL33 * gBuffer = (GIndexBufferGL33 *) buffer; if (gBuffer == nullptr ) { if (m_lastBindIndexBuffer != nullptr) { diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h index 319d32ea3..51ed68390 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h @@ -88,7 +88,7 @@ class GDeviceGL33 : public IDevice, public std::enable_shared_from_thisuploadData(&m_buffer[0], sizeToSave); + this->uploadData(m_buffer.data(), sizeToSave); } void GVertexBufferDynamicGL33::resize(size_t sizeToSave) { if (sizeToSave > m_size) { @@ -80,7 +80,5 @@ void GVertexBufferDynamicGL33::resize(size_t sizeToSave) { m_size = sizeToSave; m_buffer.resize(sizeToSave); // createBuffer(); - - } } \ No newline at end of file diff --git a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp index adf6fdc35..fcbe89bd7 100644 --- a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp +++ b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp @@ -51,7 +51,7 @@ namespace GDeviceGL4xNS { fflush(stdout); } } -void GDeviceGL4x::bindIndexBuffer(IIndexBuffer *buffer) { +void GDeviceGL4x::bindIndexBuffer(IBuffer *buffer) { GIndexBufferGL4x * gBuffer = (GIndexBufferGL4x *) buffer; if (gBuffer == nullptr ) { if (m_lastBindIndexBuffer != nullptr) { diff --git a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.h b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.h index 88f75d088..23c4196be 100644 --- a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.h +++ b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.h @@ -61,7 +61,7 @@ class GDeviceGL4x : public IDevice { void bindProgram(IShaderPermutation *program) override; - void bindIndexBuffer(IIndexBuffer *buffer) override; + void bindIndexBuffer(IBuffer *buffer) override; void bindVertexBuffer(IVertexBuffer *buffer) override; void bindUniformBuffer(IUniformBuffer *buffer, int slot, int offset, int length) override; void bindVertexBufferBindings(IVertexBufferBindings *buffer) override; diff --git a/wowViewerLib/src/gapi/ogl4.x/buffers/GIndexBufferGL4x.h b/wowViewerLib/src/gapi/ogl4.x/buffers/GIndexBufferGL4x.h index b01ceea48..5249b67a8 100644 --- a/wowViewerLib/src/gapi/ogl4.x/buffers/GIndexBufferGL4x.h +++ b/wowViewerLib/src/gapi/ogl4.x/buffers/GIndexBufferGL4x.h @@ -5,12 +5,12 @@ #ifndef WEBWOWVIEWERCPP_GINDEXBUFFER_4X_H #define WEBWOWVIEWERCPP_GINDEXBUFFER_4X_H -#include "../../interface/buffers/IIndexBuffer.h" +#include "../../interface/buffers/IBuffer.h" #include "../../interface/IDevice.h" #include "../GDeviceGL4x.h" -class GIndexBufferGL4x : public IIndexBuffer{ +class GIndexBufferGL4x : public IBuffer{ friend class GDeviceGL4x; explicit GIndexBufferGL4x(IDevice &device); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 0b3f0df7d..c9d79b573 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -15,10 +15,7 @@ #include "meshes/GM2MeshVLK.h" #include "meshes/GMeshVLK.h" -#include "buffers/GUniformBufferVLK.h" -#include "buffers/GVertexBufferVLK.h" #include "buffers/GVertexBufferDynamicVLK.h" -#include "buffers/GIndexBufferVLK.h" #include "textures/GTextureVLK.h" #include "textures/GBlpTextureVLK.h" #include "GVertexBufferBindingsVLK.h" @@ -39,6 +36,7 @@ #include "shaders/GWaterfallShaderVLK.h" #include "GRenderPassVLK.h" #include "../../engine/algorithms/FrameCounter.h" +#include "buffers/GBufferVLK.h" //#include "fastmemcp.h" #include @@ -269,26 +267,6 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { std::cout << "uniformBufferOffsetAlign = " << uniformBufferOffsetAlign << std::endl; std::cout << "maxUniformBufferSize = " << maxUniformBufferSize << std::endl; - - // Create pool -// VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -// exampleBufCreateInfo.size = 65536; // Whatever. -// exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change if needed. -// -// VmaAllocationCreateInfo allocCreateInfo = {}; -// allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; // Change if needed. -// -// uint32_t memTypeIndex; -// vmaFindMemoryTypeIndexForBufferInfo(vmaAllocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); -// -// // Create a pool that can have at most 2 blocks, 128 MiB each. -// VmaPoolCreateInfo poolCreateInfo = {}; -// poolCreateInfo.memoryTypeIndex = memTypeIndex; -// poolCreateInfo.blockSize = 128ull * 1024 * 1024; -// poolCreateInfo.maxBlockCount = 10; -// -// vmaCreatePool(vmaAllocator, &poolCreateInfo, &uboVmaPool); - } void GDeviceVLK::initialize() { @@ -433,15 +411,6 @@ void GDeviceVLK::createRenderPass() { true); } -void GDeviceVLK::createColorResources() { -// VkFormat colorFormat = swapChainImageFormat; -// -// createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage, colorImageMemory); -// colorImageView = createImageView(colorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); -// -// transitionImageLayout(colorImage, colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1); -} - uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties memProperties; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); @@ -872,26 +841,6 @@ float GDeviceVLK::getAnisLevel() { return deviceProperties.limits.maxSamplerAnisotropy; } -void GDeviceVLK::bindProgram(IShaderPermutation *program) { - -} - -void GDeviceVLK::bindIndexBuffer(IIndexBuffer *buffer) { - -} - -void GDeviceVLK::bindVertexBuffer(IVertexBuffer *buffer) { - -} - - -void GDeviceVLK::bindVertexBufferBindings(IVertexBufferBindings *buffer) { - -} - -void GDeviceVLK::bindTexture(ITexture *texture, int slot) { - -} void GDeviceVLK::startUpdateForNextFrame() { int uploadFrame = getUpdateFrameNumber(); @@ -993,23 +942,23 @@ void GDeviceVLK::updateBuffers(std::vector*> & if (bufferForUpload == nullptr) { bufferForUpload = createUniformBuffer(1000); - bufferForUpload->createBuffer(); m_UBOFrames[getUpdateFrameNumber()].m_uniformBufferForUpload = bufferForUpload; m_shaderDescriptorUpdateNeeded = true; } - auto bufferForUploadVLK = ((GUniformBufferVLK *) bufferForUpload.get()); - size_t old_size = bufferForUploadVLK->m_size; + auto bufferForUploadVLK = std::dynamic_pointer_cast(bufferForUpload); + size_t old_size = bufferForUploadVLK->getSize(); if (old_size < fullSize) { - bufferForUploadVLK->resize(fullSize); + //TODO: + //bufferForUploadVLK->resize(fullSize); //Buffer identifier was changed, so we need to update shader UBO descriptor m_shaderDescriptorUpdateNeeded = true; } if (fullSize > 0) { - char *pointerForUpload = static_cast(bufferForUploadVLK->stagingUBOBufferAllocInfo.pMappedData); + char *pointerForUpload = static_cast(bufferForUploadVLK->getPointer()); for (int i = 0; i < bufferChunks.size(); i++) { auto &bufferVec = bufferChunks[i]; @@ -1046,7 +995,8 @@ void GDeviceVLK::updateBuffers(std::vector*> & // } } if (currentSize > 0) { - bufferForUploadVLK->uploadFromStaging(currentSize); + //TODO: + //bufferForUploadVLK->uploadFromStaging(currentSize); } } } @@ -1062,7 +1012,7 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { mesh->updateDescriptor(); - for (int i = 0; i < mesh->m_textureCount; i++) { + for (int i = 0; i < mesh->textureCount(); i++) { textures.push_back(mesh->m_texture[i]); } } @@ -1075,15 +1025,14 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { if (texture->postLoad()) texturesLoaded++; if (texturesLoaded > 4) break; } - m_texturesWereUploaded = texturesLoaded > 0; } void GDeviceVLK::drawMeshes(std::vector &meshes) { } -std::shared_ptr GDeviceVLK::getShader(std::string shaderName, void *permutationDescriptor) { - const char * cstr = shaderName.c_str(); +std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) { + const char * cstr = vertexName.c_str(); size_t hash = CalculateFNV(cstr); if (m_shaderPermutCache.count(hash) > 0) { HGShaderPermutation ptr = m_shaderPermutCache.at(hash); @@ -1092,56 +1041,56 @@ std::shared_ptr GDeviceVLK::getShader(std::string shaderName std::shared_ptr sharedPtr; - if (shaderName == "m2Shader") { - IShaderPermutation *iPremutation = new GM2ShaderPermutationVLK(shaderName, this); + if (vertexName == "m2Shader") { + IShaderPermutation *iPremutation = new GM2ShaderPermutationVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "m2ParticleShader") { - IShaderPermutation *iPremutation = new GM2ParticleShaderPermutationVLK(shaderName, this); + } else if (vertexName == "m2ParticleShader") { + IShaderPermutation *iPremutation = new GM2ParticleShaderPermutationVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "ribbonShader") { - IShaderPermutation *iPremutation = new GM2RibbonShaderPermutationVLK(shaderName, this); + } else if (vertexName == "ribbonShader") { + IShaderPermutation *iPremutation = new GM2RibbonShaderPermutationVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "wmoShader"){ - IShaderPermutation *iPremutation = new GWMOShaderPermutationVLK(shaderName, this); + } else if (vertexName == "wmoShader"){ + IShaderPermutation *iPremutation = new GWMOShaderPermutationVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "waterShader"){ - IShaderPermutation *iPremutation = new GWaterShaderPermutation(shaderName, this); + } else if (vertexName == "waterShader"){ + IShaderPermutation *iPremutation = new GWaterShaderPermutation(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "adtShader"){ - IShaderPermutation *iPremutation = new GAdtShaderPermutationVLK(shaderName, this); + } else if (vertexName == "adtShader"){ + IShaderPermutation *iPremutation = new GAdtShaderPermutationVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "skyConus"){ - IShaderPermutation *iPremutation = new GSkyConusShaderVLK(shaderName, this); + } else if (vertexName == "skyConus"){ + IShaderPermutation *iPremutation = new GSkyConusShaderVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); - } else if (shaderName == "fullScreen_ffxgauss4") { - IShaderPermutation *iPremutation = new GFFXgauss4VLK(shaderName, this); + } else if (vertexName == "fullScreen_ffxgauss4") { + IShaderPermutation *iPremutation = new GFFXgauss4VLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); m_shaderPermutCache[hash] = sharedPtr; - } else if (shaderName == "ffxGlowQuad") { - IShaderPermutation *iPremutation = new GFFXGlowVLK(shaderName, this); + } else if (vertexName == "ffxGlowQuad") { + IShaderPermutation *iPremutation = new GFFXGlowVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); m_shaderPermutCache[hash] = sharedPtr; - } else if (shaderName == "waterfallShader") { - IShaderPermutation *iPremutation = new GWaterfallShaderVLK(shaderName, this); + } else if (vertexName == "waterfallShader") { + IShaderPermutation *iPremutation = new GWaterfallShaderVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); m_shaderPermutCache[hash] = sharedPtr; - } else if (shaderName == "drawBBShader") { - IShaderPermutation *iPremutation = new GDrawBoundingBoxVLK(shaderName, this); + } else if (vertexName == "drawBBShader") { + IShaderPermutation *iPremutation = new GDrawBoundingBoxVLK(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); m_shaderPermutCache[hash] = sharedPtr; - } else if (shaderName == "imguiShader") { - IShaderPermutation *iPremutation = new GImguiShaderPermutation(shaderName, this); + } else if (vertexName == "imguiShader") { + IShaderPermutation *iPremutation = new GImguiShaderPermutation(vertexName, this); sharedPtr.reset(iPremutation); sharedPtr->compileShader("",""); m_shaderPermutCache[hash] = sharedPtr; @@ -1154,31 +1103,19 @@ std::shared_ptr GDeviceVLK::getShader(std::string shaderName return sharedPtr; } -HGUniformBuffer GDeviceVLK::createUniformBuffer(size_t size) { - std::shared_ptr h_uniformBuffer; - h_uniformBuffer.reset(new GUniformBufferVLK(*this, size)); - +HGBufferVLK GDeviceVLK::createUniformBuffer(size_t initialSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize); return h_uniformBuffer; } -HGVertexBufferDynamic GDeviceVLK::createVertexBufferDynamic(size_t size) { - std::shared_ptr h_vertexBuffer; - h_vertexBuffer.reset(new GVertexBufferDynamicVLK(*this, size)); +HGBufferVLK GDeviceVLK::createVertexBuffer(size_t initialSize) { + auto h_vertexBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); return h_vertexBuffer; } -HGVertexBuffer GDeviceVLK::createVertexBuffer() { - std::shared_ptr h_vertexBuffer; - h_vertexBuffer.reset(new GVertexBufferVLK(*this)); - - return h_vertexBuffer; -} - -HGIndexBuffer GDeviceVLK::createIndexBuffer() { - std::shared_ptr h_indexBuffer; - h_indexBuffer.reset(new GIndexBufferVLK(*this)); - +HGBufferVLK GDeviceVLK::createIndexBuffer(size_t initialSize) { + auto h_indexBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); return h_indexBuffer; } @@ -1232,67 +1169,11 @@ HGMesh GDeviceVLK::createMesh(gMeshTemplate &meshTemplate) { return h_mesh; } -HGM2Mesh GDeviceVLK::createM2Mesh(gMeshTemplate &meshTemplate) { - std::shared_ptr h_mesh; - h_mesh.reset(new GM2MeshVLK(*this, meshTemplate)); - h_mesh->m_meshType = MeshType::eM2Mesh; - - return h_mesh; -} - -HGParticleMesh GDeviceVLK::createParticleMesh(gMeshTemplate &meshTemplate) { - std::shared_ptr h_mesh; - h_mesh.reset(new GM2MeshVLK(*this, meshTemplate)); - h_mesh->m_meshType = MeshType::eParticleMesh; - - return h_mesh; -} - HGPUFence GDeviceVLK::createFence() { return HGPUFence(); } -HGOcclusionQuery GDeviceVLK::createQuery(HGMesh boundingBoxMesh) { - return HGOcclusionQuery(); -} - -HGVertexBufferBindings GDeviceVLK::getBBVertexBinding() { - return HGVertexBufferBindings(); -} - -HGVertexBufferBindings GDeviceVLK::getBBLinearBinding() { - return HGVertexBufferBindings(); -} - -std::string GDeviceVLK::loadShader(std::string fileName, IShaderType shaderType) { - return std::string(); -} - -void GDeviceVLK::drawMesh(HGMesh &hmesh) { - -} - -void GDeviceVLK::reset() { - -} - -void GDeviceVLK::clearScreen() { - -} - -void GDeviceVLK::beginFrame() { - -// Rebuild pipelines -// for (auto &pipelineRec : loadedPipeLines) { -// if (!pipelineRec.second.expired()) { -// auto pipelineObj = pipelineRec.second.lock(); -// pipelineObj->createPipeline() -// } -// } - -} - -void GDeviceVLK::commitFrame() { +void GDeviceVLK::drawScenario() { if (m_firstFrame) { m_firstFrame = false; return; @@ -1358,48 +1239,49 @@ void GDeviceVLK::commitFrame() { vkWaitForFences(device, 1, &inFlightFences[currentDrawFrame], VK_TRUE, std::numeric_limits::max()); vkResetFences(device, 1, &inFlightFences[currentDrawFrame]); - - //Fill command buffer + //TODO:!!! + //This stuff creates commands that would write into the frameBuffer of the frame + //the problem is that it depends on the imageIndex, which cant be known beforehand + //Also, we would need info on the current settings of the clear color and invertZ stuff here auto commandBufferForFilling = commandBuffers[currentDrawFrame]; - - { - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = NULL; - - if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } - - std::array clearValues = {}; - clearValues[0].color = {clearColor[0], clearColor[1], clearColor[2], 1.0f}; - clearValues[1].depthStencil = {getInvertZ() ? 0.0f : 1.0f, 0}; - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.pNext = NULL; - renderPassInfo.renderPass = swapchainRenderPass->getRenderPass(); - renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = swapChainExtent; - renderPassInfo.clearValueCount = static_cast(clearValues.size()); - renderPassInfo.pClearValues = clearValues.data(); - - vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - - if (renderCommandBuffersNotNull[currentDrawFrame]) { - vkCmdExecuteCommands(commandBufferForFilling, 1, &renderCommandBuffers[currentDrawFrame]); - } - - vkCmdEndRenderPass(commandBufferForFilling); - - if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } - } +// { +// VkCommandBufferBeginInfo beginInfo = {}; +// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; +// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; +// beginInfo.pNext = NULL; +// beginInfo.pInheritanceInfo = NULL; +// +// if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { +// throw std::runtime_error("failed to begin recording command buffer!"); +// } +// +// std::array clearValues = {}; +// clearValues[0].color = {clearColor[0], clearColor[1], clearColor[2], 1.0f}; +// clearValues[1].depthStencil = {getInvertZ() ? 0.0f : 1.0f, 0}; +// +// VkRenderPassBeginInfo renderPassInfo = {}; +// renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; +// renderPassInfo.pNext = NULL; +// renderPassInfo.renderPass = swapchainRenderPass->getRenderPass(); +// renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; +// renderPassInfo.renderArea.offset = {0, 0}; +// renderPassInfo.renderArea.extent = swapChainExtent; +// renderPassInfo.clearValueCount = static_cast(clearValues.size()); +// renderPassInfo.pClearValues = clearValues.data(); +// +// vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); +// +// if (renderCommandBuffersNotNull[currentDrawFrame]) { +// vkCmdExecuteCommands(commandBufferForFilling, 1, &renderCommandBuffers[currentDrawFrame]); +// } +// +// vkCmdEndRenderPass(commandBufferForFilling); +// +// if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { +// throw std::runtime_error("failed to record command buffer!"); +// } +// } VkSubmitInfo submitInfo = {}; @@ -1473,16 +1355,6 @@ void GDeviceVLK::commitFrame() { } } -void GDeviceVLK::setClearScreenColor(float r, float g, float b) { - clearColor[0] = r; - clearColor[1] = g; - clearColor[2] = b; -} - -void GDeviceVLK::setViewPortDimensions(float x, float y, float width, float height) { - -} - std::shared_ptr GDeviceVLK::getRenderPass( std::vector textureAttachments, ITextureFormat depthAttachment, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index d2c595217..cfe3e2621 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -10,10 +10,8 @@ #include -class GVertexBufferVLK; + class GVertexBufferBindingsVLK; -class GIndexBufferVLK; -class GUniformBufferVLK; class GBlpTextureVLK; class GTextureVLK; class GShaderPermutationVLK; @@ -35,6 +33,7 @@ class gMeshTemplate; #include "descriptorSets/GDescriptorSet.h" #include "descriptorSets/GDescriptorPoolVLK.h" #include "../../engine/algorithms/FrameCounter.h" +#include "buffers/GBufferVLK.h" #include VkSampleCountFlagBits sampleCountToVkSampleCountFlagBits(uint8_t sampleCount); @@ -66,8 +65,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &meshes) override; void drawMeshes(std::vector &meshes) override; // void drawStageAndDeps(HDrawStage drawStage) override; - bool wasTexturesUploaded() override { - return m_texturesWereUploaded; - }; // void drawM2Meshes(std::vector &meshes); bool getIsVulkanAxisSystem() override {return true;} @@ -122,20 +107,19 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thiswaitInDrawStageAndDeps.getTimePerFrame(); } - std::shared_ptr getShader(std::string shaderName, void *permutationDescriptor) override; + std::shared_ptr getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) override; - HGUniformBuffer createUniformBuffer(size_t size) override; - HGVertexBuffer createVertexBuffer() override; - HGVertexBufferDynamic createVertexBufferDynamic(size_t size) override; - HGIndexBuffer createIndexBuffer() override; + HGBufferVLK createUniformBuffer(size_t size); + HGBufferVLK createVertexBuffer(size_t size); + HGBufferVLK createIndexBuffer(size_t size); HGVertexBufferBindings createVertexBufferBindings() override; HGTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) override; HGTexture createTexture(bool xWrapTex, bool yWrapTex) override; HGTexture getWhiteTexturePixel() override { return m_whitePixelTexture; }; + HGTexture getBlackTexturePixel() override { return m_blackPixelTexture; }; HGMesh createMesh(gMeshTemplate &meshTemplate) override; - HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate) override; - HGParticleMesh createParticleMesh(gMeshTemplate &meshTemplate) override; + HGPUFence createFence() override; HFrameBuffer createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) override ; @@ -156,22 +140,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int images); @@ -192,10 +162,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback); private: - void drawMesh(HGMesh &hmesh); // void internalDrawStageAndDeps(HDrawStage drawStage); void setupDebugMessenger(); @@ -260,7 +225,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_shaderPermutCache; - std::list> m_unfiormBufferCache; struct FrameUniformBuffers { HGUniformBuffer m_uniformBufferForUpload; }; @@ -449,9 +390,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this listOfDeallocators; - int uniformBuffersCreated = 0; - bool attachmentsReady = false; - std::vector m_createdFrameBuffers; struct RenderPassAvalabilityStruct { @@ -465,7 +403,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_createdRenderPasses; }; -typedef std::shared_ptr HGDeviceVLK; + #endif //AWEBWOWVIEWERCPP_GDEVICEVULKAN_H diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h index 94f3106c6..b4160d5fd 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h @@ -11,7 +11,6 @@ class GVertexBufferBindingsVLK; #include #include -#include "buffers/GVertexBufferVLK.h" #include "../interface/IVertexBufferBindings.h" #include "../interface/IDevice.h" #include "GDeviceVulkan.h" diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp new file mode 100644 index 000000000..92697b5a1 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -0,0 +1,212 @@ +// +// Created by Deamon on 16.12.22. +// + +#include "GBufferVLK.h" + +GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize) : m_device(device) { + m_usageFlags = usageFlags; + m_bufferSize = maxSize; + + createBuffer(currentBuffer); +} + +GBufferVLK::~GBufferVLK() { + destroyBuffer(currentBuffer); +} + +void GBufferVLK::createBuffer(BufferInternal &buffer) { +//Create new buffer for VBO + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = m_bufferSize; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo ibAllocCreateInfo = {}; + ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, + &buffer.stagingBuffer, + &buffer.stagingBufferAlloc, + &buffer.stagingBufferAllocInfo)); + + // No need to flush stagingBuffer memory because CPU_ONLY memory is always HOST_COHERENT. + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | m_usageFlags; + ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + ibAllocCreateInfo.flags = 0; + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, + &buffer.g_hBuffer, + &buffer.g_hBufferAlloc, nullptr)); + + //Create virtual buffer off this native buffer + VmaVirtualBlockCreateInfo blockCreateInfo = {}; + blockCreateInfo.size = m_bufferSize; + + VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &buffer.virtualBlock); + if(res != VK_SUCCESS) + { + std::cerr << "Failed to create virtual buffer" << std::endl; + } + +} + +void GBufferVLK::destroyBuffer(BufferInternal &buffer) { + auto l_device = m_device; + auto l_buffer = buffer; + m_device->addDeallocationRecord( + [l_buffer, l_device]() { + vmaClearVirtualBlock(l_buffer.virtualBlock); + vmaDestroyVirtualBlock(l_buffer.virtualBlock); + + vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.stagingBuffer, l_buffer.stagingBufferAlloc); + vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.g_hBuffer, l_buffer.g_hBufferAlloc); + } + ); +} + +VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { + VmaVirtualAllocationCreateInfo allocCreateInfo = {}; + allocCreateInfo.size = sizeInBytes; //Size in bytes + + return vmaVirtualAllocate(buffer.virtualBlock, &allocCreateInfo, &alloc, &offset); +} + +void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc) { + vmaVirtualFree(buffer.virtualBlock, alloc); +} + +void GBufferVLK::uploadData(void *data, int length) { + if (length > m_bufferSize) { + resize(length); + } + + memcpy(currentBuffer.stagingBufferAllocInfo.pMappedData, data, length); + + uploadFromStaging(0, 0, length); +} + +void GBufferVLK::subUploadData(void *data, int offset, int length) { + if (offset+length > m_bufferSize) { + resize(offset+length); + } + memcpy((uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset, data, length); +} + +void GBufferVLK::resize(int newLength) { + m_bufferSize = newLength; + BufferInternal newBuffer; + createBuffer(newBuffer); + + //Reallocate subBuffers and copy their data + for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ + auto subBuffer = it->lock(); + if (subBuffer != nullptr) { + VmaVirtualAllocation alloc; + VkDeviceSize offset; + VkResult res = allocateSubBuffer(newBuffer, subBuffer->m_size, alloc, offset); + + if (res != VK_SUCCESS) { + std::cerr << "Could not allocate sub-buffer during resize " << std::endl; + } + + memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData + offset, + (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData + subBuffer->m_offset, + subBuffer->m_size + ); + + vmaVirtualFree(currentBuffer.virtualBlock, subBuffer->m_alloc); + + subBuffer->m_offset = offset; + subBuffer->m_alloc = alloc; + } + } + + destroyBuffer(currentBuffer); + newBuffer = currentBuffer; +} + +std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes) { + VmaVirtualAllocation alloc; + VkDeviceSize offset; + VkResult res = allocateSubBuffer(currentBuffer, sizeInBytes, alloc, offset); + + if(res == VK_SUCCESS) + { + auto subBuffer = std::make_shared( + shared_from_this(), + alloc, + offset, sizeInBytes, + (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset); + currentSubBuffers.push_back(subBuffer); + subBuffer->m_iterator = std::prev(currentSubBuffers.end()); + return subBuffer; + } + else + { + resize(m_bufferSize*2); + return getSubBuffer(sizeInBytes); + } +} + +void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it) { + if(auto subBuffer = it->lock()) { + deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); + } + + currentSubBuffers.erase(it); +} + +void GBufferVLK::uploadFromStaging(int offset, int destOffset, int length) { + VkBufferCopy vbCopyRegion = {}; + vbCopyRegion.srcOffset = offset; + vbCopyRegion.dstOffset = destOffset; + vbCopyRegion.size = length; + vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), currentBuffer.stagingBuffer, currentBuffer.g_hBuffer, 1, &vbCopyRegion); +} + +//---------------------------------------------------------------- +// SubBuffer thing +//---------------------------------------------------------------- + +GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, + VmaVirtualAllocation alloc, + VkDeviceSize offset, int size, + uint8_t *dataPointer) : m_parentBuffer(parent) { + m_alloc = alloc; + m_offset = offset; + m_size = size; + m_dataPointer = dataPointer; +} + +GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { + m_parentBuffer->deleteSubBuffer(m_iterator); +} + +void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { + if (length > m_size) { + std::cerr << "invalid dataSize" << std::endl; + } + + memcpy(m_dataPointer, data, length); + + m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); +} + +void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length) { + if (offset + length > m_size) { + std::cerr << "invalid dataSize" << std::endl; + } + + memcpy(m_dataPointer + offset, data, length); + + m_parentBuffer->uploadFromStaging(m_offset+offset, m_offset+offset, length); +} + +void *GBufferVLK::GSubBufferVLK::getPointer() { + return m_dataPointer; +} + +size_t GBufferVLK::GSubBufferVLK::getSize() { + return m_size; +} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h new file mode 100644 index 000000000..0f82945a3 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -0,0 +1,101 @@ +// +// Created by Deamon on 16.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_GBUFFERVLK_H +#define AWEBWOWVIEWERCPP_GBUFFERVLK_H + +#include + +class GDeviceVLK; +typedef std::shared_ptr HGDeviceVLK; + +class GBufferVLK; +typedef std::shared_ptr HGBufferVLK; + +#include "../GDeviceVulkan.h" +#include "IBufferVLK.h" + +class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { + friend class GDeviceVLK; +public: + explicit GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize); + ~GBufferVLK() override; + + //Doesn't make actual upload, only queues it. + void uploadData(void *, int length) override; + void subUploadData(void *, int offset, int length) override; + void uploadFromStaging(int offset, int destOffset, int length); + + void *getPointer() override { return currentBuffer.stagingBufferAllocInfo.pMappedData;}; + size_t getSize() override { return m_bufferSize;}; + + VkBuffer getGPUBuffer() override { + return currentBuffer.g_hBuffer; + } + size_t getOffset() override { + return 0; + }; + + void resize(int newLength); +private: + HGDeviceVLK m_device; + + VkBufferUsageFlags m_usageFlags; + int m_bufferSize; + //Buffers + struct BufferInternal { + VkBuffer g_hBuffer = VK_NULL_HANDLE; + VmaAllocation g_hBufferAlloc = VK_NULL_HANDLE; + + VkBuffer stagingBuffer = VK_NULL_HANDLE; + VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; + VmaAllocationInfo stagingBufferAllocInfo; + + //Virtual block for suballocations + VmaVirtualBlock virtualBlock; + } currentBuffer; + + std::vector dataToBeUploaded; +private: + class GSubBufferVLK : public IBufferVLK { + friend class GBufferVLK; + public: + explicit GSubBufferVLK(HGBufferVLK parent, VmaVirtualAllocation alloc, VkDeviceSize offset, int size, uint8_t * dataPointer); + ~GSubBufferVLK() override; + void uploadData(void *data, int length) override; + void subUploadData(void *data, int offset, int length) override; + void *getPointer() override; + size_t getSize() override; + + VkBuffer getGPUBuffer() override { + return m_parentBuffer->getGPUBuffer(); + } + size_t getOffset() override { + return m_offset; + }; + private: + HGBufferVLK &m_parentBuffer; + + VmaVirtualAllocation m_alloc; + VkDeviceSize m_offset; + int m_size; + uint8_t * m_dataPointer = nullptr; + std::list>::const_iterator m_iterator; + }; + + + std::list> currentSubBuffers; +public: + std::shared_ptr getSubBuffer(int sizeInBytes); + void deleteSubBuffer(std::list>::const_iterator &it); +private: + void createBuffer(BufferInternal &buffer); + void destroyBuffer(BufferInternal &buffer); + + VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, VmaVirtualAllocation &alloc, VkDeviceSize &offset); + void deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc); +}; + + +#endif //AWEBWOWVIEWERCPP_GBUFFERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.cpp deleted file mode 100644 index 20bb8c6ef..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// -// Created by deamon on 05.06.18. -// -#include -#include -#include "GIndexBufferVLK.h" - -GIndexBufferVLK::GIndexBufferVLK(IDevice &device) : m_device(dynamic_cast(device)) { - createBuffer(); -} -GIndexBufferVLK::~GIndexBufferVLK(){ - destroyBuffer(); -} - -void GIndexBufferVLK::createBuffer() { -} - -void GIndexBufferVLK::destroyBuffer() { - if (m_dataUploaded) { - auto *l_device = &m_device; - - auto &l_stagingIndexBuffer = stagingIndexBuffer; - auto &l_stagingIndexBufferAlloc = stagingIndexBufferAlloc; - - auto &l_hIndexBuffer = g_hIndexBuffer; - auto &l_hIndexBufferAlloc = g_hIndexBufferAlloc; - - m_device.addDeallocationRecord( - [l_device, l_stagingIndexBuffer, l_stagingIndexBufferAlloc, l_hIndexBuffer, l_hIndexBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingIndexBuffer, l_stagingIndexBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hIndexBuffer, l_hIndexBufferAlloc); - } - ); - } -} - -static int ibo_uploaded = 0; -void GIndexBufferVLK::uploadData(void * data, int length) { - if (!m_dataUploaded || length > m_size) { - if (m_dataUploaded) { - auto *l_device = &m_device; - auto &l_stagingIndexBuffer = stagingIndexBuffer; - auto &l_stagingIndexBufferAlloc = stagingIndexBufferAlloc; - - auto &l_hIndexBuffer = g_hIndexBuffer; - auto &l_hIndexBufferAlloc = g_hIndexBufferAlloc; - - m_device.addDeallocationRecord( - [l_device, l_stagingIndexBuffer, l_stagingIndexBufferAlloc, l_hIndexBuffer, l_hIndexBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingIndexBuffer, l_stagingIndexBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hIndexBuffer, l_hIndexBufferAlloc); - } - ); - } - - VkBufferCreateInfo ibInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - ibInfo.size = length; - ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo ibAllocCreateInfo = {}; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - - if (length == 0) { - std::cout << "oops" << std::endl; - } - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, - &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo)); - - memcpy(stagingIndexBufferAllocInfo.pMappedData, data, length); - - // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT. - ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ibAllocCreateInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, - &g_hIndexBufferAlloc, nullptr)); - - - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = ibInfo.size; - vkCmdCopyBuffer(m_device.getUploadCommandBuffer(), stagingIndexBuffer, g_hIndexBuffer, 1, &vbCopyRegion); - - m_size = ibInfo.size; - m_dataUploaded = true; -// std::cout << "vbo_uploaded = " << vbo_uploaded++ << std::endl; - } else { - memcpy(stagingIndexBufferAllocInfo.pMappedData, data, length); - - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = length; - vkCmdCopyBuffer(m_device.getUploadCommandBuffer(), stagingIndexBuffer, g_hIndexBuffer, 1, &vbCopyRegion); - } -} - -void GIndexBufferVLK::bind() { -} - -void GIndexBufferVLK::unbind() { -} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.h deleted file mode 100644 index 3a44257b0..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GIndexBufferVLK.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Created by deamon on 05.06.18. -// - -#ifndef WEBWOWVIEWERCPP_GINDEXBUFFER_H -#define WEBWOWVIEWERCPP_GINDEXBUFFER_H - -#include "../../interface/buffers/IIndexBuffer.h" -#include "../../interface/IDevice.h" -#include "../GDeviceVulkan.h" - - -class GIndexBufferVLK : public IIndexBuffer{ - friend class GDeviceVLK; - - explicit GIndexBufferVLK(IDevice &device); -public: - ~GIndexBufferVLK() override; - -private: - void createBuffer(); - void destroyBuffer(); - void bind(); - void unbind(); - -public: - void uploadData(void *, int length) override; - -private: - GDeviceVLK &m_device; - VkBuffer g_hIndexBuffer; - VmaAllocation g_hIndexBufferAlloc; - - VkBuffer stagingIndexBuffer = VK_NULL_HANDLE; - VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingIndexBufferAllocInfo; - -private: - size_t m_size = 0; - bool m_buffCreated = false; - bool m_dataUploaded = false; -}; - - -#endif //WEBWOWVIEWERCPP_GINDEXBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.cpp deleted file mode 100644 index 0b8564f68..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// -// Created by Deamon on 6/30/2018. -// -#include -#include -#include "GUniformBufferVLK.h" -#include "../../interface/IDevice.h" - -GUniformBufferVLK::GUniformBufferVLK(IDevice &device, size_t size) : m_device((GDeviceVLK *) &device){ - m_size = size; -} - -GUniformBufferVLK::~GUniformBufferVLK() { - if (m_buffCreated) { - destroyBuffer(); - } -} - -void GUniformBufferVLK::createBuffer() { - if (m_buffCreated) - return; - - // Allocate a buffer out of it. - VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufCreateInfo.size = m_size; - bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - VmaAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocCreateInfo.flags = 0; - - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &bufCreateInfo, &allocCreateInfo, &g_buf, &g_alloc, &g_allocInfo)); - - // CPU Buffer - VkBufferCreateInfo uboInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - uboInfo.size = m_size; - uboInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - uboInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo uboAllocCreateInfo = {}; - uboAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - uboAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &uboInfo, &uboAllocCreateInfo, &stagingUBOBuffer, - &stagingUBOBufferAlloc, &stagingUBOBufferAllocInfo)); - - m_buffCreated = true; -} - -void GUniformBufferVLK::destroyBuffer() { - if (m_buffCreated) { - auto *l_device = m_device; - auto l_stagingUBOBuffer = stagingUBOBuffer; - auto l_stagingUBOBufferAlloc = stagingUBOBufferAlloc; - - auto l_hUBOBuffer = g_buf; - auto l_hUBOBufferAlloc = g_alloc; - - m_device->addDeallocationRecord( - [l_device, l_stagingUBOBuffer, l_stagingUBOBufferAlloc, l_hUBOBuffer, l_hUBOBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingUBOBuffer, l_stagingUBOBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hUBOBuffer, l_hUBOBufferAlloc); - } - ); - } -} -void GUniformBufferVLK::bind(int bindingPoint) { //Should be called only by GDevice - -} -void GUniformBufferVLK::unbind() { -} - -void GUniformBufferVLK::uploadData(void * data, int length) { - assert(m_buffCreated); - assert(length > 0 && length <= m_size); - - resize(length); - - - memcpy(stagingUBOBufferAllocInfo.pMappedData, data, length); - -// memcpy(stagingUBOBufferAllocInfo.pMappedData, data, length); - - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = length; - vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), stagingUBOBuffer, g_buf, 1, &vbCopyRegion); - - m_dataUploaded = true; -} - -void GUniformBufferVLK::uploadFromStaging(int length) { - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = length; - vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), stagingUBOBuffer, g_buf, 1, &vbCopyRegion); - - m_dataUploaded = true; -} - -void GUniformBufferVLK::resize(int newLength) { - if (newLength > m_size) { - if (m_buffCreated) { - auto *l_device = m_device; - auto l_stagingUBOBuffer = stagingUBOBuffer; - auto l_stagingUBOBufferAlloc = stagingUBOBufferAlloc; - - auto l_hUBOBuffer = g_buf; - auto l_hUBOBufferAlloc = g_alloc; - - m_device->addDeallocationRecord( - [l_device, l_stagingUBOBuffer, l_stagingUBOBufferAlloc, l_hUBOBuffer, l_hUBOBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingUBOBuffer, l_stagingUBOBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hUBOBuffer, l_hUBOBufferAlloc); - } - ); - } - - m_size = newLength; - m_buffCreated = false; - stagingUBOBuffer = VK_NULL_HANDLE; - stagingUBOBufferAlloc = VK_NULL_HANDLE; - stagingUBOBufferAllocInfo = {}; - g_buf = VK_NULL_HANDLE; - g_alloc = VK_NULL_HANDLE; - createBuffer(); - } -} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.h deleted file mode 100644 index 7c71e4090..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GUniformBufferVLK.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// Created by Deamon on 6/30/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GUNIFORMBUFFER_H -#define AWEBWOWVIEWERCPP_GUNIFORMBUFFER_H - - -#include -#include -#include "../GDeviceVulkan.h" -#include "../../interface/buffers/IUniformBuffer.h" - -class GUniformBufferVLK : public IUniformBuffer { -public: - friend class GDeviceVLK; - friend class GMeshVLK; - friend class GShaderPermutationVLK; - - explicit GUniformBufferVLK(IDevice &device, size_t size); - ~GUniformBufferVLK() override; - - void createBuffer() override; - - size_t getSize() {return m_size;} -private: - void destroyBuffer(); - void bind(int bindingPoint); //Should be called only by GDevice - void unbind(); - -private: - void uploadData(void * data, int length); - void uploadFromStaging(int length); - void resize(int newLength); - -private: - GDeviceVLK *m_device; - -private: - size_t m_size; - bool m_buffCreated = false; - bool m_dataUploaded = false; - - VkBuffer g_buf; - VmaAllocation g_alloc; - VmaAllocationInfo g_allocInfo; - - VkBuffer stagingUBOBuffer = VK_NULL_HANDLE; - VmaAllocation stagingUBOBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingUBOBufferAllocInfo = {}; -}; - - -#endif //AWEBWOWVIEWERCPP_GUNIFORMBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp index e7fc3219a..5a91f4876 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp @@ -60,18 +60,11 @@ static int vbo_uploaded = 0; void GVertexBufferDynamicVLK::uploadData(void *data, int length) { } -void GVertexBufferDynamicVLK::bind() { - -} - -void GVertexBufferDynamicVLK::unbind() { - -} - -void *GVertexBufferDynamicVLK::getPointerForModification() { +void *GVertexBufferDynamicVLK::getPointer() { return stagingVertexBufferAllocInfo.pMappedData; } +/* void GVertexBufferDynamicVLK::save(size_t sizeToSave) { VkBufferCopy vbCopyRegion = {}; vbCopyRegion.srcOffset = 0; @@ -86,4 +79,5 @@ void GVertexBufferDynamicVLK::resize(size_t sizeToSave) { m_size = sizeToSave; createBuffer(); } -} \ No newline at end of file +} + */ \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h index 641238fa3..f9222df15 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h @@ -6,28 +6,21 @@ #define WEBWOWVIEWERCPP_GVERTEXBUFFERDYNAMICVLK_H #include "../../interface/IDevice.h" -#include "../../interface/buffers/IVertexBuffer.h" -#include "../../interface/buffers/IVertexBufferDynamic.h" #include "../GDeviceVulkan.h" #include -class GVertexBufferDynamicVLK : public IVertexBufferDynamic { +class GVertexBufferDynamicVLK : public IBufferVLK { friend class GDeviceVLK; explicit GVertexBufferDynamicVLK(IDevice &device, size_t maxSize); public: ~GVertexBufferDynamicVLK() override; - void *getPointerForModification() override; + void *getPointer() override; - void save(size_t sizeToSave) override; - void resize(size_t sizeToSave) override; private: void createBuffer(); void destroyBuffer(); - void bind() override; //Should be called only by GDevice - void unbind() override; - public: void uploadData(void *, int length) override; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.cpp deleted file mode 100644 index d686eef2d..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// -// Created by deamon on 05.06.18. -// - -#include -#include -#include "GVertexBufferVLK.h" - -GVertexBufferVLK::GVertexBufferVLK(IDevice &device) : m_device(dynamic_cast(device)) { - - createBuffer(); -} - -GVertexBufferVLK::~GVertexBufferVLK() { - destroyBuffer(); - -} - -void GVertexBufferVLK::createBuffer() { - -} - -void GVertexBufferVLK::destroyBuffer() { - if (m_dataUploaded) { - auto *l_device = &m_device; - auto &l_stagingVertexBuffer = stagingVertexBuffer; - auto &l_stagingVertexBufferAlloc = stagingVertexBufferAlloc; - - auto &l_hVertexBuffer = g_hVertexBuffer; - auto &l_hVertexBufferAlloc = g_hVertexBufferAlloc; - - m_device.addDeallocationRecord( - [l_device, l_stagingVertexBuffer, l_stagingVertexBufferAlloc, l_hVertexBuffer, l_hVertexBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingVertexBuffer, l_stagingVertexBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hVertexBuffer, l_hVertexBufferAlloc); - } - ); - } -} - -static int vbo_uploaded = 0; - -void GVertexBufferVLK::uploadData(void *data, int length) { - if (!m_dataUploaded || length > m_size) { - //TODO: free previous memory - if (m_dataUploaded) { - auto *l_device = &m_device; - auto &l_stagingVertexBuffer = stagingVertexBuffer; - auto &l_stagingVertexBufferAlloc = stagingVertexBufferAlloc; - - auto &l_hVertexBuffer = g_hVertexBuffer; - auto &l_hVertexBufferAlloc = g_hVertexBufferAlloc; - - m_device.addDeallocationRecord( - [l_device, l_stagingVertexBuffer, l_stagingVertexBufferAlloc, l_hVertexBuffer, l_hVertexBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingVertexBuffer, l_stagingVertexBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hVertexBuffer, l_hVertexBufferAlloc); - } - ); - } - - //Create new buffer for VBO - VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - vbInfo.size = length; - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo ibAllocCreateInfo = {}; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, &stagingVertexBuffer, - &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo)); - - memcpy(stagingVertexBufferAllocInfo.pMappedData, data, length); - - // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT. - - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ibAllocCreateInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, &g_hVertexBuffer, - &g_hVertexBufferAlloc, nullptr)); - - - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = vbInfo.size; - vkCmdCopyBuffer(m_device.getUploadCommandBuffer(), stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion); - - m_size = vbInfo.size; - m_dataUploaded = true; - } else { - memcpy(stagingVertexBufferAllocInfo.pMappedData, data, length); - - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = length; - vkCmdCopyBuffer(m_device.getUploadCommandBuffer(), stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion); - } - - -} - -void GVertexBufferVLK::bind() { - -} - -void GVertexBufferVLK::unbind() { - -} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.h deleted file mode 100644 index 8f04c64d3..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferVLK.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by deamon on 05.06.18. -// - -#ifndef WEBWOWVIEWERCPP_GVERTEXBUFFER_H -#define WEBWOWVIEWERCPP_GVERTEXBUFFER_H - -#include "../../interface/IDevice.h" -#include "../../interface/buffers/IVertexBuffer.h" -#include "../GDeviceVulkan.h" -#include - -class GVertexBufferVLK : public IVertexBuffer { - friend class GDeviceVLK; - - explicit GVertexBufferVLK(IDevice &device); -public: - ~GVertexBufferVLK() override; -private: - void createBuffer(); - void destroyBuffer(); - void bind() override ; //Should be called only by GDevice - void unbind() override; - -public: - void uploadData(void *, int length) override; - -private: - GDeviceVLK &m_device; - VkBuffer g_hVertexBuffer; - VmaAllocation g_hVertexBufferAlloc; - - VkBuffer stagingVertexBuffer = VK_NULL_HANDLE; - VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingVertexBufferAllocInfo; - - -private: - - size_t m_size = 0; - bool m_buffCreated = false; - bool m_dataUploaded = false; - -}; - -#endif //WEBWOWVIEWERCPP_GVERTEXBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h new file mode 100644 index 000000000..f7fce3ae1 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h @@ -0,0 +1,16 @@ +// +// Created by Deamon on 24.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IBUFFERVLK_H +#define AWEBWOWVIEWERCPP_IBUFFERVLK_H + +#include +#include "../../interface/buffers/IBuffer.h" + +class IBufferVLK : public IBuffer { +public: + virtual VkBuffer getGPUBuffer() = 0; + virtual size_t getOffset() = 0; +}; +#endif //AWEBWOWVIEWERCPP_IBUFFERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index 4b7a2887f..5106e7ecb 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -5,11 +5,8 @@ #include "GM2MeshVLK.h" GM2MeshVLK::GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate) : GMeshVLK(device, meshTemplate){ -// m_meshType = MeshType::eM2Mesh; -} -void GM2MeshVLK::setM2Object(void *m2Object) { - m_m2Object = (m2Object); + m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ; } void GM2MeshVLK::setLayer(int layer) { @@ -25,12 +22,4 @@ void GM2MeshVLK::setSortDistance(float distance) { } float GM2MeshVLK::getSortDistance() { return m_sortDistance; -} - -void GM2MeshVLK::setQuery(const HGOcclusionQuery &query) { - m_query = query; -} - -void *GM2MeshVLK::getM2Object() { - return m_m2Object; -} +} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index 0c59b1490..d03a5c1a7 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -7,21 +7,15 @@ #include "GMeshVLK.h" -class GM2MeshVLK : public GMeshVLK { +class GM2MeshVLK : public GMeshVLK, public IM2Mesh { friend class GDeviceVLK; protected: GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate); public: - void *getM2Object() override; - void setM2Object(void * m2Object) override; void setLayer(int layer) override; void setPriorityPlane(int priorityPlane) override; - void setQuery(const HGOcclusionQuery &query) override; void setSortDistance(float distance) override; float getSortDistance() override; -private: - HGOcclusionQuery m_query = nullptr; - }; #endif //AWEBWOWVIEWERCPP_GM2MESH_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 58c808c7c..249067ac4 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -7,7 +7,6 @@ #include "GMeshVLK.h" #include "../textures/GTextureVLK.h" #include "../shaders/GShaderPermutationVLK.h" -#include "../buffers/GUniformBufferVLK.h" GMeshVLK::GMeshVLK(IDevice &device, const gMeshTemplate &meshTemplate @@ -20,8 +19,6 @@ GMeshVLK::GMeshVLK(IDevice &device, m_backFaceCulling = (int8_t) (meshTemplate.backFaceCulling ? 1 : 0); m_triCCW = meshTemplate.triCCW; - m_isSkyBox = meshTemplate.skybox; - m_isScissorsEnabled = meshTemplate.scissorEnabled ? 1 : 0; if (m_isScissorsEnabled) { m_scissorSize = meshTemplate.scissorSize; @@ -31,12 +28,10 @@ GMeshVLK::GMeshVLK(IDevice &device, m_colorMask = meshTemplate.colorMask; m_blendMode = meshTemplate.blendMode; - m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ; m_start = meshTemplate.start; m_end = meshTemplate.end; m_element = meshTemplate.element; - m_textureCount = meshTemplate.textureCount; m_texture = meshTemplate.texture; @@ -208,19 +203,8 @@ HGUniformBufferChunk GMeshVLK::getUniformBuffer(int slot) { return m_UniformBuffer[slot]; } -EGxBlendEnum GMeshVLK::getGxBlendMode() { return m_blendMode; } - bool GMeshVLK::getIsTransparent() { return m_isTransparent; } MeshType GMeshVLK::getMeshType() { return m_meshType; } - -void GMeshVLK::setRenderOrder(int renderOrder) { - m_renderOrder = renderOrder; -} - -void GMeshVLK::setStart(int start) {m_start = start; } -void GMeshVLK::setEnd(int end) {m_end = end; } - - diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 0e8750f4f..0deabc616 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -20,28 +20,15 @@ class GMeshVLK : public IMesh { public: ~GMeshVLK() override; HGUniformBufferChunk getUniformBuffer(int slot) override; - EGxBlendEnum getGxBlendMode() override; + bool getIsTransparent() override; MeshType getMeshType() override; - void setRenderOrder(int renderOrder) override; - void setStart(int start) override; - void setEnd(int end) override; public: - void *getM2Object() override { return nullptr; }; - void setM2Object(void * m2Object) override { throw "Not Implemented";}; - void setLayer(int layer) override { throw "Not Implemented";}; - void setPriorityPlane(int priorityPlane) override { throw "Not Implemented";}; - void setQuery(const HGOcclusionQuery &query) override { throw "Not Implemented";}; - void setSortDistance(float distance) override { m_sortDistance = distance;}; - float getSortDistance() override { return m_sortDistance; }; - - std::shared_ptr getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ); protected: MeshType m_meshType; -private: HGShaderPermutation m_shader; @@ -51,8 +38,9 @@ class GMeshVLK : public IMesh { int8_t m_depthCulling; int8_t m_backFaceCulling; int8_t m_triCCW = 1; + EGxBlendEnum m_blendMode; - bool m_isTransparent; + bool m_isTransparent = false; int8_t m_isScissorsEnabled = -1; std::array m_scissorOffset = {0,0}; @@ -67,13 +55,9 @@ class GMeshVLK : public IMesh { std::vector> imageDescriptorSets; std::vector descriptorSetsUpdated; - VkDescriptorPool m_descriptorPool; - std::shared_ptr m_lastRenderPass = nullptr; bool m_lastInvertedZ = false; std::shared_ptr m_lastPipelineForRenderPass; - - private: GDeviceVLK &m_device; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 83e9da7d3..0ae39e029 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -8,7 +8,6 @@ #include "../../../engine/algorithms/hashString.h" #include "../../../engine/shader/ShaderDefinitions.h" #include "../../UniformBufferStructures.h" -#include "../buffers/GUniformBufferVLK.h" #include "../../interface/IDevice.h" #include @@ -143,14 +142,14 @@ void GShaderPermutationVLK::updateDescriptorSet(int index) { std::vector bufferInfos; std::vector descriptorWrites; - auto *uploadBuffer = ((GUniformBufferVLK *) m_device->getUploadBuffer(index).get()); + auto *uploadBuffer = ((IBufferVLK *) m_device->getUploadBuffer(index).get()); if (uploadBuffer == nullptr) return; for (int i = 0; i < vertShaderMeta->uboBindings.size(); i++) { auto &uboVertBinding = vertShaderMeta->uboBindings[i]; VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = uploadBuffer->g_buf; + bufferInfo.buffer = uploadBuffer->getGPUBuffer(); bufferInfo.offset = 0; bufferInfo.range = uboVertBinding.size; bufferInfos.push_back(bufferInfo); @@ -159,7 +158,7 @@ void GShaderPermutationVLK::updateDescriptorSet(int index) { auto &uboFragBinding = fragShaderMeta->uboBindings[i]; VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = uploadBuffer->g_buf; + bufferInfo.buffer = uploadBuffer->getGPUBuffer(); bufferInfo.offset = 0; bufferInfo.range = uboFragBinding.size; bufferInfos.push_back(bufferInfo); @@ -204,8 +203,6 @@ void GShaderPermutationVLK::updateDescriptorSet(int index) { } void GShaderPermutationVLK::createUboDescriptorSets() { - uboDescriptorSets = std::vector>(4, NULL); - for (int j = 0; j < 4; j++) { std::vector descriptorWrites; uboDescriptorSets[j] = m_device->createDescriptorSet(uboDescriptorSetLayout, 5, 0); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index 959ae347c..7ecb9cc59 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -5,8 +5,6 @@ #ifndef AWEBWOWVIEWERCPP_GSHADERPERMUTATION_H #define AWEBWOWVIEWERCPP_GSHADERPERMUTATION_H -class GDeviceGL33; - #include #include #include "../GDeviceVulkan.h" @@ -51,7 +49,7 @@ class GShaderPermutationVLK : public IShaderPermutation { VkDescriptorSetLayout uboDescriptorSetLayout; VkDescriptorSetLayout imageDescriptorSetLayout; - std::vector> uboDescriptorSets; + std::array, 4> uboDescriptorSets = {nullptr}; GDeviceVLK *m_device; diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index f537c0f98..dd8d15ec6 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -9,7 +9,7 @@ template class IRendererParameters { - virtual void putIntoQueue(std::shared_ptr> &frameInputParams) = 0; + virtual void putIntoQueue(std::shared_ptr &frameInputParams) = 0; }; diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 3150c090d..31e139256 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -14,14 +14,14 @@ struct ViewPortDimensions{ std::array maxs; }; -template +//template struct FrameInputParams { HCameraMatrices matricesForCulling; HCameraMatrices cameraMatricesForRendering; HCameraMatrices cameraMatricesForDebugCamera; HScene scene; - std::shared_ptr additionalData; +// std::shared_ptr additionalData; //Time advance animTime_t delta = 0; @@ -30,10 +30,6 @@ struct FrameInputParams { ViewPortDimensions viewPortDimensions = {{0,0}, {64, 64}}; bool invertedZ = false; bool clearScreen = false; - - //Callback for culling stuff - std::function cullingDataCallback; - std::function frameBufferCallback; }; #endif //AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 2be5a8fde..769136c63 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -109,15 +109,11 @@ void SceneComposer::draw(HFrameScenario frameScenario) { std::future cullingFuture; std::future updateFuture; - m_apiContainer->hDevice->reset(); - if (!m_supportThreads) { processCaches(10); DoCulling(); DoUpdate(); } - m_apiContainer->hDevice->beginFrame(); - - m_apiContainer->hDevice->commitFrame(); + m_apiContainer->hDevice->drawScenario(); m_apiContainer->hDevice->increaseFrameNumber(); } diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h index 80adf7f5f..5ad9784b5 100644 --- a/wowViewerLib/src/renderer/frame/SceneScenario.h +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -30,7 +30,7 @@ class FrameScenarioBuilder { }; public: - template , T>>> + template , T>>> RendererSpecificData withSceneRenderer(T renderer) { return RendererSpecificData(this, renderer); } diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h new file mode 100644 index 000000000..819dbf23d --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -0,0 +1,27 @@ +// +// Created by Deamon on 22.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IMAPSCENEBUFFERCREATE_H +#define AWEBWOWVIEWERCPP_IMAPSCENEBUFFERCREATE_H + +#include +#include "../../gapi/interface/IDevice.h" + +class IMapSceneBufferCreate { +public: + virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; + + virtual HGVertexBuffer createADTVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createADTIndexBuffer(int sizeInBytes) = 0; + + virtual HGVertexBuffer createWMOVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createWMOIndexBuffer(int sizeInBytes) = 0; + + virtual HGVertexBuffer createWaterVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createWaterIndexBuffer(int sizeInBytes) = 0; +}; +typedef std::shared_ptr HMapSceneBufferCreate; + +#endif //AWEBWOWVIEWERCPP_IMAPSCENEBUFFERCREATE_H diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index 994e3c365..b18ba6345 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -6,7 +6,6 @@ #define AWEBWOWVIEWERCPP_MAPSCENEPLAN_H #include -#include "../../engine/objects/iWmoApi.h" #include "FrameDependentData.h" #include "../../engine/objects/ViewsObjects.h" #include "../../engine/objects/wmo/wmoObject.h" diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 23c48336e..674edd67a 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -6,17 +6,19 @@ #define AWEBWOWVIEWERCPP_MAPSCENERENDERER_H -#include "../../engine/objects/scenes/map.h" #include "../IRenderer.h" #include "../IRenderParameters.h" +#include "../../engine/objects/scenes/map.h" +#include "IMapSceneBufferCreate.h" -class MapSceneRenderer : public IRenderer, public IRendererParameters { +class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer() = default; ~MapSceneRenderer() override = 0; - - void putIntoQueue(FrameInputParams &cullStage) override = 0 ; }; +//typedef FrameInputParams MapSceneRendererInputParams; +typedef FrameInputParams MapSceneRendererInputParams; +typedef std::shared_ptr HMapSceneRenderer; #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERER_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 4334a0935..91c184eba 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -8,6 +8,40 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_devi } -void MapSceneRenderForwardVLK::putIntoQueue(FrameInputParams &frameInputParams) { +void MapSceneRenderForwardVLK::putIntoQueue(std::shared_ptr &frameInputParams) { } + + +//Buffer creation +HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { + return HGVertexBuffer(); +} + +HGIndexBuffer MapSceneRenderForwardVLK::createM2IndexBuffer(int sizeInBytes) { + return HGIndexBuffer(); +} + +HGVertexBuffer MapSceneRenderForwardVLK::createADTVertexBuffer(int sizeInBytes) { + return HGVertexBuffer(); +} + +HGIndexBuffer MapSceneRenderForwardVLK::createADTIndexBuffer(int sizeInBytes) { + return HGIndexBuffer(); +} + +HGVertexBuffer MapSceneRenderForwardVLK::createWMOVertexBuffer(int sizeInBytes) { + return HGVertexBuffer(); +} + +HGIndexBuffer MapSceneRenderForwardVLK::createWMOIndexBuffer(int sizeInBytes) { + return HGIndexBuffer(); +} + +HGVertexBuffer MapSceneRenderForwardVLK::createWaterVertexBuffer(int sizeInBytes) { + return HGVertexBuffer(); +} + +HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) { + return HGIndexBuffer(); +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 5fe062226..e2b6dcbff 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -13,7 +13,20 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { public: explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); - void putIntoQueue(FrameInputParams &frameInputParams) override; + void putIntoQueue(std::shared_ptr &frameInputParams) override; + + //Buffer creation + HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; + HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createWMOVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createWMOIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createWaterVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createWaterIndexBuffer(int sizeInBytes) override; private: HGDeviceVLK m_device; From 79a86391084b7aa25f256e423eb0d95274d88e97 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 28 Dec 2022 14:30:40 +0200 Subject: [PATCH 012/212] step one --- CMakeLists.txt | 4 +- src/ui/FrontendUI.cpp | 295 ++++++++---------- src/ui/FrontendUI.h | 4 + src/ui/renderer/uiScene/FrontendUIRenderer.h | 4 +- .../uiScene/IFrontendUIBufferCreate.h | 23 ++ .../renderer/uiScene/materials/UIMaterial.h | 23 ++ .../vulkan/FrontendUIRenderForwardVLK.cpp | 188 +---------- .../vulkan/FrontendUIRenderForwardVLK.h | 11 + wowViewerLib/CMakeLists.txt | 2 +- .../glsl/forwardRendering/adtShader.frag | 1 - .../src/engine/managers/CRibbonEmitter.cpp | 12 +- .../managers/particles/particleEmitter.cpp | 12 +- .../src/engine/objects/ViewsObjects.cpp | 12 +- .../src/engine/objects/adt/adtObject.cpp | 29 +- .../src/engine/objects/adt/adtObject.h | 2 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 12 +- .../src/engine/objects/m2/m2Object.cpp | 51 ++- wowViewerLib/src/engine/objects/m2/m2Object.h | 5 +- .../src/engine/objects/scenes/map.cpp | 21 +- wowViewerLib/src/engine/objects/scenes/map.h | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 57 ++-- .../src/engine/objects/wmo/wmoGroupObject.h | 4 +- .../src/engine/persistance/adtFile.cpp | 2 +- wowViewerLib/src/gapi/interface/IDevice.cpp | 1 - wowViewerLib/src/gapi/interface/IDevice.h | 11 +- .../src/gapi/interface/buffers/IBuffer.h | 2 + .../src/gapi/interface/buffers/IBufferChunk.h | 34 ++ .../interface/buffers/IUniformBufferChunk.h | 62 ---- .../src/gapi/interface/meshes/IMesh.h | 5 - .../src/gapi/interface/textures/ITexture.h | 2 +- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp | 2 +- .../gapi/ogl2.0/textures/GBlpTextureGL20.cpp | 4 +- .../gapi/ogl2.0/textures/GBlpTextureGL20.h | 2 +- .../src/gapi/ogl2.0/textures/GTextureGL20.h | 2 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp | 2 +- .../ogl3.3/buffers/GUnformBufferChunk33.h | 6 +- .../gapi/ogl3.3/textures/GBlpTextureGL33.cpp | 4 +- .../gapi/ogl3.3/textures/GBlpTextureGL33.h | 2 +- .../src/gapi/ogl3.3/textures/GTextureGL33.h | 2 +- .../gapi/ogl4.x/textures/GBlpTextureGL4x.cpp | 4 +- .../gapi/ogl4.x/textures/GBlpTextureGL4x.h | 2 +- .../src/gapi/ogl4.x/textures/GTextureGL4x.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 5 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 12 + .../src/gapi/vulkan/buffers/GBufferVLK.h | 7 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 38 +-- .../src/gapi/vulkan/meshes/GMeshVLK.h | 4 - .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 4 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 2 +- 51 files changed, 404 insertions(+), 601 deletions(-) create mode 100644 src/ui/renderer/uiScene/IFrontendUIBufferCreate.h create mode 100644 src/ui/renderer/uiScene/materials/UIMaterial.h create mode 100644 wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h delete mode 100644 wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fafb06f6..426f5046b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ set(SOURCE_FILES src/ui/renderer/uiScene/FrontendUIRendererFactory.h src/ui/renderer/uiScene/ImGUIPlan.cpp src/ui/renderer/uiScene/ImGUIPlan.h - ) + src/ui/renderer/uiScene/IFrontendUIBufferCreate.h) set(SOURCE_FILES_VULKAN @@ -275,7 +275,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/3rdparty/SQLiteCpp EXCLUDE_FROM_ALL) if (NOT Vulkan_FOUND) - set(SOURCE_FILES_VULKAN "") + set(SOURCE_FILES_VULKAN "" src/ui/renderer/uiScene/materials/UIMaterial.h) endif() add_executable(AWebWoWViewerCpp ${SOURCE_FILES} ${SOURCE_FILES_VULKAN}) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index e59675fbb..7116fce84 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -33,6 +33,7 @@ #include "../database/CSqliteDB.h" #include "../database/CEmptySqliteDB.h" #include "../../wowViewerLib/src/gapi/UniformBufferStructures.h" +#include "renderer/uiScene/IFrontendUIBufferCreate.h" void FrontendUI::composeUI() { if (this->fontTexture == nullptr) @@ -1736,170 +1737,136 @@ void FrontendUI::createDatabaseHandler() { filteredMapList = {}; } -//void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { -// auto m_device = m_api->hDevice; -// -// if (this->fontTexture == nullptr) { -// ImGuiIO& io = ImGui::GetIO(); -// unsigned char* pixels; -// int width, height; -// io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. -// // Upload texture to graphics system -// this->fontTexture = m_device->createTexture(false, false); -// this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); -// // Store our identifier -// io.Fonts->TexID = this->fontTexture; -// return; -// } -//// if (exporter != nullptr) { -//// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { -//// exporterFramesReady++; -//// } -//// if (exporterFramesReady > 5) { -//// exporter->saveToFile("model.gltf"); -//// exporter = nullptr; -//// } -//// } -// -// lastWidth = resultDrawStage->viewPortDimensions.maxs[0]; -// lastHeight = resultDrawStage->viewPortDimensions.maxs[1]; -// -// resultDrawStage->opaqueMeshes = std::make_shared(); -// auto *draw_data = ImGui::GetDrawData(); -// if (draw_data == nullptr) -// return; -// -// int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); -// int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); -// if (fb_width <= 0 || fb_height <= 0) { -// return; -// } -// ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports -// ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) -// //Create projection matrix: -// auto uiScale = ImGui::GetIO().uiScale; -// float L = draw_data->DisplayPos.x * uiScale; -// float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; -// float T = draw_data->DisplayPos.y * uiScale; -// float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; -// mathfu::mat4 ortho_projection = -// { -// { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, -// { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, -// { 0.0f, 0.0f, -1.0f, 0.0f }, -// { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, -// }; -// -// if (m_device->getIsVulkanAxisSystem()) { -// static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, -// 0, -1, 0, 0, -// 0, 0, 1.0/2.0, 1/2.0, -// 0, 0, 0, 1).Transpose(); -// ortho_projection = vulkanMatrixFix1 * ortho_projection; -// } -// auto uboPart = m_device->createUniformBufferChunk(sizeof(ImgUI::modelWideBlockVS)); -// -// -// uboPart->setUpdateHandler([ortho_projection,uiScale](IUniformBufferChunk* self, const HFrameDepedantData &frameDepedantData) { -// auto &uni = self->getObject(); -// uni.projectionMat = ortho_projection; -// uni.scale[0] = uiScale; -// }); -// -// auto shaderPermute = m_device->getShader("imguiShader", nullptr); -// // Render command lists -// for (int n = 0; n < draw_data->CmdListsCount; n++) -// { -// const ImDrawList* cmd_list = draw_data->CmdLists[n]; -// -// // Upload vertex/index buffers -// auto vertexBufferBindings = m_device->createVertexBufferBindings(); -// auto vboBuffer = m_device->createVertexBuffer(); -// auto iboBuffer = m_device->createIndexBuffer(); -// -// vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); -// iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); -// -// //Create vao -// GVertexBufferBinding vertexBufferBinding; -// vertexBufferBinding.bindings = std::vector(&imguiBindings[0], &imguiBindings[3]); -// vertexBufferBinding.vertexBuffer = vboBuffer; -// -// vertexBufferBindings->setIndexBuffer(iboBuffer); -// vertexBufferBindings->addVertexBufferBinding(vertexBufferBinding); -// vertexBufferBindings->save(); -// -// for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) -// { -// -// -// const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; -// if (pcmd->UserCallback != NULL) -// { -// // User callback, registered via ImDrawList::AddCallback() -// // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) -//// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) -//// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); -//// else -//// pcmd->UserCallback(cmd_list, pcmd); -// assert(pcmd->UserCallback == NULL); -// } -// else -// { -// // Project scissor/clipping rectangles into framebuffer space -// ImVec4 clip_rect; -// clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; -// clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; -// clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; -// clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; -// -// if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) -// { -// // Apply scissor/clipping rectangle -// // Create mesh add add it to collected meshes -// gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); -// meshTemplate.element = DrawElementMode::TRIANGLES; -// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; -// meshTemplate.backFaceCulling = false; -// meshTemplate.depthCulling = false; -////void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { -// -// meshTemplate.scissorEnabled = true; -// //Vulkan has different clip offset compared to OGL -// if (!m_device->getIsVulkanAxisSystem()) { -// meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; -// meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; -// } else { -// meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; -// meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; -// } -// -// meshTemplate.ubo[1] = uboPart; -// meshTemplate.textureCount = 1; -// meshTemplate.texture[0] = pcmd->TextureId; -// -// meshTemplate.start = pcmd->IdxOffset * 2; -// meshTemplate.end = pcmd->ElemCount; -// -// resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); -// } -// } +void FrontendUI::update(HFrontendUIBufferCreate renderer) { + auto m_device = m_api->hDevice; + + if (this->fontTexture == nullptr) { + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + // Upload texture to graphics system + this->fontTexture = m_device->createTexture(false, false); + this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); + // Store our identifier + io.Fonts->TexID = this->fontTexture; + return; + } +// if (exporter != nullptr) { +// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { +// exporterFramesReady++; // } -// } -// -// //1. Collect buffers -// auto &bufferChunks = updateStages[0]->uniformBufferChunks; -// int renderIndex = 0; -// for (const auto &mesh : resultDrawStage->opaqueMeshes->meshes) { -// for (int i = 0; i < 5; i++ ) { -// auto bufferChunk = mesh->getUniformBuffer(i); -// -// if (bufferChunk != nullptr) { -// bufferChunks.push_back(bufferChunk); -// } +// if (exporterFramesReady > 5) { +// exporter->saveToFile("model.gltf"); +// exporter = nullptr; // } // } -// -// std::sort( bufferChunks.begin(), bufferChunks.end()); -// bufferChunks.erase( unique( bufferChunks.begin(), bufferChunks.end() ), bufferChunks.end() ); -//} \ No newline at end of file + + auto *draw_data = ImGui::GetDrawData(); + if (draw_data == nullptr) + return; + + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) { + return; + } + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + //Create projection matrix: + auto uiScale = ImGui::GetIO().uiScale; + float L = draw_data->DisplayPos.x * uiScale; + float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; + float T = draw_data->DisplayPos.y * uiScale; + float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; + mathfu::mat4 ortho_projection = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + + if (m_device->getIsVulkanAxisSystem()) { + static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1.0/2.0, 1/2.0, + 0, 0, 0, 1).Transpose(); + ortho_projection = vulkanMatrixFix1 * ortho_projection; + } + std::shared_ptr> uboPart = nullptr; + + uboPart->setUpdateHandler([ortho_projection,uiScale](auto &data, const HFrameDependantData &frameDepedantData) { + auto &uni = data; + uni.projectionMat = ortho_projection; + uni.scale[0] = uiScale; + }); + + auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + + // Upload vertex/index buffers + + auto vboBuffer = renderer->createVertexBuffer(cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + auto iboBuffer = renderer->createIndexBuffer(cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + + auto vertexBufferBindings = renderer->createVAO(vboBuffer, iboBuffer); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) +// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) +// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); +// else +// pcmd->UserCallback(cmd_list, pcmd); + assert(pcmd->UserCallback == NULL); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + // Create mesh add add it to collected meshes + gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); + meshTemplate.element = DrawElementMode::TRIANGLES; + meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + meshTemplate.backFaceCulling = false; + meshTemplate.depthCulling = false; +//void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { + + meshTemplate.scissorEnabled = true; + //Vulkan has different clip offset compared to OGL + if (!m_device->getIsVulkanAxisSystem()) { + meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } else { + meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } + + meshTemplate.texture[0] = pcmd->TextureId; + + meshTemplate.start = pcmd->IdxOffset * 2; + meshTemplate.end = pcmd->ElemCount; + + renderer->createUIMesh(meshTemplate, uboPart) + } + } + } + } + +} \ No newline at end of file diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 83e70c60b..599b63c42 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -23,6 +23,7 @@ #include "childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h" #include "childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h" #include "../../wowViewerLib/src/exporters/IExporter.h" +#include "renderer/uiScene/IFrontendUIBufferCreate.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -243,6 +244,9 @@ class FrontendUI : public IScene, public std::enable_shared_from_this imguiBindings = {{ {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, @@ -16,8 +17,9 @@ static const std::array imguiBindings = {{ }}; -class FrontendUIRenderer : public IRendererParameters { +class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { public: + }; //typedef FrameInputParams FrontendUIInputParams; diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h new file mode 100644 index 000000000..2adddcc74 --- /dev/null +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -0,0 +1,23 @@ +// +// Created by Deamon on 25.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IFRONTENDUIBUFFERCREATE_H +#define AWEBWOWVIEWERCPP_IFRONTENDUIBUFFERCREATE_H + +#include "../../../../wowViewerLib/src/gapi/interface/IDevice.h" +#include "../../../../wowViewerLib/src/gapi/interface/IRendererProxy.h" +#include "materials/UIMaterial.h" + +class IFrontendUIBufferCreate { +public: + virtual HGVertexBuffer createVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createIndexBuffer(int sizeInBytes) = 0; + + virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + + virtual HGMesh createUIMesh(gMeshTemplate &meshTemplate, UIMaterial &material) = 0; +}; +typedef std::shared_ptr HFrontendUIBufferCreate; + +#endif //AWEBWOWVIEWERCPP_IFRONTENDUIBUFFERCREATE_H diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h new file mode 100644 index 000000000..cefc9bb01 --- /dev/null +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -0,0 +1,23 @@ +// +// Created by Deamon on 27.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IUIMATERIAL_H +#define AWEBWOWVIEWERCPP_IUIMATERIAL_H + +#include +#include "../../../../wowViewerLib/src/gapi/interface/textures/ITexture.h" +#include "../../../../wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h" +#include "../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" + +struct UIMaterialTemplate { + std::shared_ptr> uiUBO = nullptr; + std::shared_ptr texture = nullptr; +}; + +class IUIMaterial { +public: + virtual ~IUIMaterial() = 0; +}; + +#endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index e5dd48dfb..ffe19f69f 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -16,181 +16,6 @@ void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptr guard(m_inputParamsMtx); - - guard.lock(); - auto frameParams = m_inputParams.front(); - m_inputParams.pop(); - guard.unlock(); - -// if (this->fontTexture == nullptr) { -// ImGuiIO& io = ImGui::GetIO(); -// unsigned char* pixels; -// int width, height; -// io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. -// // Upload texture to graphics system -// this->fontTexture = m_device->createTexture(false, false); -// this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); -// // Store our identifier -// io.Fonts->TexID = this->fontTexture; -// return; -// } -// if (exporter != nullptr) { -// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { -// exporterFramesReady++; -// } -// if (exporterFramesReady > 5) { -// exporter->saveToFile("model.gltf"); -// exporter = nullptr; -// } -// } - int lastWidth = frameParams->viewPortDimensions.maxs[0]; - int lastHeight = frameParams->viewPortDimensions.maxs[1]; - - ImDrawData *draw_data = nullptr; //frameParams->additionalData->imData; - if (draw_data == nullptr) - return; - - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) { - return; - } - - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - //Create projection matrix: - auto uiScale = ImGui::GetIO().uiScale; - float L = draw_data->DisplayPos.x * uiScale; - float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; - float T = draw_data->DisplayPos.y * uiScale; - float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; - mathfu::mat4 ortho_projection = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, -1.0f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, - }; - - //Apply vulkan Matrix fix - if (true) { - static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1/2.0, - 0, 0, 0, 1).Transpose(); - ortho_projection = vulkanMatrixFix1 * ortho_projection; - } - - auto uboPart = m_device->createUniformBufferChunk(sizeof(ImgUI::modelWideBlockVS)); - - - uboPart->setUpdateHandler([ortho_projection,uiScale](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) { - auto &uni = self->getObject(); - uni.projectionMat = ortho_projection; - uni.scale[0] = uiScale; - }); - - auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); - - //Calc total size of index/vertex buffers needed - int vertexBufferSize = 0; - int indexBufferSize = 0; - for (int i = 0; i < draw_data->CmdListsCount; i++) { - const ImDrawList* cmd_list = draw_data->CmdLists[i]; - vertexBufferSize += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); - indexBufferSize += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); - } - - auto vboSubBuf = vboBuffer->getSubBuffer(vertexBufferSize); - auto iboSubBuf = iboBuffer->getSubBuffer(indexBufferSize); - - int vboOffset = 0; - int iboOffset = 0; - for (int i = 0; i < draw_data->CmdListsCount; i++) { - const ImDrawList* cmd_list = draw_data->CmdLists[i]; - - vboSubBuf->subUploadData(cmd_list->VtxBuffer.Data, vboOffset, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - iboSubBuf->subUploadData(cmd_list->IdxBuffer.Data, iboOffset, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - - vboOffset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); - iboOffset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); - } - - - - - // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - - // Upload vertex/index buffers - auto vertexBufferBindings = m_device->createVertexBufferBindings(); - - //Create vao - GVertexBufferBinding vertexBufferBinding; - vertexBufferBinding.bindings = std::vector(&imguiBindings[0], &imguiBindings[3]); - vertexBufferBinding.vertexBuffer = vboBuffer; - - vertexBufferBindings->setIndexBuffer(iboBuffer); - vertexBufferBindings->addVertexBufferBinding(vertexBufferBinding); - vertexBufferBindings->save(); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != NULL) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) -// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) -// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); -// else -// pcmd->UserCallback(cmd_list, pcmd); - assert(pcmd->UserCallback == NULL); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec4 clip_rect; - clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { - // Apply scissor/clipping rectangle - // Create mesh, add it to collected meshes - gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); - meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.backFaceCulling = false; - meshTemplate.depthCulling = false; - - meshTemplate.scissorEnabled = true; - //Vulkan has different clip offset compared to OGL - if (!m_device->getIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } else { - meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } - -// meshTemplate.ubo[1] = uboPart; -// meshTemplate.textureCount = 1; -// meshTemplate.texture[0] = pcmd->TextureId; -// -// meshTemplate.start = pcmd->IdxOffset * 2; -// meshTemplate.end = pcmd->ElemCount; -// -// resultDrawStage->opaqueMeshes->meshes.push_back(m_device->createMesh(meshTemplate)); - } - } - } - } } void FrontendUIRenderForwardVLK::createBuffers() { @@ -198,3 +23,16 @@ void FrontendUIRenderForwardVLK::createBuffers() { iboBuffer = m_device->createVertexBuffer(1024*1024); uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); } + +HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { + return vboBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGMesh FrontendUIRenderForwardVLK::createUIMesh(gMeshTemplate &meshTemplate, IBufferChunk) { + //TODO: + return nullptr; +} diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 69f5b8306..fc066d3ce 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -10,6 +10,7 @@ #include "../FrontendUIRenderer.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h" +#include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: @@ -17,6 +18,16 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { void putIntoQueue(std::shared_ptr &frameInputParams) override; void update(VkCommandBuffer udBuffer, VkCommandBuffer swapChainDraw); +public: + HGVertexBuffer createVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createIndexBuffer(int sizeInBytes) override; + + HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override { + return nullptr; //VAO doesnt exist in Vulkan + }; + HGMesh createUIMesh(gMeshTemplate &meshTemplate, IBufferChunk);; + + private: HGDeviceVLK m_device; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 7fe3b9d7a..531e15d93 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -282,7 +282,7 @@ set(SOURCE_FILES src/engine/objects/ViewsObjects.cpp src/engine/objects/ViewsObjects.h src/gapi/interface/sortLambda.h - src/gapi/interface/buffers/IUniformBufferChunk.h + src/gapi/interface/buffers/IBufferChunk.h src/engine/WowFilesCacheStorage.h src/engine/WowFilesCacheStorage.cpp src/engine/algorithms/quick-sort-omp.h diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index f2c5e7d59..930a8a027 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -75,7 +75,6 @@ void main() { vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); - vec4 weightedLayer_0 = (texture(uLayer0, tcLayer0) * weightsNormalized.x); vec3 matDiffuse_0 = weightedLayer_0.xyz; float specBlend_0 = weightedLayer_0.w; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 576a2102f..a9fa1bc7d 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -140,17 +140,13 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(Ribbon::meshRibbonWideBlockPS)); auto blendMode = meshTemplate.blendMode; auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; - meshTemplate.ubo[4]->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { - Ribbon::meshRibbonWideBlockPS& blockPS = self->getObject(); + std::shared_ptr> meshRibbonWideBlockPS = nullptr; + + meshRibbonWideBlockPS->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](auto &data, const HFrameDependantData &frameDepedantData) { + Ribbon::meshRibbonWideBlockPS& blockPS = data; blockPS.uAlphaTest = -1.0f; blockPS.uPixelShader = 0; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 3d1f2e1b8..0318935e7 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -339,16 +339,10 @@ void ParticleEmitter::createMesh() { } meshTemplate.texture.resize((multitex) ? 3 : 1); - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(Particle::meshParticleWideBlockPS)); - auto l_blendMode = meshTemplate.blendMode; - meshTemplate.ubo[4]->setUpdateHandler([this, l_blendMode](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { - Particle::meshParticleWideBlockPS &blockPS = self->getObject(); + std::shared_ptr> meshParticleWideBlockPS = nullptr; + meshParticleWideBlockPS->setUpdateHandler([this, l_blendMode](auto &data, const HFrameDependantData &frameDepedantData) { + Particle::meshParticleWideBlockPS &blockPS = data; uint8_t blendMode = m_data->old.blendingType; if (blendMode == 0) { blockPS.uAlphaTest = -1.0f; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 7441c859f..ef5add54d 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -160,15 +160,9 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st meshTemplate.end = indiciesArray.size(); meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = hDevice->createUniformBufferChunk(sizeof(DrawPortalShader::meshWideBlockPS)); - - meshTemplate.ubo[4]->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { - auto& blockPS = self->getObject(); + std::shared_ptr> drawPortalShaderMeshWideBlockPS = nullptr; + drawPortalShaderMeshWideBlockPS->setUpdateHandler([](auto &data, const HFrameDependantData &frameDepedantData) { + auto& blockPS = data; blockPS.uColor = {0.058, 0.058, 0.819607843, 0.3}; }); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 1826041ee..d592213bb 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -635,13 +635,14 @@ void AdtObject::createMeshes() { auto adtFileTex = m_adtFileTex; auto adtFile = m_adtFile; - adtWideBlockPS = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::modelWideBlockPS)); - +// adtWideBlockPS = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::modelWideBlockPS)); + adtWideBlockPS = nullptr; int useHeightMixFormula = m_wdtFile->mphd->flags.adt_has_height_texturing > 0; // int useHeightMixFormula = 1; auto api = m_api; - adtWideBlockPS->setUpdateHandler([api, useHeightMixFormula](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - auto *adtWideblockPS = &self->getObject(); + + adtWideBlockPS->setUpdateHandler([api, useHeightMixFormula](auto &data, const HFrameDependantData &frameDepedantData){ + auto *adtWideblockPS = &data; adtWideblockPS->useHeightMixFormula[0] = useHeightMixFormula; }); @@ -665,17 +666,18 @@ void AdtObject::createMeshes() { aTemplate.end = m_adtFile->stripOffsets[i + 1] - m_adtFile->stripOffsets[i]; aTemplate.element = DrawElementMode::TRIANGLES; - aTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - aTemplate.ubo[1] = nullptr; - aTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockVS)); - aTemplate.ubo[3] = adtWideBlockPS; - aTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockPS)); +// aTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); +// aTemplate.ubo[1] = nullptr; +// aTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockVS)); +// aTemplate.ubo[3] = adtWideBlockPS; +// aTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockPS)); aTemplate.texture = std::vector(9, nullptr); int chunkIndex = i; - aTemplate.ubo[4]->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { - auto &blockPS = self->getObject(); + std::shared_ptr> meshWideBlockPS = nullptr; + meshWideBlockPS->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](auto &data, const HFrameDependantData &frameDepedantData) { + auto &blockPS = data; for (int j = 0; j < 4; j++) { blockPS.uHeightOffset[j] = 0.0f; @@ -693,8 +695,9 @@ void AdtObject::createMeshes() { } }); - aTemplate.ubo[2]->setUpdateHandler([this, i](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { - auto &blockVS = self->getObject(); + std::shared_ptr> meshWideBlockVS = nullptr; + meshWideBlockVS->setUpdateHandler([this, i](auto &data, const HFrameDependantData &frameDepedantData) { + auto &blockVS = data; blockVS.uPos = mathfu::vec4( this->m_adtFile->mapTile[i].position.x, this->m_adtFile->mapTile[i].position.y, diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 0b07c907a..82ae8dbc8 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -125,7 +125,7 @@ class AdtObject { HGVertexBufferBindings lodVertexBindings; - HGUniformBufferChunk adtWideBlockPS; + std::shared_ptr> adtWideBlockPS; diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 79849e770..d1b8ce7ca 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -27,7 +27,9 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object int batchIndex = materialData.batchIndex; auto vertexShader = materialData.vertexShader; - hmesh->getUniformBuffer(2)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, vertexShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ + std::shared_ptr> meshWideBlockVS = nullptr; + + meshWideBlockVS->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, vertexShader](auto &data, const HFrameDependantData &frameDepedantData){ auto m2Data = m2Object->m_m2Geom->getM2Data(); auto batch = m2SkinProfile->batches[batchIndex]; @@ -38,19 +40,19 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); - auto &meshblockVS = self->getObject(); + auto &meshblockVS = data; meshblockVS.Color_Transparency = mathfu::vec4_packed(mathfu::vec4(meshColor.x, meshColor.y, meshColor.z, finalTransparency)); meshblockVS.isSkyBox = m2Object->m_boolSkybox ? 1 : 0; meshblockVS.VertexShader = vertexShader; meshblockVS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; fillTextureMatrices(*m2Object, batchIndex, m2Data, m2SkinProfile, meshblockVS.uTextMat); - }); //3. Update individual PS buffer auto pixelShader = materialData.pixelShader; - hmesh->getUniformBuffer(4)->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, pixelShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { + std::shared_ptr> meshWideBlockPS = nullptr; + meshWideBlockPS->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, pixelShader](auto &data, const HFrameDependantData &frameDepedantData) { auto m2Data = m2Object->m_m2Geom->getM2Data(); auto batch = m2SkinProfile->batches[batchIndex]; @@ -76,7 +78,7 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object // mathfu::vec3 uFogColor = getFogColor(blendMode, uGlobalFogColor); //Fill values into buffer - auto &meshblockPS = self->getObject(); + auto &meshblockPS = data; meshblockPS.PixelShader = pixelShader; meshblockPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; meshblockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index c2819da9c..6fb67c3af 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1269,17 +1269,11 @@ void M2Object::createBoundingBoxMesh() { meshTemplate.element = DrawElementMode::TRIANGLES; - HGUniformBufferChunk bbBlockVS = m_api->hDevice->createUniformBufferChunk(sizeof(bbModelWideBlockVS)); - - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = bbBlockVS; - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = nullptr; +// std::shared_ptr> bbBlockVS = m_api->hDevice->createUniformBufferChunk(sizeof(bbModelWideBlockVS)); + std::shared_ptr> bbBlockVS = nullptr; auto l_m2Geom = m_m2Geom; - bbBlockVS->setUpdateHandler([this, l_m2Geom](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ + bbBlockVS->setUpdateHandler([this, l_m2Geom](auto &data, const HFrameDependantData &frameDepedantData){ M2Data *m2Data = l_m2Geom->getM2Data(); CAaBox &aaBox = m2Data->bounding_box; @@ -1295,7 +1289,7 @@ void M2Object::createBoundingBoxMesh() { aaBox.max.z - center[2] ); - bbModelWideBlockVS &blockVS = self->getObject(); + bbModelWideBlockVS &blockVS = data; blockVS.uPlacementMat = m_placementMatrix; blockVS.uBBScale = mathfu::vec4_packed(mathfu::vec4(scale, 0.0)); blockVS.uBBCenter = mathfu::vec4_packed(mathfu::vec4(center, 0.0)); @@ -1378,22 +1372,18 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshTemplate.texture[3] = getTexture(3); //bumpTexture meshTemplate.texture[4] = getTexture(4); //normalTex - - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = vertexModelWideUniformBuffer; - meshTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::WaterfallData::meshWideBlockVS)); - - meshTemplate.ubo[2]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - auto &meshblockVS = self->getObject(); + std::shared_ptr> waterFallMeshWideBlockVS = nullptr; + waterFallMeshWideBlockVS->setUpdateHandler([this, skinData, m2Data, wfv3Data](auto &data, const HFrameDependantData &frameDepedantData){ + auto &meshblockVS = data; meshblockVS.bumpScale = mathfu::vec4(wfv3Data->bumpScale, 0, 0, 0); M2MeshBufferUpdater::fillTextureMatrices(*this, 0, m2Data, skinData, meshblockVS.uTextMat); }); - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::WaterfallData::meshWideBlockPS)); - meshTemplate.ubo[4]->setUpdateHandler([this, skinData, m2Data, wfv3Data](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - auto &meshblockPS = self->getObject(); + + std::shared_ptr> waterFallMeshWideBlockPS = nullptr; + waterFallMeshWideBlockPS->setUpdateHandler([this, skinData, m2Data, wfv3Data](auto &data, const HFrameDependantData &frameDepedantData){ + auto &meshblockPS = data; meshblockPS.baseColor = mathfu::vec4( wfv3Data->basecolor.a / 255.0f, wfv3Data->basecolor.r / 255.0f, @@ -1576,12 +1566,6 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti for (int j = 0; j < material.textureCount; j++) { meshTemplate.texture[j] = material.textures[j]; } - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = vertexModelWideUniformBuffer; - meshTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::meshWideBlockVS)); - - meshTemplate.ubo[3] = fragmentModelWideUniformBuffer; - meshTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(M2::meshWideBlockPS)); //Make mesh //TODO: @@ -1911,22 +1895,23 @@ void M2Object::createVertexBindings() { //3. Create model wide uniform buffer // vertexModelWideUniformBuffer = device->createUniformBuffer(sizeof(mathfu::mat4) * (m_m2Geom->m_m2Data->bones.size + 1)); - vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockVS), (m_m2Geom->m_m2Data->bones.size + 1) * sizeof(mathfu::mat4)); - fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockPS)); + //TODO: +// vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockVS), (m_m2Geom->m_m2Data->bones.size + 1) * sizeof(mathfu::mat4)); +// fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(M2::modelWideBlockPS)); - vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - auto &blockVS = self->getObject(); + vertexModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ + auto &blockVS = data; blockVS.uPlacementMat = m_placementMatrix; int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, blockVS.uBoneMatrixes); }); - fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ + fragmentModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); mathfu::vec4 localDiffuse = diffuseNon; - M2::modelWideBlockPS &blockPS = self->getObject(); + M2::modelWideBlockPS &blockPS = data; blockPS.intLight.uInteriorAmbientColorAndApplyInteriorLight = mathfu::vec4_packed(mathfu::vec4( diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index c17147e80..d958e8906 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -25,6 +25,7 @@ class M2ObjectListContainer; #include "../../managers/CRibbonEmitter.h" #include "../../ApiContainer.h" #include "m2Helpers/CBoneMasterData.h" +#include "../../../gapi/UniformBufferStructures.h" class M2Object { @@ -87,8 +88,8 @@ class M2Object { std::shared_ptr m_boneMasterData = nullptr; HGVertexBufferBindings bufferBindings = nullptr; - HGUniformBufferChunk vertexModelWideUniformBuffer = nullptr; - HGUniformBufferChunk fragmentModelWideUniformBuffer = nullptr; + std::shared_ptr> vertexModelWideUniformBuffer = nullptr; + std::shared_ptr> fragmentModelWideUniformBuffer = nullptr; HGMesh boundingBoxMesh = nullptr; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 4cd98c732..af1e032d2 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -305,13 +305,13 @@ Map::Map(HApiContainer api, int mapId, std::string mapName) { loadZoneLights(); - m_sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); + m_sceneWideBlockVSPSChunk = nullptr; } HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config *config, bool conusFor0x4Sky) { - auto skyVs = device->createUniformBufferChunk(sizeof(DnSky::meshWideBlockVS)); - skyVs->setUpdateHandler([config, conusFor0x4Sky](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { - auto &meshblockVS = self->getObject(); + std::shared_ptr> skyVs = nullptr; + skyVs->setUpdateHandler([config, conusFor0x4Sky](auto &data, const HFrameDependantData &frameDepedantData) -> void { + auto &meshblockVS = data; if (!conusFor0x4Sky) { meshblockVS.skyColor[0] = frameDepedantData->SkyTopColor; @@ -346,13 +346,6 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config meshTemplate.texture.resize(0); - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = nullptr; - meshTemplate.ubo[2] = skyVs; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = nullptr; - meshTemplate.element = DrawElementMode::TRIANGLE_STRIP; if (conusFor0x4Sky) { meshTemplate.start = 198 * 2; @@ -2061,9 +2054,9 @@ void Map::loadZoneLights() { } } -IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrices &renderMats, Config* config) { - return [renderMats, config](IUniformBufferChunk *chunk, const HFrameDependantData &fdd) -> void { - auto *blockPSVS = &chunk->getObject(); +IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrices &renderMats, Config* config) { + return [renderMats, config](auto &data, const HFrameDependantData &fdd) -> void { + auto *blockPSVS = &data; blockPSVS->uLookAtMat = renderMats->lookAtMat; blockPSVS->uPMatrix = renderMats->perspectiveMat; diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 25f81531b..b7139384b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -69,7 +69,7 @@ class Map : public IScene, public IMapApi { std::vector> m_mandatoryADT; std::string mapName; - HGUniformBufferChunk m_sceneWideBlockVSPSChunk; + std::shared_ptr> m_sceneWideBlockVSPSChunk; SceneMode m_sceneMode = SceneMode::smMap; @@ -232,7 +232,7 @@ class Map : public IScene, public IMapApi { void createAdtFreeLamdas(); - IChunkHandlerType generateSceneWideChunk(HCameraMatrices &renderMats, Config* config); + IChunkHandlerType generateSceneWideChunk(HCameraMatrices &renderMats, Config* config); }; typedef std::shared_ptr HMapScene; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index aa0805f50..0a49224c4 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -413,16 +413,18 @@ void WmoGroupObject::createMeshes() { //TODO: HGVertexBufferBindings binding = nullptr; //m_geom->getVertexBindings(device); - vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); +// vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); - vertexModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - WMO::modelWideBlockVS &blockVS = self->getObject(); + vertexModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ + WMO::modelWideBlockVS &blockVS = data; blockVS.uPlacementMat = *m_modelMatrix; }); - fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockPS)); - fragmentModelWideUniformBuffer->setUpdateHandler([this](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - WMO::modelWideBlockPS &blockPS = self->getObject(); +//TODO: + +// fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockPS)); + fragmentModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ + WMO::modelWideBlockPS &blockPS = data; blockPS.intLight.uInteriorAmbientColorAndApplyInteriorLight = mathfu::vec4_packed( mathfu::vec4( @@ -517,27 +519,28 @@ void WmoGroupObject::createMeshes() { } + std::shared_ptr> wmoMeshWideBlockVS = nullptr; + std::shared_ptr> wmoMeshWideBlockPS = nullptr; - - meshTemplate.ubo[0] = nullptr; - meshTemplate.ubo[1] = vertexModelWideUniformBuffer; - meshTemplate.ubo[2] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockVS)); - - meshTemplate.ubo[3] = fragmentModelWideUniformBuffer; - meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockPS)); +// +// meshTemplate.ubo[0] = nullptr; +// meshTemplate.ubo[1] = vertexModelWideUniformBuffer; +// meshTemplate.ubo[2] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockVS)); +// +// meshTemplate.ubo[3] = fragmentModelWideUniformBuffer; +// meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockPS)); //Make mesh HGMesh hmesh = device->createMesh(meshTemplate); this->m_meshArray.push_back(hmesh); - hmesh->getUniformBuffer(2)->setUpdateHandler([this, &material, vertexShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData){ - WMO::meshWideBlockVS &blockVS = self->getObject(); + wmoMeshWideBlockVS->setUpdateHandler([this, &material, vertexShader](auto &data, const HFrameDependantData &frameDepedantData){ + WMO::meshWideBlockVS &blockVS = data; blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; blockVS.VertexShader = vertexShader; }); - - hmesh->getUniformBuffer(4)->setUpdateHandler([this, isBatchA, isBatchC, &material, blendMode, pixelShader](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) { + wmoMeshWideBlockPS->setUpdateHandler([this, isBatchA, isBatchC, &material, blendMode, pixelShader](auto &data, const HFrameDependantData &frameDepedantData) { // mathfu::vec4 globalAmbientColor = m_api->getGlobalAmbientColor(); mathfu::vec4 localambientColor = this->getAmbientColor(); mathfu::vec3 directLight = mathfu::vec3(0,0,0); @@ -550,7 +553,7 @@ void WmoGroupObject::createMeshes() { } float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; - auto &blockPS = self->getObject(); + auto &blockPS = data; // blockPS.uFogStartAndFogEndAndIsBatchA = mathfu::vec4_packed( // mathfu::vec4( // m_api->getConfig()->getFogStart(), @@ -681,12 +684,13 @@ void WmoGroupObject::createWaterMeshes() { meshTemplate.texture[0] = m_api->hDevice->getBlackTexturePixel(); } - meshTemplate.ubo[0] = nullptr;//m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = vertexModelWideUniformBuffer; - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = device->createUniformBufferChunk(16); + //TODO: +// meshTemplate.ubo[0] = nullptr;//m_api->getSceneWideUniformBuffer(); +// meshTemplate.ubo[1] = vertexModelWideUniformBuffer; +// meshTemplate.ubo[2] = nullptr; +// +// meshTemplate.ubo[3] = nullptr; +// meshTemplate.ubo[4] = device->createUniformBufferChunk(16); meshTemplate.start = 0; meshTemplate.end = m_geom->waterIndexSize; @@ -694,9 +698,10 @@ void WmoGroupObject::createWaterMeshes() { auto l_liquidType = liquid_type; + std::shared_ptr> chunkBlock = nullptr; - meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, liquidFlags, color](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) -> void { - mathfu::vec4_packed &color_ = self->getObject(); + chunkBlock->setUpdateHandler([this, l_liquidType, liquidFlags, color](auto &data, const HFrameDependantData &frameDepedantData) -> void { + mathfu::vec4_packed &color_ = data; if ((liquidFlags & 1024) > 0) {// Ocean color_ = frameDepedantData->closeOceanColor; } else if (liquidFlags == 15) { //River/Lake diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 1b244d879..a18ff1ed3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -78,8 +78,8 @@ class WmoGroupObject { mathfu::mat4 *m_modelMatrix = nullptr; int m_groupNumber; - HGUniformBufferChunk vertexModelWideUniformBuffer = nullptr; - HGUniformBufferChunk fragmentModelWideUniformBuffer = nullptr; + std::shared_ptr> vertexModelWideUniformBuffer = nullptr; + std::shared_ptr> fragmentModelWideUniformBuffer = nullptr; std::vector m_meshArray = {}; std::vector m_waterMeshArray = {}; diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 19781b1a0..f0643923f 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -45,7 +45,7 @@ chunkDef AdtFile::adtFileTable = { 'MHID', { [](AdtFile& file, ChunkData& chunkData){ - debuglog("Entered MDID"); + debuglog("Entered MHID"); file.mhid_len = chunkData.chunkLen / 4; chunkData.readValues(file.mhid, file.mhid_len); } diff --git a/wowViewerLib/src/gapi/interface/IDevice.cpp b/wowViewerLib/src/gapi/interface/IDevice.cpp index deb81ee3f..d91595bc9 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.cpp +++ b/wowViewerLib/src/gapi/interface/IDevice.cpp @@ -47,7 +47,6 @@ bool IDevice::getIsAnisFiltrationSupported() { } } return anisFiltrationSupported == 1; - #else return true; #endif diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index be8727441..e1784426f 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -10,7 +10,6 @@ class IVertexBufferDynamic; class IVertexBufferBindings; class IBuffer; class IUniformBuffer; -class IUniformBufferChunk; class ITexture; class IShaderPermutation; class IMesh; @@ -33,7 +32,6 @@ typedef std::shared_ptr HGVertexBuffer; typedef std::shared_ptr HGIndexBuffer; typedef std::shared_ptr HGVertexBufferBindings; typedef std::shared_ptr HGUniformBuffer; -typedef std::shared_ptr HGUniformBufferChunk; typedef std::shared_ptr HGShaderPermutation; typedef std::shared_ptr HGMesh; typedef std::shared_ptr HGM2Mesh; @@ -49,7 +47,7 @@ typedef std::shared_ptr HFrameBuffer; #include "IShaderPermutation.h" #include "buffers/IBuffer.h" #include "IVertexBufferBindings.h" -#include "buffers/IUniformBufferChunk.h" +#include "buffers/IBufferChunk.h" #include "../../engine/wowCommonClasses.h" #include "../../engine/texture/BlpTexture.h" #include "textures/ITexture.h" @@ -178,13 +176,6 @@ class IDevice { virtual HGShaderPermutation getShader(std::string shaderName, std::string fragmentName, void *permutationDescriptor) = 0; virtual HGPUFence createFence() = 0; - - virtual HGUniformBufferChunk createUniformBufferChunk(size_t size, size_t realSize = 0) { - HGUniformBufferChunk h_uniformBuffer; - h_uniformBuffer.reset(new IUniformBufferChunk(size, realSize)); - - return h_uniformBuffer; - }; virtual HGVertexBufferBindings createVertexBufferBindings() = 0; //Creates or receives framebuffer and tells it would be occupied for frameNumber frames virtual HFrameBuffer createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) = 0; diff --git a/wowViewerLib/src/gapi/interface/buffers/IBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h index 77f92a215..0679e9051 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IBuffer.h +++ b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h @@ -10,6 +10,8 @@ class IBuffer { virtual void uploadData(void *, int length) = 0; virtual void subUploadData(void *, int offset, int length) = 0; virtual void *getPointer() = 0; + virtual void save(int length) = 0; + virtual size_t getSize() = 0; }; diff --git a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h new file mode 100644 index 000000000..c9ecc5f9a --- /dev/null +++ b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h @@ -0,0 +1,34 @@ +// +// Created by deamon on 09.12.19. +// + +#ifndef AWEBWOWVIEWERCPP_IBUFFERCHUNK_H +#define AWEBWOWVIEWERCPP_IBUFFERCHUNK_H + +#include +#include +#include "../../../renderer/mapScene/FrameDependentData.h" + +template +using IChunkHandlerType = std::function ; + +template +class IBufferChunk { + friend class IDevice; +private: + IChunkHandlerType m_handler; +public: + virtual ~IBufferChunk() = default; + virtual T &getObject() = 0; + + virtual void setUpdateHandler(IChunkHandlerType handler) { + m_handler = handler; + }; + + virtual void update(const HFrameDependantData &frameDepedantData) { + if (m_handler) { + m_handler(this, frameDepedantData); + } + }; +}; +#endif //AWEBWOWVIEWERCPP_IBUFFERCHUNK_H diff --git a/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h deleted file mode 100644 index e3d957cab..000000000 --- a/wowViewerLib/src/gapi/interface/buffers/IUniformBufferChunk.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Created by deamon on 09.12.19. -// - -#ifndef AWEBWOWVIEWERCPP_IUNIFORMBUFFERCHUNK_H -#define AWEBWOWVIEWERCPP_IUNIFORMBUFFERCHUNK_H - -#include -#include -#include "../../../renderer/mapScene/FrameDependentData.h" - -typedef std::function IChunkHandlerType; - -class IUniformBufferChunk { - friend class IDevice; -private: - IChunkHandlerType m_handler; -protected: - size_t m_offset = 0; - size_t m_size = 0; - size_t m_realSize = 0; - void *m_ptr = nullptr; -public: - IUniformBufferChunk(size_t size, size_t realSize = 0) : m_size(size), m_realSize(realSize) {} - virtual ~IUniformBufferChunk() = default; - - void setOffset(size_t offset) { - m_offset = offset; - } - void setPointer(void *ptr) { - m_ptr = ptr; - } - void * getPtr() { - return m_ptr; - } - - - template - T &getObject() { - assert(sizeof(T) == m_size); - return *(T *) getPtr(); - } - size_t getSize() { - return m_size; - } - size_t getRealSize() { - return m_realSize; - } - size_t getOffset() { - return m_offset; - } - - virtual void setUpdateHandler(IChunkHandlerType handler) { - m_handler = handler; - }; - virtual void update(const HFrameDependantData &frameDepedantData) { - if (m_handler) { - m_handler(this, frameDepedantData); - } - }; -}; -#endif //AWEBWOWVIEWERCPP_IUNIFORMBUFFERCHUNK_H diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index d9b06efcb..af0480a10 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -71,7 +71,6 @@ class gMeshTemplate { int end; DrawElementMode element; std::vector texture = {}; - std::array ubo = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}; bool scissorEnabled = false; std::array scissorOffset = {0,0}; @@ -97,15 +96,11 @@ class IMesh { int m_end; std::vector m_texture = {}; - - std::array m_UniformBuffer = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; - public: virtual ~IMesh(){ // std::cout << "Mesh destroyed" << std::endl; }; - virtual inline HGUniformBufferChunk getUniformBuffer(int slot) = 0; virtual bool getIsTransparent() = 0; virtual MeshType getMeshType() = 0; diff --git a/wowViewerLib/src/gapi/interface/textures/ITexture.h b/wowViewerLib/src/gapi/interface/textures/ITexture.h index 2d66b4dae..b6eb3698c 100644 --- a/wowViewerLib/src/gapi/interface/textures/ITexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ITexture.h @@ -27,6 +27,6 @@ class ITexture { - virtual void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) = 0; + virtual void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) = 0; }; #endif //AWEBWOWVIEWERCPP_ITEXTURE_H diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp index 657439d93..6dc047eea 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp @@ -319,7 +319,7 @@ void GDeviceGL20::drawMesh(HGMesh hIMesh, HGUniformBufferChunk matrixChunk) { bindVertexBufferBindings(hmesh->m_bindings.get()); for (int i = 0; i < 5; i++) { - IUniformBufferChunk *uniformChunk = nullptr; + IBufferChunk * uniformChunk = nullptr; if (i == 0) { uniformChunk = matrixChunk.get(); } else { diff --git a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.cpp index 40d21d009..0fcbaf4b2 100644 --- a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.cpp @@ -25,7 +25,7 @@ void GBlpTextureGL20::unbind() { } static int texturesUploaded = 0; -void GBlpTextureGL20::createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { +void GBlpTextureGL20::createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { // std::cout << "texturesUploaded = " << texturesUploaded++ << " " << this->m_texture->getTextureName() <getStatus() != FileStatus::FSLoaded) return false; m_device.bindTexture(this, 0); - this->createGlTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); + this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); m_device.bindTexture(nullptr, 0); m_loaded = true; diff --git a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h index 447614d82..f89dbb64c 100644 --- a/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/textures/GBlpTextureGL20.h @@ -13,7 +13,7 @@ class GBlpTextureGL20 : public GTextureGL20 { explicit GBlpTextureGL20(IDevice &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); public: ~GBlpTextureGL20() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override; + void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override; bool getIsLoaded() override; bool postLoad() override; diff --git a/wowViewerLib/src/gapi/ogl2.0/textures/GTextureGL20.h b/wowViewerLib/src/gapi/ogl2.0/textures/GTextureGL20.h index 385d0bae0..d910d86c9 100644 --- a/wowViewerLib/src/gapi/ogl2.0/textures/GTextureGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/textures/GTextureGL20.h @@ -19,7 +19,7 @@ class GTextureGL20 : public ITexture { void loadData(int width, int height, void *data, ITextureFormat textureFormat) override; void readData(std::vector &buff) override {}; bool getIsLoaded() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { + void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { // throw "Not Implemented in this class"; } bool postLoad() override { return false;}; diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp index 22bd75a7e..57f9abc28 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp @@ -518,7 +518,7 @@ void GDeviceGL33::drawMesh(HGMesh hIMesh, HGUniformBufferChunk matrixChunk) { #ifndef __EMSCRIPTEN__ for (int i = 0; i < 5; i++) { - IUniformBufferChunk *uniformChunk = nullptr; + IBufferChunk * uniformChunk = nullptr; if (i == 0) { uniformChunk = matrixChunk.get(); } else { diff --git a/wowViewerLib/src/gapi/ogl3.3/buffers/GUnformBufferChunk33.h b/wowViewerLib/src/gapi/ogl3.3/buffers/GUnformBufferChunk33.h index 71e7333aa..9f17d8aba 100644 --- a/wowViewerLib/src/gapi/ogl3.3/buffers/GUnformBufferChunk33.h +++ b/wowViewerLib/src/gapi/ogl3.3/buffers/GUnformBufferChunk33.h @@ -5,16 +5,16 @@ #ifndef AWEBWOWVIEWERCPP_GUNFORMBUFFERCHUNK33_H #define AWEBWOWVIEWERCPP_GUNFORMBUFFERCHUNK33_H -#include "../../interface/buffers/IUniformBufferChunk.h" +#include "../../interface/buffers/IBufferChunk.h" #include "../../interface/IDevice.h" -class GUniformBufferChunk33 : public IUniformBufferChunk { +class GUniformBufferChunk33 : public IBufferChunk { private: HGUniformBuffer m_uniformBuffer = nullptr; public: - GUniformBufferChunk33(size_t size, size_t realSize = -1) : IUniformBufferChunk(size, realSize) {} + GUniformBufferChunk33(size_t size, size_t realSize = -1) : IBufferChunk(size, realSize) {} void setUniformBuffer(HGUniformBuffer uniformBuffer) { m_uniformBuffer = uniformBuffer; diff --git a/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.cpp index f7a792df7..289b89967 100644 --- a/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.cpp @@ -43,7 +43,7 @@ void GBlpTextureGL33::unbind() { } static int texturesUploaded = 0; -void GBlpTextureGL33::createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { +void GBlpTextureGL33::createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { // std::cout << "texturesUploaded = " << texturesUploaded++ << " " << this->m_texture->getTextureName() <getStatus() != FileStatus::FSLoaded) return false; m_device->bindTexture(this, 0); - this->createGlTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); + this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); m_device->bindTexture(nullptr, 0); // m_texture = nullptr; diff --git a/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.h b/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.h index b0e1d0b9f..c388599dc 100644 --- a/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/textures/GBlpTextureGL33.h @@ -13,7 +13,7 @@ class GBlpTextureGL33 : public GTextureGL33 { explicit GBlpTextureGL33(HGDevice device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); public: ~GBlpTextureGL33() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override; + void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override; bool getIsLoaded() override; bool postLoad() override; diff --git a/wowViewerLib/src/gapi/ogl3.3/textures/GTextureGL33.h b/wowViewerLib/src/gapi/ogl3.3/textures/GTextureGL33.h index 13681d825..a4c77d18c 100644 --- a/wowViewerLib/src/gapi/ogl3.3/textures/GTextureGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/textures/GTextureGL33.h @@ -19,7 +19,7 @@ class GTextureGL33 : public ITexture { void loadData(int width, int height, void *data, ITextureFormat textureFormat) override; void readData(std::vector &buff) override; bool getIsLoaded() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { + void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { // throw "Not Implemented in this class"; } bool postLoad() override { return false;}; diff --git a/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp b/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp index 66b83f243..7e8fd6530 100644 --- a/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp +++ b/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp @@ -26,7 +26,7 @@ void GBlpTextureGL4x::unbind() { glBindTexture(GL_TEXTURE_2D, 0); } -void GBlpTextureGL4x::createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { +void GBlpTextureGL4x::createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { GLuint textureGPUFormat = 0; // if (ext) { switch (textureFormat) { @@ -183,7 +183,7 @@ void GBlpTextureGL4x::createGlTexture(TextureFormat textureFormat, const HMipmap bool GBlpTextureGL4x::getIsLoaded() { if (!m_loaded && m_texture != nullptr && m_texture->getIsLoaded()) { m_device.bindTexture(this, 0); - this->createGlTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); + this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); m_device.bindTexture(nullptr, 0); m_loaded = true; diff --git a/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.h b/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.h index a1f9cf0ed..525c1f5e3 100644 --- a/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.h +++ b/wowViewerLib/src/gapi/ogl4.x/textures/GBlpTextureGL4x.h @@ -13,7 +13,7 @@ class GBlpTextureGL4x : public GTextureGL4x { explicit GBlpTextureGL4x(IDevice &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); public: ~GBlpTextureGL4x() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; + void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; bool getIsLoaded() override; bool postLoad() override {return false;}; diff --git a/wowViewerLib/src/gapi/ogl4.x/textures/GTextureGL4x.h b/wowViewerLib/src/gapi/ogl4.x/textures/GTextureGL4x.h index 840205d6e..3c0cb952f 100644 --- a/wowViewerLib/src/gapi/ogl4.x/textures/GTextureGL4x.h +++ b/wowViewerLib/src/gapi/ogl4.x/textures/GTextureGL4x.h @@ -17,7 +17,7 @@ class GTextureGL4x : public ITexture { void loadData(int width, int height, void *data) override; bool getIsLoaded() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override { + void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override { throw "Not Implemented in this class"; } bool postLoad() override {return false;}; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index c9d79b573..2cd1e45b6 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -907,8 +907,10 @@ void GDeviceVLK::endUpdateForNextFrame() { } typedef std::shared_ptr HVKMesh; -void GDeviceVLK::updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData) { + +void GDeviceVLK::updateBuffers(std::vector &frameDepedantData) { // aggregationBufferForUpload.resize(maxUniformBufferSize); +/* if (!m_blackPixelTexture) { m_blackPixelTexture = createTexture(false, false); unsigned int zero = 0; @@ -999,6 +1001,7 @@ void GDeviceVLK::updateBuffers(std::vector*> & //bufferForUploadVLK->uploadFromStaging(currentSize); } } + */ } void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index cfe3e2621..508612ffd 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -93,7 +93,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this*> &bufferChunks, std::vector &frameDepedantData); + void updateBuffers(/*std::vector*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; void drawMeshes(std::vector &meshes) override; // void drawStageAndDeps(HDrawStage drawStage) override; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 92697b5a1..548af539c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -165,6 +165,10 @@ void GBufferVLK::uploadFromStaging(int offset, int destOffset, int length) { vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), currentBuffer.stagingBuffer, currentBuffer.g_hBuffer, 1, &vbCopyRegion); } +void GBufferVLK::save(int length) { + uploadFromStaging(0, 0, length); +} + //---------------------------------------------------------------- // SubBuffer thing //---------------------------------------------------------------- @@ -207,6 +211,14 @@ void *GBufferVLK::GSubBufferVLK::getPointer() { return m_dataPointer; } +void GBufferVLK::GSubBufferVLK::save(int length) { + if (length > m_size) { + std::cerr << "invalid dataSize" << std::endl; + } + + m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); +} + size_t GBufferVLK::GSubBufferVLK::getSize() { return m_size; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 0f82945a3..5d6ecd54a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -28,6 +28,10 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this(m_shader.get()); createDescriptorSets(shaderVLK); @@ -63,19 +55,19 @@ GMeshVLK::GMeshVLK(IDevice &device, shaderLayoutBindings.insert({uboFragBinding.binding, uboFragBinding}); } } - - for (int i = 0; i < 5; i++) { - auto it = shaderLayoutBindings.find(i); - if (it != shaderLayoutBindings.end()) { - if ((m_UniformBuffer[i] != nullptr) && (it->second.size != (m_UniformBuffer[i]->getSize()))) { - std::cout << "buffers missmatch! for shaderName = " << shaderVLK->getShaderName() << - " index = " << i << - " expected size " << (it->second.size) << - ", provided size = " << (m_UniformBuffer[i]->getSize()) << - std::endl; - } - } - } +//TODO: +// for (int i = 0; i < 5; i++) { +// auto it = shaderLayoutBindings.find(i); +// if (it != shaderLayoutBindings.end()) { +// if ((m_UniformBuffer[i] != nullptr) && (it->second.size != (m_UniformBuffer[i]->getSize()))) { +// std::cout << "buffers missmatch! for shaderName = " << shaderVLK->getShaderName() << +// " index = " << i << +// " expected size " << (it->second.size) << +// ", provided size = " << (m_UniformBuffer[i]->getSize()) << +// std::endl; +// } +// } +// } } //Works under assumption that meshes do not often change the renderpass on which they are rendered @@ -199,10 +191,6 @@ GMeshVLK::~GMeshVLK() { } -HGUniformBufferChunk GMeshVLK::getUniformBuffer(int slot) { - return m_UniformBuffer[slot]; -} - bool GMeshVLK::getIsTransparent() { return m_isTransparent; } MeshType GMeshVLK::getMeshType() { diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 0deabc616..ac19f7b38 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -19,7 +19,6 @@ class GMeshVLK : public IMesh { public: ~GMeshVLK() override; - HGUniformBufferChunk getUniformBuffer(int slot) override; bool getIsTransparent() override; MeshType getMeshType() override; @@ -32,8 +31,6 @@ class GMeshVLK : public IMesh { HGShaderPermutation m_shader; - std::array m_UniformBuffer = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; - int8_t m_depthWrite; int8_t m_depthCulling; int8_t m_backFaceCulling; @@ -62,7 +59,6 @@ class GMeshVLK : public IMesh { GDeviceVLK &m_device; void createDescriptorSets(GShaderPermutationVLK *shaderVLK); - void updateDescriptor(); }; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index d0954adcf..294658c74 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -16,7 +16,7 @@ GBlpTextureVLK::~GBlpTextureVLK() { static int texturesUploaded = 0; -void GBlpTextureVLK::createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { +void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { // std::cout << "texturesUploaded = " << texturesUploaded++ << " " << this->m_texture->getTextureName() <createGlTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); + this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); // m_texture = nullptr; return false; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index c0f25d16b..550a36cb4 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -13,7 +13,7 @@ class GBlpTextureVLK : public GTextureVLK { explicit GBlpTextureVLK(IDevice &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); public: ~GBlpTextureVLK() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; + void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; bool postLoad() override; private: diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 9b3578303..94f8cd168 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -31,7 +31,7 @@ class GTextureVLK : public ITexture { void readData(std::vector &buff) override {}; void loadData(int width, int height, void *data, ITextureFormat textureFormat) override; bool getIsLoaded() override; - void createGlTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { + void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { throw "Not Implemented in this class"; } bool postLoad() override;; From 0fcd3a42b3e4051206364bde2fef9d732b40b889 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 31 Dec 2022 21:09:38 +0200 Subject: [PATCH 013/212] export texture data from shaders --- src/ui/FrontendUI.cpp | 9 +- .../uiScene/IFrontendUIBufferCreate.h | 3 +- .../renderer/uiScene/materials/UIMaterial.h | 2 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 7 +- .../vulkan/FrontendUIRenderForwardVLK.h | 3 +- wowViewerLib/CMakeLists.txt | 9 +- wowViewerLib/shaders/CMakeLists.txt | 2 +- .../glsl/common/commonFogFunctions.glsl | 4 - .../glsl/forwardRendering/m2Shader.frag | 2 - .../shaders/src/spirv/dumpGLSLShader.h | 6 +- .../shaders/src/spirv/dumpShaderFields.h | 144 +- .../shaders/src/spirv/webGLSLCompiler.cpp | 2 +- .../shaders/src/spirv/webGLSLCompiler.h | 31 + .../src/engine/shader/ShaderDefinitions.h | 1971 +++++++++++------ .../src/gapi/interface/materials/IMaterial.h | 17 + .../src/gapi/interface/meshes/IMesh.h | 6 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 27 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 1 - .../descriptorSets/GDescriptorPoolVLK.cpp | 9 +- .../gapi/vulkan/materials/IMaterialVLK.cpp | 138 ++ .../src/gapi/vulkan/materials/IMaterialVLK.h | 40 + .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 138 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 9 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- 24 files changed, 1730 insertions(+), 852 deletions(-) create mode 100644 wowViewerLib/src/gapi/interface/materials/IMaterial.h create mode 100644 wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 7116fce84..0b8484983 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1863,7 +1863,14 @@ void FrontendUI::update(HFrontendUIBufferCreate renderer) { meshTemplate.start = pcmd->IdxOffset * 2; meshTemplate.end = pcmd->ElemCount; - renderer->createUIMesh(meshTemplate, uboPart) + UIMaterialTemplate materialTemplate; + materialTemplate.texture = pcmd->TextureId; + materialTemplate.uiUBO = uboPart; + + auto material = renderer->createUIMaterial(materialTemplate); + + + renderer->createUIMesh(meshTemplate, material); } } } diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index 2adddcc74..03f93fb7a 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -16,7 +16,8 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; - virtual HGMesh createUIMesh(gMeshTemplate &meshTemplate, UIMaterial &material) = 0; + virtual HGMesh createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) = 0; + virtual HUIMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index cefc9bb01..3406156b7 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -20,4 +20,6 @@ class IUIMaterial { virtual ~IUIMaterial() = 0; }; +typedef std::shared_ptr HUIMaterial; + #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index ffe19f69f..8d20c7b45 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -32,7 +32,12 @@ HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -HGMesh FrontendUIRenderForwardVLK::createUIMesh(gMeshTemplate &meshTemplate, IBufferChunk) { +HUIMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { + //TODO: + return nullptr; +} + +HGMesh FrontendUIRenderForwardVLK::createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) { //TODO: return nullptr; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index fc066d3ce..3f41c5fa7 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -25,7 +25,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override { return nullptr; //VAO doesnt exist in Vulkan }; - HGMesh createUIMesh(gMeshTemplate &meshTemplate, IBufferChunk);; + HGMesh createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) override; + HUIMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) override; private: diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 531e15d93..752a394b9 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -326,7 +326,9 @@ set(SOURCE_FILES src/renderer/mapScene/FrameDependentData.h src/renderer/buffers/IVertexBufferDynamicTemplate.cpp src/renderer/buffers/IVertexBufferDynamicTemplate.h - src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h) + src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h + src/renderer/mapScene/IMapSceneBufferCreate.h + src/gapi/interface/materials/IMaterial.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -504,7 +506,8 @@ if (LINK_VULKAN) src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h src/gapi/vulkan/buffers/GBufferVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.h - src/gapi/vulkan/buffers/IBufferVLK.h) + src/gapi/vulkan/buffers/IBufferVLK.h + src/gapi/vulkan/materials/IMaterialVLK.cpp src/gapi/vulkan/materials/IMaterialVLK.h) if (NOT Vulkan_SDK_DIR) set(Vulkan_SDK_DIR $ENV{VULKAN_SDK}) endif() @@ -530,7 +533,7 @@ if (LINK_VULKAN) MESSAGE("Using bundled Vulkan library version non-win32") ELSE() set(LINK_VULKAN OFF) - set(VULKAN_IMPLEMENTATION "" src/gapi/vulkan/buffers/GBufferSuballocation.cpp src/gapi/vulkan/buffers/GBufferSuballocation.h) + set(VULKAN_IMPLEMENTATION "" ) ENDIF() ENDIF() ENDIF() diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index cb1568d14..6bc864297 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -149,7 +149,7 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) OUTPUT ${GLSL33_FILE} COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL33}" COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} ${OGL3_GLSL_OPTION} ${SPIRV_NonOpt} > ${GLSL30_FILE_FULLPATH} - DEPENDS ${SPIRV_NonOpt} spirv_reflection) + DEPENDS spirv_reflection ${SPIRV_NonOpt}) list(APPEND GLSL30Files ${GLSL33_FILE}) diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index 52ffe8d78..b0a104986 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -50,10 +50,6 @@ vec3 validateFogColor(in vec3 fogColor, int blendMode) { vec4 makeFog(const in PSFog fogData, in vec4 final, in vec3 vertexInViewSpace, in vec3 sunDirInViewSpace, in int blendMode) { // //The best solution so far is to not apply fog to blendmode GxBlend_BlendAdd -// if (blendMode == 13) -// return final; - - vec4 l_densityParams = fogData.densityParams; vec4 l_heightPlane = fogData.heightPlane; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 76fb63f2d..0a8b3ff44 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -52,8 +52,6 @@ layout(std140, set=0, binding=4) uniform meshWideBlockPS { ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; vec4 uFogColorAndAlphaTest; vec4 uTexSampleAlpha; - - vec4 uPcColor; }; diff --git a/wowViewerLib/shaders/src/spirv/dumpGLSLShader.h b/wowViewerLib/shaders/src/spirv/dumpGLSLShader.h index 9db53b3d2..06f770bdc 100644 --- a/wowViewerLib/shaders/src/spirv/dumpGLSLShader.h +++ b/wowViewerLib/shaders/src/spirv/dumpGLSLShader.h @@ -60,7 +60,7 @@ void dumpGLSLText(std::vector &shaderFilePaths, int glslVersion, bo // printf("Image %s at set = %u, binding = %u\n", resource.name.c_str(), set, binding); // Modify the decoration to prepare it for GLSL. - glsl.unset_decoration(resource.id, spv::DecorationDescriptorSet); +// glsl.unset_decoration(resource.id, spv::DecorationDescriptorSet); // Some arbitrary remapping if we want. @@ -69,10 +69,10 @@ void dumpGLSLText(std::vector &shaderFilePaths, int glslVersion, bo options.enable_420pack_extension = false; } else { if (glslVersion > 300) { - glsl.unset_decoration(resource.id, spv::DecorationBinding); +// glsl.unset_decoration(resource.id, spv::DecorationBinding); options.enable_420pack_extension = false; } else { - glsl.unset_decoration(resource.id, spv::DecorationBinding); +// glsl.unset_decoration(resource.id, spv::DecorationBinding); options.enable_420pack_extension = false; } } diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index c06047173..be5829e0c 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -31,8 +31,23 @@ struct uboBindingData { unsigned long long size; }; +struct imageBindingData { + unsigned int set; + unsigned int binding; + std::string imageName; +}; + +struct imageBindingAmountData { + unsigned int start = 999; + unsigned int end = 0; + unsigned int length = 0; + +}; + struct shaderMetaData { std::vector uboBindings; + std::vector imageBindings; + std::array imageBindingAmounts; }; //Per file @@ -128,24 +143,39 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { " int location;\n" "};" << std::endl; - std::cout << "struct uboBindingData {\n" - " int set;\n" - " int binding;\n" - " int size;\n" - "};\n" - "\n" - "struct shaderMetaData {\n" - " std::vector uboBindings;\n" - "};\n" - "\n" - "//Per file\n" - "extern const std::unordered_map shaderMetaInfo;" << std::endl << - "extern const std::unordered_map> attributesPerShaderName;" - << std::endl << - "extern const std::unordered_map>> fieldDefMapPerShaderNameVert;" - << std::endl << - "extern const std::unordered_map>> fieldDefMapPerShaderNameFrag;" - << std::endl; + std::cout << + R"===( + struct uboBindingData { + int set; + int binding; + int size; + }; + struct imageBindingData { + unsigned int set; + unsigned int binding; + std::string imageName; + }; + + struct imageBindingAmountData { + unsigned int start = 999; + unsigned int end = 0; + unsigned int length = 0; + + }; + + struct shaderMetaData { + std::vector uboBindings; + std::vector imageBindings; + std::array imageBindingAmounts; + }; + //Per file + extern const std::unordered_map shaderMetaInfo; + extern const std::unordered_map> attributesPerShaderName; + + extern const std::unordered_map>> fieldDefMapPerShaderNameVert; + + extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; +)===" << std::endl; std::unordered_map>> fieldDefMapPerShaderNameVert; @@ -213,6 +243,8 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { // The SPIR-V is now parsed, and we can perform reflection on it. spirv_cross::ShaderResources resources = glsl.get_shader_resources(); + + //Record data for UBO for (auto &resource : resources.uniform_buffers) { auto uboType = glsl.get_type(resource.type_id); @@ -232,16 +264,50 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { for (int j = 0; j < uboType.member_types.size(); j++) { auto uboParentType = glsl.get_type(uboType.parent_type); +// glsl.get_member_name auto memberSize = glsl.get_declared_struct_member_size(uboParentType, j); auto offset = glsl.type_struct_member_offset(uboParentType, j); auto memberName = glsl.get_member_name(uboType.parent_type, j); dumpMembers(glsl, fieldVectorDef, uboType.member_types[j], - "_" + std::to_string(resource.id) + "_" + memberName, offset, memberSize); +// "_" + std::to_string(resource.id) + "_" + memberName, offset, memberSize); + glsl.to_name(resource.id) + "_" + memberName, offset, memberSize); + } + } + + //Record data for images + for (auto &resource : resources.sampled_images) { + unsigned int set = -1; + unsigned int binding = -1; + if (glsl.has_decoration(resource.id, spv::DecorationDescriptorSet) && + glsl.has_decoration(resource.id, spv::DecorationBinding)) + { + set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet); + binding = glsl.get_decoration(resource.id, spv::DecorationBinding); + } + metaInfo.imageBindings.push_back({set, binding, resource.name}); + if (set >= 0) { + metaInfo.imageBindingAmounts[set].start = + std::min(metaInfo.imageBindingAmounts[set].start, binding); + metaInfo.imageBindingAmounts[set].end = + std::max(metaInfo.imageBindingAmounts[set].end, binding); + } + +// std::cout << "set = " << set << std::endl; +// std::cout << "binding = " << binding << std::endl; +// std::cout << resource.name << std::endl; +// std::cout << glsl.to_name(resource.base_type_id) << std::endl; + } + for (auto &data: metaInfo.imageBindingAmounts ) { + if (data.start < 16) { + data.length = data.end - data.start + 1; + } else { + data.start = 0; } } + } //2.1 Create attribute enums @@ -269,29 +335,51 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { << std::endl; for (auto it = attributesPerShaderName.begin(); it != attributesPerShaderName.end(); it++) { - std::cout << "{\"" << it->first << "\", " << " {" << std::endl; + std::cout << "{ \"" << it->first << "\",\n" << + " {" << std::endl; for (auto &attributeInfo : it->second) { - std::cout << "{\"" << attributeInfo.name << "\", " << attributeInfo.location << "}," << std::endl; + std::cout << " { \"" << attributeInfo.name << "\", " << attributeInfo.location << "}," << std::endl; } - std::cout << "}},"; + std::cout << " }\n"<< "}," << std::endl; } std::cout << "};" << std::endl << std::endl; //Add shader meta - std::cout << "const std::unordered_map shaderMetaInfo = {"; + std::cout << "const std::unordered_map shaderMetaInfo = { \n"; for (auto it = shaderMetaInfo.begin(); it != shaderMetaInfo.end(); it++) { - std::cout << "{ \"" << it->first << "\", {\n"; - std::cout << "{\n"; + std::cout << "{ \"" << it->first << "\", \n"<< + " {\n"; + //Dump UBO Bindings per shader + std::cout << " {\n"; for (auto subIt = it->second.uboBindings.begin(); subIt != it->second.uboBindings.end(); subIt++) { - std::cout << "{" << subIt->set << "," << subIt->binding << "," << subIt->size << "}," << std::endl; + std::cout << " {" << subIt->set << "," << subIt->binding << "," << subIt->size << "}," << std::endl; } + std::cout << " },\n"; + //UBO Bindings dump end - std::cout << "}\n"; - std::cout << "}\n},"; + std::cout << " {\n"; + for (auto &binding : it->second.imageBindings) { + std::cout << " {" << binding.set << "," << binding.binding << ", \"" << binding.imageName << "\"}," << std::endl; + } + std::cout << " },\n"; + + std::cout << " {\n"; + std::cout << " {\n"; + for (auto &bindingAmount : it->second.imageBindingAmounts) { + if (bindingAmount.length > 0) { + std::cout << " {" << bindingAmount.start << "," << bindingAmount.end << ", " << bindingAmount.end << "}," + << std::endl; + } else { + std::cout << " {0,0,0}," << std::endl; + } + } + std::cout << " }\n"; + std::cout << " }\n"; + std::cout << " }\n},\n"; } std::cout << "};" << std::endl << std::endl; diff --git a/wowViewerLib/shaders/src/spirv/webGLSLCompiler.cpp b/wowViewerLib/shaders/src/spirv/webGLSLCompiler.cpp index 67793be20..59c3ec693 100644 --- a/wowViewerLib/shaders/src/spirv/webGLSLCompiler.cpp +++ b/wowViewerLib/shaders/src/spirv/webGLSLCompiler.cpp @@ -3120,7 +3120,7 @@ void WebGLSLCompiler::emit_resources() has_block_flags) { if (options.webgl10) { - emit_ubo_as_uniforms(type.parent_type, "_" +std::to_string(r_id)); + emit_ubo_as_uniforms(type.parent_type, to_name(r_id)); } else { emit_buffer_block(var); } diff --git a/wowViewerLib/shaders/src/spirv/webGLSLCompiler.h b/wowViewerLib/shaders/src/spirv/webGLSLCompiler.h index fb0689bd5..033ff1b62 100644 --- a/wowViewerLib/shaders/src/spirv/webGLSLCompiler.h +++ b/wowViewerLib/shaders/src/spirv/webGLSLCompiler.h @@ -165,6 +165,37 @@ namespace SPIRV_CROSS_NAMESPACE } } + std::string to_name(uint32_t id, bool allow_alias = true) const override + { + if (allow_alias && ir.ids[id].get_type() == TypeType) + { + // If this type is a simple alias, emit the + // name of the original type instead. + // We don't want to override the meta alias + // as that can be overridden by the reflection APIs after parse. + auto &type = get(id); + if (type.type_alias) + { + // If the alias master has been specially packed, we will have emitted a clean variant as well, + // so skip the name aliasing here. + if (!has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) + return to_name(type.type_alias); + } + } + + auto &alias = ir.get_name(id); + if (alias.empty()) { + if (has_decoration(id, spv::DecorationDescriptorSet) && has_decoration(id, spv::DecorationBinding)) { + unsigned set = get_decoration(id, spv::DecorationDescriptorSet); + unsigned binding = get_decoration(id, spv::DecorationBinding); + return join("_", set, "_", binding); + } + + return join("_", id); + } else + return alias; + } + std::string compile() override; // Returns the current string held in the conversion buffer. Useful for diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d28ea9e69..52386232a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -21,21 +21,38 @@ struct attributeDefine { std::string name; int location; }; -struct uboBindingData { - int set; - int binding; - int size; -}; -struct shaderMetaData { - std::vector uboBindings; -}; + struct uboBindingData { + int set; + int binding; + int size; + }; + struct imageBindingData { + unsigned int set; + unsigned int binding; + std::string imageName; + }; + + struct imageBindingAmountData { + unsigned int start = 999; + unsigned int end = 0; + unsigned int length = 0; + + }; + + struct shaderMetaData { + std::vector uboBindings; + std::vector imageBindings; + std::array imageBindingAmounts; + }; + //Per file + extern const std::unordered_map shaderMetaInfo; + extern const std::unordered_map> attributesPerShaderName; + + extern const std::unordered_map>> fieldDefMapPerShaderNameVert; + + extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -//Per file -extern const std::unordered_map shaderMetaInfo; -extern const std::unordered_map> attributesPerShaderName; -extern const std::unordered_map>> fieldDefMapPerShaderNameVert; -extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; struct waterfallShader { enum class Attribute { aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd @@ -141,519 +158,1185 @@ struct ribbonShader { std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{"waterfallShader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"bones", 2}, -{"boneWeights", 3}, -{"aTexCoord", 4}, -{"aTexCoord2", 5}, -}},{"adtLodShader", { -{"aHeight", 0}, -{"aIndex", 1}, -}},{"adtShader", { -{"aPos", 0}, -{"aColor", 1}, -{"aVertexLighting", 2}, -{"aNormal", 3}, -{"aIndex", 4}, -}},{"drawBBShader", { -{"aPosition", 0}, -}},{"waterShader", { -{"aPositionTransp", 0}, -{"aTexCoord", 1}, -}},{"m2ParticleShader", { -{"aPosition", 0}, -{"aColor", 1}, -{"aTexcoord0", 2}, -{"aTexcoord1", 3}, -{"aTexcoord2", 4}, -}},{"drawFrustumShader", { -{"aPosition", 0}, -}},{"drawPoints", { -{"aPosition", 0}, -}},{"drawQuad", { -{"position", 0}, -}},{"skyConus", { -{"aPosition", 0}, -}},{"m2Shader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"bones", 2}, -{"boneWeights", 3}, -{"aTexCoord", 4}, -{"aTexCoord2", 5}, -}},{"drawPortalShader", { -{"aPosition", 0}, -}},{"renderFrameBufferShader", { -{"a_position", 0}, -}},{"wmoShader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"aTexCoord", 2}, -{"aTexCoord2", 3}, -{"aTexCoord3", 4}, -{"aTexCoord4", 5}, -{"aColor", 6}, -{"aColor2", 7}, -{"aColorSecond", 8}, -}},{"imguiShader", { -{"Position", 0}, -{"UV", 1}, -{"Color", 2}, -}},{"drawLinesShader", { -{"aPosition", 0}, -}},{"ribbonShader", { -{"aPosition", 0}, -{"aColor", 1}, -{"aTexcoord0", 2}, -}},}; +{ "waterfallShader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "adtLodShader", + { + { "aHeight", 0}, + { "aIndex", 1}, + } +}, +{ "adtShader", + { + { "aPos", 0}, + { "aColor", 1}, + { "aVertexLighting", 2}, + { "aNormal", 3}, + { "aIndex", 4}, + } +}, +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "waterShader", + { + { "aPositionTransp", 0}, + { "aTexCoord", 1}, + } +}, +{ "m2ParticleShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + { "aTexcoord1", 3}, + { "aTexcoord2", 4}, + } +}, +{ "drawFrustumShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "skyConus", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, +{ "wmoShader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "aTexCoord", 2}, + { "aTexCoord2", 3}, + { "aTexCoord3", 4}, + { "aTexCoord4", 5}, + { "aColor", 6}, + { "aColor2", 7}, + { "aColorSecond", 8}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, +}; -const std::unordered_map shaderMetaInfo = {{ "wmoShader.vert.spv", { -{ -{0,1,64}, -{0,0,368}, -{0,2,16}, -} -} -},{ "wmoShader.frag.spv", { -{ -{0,4,32}, -{0,0,368}, -{0,3,32}, -} -} -},{ "waterShader.frag.spv", { -{ -{0,4,16}, -{0,0,368}, -} -} -},{ "waterfallShader.frag.spv", { -{ -{0,4,96}, -{0,0,368}, -} -} -},{ "adtShader.vert.spv", { -{ -{0,0,368}, -} -} -},{ "adtLodShader.vert.spv", { -{ -{0,0,144}, -} -} -},{ "waterfallShader.vert.spv", { -{ -{0,2,144}, -{0,1,14144}, -{0,0,368}, -} -} -},{ "drawPoints.vert.spv", { -{ -{0,0,128}, -{0,1,64}, -} -} -},{ "drawFrustumShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ffxglow.frag.spv", { -{ -{0,4,16}, -} -} -},{ "adtShader.frag.spv", { -{ -{0,4,288}, -{0,3,16}, -{0,0,368}, -} -} -},{ "drawBBShader.vert.spv", { -{ -{0,1,112}, -{0,0,368}, -} -} -},{ "drawFrustumShader.frag.spv", { -{ -} -} -},{ "drawDepthShader.frag.spv", { -{ -{0,2,12}, -} -} -},{ "adtLodShader.frag.spv", { -{ -{0,0,84}, -} -} -},{ "drawPoints.frag.spv", { -{ -{0,1,12}, -} -} -},{ "drawBBShader.frag.spv", { -{ -{0,1,112}, -} -} -},{ "drawLinesShader.frag.spv", { -{ -} -} -},{ "skyConus.frag.spv", { -{ -} -} -},{ "drawPortalShader.frag.spv", { -{ -{0,4,16}, -} -} -},{ "drawLinesShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ffxgauss4.frag.spv", { -{ -{0,4,32}, -} -} -},{ "imguiShader.frag.spv", { -{ -} -} -},{ "m2ParticleShader.vert.spv", { -{ -{0,0,368}, -} -} -},{ "drawQuad.vert.spv", { -{ -{0,2,16}, -} -} -},{ "imguiShader.vert.spv", { -{ -{0,1,80}, -} -} -},{ "m2Shader.frag.spv", { -{ -{0,4,64}, -{0,3,256}, -{0,0,368}, -{0,1,14144}, -} -} -},{ "waterShader.vert.spv", { -{ -{0,0,368}, -{0,1,64}, -} -} -},{ "drawPortalShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ribbonShader.vert.spv", { -{ -{0,0,368}, -} -} -},{ "skyConus.vert.spv", { -{ -{0,0,368}, -{0,2,96}, -} -} -},{ "renderFrameBufferShader.frag.spv", { -{ -{0,2,168}, -} -} -},{ "renderFrameBufferShader.vert.spv", { -{ -} -} -},{ "m2ParticleShader.frag.spv", { -{ -{0,4,32}, -{0,0,368}, -} -} -},{ "m2Shader.vert.spv", { -{ -{0,1,14144}, -{0,0,368}, -{0,2,160}, -} -} -},{ "ribbonShader.frag.spv", { -{ -{0,4,48}, -{0,0,368}, -} -} -},}; +const std::unordered_map shaderMetaInfo = { +{ "wmoShader.vert.spv", + { + { + {0,1,64}, + {0,0,368}, + {0,2,16}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "wmoShader.frag.spv", + { + { + {0,4,32}, + {0,0,368}, + {0,3,32}, + }, + { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, + }, + { + { + {0,0,0}, + {5,13, 13}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "waterShader.frag.spv", + { + { + {0,4,16}, + {0,0,368}, + }, + { + {1,5, "uTexture"}, + }, + { + { + {0,0,0}, + {5,5, 5}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "waterfallShader.frag.spv", + { + { + {0,4,96}, + {0,0,368}, + }, + { + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, + }, + { + { + {0,0,0}, + {5,9, 9}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "adtShader.vert.spv", + { + { + {0,0,368}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "adtLodShader.vert.spv", + { + { + {0,0,144}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "waterfallShader.vert.spv", + { + { + {0,2,144}, + {0,1,14144}, + {0,0,368}, + }, + { + {1,8, "uBumpTexture"}, + }, + { + { + {0,0,0}, + {8,8, 8}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawPoints.vert.spv", + { + { + {0,0,128}, + {0,1,64}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawFrustumShader.vert.spv", + { + { + {0,0,128}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "ffxglow.frag.spv", + { + { + {0,4,16}, + }, + { + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, + { + { + {0,0,0}, + {5,6, 6}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "adtShader.frag.spv", + { + { + {0,4,288}, + {0,3,16}, + {0,0,368}, + }, + { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, + }, + { + { + {0,0,0}, + {5,13, 13}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawBBShader.vert.spv", + { + { + {0,1,112}, + {0,0,368}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawFrustumShader.frag.spv", + { + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawDepthShader.frag.spv", + { + { + {0,2,12}, + }, + { + {0,3, "diffuse"}, + }, + { + { + {3,3, 3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "adtLodShader.frag.spv", + { + { + {0,0,84}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawPoints.frag.spv", + { + { + {0,1,12}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawBBShader.frag.spv", + { + { + {0,1,112}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawLinesShader.frag.spv", + { + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "skyConus.frag.spv", + { + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawPortalShader.frag.spv", + { + { + {0,4,16}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawLinesShader.vert.spv", + { + { + {0,0,128}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "ffxgauss4.frag.spv", + { + { + {0,4,32}, + }, + { + {1,5, "texture0"}, + }, + { + { + {0,0,0}, + {5,5, 5}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "imguiShader.frag.spv", + { + { + }, + { + {1,5, "Texture"}, + }, + { + { + {0,0,0}, + {5,5, 5}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "m2ParticleShader.vert.spv", + { + { + {0,0,368}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawQuad.vert.spv", + { + { + {0,2,16}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "imguiShader.vert.spv", + { + { + {0,1,80}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "m2Shader.frag.spv", + { + { + {0,4,64}, + {0,3,256}, + {0,0,368}, + {0,1,14144}, + }, + { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + }, + { + { + {0,0,0}, + {5,8, 8}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "waterShader.vert.spv", + { + { + {0,0,368}, + {0,1,64}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "drawPortalShader.vert.spv", + { + { + {0,0,128}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "ribbonShader.vert.spv", + { + { + {0,0,368}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "skyConus.vert.spv", + { + { + {0,0,368}, + {0,2,96}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "renderFrameBufferShader.frag.spv", + { + { + {0,2,168}, + }, + { + {0,3, "u_sampler"}, + }, + { + { + {3,3, 3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "renderFrameBufferShader.vert.spv", + { + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "m2ParticleShader.frag.spv", + { + { + {0,4,32}, + {0,0,368}, + }, + { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + }, + { + { + {0,0,0}, + {5,7, 7}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "m2Shader.vert.spv", + { + { + {0,1,14144}, + {0,0,368}, + {0,2,160}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "ribbonShader.frag.spv", + { + { + {0,4,48}, + {0,0,368}, + }, + { + {1,5, "uTexture"}, + }, + { + { + {0,0,0}, + {5,5, 5}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +}; const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { 0, { - {"_169_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_169_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_169_scene_uViewUp", true, 128, 1, 4, 0}, - {"_169_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_169_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_169_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_169_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_169_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_169_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_169_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_169_fogData_densityParams", true, 256, 1, 4, 0}, - {"_169_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_169_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_169_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_169_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_169_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_169_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, { 1, { - {"_74_uPlacementMat", true, 0, 4, 4, 0}, - {"_74_uBoneMatrixes[0]", true, 64, 4, 4, 220}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBoneMatrixes[0]", true, 64, 4, 4, 220}, } }, { 2, { - {"_17_bumpScale", true, 0, 1, 4, 0}, - {"_17_uTextMat[0]", true, 16, 4, 4, 2}, + {"_0_2_bumpScale", true, 0, 1, 4, 0}, + {"_0_2_uTextMat[0]", true, 16, 4, 4, 2}, } }, }}, {"adtLodShader", { { 0, { - {"_55_uPos", true, 0, 1, 3, 0}, - {"_55_uLookAtMat", true, 16, 4, 4, 0}, - {"_55_uPMatrix", true, 80, 4, 4, 0}, + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, } }, }}, {"adtShader", { { 0, { - {"_56_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_56_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_56_scene_uViewUp", true, 128, 1, 4, 0}, - {"_56_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_56_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_56_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_56_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_56_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_56_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_56_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_56_fogData_densityParams", true, 256, 1, 4, 0}, - {"_56_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_56_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_56_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_56_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_56_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_56_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, }}, {"drawBBShader", { { 0, { - {"_62_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_62_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_62_scene_uViewUp", true, 128, 1, 4, 0}, - {"_62_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_62_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_62_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_62_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_62_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_62_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_62_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_62_fogData_densityParams", true, 256, 1, 4, 0}, - {"_62_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_62_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_62_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_62_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_62_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_62_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, { 1, { - {"_21_uPlacementMat", true, 0, 4, 4, 0}, - {"_21_uBBScale", true, 64, 1, 4, 0}, - {"_21_uBBCenter", true, 80, 1, 4, 0}, - {"_21_uColor", true, 96, 1, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, {"waterShader", { { 1, { - {"_36_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { 0, { - {"_28_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_28_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_28_scene_uViewUp", true, 128, 1, 4, 0}, - {"_28_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_28_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_28_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_28_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_28_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_28_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_28_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_28_fogData_densityParams", true, 256, 1, 4, 0}, - {"_28_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_28_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_28_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_28_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_28_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_28_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, }}, {"m2ParticleShader", { { 0, { - {"_43_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_43_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_43_scene_uViewUp", true, 128, 1, 4, 0}, - {"_43_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_43_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_43_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_43_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_43_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_43_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_43_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_43_fogData_densityParams", true, 256, 1, 4, 0}, - {"_43_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_43_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_43_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_43_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_43_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_43_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, }}, {"drawFrustumShader", { { 0, { - {"_13_uLookAtMat", true, 0, 4, 4, 0}, - {"_13_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, {"drawPoints", { { 1, { - {"_29_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { 0, { - {"_19_uLookAtMat", true, 0, 4, 4, 0}, - {"_19_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, {"drawQuad", { { 2, { - {"_12_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, + {"_0_2_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, } }, }}, {"skyConus", { { 2, { - {"_73_skyColor[0]", true, 0, 1, 4, 6}, + {"_0_2_skyColor[0]", true, 0, 1, 4, 6}, } }, { 0, { - {"_26_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_26_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_26_scene_uViewUp", true, 128, 1, 4, 0}, - {"_26_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_26_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_26_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_26_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_26_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_26_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_26_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_26_fogData_densityParams", true, 256, 1, 4, 0}, - {"_26_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_26_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_26_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_26_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_26_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_26_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, }}, {"m2Shader", { { 2, { - {"_612_vertexShader_IsAffectedByLight", false, 0, 1, 4, 0}, - {"_612_color_Transparency", true, 16, 1, 4, 0}, - {"_612_uTextMat[0]", true, 32, 4, 4, 2}, + {"_0_2_vertexShader_IsAffectedByLight", false, 0, 1, 4, 0}, + {"_0_2_color_Transparency", true, 16, 1, 4, 0}, + {"_0_2_uTextMat[0]", true, 32, 4, 4, 2}, } }, { 0, { - {"_581_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_581_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_581_scene_uViewUp", true, 128, 1, 4, 0}, - {"_581_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_581_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_581_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_581_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_581_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_581_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_581_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_581_fogData_densityParams", true, 256, 1, 4, 0}, - {"_581_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_581_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_581_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_581_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_581_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_581_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, { 1, { - {"_484_uPlacementMat", true, 0, 4, 4, 0}, - {"_484_uBoneMatrixes[0]", true, 64, 4, 4, 220}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBoneMatrixes[0]", true, 64, 4, 4, 220}, } }, }}, {"drawPortalShader", { { 0, { - {"_30_uLookAtMat", true, 0, 4, 4, 0}, - {"_30_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, @@ -662,72 +1345,72 @@ const std::unordered_map int& { return m_start; } auto end() -> int& { return m_end; } - auto textureCount() -> int { return m_texture.size(); } +// auto textureCount() -> int { return m_texture.size(); } auto bindings() const -> const HGVertexBufferBindings& { return m_bindings; } - auto texture() const -> const std::vector& { return m_texture; } + // auto texture() const -> const HGVertexBufferBindings& { return m_bindings; } protected: @@ -95,7 +95,7 @@ class IMesh { int m_start; int m_end; - std::vector m_texture = {}; + public: virtual ~IMesh(){ // std::cout << "Mesh destroyed" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 2cd1e45b6..a2a0186ab 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1012,22 +1012,23 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { for (const auto &hmesh : meshes) { GMeshVLK * mesh = (GMeshVLK *) hmesh.get(); - mesh->updateDescriptor(); + mesh->material->updateImageDescriptorSet(); - - for (int i = 0; i < mesh->textureCount(); i++) { - textures.push_back(mesh->m_texture[i]); - } +// for (int i = 0; i < mesh->textureCount(); i++) { +// textures.push_back(mesh->m_texture[i]); +// } } - std::sort(textures.begin(), textures.end()); - textures.erase( unique( textures.begin(), textures.end() ), textures.end() ); - - for (const auto &texture : textures) { - if (texture == nullptr) continue; - if (texture->postLoad()) texturesLoaded++; - if (texturesLoaded > 4) break; - } + //TODO:!!! +// +// std::sort(textures.begin(), textures.end()); +// textures.erase( unique( textures.begin(), textures.end() ), textures.end() ); +// +// for (const auto &texture : textures) { +// if (texture == nullptr) continue; +// if (texture->postLoad()) texturesLoaded++; +// if (texturesLoaded > 4) break; +// } } void GDeviceVLK::drawMeshes(std::vector &meshes) { diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index d9443b097..1498d17f7 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -172,7 +172,6 @@ void GPipelineVLK::createPipeline( rasterizer.frontFace = m_triCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; - VkPipelineMultisampleStateCreateInfo multisampling = {}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index b9c3aa05d..abba5c400 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -34,13 +34,16 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDevice &device) : m_device(dynamic_cast< std::shared_ptr GDescriptorPoolVLK::allocate(VkDescriptorSetLayout layout, int uniforms, int images) { if (uniformsAvailable < uniforms || imageAvailable < images || setsAvailable < 1) return nullptr; - std::array descLAyouts = {layout,layout,layout,layout}; + constexpr int descSetCount = 1; + std::array descLayouts = {layout}; VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.pNext = NULL; allocInfo.descriptorPool = m_descriptorPool; - allocInfo.descriptorSetCount = 1; - allocInfo.pSetLayouts = descLAyouts.data(); + allocInfo.descriptorSetCount = descSetCount; + //VUID-VkDescriptorSetAllocateInfo-pSetLayouts-parameter + //pSetLayouts must be a valid pointer to an array of __descriptorSetCount__ valid VkDescriptorSetLayout handles + allocInfo.pSetLayouts = descLayouts.data(); VkDescriptorSet descriptorSet; diff --git a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp new file mode 100644 index 000000000..295300303 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp @@ -0,0 +1,138 @@ +// +// Created by Deamon on 29.12.22. +// + +#include "IMaterialVLK.h" +#include "../shaders/GShaderPermutationVLK.h" +#include "../textures/GTextureVLK.h" + +void IMaterialVLK::createImageDescriptorSet() { + auto shaderVLK = std::dynamic_pointer_cast(m_shader); + auto descLayout = shaderVLK->getImageDescriptorLayout(); + + imageDescriptorSets = { m_device->createDescriptorSet(descLayout, 0, shaderVLK->getTextureCount()) }; + + { + std::vector descriptorWrites; + + //Bind Black pixel texture + std::vector imageInfos(shaderVLK->getTextureCount()); + + auto blackTexture = m_device->getBlackPixelTexture(); + auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); + + int bindIndex = 0; + for (int i = 0; i < shaderVLK->getTextureCount(); i++) { + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = blackTextureVlk->texture.view; + imageInfo.sampler = blackTextureVlk->texture.sampler; + imageInfos[bindIndex] = imageInfo; + + VkWriteDescriptorSet writeDescriptor; + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = imageDescriptorSets[0]->getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = shaderVLK->getTextureBindingStart()+bindIndex; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pBufferInfo = nullptr; + writeDescriptor.pImageInfo = &imageInfos[bindIndex]; + writeDescriptor.pTexelBufferView = nullptr; + descriptorWrites.push_back(writeDescriptor); + bindIndex++; + } + + if (!descriptorWrites.empty()) { + imageDescriptorSets[0]->writeToDescriptorSets(descriptorWrites); + } + } +} + +void IMaterialVLK::updateImageDescriptorSet() { + bool allTexturesAreReady = true; + + auto shaderVLK = std::dynamic_pointer_cast(m_shader); + int textureBegin = shaderVLK->getTextureBindingStart(); + + for (auto& texture : m_textures) { + if (texture == nullptr) continue; + allTexturesAreReady &= texture->getIsLoaded(); + } + + if (allTexturesAreReady) { + std::vector descriptorWrites; + std::vector imageInfos(m_textures.size()); + + if (shaderVLK->getTextureCount() == 0) return; + + for (size_t i = 0; i < m_textures.size(); i++) { + auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); + if (textureVlk == nullptr) continue; + + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = textureVlk->texture.view; + imageInfo.sampler = textureVlk->texture.sampler; + imageInfos[i] = imageInfo; + + VkWriteDescriptorSet writeDescriptor; + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = imageDescriptorSets[0]->getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = textureBegin+i; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pImageInfo = &imageInfos[i]; + descriptorWrites.push_back(writeDescriptor); + } + + if (descriptorWrites.size() > 0) { + imageDescriptorSets[0]->writeToDescriptorSets(descriptorWrites); +// vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); + } + } +} + +IMaterialVLK::IMaterialVLK(HGDeviceVLK device) : m_device(device) { + + //TODO: + m_shader = device->getShader("", "", nullptr); + + auto shaderVLK = std::dynamic_pointer_cast(m_shader); + + + //Check the buffer sizes + std::unordered_map shaderLayoutBindings; + for (int i = 0; i < shaderVLK->vertShaderMeta->uboBindings.size(); i++) { + auto &uboVertBinding = shaderVLK->vertShaderMeta->uboBindings[i]; + + auto it = shaderLayoutBindings.find(uboVertBinding.binding); + if (it == std::end( shaderLayoutBindings )) { + shaderLayoutBindings.insert({uboVertBinding.binding, uboVertBinding}); + } + } + for (int i = 0; i < shaderVLK->fragShaderMeta->uboBindings.size(); i++) { + auto &uboFragBinding = shaderVLK->fragShaderMeta->uboBindings[i]; + auto it = shaderLayoutBindings.find(uboFragBinding.binding); + if (it == std::end( shaderLayoutBindings )) { + shaderLayoutBindings.insert({uboFragBinding.binding, uboFragBinding}); + } + } +//TODO: +// for (int i = 0; i < 5; i++) { +// auto it = shaderLayoutBindings.find(i); +// if (it != shaderLayoutBindings.end()) { +// if ((m_UniformBuffer[i] != nullptr) && (it->second.size != (m_UniformBuffer[i]->getSize()))) { +// std::cout << "buffers missmatch! for shaderName = " << shaderVLK->getShaderName() << +// " index = " << i << +// " expected size " << (it->second.size) << +// ", provided size = " << (m_UniformBuffer[i]->getSize()) << +// std::endl; +// } +// } +// } + +} diff --git a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h new file mode 100644 index 000000000..b16f70091 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h @@ -0,0 +1,40 @@ +// +// Created by Deamon on 29.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_IMATERIALVLK_H +#define AWEBWOWVIEWERCPP_IMATERIALVLK_H + + +#include +#include +#include "../../interface/materials/IMaterial.h" +#include "../descriptorSets/GDescriptorSet.h" + +class IMaterialVLK : public IMaterial { +public: + IMaterialVLK(HGDeviceVLK device); + ~IMaterialVLK() override = default;; + + HGShaderPermutation getShader() { + return m_shader; + } + + void createImageDescriptorSet(); + void updateImageDescriptorSet(); + +private: + HGDeviceVLK m_device; + + std::vector m_textures = {}; + + std::vector> imageDescriptorSets; + std::vector> uboDescriptorSets; + std::vector> ssboDescriptorSets; + + HGShaderPermutation m_shader; +}; + +typedef std::shared_ptr HMaterialVLK; + +#endif //AWEBWOWVIEWERCPP_IMATERIALVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 6590d1146..de5f5fabc 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -10,7 +10,7 @@ GMeshVLK::GMeshVLK(IDevice &device, const gMeshTemplate &meshTemplate -) : m_device(dynamic_cast(device)), m_shader(meshTemplate.shader), m_meshType(meshTemplate.meshType) { +) : m_device(dynamic_cast(device)), m_meshType(meshTemplate.meshType) { m_bindings = meshTemplate.bindings; @@ -33,48 +33,13 @@ GMeshVLK::GMeshVLK(IDevice &device, m_end = meshTemplate.end; m_element = meshTemplate.element; - m_texture = meshTemplate.texture; - - GShaderPermutationVLK* shaderVLK = reinterpret_cast(m_shader.get()); - createDescriptorSets(shaderVLK); - - //Check the buffer sizes - std::unordered_map shaderLayoutBindings; - for (int i = 0; i < shaderVLK->vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = shaderVLK->vertShaderMeta->uboBindings[i]; - - auto it = shaderLayoutBindings.find(uboVertBinding.binding); - if (it == std::end( shaderLayoutBindings )) { - shaderLayoutBindings.insert({uboVertBinding.binding, uboVertBinding}); - } - } - for (int i = 0; i < shaderVLK->fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = shaderVLK->fragShaderMeta->uboBindings[i]; - auto it = shaderLayoutBindings.find(uboFragBinding.binding); - if (it == std::end( shaderLayoutBindings )) { - shaderLayoutBindings.insert({uboFragBinding.binding, uboFragBinding}); - } - } -//TODO: -// for (int i = 0; i < 5; i++) { -// auto it = shaderLayoutBindings.find(i); -// if (it != shaderLayoutBindings.end()) { -// if ((m_UniformBuffer[i] != nullptr) && (it->second.size != (m_UniformBuffer[i]->getSize()))) { -// std::cout << "buffers missmatch! for shaderName = " << shaderVLK->getShaderName() << -// " index = " << i << -// " expected size " << (it->second.size) << -// ", provided size = " << (m_UniformBuffer[i]->getSize()) << -// std::endl; -// } -// } -// } } //Works under assumption that meshes do not often change the renderpass on which they are rendered std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ) { if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, - m_shader, renderPass, m_element, + material->getShader(), renderPass, m_element, m_backFaceCulling, m_triCCW, m_blendMode, m_depthCulling, m_depthWrite, invertedZ); @@ -86,105 +51,6 @@ std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr } -void GMeshVLK::createDescriptorSets(GShaderPermutationVLK *shaderVLK) { - - auto descLayout = shaderVLK->getImageDescriptorLayout(); - - imageDescriptorSets = std::vector>(4, NULL); - for (int j = 0; j < 4; j++) { - imageDescriptorSets[j] = m_device.createDescriptorSet(descLayout, 0, shaderVLK->getTextureCount()); - } - - descriptorSetsUpdated = std::vector(4, false); - - for (int j = 0; j < 4; j++) { - std::vector descriptorWrites; - - //Bind Black pixel texture - std::vector imageInfos(shaderVLK->getTextureCount()); - - auto blackTexture = m_device.getBlackPixelTexture(); - GTextureVLK *blackTextureVlk = reinterpret_cast(blackTexture.get()); - - int bindIndex = 0; - for (int i = 0; i < shaderVLK->getTextureCount(); i++) { - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = blackTextureVlk->texture.view; - imageInfo.sampler = blackTextureVlk->texture.sampler; - imageInfos[bindIndex] = imageInfo; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = imageDescriptorSets[j]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = shaderVLK->getTextureBindingStart()+bindIndex; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pBufferInfo = nullptr; - writeDescriptor.pImageInfo = &imageInfos[bindIndex]; - writeDescriptor.pTexelBufferView = nullptr; - descriptorWrites.push_back(writeDescriptor); - bindIndex++; - } - - if (!descriptorWrites.empty()) { - imageDescriptorSets[j]->writeToDescriptorSets(descriptorWrites); - } -// vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); - } -} - -void GMeshVLK::updateDescriptor() { - bool allTexturesAreReady = true; - - int textureBegin = ((GShaderPermutationVLK *)m_shader.get())->getTextureBindingStart(); - - int updateFrame = m_device.getUpdateFrameNumber(); - if (descriptorSetsUpdated[updateFrame]) return; - - for (auto& texture : m_texture) { - if (texture == nullptr) continue; - allTexturesAreReady &= texture->getIsLoaded(); - } - - if (allTexturesAreReady) { - std::vector descriptorWrites; - std::vector imageInfos(m_texture.size()); - - if (((GShaderPermutationVLK *)m_shader.get())->getTextureCount() == 0) return; - - for (size_t i = 0; i < m_texture.size(); i++) { - GTextureVLK *textureVlk = reinterpret_cast(m_texture[i].get()); - if (textureVlk == nullptr) continue; - - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = textureVlk->texture.view; - imageInfo.sampler = textureVlk->texture.sampler; - imageInfos[i] = imageInfo; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = imageDescriptorSets[updateFrame]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = textureBegin+i; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pImageInfo = &imageInfos[i]; - descriptorWrites.push_back(writeDescriptor); - } - - if (descriptorWrites.size() > 0) { - imageDescriptorSets[updateFrame]->writeToDescriptorSets(descriptorWrites); -// vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); - } - - descriptorSetsUpdated[updateFrame] = true; - } -} GMeshVLK::~GMeshVLK() { diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index ac19f7b38..07a34b483 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -9,6 +9,7 @@ #include "../../interface/meshes/IMesh.h" #include "../GDeviceVulkan.h" #include "../descriptorSets/GDescriptorSet.h" +#include "../materials/IMaterialVLK.h" class GMeshVLK : public IMesh { friend class GDeviceVLK; @@ -25,11 +26,11 @@ class GMeshVLK : public IMesh { public: std::shared_ptr getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ); - + HMaterialVLK material; protected: MeshType m_meshType; - HGShaderPermutation m_shader; + int8_t m_depthWrite; int8_t m_depthCulling; @@ -49,7 +50,6 @@ class GMeshVLK : public IMesh { //Vulkan specific - std::vector> imageDescriptorSets; std::vector descriptorSetsUpdated; std::shared_ptr m_lastRenderPass = nullptr; @@ -58,8 +58,7 @@ class GMeshVLK : public IMesh { private: GDeviceVLK &m_device; - void createDescriptorSets(GShaderPermutationVLK *shaderVLK); - void updateDescriptor(); + }; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 294658c74..9ac85686e 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -67,7 +67,7 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe std::copy(&mipmaps[i].texture[0], &mipmaps[i].texture[0]+mipmaps[i].texture.size(), std::back_inserter(unitedBuffer)); } - createTexture(hmipmaps, textureFormatGPU, unitedBuffer); + GTextureVLK::createTexture(hmipmaps, textureFormatGPU, unitedBuffer); } //bool GBlpTextureVLK::getIsLoaded() { From 803894dde9a3910b341f5e47ba53ad88f27fca07 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 15 Jan 2023 04:04:00 +0200 Subject: [PATCH 014/212] changes --- src/ui/FrontendUI.cpp | 109 ---- .../renderer/uiScene/FrontendUIRenderer.cpp | 114 +++++ src/ui/renderer/uiScene/FrontendUIRenderer.h | 9 +- .../uiScene/IFrontendUIBufferCreate.h | 5 +- .../renderer/uiScene/materials/UIMaterial.h | 7 - .../vulkan/FrontendUIRenderForwardVLK.cpp | 15 +- .../vulkan/FrontendUIRenderForwardVLK.h | 10 +- wowViewerLib/3rdparty/tinygltf | 2 +- wowViewerLib/CMakeLists.txt | 4 +- .../shaders/src/spirv/dumpShaderFields.h | 76 ++- .../src/engine/managers/CRibbonEmitter.cpp | 2 +- .../managers/particles/particleEmitter.cpp | 2 +- .../src/engine/objects/ViewsObjects.cpp | 2 +- .../src/engine/objects/adt/adtObject.cpp | 2 +- .../src/engine/objects/m2/m2Object.cpp | 6 +- .../src/engine/objects/scenes/map.cpp | 10 +- wowViewerLib/src/engine/objects/scenes/map.h | 3 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 475 +++++++++++++++++- wowViewerLib/src/gapi/IDeviceFactory.cpp | 2 + wowViewerLib/src/gapi/interface/IDevice.h | 4 + .../src/gapi/interface/buffers/IBufferChunk.h | 2 +- .../src/gapi/interface/materials/IMaterial.h | 3 + .../src/gapi/interface/meshes/IMesh.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 21 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 2 +- .../src/gapi/vulkan/materials/IMaterialVLK.h | 40 -- ...MaterialVLK.cpp => ISimpleMaterialVLK.cpp} | 77 +-- .../vulkan/materials/ISimpleMaterialVLK.h | 42 ++ .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 2 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 4 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 102 +++- .../vulkan/shaders/GShaderPermutationVLK.h | 23 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 2 + wowViewerLib/src/renderer/IRenderParameters.h | 6 +- .../buffers/IVertexBufferDynamicTemplate.h | 2 +- .../src/renderer/frame/FrameInputParams.h | 10 +- .../src/renderer/mapScene/MapSceneParams.h | 18 + .../src/renderer/mapScene/MapSceneRenderer.h | 4 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 6 +- .../vulkan/MapSceneRenderForwardVLK.h | 3 +- 41 files changed, 942 insertions(+), 292 deletions(-) delete mode 100644 wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h rename wowViewerLib/src/gapi/vulkan/materials/{IMaterialVLK.cpp => ISimpleMaterialVLK.cpp} (64%) create mode 100644 wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h create mode 100644 wowViewerLib/src/renderer/mapScene/MapSceneParams.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 0b8484983..e7f402e85 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1766,114 +1766,5 @@ void FrontendUI::update(HFrontendUIBufferCreate renderer) { if (draw_data == nullptr) return; - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) { - return; - } - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - //Create projection matrix: - auto uiScale = ImGui::GetIO().uiScale; - float L = draw_data->DisplayPos.x * uiScale; - float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; - float T = draw_data->DisplayPos.y * uiScale; - float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; - mathfu::mat4 ortho_projection = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, -1.0f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, - }; - - if (m_device->getIsVulkanAxisSystem()) { - static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1.0/2.0, 1/2.0, - 0, 0, 0, 1).Transpose(); - ortho_projection = vulkanMatrixFix1 * ortho_projection; - } - std::shared_ptr> uboPart = nullptr; - - uboPart->setUpdateHandler([ortho_projection,uiScale](auto &data, const HFrameDependantData &frameDepedantData) { - auto &uni = data; - uni.projectionMat = ortho_projection; - uni.scale[0] = uiScale; - }); - - auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); - // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - - // Upload vertex/index buffers - - auto vboBuffer = renderer->createVertexBuffer(cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - auto iboBuffer = renderer->createIndexBuffer(cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - - auto vertexBufferBindings = renderer->createVAO(vboBuffer, iboBuffer); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != NULL) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) -// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) -// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); -// else -// pcmd->UserCallback(cmd_list, pcmd); - assert(pcmd->UserCallback == NULL); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec4 clip_rect; - clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { - // Apply scissor/clipping rectangle - // Create mesh add add it to collected meshes - gMeshTemplate meshTemplate(vertexBufferBindings, shaderPermute); - meshTemplate.element = DrawElementMode::TRIANGLES; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.backFaceCulling = false; - meshTemplate.depthCulling = false; -//void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { - - meshTemplate.scissorEnabled = true; - //Vulkan has different clip offset compared to OGL - if (!m_device->getIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } else { - meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; - } - - meshTemplate.texture[0] = pcmd->TextureId; - - meshTemplate.start = pcmd->IdxOffset * 2; - meshTemplate.end = pcmd->ElemCount; - - UIMaterialTemplate materialTemplate; - materialTemplate.texture = pcmd->TextureId; - materialTemplate.uiUBO = uboPart; - - auto material = renderer->createUIMaterial(materialTemplate); - - - renderer->createUIMesh(meshTemplate, material); - } - } - } - } } \ No newline at end of file diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 007ecddb7..9b5b408a7 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -3,3 +3,117 @@ // #include "FrontendUIRenderer.h" + +void FrontendUIRenderer::processFramePlan() { + + ImGuiFramePlan::ImGUIParam *frameParam = nullptr; + + auto draw_data = &frameParam->imData; + + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) { + return; + } + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + //Create projection matrix: + auto uiScale = ImGui::GetIO().uiScale; + float L = draw_data->DisplayPos.x * uiScale; + float R = (draw_data->DisplayPos.x + draw_data->DisplaySize.x) * uiScale; + float T = draw_data->DisplayPos.y * uiScale; + float B = (draw_data->DisplayPos.y + draw_data->DisplaySize.y) * uiScale; + mathfu::mat4 ortho_projection = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + + if (m_device->getIsVulkanAxisSystem()) { + static const mathfu::mat4 vulkanMatrixFix1 = mathfu::mat4(1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1.0/2.0, 1/2.0, + 0, 0, 0, 1).Transpose(); + ortho_projection = vulkanMatrixFix1 * ortho_projection; + } + std::shared_ptr> uboPart = nullptr; + + uboPart->setUpdateHandler([ortho_projection,uiScale](auto &data, const HFrameDependantData &frameDepedantData) { + auto &uni = data; + uni.projectionMat = ortho_projection; + uni.scale[0] = uiScale; + }); + + auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + + // Upload vertex/index buffers + + auto vboBuffer = this->createVertexBuffer(cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + auto iboBuffer = this->createIndexBuffer(cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + + auto vertexBufferBindings = this->createVAO(vboBuffer, iboBuffer); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) +// if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) +// ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); +// else +// pcmd->UserCallback(cmd_list, pcmd); + assert(pcmd->UserCallback == NULL); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + // Create mesh add add it to collected meshes + gMeshTemplate meshTemplate(vertexBufferBindings); + meshTemplate.element = DrawElementMode::TRIANGLES; + meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + meshTemplate.backFaceCulling = false; + meshTemplate.depthCulling = false; + meshTemplate.scissorEnabled = true; + //Vulkan has different clip offset compared to OGL + if (!m_device->getIsVulkanAxisSystem()) { + meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } else { + meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; + meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + } + + meshTemplate.texture[0] = pcmd->TextureId; + + meshTemplate.start = pcmd->IdxOffset * 2; + meshTemplate.end = pcmd->ElemCount; + + UIMaterialTemplate materialTemplate; + materialTemplate.texture = pcmd->TextureId; + materialTemplate.uiUBO = uboPart; + + auto material = this->createUIMaterial(materialTemplate); + +// this->createUIMesh(meshTemplate, material); + } + } + } + } +} diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index c123b30ea..7df23e279 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -17,12 +17,15 @@ static const std::array imguiBindings = {{ }}; -class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { +class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { public: - + virtual ~FrontendUIRenderer() = default; + void processFramePlan(); +private: + HGDevice m_device = nullptr; }; //typedef FrameInputParams FrontendUIInputParams; -typedef FrameInputParams FrontendUIInputParams; +typedef FrameInputParams FrontendUIInputParams; #endif //AWEBWOWVIEWERCPP_FRONTENDUIRENDERER_H diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index 03f93fb7a..30f857cf0 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -8,6 +8,7 @@ #include "../../../../wowViewerLib/src/gapi/interface/IDevice.h" #include "../../../../wowViewerLib/src/gapi/interface/IRendererProxy.h" #include "materials/UIMaterial.h" +#include "../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" class IFrontendUIBufferCreate { public: @@ -16,8 +17,8 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; - virtual HGMesh createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) = 0; - virtual HUIMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) = 0; + virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; + virtual HMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index 3406156b7..a6a7af6f4 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -15,11 +15,4 @@ struct UIMaterialTemplate { std::shared_ptr texture = nullptr; }; -class IUIMaterial { -public: - virtual ~IUIMaterial() = 0; -}; - -typedef std::shared_ptr HUIMaterial; - #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 8d20c7b45..f718677f2 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -4,6 +4,7 @@ #include "FrontendUIRenderForwardVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { } @@ -14,7 +15,7 @@ void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptrgetSubBuffer(sizeInBytes); } -HUIMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { - //TODO: - return nullptr; +HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { + std::vector> ubos = {std::dynamic_pointer_cast(materialTemplate.uiUBO)}; + std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; + return std::make_shared(m_device, + "imguiShader", "imguiShader", + ubos, + texturesVLK); } -HGMesh FrontendUIRenderForwardVLK::createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) { +HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { //TODO: return nullptr; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 3f41c5fa7..23dc663bf 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -11,11 +11,17 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" +#include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: explicit FrontendUIRenderForwardVLK(HGDeviceVLK hDevice); + ~FrontendUIRenderForwardVLK() override = default; + void putIntoQueue(std::shared_ptr &frameInputParams) override; + std::shared_ptr getLastPlan() override { + return nullptr; + }; void update(VkCommandBuffer udBuffer, VkCommandBuffer swapChainDraw); public: @@ -25,8 +31,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override { return nullptr; //VAO doesnt exist in Vulkan }; - HGMesh createUIMesh(gMeshTemplate &meshTemplate, const HUIMaterial &material) override; - HUIMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) override; + HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; + HMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) override; private: diff --git a/wowViewerLib/3rdparty/tinygltf b/wowViewerLib/3rdparty/tinygltf index 2c521b343..44f88c0fb 160000 --- a/wowViewerLib/3rdparty/tinygltf +++ b/wowViewerLib/3rdparty/tinygltf @@ -1 +1 @@ -Subproject commit 2c521b34327ca8fe893244c854544d60941e7388 +Subproject commit 44f88c0fbe238c2aae2c1a3435c070c872e15c50 diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 752a394b9..c5c5715dc 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -328,7 +328,7 @@ set(SOURCE_FILES src/renderer/buffers/IVertexBufferDynamicTemplate.h src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h - src/gapi/interface/materials/IMaterial.h) + src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -507,7 +507,7 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/GBufferVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.h src/gapi/vulkan/buffers/IBufferVLK.h - src/gapi/vulkan/materials/IMaterialVLK.cpp src/gapi/vulkan/materials/IMaterialVLK.h) + src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp src/gapi/vulkan/materials/ISimpleMaterialVLK.h) if (NOT Vulkan_SDK_DIR) set(Vulkan_SDK_DIR $ENV{VULKAN_SDK}) endif() diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index be5829e0c..f81c12593 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -11,6 +11,8 @@ #include "fileHelpers.h" #include "webGLSLCompiler.h" +constexpr const int MAX_SHADER_DESC_SETS = 8; + struct attributeDefine { std::string name; unsigned int location; @@ -37,17 +39,18 @@ struct imageBindingData { std::string imageName; }; -struct imageBindingAmountData { +struct bindingAmountData { unsigned int start = 999; unsigned int end = 0; unsigned int length = 0; - }; struct shaderMetaData { std::vector uboBindings; + std::array uboBindingAmountsPerSet; + std::vector imageBindings; - std::array imageBindingAmounts; + std::array imageBindingAmountsPerSet; }; //Per file @@ -122,6 +125,7 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { "#include \n" "#include \n" "#include \n" + "#include \n" "#include \n" "\n" "template \n" @@ -145,10 +149,12 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::cout << R"===( + constexpr const int MAX_SHADER_DESC_SETS = 8; + struct uboBindingData { - int set; - int binding; - int size; + unsigned int set; + unsigned int binding; + unsigned long long size; }; struct imageBindingData { unsigned int set; @@ -156,18 +162,20 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::string imageName; }; - struct imageBindingAmountData { + struct bindingAmountData { unsigned int start = 999; unsigned int end = 0; unsigned int length = 0; - }; struct shaderMetaData { std::vector uboBindings; + std::array uboBindingAmountsPerSet; + std::vector imageBindings; - std::array imageBindingAmounts; + std::array imageBindingAmountsPerSet; }; + //Per file extern const std::unordered_map shaderMetaInfo; extern const std::unordered_map> attributesPerShaderName; @@ -255,6 +263,13 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { metaInfo.uboBindings.push_back({set, binding, typeId_size}); + if (set >= 0) { + metaInfo.uboBindingAmountsPerSet[set].start = + std::min(metaInfo.imageBindingAmountsPerSet[set].start, binding); + metaInfo.uboBindingAmountsPerSet[set].end = + std::max(metaInfo.imageBindingAmountsPerSet[set].end, binding); + } + if (perSetMap.find(binding) != perSetMap.end()) { perSetMap[binding] = {}; } @@ -275,11 +290,18 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { glsl.to_name(resource.id) + "_" + memberName, offset, memberSize); } } + for (auto &data: metaInfo.uboBindingAmountsPerSet ) { + if (data.start < 100) { + data.length = data.end - data.start + 1; + } else { + data.start = 0; + } + } //Record data for images for (auto &resource : resources.sampled_images) { - unsigned int set = -1; - unsigned int binding = -1; + unsigned int set = 255; + unsigned int binding = 255; if (glsl.has_decoration(resource.id, spv::DecorationDescriptorSet) && glsl.has_decoration(resource.id, spv::DecorationBinding)) { @@ -288,11 +310,11 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { } metaInfo.imageBindings.push_back({set, binding, resource.name}); - if (set >= 0) { - metaInfo.imageBindingAmounts[set].start = - std::min(metaInfo.imageBindingAmounts[set].start, binding); - metaInfo.imageBindingAmounts[set].end = - std::max(metaInfo.imageBindingAmounts[set].end, binding); + if (set < 255) { + metaInfo.imageBindingAmountsPerSet[set].start = + std::min(metaInfo.imageBindingAmountsPerSet[set].start, binding); + metaInfo.imageBindingAmountsPerSet[set].end = + std::max(metaInfo.imageBindingAmountsPerSet[set].end, binding); } // std::cout << "set = " << set << std::endl; @@ -300,8 +322,8 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { // std::cout << resource.name << std::endl; // std::cout << glsl.to_name(resource.base_type_id) << std::endl; } - for (auto &data: metaInfo.imageBindingAmounts ) { - if (data.start < 16) { + for (auto &data: metaInfo.imageBindingAmountsPerSet ) { + if (data.start < 100) { data.length = data.end - data.start + 1; } else { data.start = 0; @@ -360,6 +382,20 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::cout << " },\n"; //UBO Bindings dump end + std::cout << " {\n"; + std::cout << " {\n"; + for (auto &bindingAmount : it->second.uboBindingAmountsPerSet) { + if (bindingAmount.length > 0) { + std::cout << " {" << bindingAmount.start << "," << bindingAmount.end << "," << bindingAmount.length << "}," + << std::endl; + } else { + std::cout << " {0,0,0}," << std::endl; + } + } + std::cout << " }\n"; + std::cout << " },\n"; + + std::cout << " {\n"; for (auto &binding : it->second.imageBindings) { std::cout << " {" << binding.set << "," << binding.binding << ", \"" << binding.imageName << "\"}," << std::endl; @@ -368,9 +404,9 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::cout << " {\n"; std::cout << " {\n"; - for (auto &bindingAmount : it->second.imageBindingAmounts) { + for (auto &bindingAmount : it->second.imageBindingAmountsPerSet) { if (bindingAmount.length > 0) { - std::cout << " {" << bindingAmount.start << "," << bindingAmount.end << ", " << bindingAmount.end << "}," + std::cout << " {" << bindingAmount.start << "," << bindingAmount.end << "," << bindingAmount.length << "}," << std::endl; } else { std::cout << " {0,0,0}," << std::endl; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index a9fa1bc7d..3c48abda4 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -118,7 +118,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); //Create mesh - gMeshTemplate meshTemplate(frame[k].m_bindings, shaderPermutation); + gMeshTemplate meshTemplate(frame[k].m_bindings); meshTemplate.depthWrite = !(material.flags & 0x10); meshTemplate.depthCulling = !(material.flags & 0x8); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 0318935e7..20b057ff5 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -304,7 +304,7 @@ void ParticleEmitter::createMesh() { HGShaderPermutation shaderPermutation = device->getShader("m2ParticleShader", "m2ParticleShader", nullptr); //Create mesh - gMeshTemplate meshTemplate(frame[i].m_bindings, shaderPermutation); + gMeshTemplate meshTemplate(frame[i].m_bindings); uint8_t blendMode = m_data->old.blendingType; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index ef5add54d..6fe8668bc 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -143,7 +143,7 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st HGShaderPermutation shaderPermutation = hDevice->getShader("drawPortalShader", "drawPortalShader", nullptr); //Create mesh - gMeshTemplate meshTemplate(portalPointsFrame.m_bindings, shaderPermutation); + gMeshTemplate meshTemplate(portalPointsFrame.m_bindings); meshTemplate.depthWrite = false; meshTemplate.depthCulling = !apiContainer->getConfig()->renderPortalsIgnoreDepth; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index d592213bb..478f4d058 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -653,7 +653,7 @@ void AdtObject::createMeshes() { bool noLayers = m_adtFileTex->mcnkStructs[i].mcly == nullptr || m_adtFileTex->mcnkStructs[i].mclyCnt <= 0; HGShaderPermutation hgShaderPermutation = device->getShader("adtShader", "adtShader", nullptr); - gMeshTemplate aTemplate(adtVertexBindings, hgShaderPermutation); + gMeshTemplate aTemplate(adtVertexBindings); aTemplate.meshType = MeshType::eAdtMesh; aTemplate.triCCW = 1; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 6fb67c3af..e598d9680 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1256,7 +1256,7 @@ void M2Object::createBoundingBoxMesh() { HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", nullptr); //TODO: - gMeshTemplate meshTemplate(/*m_api->hDevice->getBBVertexBinding()*/ nullptr, boundingBoxshaderPermutation); + gMeshTemplate meshTemplate(/*m_api->hDevice->getBBVertexBinding()*/ nullptr); meshTemplate.depthWrite = false; meshTemplate.depthCulling = true; @@ -1341,7 +1341,7 @@ float wfv_convert(float value, int16_t random) { HGM2Mesh M2Object::createWaterfallMesh() { HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterfallShader", "waterfallShader", nullptr); - gMeshTemplate meshTemplate(bufferBindings, shaderPermutation); + gMeshTemplate meshTemplate(bufferBindings); auto skinData = m_skinGeom->getSkinData(); auto m2Data = m_m2Geom->getM2Data(); @@ -1538,7 +1538,7 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti } HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", "m2Shader", &cacheRecord); - gMeshTemplate meshTemplate(finalBufferBindings, shaderPermutation); + gMeshTemplate meshTemplate(finalBufferBindings); int renderFlagIndex = m2Batch->materialIndex; auto renderFlag = m_m2Data->materials[renderFlagIndex]; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index af1e032d2..2efb52a64 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -336,7 +336,7 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config ///2. Create mesh auto shader = device->getShader("skyConus", "skyConus", nullptr); - gMeshTemplate meshTemplate(skyBindings, shader); + gMeshTemplate meshTemplate(skyBindings); meshTemplate.meshType = MeshType::eGeneralMesh; meshTemplate.depthWrite = false; meshTemplate.depthCulling = true; @@ -360,16 +360,16 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config return hmesh; } -void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { +void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { // std::cout << "Map::checkCulling finished called" << std::endl; // std::cout << "m_wdtfile->getIsLoaded() = " << m_wdtfile->getIsLoaded() << std::endl; cullCreateVarsCounter.beginMeasurement(); Config* config = this->m_api->getConfig(); - mathfu::vec4 cameraPos = frameInputParams.matricesForCulling->cameraPos; + mathfu::vec4 cameraPos = frameInputParams.frameParameters->matricesForCulling->cameraPos; mathfu::vec3 cameraVec3 = cameraPos.xyz(); - mathfu::mat4 &frustumMat = frameInputParams.matricesForCulling->perspectiveMat; - mathfu::mat4 &lookAtMat4 = frameInputParams.matricesForCulling->lookAtMat; + mathfu::mat4 &frustumMat = frameInputParams.frameParameters->matricesForCulling->perspectiveMat; + mathfu::mat4 &lookAtMat4 = frameInputParams.frameParameters->matricesForCulling->lookAtMat; size_t adtRenderedThisFramePrev = mapRenderPlan->adtArray.size(); mapRenderPlan->adtArray = {}; diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index b7139384b..fffb899d2 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -18,6 +18,7 @@ #include "../../algorithms/FrameCounter.h" #include "../../../renderer/frame/FrameInputParams.h" #include "../../../renderer/mapScene/MapScenePlan.h" +#include "../../../renderer/mapScene/MapSceneParams.h" enum class SceneMode { smMap, @@ -202,7 +203,7 @@ class Map : public IScene, public IMapApi { // std::cout << "Map destroyed " << std::endl; }; - void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); + void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); void setMandatoryADTs(std::vector> &mandatoryADTs) { m_mandatoryADT = mandatoryADTs; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 0a49224c4..4c3799504 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -474,7 +474,7 @@ void WmoGroupObject::createMeshes() { HGShaderPermutation shaderPermutation = device->getShader("wmoShader", "wmoShader", &cacheRecord); - gMeshTemplate meshTemplate(binding, shaderPermutation); + gMeshTemplate meshTemplate(binding); bool isBatchA = (j >= 0 && j < (m_geom->mogp->transBatchCount)); bool isBatchC = (j >= (mogp->transBatchCount + mogp->intBatchCount)); @@ -646,7 +646,7 @@ void WmoGroupObject::createWaterMeshes() { HGShaderPermutation shaderPermutation = device->getShader("waterShader", "waterShader", nullptr); - gMeshTemplate meshTemplate(binding, shaderPermutation); + gMeshTemplate meshTemplate(binding); auto blendMode = material.blendMode; float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 52386232a..3c8111af5 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -5,6 +5,7 @@ #include #include #include +#include #include template @@ -22,10 +23,12 @@ struct attributeDefine { int location; }; + constexpr const int MAX_SHADER_DESC_SETS = 8; + struct uboBindingData { - int set; - int binding; - int size; + unsigned int set; + unsigned int binding; + unsigned long long size; }; struct imageBindingData { unsigned int set; @@ -33,18 +36,20 @@ struct attributeDefine { std::string imageName; }; - struct imageBindingAmountData { + struct bindingAmountData { unsigned int start = 999; unsigned int end = 0; unsigned int length = 0; - }; struct shaderMetaData { std::vector uboBindings; + std::array uboBindingAmountsPerSet; + std::vector imageBindings; - std::array imageBindingAmounts; + std::array imageBindingAmountsPerSet; }; + //Per file extern const std::unordered_map shaderMetaInfo; extern const std::unordered_map> attributesPerShaderName; @@ -285,6 +290,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,2,16}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -308,6 +325,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,3,32}, }, + { + { + {3,3,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "uTexture"}, {1,6, "uTexture2"}, @@ -322,7 +351,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,13, 13}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -339,13 +368,25 @@ const std::unordered_map shaderMetaInfo = { {0,4,16}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5, 5}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -362,6 +403,18 @@ const std::unordered_map shaderMetaInfo = { {0,4,96}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,9, "uNormalTex"}, {1,7, "uNoise"}, @@ -371,7 +424,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,9, 9}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -387,6 +440,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -408,6 +473,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,144}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -431,13 +508,25 @@ const std::unordered_map shaderMetaInfo = { {0,1,14144}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {8,8, 8}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -454,6 +543,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,128}, {0,1,64}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -475,6 +576,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,128}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -496,6 +609,18 @@ const std::unordered_map shaderMetaInfo = { { {0,4,16}, }, + { + { + {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "screenTex"}, {1,6, "blurTex"}, @@ -503,7 +628,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,6, 6}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -521,6 +646,18 @@ const std::unordered_map shaderMetaInfo = { {0,3,16}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,9, "uAlphaTexture"}, {1,10, "uLayerHeight0"}, @@ -535,7 +672,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,13, 13}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -552,6 +689,18 @@ const std::unordered_map shaderMetaInfo = { {0,1,112}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -572,6 +721,18 @@ const std::unordered_map shaderMetaInfo = { { { }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -593,12 +754,24 @@ const std::unordered_map shaderMetaInfo = { { {0,2,12}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {0,3, "diffuse"}, }, { { - {3,3, 3}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -615,6 +788,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,84}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -636,6 +821,18 @@ const std::unordered_map shaderMetaInfo = { { {0,1,12}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -657,6 +854,18 @@ const std::unordered_map shaderMetaInfo = { { {0,1,112}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -677,6 +886,18 @@ const std::unordered_map shaderMetaInfo = { { { }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -697,6 +918,18 @@ const std::unordered_map shaderMetaInfo = { { { }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -718,6 +951,18 @@ const std::unordered_map shaderMetaInfo = { { {0,4,16}, }, + { + { + {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -739,6 +984,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,128}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -760,13 +1017,25 @@ const std::unordered_map shaderMetaInfo = { { {0,4,32}, }, + { + { + {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "texture0"}, }, { { {0,0,0}, - {5,5, 5}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -781,13 +1050,25 @@ const std::unordered_map shaderMetaInfo = { { { }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "Texture"}, }, { { {0,0,0}, - {5,5, 5}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,6 +1084,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -824,6 +1117,18 @@ const std::unordered_map shaderMetaInfo = { { {0,2,16}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -845,6 +1150,18 @@ const std::unordered_map shaderMetaInfo = { { {0,1,80}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -869,6 +1186,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,1,14144}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "uTexture"}, {1,6, "uTexture2"}, @@ -878,7 +1207,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,8, 8}, + {5,8,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -895,6 +1224,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,1,64}, }, + { + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -916,6 +1257,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,128}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -937,6 +1290,18 @@ const std::unordered_map shaderMetaInfo = { { {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -959,6 +1324,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,2,96}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -980,12 +1357,24 @@ const std::unordered_map shaderMetaInfo = { { {0,2,168}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {0,3, "u_sampler"}, }, { { - {3,3, 3}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1001,6 +1390,18 @@ const std::unordered_map shaderMetaInfo = { { { }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -1023,6 +1424,18 @@ const std::unordered_map shaderMetaInfo = { {0,4,32}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "uTexture"}, {1,6, "uTexture2"}, @@ -1031,7 +1444,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,0}, - {5,7, 7}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1049,6 +1462,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,368}, {0,2,160}, }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { }, { @@ -1071,13 +1496,25 @@ const std::unordered_map shaderMetaInfo = { {0,4,48}, {0,0,368}, }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, { {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5, 5}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, diff --git a/wowViewerLib/src/gapi/IDeviceFactory.cpp b/wowViewerLib/src/gapi/IDeviceFactory.cpp index c6016870e..91b05e7e0 100644 --- a/wowViewerLib/src/gapi/IDeviceFactory.cpp +++ b/wowViewerLib/src/gapi/IDeviceFactory.cpp @@ -19,6 +19,7 @@ #include "vulkan/GDeviceVulkan.h" #endif +#if defined(LINK_OGL2) || defined(LINK_OGL3) || defined(LINK_OGL4) void initOGLPointers(){ #if defined(_WIN32) && (!defined(WITH_GLESv2) && !defined(__EMSCRIPTEN__)) glewExperimental = true; // Needed in core profile @@ -29,6 +30,7 @@ void initOGLPointers(){ } #endif } +#endif HGDevice IDeviceFactory::createDevice(std::string gapiName, void * data) { #ifdef LINK_OGL2 diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index e1784426f..76553c894 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -5,6 +5,10 @@ #ifndef AWEBWOWVIEWERCPP_IDEVICE_H #define AWEBWOWVIEWERCPP_IDEVICE_H +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + class IVertexBuffer; class IVertexBufferDynamic; class IVertexBufferBindings; diff --git a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h index c9ecc5f9a..875524d76 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h +++ b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h @@ -13,7 +13,7 @@ template using IChunkHandlerType = std::function ; template -class IBufferChunk { +class IBufferChunk : public IBuffer { friend class IDevice; private: IChunkHandlerType m_handler; diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index 7d2987dfe..a5c912b70 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -5,6 +5,7 @@ #ifndef AWEBWOWVIEWERCPP_IMATERIAL_H #define AWEBWOWVIEWERCPP_IMATERIAL_H +#include #include "../IDevice.h" class IMaterial { @@ -14,4 +15,6 @@ class IMaterial { virtual ~IMaterial() = default; }; +typedef std::shared_ptr HMaterial; + #endif //AWEBWOWVIEWERCPP_IMATERIAL_H diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 2e6475faa..0e60f6caf 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -53,7 +53,7 @@ enum class DrawElementMode { class gMeshTemplate { public: - gMeshTemplate(HGVertexBufferBindings bindings, HGShaderPermutation shader) : bindings(bindings), shader(shader) {} + gMeshTemplate(HGVertexBufferBindings bindings) : bindings(bindings) {} HGVertexBufferBindings bindings; HGShaderPermutation shader; MeshType meshType = MeshType::eGeneralMesh; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index a2a0186ab..c72eb677b 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -169,12 +169,12 @@ GDeviceVLK::SwapChainSupportDetails GDeviceVLK::querySwapChainSupport(VkPhysical void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) { createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - createInfo.pNext = NULL; - createInfo.flags = NULL; + createInfo.pNext = nullptr; + createInfo.flags = 0; createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; createInfo.pfnUserCallback = debugCallback; - createInfo.pUserData = 0; + createInfo.pUserData = nullptr; } @@ -614,6 +614,7 @@ GDeviceVLK::QueueFamilyIndices GDeviceVLK::findQueueFamilies(VkPhysicalDevice de vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); int i = 0; + int dedicatedTransferQueue = -1; for (const auto& queueFamily : queueFamilies) { if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { indices.graphicsFamily = i; @@ -623,6 +624,13 @@ GDeviceVLK::QueueFamilyIndices GDeviceVLK::findQueueFamilies(VkPhysicalDevice de indices.transferFamily = i; } + if (queueFamily.queueCount > 0 + && (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) + && !(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) + && !(queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT)) { + dedicatedTransferQueue = i; + } + VkBool32 presentSupport = false; vkGetPhysicalDeviceSurfaceSupportKHR(device, i, vkSurface, &presentSupport); @@ -630,12 +638,11 @@ GDeviceVLK::QueueFamilyIndices GDeviceVLK::findQueueFamilies(VkPhysicalDevice de indices.presentFamily = i; } -// if (indices.isComplete()) { -// break; -// } - i++; } + if (dedicatedTransferQueue > -1) { + indices.transferFamily = dedicatedTransferQueue; + } return indices; } diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index 1498d17f7..3a5cde4af 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -232,7 +232,7 @@ void GPipelineVLK::createPipeline( VkPipelineDynamicStateCreateInfo dynamicState = {}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.pNext = NULL; - dynamicState.pDynamicStates = &dynamicStateEnables[0]; + dynamicState.pDynamicStates = dynamicStateEnables.data(); dynamicState.dynamicStateCount = 2; VkGraphicsPipelineCreateInfo pipelineInfo = {}; diff --git a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h deleted file mode 100644 index b16f70091..000000000 --- a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by Deamon on 29.12.22. -// - -#ifndef AWEBWOWVIEWERCPP_IMATERIALVLK_H -#define AWEBWOWVIEWERCPP_IMATERIALVLK_H - - -#include -#include -#include "../../interface/materials/IMaterial.h" -#include "../descriptorSets/GDescriptorSet.h" - -class IMaterialVLK : public IMaterial { -public: - IMaterialVLK(HGDeviceVLK device); - ~IMaterialVLK() override = default;; - - HGShaderPermutation getShader() { - return m_shader; - } - - void createImageDescriptorSet(); - void updateImageDescriptorSet(); - -private: - HGDeviceVLK m_device; - - std::vector m_textures = {}; - - std::vector> imageDescriptorSets; - std::vector> uboDescriptorSets; - std::vector> ssboDescriptorSets; - - HGShaderPermutation m_shader; -}; - -typedef std::shared_ptr HMaterialVLK; - -#endif //AWEBWOWVIEWERCPP_IMATERIALVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp similarity index 64% rename from wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp rename to wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index 295300303..968c1a299 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/IMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -2,11 +2,11 @@ // Created by Deamon on 29.12.22. // -#include "IMaterialVLK.h" +#include "ISimpleMaterialVLK.h" #include "../shaders/GShaderPermutationVLK.h" #include "../textures/GTextureVLK.h" -void IMaterialVLK::createImageDescriptorSet() { +void ISimpleMaterialVLK::createImageDescriptorSet() { auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto descLayout = shaderVLK->getImageDescriptorLayout(); @@ -50,7 +50,7 @@ void IMaterialVLK::createImageDescriptorSet() { } } -void IMaterialVLK::updateImageDescriptorSet() { +void ISimpleMaterialVLK::updateImageDescriptorSet() { bool allTexturesAreReady = true; auto shaderVLK = std::dynamic_pointer_cast(m_shader); @@ -96,43 +96,50 @@ void IMaterialVLK::updateImageDescriptorSet() { } } -IMaterialVLK::IMaterialVLK(HGDeviceVLK device) : m_device(device) { - - //TODO: - m_shader = device->getShader("", "", nullptr); +ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, std::string vertexShader, std::string pixelShader, std::vector> &ubos, std::vector &textures) : m_device(device) { + m_shader = device->getShader(vertexShader, pixelShader, nullptr); auto shaderVLK = std::dynamic_pointer_cast(m_shader); + auto &shaderLayout = shaderVLK->getShaderLayout(); - - //Check the buffer sizes - std::unordered_map shaderLayoutBindings; - for (int i = 0; i < shaderVLK->vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = shaderVLK->vertShaderMeta->uboBindings[i]; - - auto it = shaderLayoutBindings.find(uboVertBinding.binding); - if (it == std::end( shaderLayoutBindings )) { - shaderLayoutBindings.insert({uboVertBinding.binding, uboVertBinding}); - } + auto uboSetLayout = shaderLayout.setLayouts[0]; + if (ubos.size() != uboSetLayout.uboBindings.length) { + std::cerr << "not enough ubos for shaderName = " << shaderVLK->getShaderName() << std::endl; } - for (int i = 0; i < shaderVLK->fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = shaderVLK->fragShaderMeta->uboBindings[i]; - auto it = shaderLayoutBindings.find(uboFragBinding.binding); - if (it == std::end( shaderLayoutBindings )) { - shaderLayoutBindings.insert({uboFragBinding.binding, uboFragBinding}); + for (unsigned int i = uboSetLayout.uboBindings.start; i <= uboSetLayout.uboBindings.end; i++) { + auto it = uboSetLayout.uboSizesPerBinding.find(i); + if (it != std::end(uboSetLayout.uboSizesPerBinding)) { + auto uboIndex = i - uboSetLayout.uboBindings.start; + if (ubos[uboIndex] == nullptr) { + std::cerr << "UBO is not set for " + << "shader = " << shaderVLK->getShaderName() + << " set = " << 1 + << " binding" << i + << std::endl; + } + + if (it->second != ubos[uboIndex]->getSize()) { + std::cout << "buffers missmatch! for" + << " shaderName = " << shaderVLK->getShaderName() + << " set = " << 1 + << " binding = " << i + << " expected size " << (it->second) + << ", provided size = " << (ubos[uboIndex]->getSize()) + << std::endl; + } } } -//TODO: -// for (int i = 0; i < 5; i++) { -// auto it = shaderLayoutBindings.find(i); -// if (it != shaderLayoutBindings.end()) { -// if ((m_UniformBuffer[i] != nullptr) && (it->second.size != (m_UniformBuffer[i]->getSize()))) { -// std::cout << "buffers missmatch! for shaderName = " << shaderVLK->getShaderName() << -// " index = " << i << -// " expected size " << (it->second.size) << -// ", provided size = " << (m_UniformBuffer[i]->getSize()) << -// std::endl; -// } -// } -// } + auto imageSetLayout = shaderLayout.setLayouts[1]; + if (imageSetLayout.imageBindings.length != textures.size()) { + std::cout << "image count mismatch! for" + << " shaderName = " << shaderVLK->getShaderName() + << " set = " << 1 + << " expected count " << uboSetLayout.imageBindings.length + << ", provided count = " << textures.size() + << std::endl; + } + + m_textures = textures; + m_ubos = ubos; } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h new file mode 100644 index 000000000..1b21cf2f6 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -0,0 +1,42 @@ +// +// Created by Deamon on 29.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_ISIMPLEMATERIALVLK_H +#define AWEBWOWVIEWERCPP_ISIMPLEMATERIALVLK_H + + +#include +#include +#include "../../interface/materials/IMaterial.h" +#include "../descriptorSets/GDescriptorSet.h" +#include "../textures/GTextureVLK.h" + +class ISimpleMaterialVLK : public IMaterial { +public: + ISimpleMaterialVLK(const HGDeviceVLK &device, std::string vertexShader, std::string pixelShader, std::vector> &ubos, std::vector> &textures); + ~ISimpleMaterialVLK() override = default; + + HGShaderPermutation getShader() { + return m_shader; + } + + void createImageDescriptorSet(); + void updateImageDescriptorSet(); + +private: + HGDeviceVLK m_device; + + std::vector m_textures = {}; + std::vector> m_ubos = {}; + + std::vector> imageDescriptorSets; + std::vector> uboDescriptorSets; + std::vector> ssboDescriptorSets; + + HGShaderPermutation m_shader; +}; + +typedef std::shared_ptr HMaterialVLK; + +#endif //AWEBWOWVIEWERCPP_ISIMPLEMATERIALVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index de5f5fabc..c36128a2d 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -35,7 +35,7 @@ GMeshVLK::GMeshVLK(IDevice &device, } -//Works under assumption that meshes do not often change the renderpass on which they are rendered +//Works under assumption that meshes do not change the renderpass, on which they are rendered, too often std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ) { if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 07a34b483..c1b0aa399 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -9,7 +9,7 @@ #include "../../interface/meshes/IMesh.h" #include "../GDeviceVulkan.h" #include "../descriptorSets/GDescriptorSet.h" -#include "../materials/IMaterialVLK.h" +#include "../materials/ISimpleMaterialVLK.h" class GMeshVLK : public IMesh { friend class GDeviceVLK; @@ -30,8 +30,6 @@ class GMeshVLK : public IMesh { protected: MeshType m_meshType; - - int8_t m_depthWrite; int8_t m_depthCulling; int8_t m_backFaceCulling; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 0ae39e029..ebdb91177 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -220,9 +220,109 @@ void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const vertShaderMeta = &shaderMetaInfo.at(m_shaderNameVert + ".vert.spv"); fragShaderMeta = &shaderMetaInfo.at(m_shaderNameFrag + ".frag.spv"); - + this->createShaderLayout(); this->createUBODescriptorLayout(); this->createImageDescriptorLayout(); this->createUboDescriptorSets(); } +int GShaderPermutationVLK::getTextureBindingStart() { + return shaderLayout.setLayouts[1].imageBindings.start; +} + +int GShaderPermutationVLK::getTextureCount() { + return shaderLayout.setLayouts[1].imageBindings.length; +} + +inline void makeMin(unsigned int &a, const unsigned int b) { + a = std::min(a, b); +} +inline void makeMax(unsigned int &a, const unsigned int b) { + a = std::max(a, b); +} + +void GShaderPermutationVLK::createShaderLayout() { + //Check the buffer sizes + + //UBO stuff + for (int i = 0; i < this->vertShaderMeta->uboBindings.size(); i++) { + auto &uboVertBinding = this->vertShaderMeta->uboBindings[i]; + + auto &setLayout = shaderLayout.setLayouts[uboVertBinding.set]; + + setLayout.uboSizesPerBinding[uboVertBinding.binding] = uboVertBinding.size; + makeMin(setLayout.uboBindings.start, uboVertBinding.binding); + makeMax(setLayout.uboBindings.end, uboVertBinding.binding); + } + for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { + auto &uboFragBinding = this->fragShaderMeta->uboBindings[i]; + + auto &setLayout = shaderLayout.setLayouts[uboFragBinding.set]; + + auto it = setLayout.uboSizesPerBinding.find(uboFragBinding.binding); + if (it != std::end(setLayout.uboSizesPerBinding)) { + if (it->second != uboFragBinding.size) { + std::cerr << "sizes mismatch for set = " << uboFragBinding.set + << " binding = " << uboFragBinding.binding + << " between " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + } + } else { + setLayout.uboSizesPerBinding[uboFragBinding.binding] = uboFragBinding.size; + + makeMin(setLayout.uboBindings.start, uboFragBinding.binding); + makeMax(setLayout.uboBindings.end, uboFragBinding.binding); + } + } + + //Image stuff + for (int i = 0; i < this->vertShaderMeta->imageBindings.size(); i++) { + auto &imageVertBinding = this->vertShaderMeta->imageBindings[i]; + auto &setLayout = shaderLayout.setLayouts[imageVertBinding.set]; + + if (setLayout.uboSizesPerBinding.find(imageVertBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { + std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageVertBinding.set + << " binding = " << imageVertBinding.binding + << " in " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + } + + makeMin(setLayout.imageBindings.start, imageVertBinding.binding); + makeMax(setLayout.imageBindings.end, imageVertBinding.binding); + } + for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { + auto &imageFragBinding = this->fragShaderMeta->imageBindings[i]; + + auto &setLayout = shaderLayout.setLayouts[imageFragBinding.set]; + + if (setLayout.uboSizesPerBinding.find(imageFragBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { + std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageFragBinding.set + << " binding = " << imageFragBinding.binding + << " in " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + } + + makeMin(setLayout.imageBindings.start, imageFragBinding.binding); + makeMax(setLayout.imageBindings.end, imageFragBinding.binding); + } + //Cleanup + for (auto &shaderLayout : shaderLayout.setLayouts) { + { + auto &data = shaderLayout.uboBindings; + if (shaderLayout.uboBindings.start < 100) { + data.length = data.end - data.start + 1; + } else { + data.start = 0; + } + } + { + auto &data = shaderLayout.imageBindings; + if (shaderLayout.uboBindings.start < 100) { + data.length = data.end - data.start + 1; + } else { + data.start = 0; + } + } + } +} + diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index 7ecb9cc59..b7a25bfdd 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -6,12 +6,23 @@ #define AWEBWOWVIEWERCPP_GSHADERPERMUTATION_H #include +#include #include #include "../GDeviceVulkan.h" #include "../../interface/IShaderPermutation.h" #include "../descriptorSets/GDescriptorSet.h" #include "../../../engine/shader/ShaderDefinitions.h" +struct ShaderSetLayout { + std::unordered_map uboSizesPerBinding; + bindingAmountData uboBindings; + bindingAmountData imageBindings; +}; + +struct CombinedShaderLayout { + std::array setLayouts; +}; + class GShaderPermutationVLK : public IShaderPermutation { friend class GDeviceVLK; @@ -23,8 +34,8 @@ class GShaderPermutationVLK : public IShaderPermutation { VkDescriptorSetLayout getImageDescriptorLayout() {return imageDescriptorSetLayout;} VkDescriptorSetLayout getUboDescriptorLayout() {return uboDescriptorSetLayout;} - virtual int getTextureBindingStart() = 0; - virtual int getTextureCount() = 0; + virtual int getTextureBindingStart(); + virtual int getTextureCount(); const shaderMetaData *fragShaderMeta; const shaderMetaData *vertShaderMeta; @@ -33,6 +44,10 @@ class GShaderPermutationVLK : public IShaderPermutation { return m_shaderName; } + const CombinedShaderLayout &getShaderLayout() { + return shaderLayout; + }; + protected: explicit GShaderPermutationVLK(std::string &shaderName, IDevice *device); explicit GShaderPermutationVLK(std::string &shaderName, std::string &shaderVertName, std::string &shaderFragName, IDevice *device); @@ -62,6 +77,8 @@ class GShaderPermutationVLK : public IShaderPermutation { std::string m_shaderNameVert; std::string m_shaderNameFrag; + CombinedShaderLayout shaderLayout; + void createUBODescriptorLayout(); void createImageDescriptorLayout(); @@ -71,6 +88,8 @@ class GShaderPermutationVLK : public IShaderPermutation { void updateDescriptorSet(int index); std::vector hasBondUBO = std::vector(7, false); + + void createShaderLayout(); }; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 94f8cd168..537f27d76 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -77,5 +77,7 @@ class GTextureVLK : public ITexture { ); }; +typedef std::shared_ptr HGTextureVLK; + #endif //AWEBWOWVIEWERCPP_GTEXTUREVLK_H diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index dd8d15ec6..0050d247a 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -7,10 +7,10 @@ #include "frame/FrameInputParams.h" -template +template class IRendererParameters { - virtual void putIntoQueue(std::shared_ptr &frameInputParams) = 0; - + virtual void putIntoQueue(std::shared_ptr> &frameInputParams) = 0; + virtual std::shared_ptr getLastPlan() = 0; }; #endif //AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H diff --git a/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h index 200f28204..de73786b7 100644 --- a/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h +++ b/wowViewerLib/src/renderer/buffers/IVertexBufferDynamicTemplate.h @@ -13,7 +13,7 @@ class IVertexBufferDynamicTemplate { virtual ~IVertexBufferDynamicTemplate() = 0; virtual const std::vector &getBuffer() = 0; - virtual void save(size_t sizeToSave) = 0; + virtual void save(std::size_t sizeToSave) = 0; }; diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 31e139256..cd00d6480 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -5,6 +5,7 @@ #ifndef AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H #define AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H +#include #include "../../engine/CameraMatrices.h" #include "../../engine/objects/iScene.h" #include "../../include/iostuff.h" @@ -14,14 +15,9 @@ struct ViewPortDimensions{ std::array maxs; }; -//template +template struct FrameInputParams { - HCameraMatrices matricesForCulling; - HCameraMatrices cameraMatricesForRendering; - HCameraMatrices cameraMatricesForDebugCamera; - HScene scene; - -// std::shared_ptr additionalData; + std::shared_ptr frameParameters; //Time advance animTime_t delta = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h new file mode 100644 index 000000000..aa1d83663 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h @@ -0,0 +1,18 @@ +// +// Created by Deamon on 08.01.23. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENEPARAMS_H +#define AWEBWOWVIEWERCPP_MAPSCENEPARAMS_H + + +#include "../../engine/CameraMatrices.h" + +struct MapSceneParams { + HCameraMatrices matricesForCulling; + HCameraMatrices cameraMatricesForRendering; + HCameraMatrices cameraMatricesForDebugCamera; +}; + +typedef std::shared_ptr HMapSceneParams; +#endif //AWEBWOWVIEWERCPP_MAPSCENEPARAMS_H diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 674edd67a..4ca4096dc 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -11,14 +11,14 @@ #include "../../engine/objects/scenes/map.h" #include "IMapSceneBufferCreate.h" -class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { +class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer() = default; ~MapSceneRenderer() override = 0; }; //typedef FrameInputParams MapSceneRendererInputParams; -typedef FrameInputParams MapSceneRendererInputParams; +typedef FrameInputParams MapSceneRendererInputParams; typedef std::shared_ptr HMapSceneRenderer; #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERER_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 91c184eba..5e9d693a1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -8,7 +8,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_devi } -void MapSceneRenderForwardVLK::putIntoQueue(std::shared_ptr &frameInputParams) { +void MapSceneRenderForwardVLK::putIntoQueue(std::shared_ptr> &frameInputParams) { } @@ -45,3 +45,7 @@ HGVertexBuffer MapSceneRenderForwardVLK::createWaterVertexBuffer(int sizeInBytes HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) { return HGIndexBuffer(); } + +std::shared_ptr MapSceneRenderForwardVLK::getLastPlan() { + return std::shared_ptr(); +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index e2b6dcbff..9a4631d91 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -13,7 +13,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { public: explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); - void putIntoQueue(std::shared_ptr &frameInputParams) override; + void putIntoQueue(std::shared_ptr> &frameInputParams) override; + std::shared_ptr getLastPlan() override; //Buffer creation HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; From d0c8c1c2d7f7b9a9f815e6f99b447e703cadd364 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 22 Jan 2023 10:07:18 +0200 Subject: [PATCH 015/212] commit --- src/ui/renderer/uiScene/FrontendUIRenderer.cpp | 12 ++++++------ src/ui/renderer/uiScene/FrontendUIRenderer.h | 1 + src/ui/renderer/uiScene/materials/UIMaterial.h | 10 +++++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 9b5b408a7..8c62a67e1 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -38,13 +38,13 @@ void FrontendUIRenderer::processFramePlan() { 0, 0, 0, 1).Transpose(); ortho_projection = vulkanMatrixFix1 * ortho_projection; } - std::shared_ptr> uboPart = nullptr; - uboPart->setUpdateHandler([ortho_projection,uiScale](auto &data, const HFrameDependantData &frameDepedantData) { - auto &uni = data; - uni.projectionMat = ortho_projection; - uni.scale[0] = uiScale; - }); + //UBO update start + auto &uni = m_imguiUbo->getObject(); + uni.projectionMat = ortho_projection; + uni.scale[0] = uiScale; + m_imguiUbo->save(sizeof(decltype(uni))); + //UBO update end auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); // Render command lists diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 7df23e279..150f00483 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -23,6 +23,7 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; }; //typedef FrameInputParams FrontendUIInputParams; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index a6a7af6f4..89fee6a21 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -9,10 +9,14 @@ #include "../../../../wowViewerLib/src/gapi/interface/textures/ITexture.h" #include "../../../../wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h" #include "../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" +#include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" -struct UIMaterialTemplate { - std::shared_ptr> uiUBO = nullptr; - std::shared_ptr texture = nullptr; +class UIMaterial : public IMaterial { + explicit UIMaterial(std::shared_ptr> UIWideChunk) : m_UIWideChunk(UIWideChunk) { + } + +protected: + std::shared_ptr> m_UIWideChunk; }; #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H From acb528ee86da606dc075e45628c5b1b3fd359ca6 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 22 Jan 2023 12:35:16 +0200 Subject: [PATCH 016/212] commit --- src/ui/renderer/uiScene/FrontendUIRenderer.cpp | 3 +-- src/ui/renderer/uiScene/FrontendUIRenderer.h | 3 ++- src/ui/renderer/uiScene/materials/UIMaterial.h | 18 +++++++++++++++++- .../vulkan/FrontendUIRenderForwardVLK.cpp | 18 ++++++++++++++++-- wowViewerLib/src/gapi/interface/meshes/IMesh.h | 5 +---- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 -- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 8c62a67e1..f59d77c03 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -93,7 +93,7 @@ void FrontendUIRenderer::processFramePlan() { meshTemplate.scissorEnabled = true; //Vulkan has different clip offset compared to OGL if (!m_device->getIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {(int)(clip_rect.x* uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; + meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; } else { meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; @@ -107,7 +107,6 @@ void FrontendUIRenderer::processFramePlan() { UIMaterialTemplate materialTemplate; materialTemplate.texture = pcmd->TextureId; - materialTemplate.uiUBO = uboPart; auto material = this->createUIMaterial(materialTemplate); diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 150f00483..f7f017a9c 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -21,8 +21,9 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; }; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index 89fee6a21..39dfd2747 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -11,12 +11,28 @@ #include "../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +struct UIMaterialTemplate { + HGTexture texture; + + bool operator==(const UIMaterialTemplate &other) const { + return (texture == other.texture); + }; +}; + class UIMaterial : public IMaterial { - explicit UIMaterial(std::shared_ptr> UIWideChunk) : m_UIWideChunk(UIWideChunk) { + explicit UIMaterial(std::shared_ptr> &UIWideChunk) : m_UIWideChunk(UIWideChunk) { } protected: std::shared_ptr> m_UIWideChunk; }; +struct UIMaterialHasher { + std::size_t operator()(const UIMaterialTemplate& k) const { + using std::hash; + return hash{}(k.texture.get()); + }; +}; +typedef std::unordered_map, UIMaterialHasher> UiMaterialCache; + #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index f718677f2..8ed846abe 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -34,12 +34,26 @@ HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { } HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { - std::vector> ubos = {std::dynamic_pointer_cast(materialTemplate.uiUBO)}; + auto i = m_materialCache.find(materialTemplate); + if (i != m_materialCache.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + m_materialCache.erase(i); + } + } + + std::vector> ubos = {}; std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; - return std::make_shared(m_device, + auto material = std::make_shared(m_device, "imguiShader", "imguiShader", ubos, texturesVLK); + + std::weak_ptr weakPtr(material); + m_materialCache[materialTemplate] = weakPtr; + + return material; } HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 0e60f6caf..c7b8650fb 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -97,10 +97,7 @@ class IMesh { public: - virtual ~IMesh(){ -// std::cout << "Mesh destroyed" << std::endl; - - }; + virtual ~IMesh() = default; virtual bool getIsTransparent() = 0; virtual MeshType getMeshType() = 0; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 508612ffd..087b6c401 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -357,10 +357,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this Date: Sun, 22 Jan 2023 17:11:07 +0200 Subject: [PATCH 017/212] commit --- CMakeLists.txt | 8 +- .../renderer/uiScene/materials/UIMaterial.h | 12 +- .../vulkan/materials/UIMaterialVLK.cpp | 5 + .../uiScene/vulkan/materials/UIMaterialVLK.h | 26 + wowViewerLib/CMakeLists.txt | 74 +- .../src/gapi/interface/buffers/IBufferChunk.h | 8 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 5 +- .../vulkan/materials/ISimpleMaterialVLK.h | 3 +- wowViewerLib/src/gapi/vulkan/volk.c | 2435 +++++++++++++++++ wowViewerLib/src/gapi/vulkan/volk.h | 1604 +++++++++++ 10 files changed, 4133 insertions(+), 47 deletions(-) create mode 100644 src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp create mode 100644 src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/volk.c create mode 100644 wowViewerLib/src/gapi/vulkan/volk.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 426f5046b..f8cde2fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,12 +233,14 @@ set(SOURCE_FILES src/ui/renderer/uiScene/FrontendUIRendererFactory.h src/ui/renderer/uiScene/ImGUIPlan.cpp src/ui/renderer/uiScene/ImGUIPlan.h - src/ui/renderer/uiScene/IFrontendUIBufferCreate.h) + src/ui/renderer/uiScene/IFrontendUIBufferCreate.h + src/ui/renderer/uiScene/materials/UIMaterial.h + ) set(SOURCE_FILES_VULKAN src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp - src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h) + src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h) ######################################################### # FIND OPENGL @@ -275,7 +277,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/3rdparty/SQLiteCpp EXCLUDE_FROM_ALL) if (NOT Vulkan_FOUND) - set(SOURCE_FILES_VULKAN "" src/ui/renderer/uiScene/materials/UIMaterial.h) + set(SOURCE_FILES_VULKAN "") endif() add_executable(AWebWoWViewerCpp ${SOURCE_FILES} ${SOURCE_FILES_VULKAN}) diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index 39dfd2747..7a4f21e42 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -19,13 +19,9 @@ struct UIMaterialTemplate { }; }; -class UIMaterial : public IMaterial { - explicit UIMaterial(std::shared_ptr> &UIWideChunk) : m_UIWideChunk(UIWideChunk) { - } - -protected: - std::shared_ptr> m_UIWideChunk; -}; +//------------------------------------------------------- +// HASHer and CACHE CLASS +//------------------------------------------------------- struct UIMaterialHasher { std::size_t operator()(const UIMaterialTemplate& k) const { @@ -33,6 +29,6 @@ struct UIMaterialHasher { return hash{}(k.texture.get()); }; }; -typedef std::unordered_map, UIMaterialHasher> UiMaterialCache; +typedef std::unordered_map, UIMaterialHasher> UiMaterialCache; #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp new file mode 100644 index 000000000..857759764 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 22.01.23. +// + +#include "UIMaterialVLK.h" diff --git a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h new file mode 100644 index 000000000..c2d7b5bf8 --- /dev/null +++ b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h @@ -0,0 +1,26 @@ +// +// Created by Deamon on 22.01.23. +// + +#ifndef AWEBWOWVIEWERCPP_UIMATERIALVLK_H +#define AWEBWOWVIEWERCPP_UIMATERIALVLK_H + +#include "../../materials/UIMaterial.h" +#include "../../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" + +class UIMaterialVLK : public ISimpleMaterialVLK { +public: + UIMaterialVLK(const HGDeviceVLK &device, + std::shared_ptr> UIWideChunk, + std::shared_ptr &texture + ) : + ISimpleMaterialVLK(device, "imguiShader", "imguiShader", + {std::dynamic_pointer_cast(UIWideChunk)}, + {std::dynamic_pointer_cast(texture)}) + { + + } +}; + + +#endif //AWEBWOWVIEWERCPP_UIMATERIALVLK_H diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index c5c5715dc..381afbf8c 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -460,7 +460,6 @@ set(OPENGL4x_IMPLEMENTATION src/gapi/ogl4.x/textures/GBlpTextureGL4x.cpp src/gapi/ogl4.x/GOcclusionQueryGL4x.h src/gapi/ogl4.x/syncronization/GPUFenceGL44.cpp src/gapi/ogl4.x/syncronization/GPUFenceGL44.h src/engine/persistance/header/skelFileHeader.h) endif() -set(Vulkan_INCLUDE_DIR "") if (LINK_VULKAN) set(VULKAN_IMPLEMENTATION src/include/vulkancontext.h @@ -508,38 +507,57 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/GBufferVLK.h src/gapi/vulkan/buffers/IBufferVLK.h src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp src/gapi/vulkan/materials/ISimpleMaterialVLK.h) - if (NOT Vulkan_SDK_DIR) - set(Vulkan_SDK_DIR $ENV{VULKAN_SDK}) - endif() - set(Vulkan_INCLUDE_DIR ${Vulkan_SDK_DIR}/include) - IF(WIN32) - IF (NOT Vulkan_FOUND) - find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS "${Vulkan_SDK_DIR}/lib") - IF (Vulkan_LIBRARY) - set(Vulkan_FOUND ON PARENT_SCOPE) - MESSAGE("Using bundled Vulkan library version win32, Vulkan_LIBRARY= ${Vulkan_LIBRARY}") - ELSE() - set(LINK_VULKAN OFF) - set(VULKAN_IMPLEMENTATION "") - ENDIF() - ENDIF() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR") - ELSE(WIN32) - IF (NOT Vulkan_FOUND) - find_library(Vulkan_LIBRARY NAMES vulkan HINTS "${Vulkan_SDK_DIR}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan") - IF (Vulkan_LIBRARY) - set(Vulkan_FOUND ON PARENT_SCOPE) - MESSAGE("Using bundled Vulkan library version non-win32") - ELSE() - set(LINK_VULKAN OFF) - set(VULKAN_IMPLEMENTATION "" ) - ENDIF() - ENDIF() + message(VULKAN_SDK = $ENV{VULKAN_SDK}) + find_package(Vulkan) + message(Vulkan_LIBRARY = ${Vulkan_LIBRARY}) + message(Vulkan_DIR = ${Vulkan_DIR}) + IF (Vulkan_LIBRARY) + set(Vulkan_FOUND ON PARENT_SCOPE) + MESSAGE("Using Vulkan library, Vulkan_LIBRARY= ${Vulkan_LIBRARY}") + ELSE() + MESSAGE("Vulkan Lib was not found. Disabling vulkan build") + + set(LINK_VULKAN OFF) + set(VULKAN_IMPLEMENTATION "") ENDIF() + + if (Vulkan_LIBRARY) + message(Vulkan_INCLUDE_DIR = ${Vulkan_INCLUDE_DIR}) + if (Vulkan_INCLUDE_DIR STREQUAL "") + message(FATAL_ERROR "Vulkan_INCLUDE_DIR is empty") + endif() + + get_filename_component(Vulkan_LIBRARY_DIR ${Vulkan_LIBRARY} DIRECTORY) + message(Vulkan_LIBRARY_DIR = ${Vulkan_LIBRARY_DIR}) + + # IF(WIN32) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR") + # endif() + + if(CMAKE_SYSTEM_NAME STREQUAL Windows) + set(VOLK_STATIC_DEFINES VK_USE_PLATFORM_WIN32_KHR) + elseif(CMAKE_SYSTEM_NAME STREQUAL Linux) + set(VOLK_STATIC_DEFINES VK_USE_PLATFORM_XLIB_KHR) + elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(VOLK_STATIC_DEFINES VK_USE_PLATFORM_MACOS_MVK) + #We need to bundle moltenVK and vulkan lib on macos + file(GLOB vulkanLibFiles RELATIVE ${srcDir} ${srcDir}/*.*) + + install(FILES ${Vulkan_LIBRARY} DESTINATION ${CMAKE_INSTALL_BINDIR}) + #TODO: The moltenVK needs to be built separately + # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() + #Add volk loader + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c) + endif() + + if (LINK_VULKAN) add_definitions(-DLINK_VULKAN) + else() + set(Vulkan_INCLUDE_DIR "") endif() endif() diff --git a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h index 875524d76..198be121b 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h +++ b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h @@ -7,6 +7,7 @@ #include #include +#include "IBuffer.h" #include "../../../renderer/mapScene/FrameDependentData.h" template @@ -18,17 +19,12 @@ class IBufferChunk : public IBuffer { private: IChunkHandlerType m_handler; public: - virtual ~IBufferChunk() = default; + ~IBufferChunk() override = default; virtual T &getObject() = 0; virtual void setUpdateHandler(IChunkHandlerType handler) { m_handler = handler; }; - virtual void update(const HFrameDependantData &frameDepedantData) { - if (m_handler) { - m_handler(this, frameDepedantData); - } - }; }; #endif //AWEBWOWVIEWERCPP_IBUFFERCHUNK_H diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index 968c1a299..d4f941c46 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -96,7 +96,10 @@ void ISimpleMaterialVLK::updateImageDescriptorSet() { } } -ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, std::string vertexShader, std::string pixelShader, std::vector> &ubos, std::vector &textures) : m_device(device) { +ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, + const std::string &vertexShader, const std::string &pixelShader, + const std::vector> &ubos, + const std::vector &textures) : m_device(device) { m_shader = device->getShader(vertexShader, pixelShader, nullptr); auto shaderVLK = std::dynamic_pointer_cast(m_shader); diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 1b21cf2f6..0091df9ce 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -14,7 +14,8 @@ class ISimpleMaterialVLK : public IMaterial { public: - ISimpleMaterialVLK(const HGDeviceVLK &device, std::string vertexShader, std::string pixelShader, std::vector> &ubos, std::vector> &textures); + explicit ISimpleMaterialVLK(const HGDeviceVLK &device, const std::string &vertexShader, const std::string &pixelShader, + const std::vector> &ubos, const std::vector> &textures); ~ISimpleMaterialVLK() override = default; HGShaderPermutation getShader() { diff --git a/wowViewerLib/src/gapi/vulkan/volk.c b/wowViewerLib/src/gapi/vulkan/volk.c new file mode 100644 index 000000000..8df800a24 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/volk.c @@ -0,0 +1,2435 @@ +/* This file is part of volk library; see volk.h for version/license details */ +/* clang-format off */ +#include "volk.h" + +#ifdef _WIN32 + typedef const char* LPCSTR; + typedef struct HINSTANCE__* HINSTANCE; + typedef HINSTANCE HMODULE; + #ifdef _WIN64 + typedef __int64 (__stdcall* FARPROC)(void); + #else + typedef int (__stdcall* FARPROC)(void); + #endif +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +__declspec(dllimport) HMODULE __stdcall LoadLibraryA(LPCSTR); +__declspec(dllimport) FARPROC __stdcall GetProcAddress(HMODULE, LPCSTR); +#endif + +static VkInstance loadedInstance = VK_NULL_HANDLE; +static VkDevice loadedDevice = VK_NULL_HANDLE; + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)); + +static PFN_vkVoidFunction vkGetInstanceProcAddrStub(void* context, const char* name) +{ + return vkGetInstanceProcAddr((VkInstance)context, name); +} + +static PFN_vkVoidFunction vkGetDeviceProcAddrStub(void* context, const char* name) +{ + return vkGetDeviceProcAddr((VkDevice)context, name); +} + +VkResult volkInitialize(void) +{ +#if defined(_WIN32) + HMODULE module = LoadLibraryA("vulkan-1.dll"); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + // note: function pointer is cast through void function pointer to silence cast-function-type warning on gcc8 + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)(void(*)(void))GetProcAddress(module, "vkGetInstanceProcAddr"); +#elif defined(__APPLE__) + void* module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#else + void* module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#endif + + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); + + return VK_SUCCESS; +} + +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler) +{ + vkGetInstanceProcAddr = handler; + + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); +} + +uint32_t volkGetInstanceVersion(void) +{ +#if defined(VK_VERSION_1_1) + uint32_t apiVersion = 0; + if (vkEnumerateInstanceVersion && vkEnumerateInstanceVersion(&apiVersion) == VK_SUCCESS) + return apiVersion; +#endif + + if (vkCreateInstance) + return VK_API_VERSION_1_0; + + return 0; +} + +void volkLoadInstance(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); + volkGenLoadDevice(instance, vkGetInstanceProcAddrStub); +} + +void volkLoadInstanceOnly(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); +} + +VkInstance volkGetLoadedInstance() +{ + return loadedInstance; +} + +void volkLoadDevice(VkDevice device) +{ + loadedDevice = device; + volkGenLoadDevice(device, vkGetDeviceProcAddrStub); +} + +VkDevice volkGetLoadedDevice() +{ + return loadedDevice; +} + +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device) +{ + volkGenLoadDeviceTable(table, device, vkGetDeviceProcAddrStub); +} + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_LOADER */ +#if defined(VK_VERSION_1_0) + vkCreateInstance = (PFN_vkCreateInstance)load(context, "vkCreateInstance"); + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)load(context, "vkEnumerateInstanceExtensionProperties"); + vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)load(context, "vkEnumerateInstanceLayerProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)load(context, "vkEnumerateInstanceVersion"); +#endif /* defined(VK_VERSION_1_1) */ + /* VOLK_GENERATE_LOAD_LOADER */ +} + +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_INSTANCE */ +#if defined(VK_VERSION_1_0) + vkCreateDevice = (PFN_vkCreateDevice)load(context, "vkCreateDevice"); + vkDestroyInstance = (PFN_vkDestroyInstance)load(context, "vkDestroyInstance"); + vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)load(context, "vkEnumerateDeviceExtensionProperties"); + vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties)load(context, "vkEnumerateDeviceLayerProperties"); + vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)load(context, "vkEnumeratePhysicalDevices"); + vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)load(context, "vkGetDeviceProcAddr"); + vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)load(context, "vkGetPhysicalDeviceFeatures"); + vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)load(context, "vkGetPhysicalDeviceFormatProperties"); + vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)load(context, "vkGetPhysicalDeviceImageFormatProperties"); + vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)load(context, "vkGetPhysicalDeviceMemoryProperties"); + vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)load(context, "vkGetPhysicalDeviceProperties"); + vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)load(context, "vkGetPhysicalDeviceQueueFamilyProperties"); + vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups)load(context, "vkEnumeratePhysicalDeviceGroups"); + vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties)load(context, "vkGetPhysicalDeviceExternalBufferProperties"); + vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties)load(context, "vkGetPhysicalDeviceExternalFenceProperties"); + vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)load(context, "vkGetPhysicalDeviceExternalSemaphoreProperties"); + vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)load(context, "vkGetPhysicalDeviceFeatures2"); + vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2)load(context, "vkGetPhysicalDeviceFormatProperties2"); + vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2)load(context, "vkGetPhysicalDeviceImageFormatProperties2"); + vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)load(context, "vkGetPhysicalDeviceMemoryProperties2"); + vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)load(context, "vkGetPhysicalDeviceProperties2"); + vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2"); + vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_3) + vkGetPhysicalDeviceToolProperties = (PFN_vkGetPhysicalDeviceToolProperties)load(context, "vkGetPhysicalDeviceToolProperties"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_EXT_acquire_drm_display) + vkAcquireDrmDisplayEXT = (PFN_vkAcquireDrmDisplayEXT)load(context, "vkAcquireDrmDisplayEXT"); + vkGetDrmDisplayEXT = (PFN_vkGetDrmDisplayEXT)load(context, "vkGetDrmDisplayEXT"); +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) + vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT)load(context, "vkAcquireXlibDisplayEXT"); + vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT)load(context, "vkGetRandROutputDisplayEXT"); +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)load(context, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_debug_report) + vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)load(context, "vkCreateDebugReportCallbackEXT"); + vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)load(context, "vkDebugReportMessageEXT"); + vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)load(context, "vkDestroyDebugReportCallbackEXT"); +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) + vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)load(context, "vkCmdBeginDebugUtilsLabelEXT"); + vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)load(context, "vkCmdEndDebugUtilsLabelEXT"); + vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)load(context, "vkCmdInsertDebugUtilsLabelEXT"); + vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)load(context, "vkCreateDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)load(context, "vkDestroyDebugUtilsMessengerEXT"); + vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)load(context, "vkQueueBeginDebugUtilsLabelEXT"); + vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)load(context, "vkQueueEndDebugUtilsLabelEXT"); + vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)load(context, "vkQueueInsertDebugUtilsLabelEXT"); + vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)load(context, "vkSetDebugUtilsObjectNameEXT"); + vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)load(context, "vkSetDebugUtilsObjectTagEXT"); + vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT)load(context, "vkSubmitDebugUtilsMessageEXT"); +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) + vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT)load(context, "vkReleaseDisplayEXT"); +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) + vkCreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT)load(context, "vkCreateDirectFBSurfaceEXT"); + vkGetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)load(context, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"); +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_display_surface_counter) + vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"); +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_full_screen_exclusive) + vkGetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)load(context, "vkGetPhysicalDeviceSurfacePresentModes2EXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_headless_surface) + vkCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)load(context, "vkCreateHeadlessSurfaceEXT"); +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_metal_surface) + vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)load(context, "vkCreateMetalSurfaceEXT"); +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_sample_locations) + vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)load(context, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) + vkGetPhysicalDeviceToolPropertiesEXT = (PFN_vkGetPhysicalDeviceToolPropertiesEXT)load(context, "vkGetPhysicalDeviceToolPropertiesEXT"); +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_FUCHSIA_imagepipe_surface) + vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA)load(context, "vkCreateImagePipeSurfaceFUCHSIA"); +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) + vkCreateStreamDescriptorSurfaceGGP = (PFN_vkCreateStreamDescriptorSurfaceGGP)load(context, "vkCreateStreamDescriptorSurfaceGGP"); +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_KHR_android_surface) + vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)load(context, "vkCreateAndroidSurfaceKHR"); +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_device_group_creation) + vkEnumeratePhysicalDeviceGroupsKHR = (PFN_vkEnumeratePhysicalDeviceGroupsKHR)load(context, "vkEnumeratePhysicalDeviceGroupsKHR"); +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) + vkCreateDisplayModeKHR = (PFN_vkCreateDisplayModeKHR)load(context, "vkCreateDisplayModeKHR"); + vkCreateDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)load(context, "vkCreateDisplayPlaneSurfaceKHR"); + vkGetDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)load(context, "vkGetDisplayModePropertiesKHR"); + vkGetDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)load(context, "vkGetDisplayPlaneCapabilitiesKHR"); + vkGetDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)load(context, "vkGetDisplayPlaneSupportedDisplaysKHR"); + vkGetPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"); + vkGetPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPropertiesKHR"); +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_external_fence_capabilities) + vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_memory_capabilities) + vkGetPhysicalDeviceExternalBufferPropertiesKHR = (PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)load(context, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_semaphore_capabilities) + vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"); +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_fragment_shading_rate) + vkGetPhysicalDeviceFragmentShadingRatesKHR = (PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)load(context, "vkGetPhysicalDeviceFragmentShadingRatesKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) + vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR)load(context, "vkGetDisplayModeProperties2KHR"); + vkGetDisplayPlaneCapabilities2KHR = (PFN_vkGetDisplayPlaneCapabilities2KHR)load(context, "vkGetDisplayPlaneCapabilities2KHR"); + vkGetPhysicalDeviceDisplayPlaneProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"); + vkGetPhysicalDeviceDisplayProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayProperties2KHR"); +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_physical_device_properties2) + vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)load(context, "vkGetPhysicalDeviceFeatures2KHR"); + vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)load(context, "vkGetPhysicalDeviceFormatProperties2KHR"); + vkGetPhysicalDeviceImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceImageFormatProperties2KHR"); + vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)load(context, "vkGetPhysicalDeviceMemoryProperties2KHR"); + vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)load(context, "vkGetPhysicalDeviceProperties2KHR"); + vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"); + vkGetPhysicalDeviceSparseImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"); +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) + vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); + vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)load(context, "vkGetPhysicalDeviceSurfaceFormats2KHR"); +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_performance_query) + vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = (PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)load(context, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR"); + vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = (PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)load(context, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_surface) + vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)load(context, "vkDestroySurfaceKHR"); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)load(context, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)load(context, "vkGetPhysicalDeviceSurfacePresentModesKHR"); + vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)load(context, "vkGetPhysicalDeviceSurfaceSupportKHR"); +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_video_queue) + vkGetPhysicalDeviceVideoCapabilitiesKHR = (PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR)load(context, "vkGetPhysicalDeviceVideoCapabilitiesKHR"); + vkGetPhysicalDeviceVideoFormatPropertiesKHR = (PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR)load(context, "vkGetPhysicalDeviceVideoFormatPropertiesKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) + vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)load(context, "vkCreateWaylandSurfaceKHR"); + vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)load(context, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) + vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)load(context, "vkCreateWin32SurfaceKHR"); + vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)load(context, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) + vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)load(context, "vkCreateXcbSurfaceKHR"); + vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)load(context, "vkCreateXlibSurfaceKHR"); + vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) + vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK)load(context, "vkCreateIOSSurfaceMVK"); +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)load(context, "vkCreateMacOSSurfaceMVK"); +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) + vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN)load(context, "vkCreateViSurfaceNN"); +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NV_acquire_winrt_display) + vkAcquireWinrtDisplayNV = (PFN_vkAcquireWinrtDisplayNV)load(context, "vkAcquireWinrtDisplayNV"); + vkGetWinrtDisplayNV = (PFN_vkGetWinrtDisplayNV)load(context, "vkGetWinrtDisplayNV"); +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_cooperative_matrix) + vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)load(context, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) + vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = (PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)load(context, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"); +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_external_memory_capabilities) + vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)load(context, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_QNX_screen_surface) + vkCreateScreenSurfaceQNX = (PFN_vkCreateScreenSurfaceQNX)load(context, "vkCreateScreenSurfaceQNX"); + vkGetPhysicalDeviceScreenPresentationSupportQNX = (PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)load(context, "vkGetPhysicalDeviceScreenPresentationSupportQNX"); +#endif /* defined(VK_QNX_screen_surface) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR)load(context, "vkGetPhysicalDevicePresentRectanglesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_INSTANCE */ +} + +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE */ +#if defined(VK_VERSION_1_0) + vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + vkCmdBeginRendering = (PFN_vkCmdBeginRendering)load(context, "vkCmdBeginRendering"); + vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2)load(context, "vkCmdBindVertexBuffers2"); + vkCmdBlitImage2 = (PFN_vkCmdBlitImage2)load(context, "vkCmdBlitImage2"); + vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2)load(context, "vkCmdCopyBuffer2"); + vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2)load(context, "vkCmdCopyBufferToImage2"); + vkCmdCopyImage2 = (PFN_vkCmdCopyImage2)load(context, "vkCmdCopyImage2"); + vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2)load(context, "vkCmdCopyImageToBuffer2"); + vkCmdEndRendering = (PFN_vkCmdEndRendering)load(context, "vkCmdEndRendering"); + vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2)load(context, "vkCmdPipelineBarrier2"); + vkCmdResetEvent2 = (PFN_vkCmdResetEvent2)load(context, "vkCmdResetEvent2"); + vkCmdResolveImage2 = (PFN_vkCmdResolveImage2)load(context, "vkCmdResolveImage2"); + vkCmdSetCullMode = (PFN_vkCmdSetCullMode)load(context, "vkCmdSetCullMode"); + vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable)load(context, "vkCmdSetDepthBiasEnable"); + vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable)load(context, "vkCmdSetDepthBoundsTestEnable"); + vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp)load(context, "vkCmdSetDepthCompareOp"); + vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable)load(context, "vkCmdSetDepthTestEnable"); + vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable)load(context, "vkCmdSetDepthWriteEnable"); + vkCmdSetEvent2 = (PFN_vkCmdSetEvent2)load(context, "vkCmdSetEvent2"); + vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace)load(context, "vkCmdSetFrontFace"); + vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable)load(context, "vkCmdSetPrimitiveRestartEnable"); + vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology)load(context, "vkCmdSetPrimitiveTopology"); + vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable)load(context, "vkCmdSetRasterizerDiscardEnable"); + vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount)load(context, "vkCmdSetScissorWithCount"); + vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp)load(context, "vkCmdSetStencilOp"); + vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable)load(context, "vkCmdSetStencilTestEnable"); + vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount)load(context, "vkCmdSetViewportWithCount"); + vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2)load(context, "vkCmdWaitEvents2"); + vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2)load(context, "vkCmdWriteTimestamp2"); + vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot)load(context, "vkCreatePrivateDataSlot"); + vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot)load(context, "vkDestroyPrivateDataSlot"); + vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)load(context, "vkGetDeviceBufferMemoryRequirements"); + vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)load(context, "vkGetDeviceImageMemoryRequirements"); + vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements)load(context, "vkGetDeviceImageSparseMemoryRequirements"); + vkGetPrivateData = (PFN_vkGetPrivateData)load(context, "vkGetPrivateData"); + vkQueueSubmit2 = (PFN_vkQueueSubmit2)load(context, "vkQueueSubmit2"); + vkSetPrivateData = (PFN_vkSetPrivateData)load(context, "vkSetPrivateData"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMD_buffer_marker) + vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)load(context, "vkCmdSetColorWriteEnableEXT"); +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_extended_dynamic_state2) + vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT)load(context, "vkCmdSetDepthBiasEnableEXT"); + vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT)load(context, "vkCmdSetLogicOpEXT"); + vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT)load(context, "vkCmdSetPatchControlPointsEXT"); + vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)load(context, "vkCmdSetPrimitiveRestartEnableEXT"); + vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT)load(context, "vkCmdSetRasterizerDiscardEnableEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state2) */ +#if defined(VK_EXT_external_memory_host) + vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_compression_control) + vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT)load(context, "vkGetImageSubresourceLayout2EXT"); +#endif /* defined(VK_EXT_image_compression_control) */ +#if defined(VK_EXT_image_drm_format_modifier) + vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_multi_draw) + vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT)load(context, "vkCmdDrawMultiEXT"); + vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT)load(context, "vkCmdDrawMultiIndexedEXT"); +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_pageable_device_local_memory) + vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT)load(context, "vkSetDeviceMemoryPriorityEXT"); +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT)load(context, "vkGetPipelinePropertiesEXT"); +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_EXT_vertex_input_dynamic_state) + vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT)load(context, "vkCmdSetVertexInputEXT"); +#endif /* defined(VK_EXT_vertex_input_dynamic_state) */ +#if defined(VK_FUCHSIA_buffer_collection) + vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)load(context, "vkCreateBufferCollectionFUCHSIA"); + vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA)load(context, "vkDestroyBufferCollectionFUCHSIA"); + vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA)load(context, "vkGetBufferCollectionPropertiesFUCHSIA"); + vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)load(context, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)load(context, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA)load(context, "vkGetMemoryZirconHandleFUCHSIA"); + vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)load(context, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA)load(context, "vkGetSemaphoreZirconHandleFUCHSIA"); + vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA)load(context, "vkImportSemaphoreZirconHandleFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_invocation_mask) + vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI)load(context, "vkCmdBindInvocationMaskHUAWEI"); +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI)load(context, "vkCmdSubpassShadingHUAWEI"); + vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)load(context, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR)load(context, "vkBuildAccelerationStructuresKHR"); + vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR)load(context, "vkCmdBuildAccelerationStructuresIndirectKHR"); + vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR)load(context, "vkCmdBuildAccelerationStructuresKHR"); + vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR)load(context, "vkGetAccelerationStructureBuildSizesKHR"); + vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR)load(context, "vkCmdBlitImage2KHR"); + vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR)load(context, "vkCmdCopyBuffer2KHR"); + vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR)load(context, "vkCmdCopyBufferToImage2KHR"); + vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR)load(context, "vkCmdCopyImage2KHR"); + vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR)load(context, "vkCmdCopyImageToBuffer2KHR"); + vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR)load(context, "vkCmdResolveImage2KHR"); +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR)load(context, "vkCmdBeginRenderingKHR"); + vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR)load(context, "vkCmdEndRenderingKHR"); +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR)load(context, "vkCmdSetFragmentShadingRateKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR)load(context, "vkGetDeviceBufferMemoryRequirementsKHR"); + vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR)load(context, "vkGetDeviceImageMemoryRequirementsKHR"); + vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)load(context, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_performance_query) + vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR)load(context, "vkWaitForPresentKHR"); +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR)load(context, "vkCmdTraceRaysIndirect2KHR"); +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR)load(context, "vkCmdSetRayTracingPipelineStackSizeKHR"); + vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR)load(context, "vkGetRayTracingShaderGroupStackSizeKHR"); +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)load(context, "vkCmdPipelineBarrier2KHR"); + vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR)load(context, "vkCmdResetEvent2KHR"); + vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR)load(context, "vkCmdSetEvent2KHR"); + vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR)load(context, "vkCmdWaitEvents2KHR"); + vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR)load(context, "vkCmdWriteTimestamp2KHR"); + vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR)load(context, "vkQueueSubmit2KHR"); +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD)load(context, "vkCmdWriteBufferMarker2AMD"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV)load(context, "vkGetQueueCheckpointData2NV"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + vkCmdDecodeVideoKHR = (PFN_vkCmdDecodeVideoKHR)load(context, "vkCmdDecodeVideoKHR"); +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + vkCmdEncodeVideoKHR = (PFN_vkCmdEncodeVideoKHR)load(context, "vkCmdEncodeVideoKHR"); +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + vkBindVideoSessionMemoryKHR = (PFN_vkBindVideoSessionMemoryKHR)load(context, "vkBindVideoSessionMemoryKHR"); + vkCmdBeginVideoCodingKHR = (PFN_vkCmdBeginVideoCodingKHR)load(context, "vkCmdBeginVideoCodingKHR"); + vkCmdControlVideoCodingKHR = (PFN_vkCmdControlVideoCodingKHR)load(context, "vkCmdControlVideoCodingKHR"); + vkCmdEndVideoCodingKHR = (PFN_vkCmdEndVideoCodingKHR)load(context, "vkCmdEndVideoCodingKHR"); + vkCreateVideoSessionKHR = (PFN_vkCreateVideoSessionKHR)load(context, "vkCreateVideoSessionKHR"); + vkCreateVideoSessionParametersKHR = (PFN_vkCreateVideoSessionParametersKHR)load(context, "vkCreateVideoSessionParametersKHR"); + vkDestroyVideoSessionKHR = (PFN_vkDestroyVideoSessionKHR)load(context, "vkDestroyVideoSessionKHR"); + vkDestroyVideoSessionParametersKHR = (PFN_vkDestroyVideoSessionParametersKHR)load(context, "vkDestroyVideoSessionParametersKHR"); + vkGetVideoSessionMemoryRequirementsKHR = (PFN_vkGetVideoSessionMemoryRequirementsKHR)load(context, "vkGetVideoSessionMemoryRequirementsKHR"); + vkUpdateVideoSessionParametersKHR = (PFN_vkUpdateVideoSessionParametersKHR)load(context, "vkUpdateVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX)load(context, "vkCmdCuLaunchKernelNVX"); + vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX)load(context, "vkCreateCuFunctionNVX"); + vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX)load(context, "vkCreateCuModuleNVX"); + vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX)load(context, "vkDestroyCuFunctionNVX"); + vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX)load(context, "vkDestroyCuModuleNVX"); +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_rdma) + vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV)load(context, "vkGetMemoryRemoteAddressNV"); +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV)load(context, "vkCmdSetFragmentShadingRateEnumNV"); +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_mesh_shader) + vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE)load(context, "vkGetDescriptorSetHostMappingVALVE"); + vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)load(context, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE */ +} + +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + table->vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + table->vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + table->vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + table->vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + table->vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + table->vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + table->vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + table->vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + table->vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + table->vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + table->vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + table->vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + table->vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + table->vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + table->vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + table->vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + table->vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + table->vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + table->vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + table->vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + table->vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + table->vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + table->vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + table->vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + table->vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + table->vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + table->vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + table->vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + table->vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + table->vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + table->vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + table->vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + table->vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + table->vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + table->vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + table->vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + table->vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + table->vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + table->vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + table->vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + table->vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + table->vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + table->vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + table->vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + table->vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + table->vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + table->vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + table->vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + table->vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + table->vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + table->vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + table->vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + table->vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + table->vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + table->vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + table->vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + table->vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + table->vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + table->vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + table->vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + table->vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + table->vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + table->vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + table->vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + table->vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + table->vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + table->vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + table->vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + table->vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + table->vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + table->vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + table->vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + table->vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + table->vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + table->vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + table->vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + table->vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + table->vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + table->vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + table->vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + table->vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + table->vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + table->vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + table->vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + table->vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + table->vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + table->vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + table->vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + table->vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + table->vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + table->vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + table->vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + table->vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + table->vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + table->vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + table->vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + table->vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + table->vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + table->vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + table->vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + table->vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + table->vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + table->vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + table->vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + table->vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + table->vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + table->vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + table->vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + table->vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + table->vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + table->vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + table->vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + table->vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + table->vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + table->vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + table->vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + table->vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + table->vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + table->vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + table->vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + table->vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + table->vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + table->vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + table->vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + table->vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + table->vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + table->vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + table->vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + table->vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + table->vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + table->vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + table->vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + table->vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + table->vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + table->vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + table->vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + table->vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + table->vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + table->vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + table->vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + table->vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + table->vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + table->vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + table->vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + table->vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + table->vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + table->vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + table->vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + table->vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + table->vkCmdBeginRendering = (PFN_vkCmdBeginRendering)load(context, "vkCmdBeginRendering"); + table->vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2)load(context, "vkCmdBindVertexBuffers2"); + table->vkCmdBlitImage2 = (PFN_vkCmdBlitImage2)load(context, "vkCmdBlitImage2"); + table->vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2)load(context, "vkCmdCopyBuffer2"); + table->vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2)load(context, "vkCmdCopyBufferToImage2"); + table->vkCmdCopyImage2 = (PFN_vkCmdCopyImage2)load(context, "vkCmdCopyImage2"); + table->vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2)load(context, "vkCmdCopyImageToBuffer2"); + table->vkCmdEndRendering = (PFN_vkCmdEndRendering)load(context, "vkCmdEndRendering"); + table->vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2)load(context, "vkCmdPipelineBarrier2"); + table->vkCmdResetEvent2 = (PFN_vkCmdResetEvent2)load(context, "vkCmdResetEvent2"); + table->vkCmdResolveImage2 = (PFN_vkCmdResolveImage2)load(context, "vkCmdResolveImage2"); + table->vkCmdSetCullMode = (PFN_vkCmdSetCullMode)load(context, "vkCmdSetCullMode"); + table->vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable)load(context, "vkCmdSetDepthBiasEnable"); + table->vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable)load(context, "vkCmdSetDepthBoundsTestEnable"); + table->vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp)load(context, "vkCmdSetDepthCompareOp"); + table->vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable)load(context, "vkCmdSetDepthTestEnable"); + table->vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable)load(context, "vkCmdSetDepthWriteEnable"); + table->vkCmdSetEvent2 = (PFN_vkCmdSetEvent2)load(context, "vkCmdSetEvent2"); + table->vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace)load(context, "vkCmdSetFrontFace"); + table->vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable)load(context, "vkCmdSetPrimitiveRestartEnable"); + table->vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology)load(context, "vkCmdSetPrimitiveTopology"); + table->vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable)load(context, "vkCmdSetRasterizerDiscardEnable"); + table->vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount)load(context, "vkCmdSetScissorWithCount"); + table->vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp)load(context, "vkCmdSetStencilOp"); + table->vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable)load(context, "vkCmdSetStencilTestEnable"); + table->vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount)load(context, "vkCmdSetViewportWithCount"); + table->vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2)load(context, "vkCmdWaitEvents2"); + table->vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2)load(context, "vkCmdWriteTimestamp2"); + table->vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot)load(context, "vkCreatePrivateDataSlot"); + table->vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot)load(context, "vkDestroyPrivateDataSlot"); + table->vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)load(context, "vkGetDeviceBufferMemoryRequirements"); + table->vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)load(context, "vkGetDeviceImageMemoryRequirements"); + table->vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements)load(context, "vkGetDeviceImageSparseMemoryRequirements"); + table->vkGetPrivateData = (PFN_vkGetPrivateData)load(context, "vkGetPrivateData"); + table->vkQueueSubmit2 = (PFN_vkQueueSubmit2)load(context, "vkQueueSubmit2"); + table->vkSetPrivateData = (PFN_vkSetPrivateData)load(context, "vkSetPrivateData"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMD_buffer_marker) + table->vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + table->vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + table->vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + table->vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + table->vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + table->vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + table->vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + table->vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + table->vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)load(context, "vkCmdSetColorWriteEnableEXT"); +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + table->vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + table->vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + table->vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + table->vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + table->vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + table->vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + table->vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + table->vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + table->vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + table->vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + table->vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + table->vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + table->vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + table->vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + table->vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + table->vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + table->vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + table->vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + table->vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + table->vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + table->vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + table->vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + table->vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + table->vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_extended_dynamic_state2) + table->vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT)load(context, "vkCmdSetDepthBiasEnableEXT"); + table->vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT)load(context, "vkCmdSetLogicOpEXT"); + table->vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT)load(context, "vkCmdSetPatchControlPointsEXT"); + table->vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)load(context, "vkCmdSetPrimitiveRestartEnableEXT"); + table->vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT)load(context, "vkCmdSetRasterizerDiscardEnableEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state2) */ +#if defined(VK_EXT_external_memory_host) + table->vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + table->vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + table->vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + table->vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + table->vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_compression_control) + table->vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT)load(context, "vkGetImageSubresourceLayout2EXT"); +#endif /* defined(VK_EXT_image_compression_control) */ +#if defined(VK_EXT_image_drm_format_modifier) + table->vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + table->vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_multi_draw) + table->vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT)load(context, "vkCmdDrawMultiEXT"); + table->vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT)load(context, "vkCmdDrawMultiIndexedEXT"); +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_pageable_device_local_memory) + table->vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT)load(context, "vkSetDeviceMemoryPriorityEXT"); +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + table->vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT)load(context, "vkGetPipelinePropertiesEXT"); +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + table->vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + table->vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + table->vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + table->vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + table->vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + table->vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + table->vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + table->vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + table->vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + table->vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + table->vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + table->vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + table->vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + table->vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + table->vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_EXT_vertex_input_dynamic_state) + table->vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT)load(context, "vkCmdSetVertexInputEXT"); +#endif /* defined(VK_EXT_vertex_input_dynamic_state) */ +#if defined(VK_FUCHSIA_buffer_collection) + table->vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)load(context, "vkCreateBufferCollectionFUCHSIA"); + table->vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA)load(context, "vkDestroyBufferCollectionFUCHSIA"); + table->vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA)load(context, "vkGetBufferCollectionPropertiesFUCHSIA"); + table->vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)load(context, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + table->vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)load(context, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + table->vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA)load(context, "vkGetMemoryZirconHandleFUCHSIA"); + table->vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)load(context, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + table->vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA)load(context, "vkGetSemaphoreZirconHandleFUCHSIA"); + table->vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA)load(context, "vkImportSemaphoreZirconHandleFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + table->vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + table->vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_invocation_mask) + table->vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI)load(context, "vkCmdBindInvocationMaskHUAWEI"); +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + table->vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI)load(context, "vkCmdSubpassShadingHUAWEI"); + table->vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)load(context, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + table->vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + table->vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + table->vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + table->vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + table->vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + table->vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + table->vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + table->vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + table->vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + table->vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR)load(context, "vkBuildAccelerationStructuresKHR"); + table->vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR)load(context, "vkCmdBuildAccelerationStructuresIndirectKHR"); + table->vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR)load(context, "vkCmdBuildAccelerationStructuresKHR"); + table->vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + table->vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + table->vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + table->vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + table->vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + table->vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + table->vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + table->vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + table->vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + table->vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR)load(context, "vkGetAccelerationStructureBuildSizesKHR"); + table->vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + table->vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + table->vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + table->vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + table->vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + table->vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + table->vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + table->vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + table->vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR)load(context, "vkCmdBlitImage2KHR"); + table->vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR)load(context, "vkCmdCopyBuffer2KHR"); + table->vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR)load(context, "vkCmdCopyBufferToImage2KHR"); + table->vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR)load(context, "vkCmdCopyImage2KHR"); + table->vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR)load(context, "vkCmdCopyImageToBuffer2KHR"); + table->vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR)load(context, "vkCmdResolveImage2KHR"); +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + table->vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + table->vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + table->vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + table->vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + table->vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + table->vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + table->vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + table->vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + table->vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + table->vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + table->vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + table->vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + table->vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + table->vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + table->vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + table->vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + table->vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + table->vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR)load(context, "vkCmdBeginRenderingKHR"); + table->vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR)load(context, "vkCmdEndRenderingKHR"); +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + table->vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + table->vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + table->vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + table->vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + table->vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + table->vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + table->vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + table->vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + table->vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + table->vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + table->vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + table->vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + table->vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR)load(context, "vkCmdSetFragmentShadingRateKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + table->vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + table->vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + table->vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + table->vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + table->vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + table->vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR)load(context, "vkGetDeviceBufferMemoryRequirementsKHR"); + table->vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR)load(context, "vkGetDeviceImageMemoryRequirementsKHR"); + table->vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)load(context, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_performance_query) + table->vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + table->vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + table->vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + table->vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + table->vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + table->vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR)load(context, "vkWaitForPresentKHR"); +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + table->vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + table->vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR)load(context, "vkCmdTraceRaysIndirect2KHR"); +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + table->vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR)load(context, "vkCmdSetRayTracingPipelineStackSizeKHR"); + table->vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + table->vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + table->vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + table->vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + table->vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + table->vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR)load(context, "vkGetRayTracingShaderGroupStackSizeKHR"); +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + table->vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + table->vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + table->vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + table->vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + table->vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + table->vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + table->vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + table->vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + table->vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)load(context, "vkCmdPipelineBarrier2KHR"); + table->vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR)load(context, "vkCmdResetEvent2KHR"); + table->vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR)load(context, "vkCmdSetEvent2KHR"); + table->vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR)load(context, "vkCmdWaitEvents2KHR"); + table->vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR)load(context, "vkCmdWriteTimestamp2KHR"); + table->vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR)load(context, "vkQueueSubmit2KHR"); +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + table->vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD)load(context, "vkCmdWriteBufferMarker2AMD"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + table->vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV)load(context, "vkGetQueueCheckpointData2NV"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + table->vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + table->vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + table->vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + table->vkCmdDecodeVideoKHR = (PFN_vkCmdDecodeVideoKHR)load(context, "vkCmdDecodeVideoKHR"); +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + table->vkCmdEncodeVideoKHR = (PFN_vkCmdEncodeVideoKHR)load(context, "vkCmdEncodeVideoKHR"); +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + table->vkBindVideoSessionMemoryKHR = (PFN_vkBindVideoSessionMemoryKHR)load(context, "vkBindVideoSessionMemoryKHR"); + table->vkCmdBeginVideoCodingKHR = (PFN_vkCmdBeginVideoCodingKHR)load(context, "vkCmdBeginVideoCodingKHR"); + table->vkCmdControlVideoCodingKHR = (PFN_vkCmdControlVideoCodingKHR)load(context, "vkCmdControlVideoCodingKHR"); + table->vkCmdEndVideoCodingKHR = (PFN_vkCmdEndVideoCodingKHR)load(context, "vkCmdEndVideoCodingKHR"); + table->vkCreateVideoSessionKHR = (PFN_vkCreateVideoSessionKHR)load(context, "vkCreateVideoSessionKHR"); + table->vkCreateVideoSessionParametersKHR = (PFN_vkCreateVideoSessionParametersKHR)load(context, "vkCreateVideoSessionParametersKHR"); + table->vkDestroyVideoSessionKHR = (PFN_vkDestroyVideoSessionKHR)load(context, "vkDestroyVideoSessionKHR"); + table->vkDestroyVideoSessionParametersKHR = (PFN_vkDestroyVideoSessionParametersKHR)load(context, "vkDestroyVideoSessionParametersKHR"); + table->vkGetVideoSessionMemoryRequirementsKHR = (PFN_vkGetVideoSessionMemoryRequirementsKHR)load(context, "vkGetVideoSessionMemoryRequirementsKHR"); + table->vkUpdateVideoSessionParametersKHR = (PFN_vkUpdateVideoSessionParametersKHR)load(context, "vkUpdateVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + table->vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX)load(context, "vkCmdCuLaunchKernelNVX"); + table->vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX)load(context, "vkCreateCuFunctionNVX"); + table->vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX)load(context, "vkCreateCuModuleNVX"); + table->vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX)load(context, "vkDestroyCuFunctionNVX"); + table->vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX)load(context, "vkDestroyCuModuleNVX"); +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + table->vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + table->vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + table->vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + table->vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + table->vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + table->vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + table->vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + table->vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + table->vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + table->vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + table->vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_rdma) + table->vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV)load(context, "vkGetMemoryRemoteAddressNV"); +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + table->vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + table->vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV)load(context, "vkCmdSetFragmentShadingRateEnumNV"); +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_mesh_shader) + table->vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + table->vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + table->vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + table->vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + table->vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + table->vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + table->vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + table->vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + table->vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + table->vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + table->vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + table->vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + table->vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + table->vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + table->vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + table->vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + table->vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + table->vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + table->vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + table->vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE)load(context, "vkGetDescriptorSetHostMappingVALVE"); + table->vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)load(context, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + table->vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + table->vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +} + +#ifdef __GNUC__ +#ifdef VOLK_DEFAULT_VISIBILITY +# pragma GCC visibility push(default) +#else +# pragma GCC visibility push(hidden) +#endif +#endif + +/* VOLK_GENERATE_PROTOTYPES_C */ +#if defined(VK_VERSION_1_0) +PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +PFN_vkAllocateMemory vkAllocateMemory; +PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +PFN_vkBindBufferMemory vkBindBufferMemory; +PFN_vkBindImageMemory vkBindImageMemory; +PFN_vkCmdBeginQuery vkCmdBeginQuery; +PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +PFN_vkCmdBindPipeline vkCmdBindPipeline; +PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +PFN_vkCmdBlitImage vkCmdBlitImage; +PFN_vkCmdClearAttachments vkCmdClearAttachments; +PFN_vkCmdClearColorImage vkCmdClearColorImage; +PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +PFN_vkCmdCopyImage vkCmdCopyImage; +PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +PFN_vkCmdDispatch vkCmdDispatch; +PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +PFN_vkCmdDraw vkCmdDraw; +PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +PFN_vkCmdEndQuery vkCmdEndQuery; +PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +PFN_vkCmdFillBuffer vkCmdFillBuffer; +PFN_vkCmdNextSubpass vkCmdNextSubpass; +PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +PFN_vkCmdPushConstants vkCmdPushConstants; +PFN_vkCmdResetEvent vkCmdResetEvent; +PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +PFN_vkCmdResolveImage vkCmdResolveImage; +PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +PFN_vkCmdSetEvent vkCmdSetEvent; +PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +PFN_vkCmdSetScissor vkCmdSetScissor; +PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +PFN_vkCmdSetViewport vkCmdSetViewport; +PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +PFN_vkCmdWaitEvents vkCmdWaitEvents; +PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +PFN_vkCreateBuffer vkCreateBuffer; +PFN_vkCreateBufferView vkCreateBufferView; +PFN_vkCreateCommandPool vkCreateCommandPool; +PFN_vkCreateComputePipelines vkCreateComputePipelines; +PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +PFN_vkCreateDevice vkCreateDevice; +PFN_vkCreateEvent vkCreateEvent; +PFN_vkCreateFence vkCreateFence; +PFN_vkCreateFramebuffer vkCreateFramebuffer; +PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +PFN_vkCreateImage vkCreateImage; +PFN_vkCreateImageView vkCreateImageView; +PFN_vkCreateInstance vkCreateInstance; +PFN_vkCreatePipelineCache vkCreatePipelineCache; +PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +PFN_vkCreateQueryPool vkCreateQueryPool; +PFN_vkCreateRenderPass vkCreateRenderPass; +PFN_vkCreateSampler vkCreateSampler; +PFN_vkCreateSemaphore vkCreateSemaphore; +PFN_vkCreateShaderModule vkCreateShaderModule; +PFN_vkDestroyBuffer vkDestroyBuffer; +PFN_vkDestroyBufferView vkDestroyBufferView; +PFN_vkDestroyCommandPool vkDestroyCommandPool; +PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +PFN_vkDestroyDevice vkDestroyDevice; +PFN_vkDestroyEvent vkDestroyEvent; +PFN_vkDestroyFence vkDestroyFence; +PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +PFN_vkDestroyImage vkDestroyImage; +PFN_vkDestroyImageView vkDestroyImageView; +PFN_vkDestroyInstance vkDestroyInstance; +PFN_vkDestroyPipeline vkDestroyPipeline; +PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +PFN_vkDestroyQueryPool vkDestroyQueryPool; +PFN_vkDestroyRenderPass vkDestroyRenderPass; +PFN_vkDestroySampler vkDestroySampler; +PFN_vkDestroySemaphore vkDestroySemaphore; +PFN_vkDestroyShaderModule vkDestroyShaderModule; +PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +PFN_vkEndCommandBuffer vkEndCommandBuffer; +PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +PFN_vkFreeMemory vkFreeMemory; +PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +PFN_vkGetDeviceQueue vkGetDeviceQueue; +PFN_vkGetEventStatus vkGetEventStatus; +PFN_vkGetFenceStatus vkGetFenceStatus; +PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +PFN_vkMapMemory vkMapMemory; +PFN_vkMergePipelineCaches vkMergePipelineCaches; +PFN_vkQueueBindSparse vkQueueBindSparse; +PFN_vkQueueSubmit vkQueueSubmit; +PFN_vkQueueWaitIdle vkQueueWaitIdle; +PFN_vkResetCommandBuffer vkResetCommandBuffer; +PFN_vkResetCommandPool vkResetCommandPool; +PFN_vkResetDescriptorPool vkResetDescriptorPool; +PFN_vkResetEvent vkResetEvent; +PFN_vkResetFences vkResetFences; +PFN_vkSetEvent vkSetEvent; +PFN_vkUnmapMemory vkUnmapMemory; +PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +PFN_vkBindBufferMemory2 vkBindBufferMemory2; +PFN_vkBindImageMemory2 vkBindImageMemory2; +PFN_vkCmdDispatchBase vkCmdDispatchBase; +PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +PFN_vkTrimCommandPool vkTrimCommandPool; +PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +PFN_vkCreateRenderPass2 vkCreateRenderPass2; +PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +PFN_vkResetQueryPool vkResetQueryPool; +PFN_vkSignalSemaphore vkSignalSemaphore; +PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) +PFN_vkCmdBeginRendering vkCmdBeginRendering; +PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; +PFN_vkCmdBlitImage2 vkCmdBlitImage2; +PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; +PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; +PFN_vkCmdCopyImage2 vkCmdCopyImage2; +PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; +PFN_vkCmdEndRendering vkCmdEndRendering; +PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; +PFN_vkCmdResetEvent2 vkCmdResetEvent2; +PFN_vkCmdResolveImage2 vkCmdResolveImage2; +PFN_vkCmdSetCullMode vkCmdSetCullMode; +PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; +PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; +PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; +PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; +PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; +PFN_vkCmdSetEvent2 vkCmdSetEvent2; +PFN_vkCmdSetFrontFace vkCmdSetFrontFace; +PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; +PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; +PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; +PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; +PFN_vkCmdSetStencilOp vkCmdSetStencilOp; +PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; +PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; +PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; +PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; +PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; +PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; +PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; +PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; +PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; +PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties; +PFN_vkGetPrivateData vkGetPrivateData; +PFN_vkQueueSubmit2 vkQueueSubmit2; +PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMD_buffer_marker) +PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_drm_display) +PFN_vkAcquireDrmDisplayEXT vkAcquireDrmDisplayEXT; +PFN_vkGetDrmDisplayEXT vkGetDrmDisplayEXT; +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) +PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_buffer_device_address) +PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) +PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) +PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) +PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) +PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_extended_dynamic_state) +PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_extended_dynamic_state2) +PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; +PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; +PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; +PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; +PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* defined(VK_EXT_extended_dynamic_state2) */ +#if defined(VK_EXT_external_memory_host) +PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_query_reset) +PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_compression_control) +PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* defined(VK_EXT_image_compression_control) */ +#if defined(VK_EXT_image_drm_format_modifier) +PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_metal_surface) +PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_multi_draw) +PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; +PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_pageable_device_local_memory) +PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) +PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) +PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) +PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_EXT_vertex_input_dynamic_state) +PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* defined(VK_EXT_vertex_input_dynamic_state) */ +#if defined(VK_FUCHSIA_buffer_collection) +PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; +PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; +PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; +PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; +PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) +PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; +PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) +PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; +PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_invocation_mask) +PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) +PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; +PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) +PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) +PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; +PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; +PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; +PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; +PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_android_surface) +PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) +PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; +PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; +PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; +PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; +PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; +PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) +PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) +PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; +PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_capabilities) +PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) +PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) +PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) +PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; +PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; +PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_performance_query) +PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) +PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) +PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) +PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) +PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; +PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) +PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; +PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; +PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; +PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; +PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; +PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) +PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) +PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) +PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) +PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) +PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) +PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; +PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; +PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; +PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; +PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; +PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; +PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; +PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; +PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR vkGetPhysicalDeviceVideoCapabilitiesKHR; +PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR vkGetPhysicalDeviceVideoFormatPropertiesKHR; +PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; +PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) +PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_binary_import) +PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; +PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; +PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; +PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; +PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) +PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_acquire_winrt_display) +PFN_vkAcquireWinrtDisplayNV vkAcquireWinrtDisplayNV; +PFN_vkGetWinrtDisplayNV vkGetWinrtDisplayNV; +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_clip_space_w_scaling) +PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) +PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_rdma) +PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) +PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) +PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_mesh_shader) +PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) +PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +PFN_vkCompileDeferredNV vkCompileDeferredNV; +PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) +PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QNX_screen_surface) +PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX; +PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX; +#endif /* defined(VK_QNX_screen_surface) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) +PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; +PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_C */ + +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} +#endif +/* clang-format on */ diff --git a/wowViewerLib/src/gapi/vulkan/volk.h b/wowViewerLib/src/gapi/vulkan/volk.h new file mode 100644 index 000000000..1befa16f5 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/volk.h @@ -0,0 +1,1604 @@ +/** + * volk + * + * Copyright (C) 2018-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at https://github.com/zeux/volk + * + * This library is distributed under the MIT License. See notice at the end of this file. + */ +/* clang-format off */ +#ifndef VOLK_H_ +#define VOLK_H_ + +#if defined(VULKAN_H_) && !defined(VK_NO_PROTOTYPES) +# error To use volk, you need to define VK_NO_PROTOTYPES before including vulkan.h +#endif + +/* VOLK_GENERATE_VERSION_DEFINE */ +#define VOLK_HEADER_VERSION 215 +/* VOLK_GENERATE_VERSION_DEFINE */ + +#ifndef VK_NO_PROTOTYPES +# define VK_NO_PROTOTYPES +#endif + +#ifndef VULKAN_H_ +# ifdef VOLK_VULKAN_H_PATH +# include VOLK_VULKAN_H_PATH +# elif defined(VK_USE_PLATFORM_WIN32_KHR) +# include +# include + + /* When VK_USE_PLATFORM_WIN32_KHR is defined, instead of including vulkan.h directly, we include individual parts of the SDK + * This is necessary to avoid including which is very heavy - it takes 200ms to parse without WIN32_LEAN_AND_MEAN + * and 100ms to parse with it. vulkan_win32.h only needs a few symbols that are easy to redefine ourselves. + */ + typedef unsigned long DWORD; + typedef const wchar_t* LPCWSTR; + typedef void* HANDLE; + typedef struct HINSTANCE__* HINSTANCE; + typedef struct HWND__* HWND; + typedef struct HMONITOR__* HMONITOR; + typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES; + +# include + +# ifdef VK_ENABLE_BETA_EXTENSIONS +# include +# endif +# else +# include +# endif +#endif + +/* Disable several extensions on earlier SDKs because later SDKs introduce a backwards incompatible change to function signatures */ +#if VK_HEADER_VERSION < 140 +# undef VK_NVX_image_view_handle +#endif +#if VK_HEADER_VERSION < 184 +# undef VK_HUAWEI_subpass_shading +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct VolkDeviceTable; + +/** + * Initialize library by loading Vulkan loader; call this function before creating the Vulkan instance. + * + * Returns VK_SUCCESS on success and VK_ERROR_INITIALIZATION_FAILED otherwise. + */ +VkResult volkInitialize(void); + +/** + * Initialize library by providing a custom handler to load global symbols. + * + * This function can be used instead of volkInitialize. + * The handler function pointer will be asked to load global Vulkan symbols which require no instance + * (such as vkCreateInstance, vkEnumerateInstance* and vkEnumerateInstanceVersion if available). + */ +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler); + +/** + * Get Vulkan instance version supported by the Vulkan loader, or 0 if Vulkan isn't supported + * + * Returns 0 if volkInitialize wasn't called or failed. + */ +uint32_t volkGetInstanceVersion(void); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + */ +void volkLoadInstance(VkInstance instance); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + * Skips loading device-based function pointers, requires usage of volkLoadDevice afterwards. + */ +void volkLoadInstanceOnly(VkInstance instance); + +/** + * Load global function pointers using application-created VkDevice; call this function after creating the Vulkan device. + * + * Note: this is not suitable for applications that want to use multiple VkDevice objects concurrently. + */ +void volkLoadDevice(VkDevice device); + +/** + * Return last VkInstance for which global function pointers have been loaded via volkLoadInstance(), + * or VK_NULL_HANDLE if volkLoadInstance() has not been called. + */ +VkInstance volkGetLoadedInstance(void); + +/** + * Return last VkDevice for which global function pointers have been loaded via volkLoadDevice(), + * or VK_NULL_HANDLE if volkLoadDevice() has not been called. + */ +VkDevice volkGetLoadedDevice(void); + +/** + * Load function pointers using application-created VkDevice into a table. + * Application should use function pointers from that table instead of using global function pointers. + */ +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device); + +/** + * Device-specific function pointer table + */ +struct VolkDeviceTable +{ + /* VOLK_GENERATE_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkBindImageMemory vkBindImageMemory; + PFN_vkCmdBeginQuery vkCmdBeginQuery; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; + PFN_vkCmdBindPipeline vkCmdBindPipeline; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; + PFN_vkCmdBlitImage vkCmdBlitImage; + PFN_vkCmdClearAttachments vkCmdClearAttachments; + PFN_vkCmdClearColorImage vkCmdClearColorImage; + PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; + PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdCopyImage vkCmdCopyImage; + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; + PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; + PFN_vkCmdDispatch vkCmdDispatch; + PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; + PFN_vkCmdDraw vkCmdDraw; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed; + PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; + PFN_vkCmdDrawIndirect vkCmdDrawIndirect; + PFN_vkCmdEndQuery vkCmdEndQuery; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkCmdExecuteCommands vkCmdExecuteCommands; + PFN_vkCmdFillBuffer vkCmdFillBuffer; + PFN_vkCmdNextSubpass vkCmdNextSubpass; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCmdPushConstants vkCmdPushConstants; + PFN_vkCmdResetEvent vkCmdResetEvent; + PFN_vkCmdResetQueryPool vkCmdResetQueryPool; + PFN_vkCmdResolveImage vkCmdResolveImage; + PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; + PFN_vkCmdSetDepthBias vkCmdSetDepthBias; + PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; + PFN_vkCmdSetEvent vkCmdSetEvent; + PFN_vkCmdSetLineWidth vkCmdSetLineWidth; + PFN_vkCmdSetScissor vkCmdSetScissor; + PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; + PFN_vkCmdSetStencilReference vkCmdSetStencilReference; + PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; + PFN_vkCmdSetViewport vkCmdSetViewport; + PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; + PFN_vkCmdWaitEvents vkCmdWaitEvents; + PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkCreateBufferView vkCreateBufferView; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkCreateComputePipelines vkCreateComputePipelines; + PFN_vkCreateDescriptorPool vkCreateDescriptorPool; + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; + PFN_vkCreateEvent vkCreateEvent; + PFN_vkCreateFence vkCreateFence; + PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; + PFN_vkCreateImage vkCreateImage; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreatePipelineCache vkCreatePipelineCache; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout; + PFN_vkCreateQueryPool vkCreateQueryPool; + PFN_vkCreateRenderPass vkCreateRenderPass; + PFN_vkCreateSampler vkCreateSampler; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateShaderModule vkCreateShaderModule; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkDestroyBufferView vkDestroyBufferView; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDestroyEvent vkDestroyEvent; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer; + PFN_vkDestroyImage vkDestroyImage; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyPipeline vkDestroyPipeline; + PFN_vkDestroyPipelineCache vkDestroyPipelineCache; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; + PFN_vkDestroyQueryPool vkDestroyQueryPool; + PFN_vkDestroyRenderPass vkDestroyRenderPass; + PFN_vkDestroySampler vkDestroySampler; + PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroyShaderModule vkDestroyShaderModule; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkFreeDescriptorSets vkFreeDescriptorSets; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkGetEventStatus vkGetEventStatus; + PFN_vkGetFenceStatus vkGetFenceStatus; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; + PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; + PFN_vkGetPipelineCacheData vkGetPipelineCacheData; + PFN_vkGetQueryPoolResults vkGetQueryPoolResults; + PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; + PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + PFN_vkMapMemory vkMapMemory; + PFN_vkMergePipelineCaches vkMergePipelineCaches; + PFN_vkQueueBindSparse vkQueueBindSparse; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueueWaitIdle vkQueueWaitIdle; + PFN_vkResetCommandBuffer vkResetCommandBuffer; + PFN_vkResetCommandPool vkResetCommandPool; + PFN_vkResetDescriptorPool vkResetDescriptorPool; + PFN_vkResetEvent vkResetEvent; + PFN_vkResetFences vkResetFences; + PFN_vkSetEvent vkSetEvent; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; + PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + PFN_vkBindBufferMemory2 vkBindBufferMemory2; + PFN_vkBindImageMemory2 vkBindImageMemory2; + PFN_vkCmdDispatchBase vkCmdDispatchBase; + PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; + PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; + PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; + PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; + PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; + PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; + PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; + PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; + PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; + PFN_vkTrimCommandPool vkTrimCommandPool; + PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; + PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; + PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; + PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; + PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; + PFN_vkCreateRenderPass2 vkCreateRenderPass2; + PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; + PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; + PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; + PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; + PFN_vkResetQueryPool vkResetQueryPool; + PFN_vkSignalSemaphore vkSignalSemaphore; + PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + PFN_vkCmdBeginRendering vkCmdBeginRendering; + PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; + PFN_vkCmdBlitImage2 vkCmdBlitImage2; + PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; + PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; + PFN_vkCmdCopyImage2 vkCmdCopyImage2; + PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; + PFN_vkCmdEndRendering vkCmdEndRendering; + PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; + PFN_vkCmdResetEvent2 vkCmdResetEvent2; + PFN_vkCmdResolveImage2 vkCmdResolveImage2; + PFN_vkCmdSetCullMode vkCmdSetCullMode; + PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; + PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; + PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; + PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; + PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; + PFN_vkCmdSetEvent2 vkCmdSetEvent2; + PFN_vkCmdSetFrontFace vkCmdSetFrontFace; + PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; + PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; + PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; + PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; + PFN_vkCmdSetStencilOp vkCmdSetStencilOp; + PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; + PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; + PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; + PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; + PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; + PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; + PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; + PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; + PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; + PFN_vkGetPrivateData vkGetPrivateData; + PFN_vkQueueSubmit2 vkQueueSubmit2; + PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMD_buffer_marker) + PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; + PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; + PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; + PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; + PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; + PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; + PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; + PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; + PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; + PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_extended_dynamic_state2) + PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; + PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; + PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; + PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; + PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* defined(VK_EXT_extended_dynamic_state2) */ +#if defined(VK_EXT_external_memory_host) + PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; + PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_compression_control) + PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* defined(VK_EXT_image_compression_control) */ +#if defined(VK_EXT_image_drm_format_modifier) + PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_multi_draw) + PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; + PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_pageable_device_local_memory) + PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; + PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; + PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; + PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; + PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; + PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; + PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; + PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; + PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; + PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; + PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; + PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_EXT_vertex_input_dynamic_state) + PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* defined(VK_EXT_vertex_input_dynamic_state) */ +#if defined(VK_FUCHSIA_buffer_collection) + PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; + PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; + PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; + PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; + PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; + PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; + PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; + PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_invocation_mask) + PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; + PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; + PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; + PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; + PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; + PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; + PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; + PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; + PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; + PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; + PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; + PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; + PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; + PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; + PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; + PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; + PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; + PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; + PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; + PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; + PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; + PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; + PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; + PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; + PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; + PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; + PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; + PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; + PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; + PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; + PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; + PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; + PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; + PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + PFN_vkGetFenceFdKHR vkGetFenceFdKHR; + PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; + PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; + PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; + PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; + PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; + PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; + PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; + PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_performance_query) + PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; + PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; + PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; + PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; + PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; + PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; + PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; + PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; + PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; + PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; + PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; + PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; + PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; + PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; + PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; + PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; + PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; + PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; + PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; + PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; + PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; + PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; + PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; + PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; + PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; + PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; + PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; + PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; + PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; + PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; + PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; + PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; + PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; + PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; + PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; + PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; + PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_rdma) + PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_mesh_shader) + PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; + PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; + PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; + PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; + PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; + PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; + PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; + PFN_vkCompileDeferredNV vkCompileDeferredNV; + PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; + PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; + PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; + PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; + PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; + PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; + PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; + PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; + PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; + PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_DEVICE_TABLE */ +}; + +/* VOLK_GENERATE_PROTOTYPES_H */ +#if defined(VK_VERSION_1_0) +extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +extern PFN_vkAllocateMemory vkAllocateMemory; +extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +extern PFN_vkBindBufferMemory vkBindBufferMemory; +extern PFN_vkBindImageMemory vkBindImageMemory; +extern PFN_vkCmdBeginQuery vkCmdBeginQuery; +extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +extern PFN_vkCmdBindPipeline vkCmdBindPipeline; +extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +extern PFN_vkCmdBlitImage vkCmdBlitImage; +extern PFN_vkCmdClearAttachments vkCmdClearAttachments; +extern PFN_vkCmdClearColorImage vkCmdClearColorImage; +extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +extern PFN_vkCmdCopyImage vkCmdCopyImage; +extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +extern PFN_vkCmdDispatch vkCmdDispatch; +extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +extern PFN_vkCmdDraw vkCmdDraw; +extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +extern PFN_vkCmdEndQuery vkCmdEndQuery; +extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +extern PFN_vkCmdFillBuffer vkCmdFillBuffer; +extern PFN_vkCmdNextSubpass vkCmdNextSubpass; +extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +extern PFN_vkCmdPushConstants vkCmdPushConstants; +extern PFN_vkCmdResetEvent vkCmdResetEvent; +extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +extern PFN_vkCmdResolveImage vkCmdResolveImage; +extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +extern PFN_vkCmdSetEvent vkCmdSetEvent; +extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +extern PFN_vkCmdSetScissor vkCmdSetScissor; +extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +extern PFN_vkCmdSetViewport vkCmdSetViewport; +extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +extern PFN_vkCmdWaitEvents vkCmdWaitEvents; +extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +extern PFN_vkCreateBuffer vkCreateBuffer; +extern PFN_vkCreateBufferView vkCreateBufferView; +extern PFN_vkCreateCommandPool vkCreateCommandPool; +extern PFN_vkCreateComputePipelines vkCreateComputePipelines; +extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +extern PFN_vkCreateDevice vkCreateDevice; +extern PFN_vkCreateEvent vkCreateEvent; +extern PFN_vkCreateFence vkCreateFence; +extern PFN_vkCreateFramebuffer vkCreateFramebuffer; +extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +extern PFN_vkCreateImage vkCreateImage; +extern PFN_vkCreateImageView vkCreateImageView; +extern PFN_vkCreateInstance vkCreateInstance; +extern PFN_vkCreatePipelineCache vkCreatePipelineCache; +extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +extern PFN_vkCreateQueryPool vkCreateQueryPool; +extern PFN_vkCreateRenderPass vkCreateRenderPass; +extern PFN_vkCreateSampler vkCreateSampler; +extern PFN_vkCreateSemaphore vkCreateSemaphore; +extern PFN_vkCreateShaderModule vkCreateShaderModule; +extern PFN_vkDestroyBuffer vkDestroyBuffer; +extern PFN_vkDestroyBufferView vkDestroyBufferView; +extern PFN_vkDestroyCommandPool vkDestroyCommandPool; +extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +extern PFN_vkDestroyDevice vkDestroyDevice; +extern PFN_vkDestroyEvent vkDestroyEvent; +extern PFN_vkDestroyFence vkDestroyFence; +extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +extern PFN_vkDestroyImage vkDestroyImage; +extern PFN_vkDestroyImageView vkDestroyImageView; +extern PFN_vkDestroyInstance vkDestroyInstance; +extern PFN_vkDestroyPipeline vkDestroyPipeline; +extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +extern PFN_vkDestroyQueryPool vkDestroyQueryPool; +extern PFN_vkDestroyRenderPass vkDestroyRenderPass; +extern PFN_vkDestroySampler vkDestroySampler; +extern PFN_vkDestroySemaphore vkDestroySemaphore; +extern PFN_vkDestroyShaderModule vkDestroyShaderModule; +extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +extern PFN_vkEndCommandBuffer vkEndCommandBuffer; +extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +extern PFN_vkFreeMemory vkFreeMemory; +extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +extern PFN_vkGetDeviceQueue vkGetDeviceQueue; +extern PFN_vkGetEventStatus vkGetEventStatus; +extern PFN_vkGetFenceStatus vkGetFenceStatus; +extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +extern PFN_vkMapMemory vkMapMemory; +extern PFN_vkMergePipelineCaches vkMergePipelineCaches; +extern PFN_vkQueueBindSparse vkQueueBindSparse; +extern PFN_vkQueueSubmit vkQueueSubmit; +extern PFN_vkQueueWaitIdle vkQueueWaitIdle; +extern PFN_vkResetCommandBuffer vkResetCommandBuffer; +extern PFN_vkResetCommandPool vkResetCommandPool; +extern PFN_vkResetDescriptorPool vkResetDescriptorPool; +extern PFN_vkResetEvent vkResetEvent; +extern PFN_vkResetFences vkResetFences; +extern PFN_vkSetEvent vkSetEvent; +extern PFN_vkUnmapMemory vkUnmapMemory; +extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +extern PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; +extern PFN_vkBindImageMemory2 vkBindImageMemory2; +extern PFN_vkCmdDispatchBase vkCmdDispatchBase; +extern PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +extern PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +extern PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +extern PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +extern PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +extern PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +extern PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +extern PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +extern PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +extern PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +extern PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +extern PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +extern PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +extern PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +extern PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +extern PFN_vkTrimCommandPool vkTrimCommandPool; +extern PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +extern PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +extern PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +extern PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +extern PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +extern PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +extern PFN_vkCreateRenderPass2 vkCreateRenderPass2; +extern PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +extern PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +extern PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +extern PFN_vkResetQueryPool vkResetQueryPool; +extern PFN_vkSignalSemaphore vkSignalSemaphore; +extern PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) +extern PFN_vkCmdBeginRendering vkCmdBeginRendering; +extern PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; +extern PFN_vkCmdBlitImage2 vkCmdBlitImage2; +extern PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; +extern PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; +extern PFN_vkCmdCopyImage2 vkCmdCopyImage2; +extern PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; +extern PFN_vkCmdEndRendering vkCmdEndRendering; +extern PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; +extern PFN_vkCmdResetEvent2 vkCmdResetEvent2; +extern PFN_vkCmdResolveImage2 vkCmdResolveImage2; +extern PFN_vkCmdSetCullMode vkCmdSetCullMode; +extern PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; +extern PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; +extern PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; +extern PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; +extern PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; +extern PFN_vkCmdSetEvent2 vkCmdSetEvent2; +extern PFN_vkCmdSetFrontFace vkCmdSetFrontFace; +extern PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; +extern PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; +extern PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; +extern PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; +extern PFN_vkCmdSetStencilOp vkCmdSetStencilOp; +extern PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; +extern PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; +extern PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; +extern PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; +extern PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; +extern PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; +extern PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; +extern PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; +extern PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; +extern PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties; +extern PFN_vkGetPrivateData vkGetPrivateData; +extern PFN_vkQueueSubmit2 vkQueueSubmit2; +extern PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMD_buffer_marker) +extern PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +extern PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +extern PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +extern PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_drm_display) +extern PFN_vkAcquireDrmDisplayEXT vkAcquireDrmDisplayEXT; +extern PFN_vkGetDrmDisplayEXT vkGetDrmDisplayEXT; +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) +extern PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +extern PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +extern PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +extern PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) +extern PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) +extern PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +extern PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +extern PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +extern PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +extern PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +extern PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +extern PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +extern PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +extern PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +extern PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) +extern PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +extern PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +extern PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +extern PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) +extern PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +extern PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +extern PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +extern PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_extended_dynamic_state) +extern PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +extern PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +extern PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +extern PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +extern PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +extern PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +extern PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +extern PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +extern PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +extern PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +extern PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +extern PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_extended_dynamic_state2) +extern PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; +extern PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; +extern PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; +extern PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; +extern PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* defined(VK_EXT_extended_dynamic_state2) */ +#if defined(VK_EXT_external_memory_host) +extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +extern PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +extern PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +extern PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +extern PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +extern PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_query_reset) +extern PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_compression_control) +extern PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* defined(VK_EXT_image_compression_control) */ +#if defined(VK_EXT_image_drm_format_modifier) +extern PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +extern PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_metal_surface) +extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_multi_draw) +extern PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; +extern PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_pageable_device_local_memory) +extern PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) +extern PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) +extern PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +extern PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +extern PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +extern PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +extern PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +extern PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) +extern PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +extern PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +extern PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +extern PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +extern PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +extern PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +extern PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +extern PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +extern PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +extern PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +extern PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_EXT_vertex_input_dynamic_state) +extern PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* defined(VK_EXT_vertex_input_dynamic_state) */ +#if defined(VK_FUCHSIA_buffer_collection) +extern PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; +extern PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; +extern PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; +extern PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; +extern PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) +extern PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; +extern PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) +extern PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; +extern PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +extern PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_invocation_mask) +extern PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) +extern PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; +extern PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) +extern PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +extern PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +extern PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +extern PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +extern PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +extern PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +extern PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +extern PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +extern PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) +extern PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; +extern PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; +extern PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; +extern PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +extern PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +extern PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +extern PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +extern PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +extern PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; +extern PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +extern PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +extern PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_android_surface) +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +extern PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +extern PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +extern PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) +extern PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; +extern PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; +extern PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; +extern PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; +extern PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; +extern PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) +extern PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +extern PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +extern PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +extern PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +extern PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +extern PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +extern PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +extern PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +extern PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +extern PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +extern PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +extern PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +extern PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +extern PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +extern PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +extern PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) +extern PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; +extern PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_capabilities) +extern PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +extern PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +extern PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +extern PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +extern PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +extern PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +extern PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +extern PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +extern PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +extern PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +extern PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) +extern PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +extern PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) +extern PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +extern PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +extern PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +extern PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +extern PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +extern PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) +extern PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; +extern PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; +extern PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_performance_query) +extern PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +extern PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +extern PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +extern PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +extern PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +extern PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) +extern PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) +extern PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) +extern PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) +extern PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; +extern PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +extern PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +extern PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +extern PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +extern PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +extern PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +extern PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +extern PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) +extern PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; +extern PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; +extern PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; +extern PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; +extern PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; +extern PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) +extern PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) +extern PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) +extern PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +extern PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +extern PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) +extern PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) +extern PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) +extern PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; +extern PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; +extern PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; +extern PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; +extern PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; +extern PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; +extern PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; +extern PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; +extern PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR vkGetPhysicalDeviceVideoCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR vkGetPhysicalDeviceVideoFormatPropertiesKHR; +extern PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; +extern PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) +extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +extern PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +extern PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +extern PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_binary_import) +extern PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; +extern PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; +extern PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; +extern PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; +extern PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) +extern PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +extern PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_acquire_winrt_display) +extern PFN_vkAcquireWinrtDisplayNV vkAcquireWinrtDisplayNV; +extern PFN_vkGetWinrtDisplayNV vkGetWinrtDisplayNV; +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_clip_space_w_scaling) +extern PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) +extern PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +extern PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +extern PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +extern PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +extern PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +extern PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +extern PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +extern PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +extern PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_rdma) +extern PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) +extern PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_mesh_shader) +extern PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +extern PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +extern PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) +extern PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +extern PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +extern PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +extern PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +extern PFN_vkCompileDeferredNV vkCompileDeferredNV; +extern PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +extern PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +extern PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +extern PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +extern PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +extern PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) +extern PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +extern PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +extern PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +extern PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QNX_screen_surface) +extern PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX; +extern PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX; +#endif /* defined(VK_QNX_screen_surface) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) +extern PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; +extern PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +extern PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +extern PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_H */ + +#ifdef __cplusplus +} +#endif + +#endif + +#ifdef VOLK_IMPLEMENTATION +#undef VOLK_IMPLEMENTATION +// Prevent tools like dependency checkers that don't evaluate +// macros from detecting a cyclic dependency. +#define VOLK_SOURCE "volk.c" +#include VOLK_SOURCE +#endif + +/** + * Copyright (c) 2018-2019 Arseny Kapoulkine + * + * 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. +*/ +/* clang-format on */ From 7bcb78300411e9a47b0f9f363d0ebe4680b6e280 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 28 Jan 2023 20:48:51 +0200 Subject: [PATCH 018/212] commit --- .../src/engine/shader/ShaderDefinitions.h | 77 ++++++++--------- wowViewerLib/src/gapi/interface/IDevice.h | 5 +- wowViewerLib/src/gapi/interface/IDeviceUI.h | 21 ----- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp | 8 +- wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h | 2 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp | 8 +- wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h | 4 +- wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp | 6 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 63 +++++++------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 12 +-- .../vulkan/materials/ISimpleMaterialVLK.cpp | 2 +- .../src/renderer/frame/SceneComposer.cpp | 84 +++++++++++++------ .../src/renderer/frame/SceneComposer.h | 19 ++--- .../src/renderer/frame/SceneScenario.h | 8 +- 14 files changed, 167 insertions(+), 152 deletions(-) delete mode 100644 wowViewerLib/src/gapi/interface/IDeviceUI.h diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 4ce0cff1b..a355228cd 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -282,8 +282,8 @@ const std::unordered_map> attributesPe }, }; -const std::unordered_map shaderMetaInfo = { -{ "wmoShader.vert.spv", +const std::unordered_map shaderMetaInfo = { +{ "wmoShader.vert.spv", { { {0,1,64}, @@ -318,7 +318,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "wmoShader.frag.spv", { { {0,4,32}, @@ -362,7 +362,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "waterShader.frag.spv", { { {0,4,16}, @@ -397,7 +397,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "waterfallShader.frag.spv", { { {0,4,96}, @@ -435,7 +435,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.vert.spv", { { {0,0,368}, @@ -468,7 +468,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "adtLodShader.vert.spv", { { {0,0,144}, @@ -501,7 +501,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "waterfallShader.vert.spv", { { {0,2,144}, @@ -537,7 +537,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "drawPoints.vert.spv", { { {0,0,128}, @@ -571,7 +571,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawFrustumShader.vert.spv", { { {0,0,128}, @@ -604,7 +604,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "ffxglow.frag.spv", { { {0,4,16}, @@ -639,7 +639,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.frag.spv", { { {0,4,288}, @@ -683,7 +683,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawBBShader.vert.spv", { { {0,1,112}, @@ -717,7 +717,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawFrustumShader.frag.spv", { { }, @@ -749,7 +749,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawDepthShader.frag.spv", { { {0,2,12}, @@ -783,7 +783,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "adtLodShader.frag.spv", { { {0,0,84}, @@ -816,7 +816,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPoints.frag.spv", { { {0,1,12}, @@ -849,7 +849,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawBBShader.frag.spv", { { {0,1,112}, @@ -882,7 +882,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawLinesShader.frag.spv", { { }, @@ -914,7 +914,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "skyConus.frag.spv", { { }, @@ -946,7 +946,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPortalShader.frag.spv", { { {0,4,16}, @@ -979,7 +979,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawLinesShader.vert.spv", { { {0,0,128}, @@ -1012,7 +1012,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "ffxgauss4.frag.spv", { { {0,4,32}, @@ -1046,7 +1046,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.frag.spv", +{ "imguiShader.frag.spv", { { }, @@ -1079,7 +1079,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2ParticleShader.vert.spv", { { {0,0,368}, @@ -1112,7 +1112,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawQuad.vert.spv", { { {0,2,16}, @@ -1145,7 +1145,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "imguiShader.vert.spv", { { {0,1,80}, @@ -1178,7 +1178,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2Shader.frag.spv", { { {0,4,64}, @@ -1218,7 +1218,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.vert.spv", +{ "waterShader.vert.spv", { { {0,0,368}, @@ -1252,7 +1252,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawPortalShader.vert.spv", { { {0,0,128}, @@ -1285,7 +1285,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "ribbonShader.vert.spv", { { {0,0,368}, @@ -1318,7 +1318,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "skyConus.vert.spv", { { {0,0,368}, @@ -1352,7 +1352,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { { {0,2,168}, @@ -1386,7 +1386,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { { }, @@ -1418,10 +1418,10 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2ParticleShader.frag.spv", { { - {0,4,32}, + {0,4,48}, {0,0,368}, }, { @@ -1455,7 +1455,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2Shader.vert.spv", { { {0,1,14144}, @@ -1490,7 +1490,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "ribbonShader.frag.spv", { { {0,4,48}, @@ -2045,6 +2045,7 @@ const std::unordered_map requiredTextures; - - #ifdef LINK_VULKAN - virtual void renderUIVLK(VkCommandBuffer commandBuffer) = 0; - #endif -}; - -#endif //AWEBWOWVIEWERCPP_IDEVICEUI_H diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp index 6dc047eea..6b0a5aeca 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.cpp @@ -711,18 +711,18 @@ void GDeviceGL20::reset() { } unsigned int GDeviceGL20::getUpdateFrameNumber() { - return (m_frameNumber + 1) & 3; + return (m_frameNumber + 1) % MAX_FRAMES_IN_FLIGHT; // return 0; } unsigned int GDeviceGL20::getCullingFrameNumber() { - return (m_frameNumber + 3) & 3; + return (m_frameNumber + 3) % MAX_FRAMES_IN_FLIGHT; // return 0; } unsigned int GDeviceGL20::getOcclusionFrameNumber() { - return (m_frameNumber + 2) & 3; + return (m_frameNumber + 2) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceGL20::getDrawFrameNumber() { - return m_frameNumber & 3; + return m_frameNumber % MAX_FRAMES_IN_FLIGHT; } void GDeviceGL20::increaseFrameNumber() { diff --git a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h index c088f8f21..eb9a59e5e 100644 --- a/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h +++ b/wowViewerLib/src/gapi/ogl2.0/GDeviceGL20.h @@ -205,7 +205,7 @@ class GDeviceGL20 : public IDevice { HGUniformBuffer m_uniformBufferForUpload; }; - std::array m_UBOFrames = {}; + std::array m_UBOFrames = {}; std::vector aggregationBufferForUpload = std::vector(1024*1024); diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp index 57f9abc28..7890829ad 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.cpp @@ -1030,18 +1030,18 @@ void GDeviceGL33::reset() { } unsigned int GDeviceGL33::getUpdateFrameNumber() { - return (m_frameNumber + 1) & 3; + return (m_frameNumber + 1) % MAX_FRAMES_IN_FLIGHT; // return 0; } unsigned int GDeviceGL33::getOcclusionFrameNumber() { - return (m_frameNumber + 2) & 3; + return (m_frameNumber + 2) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceGL33::getCullingFrameNumber() { - return (m_frameNumber + 3) & 3; + return (m_frameNumber + 3) % MAX_FRAMES_IN_FLIGHT; // return 0; } unsigned int GDeviceGL33::getDrawFrameNumber() { - return m_frameNumber & 3; + return m_frameNumber % MAX_FRAMES_IN_FLIGHT; } void GDeviceGL33::increaseFrameNumber() { diff --git a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h index 51ed68390..0f41ed65b 100644 --- a/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h +++ b/wowViewerLib/src/gapi/ogl3.3/GDeviceGL33.h @@ -149,7 +149,7 @@ class GDeviceGL33 : public IDevice, public std::enable_shared_from_this callback) override { DeallocationRecord dr; - dr.frameNumberToDoAt = m_frameNumber+4; + dr.frameNumberToDoAt = m_frameNumber+MAX_FRAMES_IN_FLIGHT; dr.callback = callback; listOfDeallocators.push_back(dr); }; @@ -260,7 +260,7 @@ class GDeviceGL33 : public IDevice, public std::enable_shared_from_this m_createdFrameBuffers; - std::array m_UBOFrames = {}; + std::array m_UBOFrames = {}; std::vector aggregationBufferForUpload; diff --git a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp index fcbe89bd7..d3121b8f8 100644 --- a/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp +++ b/wowViewerLib/src/gapi/ogl4.x/GDeviceGL4x.cpp @@ -704,13 +704,13 @@ void GDeviceGL4x::reset() { } unsigned int GDeviceGL4x::getUpdateFrameNumber() { - return (m_frameNumber + 1) & 3; + return (m_frameNumber + 1) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceGL4x::getCullingFrameNumber() { - return (m_frameNumber + 3) & 3; + return (m_frameNumber + 3) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceGL4x::getDrawFrameNumber() { - return (m_frameNumber) & 3; + return (m_frameNumber) % MAX_FRAMES_IN_FLIGHT; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 35515ed24..861b5ee65 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -286,6 +286,9 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { createCommandBuffers(); createSyncObjects(); + createCommandPoolForUpload(); + createCommandBuffersForUpload(); + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); uniformBufferOffsetAlign = deviceProperties.limits.minUniformBufferOffsetAlignment; maxUniformBufferSize = deviceProperties.limits.maxUniformBufferRange; @@ -324,10 +327,10 @@ void GDeviceVLK::createSwapChain() { VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); - uint32_t imageCount = 4; + uint32_t imageCount = MAX_FRAMES_IN_FLIGHT; if ((imageCount > swapChainSupport.capabilities.maxImageCount && (swapChainSupport.capabilities.maxImageCount != 0)) || (imageCount < swapChainSupport.capabilities.minImageCount)) { - std::cerr << "Your GPU doesnt support 4 images for swapchain, which is required by this application" << std::endl << std::flush; + std::cerr << "Your GPU doesnt support " << MAX_FRAMES_IN_FLIGHT << " images for swapchain, which is required by this application" << std::endl << std::flush; throw new std::runtime_error("Boo!"); } // if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { @@ -724,7 +727,7 @@ void GDeviceVLK::createCommandPoolForUpload(){ } void GDeviceVLK::createCommandBuffers() { - commandBuffers.resize(4); + commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); VkCommandBufferAllocateInfo allocInfo = {}; @@ -742,11 +745,11 @@ void GDeviceVLK::createCommandBuffers() { } } void GDeviceVLK::createCommandBuffersForUpload() { - renderCommandBuffers.resize(4); - renderCommandBuffersNotNull.resize(4); - renderCommandBuffersForFrameBuffers.resize(4); - renderCommandBuffersForFrameBuffersNotNull.resize(4); - for (int i = 0; i < 4; i++) renderCommandBuffersNotNull[i] = false; + renderCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); + renderCommandBuffersNotNull.resize(MAX_FRAMES_IN_FLIGHT); + renderCommandBuffersForFrameBuffers.resize(MAX_FRAMES_IN_FLIGHT); + renderCommandBuffersForFrameBuffersNotNull.resize(MAX_FRAMES_IN_FLIGHT); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) renderCommandBuffersNotNull[i] = false; { VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -771,7 +774,7 @@ void GDeviceVLK::createCommandBuffersForUpload() { } } - uploadCommandBuffers.resize(4); + uploadCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); VkCommandBufferAllocateInfo allocInfoUpload = {}; allocInfoUpload.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfoUpload.commandPool = uploadCommandPool; @@ -782,9 +785,9 @@ void GDeviceVLK::createCommandBuffersForUpload() { throw std::runtime_error("failed to allocate upload command buffers!"); } - textureTransferCommandBuffers.resize(4); - textureTransferCommandBufferNull.resize(4); - for (int i = 0; i < 4; i++) textureTransferCommandBufferNull[i] = true; + textureTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); + textureTransferCommandBufferNull.resize(MAX_FRAMES_IN_FLIGHT); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) textureTransferCommandBufferNull[i] = true; VkCommandBufferAllocateInfo texttrAllocInfoUpload = {}; texttrAllocInfoUpload.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; texttrAllocInfoUpload.commandPool = commandPoolForImageTransfer; @@ -820,14 +823,14 @@ void GDeviceVLK::createSyncObjects() { fenceInfo.pNext = NULL; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - inFlightFences.resize(4); - for (size_t i = 0; i < 4; i++) { + inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { throw std::runtime_error("failed to create synchronization objects for a frame!"); } } - inFlightTextureTransferFences.resize(4); - for (size_t i = 0; i < 4; i++) { + inFlightTextureTransferFences.resize(MAX_FRAMES_IN_FLIGHT); + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightTextureTransferFences[i]) != VK_SUCCESS) { throw std::runtime_error("failed to create synchronization objects for a textureUpdate!"); } @@ -839,10 +842,10 @@ void GDeviceVLK::createSyncObjects() { uploadFenceInfo.pNext = NULL; uploadFenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - uploadSemaphores.resize(4); - uploadFences.resize(4); - uploadSemaphoresSubmited.resize(4); - for (size_t i = 0; i < 4; i++) { + uploadSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + uploadFences.resize(MAX_FRAMES_IN_FLIGHT); + uploadSemaphoresSubmited.resize(MAX_FRAMES_IN_FLIGHT); + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { vkCreateSemaphore(device, &semaphoreInfo, nullptr, &uploadSemaphores[i]); vkCreateFence(device, &uploadFenceInfo, nullptr, &uploadFences[i]); uploadSemaphoresSubmited[i] = false; @@ -852,17 +855,17 @@ void GDeviceVLK::createSyncObjects() { unsigned int GDeviceVLK::getDrawFrameNumber() { - return m_frameNumber & 3; + return m_frameNumber % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceVLK::getUpdateFrameNumber() { - return (m_frameNumber + 1) & 3; + return (m_frameNumber + 1) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceVLK::getOcclusionFrameNumber() { - return (m_frameNumber + 2) & 3; + return (m_frameNumber + 2) % MAX_FRAMES_IN_FLIGHT; } unsigned int GDeviceVLK::getCullingFrameNumber() { - return (m_frameNumber + 3) & 3; + return (m_frameNumber + 3) % MAX_FRAMES_IN_FLIGHT; } void GDeviceVLK::increaseFrameNumber() { @@ -1209,7 +1212,7 @@ HGPUFence GDeviceVLK::createFence() { return HGPUFence(); } -void GDeviceVLK::drawScenario() { +void GDeviceVLK::submitDrawCommands() { if (m_firstFrame) { m_firstFrame = false; return; @@ -1341,9 +1344,9 @@ void GDeviceVLK::drawScenario() { submitInfo.pWaitDstStageMask = &waitStages[0]; std::vector grCommandBuffers = {}; - if (!textureTransferCommandBufferNull[currentDrawFrame]) { - grCommandBuffers.push_back(textureTransferCommandBuffers[currentDrawFrame]); - } +// if (!textureTransferCommandBufferNull[currentDrawFrame]) { +// grCommandBuffers.push_back(textureTransferCommandBuffers[currentDrawFrame]); +// } if (renderCommandBuffersForFrameBuffersNotNull[currentDrawFrame]) { grCommandBuffers.push_back(renderCommandBuffersForFrameBuffers[currentDrawFrame]); } @@ -1841,10 +1844,6 @@ GDeviceVLK::createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int //} void GDeviceVLK::initUploadThread() { - if (getIsAsynBuffUploadSupported()) { - createCommandPoolForUpload(); - createCommandBuffersForUpload(); - } } HFrameBuffer GDeviceVLK::createFrameBuffer(int width, int height, std::vector attachments, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index d4a72bb90..fecd3d921 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -64,7 +64,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int images); @@ -194,7 +190,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback) override { std::lock_guard lock(m_listOfDeallocatorsAccessMtx); DeallocationRecord dr; - dr.frameNumberToDoAt = m_frameNumber+4; + dr.frameNumberToDoAt = m_frameNumber+MAX_FRAMES_IN_FLIGHT; dr.callback = callback; listOfDeallocators.push_back(dr); }; @@ -381,7 +377,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_UBOFrames; + std::array m_UBOFrames; std::vector aggregationBufferForUpload = std::vector(1024*1024); diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index d4f941c46..c5a8977bc 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -18,7 +18,7 @@ void ISimpleMaterialVLK::createImageDescriptorSet() { //Bind Black pixel texture std::vector imageInfos(shaderVLK->getTextureCount()); - auto blackTexture = m_device->getBlackPixelTexture(); + auto blackTexture = m_device->getBlackTexturePixel(); auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); int bindIndex = 0; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 769136c63..512767daf 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -34,35 +34,49 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon cullingThread = std::thread(([&]() { using namespace std::chrono_literals; while (!this->m_isTerminating) { - DoCulling(); - } - })); + std::unique_lock lock{cullingQueueMutex}; + auto &l_cullingQueue = m_cullingQueue; + cullingCondVar.wait(lock, [&l_cullingQueue]() { return !l_cullingQueue.empty(); }); + + auto frameScenario = m_cullingQueue.front(); + m_cullingQueue.pop(); + lock.unlock(); - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - updateThread = std::thread(([&]() { - this->m_apiContainer->hDevice->initUploadThread(); - while (!this->m_isTerminating) { + consumeCulling(frameScenario); - updateTimePerFrame.beginMeasurement(); - DoUpdate(); - updateTimePerFrame.endMeasurement(); + //Push into updateRenderQueue + { + std::lock_guard l{updateRenderQueueMutex}; + m_updateRenderQueue.push(frameScenario); + updateRenderCondVar.notify_one(); } - })); - } + } + })); + + //Insert one temp element for balancing + m_updateRenderQueue.push(std::make_shared()); } } -void SceneComposer::DoCulling() { -// for (int i = 0; i < frameScenario->cullStages.size(); i++) { -// auto cullStage = frameScenario->cullStages[i]; -// -// cullStage->scene->checkCulling(cullStage); -// } +void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { + if (frameScenario == nullptr) + return; + + for (int i = 0; i < frameScenario->cullFunctions.size(); i++) { + frameScenario->drawUpdateFunction.push_back(frameScenario->cullFunctions[i]()); + } } -void SceneComposer::DoUpdate() { +void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { + if (frameScenario == nullptr) + return; + + for (int i = 0; i < frameScenario->drawUpdateFunction.size(); i++) { + frameScenario->drawUpdateFunction[i](m_apiContainer->hDevice); + } + // auto device = m_apiContainer->hDevice; // // @@ -106,14 +120,34 @@ void SceneComposer::DoUpdate() { void SceneComposer::draw(HFrameScenario frameScenario) { - std::future cullingFuture; - std::future updateFuture; - if (!m_supportThreads) { processCaches(10); - DoCulling(); - DoUpdate(); + consumeCulling(frameScenario); + consumeDrawAndUpdate(frameScenario); + } else { + { + //Add to Queue + std::lock_guard l{cullingQueueMutex}; + m_cullingQueue.push(frameScenario); + cullingCondVar.notify_one(); + } + + { + std::unique_lock lock{updateRenderQueueMutex}; + auto &l_updateRenderQueue = m_updateRenderQueue; + updateRenderCondVar.wait(lock, [&l_updateRenderQueue]() { return !l_updateRenderQueue.empty(); }); + + auto frameScenario = m_updateRenderQueue.front(); + m_updateRenderQueue.pop(); + lock.unlock(); + + updateTimePerFrame.beginMeasurement(); + consumeDrawAndUpdate(frameScenario); + updateTimePerFrame.endMeasurement(); + } } - m_apiContainer->hDevice->drawScenario(); + + + m_apiContainer->hDevice->submitDrawCommands(); m_apiContainer->hDevice->increaseFrameNumber(); } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 6238942e3..493c1a48b 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -19,7 +19,6 @@ class SceneComposer { HApiContainer m_apiContainer = nullptr; private: std::thread cullingThread; - std::thread updateThread; std::thread loadingResourcesThread; bool m_supportThreads = true; @@ -27,16 +26,21 @@ class SceneComposer { FrameCounter updateTimePerFrame; - void DoCulling(); - void DoUpdate(); + void consumeCulling(HFrameScenario &frameScenario); + void consumeDrawAndUpdate(HFrameScenario &frameScenario); void processCaches(int limit); //Flip-flop delta promises int frameMod = 0; + + std::mutex cullingQueueMutex; + std::condition_variable cullingCondVar; std::queue m_cullingQueue; - std::queue m_updateQueue; - std::queue m_render; + + std::mutex updateRenderQueueMutex; + std::condition_variable updateRenderCondVar; + std::queue m_updateRenderQueue; std::condition_variable startCulling; std::mutex cullingMutex; @@ -49,11 +53,6 @@ class SceneComposer { m_isTerminating = true; cullingThread.join(); - - if (m_apiContainer->hDevice->getIsAsynBuffUploadSupported()) { - updateThread.join(); - } - loadingResourcesThread.join(); } diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h index 5ad9784b5..3865fb679 100644 --- a/wowViewerLib/src/renderer/frame/SceneScenario.h +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -7,6 +7,8 @@ #include #include "../IRenderParameters.h" +#include "../../gapi/interface/IDevice.h" + struct CameraMatrices; @@ -36,8 +38,12 @@ class FrameScenarioBuilder { } }; +typedef std::function SceneUpdateRenderLambda; +typedef std::function CullLambda; + struct FrameScenario { - std::vector renderer; + std::vector cullFunctions; + std::vector drawUpdateFunction; }; typedef std::shared_ptr HFrameScenario; From 93cd8e03c100eb21fa585579860d26871d8e54ea Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 29 Jan 2023 00:22:46 +0200 Subject: [PATCH 019/212] progress --- src/ui/FrontendUI.cpp | 27 +++++++++++++++++++ src/ui/FrontendUI.h | 3 +++ .../renderer/uiScene/FrontendUIRenderer.cpp | 4 +-- src/ui/renderer/uiScene/FrontendUIRenderer.h | 8 +++++- .../vulkan/FrontendUIRenderForwardVLK.cpp | 15 ++++++----- .../vulkan/FrontendUIRenderForwardVLK.h | 8 +----- .../uiScene/vulkan/materials/UIMaterialVLK.h | 2 +- wowViewerLib/3rdparty/tinygltf | 2 +- wowViewerLib/src/renderer/IRenderParameters.h | 26 +++++++++++++++--- .../src/renderer/frame/SceneComposer.cpp | 2 +- .../src/renderer/frame/SceneScenario.h | 3 --- .../vulkan/MapSceneRenderForwardVLK.cpp | 19 ++++++++----- .../vulkan/MapSceneRenderForwardVLK.h | 11 +++++--- 13 files changed, 95 insertions(+), 35 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 7cafb3fce..e88b9abf8 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1484,6 +1484,33 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do m_minimapGenerationWindow->process(); } + + HFrameScenario scenario = std::make_shared(); + { + ViewPortDimensions dimension = { + {0, 0}, + {canvWidth, canvHeight} + }; + + auto uiFrameInput = std::make_shared>(); + uiFrameInput->delta = deltaTime * (1000.0f); + uiFrameInput->viewPortDimensions = dimension; + uiFrameInput->invertedZ = false; + + + + auto clearColor = m_api->getConfig()->clearColor; + + m_uiRenderer->createPlan(uiFrameInput); + +// auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); +// auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); +// std::vector updateStages = {uiUpdateStage}; +// HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, +// true, dimension, clearOnUi, false, clearColor, nullptr); + } + + return nullptr; // // HFrameScenario sceneScenario = std::make_shared(); diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 599b63c42..af931c04c 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -24,6 +24,7 @@ #include "childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h" #include "../../wowViewerLib/src/exporters/IExporter.h" #include "renderer/uiScene/IFrontendUIBufferCreate.h" +#include "renderer/uiScene/FrontendUIRenderer.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -72,6 +73,8 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_uiRenderer; + // HCullStage m_lastCullstage = {}; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index f59d77c03..75eba632d 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -4,9 +4,9 @@ #include "FrontendUIRenderer.h" -void FrontendUIRenderer::processFramePlan() { +void FrontendUIRenderer::consumeFrameInput(const std::shared_ptr> &frameInputParams) { - ImGuiFramePlan::ImGUIParam *frameParam = nullptr; + auto frameParam = frameInputParams->frameParameters; auto draw_data = &frameParam->imData; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index f7f017a9c..b2b8e1585 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -20,11 +20,17 @@ static const std::array imguiBindings = {{ class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { public: virtual ~FrontendUIRenderer() = default; - void processFramePlan(); + + std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override { + return nullptr; + }; + std::shared_ptr getLastCreatedPlan() override { return nullptr; } protected: HGDevice m_device = nullptr; UiMaterialCache m_materialCache; std::shared_ptr> m_imguiUbo = nullptr; + + void consumeFrameInput(const std::shared_ptr> &frameInputParams); }; //typedef FrameInputParams FrontendUIInputParams; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 8ed846abe..c9df8d364 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -9,12 +9,6 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { } -void FrontendUIRenderForwardVLK::putIntoQueue(std::shared_ptr &frameInputParams) { - std::lock_guard guard(m_inputParamsMtx); - - m_inputParams.push(frameInputParams); -} - void FrontendUIRenderForwardVLK::update(VkCommandBuffer transferQueueCMD, VkCommandBuffer renderQueueCMD) { } @@ -60,3 +54,12 @@ HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const //TODO: return nullptr; } + +void FrontendUIRenderForwardVLK::updateAndDraw( + const std::shared_ptr> &frameInputParams, + const std::shared_ptr &framePlan) { + + this->consumeFrameInput(frameInputParams); + + // +} diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 23dc663bf..31b73230c 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -18,10 +18,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { explicit FrontendUIRenderForwardVLK(HGDeviceVLK hDevice); ~FrontendUIRenderForwardVLK() override = default; - void putIntoQueue(std::shared_ptr &frameInputParams) override; - std::shared_ptr getLastPlan() override { - return nullptr; - }; + void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; void update(VkCommandBuffer udBuffer, VkCommandBuffer swapChainDraw); public: @@ -43,9 +40,6 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { //Rendering pipelining std::mutex m_inputParamsMtx; - std::queue> m_inputParams; - std::queue> m_updateParams; - private: HGBufferVLK vboBuffer; HGBufferVLK iboBuffer; diff --git a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h index c2d7b5bf8..393c8ca2f 100644 --- a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h +++ b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h @@ -11,7 +11,7 @@ class UIMaterialVLK : public ISimpleMaterialVLK { public: UIMaterialVLK(const HGDeviceVLK &device, - std::shared_ptr> UIWideChunk, + std::shared_ptr> &UIWideChunk, std::shared_ptr &texture ) : ISimpleMaterialVLK(device, "imguiShader", "imguiShader", diff --git a/wowViewerLib/3rdparty/tinygltf b/wowViewerLib/3rdparty/tinygltf index 44f88c0fb..2c521b343 160000 --- a/wowViewerLib/3rdparty/tinygltf +++ b/wowViewerLib/3rdparty/tinygltf @@ -1 +1 @@ -Subproject commit 44f88c0fbe238c2aae2c1a3435c070c872e15c50 +Subproject commit 2c521b34327ca8fe893244c854544d60941e7388 diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index 0050d247a..9550e22b8 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -5,12 +5,32 @@ #ifndef AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H #define AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H +#include #include "frame/FrameInputParams.h" +typedef std::function SceneUpdateRenderLambda; +typedef std::function CullLambda; + template -class IRendererParameters { - virtual void putIntoQueue(std::shared_ptr> &frameInputParams) = 0; - virtual std::shared_ptr getLastPlan() = 0; +class IRendererParameters : public std::enable_shared_from_this> { +public: + virtual std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) = 0; + virtual void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) = 0; + + //This function is to be used to display data in UI + virtual std::shared_ptr getLastCreatedPlan() = 0; + + CullLambda createPlan(const std::shared_ptr> &frameInputParams) { + auto this_s = this->shared_from_this(); + + return [frameInputParams, this_s]() -> SceneUpdateRenderLambda { + std::shared_ptr framePlan = this_s->processCulling(frameInputParams); + + return [framePlan, frameInputParams, this_s]() -> void { + this_s->updateAndDraw(frameInputParams, framePlan); + }; + }; + } }; #endif //AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 512767daf..67bb7edd0 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -74,7 +74,7 @@ void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { return; for (int i = 0; i < frameScenario->drawUpdateFunction.size(); i++) { - frameScenario->drawUpdateFunction[i](m_apiContainer->hDevice); + frameScenario->drawUpdateFunction[i](); } // auto device = m_apiContainer->hDevice; diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h index 3865fb679..1f5861e49 100644 --- a/wowViewerLib/src/renderer/frame/SceneScenario.h +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -38,9 +38,6 @@ class FrameScenarioBuilder { } }; -typedef std::function SceneUpdateRenderLambda; -typedef std::function CullLambda; - struct FrameScenario { std::vector cullFunctions; std::vector drawUpdateFunction; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 5e9d693a1..47b891d69 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -8,11 +8,6 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_devi } -void MapSceneRenderForwardVLK::putIntoQueue(std::shared_ptr> &frameInputParams) { - -} - - //Buffer creation HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { return HGVertexBuffer(); @@ -46,6 +41,16 @@ HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) return HGIndexBuffer(); } -std::shared_ptr MapSceneRenderForwardVLK::getLastPlan() { - return std::shared_ptr(); +void MapSceneRenderForwardVLK::updateAndDraw(const std::shared_ptr> &frameInputParams, + const std::shared_ptr &framePlan) { + +} + +std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { + return nullptr; +} + +std::shared_ptr +MapSceneRenderForwardVLK::processCulling(const std::shared_ptr> &frameInputParams) { + return nullptr; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 9a4631d91..360868497 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -13,10 +13,15 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { public: explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); - void putIntoQueue(std::shared_ptr> &frameInputParams) override; - std::shared_ptr getLastPlan() override; + std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; + void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + + std::shared_ptr getLastCreatedPlan() override; + +//------------------------------------- +// Buffer creation +//------------------------------------- - //Buffer creation HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; From 2459754464af0d39785b7edbcd21021c427fbeb0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 29 Jan 2023 12:33:55 +0200 Subject: [PATCH 020/212] getting closer --- src/ui/FrontendUI.cpp | 63 ++++++++++--------- src/ui/FrontendUI.h | 13 +--- .../renderer/uiScene/FrontendUIRenderer.cpp | 9 ++- src/ui/renderer/uiScene/FrontendUIRenderer.h | 7 +++ .../uiScene/FrontendUIRendererFactory.h | 1 + src/ui/renderer/uiScene/ImGUIPlan.h | 24 +++++-- .../vulkan/FrontendUIRenderForwardVLK.cpp | 7 ++- 7 files changed, 76 insertions(+), 48 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index e88b9abf8..36f7fa62d 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -34,11 +34,19 @@ #include "../database/CEmptySqliteDB.h" #include "../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "renderer/uiScene/IFrontendUIBufferCreate.h" +#include "renderer/uiScene/FrontendUIRendererFactory.h" -void FrontendUI::composeUI() { - if (this->fontTexture == nullptr) - return; +FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { + m_api = api; + m_processor = processor; + + this->createDatabaseHandler(); + m_uiRenderer = FrontendUIRendererFactory::createForwardRenderer(m_api->hDevice); + //this->createDefaultprocessor(); + +} +void FrontendUI::composeUI() { if (mapCanBeOpened) { if (!adtMinimapFilled && fillAdtSelectionminimap(adtSelectionMinimap, isWmoMap, mapCanBeOpened )) { // fillAdtSelectionminimap = nullptr; @@ -289,7 +297,6 @@ int ci_find_substr( const T& str1, const T& str2, const std::locale& loc = std:: if ( it != str1.end() ) return it - str1.begin(); else return -1; // not found } - void FrontendUI::filterMapList(std::string text) { filteredMapList = {}; for (int i = 0; i < mapList.size(); i++) { @@ -313,6 +320,7 @@ void FrontendUI::showMapConstructionDialog() { showMapConstruction = m_mapConstructionWindow->render(); } + void FrontendUI::showMapSelectionDialog() { if (showSelectMap) { if (mapList.size() == 0) { @@ -634,14 +642,13 @@ void FrontendUI::initImgui( #else ImGui_ImplGlfw_InitForOpenGL(window, true); #endif + + this->createFontTexture(); } void FrontendUI::newFrame() { // ImGui_ImplOpenGL3_NewFrame(); - //Create Font image - if (this->fontTexture == nullptr) - return; #ifdef __ANDROID_API__ ImGui_ImplAndroid_NewFrame(); @@ -1298,10 +1305,10 @@ void FrontendUI::showSettingsDialog() { //void FrontendUI::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { //} - void FrontendUI::getAdtSelectionMinimap(int wdtFileDataId) { m_wdtFile = m_api->cacheStorage->getWdtFileCache()->getFileId(wdtFileDataId); } + void FrontendUI::getAdtSelectionMinimap(std::string wdtFilePath) { m_wdtFile = m_api->cacheStorage->getWdtFileCache()->get(wdtFilePath); } @@ -1496,12 +1503,11 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do uiFrameInput->delta = deltaTime * (1000.0f); uiFrameInput->viewPortDimensions = dimension; uiFrameInput->invertedZ = false; - - + uiFrameInput->frameParameters = std::make_shared( ImGui::GetDrawData()); auto clearColor = m_api->getConfig()->clearColor; - m_uiRenderer->createPlan(uiFrameInput); + scenario->cullFunctions.push_back(m_uiRenderer->createPlan(uiFrameInput)); // auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); // auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); @@ -1511,7 +1517,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do } - return nullptr; + return scenario; // // HFrameScenario sceneScenario = std::make_shared(); // std::vector uiDependecies = {}; @@ -1598,7 +1604,6 @@ void FrontendUI::openWMOSceneByfdid(int WMOFdid) { currentScene = std::make_shared(m_api, WMOFdid); m_api->camera->setCameraPos(0, 0, 0); } - void FrontendUI::openMapByIdAndFilename(int mapId, std::string mapName, float x, float y, float z) { currentScene = std::make_shared(m_api, mapId, mapName); @@ -1625,6 +1630,7 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText // m_api->camera->setCameraPos(0, 0, 0); } + void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { auto m2Scene = std::make_shared(m_api, m2FileName); currentScene = m2Scene; @@ -1642,6 +1648,8 @@ void FrontendUI::unloadScene() { currentScene = std::make_shared(); } + + int FrontendUI::getCameraNumCallback() { // if (currentScene != nullptr) { // return currentScene->getCameraNum(); @@ -1650,8 +1658,6 @@ int FrontendUI::getCameraNumCallback() { return 0; } - - bool FrontendUI::setNewCameraCallback(int cameraNum) { return false; // if (currentScene == nullptr) return false; @@ -1683,6 +1689,7 @@ void FrontendUI::getCameraPos(float &cameraX, float &cameraY, float &cameraZ) { cameraZ = currentCameraPos[2]; } + void FrontendUI::getDebugCameraPos(float &cameraX, float &cameraY, float &cameraZ) { if (m_api->debugCamera == nullptr) { cameraX = 0; cameraY = 0; cameraZ = 0; @@ -1695,7 +1702,6 @@ void FrontendUI::getDebugCameraPos(float &cameraX, float &cameraY, float &camera cameraZ = currentCameraPos[2]; } - inline bool fileExistsNotNull (const std::string& name) { #ifdef ANDROID return false; @@ -1773,18 +1779,6 @@ void FrontendUI::createDatabaseHandler() { void FrontendUI::update(HFrontendUIBufferCreate renderer) { auto m_device = m_api->hDevice; - if (this->fontTexture == nullptr) { - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - // Upload texture to graphics system - this->fontTexture = m_device->createTexture(false, false); - this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); - // Store our identifier - io.Fonts->TexID = this->fontTexture; - return; - } // if (exporter != nullptr) { // if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { // exporterFramesReady++; @@ -1800,4 +1794,15 @@ void FrontendUI::update(HFrontendUIBufferCreate renderer) { return; -} \ No newline at end of file +} + +void FrontendUI::createFontTexture() { + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + // Upload texture to graphics system + + // Store our identifier + io.Fonts->TexID = this->m_uiRenderer->uploadFontTexture(pixels, width, height); +} diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index af931c04c..38d126bae 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -28,19 +28,11 @@ class FrontendUI : public IScene, public std::enable_shared_from_this { -//Implementation of iInnerSceneApi public: void createDefaultprocessor(); void createDatabaseHandler(); - FrontendUI(HApiContainer api, HRequestProcessor processor) { - m_api = api; - m_processor = processor; - - this->createDatabaseHandler(); - //this->createDefaultprocessor(); - - } + FrontendUI(HApiContainer api, HRequestProcessor processor); ~FrontendUI() override { fileDialog.Close(); createFileDialog.Close(); @@ -174,7 +166,6 @@ class FrontendUI : public IScene, public std::enable_shared_from_this> &frameInputParams) { auto frameParam = frameInputParams->frameParameters; - auto draw_data = &frameParam->imData; + auto draw_data = frameParam->getImData(); int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); @@ -116,3 +117,9 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrfontTexture = m_device->createTexture(false, false); + this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); + return this->fontTexture; +} diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index b2b8e1585..3e234fb82 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -19,18 +19,25 @@ static const std::array imguiBindings = {{ class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { public: + FrontendUIRenderer(HGDevice m_device) : m_device(m_device) { + + } virtual ~FrontendUIRenderer() = default; std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override { return nullptr; }; std::shared_ptr getLastCreatedPlan() override { return nullptr; } + HGTexture uploadFontTexture(unsigned char* pixels, int width, int height); protected: HGDevice m_device = nullptr; UiMaterialCache m_materialCache; std::shared_ptr> m_imguiUbo = nullptr; void consumeFrameInput(const std::shared_ptr> &frameInputParams); + +private: + HGTexture fontTexture; }; //typedef FrameInputParams FrontendUIInputParams; diff --git a/src/ui/renderer/uiScene/FrontendUIRendererFactory.h b/src/ui/renderer/uiScene/FrontendUIRendererFactory.h index 4d3e2a310..c086b8be4 100644 --- a/src/ui/renderer/uiScene/FrontendUIRendererFactory.h +++ b/src/ui/renderer/uiScene/FrontendUIRendererFactory.h @@ -11,6 +11,7 @@ #include "../../../../wowViewerLib/src/gapi/interface/IDevice.h" class FrontendUIRendererFactory { +public: static std::shared_ptr createForwardRenderer(HGDevice &device); }; diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index 9cf97bb8b..8c1d3621b 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -15,18 +15,30 @@ namespace ImGuiFramePlan { public: explicit ImGUIParam(ImDrawData *imData) { //Do copy of imData into local copy - + if (imData != nullptr) { + m_imData = *imData; + m_imData.CmdLists = new ImDrawList *[imData->CmdListsCount]; + + for (int i = 0; i < m_imData.CmdListsCount; i++) { + m_imData.CmdLists[i] = imData->CmdLists[i]->CloneOutput(); + } + } else { + m_imData.CmdLists = nullptr; + } } ~ImGUIParam() { - for (int i = 0; i < imData.CmdListsCount; i++ ) { - IM_FREE(imData.CmdLists[i]); + if (m_imData.CmdLists != nullptr) { + for (int i = 0; i < m_imData.CmdListsCount; i++) { + IM_FREE(m_imData.CmdLists[i]); + } + delete m_imData.CmdLists; } - } - public: - ImDrawData imData; + const ImDrawData * const getImData() { return &m_imData; }; + private: + ImDrawData m_imData; }; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index c9df8d364..3d28c184d 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -6,7 +6,8 @@ #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" -FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { +FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : FrontendUIRenderer( + hDevice), m_device(hDevice) { } void FrontendUIRenderForwardVLK::update(VkCommandBuffer transferQueueCMD, VkCommandBuffer renderQueueCMD) { @@ -17,6 +18,8 @@ void FrontendUIRenderForwardVLK::createBuffers() { vboBuffer = m_device->createIndexBuffer(1024*1024); iboBuffer = m_device->createVertexBuffer(1024*1024); uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); + + m_imguiUbo = uboBuffer->getSubBuffer() } HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { @@ -61,5 +64,5 @@ void FrontendUIRenderForwardVLK::updateAndDraw( this->consumeFrameInput(frameInputParams); - // + //Record commands to update buffer and draw } From 739097d1f0bd78792ef27618885fe3cce66d994b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 4 Feb 2023 17:32:17 +0200 Subject: [PATCH 021/212] delete unneeded shader permutation classes, add descriptor layout class for reflection --- .../renderer/uiScene/FrontendUIRenderer.cpp | 11 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 6 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 18 +-- .../vulkan/FrontendUIRenderForwardVLK.h | 4 +- wowViewerLib/CMakeLists.txt | 26 +--- .../shaders/src/spirv/dumpShaderFields.h | 54 ++++++++ .../src/engine/shader/ShaderDefinitions.h | 43 ++++++ .../src/gapi/interface/buffers/IBuffer.h | 3 + .../src/gapi/interface/buffers/IBufferChunk.h | 15 +-- .../src/gapi/vulkan/GDeviceVulkan.cpp | 125 +++++------------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 6 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 6 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 1 + .../gapi/vulkan/buffers/IBufferChunkVLK.cpp | 5 + .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 31 +++++ .../descriptorSets/GDescriptorPoolVLK.cpp | 30 ++--- .../descriptorSets/GDescriptorPoolVLK.h | 9 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 119 ++++++++++++++++- .../vulkan/descriptorSets/GDescriptorSet.h | 55 ++++++-- .../descriptorSets/GDescriptorSetLayout.cpp | 98 ++++++++++++++ .../descriptorSets/GDescriptorSetLayout.h | 35 +++++ .../vulkan/materials/ISimpleMaterialVLK.cpp | 10 +- .../vulkan/materials/ISimpleMaterialVLK.h | 10 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 3 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 3 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 8 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 14 +- .../shaders/GAdtShaderPermutationVLK.cpp | 12 -- .../vulkan/shaders/GAdtShaderPermutationVLK.h | 27 ---- .../vulkan/shaders/GDrawBoundingBoxVLK.cpp | 10 -- .../gapi/vulkan/shaders/GDrawBoundingBoxVLK.h | 26 ---- .../src/gapi/vulkan/shaders/GFFXGlowVLK.cpp | 14 -- .../src/gapi/vulkan/shaders/GFFXGlowVLK.h | 27 ---- .../src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp | 16 --- .../src/gapi/vulkan/shaders/GFFXgauss4VLK.h | 27 ---- .../shaders/GImguiShaderPermutation.cpp | 12 -- .../vulkan/shaders/GImguiShaderPermutation.h | 27 ---- .../GM2ParticleShaderPermutationVLK.cpp | 12 -- .../shaders/GM2ParticleShaderPermutationVLK.h | 27 ---- .../shaders/GM2RibbonShaderPermutationVLK.cpp | 12 -- .../shaders/GM2RibbonShaderPermutationVLK.h | 27 ---- .../shaders/GM2ShaderPermutationVLK.cpp | 12 -- .../vulkan/shaders/GM2ShaderPermutationVLK.h | 27 ---- .../vulkan/shaders/GShaderPermutationVLK.cpp | 97 ++------------ .../vulkan/shaders/GShaderPermutationVLK.h | 24 ++-- .../vulkan/shaders/GSkyConusShaderVLK.cpp | 10 -- .../gapi/vulkan/shaders/GSkyConusShaderVLK.h | 27 ---- .../shaders/GWMOShaderPermutationVLK.cpp | 9 -- .../vulkan/shaders/GWMOShaderPermutationVLK.h | 24 ---- .../shaders/GWaterShaderPermutation.cpp | 9 -- .../vulkan/shaders/GWaterShaderPermutation.h | 28 ---- .../vulkan/shaders/GWaterfallShaderVLK.cpp | 10 -- .../gapi/vulkan/shaders/GWaterfallShaderVLK.h | 27 ---- .../src/renderer/frame/SceneComposer.cpp | 2 +- 54 files changed, 566 insertions(+), 764 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.h delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.h diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 39c9d0f9f..512b99a4d 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -5,7 +5,7 @@ #include "FrontendUIRenderer.h" //This should be called during Update/Draw stage, cause this stuff allocates buffers -void FrontendUIRenderer::consumeFrameInput(const std::shared_ptr> &frameInputParams) { +void FrontendUIRenderer::consumeFrameInput(const std::shared_ptr> &frameInputParams, std::vector &meshes) { auto frameParam = frameInputParams->frameParameters; @@ -44,10 +44,10 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrgetObject(); uni.projectionMat = ortho_projection; uni.scale[0] = uiScale; - m_imguiUbo->save(sizeof(decltype(uni))); + m_imguiUbo->save(); //UBO update end - auto shaderPermute = m_device->getShader("imguiShader", "imguiShader", nullptr); + // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -85,7 +85,7 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptr= 0.0f && clip_rect.w >= 0.0f) { // Apply scissor/clipping rectangle - // Create mesh add add it to collected meshes + // Create mesh and add it to collected meshes gMeshTemplate meshTemplate(vertexBufferBindings); meshTemplate.element = DrawElementMode::TRIANGLES; meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; @@ -110,8 +110,7 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrTextureId; auto material = this->createUIMaterial(materialTemplate); - -// this->createUIMesh(meshTemplate, material); + meshes.push_back(this->createMesh(meshTemplate, material)); } } } diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 3e234fb82..28586242d 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -31,13 +31,13 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; - void consumeFrameInput(const std::shared_ptr> &frameInputParams); + void consumeFrameInput(const std::shared_ptr> &frameInputParams, std::vector &meshes); -private: - HGTexture fontTexture; }; //typedef FrameInputParams FrontendUIInputParams; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 3d28c184d..8fa00420f 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -5,21 +5,19 @@ #include "FrontendUIRenderForwardVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" -FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(HGDeviceVLK hDevice) : FrontendUIRenderer( +FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( hDevice), m_device(hDevice) { } -void FrontendUIRenderForwardVLK::update(VkCommandBuffer transferQueueCMD, VkCommandBuffer renderQueueCMD) { - -} - void FrontendUIRenderForwardVLK::createBuffers() { vboBuffer = m_device->createIndexBuffer(1024*1024); iboBuffer = m_device->createVertexBuffer(1024*1024); uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); - m_imguiUbo = uboBuffer->getSubBuffer() + m_imguiUbo = std::make_shared>(uboBuffer); } HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { @@ -55,14 +53,18 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { //TODO: - return nullptr; + return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); } void FrontendUIRenderForwardVLK::updateAndDraw( const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { - this->consumeFrameInput(frameInputParams); + std::vector meshes; + this->consumeFrameInput(frameInputParams, meshes); //Record commands to update buffer and draw + [&meshes](VkCommandBuffer transferQueueCMD, VkCommandBuffer renderFB, VkCommandBuffer renderSwapFB) { + + }; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 31b73230c..ab893282f 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -15,12 +15,10 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: - explicit FrontendUIRenderForwardVLK(HGDeviceVLK hDevice); + explicit FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice); ~FrontendUIRenderForwardVLK() override = default; void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; - - void update(VkCommandBuffer udBuffer, VkCommandBuffer swapChainDraw); public: HGVertexBuffer createVertexBuffer(int sizeInBytes) override; HGIndexBuffer createIndexBuffer(int sizeInBytes) override; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index f0f9b89ba..bf74534b2 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -467,11 +467,6 @@ if (LINK_VULKAN) src/gapi/vulkan/vkAllocator.cpp src/gapi/vulkan/GVertexBufferBindingsVLK.cpp src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp - src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.cpp - src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.cpp - src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.cpp - src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.cpp - src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.cpp src/gapi/vulkan/meshes/GM2MeshVLK.cpp src/gapi/vulkan/meshes/GMeshVLK.cpp src/gapi/vulkan/textures/GTextureVLK.cpp @@ -482,30 +477,21 @@ if (LINK_VULKAN) src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp src/gapi/vulkan/descriptorSets/GDescriptorSet.h - src/gapi/vulkan/shaders/GImguiShaderPermutation.cpp - src/gapi/vulkan/shaders/GImguiShaderPermutation.h - src/gapi/vulkan/shaders/GWaterShaderPermutation.cpp - src/gapi/vulkan/shaders/GWaterShaderPermutation.h - src/gapi/vulkan/shaders/GSkyConusShaderVLK.cpp - src/gapi/vulkan/shaders/GSkyConusShaderVLK.h src/gapi/vulkan/GFrameBufferVLK.cpp src/gapi/vulkan/GFrameBufferVLK.h - src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp - src/gapi/vulkan/shaders/GFFXgauss4VLK.h - src/gapi/vulkan/shaders/GFFXGlowVLK.cpp - src/gapi/vulkan/shaders/GFFXGlowVLK.h src/gapi/vulkan/GRenderPassVLK.cpp src/gapi/vulkan/GRenderPassVLK.h - src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp - src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h - src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp - src/gapi/vulkan/shaders/GWaterfallShaderVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h src/gapi/vulkan/buffers/GBufferVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.h src/gapi/vulkan/buffers/IBufferVLK.h - src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp src/gapi/vulkan/materials/ISimpleMaterialVLK.h) + src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp + src/gapi/vulkan/materials/ISimpleMaterialVLK.h + src/gapi/vulkan/buffers/IBufferChunkVLK.cpp + src/gapi/vulkan/buffers/IBufferChunkVLK.h + src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp + src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index f81c12593..7e8448539 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -13,6 +13,23 @@ constexpr const int MAX_SHADER_DESC_SETS = 8; +enum class ShaderStage { + Unk, Vertex, Fragment, RayGenerate, RayAnyHit, RayClosestHit, RayMiss +}; + +#define printStage(stage) case stage: return #stage; break; +std::string ShaderStageToStr(ShaderStage stage) { + switch (stage) { + printStage(ShaderStage::Unk) + printStage(ShaderStage::Vertex) + printStage(ShaderStage::Fragment) + printStage(ShaderStage::RayGenerate) + printStage(ShaderStage::RayAnyHit) + printStage(ShaderStage::RayClosestHit) + printStage(ShaderStage::RayMiss) + } +} + struct attributeDefine { std::string name; unsigned int location; @@ -46,6 +63,7 @@ struct bindingAmountData { }; struct shaderMetaData { + ShaderStage stage; std::vector uboBindings; std::array uboBindingAmountsPerSet; @@ -151,6 +169,11 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { R"===( constexpr const int MAX_SHADER_DESC_SETS = 8; + enum class ShaderStage { + Unk, Vertex, Fragment, RayGenerate, RayAnyHit, RayClosestHit, RayMiss + }; + + struct uboBindingData { unsigned int set; unsigned int binding; @@ -169,6 +192,8 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { }; struct shaderMetaData { + ShaderStage stage; + std::vector uboBindings; std::array uboBindingAmountsPerSet; @@ -226,6 +251,33 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { auto &perSetMap = fieldDefMapPerShaderName.at(tokens[0]); auto &metaInfo = shaderMetaInfo.at(fileName); + + auto execModel = glsl.get_entry_points_and_stages()[0].execution_model; + metaInfo.stage = [&execModel]() -> ShaderStage { + switch (execModel) { + case(spv::ExecutionModel::ExecutionModelVertex): + return ShaderStage::Vertex; + + case(spv::ExecutionModel::ExecutionModelFragment): + return ShaderStage::Fragment; + + case(spv::ExecutionModel::ExecutionModelAnyHitKHR): + return ShaderStage::RayAnyHit; + + case(spv::ExecutionModel::ExecutionModelClosestHitKHR): + return ShaderStage::RayClosestHit; + + case(spv::ExecutionModel::ExecutionModelRayGenerationKHR): + return ShaderStage::RayGenerate; + + case(spv::ExecutionModel::ExecutionModelMissKHR): + return ShaderStage::RayMiss; + + default: + return ShaderStage::Unk; + } + }(); + if (glsl.get_entry_points_and_stages()[0].execution_model == spv::ExecutionModel::ExecutionModelVertex) { auto it = attributesPerShaderName.find(tokens[0]); if (it == attributesPerShaderName.end()) { @@ -374,6 +426,8 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::cout << "{ \"" << it->first << "\", \n"<< " {\n"; + //Dump stage + std::cout << " " << ShaderStageToStr(it->second.stage) << "," << std::endl; //Dump UBO Bindings per shader std::cout << " {\n"; for (auto subIt = it->second.uboBindings.begin(); subIt != it->second.uboBindings.end(); subIt++) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a355228cd..de002d162 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -25,6 +25,11 @@ struct attributeDefine { constexpr const int MAX_SHADER_DESC_SETS = 8; + enum class ShaderStage { + Unk, Vertex, Fragment, RayGenerate, RayAnyHit, RayClosestHit, RayMiss + }; + + struct uboBindingData { unsigned int set; unsigned int binding; @@ -43,6 +48,8 @@ struct attributeDefine { }; struct shaderMetaData { + ShaderStage stage; + std::vector uboBindings; std::array uboBindingAmountsPerSet; @@ -285,6 +292,7 @@ const std::unordered_map> attributesPe const std::unordered_map shaderMetaInfo = { { "wmoShader.vert.spv", { + ShaderStage::Vertex, { {0,1,64}, {0,0,368}, @@ -320,6 +328,7 @@ const std::unordered_map shaderMetaInfo = { }, { "wmoShader.frag.spv", { + ShaderStage::Fragment, { {0,4,32}, {0,0,368}, @@ -364,6 +373,7 @@ const std::unordered_map shaderMetaInfo = { }, { "waterShader.frag.spv", { + ShaderStage::Fragment, { {0,4,16}, {0,0,368}, @@ -399,6 +409,7 @@ const std::unordered_map shaderMetaInfo = { }, { "waterfallShader.frag.spv", { + ShaderStage::Fragment, { {0,4,96}, {0,0,368}, @@ -437,6 +448,7 @@ const std::unordered_map shaderMetaInfo = { }, { "adtShader.vert.spv", { + ShaderStage::Vertex, { {0,0,368}, }, @@ -470,6 +482,7 @@ const std::unordered_map shaderMetaInfo = { }, { "adtLodShader.vert.spv", { + ShaderStage::Vertex, { {0,0,144}, }, @@ -503,6 +516,7 @@ const std::unordered_map shaderMetaInfo = { }, { "waterfallShader.vert.spv", { + ShaderStage::Vertex, { {0,2,144}, {0,1,14144}, @@ -539,6 +553,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawPoints.vert.spv", { + ShaderStage::Vertex, { {0,0,128}, {0,1,64}, @@ -573,6 +588,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawFrustumShader.vert.spv", { + ShaderStage::Vertex, { {0,0,128}, }, @@ -606,6 +622,7 @@ const std::unordered_map shaderMetaInfo = { }, { "ffxglow.frag.spv", { + ShaderStage::Fragment, { {0,4,16}, }, @@ -641,6 +658,7 @@ const std::unordered_map shaderMetaInfo = { }, { "adtShader.frag.spv", { + ShaderStage::Fragment, { {0,4,288}, {0,3,16}, @@ -685,6 +703,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawBBShader.vert.spv", { + ShaderStage::Vertex, { {0,1,112}, {0,0,368}, @@ -719,6 +738,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawFrustumShader.frag.spv", { + ShaderStage::Fragment, { }, { @@ -751,6 +771,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawDepthShader.frag.spv", { + ShaderStage::Fragment, { {0,2,12}, }, @@ -785,6 +806,7 @@ const std::unordered_map shaderMetaInfo = { }, { "adtLodShader.frag.spv", { + ShaderStage::Fragment, { {0,0,84}, }, @@ -818,6 +840,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawPoints.frag.spv", { + ShaderStage::Fragment, { {0,1,12}, }, @@ -851,6 +874,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawBBShader.frag.spv", { + ShaderStage::Fragment, { {0,1,112}, }, @@ -884,6 +908,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawLinesShader.frag.spv", { + ShaderStage::Fragment, { }, { @@ -916,6 +941,7 @@ const std::unordered_map shaderMetaInfo = { }, { "skyConus.frag.spv", { + ShaderStage::Fragment, { }, { @@ -948,6 +974,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawPortalShader.frag.spv", { + ShaderStage::Fragment, { {0,4,16}, }, @@ -981,6 +1008,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawLinesShader.vert.spv", { + ShaderStage::Vertex, { {0,0,128}, }, @@ -1014,6 +1042,7 @@ const std::unordered_map shaderMetaInfo = { }, { "ffxgauss4.frag.spv", { + ShaderStage::Fragment, { {0,4,32}, }, @@ -1048,6 +1077,7 @@ const std::unordered_map shaderMetaInfo = { }, { "imguiShader.frag.spv", { + ShaderStage::Fragment, { }, { @@ -1081,6 +1111,7 @@ const std::unordered_map shaderMetaInfo = { }, { "m2ParticleShader.vert.spv", { + ShaderStage::Vertex, { {0,0,368}, }, @@ -1114,6 +1145,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawQuad.vert.spv", { + ShaderStage::Vertex, { {0,2,16}, }, @@ -1147,6 +1179,7 @@ const std::unordered_map shaderMetaInfo = { }, { "imguiShader.vert.spv", { + ShaderStage::Vertex, { {0,1,80}, }, @@ -1180,6 +1213,7 @@ const std::unordered_map shaderMetaInfo = { }, { "m2Shader.frag.spv", { + ShaderStage::Fragment, { {0,4,64}, {0,3,256}, @@ -1220,6 +1254,7 @@ const std::unordered_map shaderMetaInfo = { }, { "waterShader.vert.spv", { + ShaderStage::Vertex, { {0,0,368}, {0,1,64}, @@ -1254,6 +1289,7 @@ const std::unordered_map shaderMetaInfo = { }, { "drawPortalShader.vert.spv", { + ShaderStage::Vertex, { {0,0,128}, }, @@ -1287,6 +1323,7 @@ const std::unordered_map shaderMetaInfo = { }, { "ribbonShader.vert.spv", { + ShaderStage::Vertex, { {0,0,368}, }, @@ -1320,6 +1357,7 @@ const std::unordered_map shaderMetaInfo = { }, { "skyConus.vert.spv", { + ShaderStage::Vertex, { {0,0,368}, {0,2,96}, @@ -1354,6 +1392,7 @@ const std::unordered_map shaderMetaInfo = { }, { "renderFrameBufferShader.frag.spv", { + ShaderStage::Fragment, { {0,2,168}, }, @@ -1388,6 +1427,7 @@ const std::unordered_map shaderMetaInfo = { }, { "renderFrameBufferShader.vert.spv", { + ShaderStage::Vertex, { }, { @@ -1420,6 +1460,7 @@ const std::unordered_map shaderMetaInfo = { }, { "m2ParticleShader.frag.spv", { + ShaderStage::Fragment, { {0,4,48}, {0,0,368}, @@ -1457,6 +1498,7 @@ const std::unordered_map shaderMetaInfo = { }, { "m2Shader.vert.spv", { + ShaderStage::Vertex, { {0,1,14144}, {0,0,368}, @@ -1492,6 +1534,7 @@ const std::unordered_map shaderMetaInfo = { }, { "ribbonShader.frag.spv", { + ShaderStage::Fragment, { {0,4,48}, {0,0,368}, diff --git a/wowViewerLib/src/gapi/interface/buffers/IBuffer.h b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h index 0679e9051..6a711e2ce 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IBuffer.h +++ b/wowViewerLib/src/gapi/interface/buffers/IBuffer.h @@ -4,6 +4,9 @@ #ifndef AWEBWOWVIEWERCPP_IBUFFER_H #define AWEBWOWVIEWERCPP_IBUFFER_H + +#include + class IBuffer { public: virtual ~IBuffer() = default; diff --git a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h index 198be121b..d8cfb5ae6 100644 --- a/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h +++ b/wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h @@ -1,4 +1,4 @@ -// + // // Created by deamon on 09.12.19. // @@ -14,17 +14,12 @@ template using IChunkHandlerType = std::function ; template -class IBufferChunk : public IBuffer { - friend class IDevice; -private: - IChunkHandlerType m_handler; +class IBufferChunk { public: - ~IBufferChunk() override = default; + virtual ~IBufferChunk() = default; virtual T &getObject() = 0; + virtual void save() = 0; - virtual void setUpdateHandler(IChunkHandlerType handler) { - m_handler = handler; - }; - + virtual void setUpdateHandler(IChunkHandlerType handler) {}; }; #endif //AWEBWOWVIEWERCPP_IBUFFERCHUNK_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 861b5ee65..5130ee90c 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -19,20 +19,9 @@ #include "textures/GBlpTextureVLK.h" #include "GVertexBufferBindingsVLK.h" #include "GPipelineVLK.h" -#include "shaders/GM2ShaderPermutationVLK.h" -#include "shaders/GM2ParticleShaderPermutationVLK.h" #include "../../engine/algorithms/hashString.h" -#include "shaders/GAdtShaderPermutationVLK.h" -#include "shaders/GWMOShaderPermutationVLK.h" -#include "shaders/GWaterShaderPermutation.h" -#include "shaders/GImguiShaderPermutation.h" -#include "shaders/GM2RibbonShaderPermutationVLK.h" -#include "shaders/GSkyConusShaderVLK.h" -#include "shaders/GDrawBoundingBoxVLK.h" #include "GFrameBufferVLK.h" -#include "shaders/GFFXgauss4VLK.h" -#include "shaders/GFFXGlowVLK.h" -#include "shaders/GWaterfallShaderVLK.h" +#include "shaders/GShaderPermutationVLK.h" #include "GRenderPassVLK.h" #include "../../engine/algorithms/FrameCounter.h" #include "buffers/GBufferVLK.h" @@ -1040,6 +1029,8 @@ void GDeviceVLK::updateBuffers(std::vector &frameDepedantDa } void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { + //TODO: REWRITE THIS PART FFS!!! + std::vector textures; textures.reserve(meshes.size() * 3); @@ -1047,23 +1038,23 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { for (const auto &hmesh : meshes) { GMeshVLK * mesh = (GMeshVLK *) hmesh.get(); - mesh->material->updateImageDescriptorSet(); + mesh->material()->updateImageDescriptorSet(); // for (int i = 0; i < mesh->textureCount(); i++) { // textures.push_back(mesh->m_texture[i]); // } } - //TODO:!!! -// -// std::sort(textures.begin(), textures.end()); -// textures.erase( unique( textures.begin(), textures.end() ), textures.end() ); -// -// for (const auto &texture : textures) { -// if (texture == nullptr) continue; -// if (texture->postLoad()) texturesLoaded++; -// if (texturesLoaded > 4) break; -// } + + + std::sort(textures.begin(), textures.end()); + textures.erase( unique( textures.begin(), textures.end() ), textures.end() ); + + for (const auto &texture : textures) { + if (texture == nullptr) continue; + if (texture->postLoad()) texturesLoaded++; + if (texturesLoaded > 4) break; + } } void GDeviceVLK::drawMeshes(std::vector &meshes) { @@ -1071,72 +1062,18 @@ void GDeviceVLK::drawMeshes(std::vector &meshes) { } std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) { - const char * cstr = vertexName.c_str(); + std::string combinedName = vertexName + " " + fragmentName; + const char * cstr = combinedName.c_str(); size_t hash = CalculateFNV(cstr); - if (m_shaderPermutCache.count(hash) > 0) { - HGShaderPermutation ptr = m_shaderPermutCache.at(hash); + if (m_shaderPermuteCache.count(hash) > 0) { + HGShaderPermutation ptr = m_shaderPermuteCache.at(hash); return ptr; } - std::shared_ptr sharedPtr; - - if (vertexName == "m2Shader") { - IShaderPermutation *iPremutation = new GM2ShaderPermutationVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "m2ParticleShader") { - IShaderPermutation *iPremutation = new GM2ParticleShaderPermutationVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "ribbonShader") { - IShaderPermutation *iPremutation = new GM2RibbonShaderPermutationVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "wmoShader"){ - IShaderPermutation *iPremutation = new GWMOShaderPermutationVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "waterShader"){ - IShaderPermutation *iPremutation = new GWaterShaderPermutation(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "adtShader"){ - IShaderPermutation *iPremutation = new GAdtShaderPermutationVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "skyConus"){ - IShaderPermutation *iPremutation = new GSkyConusShaderVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - } else if (vertexName == "fullScreen_ffxgauss4") { - IShaderPermutation *iPremutation = new GFFXgauss4VLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - m_shaderPermutCache[hash] = sharedPtr; - } else if (vertexName == "ffxGlowQuad") { - IShaderPermutation *iPremutation = new GFFXGlowVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - m_shaderPermutCache[hash] = sharedPtr; - } else if (vertexName == "waterfallShader") { - IShaderPermutation *iPremutation = new GWaterfallShaderVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - m_shaderPermutCache[hash] = sharedPtr; - } else if (vertexName == "drawBBShader") { - IShaderPermutation *iPremutation = new GDrawBoundingBoxVLK(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - m_shaderPermutCache[hash] = sharedPtr; - } else if (vertexName == "imguiShader") { - IShaderPermutation *iPremutation = new GImguiShaderPermutation(vertexName, this); - sharedPtr.reset(iPremutation); - sharedPtr->compileShader("",""); - m_shaderPermutCache[hash] = sharedPtr; - } - - - m_shaderPermutCache[hash] = sharedPtr; + std::shared_ptr sharedPtr = std::make_shared(vertexName, fragmentName, this->shared_from_this()); + + + m_shaderPermuteCache[hash] = sharedPtr; return sharedPtr; @@ -1202,10 +1139,10 @@ HGTexture GDeviceVLK::createTexture(bool xWrapTex, bool yWrapTex) { } HGMesh GDeviceVLK::createMesh(gMeshTemplate &meshTemplate) { - std::shared_ptr h_mesh; - h_mesh.reset(new GMeshVLK(*this, meshTemplate)); - - return h_mesh; +// std::shared_ptr h_mesh; +// h_mesh.reset(new GMeshVLK(*this, meshTemplate)); +// + return nullptr; } HGPUFence GDeviceVLK::createFence() { @@ -1488,13 +1425,13 @@ HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, } -std::shared_ptr -GDeviceVLK::createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int images) { +std::shared_ptr +GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescriptorSetLayout) { //1. Try to allocate from existing sets - std::shared_ptr descriptorSet; + std::shared_ptr descriptorSet; for (size_t i = 0; i < m_descriptorPools.size(); i++) { - descriptorSet = m_descriptorPools[i]->allocate(layout, uniforms, images); + descriptorSet = m_descriptorPools[i]->allocate(hDescriptorSetLayout); if (descriptorSet != nullptr) return descriptorSet; } @@ -1503,7 +1440,7 @@ GDeviceVLK::createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int GDescriptorPoolVLK * newPool = new GDescriptorPoolVLK(*this); m_descriptorPools.push_back(newPool); - return newPool->allocate(layout, uniforms, images); + return newPool->allocate(hDescriptorSetLayout); } //void GDeviceVLK::internalDrawStageAndDeps(HDrawStage drawStage) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index fecd3d921..7f4392b78 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -138,7 +138,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this createDescriptorSet(VkDescriptorSetLayout layout, int uniforms, int images); + std::shared_ptr createDescriptorSet(std::shared_ptr &hDescriptorSetLayout); virtual VkDevice getVkDevice() { return device; @@ -319,7 +319,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this swapchainRenderPass; - VkCommandPool commandPool; VkCommandPool commandPoolForImageTransfer; VkCommandPool renderCommandPool; @@ -350,7 +349,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_descriptorPools; VmaAllocator vmaAllocator; - VmaPool uboVmaPool; VkPhysicalDeviceProperties deviceProperties; @@ -372,7 +370,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_shaderPermutCache; + std::unordered_map m_shaderPermuteCache; struct FrameUniformBuffers { HGUniformBuffer m_uniformBufferForUpload; }; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index 3a5cde4af..fc6e5aa05 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -210,8 +210,8 @@ void GPipelineVLK::createPipeline( depthStencil.stencilTestEnable = VK_FALSE; std::array descLayouts ; - descLayouts[0] = shaderVLK->getUboDescriptorLayout(); - descLayouts[1] = shaderVLK->getImageDescriptorLayout(); + descLayouts[0] = shaderVLK->getUboDescriptorLayout()->getSetLayout(); + descLayouts[1] = shaderVLK->getImageDescriptorLayout()->getSetLayout(); VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -221,7 +221,7 @@ void GPipelineVLK::createPipeline( pipelineLayoutInfo.setLayoutCount = 2; pipelineLayoutInfo.pSetLayouts = &descLayouts[0]; - std::cout << "Pipeline layout for "+shaderVLK->getShaderName() << std::endl; + std::cout << "Pipeline layout for "+shaderVLK->getShaderCombinedName() << std::endl; if (vkCreatePipelineLayout(m_device.getVkDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create pipeline layout!"); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 548af539c..142d7151b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -95,6 +95,7 @@ void GBufferVLK::subUploadData(void *data, int offset, int length) { void GBufferVLK::resize(int newLength) { m_bufferSize = newLength; + BufferInternal newBuffer; createBuffer(newBuffer); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp new file mode 100644 index 000000000..52d62d2ea --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 30.01.23. +// + +#include "IBufferChunkVLK.h" diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h new file mode 100644 index 000000000..392f59149 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -0,0 +1,31 @@ +// +// Created by Deamon on 30.01.23. +// + +#ifndef AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H +#define AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H + + +#include "../../interface/buffers/IBufferChunk.h" +#include "GBufferVLK.h" + +template +class CBufferChunkVLK : public IBufferChunk { +public: + CBufferChunkVLK(const std::shared_ptr &mainBuffer) { + subBuffer = mainBuffer->getSubBuffer(sizeof(T)); + } + + T &getObject() override { + return *(T*)subBuffer->getPointer(); + }; + void save() override { + subBuffer->save(sizeof(T)); + }; +private: + std::shared_ptr subBuffer = nullptr; + +}; + + +#endif //AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index abba5c400..5b0163be6 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -13,7 +13,7 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDevice &device) : m_device(dynamic_cast< setsAvailable = 4096; std::array poolSizes = {}; - poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].descriptorCount = static_cast(uniformsAvailable); poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSizes[1].descriptorCount = static_cast(imageAvailable); @@ -31,11 +31,11 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDevice &device) : m_device(dynamic_cast< } } -std::shared_ptr GDescriptorPoolVLK::allocate(VkDescriptorSetLayout layout, int uniforms, int images) { - if (uniformsAvailable < uniforms || imageAvailable < images || setsAvailable < 1) return nullptr; +std::shared_ptr GDescriptorPoolVLK::allocate(std::shared_ptr &hDescriptorSetLayout) { + if (uniformsAvailable < hDescriptorSetLayout->getTotalUbos() || imageAvailable < hDescriptorSetLayout->getTotalImages() || setsAvailable < 1) return nullptr; constexpr int descSetCount = 1; - std::array descLayouts = {layout}; + std::array descLayouts = {hDescriptorSetLayout->getSetLayout()}; VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.pNext = NULL; @@ -52,25 +52,25 @@ std::shared_ptr GDescriptorPoolVLK::allocate(VkDescriptorSetLay throw std::runtime_error("failed to allocate descriptor sets!"); } - uniformsAvailable -= uniforms; - imageAvailable -= images; + uniformsAvailable -= hDescriptorSetLayout->getTotalUbos(); + imageAvailable -= hDescriptorSetLayout->getTotalImages(); setsAvailable -= 1; - std::shared_ptr result = std::make_shared(m_device, descriptorSet, this, uniforms, images); + std::shared_ptr result = std::make_shared(m_device, hDescriptorSetLayout, descriptorSet, this->shared_from_this()); return result; } -void GDescriptorPoolVLK::deallocate(GDescriptorSets *set) { +void GDescriptorPoolVLK::deallocate(GDescriptorSet *set) { auto descSet = set->getDescSet(); - auto imgCnt = set->getImageCount(); - auto uniformCnt = set->getImageCount(); + auto hDescriptorLayout = set->getSetLayout(); + auto h_this = this->shared_from_this(); - m_device.addDeallocationRecord([this, imgCnt, uniformCnt, descSet]() { - vkFreeDescriptorSets(m_device.getVkDevice(), m_descriptorPool, 1, &descSet); + m_device.addDeallocationRecord([h_this, hDescriptorLayout, descSet]() { + vkFreeDescriptorSets(h_this->m_device.getVkDevice(), h_this->m_descriptorPool, 1, &descSet); - imageAvailable+= imgCnt; - uniformsAvailable+= uniformCnt; - setsAvailable+=1; + h_this->imageAvailable+= hDescriptorLayout->getTotalImages(); + h_this->uniformsAvailable+= hDescriptorLayout->getTotalUbos(); + h_this->setsAvailable+=1; }); } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h index bd9bde4f8..5fd50eb5e 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -5,18 +5,19 @@ #ifndef AWEBWOWVIEWERCPP_GDESCRIPTORPOOLVLK_H #define AWEBWOWVIEWERCPP_GDESCRIPTORPOOLVLK_H -class GDescriptorSets; +class GDescriptorSet; #include "../../interface/IDevice.h" #include "../GDeviceVulkan.h" #include "GDescriptorSet.h" +#include "GDescriptorSetLayout.h" -class GDescriptorPoolVLK { +class GDescriptorPoolVLK : public std::enable_shared_from_this{ public: explicit GDescriptorPoolVLK(IDevice &device); - std::shared_ptr allocate(VkDescriptorSetLayout layout, int uniforms, int images); - void deallocate(GDescriptorSets *set); + std::shared_ptr allocate(std::shared_ptr &gDescriptorSetLayout); + void deallocate(GDescriptorSet *set); private: GDeviceVLK &m_device; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 6125789e4..3c3b9d699 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -4,16 +4,123 @@ #include "GDescriptorSet.h" -GDescriptorSets::GDescriptorSets(IDevice &device, VkDescriptorSet descriptorSet, - GDescriptorPoolVLK* parentPool, int uniforms, int images) - : m_device(dynamic_cast(device)), m_descriptorSet(descriptorSet), m_parentPool(parentPool), - m_uniforms(uniforms), m_images(images) { +#include "../textures/GTextureVLK.h" + +GDescriptorSet::GDescriptorSet(IDevice &device, + std::shared_ptr &hDescriptorSetLayout, + VkDescriptorSet descriptorSet, + std::shared_ptr parentPool) + : m_device(dynamic_cast(device)), + m_parentPool(parentPool), + m_descriptorSet(descriptorSet), + m_hDescriptorSetLayout(hDescriptorSetLayout) { } -GDescriptorSets::~GDescriptorSets() { +GDescriptorSet::~GDescriptorSet() { m_parentPool->deallocate(this); }; -void GDescriptorSets::writeToDescriptorSets(std::vector &descriptorWrites) { +void GDescriptorSet::update() { + auto update = beginUpdate(); +} + +// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkUpdateDescriptorSets.html : +// The operations described by pDescriptorWrites are performed first, followed by the operations described by pDescriptorCopies. +// +// So, writes first, copies second. T_T +void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites) { vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); + +// m_updateBitSet |= updatedBindsBitSet; +// +// for (int i = 0; updatedBindsBitSet.size(); i++) { +// m_updatesLeft[i] = GDeviceVLK::MAX_FRAMES_IN_FLIGHT; +// } +} + + +// ------------------------------------- +// Update Helper +// ------------------------------------- + +GDescriptorSet::SetUpdateHelper & +GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &textureVlk) { + VkDescriptorImageInfo &imageInfo = imageInfos.emplace_back(); + imageInfo = {}; + + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = textureVlk->texture.view; + imageInfo.sampler = textureVlk->texture.sampler; + + VkWriteDescriptorSet writeDescriptor = updates.emplace_back(); + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = m_set.getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = bindIndex; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pBufferInfo = nullptr; + writeDescriptor.pImageInfo = &imageInfo; + writeDescriptor.pTexelBufferView = nullptr; + + return *this; } + +//NOTE: Dynamic UBO still requires the buffer to be bound, but the offset can be served in runtime. +//And this current system of sub-allocation it seems, there is no real reason to rely on this. Sort of. +GDescriptorSet::SetUpdateHelper & +GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_ptr &buffer) { + VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); + bufferInfo = {}; + bufferInfo.buffer = buffer->getGPUBuffer(); + bufferInfo.offset = buffer->getOffset(); + bufferInfo.range = buffer->getSize(); + + + VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = m_set.getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = bindIndex; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pBufferInfo = &bufferInfo; + writeDescriptor.pImageInfo = nullptr; + writeDescriptor.pTexelBufferView = nullptr; + + return *this; +} + +GDescriptorSet::SetUpdateHelper & +GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr &buffer) { + VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); + bufferInfo = {}; + bufferInfo.buffer = buffer->getGPUBuffer(); + bufferInfo.offset = buffer->getOffset(); + bufferInfo.range = buffer->getSize(); + + + VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = m_set.getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = bindIndex; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pBufferInfo = &bufferInfo; + writeDescriptor.pImageInfo = nullptr; + writeDescriptor.pTexelBufferView = nullptr; + + return *this; +} + +GDescriptorSet::SetUpdateHelper & +GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptr &buffer) { + throw "unimplemented"; + + return *this; +} + diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 72b38b8cd..0fccdd63d 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -9,27 +9,64 @@ class GDeviceVLK; class GDescriptorPoolVLK; #include +#include #include "../../interface/IDevice.h" #include "../GDeviceVulkan.h" +#include "../buffers/IBufferVLK.h" +#include "GDescriptorSetLayout.h" - -class GDescriptorSets { +class GDescriptorSet { public: - explicit GDescriptorSets(IDevice &device, VkDescriptorSet descriptorSet, GDescriptorPoolVLK* parentPool, int uniforms, int images); - ~GDescriptorSets(); + static const constexpr int MAX_BINDPOINT_NUMBER = 16; + + explicit GDescriptorSet(IDevice &device, std::shared_ptr &hDescriptorSetLayout, VkDescriptorSet descriptorSet, std::shared_ptr parentPool); + ~GDescriptorSet(); + void update(); void writeToDescriptorSets(std::vector &descriptorWrites); + const std::shared_ptr getSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() {return m_descriptorSet;} - int getUniformCount() {return m_uniforms;} - int getImageCount() {return m_images;} + + class SetUpdateHelper { + public: + SetUpdateHelper(GDescriptorSet &set) : m_set(set) {} + + SetUpdateHelper& ubo(int bindIndex, const std::shared_ptr &buffer); + + SetUpdateHelper& ubo_dynamic(int bindIndex, const std::shared_ptr &buffer); + + SetUpdateHelper& ssbo(int bindIndex, const std::shared_ptr &buffer); + + //TODO: add version of this array texture case (aka bindless) + SetUpdateHelper& texture(int bindIndex, const std::shared_ptr &textureVlk); + + std::bitset m_updateBitSet = 0; + + private: + GDescriptorSet &m_set; + std::vector imageInfos; + std::vector bufferInfos; + + std::vector updates; + }; + + SetUpdateHelper beginUpdate() { + return SetUpdateHelper(*this); + }; + private: GDeviceVLK &m_device; VkDescriptorSet m_descriptorSet; - GDescriptorPoolVLK *m_parentPool; - int m_uniforms = 0; - int m_images = 0; + std::shared_ptr m_parentPool; + + std::shared_ptr m_hDescriptorSetLayout; + +// Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea +// //Defines amount of frames that the updates has to be copied from previous frame +// std::array m_updatesLeft = {0}; +// std::bitset m_updateBitSet = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp new file mode 100644 index 000000000..43325febb --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -0,0 +1,98 @@ +// +// Created by Deamon on 03.02.23. +// + +#include +#include "GDescriptorSetLayout.h" + +GDescriptorSetLayout::GDescriptorSetLayout(std::shared_ptr &device, const std::vector &metaDatas, int setIndex) : m_device(device) { + //Create Layout + std::unordered_map shaderLayoutBindings; + + for (const auto p_metaData : metaDatas) { + auto const &metaData = *p_metaData; + + VkShaderStageFlagBits vkStageFlag = [](ShaderStage stage) -> VkShaderStageFlagBits { + switch (stage) { + case ShaderStage::Vertex: return VK_SHADER_STAGE_VERTEX_BIT; break; + case ShaderStage::Fragment: return VK_SHADER_STAGE_FRAGMENT_BIT; break; + case ShaderStage::RayGenerate: return VK_SHADER_STAGE_RAYGEN_BIT_KHR; break; + case ShaderStage::RayAnyHit: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break; + case ShaderStage::RayClosestHit: return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; break; + case ShaderStage::RayMiss: return VK_SHADER_STAGE_MISS_BIT_KHR; break; + default: + return (VkShaderStageFlagBits)0; + } + }(metaData.stage); + + + + for (int i = 0; i < p_metaData->uboBindings.size(); i++) { + auto &uboBinding = p_metaData->uboBindings[i]; + + if (uboBinding.set != setIndex) return; + + auto it = shaderLayoutBindings.find(uboBinding.binding); + if (it != std::end( shaderLayoutBindings )) { + it->second.stageFlags |= vkStageFlag; + if (it->second.descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + std::cerr << "Type mismatch for ubo in GDescriptorSetLayout" << std::endl; + throw std::runtime_error("types mismatch"); + } + } else { + VkDescriptorSetLayoutBinding uboLayoutBinding = {}; + uboLayoutBinding.binding = uboBinding.binding; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.pImmutableSamplers = nullptr; + uboLayoutBinding.stageFlags = vkStageFlag; + + shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); + m_totalUbos++; + } + } + + for (int i = 0; i < p_metaData->imageBindings.size(); i++) { + auto &imageBinding = p_metaData->imageBindings[i]; + + if (imageBinding.set != setIndex) return; + + auto it = shaderLayoutBindings.find(imageBinding.binding); + if (it != std::end( shaderLayoutBindings )) { + it->second.stageFlags |= vkStageFlag; + if (it->second.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { + std::cerr << "Type mismatch for image in GDescriptorSetLayout" << std::endl; + throw std::runtime_error("types mismatch"); + } + } else { + VkDescriptorSetLayoutBinding imageLayoutBinding = {}; + imageLayoutBinding.binding = p_metaData->imageBindings[i].binding; + imageLayoutBinding.descriptorCount = 1; + imageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + imageLayoutBinding.pImmutableSamplers = nullptr; + imageLayoutBinding.stageFlags = vkStageFlag; + + shaderLayoutBindings.insert({imageBinding.binding, imageLayoutBinding}); + m_totalImages++; + } + } + } + + std::vector layouts(shaderLayoutBindings.size()); + std::transform(shaderLayoutBindings.begin(), shaderLayoutBindings.end(), layouts.begin(), [](auto &pair){return pair.second;}); + + + //Create VK descriptor layout + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = shaderLayoutBindings.size(); + layoutInfo.pBindings = (shaderLayoutBindings.size() > 0) ? &shaderLayoutBindings[0] : nullptr; + + if (vkCreateDescriptorSetLayout(m_device->getVkDevice(), &layoutInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor set layout!"); + } +} + +GDescriptorSetLayout::~GDescriptorSetLayout() { + vkDestroyDescriptorSetLayout(m_device->getVkDevice(), m_descriptorSetLayout, nullptr); +} diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h new file mode 100644 index 000000000..233a9eabb --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -0,0 +1,35 @@ +// +// Created by Deamon on 03.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_GDESCRIPTORSETLAYOUT_H +#define AWEBWOWVIEWERCPP_GDESCRIPTORSETLAYOUT_H + +#include + +class GDescriptorSetLayout; + +#include "../GDeviceVulkan.h" +#include "../../../engine/shader/ShaderDefinitions.h" + +class GDescriptorSetLayout { +public: + GDescriptorSetLayout(std::shared_ptr &device, const std::vector &metaData, int setIndex); + + ~GDescriptorSetLayout(); + + const VkDescriptorSetLayout getSetLayout() {return m_descriptorSetLayout;} ; + const std::unordered_map getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; + int getTotalUbos() { return m_totalUbos; }; + int getTotalImages() { return m_totalImages; }; +private: + std::unordered_map m_shaderLayoutBindings; + VkDescriptorSetLayout m_descriptorSetLayout; + int m_totalImages = 0; + int m_totalUbos = 0; + + std::shared_ptr m_device; +}; + + +#endif //AWEBWOWVIEWERCPP_GDESCRIPTORSETLAYOUT_H diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index c5a8977bc..ca2af8a4f 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -10,7 +10,7 @@ void ISimpleMaterialVLK::createImageDescriptorSet() { auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto descLayout = shaderVLK->getImageDescriptorLayout(); - imageDescriptorSets = { m_device->createDescriptorSet(descLayout, 0, shaderVLK->getTextureCount()) }; + imageDescriptorSets = { m_device->createDescriptorSet(descLayout) }; { std::vector descriptorWrites; @@ -107,7 +107,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, auto uboSetLayout = shaderLayout.setLayouts[0]; if (ubos.size() != uboSetLayout.uboBindings.length) { - std::cerr << "not enough ubos for shaderName = " << shaderVLK->getShaderName() << std::endl; + std::cerr << "not enough ubos for shaderName = " << shaderVLK->getShaderCombinedName() << std::endl; } for (unsigned int i = uboSetLayout.uboBindings.start; i <= uboSetLayout.uboBindings.end; i++) { auto it = uboSetLayout.uboSizesPerBinding.find(i); @@ -115,7 +115,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, auto uboIndex = i - uboSetLayout.uboBindings.start; if (ubos[uboIndex] == nullptr) { std::cerr << "UBO is not set for " - << "shader = " << shaderVLK->getShaderName() + << "shader = " << shaderVLK->getShaderCombinedName() << " set = " << 1 << " binding" << i << std::endl; @@ -123,7 +123,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, if (it->second != ubos[uboIndex]->getSize()) { std::cout << "buffers missmatch! for" - << " shaderName = " << shaderVLK->getShaderName() + << " shaderName = " << shaderVLK->getShaderCombinedName() << " set = " << 1 << " binding = " << i << " expected size " << (it->second) @@ -136,7 +136,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, auto imageSetLayout = shaderLayout.setLayouts[1]; if (imageSetLayout.imageBindings.length != textures.size()) { std::cout << "image count mismatch! for" - << " shaderName = " << shaderVLK->getShaderName() + << " shaderName = " << shaderVLK->getShaderCombinedName() << " set = " << 1 << " expected count " << uboSetLayout.imageBindings.length << ", provided count = " << textures.size() diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 0091df9ce..3f2759b54 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -15,7 +15,9 @@ class ISimpleMaterialVLK : public IMaterial { public: explicit ISimpleMaterialVLK(const HGDeviceVLK &device, const std::string &vertexShader, const std::string &pixelShader, - const std::vector> &ubos, const std::vector> &textures); + + const std::vector> &ubos, + const std::vector> &textures); ~ISimpleMaterialVLK() override = default; HGShaderPermutation getShader() { @@ -31,9 +33,9 @@ class ISimpleMaterialVLK : public IMaterial { std::vector m_textures = {}; std::vector> m_ubos = {}; - std::vector> imageDescriptorSets; - std::vector> uboDescriptorSets; - std::vector> ssboDescriptorSets; + std::vector> imageDescriptorSets; + std::vector> uboDescriptorSets; + std::vector> ssboDescriptorSets; HGShaderPermutation m_shader; }; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index 5106e7ecb..4638af075 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -4,7 +4,8 @@ #include "GM2MeshVLK.h" -GM2MeshVLK::GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate) : GMeshVLK(device, meshTemplate){ +GM2MeshVLK::GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate, + const HMaterialVLK &material) : GMeshVLK(device, meshTemplate, material){ m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ; } diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index d03a5c1a7..5ad71b8e4 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -10,7 +10,8 @@ class GM2MeshVLK : public GMeshVLK, public IM2Mesh { friend class GDeviceVLK; protected: - GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate); + GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate, + const HMaterialVLK &material); public: void setLayer(int layer) override; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index c36128a2d..1c89584bc 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -9,8 +9,9 @@ #include "../shaders/GShaderPermutationVLK.h" GMeshVLK::GMeshVLK(IDevice &device, - const gMeshTemplate &meshTemplate -) : m_device(dynamic_cast(device)), m_meshType(meshTemplate.meshType) { + const gMeshTemplate &meshTemplate, + const HMaterialVLK &material +) : m_device(dynamic_cast(device)), m_meshType(meshTemplate.meshType), m_material(material) { m_bindings = meshTemplate.bindings; @@ -32,14 +33,13 @@ GMeshVLK::GMeshVLK(IDevice &device, m_start = meshTemplate.start; m_end = meshTemplate.end; m_element = meshTemplate.element; - } //Works under assumption that meshes do not change the renderpass, on which they are rendered, too often std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ) { if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, - material->getShader(), renderPass, m_element, + m_material->getShader(), renderPass, m_element, m_backFaceCulling, m_triCCW, m_blendMode, m_depthCulling, m_depthWrite, invertedZ); diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index c1b0aa399..42fa5be70 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -13,9 +13,10 @@ class GMeshVLK : public IMesh { friend class GDeviceVLK; -protected: +public: explicit GMeshVLK(IDevice &device, - const gMeshTemplate &meshTemplate + const gMeshTemplate &meshTemplate, + const HMaterialVLK &material ); public: @@ -26,17 +27,17 @@ class GMeshVLK : public IMesh { public: std::shared_ptr getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ); - HMaterialVLK material; + auto material() const -> const HMaterialVLK& { return m_material; } protected: MeshType m_meshType; + bool m_isTransparent = false; int8_t m_depthWrite; int8_t m_depthCulling; int8_t m_backFaceCulling; - int8_t m_triCCW = 1; + int8_t m_triCCW = 1; EGxBlendEnum m_blendMode; - bool m_isTransparent = false; int8_t m_isScissorsEnabled = -1; std::array m_scissorOffset = {0,0}; @@ -55,8 +56,7 @@ class GMeshVLK : public IMesh { std::shared_ptr m_lastPipelineForRenderPass; private: GDeviceVLK &m_device; - - + HMaterialVLK m_material; }; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.cpp deleted file mode 100644 index 4aa27a3ef..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#include "GAdtShaderPermutationVLK.h" -#include -#include - - -GAdtShaderPermutationVLK::GAdtShaderPermutationVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, device) {} - diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.h deleted file mode 100644 index f4f10c86d..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GAdtShaderPermutationVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GAdtSHADERPERMUTATIONVLK_H -#define AWEBWOWVIEWERCPP_GAdtSHADERPERMUTATIONVLK_H - -#include "GShaderPermutationVLK.h" - -class GAdtShaderPermutationVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GAdtShaderPermutationVLK() override {}; - -protected: - explicit GAdtShaderPermutationVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 9; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GM2PARTICLESHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp deleted file mode 100644 index dc3b936d8..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by Deamon on 1/7/2021. -// - -#include "GDrawBoundingBoxVLK.h" - -GDrawBoundingBoxVLK::GDrawBoundingBoxVLK(std::string &shaderName, IDevice *device) : GShaderPermutationVLK(shaderName, - device) { - -} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h deleted file mode 100644 index 3da468923..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GDrawBoundingBoxVLK.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Created by Deamon on 1/7/2021. -// - -#ifndef AWEBWOWVIEWERCPP_GDRAWBOUNDINGBOXVLK_H -#define AWEBWOWVIEWERCPP_GDRAWBOUNDINGBOXVLK_H - -#include "GShaderPermutationVLK.h" - -class GDrawBoundingBoxVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GDrawBoundingBoxVLK() override {}; - -protected: - explicit GDrawBoundingBoxVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 0; - }; -}; - -#endif //AWEBWOWVIEWERCPP_GDRAWBOUNDINGBOXVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.cpp deleted file mode 100644 index 08cf9ef7b..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// Created by Deamon on 12/13/2020. -// - -#include "GFFXGlowVLK.h" - -namespace GFFXGlowVLKPrivate { - auto vertShaderName = std::string("drawQuad"); - auto fragShaderName = std::string("ffxglow"); -} - -GFFXGlowVLK::GFFXGlowVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, GFFXGlowVLKPrivate::vertShaderName, GFFXGlowVLKPrivate::fragShaderName, device) { -} diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.h deleted file mode 100644 index 0469ad00c..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GFFXGlowVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 12/13/2020. -// - -#ifndef AWEBWOWVIEWERCPP_GFFXGLOWVLK_H -#define AWEBWOWVIEWERCPP_GFFXGLOWVLK_H - -#include "GShaderPermutationVLK.h" - -class GFFXGlowVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GFFXGlowVLK() override {}; - -protected: - explicit GFFXGlowVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 2; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GFFXGLOWVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp deleted file mode 100644 index a737a39a2..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by Deamon on 12/13/2020. -// - -#include "GFFXgauss4VLK.h" - -namespace GFFXgauss4VLKPrivate { - auto vertShaderName = std::string("drawQuad"); - auto fragShaderName = std::string("ffxgauss4"); -} - -GFFXgauss4VLK::GFFXgauss4VLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, GFFXgauss4VLKPrivate::vertShaderName, GFFXgauss4VLKPrivate::fragShaderName, device) { - - -} diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.h deleted file mode 100644 index 5d7ae1db5..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GFFXgauss4VLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 12/13/2020. -// - -#ifndef AWEBWOWVIEWERCPP_GFFXGAUSS4VLK_H -#define AWEBWOWVIEWERCPP_GFFXGAUSS4VLK_H - -#include "GShaderPermutationVLK.h" - -class GFFXgauss4VLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GFFXgauss4VLK() override {}; - -protected: - explicit GFFXgauss4VLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 1; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GFFXGAUSS4VLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.cpp deleted file mode 100644 index 0dde60266..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Deamon on 26.03.2020. -// - -#include "GImguiShaderPermutation.h" -#include -#include - -GImguiShaderPermutation::GImguiShaderPermutation(std::string &shaderName, IDevice *device) : GShaderPermutationVLK( - shaderName, device) { - -} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.h b/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.h deleted file mode 100644 index 9dccf56c7..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GImguiShaderPermutation.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 26.03.2020. -// - -#ifndef AWEBWOWVIEWERCPP_GIMGUISHADERPERMUTATION_H -#define AWEBWOWVIEWERCPP_GIMGUISHADERPERMUTATION_H - -#include "GShaderPermutationVLK.h" - -class GImguiShaderPermutation : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GImguiShaderPermutation() override {}; - -protected: - explicit GImguiShaderPermutation(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 1; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GIMGUISHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.cpp deleted file mode 100644 index 40a144ec5..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#include "GM2ParticleShaderPermutationVLK.h" -#include -#include - - -GM2ParticleShaderPermutationVLK::GM2ParticleShaderPermutationVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, device) {} - diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.h deleted file mode 100644 index bca40efa2..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2ParticleShaderPermutationVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GM2PARTICLESHADERPERMUTATION_H -#define AWEBWOWVIEWERCPP_GM2PARTICLESHADERPERMUTATION_H - -#include "GShaderPermutationVLK.h" - -class GM2ParticleShaderPermutationVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GM2ParticleShaderPermutationVLK() override {}; - -protected: - explicit GM2ParticleShaderPermutationVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 3; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GM2PARTICLESHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.cpp deleted file mode 100644 index 4e3229cd6..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#include "GM2RibbonShaderPermutationVLK.h" -#include -#include - - -GM2RibbonShaderPermutationVLK::GM2RibbonShaderPermutationVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, device) {} - diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.h deleted file mode 100644 index fa0df8cd5..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2RibbonShaderPermutationVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GM2RIBBONSHADERPERMUTATIONVLK_H -#define AWEBWOWVIEWERCPP_GM2RIBBONSHADERPERMUTATIONVLK_H - -#include "GShaderPermutationVLK.h" - -class GM2RibbonShaderPermutationVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GM2RibbonShaderPermutationVLK() override {}; - -protected: - explicit GM2RibbonShaderPermutationVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 3; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GM2RIBBONSHADERPERMUTATIONVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.cpp deleted file mode 100644 index 0cfa88582..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#include "GM2ShaderPermutationVLK.h" -#include -#include - - -GM2ShaderPermutationVLK::GM2ShaderPermutationVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, device) {} - diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.h deleted file mode 100644 index 44477e6a8..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GM2ShaderPermutationVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 7/8/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GM2SHADERPERMUTATION_H -#define AWEBWOWVIEWERCPP_GM2SHADERPERMUTATION_H - -#include "GShaderPermutationVLK.h" - -class GM2ShaderPermutationVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GM2ShaderPermutationVLK() override {}; - -protected: - explicit GM2ShaderPermutationVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 4; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GM2SHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index ebdb91177..d0de210d4 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -43,99 +43,24 @@ VkShaderModule GShaderPermutationVLK::createShaderModule(const std::vector return shaderModule; } -GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderName, IDevice * device) : - m_device(dynamic_cast(device)), m_shaderName(shaderName), m_shaderNameVert(shaderName), m_shaderNameFrag(shaderName){ - -} - -GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderName, std::string &shaderVertName, std::string &shaderFragName, - IDevice *device) : - m_device(dynamic_cast(device)), m_shaderName(shaderName), m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName){ +GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, + const std::shared_ptr &device) : + m_device(device), m_combinedName(shaderVertName + " "+ shaderFragName), m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName){ } void GShaderPermutationVLK::createUBODescriptorLayout() { - std::unordered_map shaderLayoutBindings; - for (int i = 0; i < vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = vertShaderMeta->uboBindings[i]; - - auto it = shaderLayoutBindings.find(uboVertBinding.binding); - if (it != std::end( shaderLayoutBindings )) { - it->second.stageFlags |= VK_SHADER_STAGE_VERTEX_BIT; - } else { - VkDescriptorSetLayoutBinding uboLayoutBinding = {}; - uboLayoutBinding.binding = uboVertBinding.binding; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - shaderLayoutBindings.insert({uboVertBinding.binding, uboLayoutBinding}); - } - - hasBondUBO[uboVertBinding.binding] = true; - - } - for (int i = 0; i < fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = fragShaderMeta->uboBindings[i]; - - auto it = shaderLayoutBindings.find(uboFragBinding.binding); - if (it != std::end( shaderLayoutBindings )) { - it->second.stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT; - } else { - VkDescriptorSetLayoutBinding uboLayoutBinding = {}; - uboLayoutBinding.binding = uboFragBinding.binding; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - - shaderLayoutBindings.insert({uboFragBinding.binding, uboLayoutBinding}); - } - - hasBondUBO[uboFragBinding.binding] = true; - } - - std::vector shaderLayoutBindingsVec; - shaderLayoutBindingsVec.reserve(shaderLayoutBindings.size()); - for(auto elem : shaderLayoutBindings) { - shaderLayoutBindingsVec.push_back(elem.second); - } - - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.pNext = NULL; - layoutInfo.bindingCount = shaderLayoutBindingsVec.size(); - layoutInfo.pBindings = &shaderLayoutBindingsVec[0]; + const constexpr int UBO_SET_INDEX = 0; - if (vkCreateDescriptorSetLayout(m_device->getVkDevice(), &layoutInfo, nullptr, &uboDescriptorSetLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor set layout!"); - } + std::vector metas = {fragShaderMeta, vertShaderMeta}; + hUboDescriptorSetLayout = std::make_shared(m_device, metas, UBO_SET_INDEX); } void GShaderPermutationVLK::createImageDescriptorLayout() { - std::vector shaderLayoutBindings; - - for (int i = 0; i < getTextureCount(); i++) { - VkDescriptorSetLayoutBinding imageLayoutBinding = {}; - imageLayoutBinding.binding = getTextureBindingStart()+i; - imageLayoutBinding.descriptorCount = 1; - imageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - imageLayoutBinding.pImmutableSamplers = nullptr; - imageLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT; - - shaderLayoutBindings.push_back(imageLayoutBinding); - } - - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = shaderLayoutBindings.size(); - layoutInfo.pBindings = (shaderLayoutBindings.size() > 0) ? &shaderLayoutBindings[0] : nullptr; - - if (vkCreateDescriptorSetLayout(m_device->getVkDevice(), &layoutInfo, nullptr, &imageDescriptorSetLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor set layout!"); - } + const constexpr int IMAGE_SET_INDEX = 0; + std::vector metas = {fragShaderMeta, vertShaderMeta}; + hImageDescriptorSetLayout = std::make_shared(m_device, metas, IMAGE_SET_INDEX); } void GShaderPermutationVLK::updateDescriptorSet(int index) { @@ -205,7 +130,7 @@ void GShaderPermutationVLK::updateDescriptorSet(int index) { void GShaderPermutationVLK::createUboDescriptorSets() { for (int j = 0; j < 4; j++) { std::vector descriptorWrites; - uboDescriptorSets[j] = m_device->createDescriptorSet(uboDescriptorSetLayout, 5, 0); + uboDescriptorSets[j] = m_device->createDescriptorSet(hUboDescriptorSetLayout); updateDescriptorSet(j); } } @@ -285,6 +210,7 @@ void GShaderPermutationVLK::createShaderLayout() { << " binding = " << imageVertBinding.binding << " in " << m_shaderNameVert << " and " << m_shaderNameFrag << std::endl; + throw std::runtime_error("types mismatch"); } makeMin(setLayout.imageBindings.start, imageVertBinding.binding); @@ -300,6 +226,7 @@ void GShaderPermutationVLK::createShaderLayout() { << " binding = " << imageFragBinding.binding << " in " << m_shaderNameVert << " and " << m_shaderNameFrag << std::endl; + throw std::runtime_error("types mismatch"); } makeMin(setLayout.imageBindings.start, imageFragBinding.binding); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index b7a25bfdd..173284378 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -27,12 +27,13 @@ class GShaderPermutationVLK : public IShaderPermutation { friend class GDeviceVLK; public: + explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device); ~GShaderPermutationVLK() override {}; VkShaderModule getVertexModule() {return vertShaderModule;} VkShaderModule getFragmentModule() {return fragShaderModule;} - VkDescriptorSetLayout getImageDescriptorLayout() {return imageDescriptorSetLayout;} - VkDescriptorSetLayout getUboDescriptorLayout() {return uboDescriptorSetLayout;} + const std::shared_ptr getImageDescriptorLayout() {return hImageDescriptorSetLayout;} + const std::shared_ptr getUboDescriptorLayout() {return hUboDescriptorSetLayout;} virtual int getTextureBindingStart(); virtual int getTextureCount(); @@ -40,8 +41,8 @@ class GShaderPermutationVLK : public IShaderPermutation { const shaderMetaData *fragShaderMeta; const shaderMetaData *vertShaderMeta; - std::string getShaderName() { - return m_shaderName; + std::string getShaderCombinedName() { + return m_combinedName; } const CombinedShaderLayout &getShaderLayout() { @@ -49,9 +50,6 @@ class GShaderPermutationVLK : public IShaderPermutation { }; protected: - explicit GShaderPermutationVLK(std::string &shaderName, IDevice *device); - explicit GShaderPermutationVLK(std::string &shaderName, std::string &shaderVertName, std::string &shaderFragName, IDevice *device); - VkShaderModule createShaderModule(const std::vector& code); void compileShader(const std::string &vertExtraDefStrings, const std::string &fragExtraDefStrings) override; @@ -61,22 +59,24 @@ class GShaderPermutationVLK : public IShaderPermutation { VkShaderModule fragShaderModule; - VkDescriptorSetLayout uboDescriptorSetLayout; - VkDescriptorSetLayout imageDescriptorSetLayout; + std::shared_ptr hUboDescriptorSetLayout; + std::shared_ptr hImageDescriptorSetLayout; - std::array, 4> uboDescriptorSets = {nullptr}; + std::array, 4> uboDescriptorSets = {nullptr}; - GDeviceVLK *m_device; + std::shared_ptr m_device; private: //Used only for logging - std::string m_shaderName; + std::string m_combinedName; //Used for getting SPIRV std::string m_shaderNameVert; std::string m_shaderNameFrag; + + CombinedShaderLayout shaderLayout; void createUBODescriptorLayout(); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.cpp deleted file mode 100644 index 6cb0cab5b..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by Deamon on 11/28/2020. -// - -#include "GSkyConusShaderVLK.h" - -GSkyConusShaderVLK::GSkyConusShaderVLK(std::string &shaderName, IDevice *device): - GShaderPermutationVLK(shaderName, device) { - -} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.h deleted file mode 100644 index e6000c3cf..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GSkyConusShaderVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 11/28/2020. -// - -#ifndef AWEBWOWVIEWERCPP_GSKYCONUSSHADERVLK_H -#define AWEBWOWVIEWERCPP_GSKYCONUSSHADERVLK_H - -#include "GShaderPermutationVLK.h" - -class GSkyConusShaderVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GSkyConusShaderVLK() override {}; - -protected: - explicit GSkyConusShaderVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 0; - }; - int getTextureCount() override { - return 0; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GSKYCONUSSHADERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.cpp deleted file mode 100644 index 0459c0780..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by Deamon on 7/27/2018. -// - -#include "GWMOShaderPermutationVLK.h" - - -GWMOShaderPermutationVLK::GWMOShaderPermutationVLK(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName,device) {} diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.h deleted file mode 100644 index 538d761ae..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWMOShaderPermutationVLK.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by Deamon on 7/27/2018. -// - -#ifndef AWEBWOWVIEWERCPP_GWMOSHADERPERMUTATIONVLK_H -#define AWEBWOWVIEWERCPP_GWMOSHADERPERMUTATIONVLK_H - -#include "GShaderPermutationVLK.h" - -class GWMOShaderPermutationVLK : public GShaderPermutationVLK { - friend class GDeviceVLK; -protected: - explicit GWMOShaderPermutationVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 9; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GWMOSHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.cpp deleted file mode 100644 index 8ea6b7fcc..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by Deamon on 26.03.2020. -// - -#include "GWaterShaderPermutation.h" - -GWaterShaderPermutation::GWaterShaderPermutation(std::string &shaderName, IDevice *device) : - GShaderPermutationVLK(shaderName, device) {} - diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.h b/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.h deleted file mode 100644 index 62854fcfd..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWaterShaderPermutation.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by Deamon on 26.03.2020. -// - -#ifndef AWEBWOWVIEWERCPP_GWATERSHADERPERMUTATION_H -#define AWEBWOWVIEWERCPP_GWATERSHADERPERMUTATION_H - - -#include "GShaderPermutationVLK.h" - -class GWaterShaderPermutation: public GShaderPermutationVLK { - friend class GDeviceVLK; -public: - ~GWaterShaderPermutation() override {}; - -protected: - explicit GWaterShaderPermutation(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 1; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GWATERSHADERPERMUTATION_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp deleted file mode 100644 index 44ab3449b..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by Deamon on 1/31/2021. -// - -#include "GWaterfallShaderVLK.h" - -GWaterfallShaderVLK::GWaterfallShaderVLK(std::string &shaderName, IDevice *device): - GShaderPermutationVLK(shaderName, device) { - -} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.h deleted file mode 100644 index 7e4c4b9f7..000000000 --- a/wowViewerLib/src/gapi/vulkan/shaders/GWaterfallShaderVLK.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by Deamon on 1/31/2021. -// - -#ifndef AWEBWOWVIEWERCPP_GWATERFALLSHADERVLK_H -#define AWEBWOWVIEWERCPP_GWATERFALLSHADERVLK_H - -#include "GShaderPermutationVLK.h" - -class GWaterfallShaderVLK : public GShaderPermutationVLK{ - friend class GDeviceVLK; -public: - ~GWaterfallShaderVLK() override {}; - -protected: - explicit GWaterfallShaderVLK(std::string &shaderName, IDevice *device); -public: - int getTextureBindingStart() override { - return 5; - }; - int getTextureCount() override { - return 5; - }; -}; - - -#endif //AWEBWOWVIEWERCPP_GWATERFALLSHADERVLK_H diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 67bb7edd0..e81511a2e 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -148,6 +148,6 @@ void SceneComposer::draw(HFrameScenario frameScenario) { } - m_apiContainer->hDevice->submitDrawCommands(); +// m_apiContainer->hDevice->submitDrawCommands(); m_apiContainer->hDevice->increaseFrameNumber(); } From 4b4670e891ac625090e5f011704835e5509636e4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 5 Feb 2023 09:24:37 +0200 Subject: [PATCH 022/212] Descriptor set updates --- .../src/gapi/vulkan/GDeviceVulkan.cpp | 36 +++++--- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 4 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 10 +-- .../descriptorSets/GDescriptorPoolVLK.h | 4 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 77 +++++++++++++--- .../vulkan/descriptorSets/GDescriptorSet.h | 33 +++++-- .../descriptorSets/GDescriptorSetLayout.h | 4 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 87 ++++++------------- .../vulkan/materials/ISimpleMaterialVLK.h | 10 ++- .../vulkan/shaders/GShaderPermutationVLK.cpp | 3 - .../vulkan/shaders/GShaderPermutationVLK.h | 6 +- 11 files changed, 164 insertions(+), 110 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 5130ee90c..aa43d1fba 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1425,22 +1425,36 @@ HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, } -std::shared_ptr -GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescriptorSetLayout) { +VkDescriptorSet +GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) { //1. Try to allocate from existing sets - std::shared_ptr descriptorSet; - for (size_t i = 0; i < m_descriptorPools.size(); i++) { - descriptorSet = m_descriptorPools[i]->allocate(hDescriptorSetLayout); - if (descriptorSet != nullptr) - return descriptorSet; + if (m_descriptorPools.size() == 0) { + std::shared_ptr newPool = std::make_shared(*this); + m_descriptorPools.push_back(newPool); } - //2. Create new descriptor set and allocate from it - GDescriptorPoolVLK * newPool = new GDescriptorPoolVLK(*this); - m_descriptorPools.push_back(newPool); + desciptorPool = m_descriptorPools[0]; + return m_descriptorPools[0]->allocate(hDescriptorSetLayout); +// +// for (size_t i = 0; i < m_descriptorPools.size(); i++) { +// descriptorSet = m_descriptorPools[i]->allocate(hDescriptorSetLayout); +// if (descriptorSet != nullptr) +// return descriptorSet; +// } +// +// //2. Create new descriptor set and allocate from it +// GDescriptorPoolVLK * newPool = new GDescriptorPoolVLK(*this); +// m_descriptorPools.push_back(newPool); +// +// return newPool->allocate(hDescriptorSetLayout); +} + +std::shared_ptr +GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescriptorSetLayout) { + std::shared_ptr result = std::make_shared(this->shared_from_this(), hDescriptorSetLayout); - return newPool->allocate(hDescriptorSetLayout); + return result; } //void GDeviceVLK::internalDrawStageAndDeps(HDrawStage drawStage) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 7f4392b78..d5a4e4f82 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -138,6 +138,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &hDescriptorSetLayout, std::shared_ptr &desciptorPool); std::shared_ptr createDescriptorSet(std::shared_ptr &hDescriptorSetLayout); virtual VkDevice getVkDevice() { @@ -346,7 +348,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this uploadSemaphores; std::vector uploadFences; - std::vector m_descriptorPools; + std::vector> m_descriptorPools; VmaAllocator vmaAllocator; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index 5b0163be6..fc37d2a1c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -31,7 +31,7 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDevice &device) : m_device(dynamic_cast< } } -std::shared_ptr GDescriptorPoolVLK::allocate(std::shared_ptr &hDescriptorSetLayout) { +VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptr &hDescriptorSetLayout) { if (uniformsAvailable < hDescriptorSetLayout->getTotalUbos() || imageAvailable < hDescriptorSetLayout->getTotalImages() || setsAvailable < 1) return nullptr; constexpr int descSetCount = 1; @@ -56,13 +56,10 @@ std::shared_ptr GDescriptorPoolVLK::allocate(std::shared_ptrgetTotalImages(); setsAvailable -= 1; - std::shared_ptr result = std::make_shared(m_device, hDescriptorSetLayout, descriptorSet, this->shared_from_this()); - return result; + return descriptorSet; } -void GDescriptorPoolVLK::deallocate(GDescriptorSet *set) { - auto descSet = set->getDescSet(); - auto hDescriptorLayout = set->getSetLayout(); +void GDescriptorPoolVLK::deallocate(const std::shared_ptr &hDescriptorLayout, VkDescriptorSet descSet) { auto h_this = this->shared_from_this(); m_device.addDeallocationRecord([h_this, hDescriptorLayout, descSet]() { @@ -72,5 +69,4 @@ void GDescriptorPoolVLK::deallocate(GDescriptorSet *set) { h_this->uniformsAvailable+= hDescriptorLayout->getTotalUbos(); h_this->setsAvailable+=1; }); - } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h index 5fd50eb5e..a6d23a927 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -16,8 +16,8 @@ class GDescriptorPoolVLK : public std::enable_shared_from_this allocate(std::shared_ptr &gDescriptorSetLayout); - void deallocate(GDescriptorSet *set); + VkDescriptorSet allocate(const std::shared_ptr &gDescriptorSetLayout); + void deallocate(const std::shared_ptr &hDescriptorLayout, VkDescriptorSet descSet); private: GDeviceVLK &m_device; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 3c3b9d699..7f615e33d 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -6,20 +6,31 @@ #include "../textures/GTextureVLK.h" -GDescriptorSet::GDescriptorSet(IDevice &device, - std::shared_ptr &hDescriptorSetLayout, - VkDescriptorSet descriptorSet, - std::shared_ptr parentPool) - : m_device(dynamic_cast(device)), - m_parentPool(parentPool), - m_descriptorSet(descriptorSet), - m_hDescriptorSetLayout(hDescriptorSetLayout) { +GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout) + : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { + m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); } GDescriptorSet::~GDescriptorSet() { - m_parentPool->deallocate(this); + m_parentPool->deallocate(m_hDescriptorSetLayout, getDescSet()); }; +GDescriptorSet::SetUpdateHelper GDescriptorSet::beginUpdate() { + if (!m_firstUpdate) { + //In this implementation of descriptor set, the descriptor set is getting free'd on update + //and new one is created + auto l_descriptorSet = m_descriptorSet; + auto l_parentPool = m_parentPool; + auto l_hDescriptorSetLayout = m_hDescriptorSetLayout; + m_device->addDeallocationRecord([l_parentPool, l_descriptorSet, l_hDescriptorSetLayout]() { + l_parentPool->deallocate(l_hDescriptorSetLayout, l_descriptorSet); + }); + + m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); + } + return SetUpdateHelper(*this, boundDescriptors); +} + void GDescriptorSet::update() { auto update = beginUpdate(); } @@ -29,7 +40,9 @@ void GDescriptorSet::update() { // // So, writes first, copies second. T_T void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites) { - vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); + vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); + + m_firstUpdate = false; // m_updateBitSet |= updatedBindsBitSet; // @@ -45,6 +58,15 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &textureVlk) { + if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { + std::cerr << "descriptor mismatch for image" << std::endl; + throw std::runtime_error("descriptor mismatch for image"); + } + + m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBODynamic; + m_boundDescriptors[bindIndex].textureVlk = textureVlk; + m_updateBindPoints[bindIndex] = true; + VkDescriptorImageInfo &imageInfo = imageInfos.emplace_back(); imageInfo = {}; @@ -71,6 +93,15 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &buffer) { + if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { + std::cerr << "descriptor mismatch for UBO dynamic" << std::endl; + throw std::runtime_error("descriptor mismatch for UBO dynamic"); + } + + m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBODynamic; + m_boundDescriptors[bindIndex].buffer = buffer; + m_updateBindPoints[bindIndex] = true; + VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); bufferInfo = {}; bufferInfo.buffer = buffer->getGPUBuffer(); @@ -95,6 +126,15 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr &buffer) { + if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + std::cerr << "descriptor mismatch for UBO" << std::endl; + throw std::runtime_error("descriptor mismatch for UBO"); + } + + m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBO; + m_boundDescriptors[bindIndex].buffer = buffer; + m_updateBindPoints[bindIndex] = true; + VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); bufferInfo = {}; bufferInfo.buffer = buffer->getGPUBuffer(); @@ -124,3 +164,20 @@ GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptr &hDescriptorSetLayout, VkDescriptorSet descriptorSet, std::shared_ptr parentPool); + explicit GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout); ~GDescriptorSet(); void update(); void writeToDescriptorSets(std::vector &descriptorWrites); - const std::shared_ptr getSetLayout() const { return m_hDescriptorSetLayout;}; + const std::shared_ptr &getSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() {return m_descriptorSet;} + struct DescriptorRecord { + enum class DescriptorRecordType { + None, UBO, UBODynamic, Texture + }; + + DescriptorRecordType descType = DescriptorRecordType::None; + std::shared_ptr buffer = nullptr; + std::shared_ptr textureVlk = nullptr; + }; + class SetUpdateHelper { public: - SetUpdateHelper(GDescriptorSet &set) : m_set(set) {} + explicit SetUpdateHelper(GDescriptorSet &set, std::array &boundDescriptors) : + m_set(set), m_boundDescriptors(boundDescriptors) {} + ~SetUpdateHelper(); SetUpdateHelper& ubo(int bindIndex, const std::shared_ptr &buffer); @@ -42,27 +54,30 @@ class GDescriptorSet { //TODO: add version of this array texture case (aka bindless) SetUpdateHelper& texture(int bindIndex, const std::shared_ptr &textureVlk); - std::bitset m_updateBitSet = 0; - private: GDescriptorSet &m_set; + std::array &m_boundDescriptors; + std::vector imageInfos; std::vector bufferInfos; std::vector updates; + std::bitset m_updateBindPoints = 0; }; - SetUpdateHelper beginUpdate() { - return SetUpdateHelper(*this); - }; + SetUpdateHelper beginUpdate(); private: - GDeviceVLK &m_device; + std::shared_ptr m_device; VkDescriptorSet m_descriptorSet; std::shared_ptr m_parentPool; std::shared_ptr m_hDescriptorSetLayout; + bool m_firstUpdate = true; + + std::array boundDescriptors; + // Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea // //Defines amount of frames that the updates has to be copied from previous frame // std::array m_updatesLeft = {0}; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 233a9eabb..27bbdea76 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -19,7 +19,9 @@ class GDescriptorSetLayout { ~GDescriptorSetLayout(); const VkDescriptorSetLayout getSetLayout() {return m_descriptorSetLayout;} ; - const std::unordered_map getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; + + const std::unordered_map& getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; + int getTotalUbos() { return m_totalUbos; }; int getTotalImages() { return m_totalImages; }; private: diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index ca2af8a4f..e95fa1dae 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -10,46 +10,22 @@ void ISimpleMaterialVLK::createImageDescriptorSet() { auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto descLayout = shaderVLK->getImageDescriptorLayout(); - imageDescriptorSets = { m_device->createDescriptorSet(descLayout) }; + imageDescriptorSet = m_device->createDescriptorSet(descLayout) ; - { - std::vector descriptorWrites; - - //Bind Black pixel texture - std::vector imageInfos(shaderVLK->getTextureCount()); + int textureBegin = shaderVLK->getTextureBindingStart(); - auto blackTexture = m_device->getBlackTexturePixel(); - auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); + auto blackTexture = m_device->getBlackTexturePixel(); + auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); - int bindIndex = 0; + { + auto updateHelper = imageDescriptorSet->beginUpdate(); for (int i = 0; i < shaderVLK->getTextureCount(); i++) { - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = blackTextureVlk->texture.view; - imageInfo.sampler = blackTextureVlk->texture.sampler; - imageInfos[bindIndex] = imageInfo; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = imageDescriptorSets[0]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = shaderVLK->getTextureBindingStart()+bindIndex; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pBufferInfo = nullptr; - writeDescriptor.pImageInfo = &imageInfos[bindIndex]; - writeDescriptor.pTexelBufferView = nullptr; - descriptorWrites.push_back(writeDescriptor); - bindIndex++; - } - - if (!descriptorWrites.empty()) { - imageDescriptorSets[0]->writeToDescriptorSets(descriptorWrites); + updateHelper.texture(textureBegin + i, blackTextureVlk); } } } + void ISimpleMaterialVLK::updateImageDescriptorSet() { bool allTexturesAreReady = true; @@ -62,40 +38,29 @@ void ISimpleMaterialVLK::updateImageDescriptorSet() { } if (allTexturesAreReady) { - std::vector descriptorWrites; - std::vector imageInfos(m_textures.size()); - - if (shaderVLK->getTextureCount() == 0) return; - + auto updateHelper = imageDescriptorSet->beginUpdate(); for (size_t i = 0; i < m_textures.size(); i++) { auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); if (textureVlk == nullptr) continue; - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = textureVlk->texture.view; - imageInfo.sampler = textureVlk->texture.sampler; - imageInfos[i] = imageInfo; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = imageDescriptorSets[0]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = textureBegin+i; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pImageInfo = &imageInfos[i]; - descriptorWrites.push_back(writeDescriptor); + updateHelper.texture(textureBegin + i, textureVlk); } + } +} - if (descriptorWrites.size() > 0) { - imageDescriptorSets[0]->writeToDescriptorSets(descriptorWrites); -// vkUpdateDescriptorSets(m_device.getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); - } +void ISimpleMaterialVLK::createUBODescriptorSet() { + auto shaderVLK = std::dynamic_pointer_cast(m_shader); + auto descLayout = shaderVLK->getUboDescriptorLayout(); + + uboDescriptorSet = m_device->createDescriptorSet(descLayout) ; + + auto updateHelper = imageDescriptorSet->beginUpdate(); + for (size_t i = 0; i < m_ubos.size(); i++) { + updateHelper.ubo(i, m_ubos[i]); } } + ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, const std::string &vertexShader, const std::string &pixelShader, const std::vector> &ubos, @@ -105,7 +70,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto &shaderLayout = shaderVLK->getShaderLayout(); - auto uboSetLayout = shaderLayout.setLayouts[0]; + auto uboSetLayout = shaderLayout.setLayouts[GShaderPermutationVLK::UBO_SET_INDEX]; if (ubos.size() != uboSetLayout.uboBindings.length) { std::cerr << "not enough ubos for shaderName = " << shaderVLK->getShaderCombinedName() << std::endl; } @@ -133,7 +98,7 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, } } - auto imageSetLayout = shaderLayout.setLayouts[1]; + auto imageSetLayout = shaderLayout.setLayouts[GShaderPermutationVLK::IMAGE_SET_INDEX]; if (imageSetLayout.imageBindings.length != textures.size()) { std::cout << "image count mismatch! for" << " shaderName = " << shaderVLK->getShaderCombinedName() @@ -145,4 +110,8 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, m_textures = textures; m_ubos = ubos; + + createImageDescriptorSet(); + createUBODescriptorSet(); + } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 3f2759b54..8fec9e82e 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -12,7 +12,7 @@ #include "../descriptorSets/GDescriptorSet.h" #include "../textures/GTextureVLK.h" -class ISimpleMaterialVLK : public IMaterial { +class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: explicit ISimpleMaterialVLK(const HGDeviceVLK &device, const std::string &vertexShader, const std::string &pixelShader, @@ -27,15 +27,17 @@ class ISimpleMaterialVLK : public IMaterial { void createImageDescriptorSet(); void updateImageDescriptorSet(); + void createUBODescriptorSet(); + private: HGDeviceVLK m_device; std::vector m_textures = {}; std::vector> m_ubos = {}; - std::vector> imageDescriptorSets; - std::vector> uboDescriptorSets; - std::vector> ssboDescriptorSets; + std::shared_ptr imageDescriptorSet; + std::shared_ptr uboDescriptorSet; + std::shared_ptr ssboDescriptorSet; HGShaderPermutation m_shader; }; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index d0de210d4..f06e4277a 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -51,14 +51,11 @@ GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderVertName, std::s } void GShaderPermutationVLK::createUBODescriptorLayout() { - const constexpr int UBO_SET_INDEX = 0; - std::vector metas = {fragShaderMeta, vertShaderMeta}; hUboDescriptorSetLayout = std::make_shared(m_device, metas, UBO_SET_INDEX); } void GShaderPermutationVLK::createImageDescriptorLayout() { - const constexpr int IMAGE_SET_INDEX = 0; std::vector metas = {fragShaderMeta, vertShaderMeta}; hImageDescriptorSetLayout = std::make_shared(m_device, metas, IMAGE_SET_INDEX); } diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index 173284378..c1c783ff9 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -25,8 +25,10 @@ struct CombinedShaderLayout { class GShaderPermutationVLK : public IShaderPermutation { friend class GDeviceVLK; - public: + static const constexpr int UBO_SET_INDEX = 0; + static const constexpr int IMAGE_SET_INDEX = 1; + explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device); ~GShaderPermutationVLK() override {}; @@ -75,8 +77,6 @@ class GShaderPermutationVLK : public IShaderPermutation { std::string m_shaderNameVert; std::string m_shaderNameFrag; - - CombinedShaderLayout shaderLayout; void createUBODescriptorLayout(); From 0e2145573a17f614e86f602be14b4d7b0d3f0fc2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 5 Feb 2023 21:42:38 +0200 Subject: [PATCH 023/212] commit --- wowViewerLib/CMakeLists.txt | 4 +- .../src/gapi/vulkan/CommandBuffer.cpp | 137 ++++++++++++++++++ wowViewerLib/src/gapi/vulkan/CommandBuffer.h | 66 +++++++++ .../src/gapi/vulkan/GDeviceVulkan.cpp | 1 + .../src/gapi/vulkan/GFrameBufferVLK.cpp | 25 ++-- .../src/gapi/vulkan/GFrameBufferVLK.h | 12 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 24 +-- wowViewerLib/src/gapi/vulkan/GPipelineVLK.h | 1 - .../src/gapi/vulkan/GRenderPassVLK.cpp | 1 + .../vulkan/shaders/GShaderPermutationVLK.cpp | 97 +++---------- .../vulkan/shaders/GShaderPermutationVLK.h | 16 +- 11 files changed, 264 insertions(+), 120 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/CommandBuffer.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index bf74534b2..1f723074a 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -491,7 +491,9 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/IBufferChunkVLK.cpp src/gapi/vulkan/buffers/IBufferChunkVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp - src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h) + src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h + src/gapi/vulkan/CommandBuffer.cpp + src/gapi/vulkan/CommandBuffer.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp new file mode 100644 index 000000000..e0ce49a98 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp @@ -0,0 +1,137 @@ +// +// Created by Deamon on 05.02.23. +// + +#include "CommandBuffer.h" +#include "GRenderPassVLK.h" +#include "GFrameBufferVLK.h" + +GCommandBuffer::GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary) { + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocInfo.commandBufferCount = 1; + + if (vkAllocateCommandBuffers(deviceVlk.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } +} + +GCommandBuffer::CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr &renderPass) { + //If renderPass != nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside + if (m_isPrimary && renderPass != nullptr) { + std::cerr << "tried to continue renderpass in primary buffer " << std::endl; + throw std::runtime_error("tried to continue renderpass in primary buffer "); + } + + return CmdBufRecorder(*this, renderPass); +} + +// ---------------------------------------- +// CmdBufRecorder +// ---------------------------------------- + +GCommandBuffer::CmdBufRecorder::CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass) : m_gCmdBuffer(cmdBuffer) { + VkCommandBufferInheritanceInfo bufferInheritanceInfo; + + //If not nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside + if (renderPass != nullptr) { + bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + bufferInheritanceInfo.pNext = nullptr; + bufferInheritanceInfo.renderPass = renderPass->getRenderPass(); + bufferInheritanceInfo.subpass = 0; + bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; + bufferInheritanceInfo.occlusionQueryEnable = false; + bufferInheritanceInfo.queryFlags = 0; + bufferInheritanceInfo.pipelineStatistics = 0; + + m_currentRenderPass = renderPass; + } + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.pNext = NULL; + beginInfo.pInheritanceInfo = (renderPass != nullptr) ? &bufferInheritanceInfo : nullptr; + + if (vkBeginCommandBuffer(m_gCmdBuffer.m_cmdBuffer, &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("failed to begin recording command buffer!"); + } +} +GCommandBuffer::CmdBufRecorder::~CmdBufRecorder() { + if (m_gCmdBuffer.m_isPrimary && m_currentRenderPass != nullptr) { + std::cerr << "currentRenderPass is not null. RenderPass was not closed" << std::endl; + } + + if (vkEndCommandBuffer(m_gCmdBuffer.m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to record command buffer!"); + } +} + + +GCommandBuffer::CmdBufRecorder::RenderPassHelper GCommandBuffer::CmdBufRecorder::beginRenderPass( + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array areaOffset, + const std::array areaSize, + const std::array &colorClearColor, float depthClear +) { + if (m_currentRenderPass != nullptr) { + throw std::runtime_error("tried to start render pass with another pass being active already"); + } + + m_currentRenderPass = renderPassVlk; + return GCommandBuffer::CmdBufRecorder::RenderPassHelper( + *this, + isAboutToExecSecondaryCMD, + renderPassVlk, frameBuffer, areaOffset, areaSize, colorClearColor, depthClear + ); +} + +void GCommandBuffer::CmdBufRecorder::bindDescriptorSet(std::shared_ptr &descriptorSet) { + vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, + h_pipeLine->pipelineLayout, 0, 1, &uboDescSet, uboIndPerMesh[i], dynamicOffsetPerMesh[i].data()); +} + +// ---------------------------------------- +// RenderPassHelper +// ---------------------------------------- + +GCommandBuffer::CmdBufRecorder::RenderPassHelper::RenderPassHelper(CmdBufRecorder &cmdBufRecorder, + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear + ) : m_cmdBufRecorder(cmdBufRecorder) { + + auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor, depthClear); + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.pNext = NULL; + renderPassInfo.renderPass = renderPassVlk->getRenderPass(); + renderPassInfo.framebuffer = frameBuffer->getFrameBuffer(); + renderPassInfo.renderArea.offset = {areaOffset[0], areaOffset[1]}; + renderPassInfo.renderArea.extent = {areaSize[0], areaSize[1]}; + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); + + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + + vkCmdBeginRenderPass( + gCmdBuffer.m_cmdBuffer, &renderPassInfo, + isAboutToExecSecondaryCMD ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE + ); +} + +GCommandBuffer::CmdBufRecorder::RenderPassHelper::~RenderPassHelper() { + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + + vkCmdEndRenderPass(gCmdBuffer.m_cmdBuffer); + m_cmdBufRecorder.m_currentRenderPass = nullptr; +} + diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/CommandBuffer.h new file mode 100644 index 000000000..3cfdd4c95 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/CommandBuffer.h @@ -0,0 +1,66 @@ +// +// Created by Deamon on 05.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFER_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFER_H + + +#include "../vulkan/volk.h" +#include "GDeviceVulkan.h" +#include "GFrameBufferVLK.h" + +class GCommandBuffer { +public: + class CmdBufRecorder { + public: + + class RenderPassHelper { + public: + explicit RenderPassHelper(CmdBufRecorder &cmdBufRecorder, + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear); + + ~RenderPassHelper(); + private: + CmdBufRecorder &m_cmdBufRecorder; + }; + + public: + CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); + ~CmdBufRecorder(); + + RenderPassHelper beginRenderPass( + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array areaOffset, + const std::array areaSize, + const std::array &colorClearColor, float depthClear); + + void bindDescriptorSet(std::shared_ptr &descriptorSet); + + friend RenderPassHelper::~RenderPassHelper(); + private: + const GCommandBuffer &m_gCmdBuffer; + + //States + std::shared_ptr m_currentRenderPass = nullptr; + std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + }; + +public: + GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary); + + CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); +private: + VkCommandBuffer m_cmdBuffer; + bool m_isPrimary = true; +}; + + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index aa43d1fba..7ffba4eaf 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1429,6 +1429,7 @@ VkDescriptorSet GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) { //1. Try to allocate from existing sets + //Keep only one descriptor set pool for now if (m_descriptorPools.size() == 0) { std::shared_ptr newPool = std::make_shared(*this); m_descriptorPools.push_back(newPool); diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index a0f93bd65..bb2c6c59c 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -7,23 +7,30 @@ #include "textures/GTextureVLK.h" #include "GRenderPassVLK.h" -void GFrameBufferVLK::iterateOverAttachments(std::vector textureAttachments, std::function callback) { +void GFrameBufferVLK::iterateOverAttachments(const std::vector &textureAttachments, std::function callback) { for (int i = 0; i < textureAttachments.size(); i++) { - if (textureAttachments[i] == ITextureFormat::itNone) continue; - if (textureAttachments[i] == ITextureFormat::itDepth32) continue; - VkFormat textureFormat; - if (textureAttachments[i] == ITextureFormat::itRGBA) { - textureFormat = VK_FORMAT_R8G8B8A8_UNORM; - } else if (textureAttachments[i] == ITextureFormat::itRGBAFloat32) { - textureFormat = VK_FORMAT_R16G16B16_SFLOAT; + + switch (textureAttachments[i]) { + case ITextureFormat::itNone: + case ITextureFormat::itDepth32: + continue; + + case ITextureFormat::itRGBA: + textureFormat = VK_FORMAT_R8G8B8A8_UNORM; + break; + + case ITextureFormat::itRGBAFloat32: + textureFormat = VK_FORMAT_R16G16B16_SFLOAT; + break; } callback(i, textureFormat); } } -GFrameBufferVLK::GFrameBufferVLK(IDevice &device, std::vector textureAttachments, +GFrameBufferVLK::GFrameBufferVLK(IDevice &device, + const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, int width, int height) : mdevice(dynamic_cast(device)), diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index ceb09c01e..6133aa4bf 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -12,7 +12,7 @@ class GFrameBufferVLK : public IFrameBuffer { public: - GFrameBufferVLK(IDevice &device, std::vector textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, int width, int height); + GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, int width, int height); ~GFrameBufferVLK() override; void readRGBAPixels(int x, int y, int width, int height, void *data) override; @@ -21,15 +21,17 @@ class GFrameBufferVLK : public IFrameBuffer { void bindFrameBuffer() override; void copyRenderBufferToTexture() override; - std::shared_ptr m_renderPass; - VkFramebuffer m_frameBuffer; - - static void iterateOverAttachments(std::vector textureAttachments, std::function callback); + static void iterateOverAttachments(const std::vector &textureAttachments, std::function callback); + VkFramebuffer getFrameBuffer() {return m_frameBuffer;}; + int getColorOrDataAttachmentCount() { return attachmentFormats.size(); }; private: GDeviceVLK &mdevice; + std::shared_ptr m_renderPass; + VkFramebuffer m_frameBuffer; + std::vector attachmentTextures; HGTexture depthTexture; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index fc6e5aa05..5cde9d5c7 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -101,13 +101,13 @@ void GPipelineVLK::createPipeline( vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vertShaderStageInfo.module = vertShaderModule; - vertShaderStageInfo.pName = "main"; + vertShaderStageInfo.pName = "main"; //entry point in SPIR-V VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.module = fragShaderModule; - fragShaderStageInfo.pName = "main"; + fragShaderStageInfo.pName = "main"; //entry point in SPIR-V VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; @@ -209,24 +209,6 @@ void GPipelineVLK::createPipeline( depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.stencilTestEnable = VK_FALSE; - std::array descLayouts ; - descLayouts[0] = shaderVLK->getUboDescriptorLayout()->getSetLayout(); - descLayouts[1] = shaderVLK->getImageDescriptorLayout()->getSetLayout(); - - VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.pNext = NULL; - pipelineLayoutInfo.pushConstantRangeCount = 0; - pipelineLayoutInfo.pPushConstantRanges = NULL; - pipelineLayoutInfo.setLayoutCount = 2; - pipelineLayoutInfo.pSetLayouts = &descLayouts[0]; - - std::cout << "Pipeline layout for "+shaderVLK->getShaderCombinedName() << std::endl; - - if (vkCreatePipelineLayout(m_device.getVkDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create pipeline layout!"); - } - std::array dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo dynamicState = {}; @@ -247,7 +229,7 @@ void GPipelineVLK::createPipeline( pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDepthStencilState = &depthStencil; pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.layout = pipelineLayout; + pipelineInfo.layout = shaderVLK->getPipelineLayout(); pipelineInfo.renderPass = renderPass->getRenderPass(); pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h index c7276669b..37967ab19 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h @@ -41,7 +41,6 @@ class GPipelineVLK { private: GDeviceVLK &m_device; - VkPipelineLayout pipelineLayout; VkPipeline graphicsPipeline; }; diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp index b7718e968..f16d00d5b 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp @@ -10,6 +10,7 @@ GRenderPassVLK::GRenderPassVLK(GDeviceVLK &device, std::vector texture std::vector attachments; std::vector colorAttachmentsResolves; + std::vector colorReferences; std::vector colorResolveReferences; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index f06e4277a..9cebe171e 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -60,78 +60,6 @@ void GShaderPermutationVLK::createImageDescriptorLayout() { hImageDescriptorSetLayout = std::make_shared(m_device, metas, IMAGE_SET_INDEX); } -void GShaderPermutationVLK::updateDescriptorSet(int index) { - std::vector bufferInfos; - std::vector descriptorWrites; - - auto *uploadBuffer = ((IBufferVLK *) m_device->getUploadBuffer(index).get()); - if (uploadBuffer == nullptr) return; - - for (int i = 0; i < vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = vertShaderMeta->uboBindings[i]; - - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = uploadBuffer->getGPUBuffer(); - bufferInfo.offset = 0; - bufferInfo.range = uboVertBinding.size; - bufferInfos.push_back(bufferInfo); - } - for (int i = 0; i < fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = fragShaderMeta->uboBindings[i]; - - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = uploadBuffer->getGPUBuffer(); - bufferInfo.offset = 0; - bufferInfo.range = uboFragBinding.size; - bufferInfos.push_back(bufferInfo); - } - - int buffInd = 0; - for (int i = 0; i < vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = vertShaderMeta->uboBindings[i]; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = uboDescriptorSets[index]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = uboVertBinding.binding; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pBufferInfo = &bufferInfos[buffInd++]; - writeDescriptor.pImageInfo = nullptr; - writeDescriptor.pTexelBufferView = nullptr; - descriptorWrites.push_back(writeDescriptor); - - } - for (int i = 0; i < fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = fragShaderMeta->uboBindings[i]; - - VkWriteDescriptorSet writeDescriptor; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.dstSet = uboDescriptorSets[index]->getDescSet(); - writeDescriptor.pNext = nullptr; - writeDescriptor.dstBinding = uboFragBinding.binding; - writeDescriptor.dstArrayElement = 0; - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptor.descriptorCount = 1; - writeDescriptor.pBufferInfo = &bufferInfos[buffInd++]; - writeDescriptor.pImageInfo = nullptr; - writeDescriptor.pTexelBufferView = nullptr; - descriptorWrites.push_back(writeDescriptor); - } - - uboDescriptorSets[index]->writeToDescriptorSets(descriptorWrites); -} - -void GShaderPermutationVLK::createUboDescriptorSets() { - for (int j = 0; j < 4; j++) { - std::vector descriptorWrites; - uboDescriptorSets[j] = m_device->createDescriptorSet(hUboDescriptorSetLayout); - updateDescriptorSet(j); - } -} - void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const std::string &fragExtraDef) { auto vertShaderCode = readFile("spirv/" + m_shaderNameVert + ".vert.spv"); auto fragShaderCode = readFile("spirv/" + m_shaderNameFrag + ".frag.spv"); @@ -143,9 +71,12 @@ void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const fragShaderMeta = &shaderMetaInfo.at(m_shaderNameFrag + ".frag.spv"); this->createShaderLayout(); + this->createUBODescriptorLayout(); this->createImageDescriptorLayout(); - this->createUboDescriptorSets(); + + this->createPipelineLayout(); + } int GShaderPermutationVLK::getTextureBindingStart() { @@ -250,3 +181,23 @@ void GShaderPermutationVLK::createShaderLayout() { } } +void GShaderPermutationVLK::createPipelineLayout() { + std::array descLayouts ; + descLayouts[0] = this->getUboDescriptorLayout()->getSetLayout(); + descLayouts[1] = this->getImageDescriptorLayout()->getSetLayout(); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pNext = NULL; + pipelineLayoutInfo.pushConstantRangeCount = 0; + pipelineLayoutInfo.pPushConstantRanges = NULL; + pipelineLayoutInfo.setLayoutCount = 2; + pipelineLayoutInfo.pSetLayouts = &descLayouts[0]; + + std::cout << "Pipeline layout for "+this->getShaderCombinedName() << std::endl; + + if (vkCreatePipelineLayout(m_device->getVkDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create pipeline layout!"); + } +} + diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index c1c783ff9..cd64ddb86 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -51,6 +51,10 @@ class GShaderPermutationVLK : public IShaderPermutation { return shaderLayout; }; + VkPipelineLayout getPipelineLayout() { + return pipelineLayout; + } + protected: VkShaderModule createShaderModule(const std::vector& code); @@ -60,15 +64,12 @@ class GShaderPermutationVLK : public IShaderPermutation { VkShaderModule vertShaderModule; VkShaderModule fragShaderModule; + VkPipelineLayout pipelineLayout; std::shared_ptr hUboDescriptorSetLayout; std::shared_ptr hImageDescriptorSetLayout; - std::array, 4> uboDescriptorSets = {nullptr}; - std::shared_ptr m_device; - - private: //Used only for logging std::string m_combinedName; @@ -83,13 +84,8 @@ class GShaderPermutationVLK : public IShaderPermutation { void createImageDescriptorLayout(); - void createUboDescriptorSets(); - - void updateDescriptorSet(int index); - - std::vector hasBondUBO = std::vector(7, false); - void createShaderLayout(); + void createPipelineLayout(); }; From 5a42152ab51c16b18d5226fb88c02c43f9f55122 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 6 Feb 2023 20:06:23 +0200 Subject: [PATCH 024/212] commit --- .../src/gapi/vulkan/CommandBuffer.cpp | 25 ++- wowViewerLib/src/gapi/vulkan/CommandBuffer.h | 4 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 16 -- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 9 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.h | 10 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 195 +++++++++--------- .../src/gapi/vulkan/textures/GTextureVLK.h | 9 + 7 files changed, 145 insertions(+), 123 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp index e0ce49a98..41c628db4 100644 --- a/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp @@ -5,6 +5,7 @@ #include "CommandBuffer.h" #include "GRenderPassVLK.h" #include "GFrameBufferVLK.h" +#include "GPipelineVLK.h" GCommandBuffer::GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary) { VkCommandBufferAllocateInfo allocInfo = {}; @@ -90,9 +91,27 @@ GCommandBuffer::CmdBufRecorder::RenderPassHelper GCommandBuffer::CmdBufRecorder: ); } -void GCommandBuffer::CmdBufRecorder::bindDescriptorSet(std::shared_ptr &descriptorSet) { - vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, - h_pipeLine->pipelineLayout, 0, 1, &uboDescSet, uboIndPerMesh[i], dynamicOffsetPerMesh[i].data()); +void GCommandBuffer::CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet) { + //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others + //Which leads to three separate states for: + // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR + // Also, implement "Pipeline Layout Compatibility" thing from spec + + if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; + + auto vkDescSet = descriptorSet->getDescSet(); + constexpr uint32_t vkDescCnt = 1; + + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); +} + +void GCommandBuffer::CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { + if (m_currentPipeline == pipeline) return; + + vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline()); + + m_currentPipeline = pipeline; } // ---------------------------------------- diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/CommandBuffer.h index 3cfdd4c95..4cdbe20d0 100644 --- a/wowViewerLib/src/gapi/vulkan/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/CommandBuffer.h @@ -42,7 +42,8 @@ class GCommandBuffer { const std::array areaSize, const std::array &colorClearColor, float depthClear); - void bindDescriptorSet(std::shared_ptr &descriptorSet); + void bindPipeline(std::shared_ptr &pipeline); + void bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet); friend RenderPassHelper::~RenderPassHelper(); private: @@ -50,6 +51,7 @@ class GCommandBuffer { //States std::shared_ptr m_currentRenderPass = nullptr; + std::shared_ptr m_currentPipeline = nullptr; std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index d5a4e4f82..fa195b81b 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -159,20 +159,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_UBOFrames; - std::vector aggregationBufferForUpload = std::vector(1024*1024); std::list listOfDeallocators; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index 5cde9d5c7..a487961c0 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -34,9 +34,9 @@ BlendModeDescVLK blendModesVLK[(int)EGxBlendEnum::GxBlend_MAX] = { }; GPipelineVLK::GPipelineVLK(IDevice &device, - HGVertexBufferBindings m_bindings, - std::shared_ptr renderPass, - HGShaderPermutation shader, + const HGVertexBufferBindings &m_bindings, + const std::shared_ptr &renderPass, + const HGShaderPermutation &shader, DrawElementMode element, int8_t backFaceCulling, int8_t triCCW, @@ -45,7 +45,6 @@ GPipelineVLK::GPipelineVLK(IDevice &device, int8_t depthWrite, bool invertZ) : m_device(dynamic_cast(device)) { - GVertexBufferBindingsVLK* bufferBindingsVlk = dynamic_cast(m_bindings.get()); auto &arrVLKFormat = bufferBindingsVlk->getVLKFormat(); @@ -59,6 +58,8 @@ GPipelineVLK::GPipelineVLK(IDevice &device, } GShaderPermutationVLK* shaderVLK = reinterpret_cast(shader.get()); + m_pipelineLayout = shaderVLK->getPipelineLayout(); + createPipeline(shaderVLK, renderPass, element, diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h index 37967ab19..6eca7a33c 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h @@ -13,9 +13,9 @@ class GPipelineVLK { friend class GDeviceVLK; public: explicit GPipelineVLK(IDevice &m_device, - HGVertexBufferBindings m_bindings, - std::shared_ptr renderPass, - HGShaderPermutation shader, + const HGVertexBufferBindings &m_bindings, + const std::shared_ptr &renderPass, + const HGShaderPermutation &shader, DrawElementMode element, int8_t backFaceCulling, int8_t triCCW, @@ -38,9 +38,13 @@ class GPipelineVLK { const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions); + + VkPipelineLayout getLayout() { return m_pipelineLayout; }; + VkPipeline getPipeline() { return graphicsPipeline; }; private: GDeviceVLK &m_device; + VkPipelineLayout m_pipelineLayout; VkPipeline graphicsPipeline; }; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 82c477d11..b71539449 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -139,7 +139,7 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & ///2. Create regions to copy from CPU staging buffer to GPU buffer // Setup buffer copy regions for each mip level - std::vector bufferCopyRegions; + bufferCopyRegions = {}; uint32_t offset = 0; int vulkanMipMapCount = 0; @@ -172,8 +172,6 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & } // Create optimal tiled target image on the device - auto indicies = m_device.getQueueFamilyIndices(); - createVulkanImageObject( false, textureFormatGPU, @@ -181,101 +179,9 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & vulkanMipMapCount, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ); - ///4. Fill commands to copy from CPU staging buffer to GPU buffer - - // Image memory barriers for the texture image - - // The sub resource range describes the regions of the image that will be transitioned using the memory barriers below - VkImageSubresourceRange subresourceRange = {}; - // Image only contains color data - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // Start at first mip level - subresourceRange.baseMipLevel = 0; - // We will transition on all mip levels - subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - // The 2D texture only has one layer - subresourceRange.layerCount = 1; - - // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. - VkImageMemoryBarrier imageMemoryBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - imageMemoryBarrier.subresourceRange = subresourceRange; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.image = texture.image; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is host write/read exection (VK_PIPELINE_STAGE_HOST_BIT) - // Destination pipeline stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT) - vkCmdPipelineBarrier( - m_device.getUploadCommandBuffer(), - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); - - // Copy mip levels from staging buffer - vkCmdCopyBufferToImage( - m_device.getUploadCommandBuffer(), - stagingBuffer, - texture.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(bufferCopyRegions.size()), - bufferCopyRegions.data()); - - // Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from - - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ; - imageMemoryBarrier.dstAccessMask = 0; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (m_device.canUploadInSeparateThread()) { - imageMemoryBarrier.srcQueueFamilyIndex = indicies.transferFamily.value(); - imageMemoryBarrier.dstQueueFamilyIndex = indicies.graphicsFamily.value(); - } else { - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } - ///SeparateUploadQueue reference: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples - /// "Upload data from the CPU to an image sampled in a fragment shader" - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT) - // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - - if (m_device.canUploadInSeparateThread()) { - vkCmdPipelineBarrier( - m_device.getTextureTransferCommandBuffer(), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); - - m_device.signalTextureTransferCommandRecorded(); - } else { - vkCmdPipelineBarrier( - m_device.getUploadCommandBuffer(), - VK_PIPELINE_STAGE_TRANSFER_BIT , - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); - } - - // Store current layout for later reuse - texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - m_uploaded = true; stagingBufferCreated = true; + } void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat textureFormatGPU, @@ -377,4 +283,101 @@ bool GTextureVLK::postLoad() { } +void GTextureVLK::updateVulkan() { +///4. Fill commands to copy from CPU staging buffer to GPU buffer + + // Image memory barriers for the texture image + + // The sub resource range describes the regions of the image that will be transitioned using the memory barriers below + VkImageSubresourceRange subresourceRange = {}; + // Image only contains color data + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // Start at first mip level + subresourceRange.baseMipLevel = 0; + // We will transition on all mip levels + subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + // The 2D texture only has one layer + subresourceRange.layerCount = 1; + + // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. + VkImageMemoryBarrier imageMemoryBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + imageMemoryBarrier.subresourceRange = subresourceRange; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.image = texture.image; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition + // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) + // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) + vkCmdPipelineBarrier( + m_device.getUploadCommandBuffer(), + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + + // Copy mip levels from staging buffer + vkCmdCopyBufferToImage( + m_device.getUploadCommandBuffer(), + stagingBuffer, + texture.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(bufferCopyRegions.size()), + bufferCopyRegions.data()); + + // Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from + + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + if (m_device.canUploadInSeparateThread()) { + imageMemoryBarrier.srcQueueFamilyIndex = indicies.transferFamily.value(); + imageMemoryBarrier.dstQueueFamilyIndex = indicies.graphicsFamily.value(); + } else { + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + } + //SeparateUploadQueue reference: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples + //"Upload data from the CPU to an image sampled in a fragment shader" + + + // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition + // Source pipeline stage stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT) + // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) + + if (m_device.canUploadInSeparateThread()) { + vkCmdPipelineBarrier( + m_device.getTextureTransferCommandBuffer(), + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + + m_device.signalTextureTransferCommandRecorded(); + } else { + vkCmdPipelineBarrier( + m_device.getUploadCommandBuffer(), + VK_PIPELINE_STAGE_TRANSFER_BIT , + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + + // Store current layout for later reuse + texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + m_uploaded = true; +} + diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 537f27d76..fecde9776 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -10,6 +10,8 @@ class GFrameBufferVLK; #include "../GDeviceVulkan.h" #include "../../interface/textures/ITexture.h" +class + class GTextureVLK : public ITexture { friend class GDeviceVLK; friend class GFrameBufferVLK; @@ -34,6 +36,8 @@ class GTextureVLK : public ITexture { void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) override { throw "Not Implemented in this class"; } + + void updateVulkan(); bool postLoad() override;; struct Texture { @@ -55,6 +59,10 @@ class GTextureVLK : public ITexture { VmaAllocation imageAllocation = VK_NULL_HANDLE; VmaAllocationInfo imageAllocationInfo = {}; + + std::vector bufferCopyRegions = {}; + + protected: GDeviceVLK &m_device; @@ -68,6 +76,7 @@ class GTextureVLK : public ITexture { int m_width = 0; int m_height = 0; + void createVulkanImageObject( bool isDepthTexture, const VkFormat textureFormatGPU, From aaf52aef6753c4abcfbed22dac5248f62581776a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 6 Feb 2023 23:48:19 +0200 Subject: [PATCH 025/212] half way for texture upload --- wowViewerLib/CMakeLists.txt | 4 +- .../src/gapi/vulkan/CommandBuffer.cpp | 156 ------------------ wowViewerLib/src/gapi/vulkan/CommandBuffer.h | 68 -------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 13 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 2 + .../vulkan/commandBuffer/CommandBuffer.cpp | 30 ++++ .../gapi/vulkan/commandBuffer/CommandBuffer.h | 31 ++++ .../CommandBufferRecorder.cpp | 118 +++++++++++++ .../CommandBufferRecorder.h | 53 ++++++ .../RenderPassHelper.cpp | 50 ++++++ .../commandBufferRecorder/RenderPassHelper.h | 27 +++ .../TextureUploadHelper.cpp | 64 +++++++ .../TextureUploadHelper.h | 22 +++ .../src/gapi/vulkan/textures/GTextureVLK.cpp | 40 +---- .../src/gapi/vulkan/textures/GTextureVLK.h | 6 +- 16 files changed, 409 insertions(+), 277 deletions(-) delete mode 100644 wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/CommandBuffer.h create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 1f723074a..9e79270a1 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -492,8 +492,8 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/IBufferChunkVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h - src/gapi/vulkan/CommandBuffer.cpp - src/gapi/vulkan/CommandBuffer.h) + src/gapi/vulkan/commandBuffer/CommandBuffer.cpp + src/gapi/vulkan/commandBuffer/CommandBuffer.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp deleted file mode 100644 index 41c628db4..000000000 --- a/wowViewerLib/src/gapi/vulkan/CommandBuffer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// -// Created by Deamon on 05.02.23. -// - -#include "CommandBuffer.h" -#include "GRenderPassVLK.h" -#include "GFrameBufferVLK.h" -#include "GPipelineVLK.h" - -GCommandBuffer::GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary) { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = commandPool; - allocInfo.level = isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocInfo.commandBufferCount = 1; - - if (vkAllocateCommandBuffers(deviceVlk.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } -} - -GCommandBuffer::CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr &renderPass) { - //If renderPass != nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside - if (m_isPrimary && renderPass != nullptr) { - std::cerr << "tried to continue renderpass in primary buffer " << std::endl; - throw std::runtime_error("tried to continue renderpass in primary buffer "); - } - - return CmdBufRecorder(*this, renderPass); -} - -// ---------------------------------------- -// CmdBufRecorder -// ---------------------------------------- - -GCommandBuffer::CmdBufRecorder::CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass) : m_gCmdBuffer(cmdBuffer) { - VkCommandBufferInheritanceInfo bufferInheritanceInfo; - - //If not nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside - if (renderPass != nullptr) { - bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - bufferInheritanceInfo.pNext = nullptr; - bufferInheritanceInfo.renderPass = renderPass->getRenderPass(); - bufferInheritanceInfo.subpass = 0; - bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; - bufferInheritanceInfo.occlusionQueryEnable = false; - bufferInheritanceInfo.queryFlags = 0; - bufferInheritanceInfo.pipelineStatistics = 0; - - m_currentRenderPass = renderPass; - } - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = (renderPass != nullptr) ? &bufferInheritanceInfo : nullptr; - - if (vkBeginCommandBuffer(m_gCmdBuffer.m_cmdBuffer, &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } -} -GCommandBuffer::CmdBufRecorder::~CmdBufRecorder() { - if (m_gCmdBuffer.m_isPrimary && m_currentRenderPass != nullptr) { - std::cerr << "currentRenderPass is not null. RenderPass was not closed" << std::endl; - } - - if (vkEndCommandBuffer(m_gCmdBuffer.m_cmdBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } -} - - -GCommandBuffer::CmdBufRecorder::RenderPassHelper GCommandBuffer::CmdBufRecorder::beginRenderPass( - bool isAboutToExecSecondaryCMD, - const std::shared_ptr &renderPassVlk, - const std::shared_ptr &frameBuffer, - const std::array areaOffset, - const std::array areaSize, - const std::array &colorClearColor, float depthClear -) { - if (m_currentRenderPass != nullptr) { - throw std::runtime_error("tried to start render pass with another pass being active already"); - } - - m_currentRenderPass = renderPassVlk; - return GCommandBuffer::CmdBufRecorder::RenderPassHelper( - *this, - isAboutToExecSecondaryCMD, - renderPassVlk, frameBuffer, areaOffset, areaSize, colorClearColor, depthClear - ); -} - -void GCommandBuffer::CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet) { - //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others - //Which leads to three separate states for: - // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR - // Also, implement "Pipeline Layout Compatibility" thing from spec - - if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; - - auto vkDescSet = descriptorSet->getDescSet(); - constexpr uint32_t vkDescCnt = 1; - - vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); -} - -void GCommandBuffer::CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { - if (m_currentPipeline == pipeline) return; - - vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline()); - - m_currentPipeline = pipeline; -} - -// ---------------------------------------- -// RenderPassHelper -// ---------------------------------------- - -GCommandBuffer::CmdBufRecorder::RenderPassHelper::RenderPassHelper(CmdBufRecorder &cmdBufRecorder, - bool isAboutToExecSecondaryCMD, - const std::shared_ptr &renderPassVlk, - const std::shared_ptr &frameBuffer, - const std::array &areaOffset, - const std::array &areaSize, - const std::array &colorClearColor, float depthClear - ) : m_cmdBufRecorder(cmdBufRecorder) { - - auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor, depthClear); - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.pNext = NULL; - renderPassInfo.renderPass = renderPassVlk->getRenderPass(); - renderPassInfo.framebuffer = frameBuffer->getFrameBuffer(); - renderPassInfo.renderArea.offset = {areaOffset[0], areaOffset[1]}; - renderPassInfo.renderArea.extent = {areaSize[0], areaSize[1]}; - renderPassInfo.clearValueCount = static_cast(clearValues.size()); - renderPassInfo.pClearValues = clearValues.data(); - - auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; - - vkCmdBeginRenderPass( - gCmdBuffer.m_cmdBuffer, &renderPassInfo, - isAboutToExecSecondaryCMD ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE - ); -} - -GCommandBuffer::CmdBufRecorder::RenderPassHelper::~RenderPassHelper() { - auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; - - vkCmdEndRenderPass(gCmdBuffer.m_cmdBuffer); - m_cmdBufRecorder.m_currentRenderPass = nullptr; -} - diff --git a/wowViewerLib/src/gapi/vulkan/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/CommandBuffer.h deleted file mode 100644 index 4cdbe20d0..000000000 --- a/wowViewerLib/src/gapi/vulkan/CommandBuffer.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Created by Deamon on 05.02.23. -// - -#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFER_H -#define AWEBWOWVIEWERCPP_COMMANDBUFFER_H - - -#include "../vulkan/volk.h" -#include "GDeviceVulkan.h" -#include "GFrameBufferVLK.h" - -class GCommandBuffer { -public: - class CmdBufRecorder { - public: - - class RenderPassHelper { - public: - explicit RenderPassHelper(CmdBufRecorder &cmdBufRecorder, - bool isAboutToExecSecondaryCMD, - const std::shared_ptr &renderPassVlk, - const std::shared_ptr &frameBuffer, - const std::array &areaOffset, - const std::array &areaSize, - const std::array &colorClearColor, float depthClear); - - ~RenderPassHelper(); - private: - CmdBufRecorder &m_cmdBufRecorder; - }; - - public: - CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); - ~CmdBufRecorder(); - - RenderPassHelper beginRenderPass( - bool isAboutToExecSecondaryCMD, - const std::shared_ptr &renderPassVlk, - const std::shared_ptr &frameBuffer, - const std::array areaOffset, - const std::array areaSize, - const std::array &colorClearColor, float depthClear); - - void bindPipeline(std::shared_ptr &pipeline); - void bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet); - - friend RenderPassHelper::~RenderPassHelper(); - private: - const GCommandBuffer &m_gCmdBuffer; - - //States - std::shared_ptr m_currentRenderPass = nullptr; - std::shared_ptr m_currentPipeline = nullptr; - std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; - }; - -public: - GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary); - - CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); -private: - VkCommandBuffer m_cmdBuffer; - bool m_isPrimary = true; -}; - - -#endif //AWEBWOWVIEWERCPP_COMMANDBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index fa195b81b..b72026994 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -159,11 +159,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this commandBuffers; - std::vector renderCommandBuffers; - std::vector renderCommandBuffersNotNull; - std::vector renderCommandBuffersForFrameBuffers; - std::vector renderCommandBuffersForFrameBuffersNotNull; - std::vector uploadCommandBuffers; - std::vector textureTransferCommandBuffers; - std::vector textureTransferCommandBufferNull; + std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 142d7151b..6653a7e0b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -163,7 +163,7 @@ void GBufferVLK::uploadFromStaging(int offset, int destOffset, int length) { vbCopyRegion.srcOffset = offset; vbCopyRegion.dstOffset = destOffset; vbCopyRegion.size = length; - vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), currentBuffer.stagingBuffer, currentBuffer.g_hBuffer, 1, &vbCopyRegion); +// vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), currentBuffer.stagingBuffer, currentBuffer.g_hBuffer, 1, &vbCopyRegion); } void GBufferVLK::save(int length) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 5d6ecd54a..f52877afa 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -91,6 +91,8 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> currentSubBuffers; + +// uploadCache = {}; public: std::shared_ptr getSubBuffer(int sizeInBytes); void deleteSubBuffer(std::list>::const_iterator &it); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp new file mode 100644 index 000000000..8b16b7b55 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -0,0 +1,30 @@ +// +// Created by Deamon on 05.02.23. +// + +#include "CommandBuffer.h" +#include "../GRenderPassVLK.h" +#include "../GFrameBufferVLK.h" +#include "../GPipelineVLK.h" + +GCommandBuffer::GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex) : m_queueFamilyIndex(queueFamilyIndex) { + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocInfo.commandBufferCount = 1; + + if (vkAllocateCommandBuffers(deviceVlk.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } +} + +CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr &renderPass) { + //If renderPass != nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside + if (m_isPrimary && renderPass != nullptr) { + std::cerr << "tried to continue renderpass in primary buffer " << std::endl; + throw std::runtime_error("tried to continue renderpass in primary buffer "); + } + + return CmdBufRecorder(*this, renderPass); +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h new file mode 100644 index 000000000..264b8663a --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -0,0 +1,31 @@ +// +// Created by Deamon on 05.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFER_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFER_H + + +#include "../volk.h" +#include "../GDeviceVulkan.h" +#include "../GFrameBufferVLK.h" +#include "commandBufferRecorder/CommandBufferRecorder.h" + +class GCommandBuffer { +public: + friend CmdBufRecorder; + friend RenderPassHelper; + +public: + GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); + + CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); +private: + VkCommandBuffer m_cmdBuffer; + bool m_isPrimary = true; + + const uint32_t m_queueFamilyIndex; +}; + + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp new file mode 100644 index 000000000..8c19d15e0 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -0,0 +1,118 @@ +// +// Created by Deamon on 06.02.23. +// + +#include "CommandBufferRecorder.h" +#include "../../GPipelineVLK.h" + +// ---------------------------------------- +// CmdBufRecorder +// ---------------------------------------- + +CmdBufRecorder::CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass) : m_gCmdBuffer(cmdBuffer) { + VkCommandBufferInheritanceInfo bufferInheritanceInfo; + + //If not nullptr -> it means this is a secondary command buffer, that needs to continue renderPass, that's going on outside + if (renderPass != nullptr) { + bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + bufferInheritanceInfo.pNext = nullptr; + bufferInheritanceInfo.renderPass = renderPass->getRenderPass(); + bufferInheritanceInfo.subpass = 0; + bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; + bufferInheritanceInfo.occlusionQueryEnable = false; + bufferInheritanceInfo.queryFlags = 0; + bufferInheritanceInfo.pipelineStatistics = 0; + + m_currentRenderPass = renderPass; + } + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.pNext = NULL; + beginInfo.pInheritanceInfo = (renderPass != nullptr) ? &bufferInheritanceInfo : nullptr; + + if (vkBeginCommandBuffer(m_gCmdBuffer.m_cmdBuffer, &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("failed to begin recording command buffer!"); + } +} +CmdBufRecorder::~CmdBufRecorder() { + if (m_gCmdBuffer.m_isPrimary && m_currentRenderPass != nullptr) { + std::cerr << "currentRenderPass is not null. RenderPass was not closed" << std::endl; + } + + if (vkEndCommandBuffer(m_gCmdBuffer.m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to record command buffer!"); + } +} + + +uint32_t CmdBufRecorder::getQueueFamily() { + return m_gCmdBuffer.m_queueFamilyIndex; +} + + +RenderPassHelper CmdBufRecorder::beginRenderPass( + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear +) { + if (m_currentRenderPass != nullptr) { + throw std::runtime_error("tried to start render pass with another pass being active already"); + } + + m_currentRenderPass = renderPassVlk; + return RenderPassHelper( + *this, + isAboutToExecSecondaryCMD, + renderPassVlk, frameBuffer, areaOffset, areaSize, colorClearColor, depthClear + ); +} + +void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet) { + //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others + //Which leads to three separate states for: + // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR + // Also, implement "Pipeline Layout Compatibility" thing from spec + + if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; + + auto vkDescSet = descriptorSet->getDescSet(); + constexpr uint32_t vkDescCnt = 1; + + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); +} + +void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { + if (m_currentPipeline == pipeline) return; + + vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline()); + + m_currentPipeline = pipeline; +} + +void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + const std::vector &imageBarrierData) { + vkCmdPipelineBarrier( + m_gCmdBuffer.m_cmdBuffer, + srcStageMask, + dstStageMask, + 0, + 0, nullptr, + 0, nullptr, + imageBarrierData.size(), imageBarrierData.data()); +} + +void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, VkImageLayout imageLayout, const std::vector ®ions) { + vkCmdCopyBufferToImage( + m_gCmdBuffer.m_cmdBuffer, + buffer, + image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(regions.size()), + regions.data()); +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h new file mode 100644 index 000000000..3c3f40b3b --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -0,0 +1,53 @@ +// +// Created by Deamon on 06.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H + +#include +#include "../../GRenderPassVLK.h" +#include "../../GFrameBufferVLK.h" + + +class CmdBufRecorder; +class RenderPassHelper; +class GCommandBuffer; + +#include "../CommandBuffer.h" +#include "RenderPassHelper.h" + +class CmdBufRecorder { +public: + friend RenderPassHelper; + + CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); + ~CmdBufRecorder(); + + uint32_t getQueueFamily(); + + RenderPassHelper beginRenderPass( + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear); + + void bindPipeline(std::shared_ptr &pipeline); + void bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet); + + void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); + void copyBufferToImage(VkBuffer buffer, VkImage image, VkImageLayout imageLayout, const std::vector ®ions); + + friend RenderPassHelper::~RenderPassHelper(); +private: + const GCommandBuffer &m_gCmdBuffer; + + //States + std::shared_ptr m_currentRenderPass = nullptr; + std::shared_ptr m_currentPipeline = nullptr; + std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; +}; + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp new file mode 100644 index 000000000..058898843 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp @@ -0,0 +1,50 @@ +// +// Created by Deamon on 06.02.23. +// + +#include "RenderPassHelper.h" +#include "CommandBufferRecorder.h" + + + +// ---------------------------------------- +// RenderPassHelper +// ---------------------------------------- + +RenderPassHelper::RenderPassHelper(CmdBufRecorder &cmdBufRecorder, + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear +) : m_cmdBufRecorder(cmdBufRecorder) { + + auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor, depthClear); + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.pNext = NULL; + renderPassInfo.renderPass = renderPassVlk->getRenderPass(); + renderPassInfo.framebuffer = frameBuffer->getFrameBuffer(); + renderPassInfo.renderArea.offset = {areaOffset[0], areaOffset[1]}; + renderPassInfo.renderArea.extent = {areaSize[0], areaSize[1]}; + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); + + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + + vkCmdBeginRenderPass( + gCmdBuffer.m_cmdBuffer, &renderPassInfo, + isAboutToExecSecondaryCMD ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE + ); +} + +RenderPassHelper::~RenderPassHelper() { + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + + vkCmdEndRenderPass(gCmdBuffer.m_cmdBuffer); + m_cmdBufRecorder.m_currentRenderPass = nullptr; +} + + diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h new file mode 100644 index 000000000..733d0f0d2 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h @@ -0,0 +1,27 @@ +// +// Created by Deamon on 06.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_RENDERPASSHELPER_H +#define AWEBWOWVIEWERCPP_RENDERPASSHELPER_H + +#include +#include "CommandBufferRecorder.h" + +class RenderPassHelper { +public: + explicit RenderPassHelper(CmdBufRecorder &cmdBufRecorder, + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear); + + ~RenderPassHelper(); +private: + CmdBufRecorder &m_cmdBufRecorder; +}; + + +#endif //AWEBWOWVIEWERCPP_RENDERPASSHELPER_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp new file mode 100644 index 000000000..e8c596660 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -0,0 +1,64 @@ +// +// Created by Deamon on 06.02.23. +// + +#include "TextureUploadHelper.h" + +TextureUploadHelper::TextureUploadHelper(CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) + : m_renderCmdBufRecorder(renderCmdBufRecorder), m_uploadCmdBufRecorder(uploadCmdBufRecorder) +{ + +} + +TextureUploadHelper::~TextureUploadHelper() { + // ------------------------------------ + // 1. Transition to upload queue + // ------------------------------------ + + std::vector imageMemoryBarriers; + imageMemoryBarriers.reserve(m_texturesToUpload.size()); + + for ( auto &textureVlk : m_texturesToUpload) { + // Image memory barriers for the texture image + VkImageMemoryBarrier &imageMemoryBarrier = imageMemoryBarriers.emplace_back(); + + // The sub resource range describes the regions of the image that will be transitioned using the memory barriers below + VkImageSubresourceRange subresourceRange = {}; + // Image only contains color data + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // Start at first mip level + subresourceRange.baseMipLevel = 0; + // We will transition on all mip levels + subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + // The 2D texture only has one layer + subresourceRange.layerCount = 1; + + // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. + imageMemoryBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + imageMemoryBarrier.subresourceRange = subresourceRange; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.image = textureVlk.texture.image; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = m_uploadCmdBufRecorder.getQueueFamily(); + } + + // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition + // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) + // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) + m_uploadCmdBufRecorder.recordPipelineBarrier( + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + imageMemoryBarriers + ); + + // 2. Do copy of texture to GPU memory + for ( auto &textureVlk : m_texturesToUpload) { + m_uploadCmdBufRecorder.copyBufferToImage( + textureVlk.texture.image + ); + } + +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h new file mode 100644 index 000000000..9604df35e --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -0,0 +1,22 @@ +// +// Created by Deamon on 06.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_TEXTUREUPLOADHELPER_H +#define AWEBWOWVIEWERCPP_TEXTUREUPLOADHELPER_H + +#include +#include "../../textures/GTextureVLK.h" + +class TextureUploadHelper { + TextureUploadHelper(CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); + ~TextureUploadHelper(); + +private: + CmdBufRecorder &m_renderCmdBufRecorder; + CmdBufRecorder &m_uploadCmdBufRecorder; + std::vector m_texturesToUpload; +}; + + +#endif //AWEBWOWVIEWERCPP_TEXTUREUPLOADHELPER_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index b71539449..f0d41744a 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -283,44 +283,12 @@ bool GTextureVLK::postLoad() { } -void GTextureVLK::updateVulkan() { +void GTextureVLK::updateVulkan(CmdBufRecorder &renderCmd, CmdBufRecorder &uploadCmd) { ///4. Fill commands to copy from CPU staging buffer to GPU buffer - // Image memory barriers for the texture image - - // The sub resource range describes the regions of the image that will be transitioned using the memory barriers below - VkImageSubresourceRange subresourceRange = {}; - // Image only contains color data - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // Start at first mip level - subresourceRange.baseMipLevel = 0; - // We will transition on all mip levels - subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - // The 2D texture only has one layer - subresourceRange.layerCount = 1; - - // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. - VkImageMemoryBarrier imageMemoryBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - imageMemoryBarrier.subresourceRange = subresourceRange; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.image = texture.image; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) - // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - vkCmdPipelineBarrier( - m_device.getUploadCommandBuffer(), - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); + + // Copy mip levels from staging buffer vkCmdCopyBufferToImage( @@ -349,7 +317,7 @@ void GTextureVLK::updateVulkan() { // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT) + // Source pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) if (m_device.canUploadInSeparateThread()) { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index fecde9776..6830af1d2 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -7,10 +7,12 @@ class GDeviceVLK; class GFrameBufferVLK; +class GCommandBuffer; + #include "../GDeviceVulkan.h" #include "../../interface/textures/ITexture.h" +#include "../commandBuffer/CommandBuffer.h" -class class GTextureVLK : public ITexture { friend class GDeviceVLK; @@ -37,7 +39,7 @@ class GTextureVLK : public ITexture { throw "Not Implemented in this class"; } - void updateVulkan(); + void updateVulkan(CmdBufRecorder &renderCmd, CmdBufRecorder &uploadCmd); bool postLoad() override;; struct Texture { From 147596838e18579ee5768e90d1e216900c62669a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 8 Feb 2023 10:58:45 +0200 Subject: [PATCH 026/212] commit --- .../CommandBufferRecorder.cpp | 2 +- .../CommandBufferRecorder.h | 2 +- .../TextureUploadHelper.cpp | 148 +++++++++++++++--- .../TextureUploadHelper.h | 10 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 4 - .../src/gapi/vulkan/textures/GTextureVLK.cpp | 43 ++--- .../src/gapi/vulkan/textures/GTextureVLK.h | 36 ++++- 7 files changed, 171 insertions(+), 74 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 8c19d15e0..d597c37b5 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -107,7 +107,7 @@ void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, Vk imageBarrierData.size(), imageBarrierData.data()); } -void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, VkImageLayout imageLayout, const std::vector ®ions) { +void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions) { vkCmdCopyBufferToImage( m_gCmdBuffer.m_cmdBuffer, buffer, diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 3c3f40b3b..4f6f10d15 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -38,7 +38,7 @@ class CmdBufRecorder { void bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet); void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); - void copyBufferToImage(VkBuffer buffer, VkImage image, VkImageLayout imageLayout, const std::vector ®ions); + void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); friend RenderPassHelper::~RenderPassHelper(); private: diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index e8c596660..67a5e1bc4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -4,21 +4,25 @@ #include "TextureUploadHelper.h" -TextureUploadHelper::TextureUploadHelper(CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) - : m_renderCmdBufRecorder(renderCmdBufRecorder), m_uploadCmdBufRecorder(uploadCmdBufRecorder) -{ +struct TransitionParams { + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; +}; -} - -TextureUploadHelper::~TextureUploadHelper() { - // ------------------------------------ - // 1. Transition to upload queue - // ------------------------------------ +void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, + const std::vector &textures, + const TransitionParams &transitionParams) { std::vector imageMemoryBarriers; - imageMemoryBarriers.reserve(m_texturesToUpload.size()); + imageMemoryBarriers.reserve(textures.size()); - for ( auto &textureVlk : m_texturesToUpload) { + for ( auto &textureVlk : textures) { // Image memory barriers for the texture image VkImageMemoryBarrier &imageMemoryBarrier = imageMemoryBarriers.emplace_back(); @@ -36,29 +40,123 @@ TextureUploadHelper::~TextureUploadHelper() { // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. imageMemoryBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; imageMemoryBarrier.subresourceRange = subresourceRange; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = transitionParams.srcAccessMask; + imageMemoryBarrier.dstAccessMask = transitionParams.dstAccessMask; + imageMemoryBarrier.oldLayout = transitionParams.oldLayout; + imageMemoryBarrier.newLayout = transitionParams.newLayout; imageMemoryBarrier.image = textureVlk.texture.image; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = m_uploadCmdBufRecorder.getQueueFamily(); + imageMemoryBarrier.srcQueueFamilyIndex = transitionParams.srcQueueFamilyIndex; + imageMemoryBarrier.dstQueueFamilyIndex = transitionParams.dstQueueFamilyIndex; } // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) - // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - m_uploadCmdBufRecorder.recordPipelineBarrier( - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, +// Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) +// Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) + uploadCmdBufRecorder.recordPipelineBarrier( + transitionParams.srcStageMask, + transitionParams.dstStageMask, imageMemoryBarriers ); +} + +void textureUploadStrategy(std::vector &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) { + // ------------------------------------ + // 1. Transition ownage to upload queue + // ------------------------------------ + + { + const TransitionParams transitionParams = { + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), + .srcStageMask = VK_PIPELINE_STAGE_HOST_BIT, + .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT + }; + + transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); + } + // ------------------------------------ // 2. Do copy of texture to GPU memory - for ( auto &textureVlk : m_texturesToUpload) { - m_uploadCmdBufRecorder.copyBufferToImage( - textureVlk.texture.image + // ------------------------------------ + + for ( auto &textureVlk : textures) { + auto updateRecord = textureVlk.getAndPlanDestroy(); + + uploadCmdBufRecorder.copyBufferToImage( + updateRecord->stagingBuffer, + textureVlk.texture.image, + updateRecord->bufferCopyRegions ); } + // -------------------------------------------------------- + // 3. Transition ownage from upload queue to render queue + // -------------------------------------------------------- + { + if (uploadCmdBufRecorder.getQueueFamily() == renderCmdBufRecorder.getQueueFamily()) { + TransitionParams transitionParams = { + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), + .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + }; + + transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); + } else { + //Change access mask + TransitionParams transitionParams = { + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT + }; + + transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); + } + + //Change ownership + { + TransitionParams transitionParams = { + .srcAccessMask = 0, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), + .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT + }; + + transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); + transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); + } + + { + TransitionParams transitionParams = { + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + }; + transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); + } + } + } + } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h index 9604df35e..55016df12 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -8,15 +8,7 @@ #include #include "../../textures/GTextureVLK.h" -class TextureUploadHelper { - TextureUploadHelper(CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); - ~TextureUploadHelper(); - -private: - CmdBufRecorder &m_renderCmdBufRecorder; - CmdBufRecorder &m_uploadCmdBufRecorder; - std::vector m_texturesToUpload; -}; +void textureUploadStrategy(std::vector &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); #endif //AWEBWOWVIEWERCPP_TEXTUREUPLOADHELPER_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 9ac85686e..57e31ab9a 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -70,10 +70,6 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe GTextureVLK::createTexture(hmipmaps, textureFormatGPU, unitedBuffer); } -//bool GBlpTextureVLK::getIsLoaded() { -// return m_loaded; -//} - bool GBlpTextureVLK::postLoad() { if (m_loaded) return false; if (!m_uploaded) { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index f0d41744a..82713c96b 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -52,6 +52,9 @@ GTextureVLK::~GTextureVLK() { void GTextureVLK::createBuffer() { } + + + void GTextureVLK::destroyBuffer() { if (!m_uploaded) return; @@ -59,19 +62,15 @@ void GTextureVLK::destroyBuffer() { auto &l_texture = texture; auto &l_imageAllocation = imageAllocation; - auto &l_stagingBuffer = stagingBuffer; - auto &l_stagingBufferAlloc = stagingBufferAlloc; - auto l_stagingBufferCreated = stagingBufferCreated; + m_device.addDeallocationRecord( - [l_device, l_texture, l_imageAllocation, l_stagingBuffer, l_stagingBufferAlloc, l_stagingBufferCreated]() { + [l_device, l_texture, l_imageAllocation]() { vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); vkDestroySampler(l_device->getVkDevice(), l_texture.sampler, nullptr); vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); - if (l_stagingBufferCreated) { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingBuffer, l_stagingBufferAlloc); - } + }); } @@ -109,6 +108,8 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & std::cout << "oops!" << std::endl << std::flush; } + m_tempUpdateData = new std::remove_pointer::type(); + auto &mipmaps = *hmipmaps; m_width = mipmaps[0].width; @@ -128,18 +129,20 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &createInfo, &allocCreateInfo, &stagingBuffer, - &stagingBufferAlloc, &stagingBufferAllocInfo)); + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &createInfo, &allocCreateInfo, + &m_tempUpdateData->stagingBuffer, + &m_tempUpdateData->stagingBufferAlloc, + &m_tempUpdateData->stagingBufferAllocInfo)); // Copy texture data into host local staging buffer - memcpy(stagingBufferAllocInfo.pMappedData, unitedBuffer.data(), unitedBuffer.size()); + memcpy(m_tempUpdateData->stagingBufferAllocInfo.pMappedData, unitedBuffer.data(), unitedBuffer.size()); ///2. Create regions to copy from CPU staging buffer to GPU buffer // Setup buffer copy regions for each mip level - bufferCopyRegions = {}; + uint32_t offset = 0; int vulkanMipMapCount = 0; @@ -150,9 +153,9 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & (textureFormatGPU != VK_FORMAT_R8G8B8A8_UNORM) && ((mipmaps[i].width < 4) || (mipmaps[i].height < 4)) ) - break; + break; - VkBufferImageCopy bufferCopyRegion; + VkBufferImageCopy &bufferCopyRegion = m_tempUpdateData->bufferCopyRegions.emplace_back(); bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.mipLevel = i; bufferCopyRegion.imageSubresource.baseArrayLayer = 0; @@ -165,8 +168,6 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & bufferCopyRegion.bufferOffset = offset; bufferCopyRegion.imageOffset = {0, 0, 0}; - bufferCopyRegions.push_back(bufferCopyRegion); - offset += static_cast(mipmaps[i].texture.size()); vulkanMipMapCount++; } @@ -287,18 +288,6 @@ void GTextureVLK::updateVulkan(CmdBufRecorder &renderCmd, CmdBufRecorder &upload ///4. Fill commands to copy from CPU staging buffer to GPU buffer - - - - // Copy mip levels from staging buffer - vkCmdCopyBufferToImage( - m_device.getUploadCommandBuffer(), - stagingBuffer, - texture.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(bufferCopyRegions.size()), - bufferCopyRegions.data()); - // Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 6830af1d2..12a49eae8 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -39,7 +39,27 @@ class GTextureVLK : public ITexture { throw "Not Implemented in this class"; } - void updateVulkan(CmdBufRecorder &renderCmd, CmdBufRecorder &uploadCmd); + auto * getAndPlanDestroy() { + if (!stagingBufferCreated || m_tempUpdateData == nullptr) { + return (decltype(m_tempUpdateData)) nullptr; + } + auto *l_device = &m_device; + auto *l_tempUpdateData = m_tempUpdateData; + + auto &l_stagingBuffer = m_tempUpdateData->stagingBuffer; + auto &l_stagingBufferAlloc = m_tempUpdateData->stagingBufferAlloc; + + + m_device.addDeallocationRecord([l_tempUpdateData, l_device, l_stagingBuffer, l_stagingBufferAlloc]() { + vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingBuffer, l_stagingBufferAlloc); + + delete l_tempUpdateData; + }); + + m_tempUpdateData = nullptr; + + return l_tempUpdateData; + } bool postLoad() override;; struct Texture { @@ -54,16 +74,18 @@ class GTextureVLK : public ITexture { virtual void bind(); //Should be called only by GDevice void unbind(); - VkBuffer stagingBuffer; - VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingBufferAllocInfo = {}; + struct updateData { + VkBuffer stagingBuffer; + VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; + VmaAllocationInfo stagingBufferAllocInfo = {}; - VmaAllocation imageAllocation = VK_NULL_HANDLE; - VmaAllocationInfo imageAllocationInfo = {}; + std::vector bufferCopyRegions = {}; + } * m_tempUpdateData = nullptr; - std::vector bufferCopyRegions = {}; + VmaAllocation imageAllocation = VK_NULL_HANDLE; + VmaAllocationInfo imageAllocationInfo = {}; protected: GDeviceVLK &m_device; From c7b202f94aba4f3e3dcb88d171dbb7db82c5810d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 13 Feb 2023 01:51:51 +0200 Subject: [PATCH 027/212] commit. pretty close to debugging whole codeflow --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 12 +- .../vulkan/FrontendUIRenderForwardVLK.h | 3 +- wowViewerLib/CMakeLists.txt | 4 +- wowViewerLib/src/gapi/interface/IDevice.h | 22 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 308 ++++++------------ wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 39 ++- .../src/gapi/vulkan/GRenderPassVLK.cpp | 8 +- wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h | 6 +- .../gapi/vulkan/GVertexBufferBindingsVLK.h | 2 - wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 30 ++ .../vulkan/commandBuffer/CommandBuffer.cpp | 44 ++- .../gapi/vulkan/commandBuffer/CommandBuffer.h | 14 +- .../CommandBufferRecorder.h | 4 +- .../TextureUploadHelper.cpp | 67 ++-- .../TextureUploadHelper.h | 1 + .../src/gapi/vulkan/context/vulkan_context.h | 30 ++ .../descriptorSets/GDescriptorPoolVLK.cpp | 3 +- .../descriptorSets/GDescriptorPoolVLK.h | 9 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.h | 7 +- .../descriptorSets/GDescriptorSetLayout.cpp | 4 +- .../descriptorSets/GDescriptorSetLayout.h | 8 +- .../vulkan/materials/ISimpleMaterialVLK.h | 1 + .../gapi/vulkan/syncronization/GFenceVLK.cpp | 34 ++ .../gapi/vulkan/syncronization/GFenceVLK.h | 28 ++ .../vulkan/syncronization/GSemaphoreVLK.cpp | 5 + .../vulkan/syncronization/GSemaphoreVLK.h | 14 + .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 5 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 61 +--- .../src/gapi/vulkan/textures/GTextureVLK.h | 13 +- wowViewerLib/src/renderer/IRenderParameters.h | 14 +- .../src/renderer/frame/SceneComposer.cpp | 3 +- .../src/renderer/frame/SceneScenario.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 3 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../src/renderer/vulkan/IRenderFunctionVLK.h | 37 +++ 37 files changed, 435 insertions(+), 416 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h create mode 100644 wowViewerLib/src/gapi/vulkan/context/vulkan_context.h create mode 100644 wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h create mode 100644 wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 8fa00420f..bbbdaa952 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -7,6 +7,7 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h" FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( hDevice), m_device(hDevice) { @@ -56,15 +57,16 @@ HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); } -void FrontendUIRenderForwardVLK::updateAndDraw( +std::unique_ptr FrontendUIRenderForwardVLK::update( const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { - std::vector meshes; - this->consumeFrameInput(frameInputParams, meshes); + auto meshes = std::make_unique>(); + this->consumeFrameInput(frameInputParams, *meshes); //Record commands to update buffer and draw - [&meshes](VkCommandBuffer transferQueueCMD, VkCommandBuffer renderFB, VkCommandBuffer renderSwapFB) { - }; + return createRenderFuncVLK(std::move([meshes = std::move(meshes)](CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) { + + })); } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index ab893282f..101351ce7 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -12,13 +12,14 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +#include "../../../../../wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: explicit FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice); ~FrontendUIRenderForwardVLK() override = default; - void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; public: HGVertexBuffer createVertexBuffer(int sizeInBytes) override; HGIndexBuffer createIndexBuffer(int sizeInBytes) override; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 9e79270a1..bf91e0d62 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -493,7 +493,7 @@ if (LINK_VULKAN) src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h src/gapi/vulkan/commandBuffer/CommandBuffer.cpp - src/gapi/vulkan/commandBuffer/CommandBuffer.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h) + src/gapi/vulkan/commandBuffer/CommandBuffer.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h src/gapi/vulkan/IDeviceVulkan.h src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp src/gapi/vulkan/syncronization/GSemaphoreVLK.h src/gapi/vulkan/syncronization/GFenceVLK.cpp src/gapi/vulkan/syncronization/GFenceVLK.h src/renderer/vulkan/IRenderFunctionVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) @@ -537,7 +537,7 @@ if (LINK_VULKAN) # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() #Add volk loader - set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c) + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c src/gapi/vulkan/context/vulkan_context.h) endif() diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 1d7c7ef17..fdcb5ff1b 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -28,27 +28,7 @@ class gMeshTemplate; #include #include "syncronization/IGPUFence.h" -#ifdef LINK_VULKAN - #define VK_NO_PROTOTYPES - #include "../vulkan/volk.h" - - //HACKS for stupid defines in X11 - #undef None // Defined by X11/X.h to 0L - #undef Status // Defined by X11/Xlib.h to int - #undef True // Defined by X11/Xlib.h to 1 - #undef False // Defined by X11/Xlib.h to 0 - #undef Bool // Defined by X11/Xlib.h to int - #undef RootWindow // Defined by X11/Xlib.h - #undef CurrentTime // Defined by X11/X.h to 0L - #undef Success // Defined by X11/X.h to 0 - #undef DestroyAll // Defined by X11/X.h to 0 - #undef COUNT // Defined by X11/extensions/XI.h to 0 - #undef CREATE // Defined by X11/extensions/XI.h to 1 - #undef DeviceAdded // Defined by X11/extensions/XI.h to 0 - #undef DeviceRemoved // Defined by X11/extensions/XI.h to 1 - - #include "../vulkan/vk_mem_alloc.h" -#endif +#include "../vulkan/context/vulkan_context.h" typedef std::shared_ptr HGVertexBufferDynamic; typedef std::shared_ptr HGVertexBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 7ffba4eaf..f86410293 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -25,6 +25,8 @@ #include "GRenderPassVLK.h" #include "../../engine/algorithms/FrameCounter.h" #include "buffers/GBufferVLK.h" +#include "syncronization/GFenceVLK.h" +#include "../../renderer/vulkan/IRenderFunctionVLK.h" //#include "fastmemcp.h" #include @@ -203,7 +205,7 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { } createInfo.enabledExtensionCount = extensionsVec.size(); - createInfo.ppEnabledExtensionNames = &extensionsVec[0]; + createInfo.ppEnabledExtensionNames = extensionsVec.data(); //Request validation layers @@ -272,11 +274,11 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { createDepthResources(); createFramebuffers(); createCommandPool(); + createCommandPoolForUpload(); + createCommandBuffers(); createSyncObjects(); - createCommandPoolForUpload(); - createCommandBuffersForUpload(); vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); uniformBufferOffsetAlign = deviceProperties.limits.minUniformBufferOffsetAlignment; @@ -421,7 +423,7 @@ VkFormat GDeviceVLK::findDepthFormat() { } void GDeviceVLK::createRenderPass() { - swapchainRenderPass = std::make_shared(*this, + swapchainRenderPass = std::make_shared(this->device, std::vector({swapChainImageFormat}), findDepthFormat(), VK_SAMPLE_COUNT_1_BIT, @@ -716,129 +718,74 @@ void GDeviceVLK::createCommandPoolForUpload(){ } void GDeviceVLK::createCommandBuffers() { - commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - - - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = commandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t) commandBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } - - if (!getIsAsynBuffUploadSupported()) { - createCommandBuffersForUpload(); - } -} -void GDeviceVLK::createCommandBuffersForUpload() { - renderCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - renderCommandBuffersNotNull.resize(MAX_FRAMES_IN_FLIGHT); - renderCommandBuffersForFrameBuffers.resize(MAX_FRAMES_IN_FLIGHT); - renderCommandBuffersForFrameBuffersNotNull.resize(MAX_FRAMES_IN_FLIGHT); - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) renderCommandBuffersNotNull[i] = false; - { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = renderCommandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocInfo.commandBufferCount = (uint32_t) renderCommandBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfo, renderCommandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } + for (auto & commandBuffer : commandBuffers) { + commandBuffer = std::make_shared(*this, commandPool, false, indices.graphicsFamily); } - { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = renderCommandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t) renderCommandBuffersForFrameBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfo, renderCommandBuffersForFrameBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } - } - uploadCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - VkCommandBufferAllocateInfo allocInfoUpload = {}; - allocInfoUpload.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfoUpload.commandPool = uploadCommandPool; - allocInfoUpload.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfoUpload.commandBufferCount = (uint32_t) commandBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfoUpload, uploadCommandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate upload command buffers!"); + for (auto & commandBuffer : uploadCommandBuffers) { + commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.graphicsFamily); } - textureTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - textureTransferCommandBufferNull.resize(MAX_FRAMES_IN_FLIGHT); - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) textureTransferCommandBufferNull[i] = true; - VkCommandBufferAllocateInfo texttrAllocInfoUpload = {}; - texttrAllocInfoUpload.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - texttrAllocInfoUpload.commandPool = commandPoolForImageTransfer; - texttrAllocInfoUpload.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - texttrAllocInfoUpload.commandBufferCount = (uint32_t) textureTransferCommandBuffers.size(); - - if (vkAllocateCommandBuffers(device, &texttrAllocInfoUpload, textureTransferCommandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate upload command buffers!"); + for (auto & commandBuffer : presentCommandBuffers) { + commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily); } } -void GDeviceVLK::createSyncObjects() { - imageAvailableSemaphores.resize(commandBuffers.size()); - renderFinishedSemaphores.resize(commandBuffers.size()); - textureTransferFinishedSemaphores.resize(commandBuffers.size()); - - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreInfo.pNext = NULL; - - for (size_t i = 0; i < commandBuffers.size(); i++) { - if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &textureTransferFinishedSemaphores[i]) != VK_SUCCESS) { - - throw std::runtime_error("failed to create synchronization objects for a frame!"); - } - } - - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.pNext = NULL; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create synchronization objects for a frame!"); - } - } - inFlightTextureTransferFences.resize(MAX_FRAMES_IN_FLIGHT); - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightTextureTransferFences[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create synchronization objects for a textureUpdate!"); - } - } - - VkFenceCreateInfo uploadFenceInfo = {}; - uploadFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - uploadFenceInfo.pNext = NULL; - uploadFenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; +void GDeviceVLK::createSyncObjects() { +//TODO: - uploadSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - uploadFences.resize(MAX_FRAMES_IN_FLIGHT); - uploadSemaphoresSubmited.resize(MAX_FRAMES_IN_FLIGHT); - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &uploadSemaphores[i]); - vkCreateFence(device, &uploadFenceInfo, nullptr, &uploadFences[i]); - uploadSemaphoresSubmited[i] = false; - } +// imageAvailableSemaphores.resize(commandBuffers.size()); +// renderFinishedSemaphores.resize(commandBuffers.size()); +// textureTransferFinishedSemaphores.resize(commandBuffers.size()); +// +// +// VkSemaphoreCreateInfo semaphoreInfo = {}; +// semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; +// semaphoreInfo.pNext = NULL; +// +// for (size_t i = 0; i < commandBuffers.size(); i++) { +// if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || +// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS || +// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &textureTransferFinishedSemaphores[i]) != VK_SUCCESS) { +// +// throw std::runtime_error("failed to create synchronization objects for a frame!"); +// } +// } +// +// VkFenceCreateInfo fenceInfo = {}; +// fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; +// fenceInfo.pNext = NULL; +// fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; +// +// inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); +// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { +// if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { +// throw std::runtime_error("failed to create synchronization objects for a frame!"); +// } +// } +// inFlightTextureTransferFences.resize(MAX_FRAMES_IN_FLIGHT); +// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { +// if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightTextureTransferFences[i]) != VK_SUCCESS) { +// throw std::runtime_error("failed to create synchronization objects for a textureUpdate!"); +// } +// } +// +// +// VkFenceCreateInfo uploadFenceInfo = {}; +// uploadFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; +// uploadFenceInfo.pNext = NULL; +// uploadFenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; +// +// uploadSemaphores.resize(MAX_FRAMES_IN_FLIGHT); +// uploadFences.resize(MAX_FRAMES_IN_FLIGHT); +// uploadSemaphoresSubmited.resize(MAX_FRAMES_IN_FLIGHT); +// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { +// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &uploadSemaphores[i]); +// vkCreateFence(device, &uploadFenceInfo, nullptr, &uploadFences[i]); +// uploadSemaphoresSubmited[i] = false; +// } } @@ -865,68 +812,20 @@ float GDeviceVLK::getAnisLevel() { return deviceProperties.limits.maxSamplerAnisotropy; } - -void GDeviceVLK::startUpdateForNextFrame() { +void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { int uploadFrame = getUpdateFrameNumber(); - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = NULL; - -// std::cout << "updateBuffers: updateFrame = " << uploadFrame << std::endl; this->waitInDrawStageAndDeps.beginMeasurement(); - vkWaitForFences(device, 1, &uploadFences[uploadFrame], VK_TRUE, std::numeric_limits::max()); - vkWaitForFences(device, 1, &inFlightFences[uploadFrame], VK_TRUE, std::numeric_limits::max()); - vkResetFences(device, 1, &uploadFences[uploadFrame]); + uploadFences[uploadFrame]->wait(std::numeric_limits::max()); + inFlightFences[uploadFrame]->wait(std::numeric_limits::max()); + uploadFences[uploadFrame]->reset(); this->waitInDrawStageAndDeps.endMeasurement(); - if (vkBeginCommandBuffer(uploadCommandBuffers[uploadFrame], &beginInfo) != VK_SUCCESS) { - std::cout << "failed to begin recording uploadCommandBuffer command buffer!" << std::endl; - } - - textureTransferCommandBufferNull[uploadFrame] = true; -// vkWaitForFences(device, 1, &inFlightTextureTransferFences[uploadFrame], VK_TRUE, std::numeric_limits::max()); - if (vkBeginCommandBuffer(textureTransferCommandBuffers[uploadFrame], &beginInfo) != VK_SUCCESS) { - std::cout << "failed to begin recording textureTransferCommandBuffers command buffer!" << std::endl; - } -} -void GDeviceVLK::endUpdateForNextFrame() { - int uploadFrame = getUpdateFrameNumber(); - if (vkEndCommandBuffer(uploadCommandBuffers[uploadFrame]) != VK_SUCCESS) { - std::cout << "failed to record uploadCommandBuffer command buffer!" << std::endl; - } - if (vkEndCommandBuffer(textureTransferCommandBuffers[uploadFrame]) != VK_SUCCESS) { - std::cout << "failed to record textureTransferCommandBuffers command buffer!" << std::endl; - } - if (this->canUploadInSeparateThread()) { - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &uploadCommandBuffers[uploadFrame]; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &uploadSemaphores[uploadFrame]; - uploadSemaphoresSubmited[uploadFrame] = true; + auto uploadCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); - { - auto result = vkQueueSubmit(uploadQueue, 1, &submitInfo, uploadFences[uploadFrame]); - if ( result != VK_SUCCESS) { - std::cout << "failed to submit uploadCommandBuffer command buffer! result = " << result << std::endl << std::flush; - } - } - } - - { - std::lock_guard lock(m_listOfDeallocatorsAccessMtx); - while ((!listOfDeallocators.empty()) && (listOfDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { - auto stuff = listOfDeallocators.front(); - if (stuff.callback != nullptr) { - stuff.callback(); - } - - listOfDeallocators.pop_front(); - } + for (int i = 0; i < renderFuncs.size(); i++) { + dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, ) } } @@ -1164,21 +1063,6 @@ void GDeviceVLK::submitDrawCommands() { std::cout << "got VK_ERROR_OUT_OF_DATE_KHR" << std::endl << std::flush; recreateSwapChain(); - if (!this->canUploadInSeparateThread()) { - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &uploadCommandBuffers[currentDrawFrame]; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &uploadSemaphores[currentDrawFrame]; - uploadSemaphoresSubmited[currentDrawFrame] = true; - - - - if (vkQueueSubmit(uploadQueue, 1, &submitInfo, uploadFences[currentDrawFrame]) != VK_SUCCESS) { - std::cout << "failed to submit uploadCommandBuffer command buffer!" << std::endl << std::flush; - } - } - return; } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { std::cout << "error happened " << result << std::endl << std::flush; @@ -1195,25 +1079,8 @@ void GDeviceVLK::submitDrawCommands() { // std::cout << "imageIndex != currentDrawFrame" << std::endl; } - if (!this->canUploadInSeparateThread()) { - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &uploadCommandBuffers[currentDrawFrame]; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &uploadSemaphores[currentDrawFrame]; - uploadSemaphoresSubmited[currentDrawFrame] = true; - - vkResetFences(device, 1, &uploadFences[currentDrawFrame]); - { - auto result = vkQueueSubmit(uploadQueue, 1, &submitInfo, uploadFences[currentDrawFrame]); - if ( result != VK_SUCCESS) { - std::cout << "failed to submit uploadCommandBuffer command buffer! result = " << result << std::endl << std::flush; - } - } - } - - vkWaitForFences(device, 1, &inFlightFences[currentDrawFrame], VK_TRUE, std::numeric_limits::max()); - vkResetFences(device, 1, &inFlightFences[currentDrawFrame]); + inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); + inFlightFences[currentDrawFrame]->reset(); //Fill command buffer //TODO:!!! @@ -1329,6 +1196,20 @@ void GDeviceVLK::submitDrawCommands() { std::cout << "failed to present swap chain image!" << std::endl << std::flush; // throw std::runtime_error("failed to present swap chain image!"); } + + executeDeallocators(); +} + +void GDeviceVLK::executeDeallocators() { + std::lock_guard lock(m_listOfDeallocatorsAccessMtx); + while ((!listOfDeallocators.empty()) && (listOfDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { + auto stuff = listOfDeallocators.front(); + if (stuff.callback != nullptr) { + stuff.callback(); + } + + listOfDeallocators.pop_front(); + } } std::shared_ptr GDeviceVLK::getRenderPass( @@ -1880,20 +1761,13 @@ void GDeviceVLK::singleExecuteAndWait(std::function callb submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; - // Create fence to ensure that the command buffer has finished executing - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.pNext = NULL; - fenceInfo.flags = 0; + GFenceVLK fenceVlk(this->shared_from_this()); - VkFence fence; - ERR_GUARD_VULKAN(vkCreateFence(device, &fenceInfo, nullptr, &fence)); - // Submit to the queue - ERR_GUARD_VULKAN(vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence)); + // Submit to the queue + ERR_GUARD_VULKAN(vkQueueSubmit(graphicsQueue, 1, &submitInfo, fenceVlk.getNativeFence())); // Wait for the fence to signal that command buffer has finished executing - ERR_GUARD_VULKAN(vkWaitForFences(device, 1, &fence, VK_TRUE, std::numeric_limits::max())); + fenceVlk.wait(std::numeric_limits::max()); - vkDestroyFence(device, fence, nullptr); vkFreeCommandBuffers(device, commandPool, 1, ©Cmd); } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index b72026994..b3d07b44e 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -32,12 +32,16 @@ class gMeshTemplate; #include "descriptorSets/GDescriptorSet.h" #include "descriptorSets/GDescriptorPoolVLK.h" #include "../../engine/algorithms/FrameCounter.h" +#include "../../renderer/IRenderParameters.h" #include "buffers/GBufferVLK.h" +#include "IDeviceVulkan.h" +#include "syncronization/GFenceVLK.h" + #include VkSampleCountFlagBits sampleCountToVkSampleCountFlagBits(uint8_t sampleCount); -class GDeviceVLK : public IDevice, public std::enable_shared_from_this { +class GDeviceVLK : public IDevice, public std::enable_shared_from_this, public IDeviceVulkan { struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; @@ -85,8 +89,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> &renderFuncs); void updateBuffers(/*std::vector*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; @@ -138,11 +144,13 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &hDescriptorSetLayout, std::shared_ptr &desciptorPool); + VkDescriptorSet allocateDescriptorSetPrimitive( + const std::shared_ptr &hDescriptorSetLayout, + std::shared_ptr &desciptorPool) override; + std::shared_ptr createDescriptorSet(std::shared_ptr &hDescriptorSetLayout); - virtual VkDevice getVkDevice() { + virtual VkDevice getVkDevice() override { return device; }; virtual VkPhysicalDevice getVkPhysicalDevice() { @@ -155,7 +163,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this commandBuffers; + std::array, MAX_FRAMES_IN_FLIGHT> commandBuffers = {nullptr}; + std::array, MAX_FRAMES_IN_FLIGHT> uploadCommandBuffers = {nullptr}; + std::array, MAX_FRAMES_IN_FLIGHT> presentCommandBuffers = {nullptr}; - std::vector imageAvailableSemaphores; - std::vector renderFinishedSemaphores; - std::vector textureTransferFinishedSemaphores; - std::vector inFlightFences; - std::vector inFlightTextureTransferFences; - std::vector uploadSemaphoresSubmited; - std::vector uploadSemaphores; - std::vector uploadFences; + std::array, MAX_FRAMES_IN_FLIGHT> inFlightFences; + std::array, MAX_FRAMES_IN_FLIGHT> uploadFences; std::vector> m_descriptorPools; @@ -367,6 +370,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_createdRenderPasses; + + void executeDeallocators(); }; diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp index f16d00d5b..77b9142bc 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp @@ -2,10 +2,12 @@ // Created by Deamon on 12/14/2020. // +#include #include "GRenderPassVLK.h" -GRenderPassVLK::GRenderPassVLK(GDeviceVLK &device, std::vector textureAttachments, VkFormat depthAttachmentFormat, - VkSampleCountFlagBits sampleCountBit, bool isSwapChainPass) : mdevice(device) { + +GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, std::vector textureAttachments, VkFormat depthAttachmentFormat, + VkSampleCountFlagBits sampleCountBit, bool isSwapChainPass) { m_sampleCountBit = sampleCountBit; std::vector attachments; @@ -130,7 +132,7 @@ GRenderPassVLK::GRenderPassVLK(GDeviceVLK &device, std::vector texture renderPassInfo.dependencyCount = dependencies.size(); renderPassInfo.pDependencies = dependencies.data(); - if (vkCreateRenderPass(device.getVkDevice(), &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { + if (vkCreateRenderPass(vkDevice, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { throw std::runtime_error("failed to create render pass!"); } } diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h index 3b0ad6dd2..385ab1072 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h @@ -5,12 +5,13 @@ #ifndef AWEBWOWVIEWERCPP_GRENDERPASSVLK_H #define AWEBWOWVIEWERCPP_GRENDERPASSVLK_H -#include "GDeviceVulkan.h" +#include "context/vulkan_context.h" #include +#include class GRenderPassVLK { public: - GRenderPassVLK(GDeviceVLK &device, std::vector textureAttachments, + GRenderPassVLK(VkDevice vkDevice, std::vector textureAttachments, VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, bool isSwapChainPass); @@ -21,7 +22,6 @@ class GRenderPassVLK { private: VkSampleCountFlagBits m_sampleCountBit; - GDeviceVLK &mdevice; VkRenderPass renderPass; enum class AttachmentType { diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h index b4160d5fd..94c6aef56 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h @@ -13,7 +13,6 @@ class GVertexBufferBindingsVLK; #include #include "../interface/IVertexBufferBindings.h" #include "../interface/IDevice.h" -#include "GDeviceVulkan.h" struct vkBufferFormatHolder { @@ -22,7 +21,6 @@ struct vkBufferFormatHolder { }; class GVertexBufferBindingsVLK : public IVertexBufferBindings { - friend class GDeviceVLK; private: std::vector m_bindings; std::vector m_BufferBindingsVLK; diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h new file mode 100644 index 000000000..b1b8f5690 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -0,0 +1,30 @@ +// +// Created by Deamon on 09.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_IDEVICEVULKAN_H +#define AWEBWOWVIEWERCPP_IDEVICEVULKAN_H + +#include +#include "descriptorSets/GDescriptorSetLayout.h" +#include "descriptorSets/GDescriptorPoolVLK.h" + +class IDeviceVulkan { +public: + virtual ~IDeviceVulkan() = default; + + virtual VkDevice getVkDevice() = 0; + virtual void addDeallocationRecord(std::function callback) = 0; + virtual VkDescriptorSet allocateDescriptorSetPrimitive( + const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) = 0; + + virtual VmaAllocator getVMAAllocator() = 0; + + //TODO: + bool getIsAnisFiltrationSupported() {return true;}; + //TODO: + bool getIsCompressedTexturesSupported() {return true;}; + virtual float getAnisLevel() = 0; +}; + +#endif //AWEBWOWVIEWERCPP_IDEVICEVULKAN_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index 8b16b7b55..9a59847d4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -3,20 +3,16 @@ // #include "CommandBuffer.h" -#include "../GRenderPassVLK.h" -#include "../GFrameBufferVLK.h" -#include "../GPipelineVLK.h" -GCommandBuffer::GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex) : m_queueFamilyIndex(queueFamilyIndex) { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = commandPool; - allocInfo.level = isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocInfo.commandBufferCount = 1; +GCommandBuffer::GCommandBuffer(IDeviceVulkan &deviceVlk, + VkCommandPool commandPool, + bool isPrimary, + uint32_t queueFamilyIndex) : m_device(deviceVlk), + m_isPrimary(isPrimary), + m_queueFamilyIndex(queueFamilyIndex), + m_commandPool(commandPool) +{ - if (vkAllocateCommandBuffers(deviceVlk.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } } CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr &renderPass) { @@ -26,5 +22,29 @@ CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr throw std::runtime_error("tried to continue renderpass in primary buffer "); } + createCommandBufVLK(); + return CmdBufRecorder(*this, renderPass); } + +void GCommandBuffer::createCommandBufVLK() { + if (m_cmdBufWasCreated) { + //Dispose of previous buffer + auto l_cmdBuf = m_cmdBuffer; + auto l_deviceVlk = m_device.getVkDevice(); + auto l_commandPool = m_commandPool; + m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_commandPool]() -> void { + vkFreeCommandBuffers(l_deviceVlk, l_commandPool, 1, &l_cmdBuf); + }); + } + + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_commandPool; + allocInfo.level = m_isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocInfo.commandBufferCount = 1; + + if (vkAllocateCommandBuffers(m_device.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index 264b8663a..ac86e5494 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -13,18 +13,24 @@ class GCommandBuffer { public: - friend CmdBufRecorder; - friend RenderPassHelper; + friend class CmdBufRecorder; + friend class RenderPassHelper; public: - GCommandBuffer(GDeviceVLK &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); + GCommandBuffer(IDeviceVulkan &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); private: + void createCommandBufVLK(); + +private: + IDeviceVulkan &m_device; VkCommandBuffer m_cmdBuffer; bool m_isPrimary = true; - const uint32_t m_queueFamilyIndex; + VkCommandPool m_commandPool; + + bool m_cmdBufWasCreated = false; }; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 4f6f10d15..e6c9b502f 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -10,12 +10,14 @@ #include "../../GFrameBufferVLK.h" + class CmdBufRecorder; class RenderPassHelper; class GCommandBuffer; #include "../CommandBuffer.h" #include "RenderPassHelper.h" +#include "../../descriptorSets/GDescriptorSet.h" class CmdBufRecorder { public: @@ -40,7 +42,7 @@ class CmdBufRecorder { void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); - friend RenderPassHelper::~RenderPassHelper(); + friend class RenderPassHelper; private: const GCommandBuffer &m_gCmdBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index 67a5e1bc4..7e5b1dac9 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -4,6 +4,7 @@ #include "TextureUploadHelper.h" + struct TransitionParams { VkAccessFlags srcAccessMask; VkAccessFlags dstAccessMask; @@ -94,7 +95,7 @@ void textureUploadStrategy(std::vector &textures, CmdBufRecorder &r } // -------------------------------------------------------- - // 3. Transition ownage from upload queue to render queue + // 3. Transition ownership from upload queue to render queue // -------------------------------------------------------- { if (uploadCmdBufRecorder.getQueueFamily() == renderCmdBufRecorder.getQueueFamily()) { @@ -124,39 +125,37 @@ void textureUploadStrategy(std::vector &textures, CmdBufRecorder &r }; transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); - } - - //Change ownership - { - TransitionParams transitionParams = { - .srcAccessMask = 0, - .dstAccessMask = 0, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), - .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), - .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, - .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT - }; - - transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); - transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); - } - - { - TransitionParams transitionParams = { - .srcAccessMask = 0, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, - .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT - }; - transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); - } } - } + //Change ownership + { + TransitionParams transitionParams = { + .srcAccessMask = 0, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), + .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT + }; + + transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); + transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); + } + + { + TransitionParams transitionParams = { + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + }; + transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); + } + } } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h index 55016df12..82e743584 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -7,6 +7,7 @@ #include #include "../../textures/GTextureVLK.h" +#include "CommandBufferRecorder.h" void textureUploadStrategy(std::vector &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); diff --git a/wowViewerLib/src/gapi/vulkan/context/vulkan_context.h b/wowViewerLib/src/gapi/vulkan/context/vulkan_context.h new file mode 100644 index 000000000..7eb28ba09 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/context/vulkan_context.h @@ -0,0 +1,30 @@ +// +// Created by Deamon on 09.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_VULKAN_CONTEXT_H +#define AWEBWOWVIEWERCPP_VULKAN_CONTEXT_H + +#ifdef LINK_VULKAN +#define VK_NO_PROTOTYPES +#include "../volk.h" + +//HACKS for stupid defines in X11 +#undef None // Defined by X11/X.h to 0L +#undef Status // Defined by X11/Xlib.h to int +#undef True // Defined by X11/Xlib.h to 1 +#undef False // Defined by X11/Xlib.h to 0 +#undef Bool // Defined by X11/Xlib.h to int +#undef RootWindow // Defined by X11/Xlib.h +#undef CurrentTime // Defined by X11/X.h to 0L +#undef Success // Defined by X11/X.h to 0 +#undef DestroyAll // Defined by X11/X.h to 0 +#undef COUNT // Defined by X11/extensions/XI.h to 0 +#undef CREATE // Defined by X11/extensions/XI.h to 1 +#undef DeviceAdded // Defined by X11/extensions/XI.h to 0 +#undef DeviceRemoved // Defined by X11/extensions/XI.h to 1 + +#include "../vk_mem_alloc.h" +#endif + +#endif //AWEBWOWVIEWERCPP_VULKAN_CONTEXT_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index fc37d2a1c..f303de5ce 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -5,9 +5,8 @@ #include #include "GDescriptorPoolVLK.h" -#include "../shaders/GShaderPermutationVLK.h" -GDescriptorPoolVLK::GDescriptorPoolVLK(IDevice &device) : m_device(dynamic_cast(device)) { +GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) { uniformsAvailable = 5*4096; imageAvailable = 4096 * 4; setsAvailable = 4096; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h index a6d23a927..2f7b5d5fe 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -6,21 +6,20 @@ #define AWEBWOWVIEWERCPP_GDESCRIPTORPOOLVLK_H class GDescriptorSet; +class GDescriptorPoolVLK; -#include "../../interface/IDevice.h" -#include "../GDeviceVulkan.h" -#include "GDescriptorSet.h" +#include "../IDeviceVulkan.h" #include "GDescriptorSetLayout.h" class GDescriptorPoolVLK : public std::enable_shared_from_this{ public: - explicit GDescriptorPoolVLK(IDevice &device); + explicit GDescriptorPoolVLK(IDeviceVulkan &device); VkDescriptorSet allocate(const std::shared_ptr &gDescriptorSetLayout); void deallocate(const std::shared_ptr &hDescriptorLayout, VkDescriptorSet descSet); private: - GDeviceVLK &m_device; + IDeviceVulkan &m_device; VkDescriptorPool m_descriptorPool; int uniformsAvailable = 0; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 7f615e33d..f6985eb7d 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -6,7 +6,7 @@ #include "../textures/GTextureVLK.h" -GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout) +GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout) : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 13c7027ad..0eb4851fb 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -11,8 +11,9 @@ class GDescriptorPoolVLK; #include #include #include "../../interface/IDevice.h" -#include "../GDeviceVulkan.h" +#include "../IDeviceVulkan.h" #include "../buffers/IBufferVLK.h" +#include "../textures/GTextureVLK.h" #include "GDescriptorSetLayout.h" @@ -20,7 +21,7 @@ class GDescriptorSet { public: static const constexpr int MAX_BINDPOINT_NUMBER = 16; - explicit GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout); + explicit GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout); ~GDescriptorSet(); void update(); @@ -68,7 +69,7 @@ class GDescriptorSet { SetUpdateHelper beginUpdate(); private: - std::shared_ptr m_device; + std::shared_ptr m_device; VkDescriptorSet m_descriptorSet; std::shared_ptr m_parentPool; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 43325febb..615ff29b3 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -4,8 +4,10 @@ #include #include "GDescriptorSetLayout.h" +#include "../GDeviceVulkan.h" -GDescriptorSetLayout::GDescriptorSetLayout(std::shared_ptr &device, const std::vector &metaDatas, int setIndex) : m_device(device) { + +GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaDatas, int setIndex) : m_device(device) { //Create Layout std::unordered_map shaderLayoutBindings; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 27bbdea76..5c15a974a 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -8,13 +8,15 @@ #include class GDescriptorSetLayout; +class IDeviceVulkan; -#include "../GDeviceVulkan.h" +#include "../context/vulkan_context.h" +#include "../IDeviceVulkan.h" #include "../../../engine/shader/ShaderDefinitions.h" class GDescriptorSetLayout { public: - GDescriptorSetLayout(std::shared_ptr &device, const std::vector &metaData, int setIndex); + GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaData, int setIndex); ~GDescriptorSetLayout(); @@ -30,7 +32,7 @@ class GDescriptorSetLayout { int m_totalImages = 0; int m_totalUbos = 0; - std::shared_ptr m_device; + std::shared_ptr m_device; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 8fec9e82e..9031c54db 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -11,6 +11,7 @@ #include "../../interface/materials/IMaterial.h" #include "../descriptorSets/GDescriptorSet.h" #include "../textures/GTextureVLK.h" +#include "../GDeviceVulkan.h" class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp new file mode 100644 index 000000000..2719d729a --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp @@ -0,0 +1,34 @@ +// +// Created by Deamon on 11.02.23. +// + +#include "GFenceVLK.h" +#include "../../interface/IDevice.h" + +GFenceVLK::GFenceVLK(const std::shared_ptr &deviceVulkan) : m_device(deviceVulkan) { + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.pNext = NULL; + fenceInfo.flags = 0; + + ERR_GUARD_VULKAN(vkCreateFence(m_device->getVkDevice(), &fenceInfo, nullptr, &m_fence)); +} + +GFenceVLK::~GFenceVLK() { + auto l_deviceVlk = m_device->getVkDevice(); + auto l_fence = m_fence; + + m_device->addDeallocationRecord([l_deviceVlk, l_fence]() { + vkDestroyFence(l_deviceVlk, l_fence, nullptr); + }); +} + +constexpr int FENCES_COUNT = 1; + +void GFenceVLK::wait(uint64_t maxWaitTime) { + ERR_GUARD_VULKAN(vkWaitForFences(m_device->getVkDevice(), FENCES_COUNT, &m_fence, VK_TRUE, maxWaitTime)); +} + +void GFenceVLK::reset() { + ERR_GUARD_VULKAN(vkResetFences(m_device->getVkDevice(), FENCES_COUNT, &m_fence)); +} diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h new file mode 100644 index 000000000..e2b7ef2de --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h @@ -0,0 +1,28 @@ +// +// Created by Deamon on 11.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_GFENCEVLK_H +#define AWEBWOWVIEWERCPP_GFENCEVLK_H + +#include +#include "../context/vulkan_context.h" +#include "../IDeviceVulkan.h" + +class GFenceVLK { +public: + GFenceVLK(const std::shared_ptr &deviceVulkan); + ~GFenceVLK(); + + void wait(uint64_t maxWaitTime); + void reset(); + + VkFence getNativeFence() {return m_fence;}; +private: + std::shared_ptr m_device; + VkFence m_fence; + +}; + + +#endif //AWEBWOWVIEWERCPP_GFENCEVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp new file mode 100644 index 000000000..b102ae9fe --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 11.02.23. +// + +#include "GSemaphoreVLK.h" diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h new file mode 100644 index 000000000..77a246e09 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h @@ -0,0 +1,14 @@ +// +// Created by Deamon on 11.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_GSEMAPHOREVLK_H +#define AWEBWOWVIEWERCPP_GSEMAPHOREVLK_H + + +class GSemaphoreVLK { + +}; + + +#endif //AWEBWOWVIEWERCPP_GSEMAPHOREVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 57e31ab9a..f591bf755 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -6,7 +6,7 @@ #include "../../../engine/persistance/helper/ChunkFileReader.h" #include "../../../engine/texture/DxtDecompress.h" -GBlpTextureVLK::GBlpTextureVLK(IDevice &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex) +GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex) : GTextureVLK(device,xWrapTex,yWrapTex), m_texture(texture) { } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index 550a36cb4..6eacec2b9 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -6,12 +6,11 @@ #define WEBWOWVIEWERCPP_GBLPTEXTUREVLK_H #include "GTextureVLK.h" -#include "../GDeviceVulkan.h" +#include "../IDeviceVulkan.h" class GBlpTextureVLK : public GTextureVLK { - friend class GDeviceVLK; - explicit GBlpTextureVLK(IDevice &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); public: + explicit GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); ~GBlpTextureVLK() override; void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 82713c96b..ad0970622 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -6,19 +6,19 @@ #include "GTextureVLK.h" #include "../../interface/IDevice.h" -GTextureVLK::GTextureVLK(IDevice &device, bool xWrapTex, bool yWrapTex) : m_device(dynamic_cast(device)) { +GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex) : m_device(device) { this->m_wrapX = xWrapTex; this->m_wrapY = yWrapTex; createBuffer(); } -GTextureVLK::GTextureVLK(IDevice &device, +GTextureVLK::GTextureVLK(IDeviceVulkan &device, int width, int height, bool xWrapTex, bool yWrapTex, bool isDepthTexture, const VkFormat textureFormatGPU, VkSampleCountFlagBits numSamples, - int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(dynamic_cast(device)) { + int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device) { //For use in frameBuffer this->m_wrapX = xWrapTex; @@ -281,60 +281,5 @@ bool GTextureVLK::postLoad() { } return false; - -} - -void GTextureVLK::updateVulkan(CmdBufRecorder &renderCmd, CmdBufRecorder &uploadCmd) { -///4. Fill commands to copy from CPU staging buffer to GPU buffer - - - // Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from - - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ; - imageMemoryBarrier.dstAccessMask = 0; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (m_device.canUploadInSeparateThread()) { - imageMemoryBarrier.srcQueueFamilyIndex = indicies.transferFamily.value(); - imageMemoryBarrier.dstQueueFamilyIndex = indicies.graphicsFamily.value(); - } else { - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } - //SeparateUploadQueue reference: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples - //"Upload data from the CPU to an image sampled in a fragment shader" - - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - - if (m_device.canUploadInSeparateThread()) { - vkCmdPipelineBarrier( - m_device.getTextureTransferCommandBuffer(), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); - - m_device.signalTextureTransferCommandRecorded(); - } else { - vkCmdPipelineBarrier( - m_device.getUploadCommandBuffer(), - VK_PIPELINE_STAGE_TRANSFER_BIT , - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); - } - - // Store current layout for later reuse - texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - m_uploaded = true; } - diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 12a49eae8..b5e2e3a45 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -5,22 +5,19 @@ #ifndef AWEBWOWVIEWERCPP_GTEXTUREVLK_H #define AWEBWOWVIEWERCPP_GTEXTUREVLK_H -class GDeviceVLK; class GFrameBufferVLK; class GCommandBuffer; -#include "../GDeviceVulkan.h" +#include "../IDeviceVulkan.h" #include "../../interface/textures/ITexture.h" -#include "../commandBuffer/CommandBuffer.h" class GTextureVLK : public ITexture { - friend class GDeviceVLK; friend class GFrameBufferVLK; -protected: - explicit GTextureVLK(IDevice &device, bool xWrapTex, bool yWrapTex); +public: + explicit GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex); //Used for rendering to texture in framebuffer - explicit GTextureVLK(IDevice &device, + explicit GTextureVLK(IDeviceVulkan &device, int width, int height, bool xWrapTex, bool yWrapTex, bool isDepthTexture, @@ -88,7 +85,7 @@ class GTextureVLK : public ITexture { VmaAllocationInfo imageAllocationInfo = {}; protected: - GDeviceVLK &m_device; + IDeviceVulkan &m_device; bool stagingBufferCreated = false; diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index 9550e22b8..9cb9fbdde 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -8,14 +8,18 @@ #include #include "frame/FrameInputParams.h" -typedef std::function SceneUpdateRenderLambda; -typedef std::function CullLambda; +class IRenderFunction { +public: + virtual ~IRenderFunction() = default; +}; +typedef std::function()> SceneUpdateLambda; +typedef std::function CullLambda; template class IRendererParameters : public std::enable_shared_from_this> { public: virtual std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) = 0; - virtual void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) = 0; + virtual std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) = 0; //This function is to be used to display data in UI virtual std::shared_ptr getLastCreatedPlan() = 0; @@ -23,11 +27,11 @@ class IRendererParameters : public std::enable_shared_from_this> &frameInputParams) { auto this_s = this->shared_from_this(); - return [frameInputParams, this_s]() -> SceneUpdateRenderLambda { + return [frameInputParams, this_s]() -> SceneUpdateLambda { std::shared_ptr framePlan = this_s->processCulling(frameInputParams); return [framePlan, frameInputParams, this_s]() -> void { - this_s->updateAndDraw(frameInputParams, framePlan); + return this_s->update(frameInputParams, framePlan); }; }; } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index e81511a2e..171e1f545 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -73,8 +73,9 @@ void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { if (frameScenario == nullptr) return; + std::vector> renderFunctions; for (int i = 0; i < frameScenario->drawUpdateFunction.size(); i++) { - frameScenario->drawUpdateFunction[i](); + renderFunctions.push_back(std::move(frameScenario->drawUpdateFunction[i]())); } // auto device = m_apiContainer->hDevice; diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h index 1f5861e49..2a640a976 100644 --- a/wowViewerLib/src/renderer/frame/SceneScenario.h +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -40,7 +40,7 @@ class FrameScenarioBuilder { struct FrameScenario { std::vector cullFunctions; - std::vector drawUpdateFunction; + std::vector drawUpdateFunction; }; typedef std::shared_ptr HFrameScenario; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 47b891d69..ccdc7a6fa 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -41,9 +41,10 @@ HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) return HGIndexBuffer(); } -void MapSceneRenderForwardVLK::updateAndDraw(const std::shared_ptr> &frameInputParams, +std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + return nullptr; } std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 360868497..9be65be59 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -14,7 +14,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; - void updateAndDraw(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; std::shared_ptr getLastCreatedPlan() override; diff --git a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h new file mode 100644 index 000000000..aaa62d651 --- /dev/null +++ b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h @@ -0,0 +1,37 @@ +// +// Created by Deamon on 11.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_IRENDERFUNCTIONVLK_H +#define AWEBWOWVIEWERCPP_IRENDERFUNCTIONVLK_H + +#include "../IRenderParameters.h" +#include "../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h" + +class IRenderFunctionVLK : public IRenderFunction { +public: + ~IRenderFunctionVLK() override = default; + + virtual void execute(CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) = 0; +}; + +template +class TemplateIRenderFunctionVLK : public IRenderFunctionVLK { +public: + TemplateIRenderFunctionVLK(T a) : m_a(std::move(a)){ + + }; + void execute(CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) override { + m_a(transferQueueCMD, renderFB, renderSwapFB); + }; +private: + T m_a; +}; + +template +std::unique_ptr createRenderFuncVLK(T a) { + return std::make_unique>(std::move(a)); +} + + +#endif //AWEBWOWVIEWERCPP_IRENDERFUNCTIONVLK_H From 6ba41ddd4b9cc9bbab8461c79eb957acf67b2e3b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 16 Feb 2023 11:18:34 +0200 Subject: [PATCH 028/212] commit --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 28 ++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 173 +++++++----------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 28 ++- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 5 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 22 +++ .../gapi/vulkan/commandBuffer/CommandBuffer.h | 2 + .../CommandBufferRecorder.cpp | 15 +- .../CommandBufferRecorder.h | 5 +- .../vulkan/descriptorSets/GDescriptorSet.h | 2 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 14 +- .../vulkan/materials/ISimpleMaterialVLK.h | 11 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 2 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 2 +- .../gapi/vulkan/syncronization/GFenceVLK.cpp | 6 +- .../gapi/vulkan/syncronization/GFenceVLK.h | 2 +- .../vulkan/syncronization/GSemaphoreVLK.cpp | 18 ++ .../vulkan/syncronization/GSemaphoreVLK.h | 10 + .../src/renderer/vulkan/IRenderFunctionVLK.h | 6 +- 18 files changed, 208 insertions(+), 143 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index bbbdaa952..4199505dd 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -65,8 +65,30 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( this->consumeFrameInput(frameInputParams, *meshes); //Record commands to update buffer and draw - - return createRenderFuncVLK(std::move([meshes = std::move(meshes)](CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) { - + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); + return createRenderFuncVLK(std::move([meshes = std::move(meshes), l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) { + // --------------------- + // Upload stuff + // --------------------- + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->vboBuffer); + uploadCmd.submitBufferUploads(l_this->iboBuffer); + + // ---------------------- + // Draw meshes + // ---------------------- + + for (auto const &mesh : *meshes) { + const auto &meshVlk = std::dynamic_pointer_cast(mesh); + + meshVlk->getPipeLineForRenderPass(); + + auto const &descSets = meshVlk->material()->getDescriptorSets(); + for (int i = 0; i < descSets.size(); i++) { + if (descSets[i] != nullptr) { + frameBufCmd.bindDescriptorSet(i, descSets[i]); + } + } + } })); } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index f86410293..70feefdd9 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -718,75 +718,32 @@ void GDeviceVLK::createCommandPoolForUpload(){ } void GDeviceVLK::createCommandBuffers() { - for (auto & commandBuffer : commandBuffers) { + for (auto & commandBuffer : fbCommandBuffers) { commandBuffer = std::make_shared(*this, commandPool, false, indices.graphicsFamily); } + for (auto & commandBuffer : swapChainCommandBuffers) { + commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily); + } for (auto & commandBuffer : uploadCommandBuffers) { commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.graphicsFamily); } - for (auto & commandBuffer : presentCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily); - } } void GDeviceVLK::createSyncObjects() { -//TODO: + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + imageAvailableSemaphores[i] = std::make_shared(this->shared_from_this()); + renderFinishedSemaphores[i] = std::make_shared(this->shared_from_this()); -// imageAvailableSemaphores.resize(commandBuffers.size()); -// renderFinishedSemaphores.resize(commandBuffers.size()); -// textureTransferFinishedSemaphores.resize(commandBuffers.size()); -// -// -// VkSemaphoreCreateInfo semaphoreInfo = {}; -// semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; -// semaphoreInfo.pNext = NULL; -// -// for (size_t i = 0; i < commandBuffers.size(); i++) { -// if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || -// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS || -// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &textureTransferFinishedSemaphores[i]) != VK_SUCCESS) { -// -// throw std::runtime_error("failed to create synchronization objects for a frame!"); -// } -// } -// -// VkFenceCreateInfo fenceInfo = {}; -// fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; -// fenceInfo.pNext = NULL; -// fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; -// -// inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); -// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { -// if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { -// throw std::runtime_error("failed to create synchronization objects for a frame!"); -// } -// } -// inFlightTextureTransferFences.resize(MAX_FRAMES_IN_FLIGHT); -// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { -// if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightTextureTransferFences[i]) != VK_SUCCESS) { -// throw std::runtime_error("failed to create synchronization objects for a textureUpdate!"); -// } -// } -// -// -// VkFenceCreateInfo uploadFenceInfo = {}; -// uploadFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; -// uploadFenceInfo.pNext = NULL; -// uploadFenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; -// -// uploadSemaphores.resize(MAX_FRAMES_IN_FLIGHT); -// uploadFences.resize(MAX_FRAMES_IN_FLIGHT); -// uploadSemaphoresSubmited.resize(MAX_FRAMES_IN_FLIGHT); -// for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { -// vkCreateSemaphore(device, &semaphoreInfo, nullptr, &uploadSemaphores[i]); -// vkCreateFence(device, &uploadFenceInfo, nullptr, &uploadFences[i]); -// uploadSemaphoresSubmited[i] = false; -// } + uploadSemaphores[i] = std::make_shared(this->shared_from_this()); + } + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + inFlightFences[i] = std::make_shared(this->shared_from_this(), true); + } } @@ -823,9 +780,11 @@ void GDeviceVLK::drawFrame(const std::vector> & auto uploadCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); + auto swapChainCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); + auto frameBufCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, ) + dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); } } @@ -1057,7 +1016,7 @@ void GDeviceVLK::submitDrawCommands() { int currentDrawFrame = getDrawFrameNumber(); uint32_t imageIndex; - VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame], VK_NULL_HANDLE, &imageIndex); + VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { std::cout << "got VK_ERROR_OUT_OF_DATE_KHR" << std::endl << std::flush; @@ -1087,7 +1046,7 @@ void GDeviceVLK::submitDrawCommands() { //This stuff creates commands that would write into the frameBuffer of the frame //the problem is that it depends on the imageIndex, which cant be known beforehand //Also, we would need info on the current settings of the clear color and invertZ stuff here - auto commandBufferForFilling = commandBuffers[currentDrawFrame]; + auto swapChainCmd = swapChainCommandBuffers[currentDrawFrame]; // { // VkCommandBufferBeginInfo beginInfo = {}; // beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -1126,67 +1085,72 @@ void GDeviceVLK::submitDrawCommands() { // } // } + auto fbCommandBuffer = fbCommandBuffers[currentDrawFrame]; + + submitQueue( + { + uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), + imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() + }, + {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, + + {fbCommandBuffer->m_cmdBuffer, swapChainCmd->m_cmdBuffer}, + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()} + ); + + presentQueue( + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + {swapChain}, + {imageIndex} + ); + + executeDeallocators(); +} + +void GDeviceVLK::submitQueue( const std::vector &waitSemaphores, + const std::vector &waitStages, + const std::vector &commandBuffers, + const std::vector &signalSemaphoresOnCompletion) { VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = NULL; - VkSemaphore waitSemaphores[2]; - VkPipelineStageFlags waitStages[2]; + submitInfo.waitSemaphoreCount = waitSemaphores.size(); + submitInfo.pWaitDstStageMask = waitStages.data(); + submitInfo.pWaitSemaphores = waitSemaphores.data(); - waitSemaphores[0] = imageAvailableSemaphores[currentDrawFrame]; - waitStages[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - if (uploadSemaphoresSubmited[currentDrawFrame]) { - waitSemaphores[1] = uploadSemaphores[currentDrawFrame]; - waitStages[1] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - submitInfo.waitSemaphoreCount = 2; - } else { - submitInfo.waitSemaphoreCount = 1; - } - - submitInfo.pWaitSemaphores = &waitSemaphores[0]; - submitInfo.pWaitDstStageMask = &waitStages[0]; - - std::vector grCommandBuffers = {}; -// if (!textureTransferCommandBufferNull[currentDrawFrame]) { -// grCommandBuffers.push_back(textureTransferCommandBuffers[currentDrawFrame]); -// } - if (renderCommandBuffersForFrameBuffersNotNull[currentDrawFrame]) { - grCommandBuffers.push_back(renderCommandBuffersForFrameBuffers[currentDrawFrame]); - } - grCommandBuffers.push_back(commandBufferForFilling); + submitInfo.commandBufferCount = commandBuffers.size(); + submitInfo.pCommandBuffers = commandBuffers.data(); - submitInfo.commandBufferCount = grCommandBuffers.size(); - submitInfo.pCommandBuffers = grCommandBuffers.data(); + submitInfo.signalSemaphoreCount = signalSemaphoresOnCompletion.size(); + submitInfo.pSignalSemaphores = signalSemaphoresOnCompletion.data(); - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &renderFinishedSemaphores[currentDrawFrame]; + int currentDrawFrame = getDrawFrameNumber(); -// if (!renderCommandBuffersNull[currentDrawFrame]) { { - auto result = vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentDrawFrame]); + auto result = vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentDrawFrame]->getNativeFence()); if (result != VK_SUCCESS) { std::cout << "failed to submit draw command buffer! result = " << result << std::endl << std::flush; } } -// } +} +void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, + const std::vector &swapchains, + const std::vector &imageIndexes) { VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.pNext = NULL; -// if (!renderCommandBuffersNull[currentDrawFrame]) { - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &renderFinishedSemaphores[currentDrawFrame]; -// } else { -// presentInfo.waitSemaphoreCount = 0; -// } - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapChain; - presentInfo.pImageIndices = &imageIndex; -// presentInfo.pResults = nullptr; + presentInfo.waitSemaphoreCount = waitSemaphores.size(); + presentInfo.pWaitSemaphores = waitSemaphores.data(); - result = vkQueuePresentKHR(graphicsQueue, &presentInfo); + presentInfo.swapchainCount = waitSemaphores.size(); + presentInfo.pSwapchains = swapchains.data(); + presentInfo.pImageIndices = imageIndexes.data(); + + auto result = vkQueuePresentKHR(graphicsQueue, &presentInfo); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { framebufferResized = false; @@ -1194,10 +1158,7 @@ void GDeviceVLK::submitDrawCommands() { return; } else if (result != VK_SUCCESS) { std::cout << "failed to present swap chain image!" << std::endl << std::flush; -// throw std::runtime_error("failed to present swap chain image!"); } - - executeDeallocators(); } void GDeviceVLK::executeDeallocators() { @@ -1679,6 +1640,8 @@ GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescript void GDeviceVLK::initUploadThread() { } + + HFrameBuffer GDeviceVLK::createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) { @@ -1761,7 +1724,7 @@ void GDeviceVLK::singleExecuteAndWait(std::function callb submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; - GFenceVLK fenceVlk(this->shared_from_this()); + GFenceVLK fenceVlk(this->shared_from_this(), false); // Submit to the queue ERR_GUARD_VULKAN(vkQueueSubmit(graphicsQueue, 1, &submitInfo, fenceVlk.getNativeFence())); @@ -1770,7 +1733,6 @@ void GDeviceVLK::singleExecuteAndWait(std::function callb vkFreeCommandBuffers(device, commandPool, 1, ©Cmd); } - VkSampleCountFlagBits sampleCountToVkSampleCountFlagBits(uint8_t sampleCount) { switch (sampleCount) { case 1: @@ -1792,6 +1754,8 @@ VkSampleCountFlagBits sampleCountToVkSampleCountFlagBits(uint8_t sampleCount) { } return VK_SAMPLE_COUNT_1_BIT; }; + + static const constexpr uint8_t countFlagBitsToSampleCount(VkSampleCountFlagBits sampleCountBit) { switch (sampleCountBit) { case VK_SAMPLE_COUNT_1_BIT: @@ -1815,7 +1779,6 @@ static const constexpr uint8_t countFlagBitsToSampleCount(VkSampleCountFlagBits return 1; } - int GDeviceVLK::getMaxSamplesCnt() { if (maxMultiSample < 0) { VkPhysicalDeviceProperties physicalDeviceProperties; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index b3d07b44e..aa1d43b91 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -36,6 +36,7 @@ class gMeshTemplate; #include "buffers/GBufferVLK.h" #include "IDeviceVulkan.h" #include "syncronization/GFenceVLK.h" +#include "syncronization/GSemaphoreVLK.h" #include @@ -143,6 +144,15 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &waitSemaphores, + const std::vector &waitStages, + const std::vector &commandBuffers, + const std::vector &signalSemaphoresOnCompletion) ; + + void presentQueue(const std::vector &waitSemaphores, + const std::vector &swapchains, + const std::vector &imageIndexes); VkDescriptorSet allocateDescriptorSetPrimitive( const std::shared_ptr &hDescriptorSetLayout, @@ -218,14 +228,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this renderPass, -// const HMeshesToRender &iMeshes, -// const std::array &viewportsForThisStage, -// VkRect2D &defaultScissor); - protected: struct BlpCacheRecord { BlpTexture* texture; @@ -318,14 +320,20 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> commandBuffers = {nullptr}; + std::array, MAX_FRAMES_IN_FLIGHT> fbCommandBuffers = {nullptr}; + std::array, MAX_FRAMES_IN_FLIGHT> swapChainCommandBuffers = {nullptr}; std::array, MAX_FRAMES_IN_FLIGHT> uploadCommandBuffers = {nullptr}; - std::array, MAX_FRAMES_IN_FLIGHT> presentCommandBuffers = {nullptr}; std::array, MAX_FRAMES_IN_FLIGHT> inFlightFences; std::array, MAX_FRAMES_IN_FLIGHT> uploadFences; + std::array, MAX_FRAMES_IN_FLIGHT> imageAvailableSemaphores; + // Is used to signal for present queue that frame has finished rendering and it can be presented on screen + std::array, MAX_FRAMES_IN_FLIGHT> renderFinishedSemaphores; + + std::array, MAX_FRAMES_IN_FLIGHT> uploadSemaphores; + std::vector> m_descriptorPools; VmaAllocator vmaAllocator; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 6653a7e0b..778c64677 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -159,11 +159,12 @@ void GBufferVLK::deleteSubBuffer(std::list>::const_ } void GBufferVLK::uploadFromStaging(int offset, int destOffset, int length) { - VkBufferCopy vbCopyRegion = {}; + std::lock_guard lock(dataToBeUploadedMtx); + + VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); vbCopyRegion.srcOffset = offset; vbCopyRegion.dstOffset = destOffset; vbCopyRegion.size = length; -// vkCmdCopyBuffer(m_device->getUploadCommandBuffer(), currentBuffer.stagingBuffer, currentBuffer.g_hBuffer, 1, &vbCopyRegion); } void GBufferVLK::save(int length) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index f52877afa..4d2290ac8 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -16,6 +16,20 @@ typedef std::shared_ptr HGBufferVLK; #include "../GDeviceVulkan.h" #include "IBufferVLK.h" +template +class MutexLockedVector { +public: + MutexLockedVector(std::vector &vec, std::mutex &m) : m_vec(vec), m_lockGuard(std::lock_guard(m)) { + + } + const std::vector &get() const { + return m_vec; + } +private: + std::vector &m_vec; + std::lock_guard m_lockGuard; +}; + class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; public: @@ -37,10 +51,17 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords() { + return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx); + } + void resize(int newLength); private: HGDeviceVLK m_device; @@ -60,6 +81,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this dataToBeUploaded; private: class GSubBufferVLK : public IBufferVLK { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index ac86e5494..a60d5e6ef 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -15,6 +15,7 @@ class GCommandBuffer { public: friend class CmdBufRecorder; friend class RenderPassHelper; + friend class IDeviceVulkan; public: GCommandBuffer(IDeviceVulkan &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); @@ -31,6 +32,7 @@ class GCommandBuffer { VkCommandPool m_commandPool; bool m_cmdBufWasCreated = false; + bool m_hasData = false; }; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index d597c37b5..081a0c3a9 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -72,7 +72,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( ); } -void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet) { +void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet) { //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others //Which leads to three separate states for: // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR @@ -116,3 +116,16 @@ void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, const std static_cast(regions.size()), regions.data()); } + +void CmdBufRecorder:: submitBufferUploads(const std::shared_ptr &bufferVLK) { + auto submitRecords = bufferVLK->getSubmitRecords(); + + if (submitRecords.get().empty()) + return; + + vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, + bufferVLK->getCPUBuffer(), + bufferVLK->getGPUBuffer(), + submitRecords.get().size(), + submitRecords.get().data()); +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index e6c9b502f..a71ea7db1 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -37,10 +37,11 @@ class CmdBufRecorder { const std::array &colorClearColor, float depthClear); void bindPipeline(std::shared_ptr &pipeline); - void bindDescriptorSet(uint32_t bindIndex, std::shared_ptr &descriptorSet); + void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); + void submitBufferUploads(const std::shared_ptr &bufferVLK); friend class RenderPassHelper; private: @@ -49,7 +50,7 @@ class CmdBufRecorder { //States std::shared_ptr m_currentRenderPass = nullptr; std::shared_ptr m_currentPipeline = nullptr; - std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; }; #endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 0eb4851fb..b76dc8b42 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -28,7 +28,7 @@ class GDescriptorSet { void writeToDescriptorSets(std::vector &descriptorWrites); const std::shared_ptr &getSetLayout() const { return m_hDescriptorSetLayout;}; - VkDescriptorSet getDescSet() {return m_descriptorSet;} + VkDescriptorSet getDescSet() const {return m_descriptorSet;} struct DescriptorRecord { enum class DescriptorRecordType { diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index e95fa1dae..cc86cab61 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -10,7 +10,7 @@ void ISimpleMaterialVLK::createImageDescriptorSet() { auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto descLayout = shaderVLK->getImageDescriptorLayout(); - imageDescriptorSet = m_device->createDescriptorSet(descLayout) ; + descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; int textureBegin = shaderVLK->getTextureBindingStart(); @@ -18,7 +18,7 @@ void ISimpleMaterialVLK::createImageDescriptorSet() { auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); { - auto updateHelper = imageDescriptorSet->beginUpdate(); + auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); for (int i = 0; i < shaderVLK->getTextureCount(); i++) { updateHelper.texture(textureBegin + i, blackTextureVlk); } @@ -38,7 +38,7 @@ void ISimpleMaterialVLK::updateImageDescriptorSet() { } if (allTexturesAreReady) { - auto updateHelper = imageDescriptorSet->beginUpdate(); + auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); for (size_t i = 0; i < m_textures.size(); i++) { auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); if (textureVlk == nullptr) continue; @@ -48,13 +48,13 @@ void ISimpleMaterialVLK::updateImageDescriptorSet() { } } -void ISimpleMaterialVLK::createUBODescriptorSet() { +void ISimpleMaterialVLK::createAndUpdateUBODescriptorSet() { auto shaderVLK = std::dynamic_pointer_cast(m_shader); auto descLayout = shaderVLK->getUboDescriptorLayout(); - uboDescriptorSet = m_device->createDescriptorSet(descLayout) ; + descriptors[GShaderPermutationVLK::UBO_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; - auto updateHelper = imageDescriptorSet->beginUpdate(); + auto updateHelper = descriptors[GShaderPermutationVLK::UBO_SET_INDEX]->beginUpdate(); for (size_t i = 0; i < m_ubos.size(); i++) { updateHelper.ubo(i, m_ubos[i]); } @@ -112,6 +112,6 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, m_ubos = ubos; createImageDescriptorSet(); - createUBODescriptorSet(); + createAndUpdateUBODescriptorSet(); } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 9031c54db..84e308888 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -28,7 +28,11 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this void createImageDescriptorSet(); void updateImageDescriptorSet(); - void createUBODescriptorSet(); + void createAndUpdateUBODescriptorSet(); + + const std::array, MAX_SHADER_DESC_SETS> &getDescriptorSets() { + return descriptors; + } private: HGDeviceVLK m_device; @@ -36,9 +40,8 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this std::vector m_textures = {}; std::vector> m_ubos = {}; - std::shared_ptr imageDescriptorSet; - std::shared_ptr uboDescriptorSet; - std::shared_ptr ssboDescriptorSet; + + std::array, MAX_SHADER_DESC_SETS> descriptors; HGShaderPermutation m_shader; }; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 1c89584bc..7cb5289ec 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -36,7 +36,7 @@ GMeshVLK::GMeshVLK(IDevice &device, } //Works under assumption that meshes do not change the renderpass, on which they are rendered, too often -std::shared_ptr GMeshVLK::getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ) { +std::shared_ptr GMeshVLK::getPipeLineForRenderPass(const std::shared_ptr &renderPass, bool invertedZ) { if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, m_material->getShader(), renderPass, m_element, diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 42fa5be70..5fb37d63c 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -26,7 +26,7 @@ class GMeshVLK : public IMesh { MeshType getMeshType() override; public: - std::shared_ptr getPipeLineForRenderPass(std::shared_ptr renderPass, bool invertedZ); + std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass, bool invertedZ); auto material() const -> const HMaterialVLK& { return m_material; } protected: MeshType m_meshType; diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp index 2719d729a..eea2b5609 100644 --- a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp @@ -5,11 +5,13 @@ #include "GFenceVLK.h" #include "../../interface/IDevice.h" -GFenceVLK::GFenceVLK(const std::shared_ptr &deviceVulkan) : m_device(deviceVulkan) { +GFenceVLK::GFenceVLK(const std::shared_ptr &deviceVulkan, bool createInSignalledState) : m_device(deviceVulkan) { VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; - fenceInfo.flags = 0; + fenceInfo.flags = + (createInSignalledState ? VK_FENCE_CREATE_SIGNALED_BIT : 0) | + 0; ERR_GUARD_VULKAN(vkCreateFence(m_device->getVkDevice(), &fenceInfo, nullptr, &m_fence)); } diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h index e2b7ef2de..353162ce8 100644 --- a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h @@ -11,7 +11,7 @@ class GFenceVLK { public: - GFenceVLK(const std::shared_ptr &deviceVulkan); + GFenceVLK(const std::shared_ptr &deviceVulkan, bool createInSignalledState); ~GFenceVLK(); void wait(uint64_t maxWaitTime); diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp index b102ae9fe..ae560a3e6 100644 --- a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp @@ -3,3 +3,21 @@ // #include "GSemaphoreVLK.h" +#include "../../interface/IDevice.h" + +GSemaphoreVLK::GSemaphoreVLK(const std::shared_ptr &deviceVulkan) { + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreInfo.pNext = NULL; + + ERR_GUARD_VULKAN(vkCreateSemaphore(deviceVulkan->getVkDevice(), &semaphoreInfo, nullptr, &m_semaphore)); +} + +GSemaphoreVLK::~GSemaphoreVLK() { + auto l_deviceVlk = m_device->getVkDevice(); + auto l_semaphore = m_semaphore; + + m_device->addDeallocationRecord([l_deviceVlk, l_semaphore]() { + vkDestroySemaphore(l_deviceVlk, l_semaphore, nullptr); + }); +} diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h index 77a246e09..37bfae507 100644 --- a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h +++ b/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h @@ -6,7 +6,17 @@ #define AWEBWOWVIEWERCPP_GSEMAPHOREVLK_H +#include "../IDeviceVulkan.h" + class GSemaphoreVLK { +public: + GSemaphoreVLK(const std::shared_ptr &deviceVulkan); + ~GSemaphoreVLK(); + + VkSemaphore getNativeSemaphore() {return m_semaphore;}; +private: + std::shared_ptr m_device; + VkSemaphore m_semaphore; }; diff --git a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h index aaa62d651..503983aa6 100644 --- a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h +++ b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h @@ -12,7 +12,7 @@ class IRenderFunctionVLK : public IRenderFunction { public: ~IRenderFunctionVLK() override = default; - virtual void execute(CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) = 0; + virtual void execute(CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) = 0; }; template @@ -21,8 +21,8 @@ class TemplateIRenderFunctionVLK : public IRenderFunctionVLK { TemplateIRenderFunctionVLK(T a) : m_a(std::move(a)){ }; - void execute(CmdBufRecorder &transferQueueCMD, CmdBufRecorder &renderFB, CmdBufRecorder &renderSwapFB) override { - m_a(transferQueueCMD, renderFB, renderSwapFB); + void execute(CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) override { + m_a(uploadCmd, frameBufCmd, swapChainCmd); }; private: T m_a; From 42e151f1639a465b77539fdbbf145aaaeffb8675 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 16 Feb 2023 17:18:51 +0200 Subject: [PATCH 029/212] commit --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 12 +++++++-- .../vulkan/FrontendUIRenderForwardVLK.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 27 ++++++++++--------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 1 + .../gapi/vulkan/commandBuffer/CommandBuffer.h | 3 +++ .../CommandBufferRecorder.cpp | 4 +++ .../CommandBufferRecorder.h | 2 ++ wowViewerLib/src/renderer/IRenderParameters.h | 2 +- 8 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 4199505dd..ee42674df 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -11,6 +11,8 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( hDevice), m_device(hDevice) { + + m_lastRenderPass = m_device->getSwapChainRenderPass(); } void FrontendUIRenderForwardVLK::createBuffers() { @@ -81,14 +83,20 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( for (auto const &mesh : *meshes) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); - meshVlk->getPipeLineForRenderPass(); + //1. Bind pipeline + auto pipeline = meshVlk->getPipeLineForRenderPass(l_this->m_lastRenderPass, false); + swapChainCmd.bindPipeline(pipeline); + //2. Bind Descriptor sets auto const &descSets = meshVlk->material()->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { - frameBufCmd.bindDescriptorSet(i, descSets[i]); + swapChainCmd.bindDescriptorSet(i, descSets[i]); } } + + //3. Draw the mesh + swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0, 0); } })); } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 101351ce7..d1d584d59 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -46,6 +46,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { void createBuffers(); + std::shared_ptr m_lastRenderPass; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 70feefdd9..28e5c7ff5 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -7,14 +7,11 @@ #include #include #include -#include #include #include #include "GDeviceVulkan.h" -#include "meshes/GM2MeshVLK.h" #include "meshes/GMeshVLK.h" -#include "buffers/GVertexBufferDynamicVLK.h" #include "textures/GTextureVLK.h" #include "textures/GBlpTextureVLK.h" #include "GVertexBufferBindingsVLK.h" @@ -27,7 +24,6 @@ #include "buffers/GBufferVLK.h" #include "syncronization/GFenceVLK.h" #include "../../renderer/vulkan/IRenderFunctionVLK.h" -//#include "fastmemcp.h" #include const int WIDTH = 1900; @@ -719,15 +715,15 @@ void GDeviceVLK::createCommandPoolForUpload(){ void GDeviceVLK::createCommandBuffers() { for (auto & commandBuffer : fbCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, false, indices.graphicsFamily); + commandBuffer = std::make_shared(*this, commandPool, false, indices.graphicsFamily.value()); } for (auto & commandBuffer : swapChainCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily); + commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily.value()); } for (auto & commandBuffer : uploadCommandBuffers) { - commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.graphicsFamily); + commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.transferFamily.value()); } } @@ -1094,7 +1090,7 @@ void GDeviceVLK::submitDrawCommands() { }, {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, - {fbCommandBuffer->m_cmdBuffer, swapChainCmd->m_cmdBuffer}, + {fbCommandBuffer->getNativeCmdBuffer(), swapChainCmd->getNativeCmdBuffer()}, {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()} ); @@ -1206,11 +1202,12 @@ std::shared_ptr GDeviceVLK::getRenderPass( }); VkFormat fbDepthFormat = findDepthFormat(); - auto renderPass = std::make_shared(*this, - attachmentFormats, - findDepthFormat(), - sampleCountFlagBits, - false); + auto renderPass = std::make_shared(this->device, + attachmentFormats, + findDepthFormat(), + sampleCountFlagBits, + false + ); RenderPassAvalabilityStruct avalabilityStruct; avalabilityStruct.attachments = textureAttachments; @@ -1224,6 +1221,10 @@ std::shared_ptr GDeviceVLK::getRenderPass( return renderPass; } +std::shared_ptr GDeviceVLK::getSwapChainRenderPass() { + return swapchainRenderPass; +} + HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, HGShaderPermutation shader, std::shared_ptr renderPass, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index aa1d43b91..bbf038493 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -142,6 +142,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getSwapChainRenderPass(); void submitDrawCommands() override; void submitQueue( diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index a60d5e6ef..450437b7a 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -21,6 +21,9 @@ class GCommandBuffer { GCommandBuffer(IDeviceVulkan &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); + VkCommandBuffer getNativeCmdBuffer() { + return m_cmdBuffer; + } private: void createCommandBufVLK(); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 081a0c3a9..385d55c4f 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -95,6 +95,10 @@ void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { m_currentPipeline = pipeline; } +void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { + vkCmdDrawIndexed(m_gCmdBuffer.m_cmdBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); +} + void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData) { vkCmdPipelineBarrier( diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index a71ea7db1..69f19be96 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -38,6 +38,8 @@ class CmdBufRecorder { void bindPipeline(std::shared_ptr &pipeline); void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); + void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); + void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index 9cb9fbdde..cdc126423 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -30,7 +30,7 @@ class IRendererParameters : public std::enable_shared_from_this SceneUpdateLambda { std::shared_ptr framePlan = this_s->processCulling(frameInputParams); - return [framePlan, frameInputParams, this_s]() -> void { + return [framePlan, frameInputParams, this_s]() -> std::unique_ptr { return this_s->update(frameInputParams, framePlan); }; }; From fb575737dae5b00fa58cd4d63cba68e4cd33f06b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 17 Feb 2023 00:17:10 +0200 Subject: [PATCH 030/212] commit --- .../renderer/uiScene/FrontendUIRenderer.cpp | 2 - src/ui/renderer/uiScene/FrontendUIRenderer.h | 3 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 18 ++++-- wowViewerLib/src/gapi/IDeviceFactory.cpp | 4 +- wowViewerLib/src/gapi/interface/IDevice.h | 4 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 60 +++++++++++-------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 9 +-- .../CommandBufferRecorder.cpp | 29 ++++++++- .../CommandBufferRecorder.h | 6 +- .../descriptorSets/GDescriptorSetLayout.cpp | 4 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 12 ++-- .../src/renderer/frame/SceneComposer.cpp | 36 +---------- 12 files changed, 102 insertions(+), 85 deletions(-) diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 512b99a4d..da31c9e17 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -101,8 +101,6 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrTextureId; - meshTemplate.start = pcmd->IdxOffset * 2; meshTemplate.end = pcmd->ElemCount; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 28586242d..8e1fbabd6 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -9,6 +9,7 @@ #include "ImGUIPlan.h" #include "../../../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" #include "IFrontendUIBufferCreate.h" +#include "../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" static const std::array imguiBindings = {{ {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, @@ -34,7 +35,7 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; + std::shared_ptr> m_imguiUbo = nullptr; void consumeFrameInput(const std::shared_ptr> &frameInputParams, std::vector &meshes); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index ee42674df..c9288126e 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -13,6 +13,8 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic hDevice), m_device(hDevice) { m_lastRenderPass = m_device->getSwapChainRenderPass(); + + createBuffers(); } void FrontendUIRenderForwardVLK::createBuffers() { @@ -41,7 +43,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate } } - std::vector> ubos = {}; + std::vector> ubos = {m_imguiUbo->}; std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; auto material = std::make_shared(m_device, "imguiShader", "imguiShader", @@ -83,11 +85,17 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( for (auto const &mesh : *meshes) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); - //1. Bind pipeline + //1. Bind VBOs + swapChainCmd.bindVertexBuffer(l_this->vboBuffer); + + //2. Bind IBOs + swapChainCmd.bindVertexBuffer(l_this->iboBuffer); + + //3. Bind pipeline auto pipeline = meshVlk->getPipeLineForRenderPass(l_this->m_lastRenderPass, false); swapChainCmd.bindPipeline(pipeline); - //2. Bind Descriptor sets + //4. Bind Descriptor sets auto const &descSets = meshVlk->material()->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { @@ -95,8 +103,8 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( } } - //3. Draw the mesh - swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0, 0); + //5. Draw the mesh + swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } })); } diff --git a/wowViewerLib/src/gapi/IDeviceFactory.cpp b/wowViewerLib/src/gapi/IDeviceFactory.cpp index 91b05e7e0..ae508babf 100644 --- a/wowViewerLib/src/gapi/IDeviceFactory.cpp +++ b/wowViewerLib/src/gapi/IDeviceFactory.cpp @@ -62,7 +62,9 @@ HGDevice IDeviceFactory::createDevice(std::string gapiName, void * data) { #ifndef SKIP_VULKAN if (gapiName == "vulkan") { - return std::make_shared((vkCallInitCallback *) data); + auto deviceVlk = std::make_shared((vkCallInitCallback *) data); + deviceVlk->initialize(); + return deviceVlk; } else #endif {} diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index fdcb5ff1b..d3c6cc034 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -55,6 +55,7 @@ typedef std::shared_ptr HFrameBuffer; #include "../../engine/texture/BlpTexture.h" #include "textures/ITexture.h" #include "IFrameBuffer.h" +#include "../../renderer/IRenderParameters.h" struct M2ShaderCacheRecord { int vertexShader; @@ -164,7 +165,8 @@ class IDevice { // virtual void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData)= 0; virtual void uploadTextureForMeshes(std::vector &meshes) = 0; - virtual void drawMeshes(std::vector &meshes) = 0; + + virtual void drawFrame(const std::vector> &renderFuncs) = 0; // virtual void drawStageAndDeps(HDrawStage drawStage) = 0; virtual bool getIsCompressedTexturesSupported(); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 28e5c7ff5..83a1774e8 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -227,13 +227,15 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { //Create surface vkSurface = callback->createSurface(vkInstance); +} +void GDeviceVLK::initialize() { setupDebugMessenger(); pickPhysicalDevice(); createLogicalDevice(); //--------------- - //Init AMD's VMA +//Init AMD's VMA VmaVulkanFunctions vma_vulkan_func{}; vma_vulkan_func.vkAllocateMemory = vkAllocateMemory; vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory; @@ -284,9 +286,6 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { std::cout << "maxUniformBufferSize = " << maxUniformBufferSize << std::endl; } -void GDeviceVLK::initialize() { - -} void GDeviceVLK::recreateSwapChain() { createSwapChain(); @@ -739,6 +738,7 @@ void GDeviceVLK::createSyncObjects() { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { inFlightFences[i] = std::make_shared(this->shared_from_this(), true); + uploadFences[i] = std::make_shared(this->shared_from_this(), true); } } @@ -775,16 +775,28 @@ void GDeviceVLK::drawFrame(const std::vector> & this->waitInDrawStageAndDeps.endMeasurement(); - auto uploadCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); - auto swapChainCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); - auto frameBufCmd = std::move(uploadCommandBuffers[uploadFrame]->beginRecord(nullptr)); + auto &uploadCmdBuf = uploadCommandBuffers[uploadFrame]; + auto &swapChainCmdBuf = swapChainCommandBuffers[uploadFrame]; + auto &frameBufCmdBuf = fbCommandBuffers[uploadFrame]; + { + auto uploadCmd = std::move(uploadCmdBuf->beginRecord(nullptr)); + auto swapChainCmd = std::move(swapChainCmdBuf->beginRecord(nullptr)); + auto frameBufCmd = std::move(frameBufCmdBuf->beginRecord(nullptr)); - for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); + for (int i = 0; i < renderFuncs.size(); i++) { + dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); + } } -} -typedef std::shared_ptr HVKMesh; + submitQueue( + uploadQueue, + {}, + {}, + {uploadCmdBuf->getNativeCmdBuffer()}, + {uploadSemaphores[uploadFrame]->getNativeSemaphore()}, + uploadFences[uploadFrame]->getNativeFence() + ); +} void GDeviceVLK::updateBuffers(std::vector &frameDepedantData) { // aggregationBufferForUpload.resize(maxUniformBufferSize); @@ -911,10 +923,6 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { } } -void GDeviceVLK::drawMeshes(std::vector &meshes) { - -} - std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) { std::string combinedName = vertexName + " " + fragmentName; const char * cstr = combinedName.c_str(); @@ -925,7 +933,7 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName } std::shared_ptr sharedPtr = std::make_shared(vertexName, fragmentName, this->shared_from_this()); - + sharedPtr->compileShader("", ""); m_shaderPermuteCache[hash] = sharedPtr; @@ -1084,6 +1092,7 @@ void GDeviceVLK::submitDrawCommands() { auto fbCommandBuffer = fbCommandBuffers[currentDrawFrame]; submitQueue( + graphicsQueue, { uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() @@ -1091,7 +1100,8 @@ void GDeviceVLK::submitDrawCommands() { {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, {fbCommandBuffer->getNativeCmdBuffer(), swapChainCmd->getNativeCmdBuffer()}, - {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()} + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + inFlightFences[currentDrawFrame]->getNativeFence() ); presentQueue( @@ -1103,29 +1113,29 @@ void GDeviceVLK::submitDrawCommands() { executeDeallocators(); } -void GDeviceVLK::submitQueue( const std::vector &waitSemaphores, +void GDeviceVLK::submitQueue( VkQueue queue, + const std::vector &waitSemaphores, const std::vector &waitStages, const std::vector &commandBuffers, - const std::vector &signalSemaphoresOnCompletion) { + const std::vector &signalSemaphoresOnCompletion, + const VkFence signalFenceOnCompletion) { VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = NULL; submitInfo.waitSemaphoreCount = waitSemaphores.size(); - submitInfo.pWaitDstStageMask = waitStages.data(); - submitInfo.pWaitSemaphores = waitSemaphores.data(); + submitInfo.pWaitDstStageMask = waitSemaphores.empty() ? nullptr : waitStages.data(); + submitInfo.pWaitSemaphores = waitSemaphores.empty() ? nullptr : waitSemaphores.data(); submitInfo.commandBufferCount = commandBuffers.size(); submitInfo.pCommandBuffers = commandBuffers.data(); submitInfo.signalSemaphoreCount = signalSemaphoresOnCompletion.size(); - submitInfo.pSignalSemaphores = signalSemaphoresOnCompletion.data(); - - int currentDrawFrame = getDrawFrameNumber(); + submitInfo.pSignalSemaphores = signalSemaphoresOnCompletion.empty() ? nullptr : signalSemaphoresOnCompletion.data(); { - auto result = vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentDrawFrame]->getNativeFence()); + auto result = vkQueueSubmit(queue, 1, &submitInfo, signalFenceOnCompletion); if (result != VK_SUCCESS) { std::cout << "failed to submit draw command buffer! result = " << result << std::endl << std::flush; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index bbf038493..8cf589e13 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -93,12 +93,11 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> &renderFuncs); + void drawFrame(const std::vector> &renderFuncs) override; void updateBuffers(/*std::vector*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; - void drawMeshes(std::vector &meshes) override; -// void drawStageAndDeps(HDrawStage drawStage) override; + // void drawStageAndDeps(HDrawStage drawStage) override; // void drawM2Meshes(std::vector &meshes); bool getIsVulkanAxisSystem() override {return true;} @@ -146,10 +145,12 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &waitSemaphores, const std::vector &waitStages, const std::vector &commandBuffers, - const std::vector &signalSemaphoresOnCompletion) ; + const std::vector &signalSemaphoresOnCompletion, + const VkFence signalFenceOnCompletion) ; void presentQueue(const std::vector &waitSemaphores, const std::vector &swapchains, diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 385d55c4f..25d70caed 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -87,6 +87,26 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); } +void CmdBufRecorder::bindIndexBuffer(std::shared_ptr &bufferVlk) { + if (m_currentIndexBuffer == bufferVlk) return; + + vkCmdBindIndexBuffer(m_gCmdBuffer.m_cmdBuffer, bufferVlk->getGPUBuffer(), 0, VK_INDEX_TYPE_UINT16); + + m_currentIndexBuffer = bufferVlk; +} +void CmdBufRecorder::bindVertexBuffer(std::shared_ptr &bufferVlk){ + if (m_currentIndexBuffer == bufferVlk) return; + + constexpr const int firstBinding = 0; + constexpr const int bindingCount = 1; + const std::array vbos = {bufferVlk->getGPUBuffer()}; + const std::array offsets = {0}; + + vkCmdBindVertexBuffers(m_gCmdBuffer.m_cmdBuffer, firstBinding, bindingCount, vbos.data(), offsets.data()); + + m_currentIndexBuffer = bufferVlk; +} + void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { if (m_currentPipeline == pipeline) return; @@ -95,8 +115,13 @@ void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { m_currentPipeline = pipeline; } -void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { - vkCmdDrawIndexed(m_gCmdBuffer.m_cmdBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); +void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance) { + vkCmdDrawIndexed(m_gCmdBuffer.m_cmdBuffer, + indexCount, + instanceCount, + firstIndex, + 0, //m_currentVertexBuffer->getOffset(), + firstInstance); } void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 69f19be96..debe06f53 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -36,9 +36,11 @@ class CmdBufRecorder { const std::array &areaSize, const std::array &colorClearColor, float depthClear); + void bindIndexBuffer(std::shared_ptr &bufferVlk); + void bindVertexBuffer(std::shared_ptr &bufferVlk); void bindPipeline(std::shared_ptr &pipeline); void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); - void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); + void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); @@ -52,6 +54,8 @@ class CmdBufRecorder { //States std::shared_ptr m_currentRenderPass = nullptr; std::shared_ptr m_currentPipeline = nullptr; + std::shared_ptr m_currentIndexBuffer = nullptr; + std::shared_ptr m_currentVertexBuffer = nullptr; std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 615ff29b3..bc7eb6095 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -32,7 +32,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr for (int i = 0; i < p_metaData->uboBindings.size(); i++) { auto &uboBinding = p_metaData->uboBindings[i]; - if (uboBinding.set != setIndex) return; + if (uboBinding.set != setIndex) continue; auto it = shaderLayoutBindings.find(uboBinding.binding); if (it != std::end( shaderLayoutBindings )) { @@ -57,7 +57,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr for (int i = 0; i < p_metaData->imageBindings.size(); i++) { auto &imageBinding = p_metaData->imageBindings[i]; - if (imageBinding.set != setIndex) return; + if (imageBinding.set != setIndex) continue; auto it = shaderLayoutBindings.find(imageBinding.binding); if (it != std::end( shaderLayoutBindings )) { diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 9cebe171e..55729f896 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -76,7 +76,6 @@ void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const this->createImageDescriptorLayout(); this->createPipelineLayout(); - } int GShaderPermutationVLK::getTextureBindingStart() { @@ -182,17 +181,18 @@ void GShaderPermutationVLK::createShaderLayout() { } void GShaderPermutationVLK::createPipelineLayout() { - std::array descLayouts ; - descLayouts[0] = this->getUboDescriptorLayout()->getSetLayout(); - descLayouts[1] = this->getImageDescriptorLayout()->getSetLayout(); + std::array descLayouts = { + this->getUboDescriptorLayout()->getSetLayout(), + this->getImageDescriptorLayout()->getSetLayout() + }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.pNext = NULL; pipelineLayoutInfo.pushConstantRangeCount = 0; pipelineLayoutInfo.pPushConstantRanges = NULL; - pipelineLayoutInfo.setLayoutCount = 2; - pipelineLayoutInfo.pSetLayouts = &descLayouts[0]; + pipelineLayoutInfo.setLayoutCount = descLayouts.size(); + pipelineLayoutInfo.pSetLayouts = descLayouts.data(); std::cout << "Pipeline layout for "+this->getShaderCombinedName() << std::endl; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 171e1f545..40e4992bc 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -78,41 +78,7 @@ void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { renderFunctions.push_back(std::move(frameScenario->drawUpdateFunction[i]())); } -// auto device = m_apiContainer->hDevice; -// -// -// auto frameScenario = m_frameScenarios[updateObjFrame]; -// if (frameScenario == nullptr) return; -// device->startUpdateForNextFrame(); -// for (auto updateStage : frameScenario->updateStages) { -// updateStage->cullResult->scene->produceUpdateStage(updateStage); -// } -// std::vector meshes; -// collectMeshes(frameScenario->getDrawStage(), meshes); -// -// for (auto updateStage : frameScenario->updateStages) { -// updateStage->cullResult->scene->updateBuffers(updateStage); -// } -// -// std::vector*> uniformChunkVec; -// std::vector frameDepDataVec; -// -// for (auto &updateStage : frameScenario->updateStages) { -// frameDepDataVec.push_back(updateStage->cullResult->frameDependentData); -// uniformChunkVec.push_back(&updateStage->uniformBufferChunks); -// } -// device->updateBuffers(uniformChunkVec, frameDepDataVec); -// for (auto cullStage : frameScenario->cullStages) { -// cullStage->scene->doPostLoad(cullStage); //Do post load after rendering is done! -// } -// device->uploadTextureForMeshes(meshes); -// -// if (device->getIsVulkanAxisSystem()) { -// if (frameScenario != nullptr) { -// m_apiContainer->hDevice->drawStageAndDeps(frameScenario->getDrawStage()); -// } -// } -// device->endUpdateForNextFrame(); + m_apiContainer->hDevice->drawFrame(renderFunctions); } #define logExecution {} //#define logExecution { \ From 3cb8f2ec25260fddcc853b11ad2c982fe9851f83 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 18 Feb 2023 19:23:13 +0200 Subject: [PATCH 031/212] commit --- CMakeLists.txt | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 36 +++- .../vulkan/FrontendUIRenderForwardVLK.h | 6 +- .../vulkan/materials/UIMaterialVLK.cpp | 5 - .../uiScene/vulkan/materials/UIMaterialVLK.h | 26 --- wowViewerLib/CMakeLists.txt | 15 +- .../src/engine/managers/CRibbonEmitter.cpp | 17 +- .../managers/particles/particleEmitter.cpp | 14 +- .../src/engine/objects/ViewsObjects.cpp | 6 +- .../src/engine/objects/adt/adtObject.cpp | 25 +-- .../gapi/interface/IVertexBufferBindings.h | 2 +- .../src/gapi/interface/materials/IMaterial.h | 2 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 6 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 4 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 6 +- .../gapi/vulkan/GVertexBufferBindingsVLK.cpp | 21 ++- .../gapi/vulkan/GVertexBufferBindingsVLK.h | 13 +- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 4 + .../CommandBufferRecorder.cpp | 6 +- .../CommandBufferRecorder.h | 2 +- .../vulkan/descriptorSets/DescriptorRecord.h | 22 +++ .../vulkan/descriptorSets/GDescriptorSet.cpp | 50 ++++-- .../vulkan/descriptorSets/GDescriptorSet.h | 23 +-- .../descriptorSets/GDescriptorSetLayout.cpp | 17 +- .../descriptorSets/GDescriptorSetLayout.h | 8 + .../vulkan/materials/ISimpleMaterialVLK.cpp | 164 ++++++------------ .../vulkan/materials/ISimpleMaterialVLK.h | 18 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 44 +++++ .../vulkan/materials/MaterialBuilderVLK.h | 43 +++++ .../vulkan/shaders/GShaderPermutationVLK.cpp | 33 ++-- .../vulkan/shaders/GShaderPermutationVLK.h | 16 +- .../GFenceVLK.cpp | 0 .../GFenceVLK.h | 0 .../GSemaphoreVLK.cpp | 0 .../GSemaphoreVLK.h | 0 35 files changed, 364 insertions(+), 292 deletions(-) delete mode 100644 src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp delete mode 100644 src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h create mode 100644 wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h rename wowViewerLib/src/gapi/vulkan/{syncronization => synchronization}/GFenceVLK.cpp (100%) rename wowViewerLib/src/gapi/vulkan/{syncronization => synchronization}/GFenceVLK.h (100%) rename wowViewerLib/src/gapi/vulkan/{syncronization => synchronization}/GSemaphoreVLK.cpp (100%) rename wowViewerLib/src/gapi/vulkan/{syncronization => synchronization}/GSemaphoreVLK.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f8cde2fef..a4620b999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,7 +240,7 @@ set(SOURCE_FILES set(SOURCE_FILES_VULKAN src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp - src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h) + src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h) ######################################################### # FIND OPENGL diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index c9288126e..3509d799d 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -8,6 +8,7 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h" FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( hDevice), m_device(hDevice) { @@ -23,6 +24,9 @@ void FrontendUIRenderForwardVLK::createBuffers() { uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_imguiUbo = std::make_shared>(uboBuffer); + + m_imguiVAO = m_device->createVertexBufferBindings(); + m_imguiVAO->addVertexBufferBinding(nullptr, std::vector(imguiBindings.begin(), imguiBindings.end())); } HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { @@ -33,6 +37,11 @@ HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } +HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules + return m_imguiVAO; +} + HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { auto i = m_materialCache.find(materialTemplate); if (i != m_materialCache.end()) { @@ -43,12 +52,25 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate } } - std::vector> ubos = {m_imguiUbo->}; - std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; - auto material = std::make_shared(m_device, - "imguiShader", "imguiShader", - ubos, - texturesVLK); + auto &l_imguiUbo = m_imguiUbo; + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}) + .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(1, l_imguiUbo->getSubBuffer()); + }) + .createDescriptorSet(1, [&materialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, std::dynamic_pointer_cast(materialTemplate.texture)); + }) + .toMaterial(); + +// +// std::vector> ubos = {m_imguiUbo->getSubBuffer()}; +// std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; +// auto material = std::make_shared(m_device, +// "imguiShader", "imguiShader", +// ubos, +// texturesVLK); std::weak_ptr weakPtr(material); m_materialCache[materialTemplate] = weakPtr; @@ -89,7 +111,7 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( swapChainCmd.bindVertexBuffer(l_this->vboBuffer); //2. Bind IBOs - swapChainCmd.bindVertexBuffer(l_this->iboBuffer); + swapChainCmd.bindIndexBuffer(l_this->iboBuffer); //3. Bind pipeline auto pipeline = meshVlk->getPipeLineForRenderPass(l_this->m_lastRenderPass, false); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index d1d584d59..179da60a2 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -24,9 +24,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBuffer createVertexBuffer(int sizeInBytes) override; HGIndexBuffer createIndexBuffer(int sizeInBytes) override; - HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override { - return nullptr; //VAO doesnt exist in Vulkan - }; + HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; HMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) override; @@ -44,6 +42,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; + HGVertexBufferBindings m_imguiVAO; + void createBuffers(); std::shared_ptr m_lastRenderPass; diff --git a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp deleted file mode 100644 index 857759764..000000000 --- a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by Deamon on 22.01.23. -// - -#include "UIMaterialVLK.h" diff --git a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h b/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h deleted file mode 100644 index 393c8ca2f..000000000 --- a/src/ui/renderer/uiScene/vulkan/materials/UIMaterialVLK.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Created by Deamon on 22.01.23. -// - -#ifndef AWEBWOWVIEWERCPP_UIMATERIALVLK_H -#define AWEBWOWVIEWERCPP_UIMATERIALVLK_H - -#include "../../materials/UIMaterial.h" -#include "../../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" - -class UIMaterialVLK : public ISimpleMaterialVLK { -public: - UIMaterialVLK(const HGDeviceVLK &device, - std::shared_ptr> &UIWideChunk, - std::shared_ptr &texture - ) : - ISimpleMaterialVLK(device, "imguiShader", "imguiShader", - {std::dynamic_pointer_cast(UIWideChunk)}, - {std::dynamic_pointer_cast(texture)}) - { - - } -}; - - -#endif //AWEBWOWVIEWERCPP_UIMATERIALVLK_H diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index bf91e0d62..3fadb6418 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -493,7 +493,20 @@ if (LINK_VULKAN) src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h src/gapi/vulkan/commandBuffer/CommandBuffer.cpp - src/gapi/vulkan/commandBuffer/CommandBuffer.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h src/gapi/vulkan/IDeviceVulkan.h src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp src/gapi/vulkan/syncronization/GSemaphoreVLK.h src/gapi/vulkan/syncronization/GFenceVLK.cpp src/gapi/vulkan/syncronization/GFenceVLK.h src/renderer/vulkan/IRenderFunctionVLK.h) + src/gapi/vulkan/commandBuffer/CommandBuffer.h + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h + src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp + src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h + src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp + src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h + src/gapi/vulkan/IDeviceVulkan.h + src/gapi/vulkan/synchronization/GSemaphoreVLK.cpp + src/gapi/vulkan/synchronization/GSemaphoreVLK.h + src/gapi/vulkan/synchronization/GFenceVLK.cpp + src/gapi/vulkan/synchronization/GFenceVLK.h + src/renderer/vulkan/IRenderFunctionVLK.h + src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 3c48abda4..6b6593ef6 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -6,12 +6,12 @@ #include "../../../3rdparty/mathfu/include/mathfu/glsl_mappings.h" #include "../../gapi/UniformBufferStructures.h" -static GBufferBinding staticRibbonBindings[3] = { - {+ribbonShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 24, 0 }, // 0 - {+ribbonShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, 24, 12}, // 12 - {+ribbonShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, 24, 16}, // 16 +static std::array staticRibbonBindings = {{ + {+ribbonShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, pos) }, // 0 + {+ribbonShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(CRibbonVertex), offsetof(CRibbonVertex, diffuseColor)}, // 12 + {+ribbonShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, texCoord)}, // 16 //24 -}; +}}; //----- (00A19710) -------------------------------------------------------- CRibbonEmitter::CRibbonEmitter(HApiContainer api, M2Object *object, @@ -92,6 +92,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat auto device = m_api->hDevice; //Create Buffers + auto ribbonBindings = std::vector(staticRibbonBindings.begin(), staticRibbonBindings.end()); for (int k = 0; k < 4; k++) { //TODO: /* @@ -102,11 +103,7 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat frame[k].m_bindings = device->createVertexBufferBindings(); frame[k].m_bindings->setIndexBuffer(frame[k].m_indexVBO); - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = frame[k].m_bufferVBO; - vertexBinding.bindings = std::vector(&staticRibbonBindings[0],&staticRibbonBindings[3]); - - frame[k].m_bindings->addVertexBufferBinding(vertexBinding); + frame[k].m_bindings->addVertexBufferBinding(frame[k].m_bufferVBO, ribbonBindings); frame[k].m_bindings->save(); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 20b057ff5..f3102c2a6 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -20,13 +20,13 @@ HGIndexBuffer ParticleEmitter::m_indexVBO = nullptr; static const size_t MAX_PARTICLES_PER_EMITTER = 2000; -static GBufferBinding staticM2ParticleBindings[5] = { +static const std::array staticM2ParticleBindings = {{ {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, -}; +}}; enum class ParticleVertexShader : int { @@ -284,6 +284,8 @@ void ParticleEmitter::createMesh() { } //Create Buffers + auto bindingVector = std::vector(staticM2ParticleBindings.begin(), + staticM2ParticleBindings.end()); for (int i = 0; i < 4; i++) { //TODO: // frame[i].m_bufferVBO = device->createVertexBufferDynamic(10 * sizeof(ParticleBuffStructQuad)); @@ -291,15 +293,9 @@ void ParticleEmitter::createMesh() { frame[i].m_bindings = device->createVertexBufferBindings(); frame[i].m_bindings->setIndexBuffer(m_indexVBO); - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = frame[i].m_bufferVBO; - vertexBinding.bindings = std::vector(&staticM2ParticleBindings[0], - &staticM2ParticleBindings[5]); - - frame[i].m_bindings->addVertexBufferBinding(vertexBinding); + frame[i].m_bindings->addVertexBufferBinding(frame[i].m_bufferVBO, bindingVector); frame[i].m_bindings->save(); - //Get shader HGShaderPermutation shaderPermutation = device->getShader("m2ParticleShader", "m2ParticleShader", nullptr); diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 6fe8668bc..5dc971040 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -128,11 +128,9 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st portalPointsFrame.m_bindings = hDevice->createVertexBufferBindings(); portalPointsFrame.m_bindings->setIndexBuffer(portalPointsFrame.m_indexVBO); - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = portalPointsFrame.m_bufferVBO; - vertexBinding.bindings = std::vector(DrawPortalBindings.begin(), DrawPortalBindings.end()); + auto const drawPortalBindings = std::vector(DrawPortalBindings.begin(), DrawPortalBindings.end()); - portalPointsFrame.m_bindings->addVertexBufferBinding(vertexBinding); + portalPointsFrame.m_bindings->addVertexBufferBinding(portalPointsFrame.m_bufferVBO, drawPortalBindings); portalPointsFrame.m_bindings->save(); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 478f4d058..4cf65057a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -39,6 +39,11 @@ static std::array adtVertexBufferBinding = {{ {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, }}; +static std::array adtVertexBufferLODBinding = {{ + {+adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 8, 0 }, + {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} +}}; + static GBufferBinding staticWaterBindings[2] = { {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)}, @@ -542,12 +547,10 @@ void AdtObject::createVBO() { adtVertexBindings = device->createVertexBufferBindings(); adtVertexBindings->setIndexBuffer(stripIBO); - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = combinedVbo; - vertexBinding.bindings = std::vector(adtVertexBufferBinding.begin(), + auto const adtBindings = std::vector(adtVertexBufferBinding.begin(), adtVertexBufferBinding.end()); - adtVertexBindings->addVertexBufferBinding(vertexBinding); + adtVertexBindings->addVertexBufferBinding(combinedVbo, adtBindings); adtVertexBindings->save(); } else { stripIBO = nullptr; @@ -564,9 +567,6 @@ void AdtObject::createVBO() { for (int i = 0; i < m_adtFileLod->floatDataBlob_len ; i++) { vboLod.push_back(this->m_adtFileLod->floatDataBlob[i]); - } - uint32_t indexVBOLodOffset = vboLod.size(); - for (int i = 0; i < (129 * 129 + 128 * 128); i++) { vboLod.push_back((float) i); } @@ -586,12 +586,13 @@ void AdtObject::createVBO() { GVertexBufferBinding vertexBinding; vertexBinding.vertexBuffer = combinedVbo; - GBufferBinding adtLodBufferBinding = { +adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 4, 0 }; - vertexBinding.bindings.push_back(adtLodBufferBinding); - GBufferBinding adtLodBufferBinding2 = {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 4, static_cast(indexVBOLodOffset * sizeof(float))}; - vertexBinding.bindings.push_back(adtLodBufferBinding2); + //TODO: +// GBufferBinding adtLodBufferBinding = { +adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 4, 0 }; +// vertexBinding.bindings.push_back(adtLodBufferBinding); +// GBufferBinding adtLodBufferBinding2 = {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 4, static_cast(indexVBOLodOffset * sizeof(float))}; +// vertexBinding.bindings.push_back(adtLodBufferBinding2); - lodVertexBindings->addVertexBufferBinding(vertexBinding); +// lodVertexBindings->addVertexBufferBinding(vertexBinding, ); lodVertexBindings->save(); } } diff --git a/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h b/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h index 5009a821d..1eef20da2 100644 --- a/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h +++ b/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h @@ -33,7 +33,7 @@ class IVertexBufferBindings { virtual void save() = 0; virtual void setIndexBuffer(HGIndexBuffer indexBuffer) = 0; - virtual void addVertexBufferBinding(GVertexBufferBinding binding) = 0; + virtual void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) = 0; }; #endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERBINDINGS_H diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index a5c912b70..559374429 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -10,8 +10,6 @@ class IMaterial { public: - HGShaderPermutation m_shader = nullptr; - virtual ~IMaterial() = default; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 83a1774e8..c44730a93 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -22,7 +22,7 @@ #include "GRenderPassVLK.h" #include "../../engine/algorithms/FrameCounter.h" #include "buffers/GBufferVLK.h" -#include "syncronization/GFenceVLK.h" +#include "synchronization/GFenceVLK.h" #include "../../renderer/vulkan/IRenderFunctionVLK.h" #include @@ -904,7 +904,7 @@ void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { for (const auto &hmesh : meshes) { GMeshVLK * mesh = (GMeshVLK *) hmesh.get(); - mesh->material()->updateImageDescriptorSet(); +// mesh->material()->updateImageDescriptorSet(); // for (int i = 0; i < mesh->textureCount(); i++) { // textures.push_back(mesh->m_texture[i]); @@ -959,7 +959,7 @@ HGBufferVLK GDeviceVLK::createIndexBuffer(size_t initialSize) { HGVertexBufferBindings GDeviceVLK::createVertexBufferBindings() { std::shared_ptr h_vertexBindings; - h_vertexBindings.reset(new GVertexBufferBindingsVLK(*this)); + h_vertexBindings.reset(new GVertexBufferBindingsVLK()); return h_vertexBindings; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 8cf589e13..c344d1163 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -35,8 +35,8 @@ class gMeshTemplate; #include "../../renderer/IRenderParameters.h" #include "buffers/GBufferVLK.h" #include "IDeviceVulkan.h" -#include "syncronization/GFenceVLK.h" -#include "syncronization/GSemaphoreVLK.h" +#include "synchronization/GFenceVLK.h" +#include "synchronization/GSemaphoreVLK.h" #include diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index a487961c0..038c49dde 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -117,9 +117,9 @@ void GPipelineVLK::createPipeline( vertexInputInfo.vertexBindingDescriptionCount = vertexBindingDescriptions.size(); - vertexInputInfo.vertexAttributeDescriptionCount = vertexAttributeDescriptions.size(); - vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescriptions[0]; - vertexInputInfo.pVertexAttributeDescriptions = &vertexAttributeDescriptions[0]; + vertexInputInfo.pVertexBindingDescriptions = vertexBindingDescriptions.data(); + vertexInputInfo.vertexAttributeDescriptionCount = vertexAttributeDescriptions.size(); + vertexInputInfo.pVertexAttributeDescriptions = vertexAttributeDescriptions.data(); VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp index f10a805f4..a15f2f085 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp @@ -6,7 +6,7 @@ #include "GVertexBufferBindingsVLK.h" #include "../interface/IDevice.h" -GVertexBufferBindingsVLK::GVertexBufferBindingsVLK(IDevice &m_device) : m_device(m_device) { +GVertexBufferBindingsVLK::GVertexBufferBindingsVLK() { } @@ -64,19 +64,17 @@ VkFormat gBindingToVkFormat(GBindingType gType, uint32_t size, bool normalized ) void GVertexBufferBindingsVLK::setIndexBuffer(HGIndexBuffer indexBuffer) { - m_indexBuffer = indexBuffer; + //Not used in VULKAN } -void GVertexBufferBindingsVLK::addVertexBufferBinding(GVertexBufferBinding binding) { - m_bindings.push_back(binding); - +void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) { int bindingIdx = 0; - for (auto &gVertexBinding : m_bindings) { +// for (auto &gVertexBinding : m_bindings) { uint32_t stride = 0; - if (gVertexBinding.bindings[0].stride != 0) { - stride = gVertexBinding.bindings[0].stride; + if (bindings[0].stride != 0) { + stride = bindings[0].stride; } else { - stride = gVertexBinding.bindings[0].size * ((gVertexBinding.bindings[0].type == GBindingType::GFLOAT) ? 4 : 1); + stride = bindings[0].size * ((bindings[0].type == GBindingType::GFLOAT) ? 4 : 1); } vkBufferFormatHolder bufferFormatHolder; @@ -84,7 +82,7 @@ void GVertexBufferBindingsVLK::addVertexBufferBinding(GVertexBufferBinding bindi bufferFormatHolder.bindingDescription.stride = stride; bufferFormatHolder.bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - for (auto &gBinding : gVertexBinding.bindings) { + for (auto &gBinding : bindings) { VkVertexInputAttributeDescription attributeDescription = {}; attributeDescription.binding = bindingIdx; attributeDescription.location = gBinding.position; @@ -96,10 +94,11 @@ void GVertexBufferBindingsVLK::addVertexBufferBinding(GVertexBufferBinding bindi bindingIdx++; m_BufferBindingsVLK.push_back(bufferFormatHolder); - } +// } } void GVertexBufferBindingsVLK::save() { + //Not used in VULKAN } std::vector &GVertexBufferBindingsVLK::getVLKFormat() { diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h index 94c6aef56..407c909ab 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h @@ -22,18 +22,9 @@ struct vkBufferFormatHolder { class GVertexBufferBindingsVLK : public IVertexBufferBindings { private: - std::vector m_bindings; std::vector m_BufferBindingsVLK; - HGIndexBuffer m_indexBuffer = HGIndexBuffer(nullptr); - - -private: - IDevice &m_device; -private: - - public: - explicit GVertexBufferBindingsVLK(IDevice &m_device); + explicit GVertexBufferBindingsVLK(); ~GVertexBufferBindingsVLK() override; private: @@ -42,7 +33,7 @@ class GVertexBufferBindingsVLK : public IVertexBufferBindings { void save() override; void setIndexBuffer(HGIndexBuffer indexBuffer) override; - void addVertexBufferBinding(GVertexBufferBinding binding) override; + void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) override; std::vector &getVLKFormat(); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index 392f59149..3bc53989a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -22,6 +22,10 @@ class CBufferChunkVLK : public IBufferChunk { void save() override { subBuffer->save(sizeof(T)); }; + + const std::shared_ptr getSubBuffer() { + return subBuffer; + } private: std::shared_ptr subBuffer = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 25d70caed..f6ee42c37 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -85,6 +85,8 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); + + m_currentDescriptorSet[bindIndex] = descriptorSet; } void CmdBufRecorder::bindIndexBuffer(std::shared_ptr &bufferVlk) { @@ -95,7 +97,7 @@ void CmdBufRecorder::bindIndexBuffer(std::shared_ptr &bufferVlk) { m_currentIndexBuffer = bufferVlk; } void CmdBufRecorder::bindVertexBuffer(std::shared_ptr &bufferVlk){ - if (m_currentIndexBuffer == bufferVlk) return; + if (m_currentVertexBuffer == bufferVlk) return; constexpr const int firstBinding = 0; constexpr const int bindingCount = 1; @@ -104,7 +106,7 @@ void CmdBufRecorder::bindVertexBuffer(std::shared_ptr &bufferVlk){ vkCmdBindVertexBuffers(m_gCmdBuffer.m_cmdBuffer, firstBinding, bindingCount, vbos.data(), offsets.data()); - m_currentIndexBuffer = bufferVlk; + m_currentVertexBuffer = bufferVlk; } void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index debe06f53..552b02809 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -56,7 +56,7 @@ class CmdBufRecorder { std::shared_ptr m_currentPipeline = nullptr; std::shared_ptr m_currentIndexBuffer = nullptr; std::shared_ptr m_currentVertexBuffer = nullptr; - std::array, GDescriptorSet::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; }; #endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h new file mode 100644 index 000000000..797a7821a --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -0,0 +1,22 @@ +// +// Created by Deamon on 17.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_DESCRIPTORRECORD_H +#define AWEBWOWVIEWERCPP_DESCRIPTORRECORD_H + +#include +#include "../buffers/IBufferVLK.h" +#include "../textures/GTextureVLK.h" + +struct DescriptorRecord { + enum class DescriptorRecordType { + None, UBO, UBODynamic, Texture + }; + + DescriptorRecordType descType = DescriptorRecordType::None; + std::shared_ptr buffer = nullptr; + std::shared_ptr textureVlk = nullptr; +}; + +#endif //AWEBWOWVIEWERCPP_DESCRIPTORRECORD_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index f6985eb7d..408d186fe 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -6,7 +6,7 @@ #include "../textures/GTextureVLK.h" -GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout) +GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout) : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); @@ -40,7 +40,7 @@ void GDescriptorSet::update() { // // So, writes first, copies second. T_T void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites) { - vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), &descriptorWrites[0], 0, nullptr); + vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); m_firstUpdate = false; @@ -58,23 +58,24 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &textureVlk) { - if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { + auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); + + if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { std::cerr << "descriptor mismatch for image" << std::endl; throw std::runtime_error("descriptor mismatch for image"); } - m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBODynamic; + m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::Texture; m_boundDescriptors[bindIndex].textureVlk = textureVlk; m_updateBindPoints[bindIndex] = true; VkDescriptorImageInfo &imageInfo = imageInfos.emplace_back(); imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageView = textureVlk->texture.view; imageInfo.sampler = textureVlk->texture.sampler; - VkWriteDescriptorSet writeDescriptor = updates.emplace_back(); + VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptor.dstSet = m_set.getDescSet(); writeDescriptor.pNext = nullptr; @@ -93,7 +94,9 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &buffer) { - if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { + auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); + + if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { std::cerr << "descriptor mismatch for UBO dynamic" << std::endl; throw std::runtime_error("descriptor mismatch for UBO dynamic"); } @@ -126,10 +129,20 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr &buffer) { - if (m_set.m_hDescriptorSetLayout->getShaderLayoutBindings().at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); + auto &uboSizes = m_set.m_hDescriptorSetLayout->getRequiredUBOSize(); + + if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { std::cerr << "descriptor mismatch for UBO" << std::endl; throw std::runtime_error("descriptor mismatch for UBO"); } + if (uboSizes.find(bindIndex) != uboSizes.end() && buffer->getSize() != uboSizes.at(bindIndex)) { + std::cout << "buffers missmatch! for" + << " binding = " << bindIndex + << " expected size " << uboSizes.at(bindIndex) + << ", provided size = " << (buffer->getSize()) + << std::endl; + } m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBO; m_boundDescriptors[bindIndex].buffer = buffer; @@ -141,7 +154,6 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptrgetOffset(); bufferInfo.range = buffer->getSize(); - VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptor.dstSet = m_set.getDescSet(); @@ -165,8 +177,10 @@ GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptrgetRequiredBindPoints() & m_updateBindPoints.flip(); + + if (!noSetBitSet.none()) { + std::string notSetBits; + for (int i = 0; i < noSetBitSet.size(); i++) { + notSetBits += " " + std::to_string(i); + } + + std::cerr << "required descriptors " << notSetBits << " were not set during update" << std::endl; + throw std::runtime_error("required descriptors were not set"); + } + + m_set.writeToDescriptorSets(updates); + + } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index b76dc8b42..3802d96f6 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -15,30 +15,21 @@ class GDescriptorPoolVLK; #include "../buffers/IBufferVLK.h" #include "../textures/GTextureVLK.h" #include "GDescriptorSetLayout.h" +#include "DescriptorRecord.h" class GDescriptorSet { public: - static const constexpr int MAX_BINDPOINT_NUMBER = 16; - - explicit GDescriptorSet(const std::shared_ptr &device, std::shared_ptr &hDescriptorSetLayout); + explicit GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout); ~GDescriptorSet(); void update(); void writeToDescriptorSets(std::vector &descriptorWrites); - const std::shared_ptr &getSetLayout() const { return m_hDescriptorSetLayout;}; + const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} - struct DescriptorRecord { - enum class DescriptorRecordType { - None, UBO, UBODynamic, Texture - }; - DescriptorRecordType descType = DescriptorRecordType::None; - std::shared_ptr buffer = nullptr; - std::shared_ptr textureVlk = nullptr; - }; class SetUpdateHelper { public: @@ -57,13 +48,13 @@ class GDescriptorSet { private: GDescriptorSet &m_set; - std::array &m_boundDescriptors; + std::array &m_boundDescriptors; std::vector imageInfos; std::vector bufferInfos; std::vector updates; - std::bitset m_updateBindPoints = 0; + std::bitset m_updateBindPoints = 0; }; SetUpdateHelper beginUpdate(); @@ -73,11 +64,11 @@ class GDescriptorSet { VkDescriptorSet m_descriptorSet; std::shared_ptr m_parentPool; - std::shared_ptr m_hDescriptorSetLayout; + const std::shared_ptr m_hDescriptorSetLayout; bool m_firstUpdate = true; - std::array boundDescriptors; + std::array boundDescriptors; // Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea // //Defines amount of frames that the updates has to be copied from previous frame diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index bc7eb6095..67981ee4e 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -9,7 +9,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaDatas, int setIndex) : m_device(device) { //Create Layout - std::unordered_map shaderLayoutBindings; + auto &shaderLayoutBindings = m_shaderLayoutBindings; for (const auto p_metaData : metaDatas) { auto const &metaData = *p_metaData; @@ -27,8 +27,6 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } }(metaData.stage); - - for (int i = 0; i < p_metaData->uboBindings.size(); i++) { auto &uboBinding = p_metaData->uboBindings[i]; @@ -50,7 +48,12 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr uboLayoutBinding.stageFlags = vkStageFlag; shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); + if (uboBinding.size > 0) { + m_requiredUBOSize.insert({uboBinding.binding,uboBinding.size}); + } m_totalUbos++; + + m_requiredBindPoints[uboBinding.binding] = true; } } @@ -68,7 +71,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } } else { VkDescriptorSetLayoutBinding imageLayoutBinding = {}; - imageLayoutBinding.binding = p_metaData->imageBindings[i].binding; + imageLayoutBinding.binding = imageBinding.binding; imageLayoutBinding.descriptorCount = 1; imageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; imageLayoutBinding.pImmutableSamplers = nullptr; @@ -76,6 +79,8 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr shaderLayoutBindings.insert({imageBinding.binding, imageLayoutBinding}); m_totalImages++; + + m_requiredBindPoints[imageBinding.binding] = true; } } } @@ -87,8 +92,8 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr //Create VK descriptor layout VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = shaderLayoutBindings.size(); - layoutInfo.pBindings = (shaderLayoutBindings.size() > 0) ? &shaderLayoutBindings[0] : nullptr; + layoutInfo.bindingCount = layouts.size(); + layoutInfo.pBindings = (!layouts.empty()) ? layouts.data() : nullptr; if (vkCreateDescriptorSetLayout(m_device->getVkDevice(), &layoutInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 5c15a974a..85da59c53 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -10,12 +10,15 @@ class GDescriptorSetLayout; class IDeviceVulkan; +#include #include "../context/vulkan_context.h" #include "../IDeviceVulkan.h" #include "../../../engine/shader/ShaderDefinitions.h" class GDescriptorSetLayout { public: + static const constexpr int MAX_BINDPOINT_NUMBER = 16; + GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaData, int setIndex); ~GDescriptorSetLayout(); @@ -23,11 +26,16 @@ class GDescriptorSetLayout { const VkDescriptorSetLayout getSetLayout() {return m_descriptorSetLayout;} ; const std::unordered_map& getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; + const std::unordered_map& getRequiredUBOSize() const {return m_requiredUBOSize;} ; int getTotalUbos() { return m_totalUbos; }; int getTotalImages() { return m_totalImages; }; + std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; private: std::unordered_map m_shaderLayoutBindings; + std::unordered_map m_requiredUBOSize; + + std::bitset m_requiredBindPoints = 0; VkDescriptorSetLayout m_descriptorSetLayout; int m_totalImages = 0; int m_totalUbos = 0; diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index cc86cab61..f25ae426c 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -6,112 +6,62 @@ #include "../shaders/GShaderPermutationVLK.h" #include "../textures/GTextureVLK.h" -void ISimpleMaterialVLK::createImageDescriptorSet() { - auto shaderVLK = std::dynamic_pointer_cast(m_shader); - auto descLayout = shaderVLK->getImageDescriptorLayout(); - - descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; - - int textureBegin = shaderVLK->getTextureBindingStart(); - - auto blackTexture = m_device->getBlackTexturePixel(); - auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); - - { - auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); - for (int i = 0; i < shaderVLK->getTextureCount(); i++) { - updateHelper.texture(textureBegin + i, blackTextureVlk); - } - } -} - - -void ISimpleMaterialVLK::updateImageDescriptorSet() { - bool allTexturesAreReady = true; - - auto shaderVLK = std::dynamic_pointer_cast(m_shader); - int textureBegin = shaderVLK->getTextureBindingStart(); - - for (auto& texture : m_textures) { - if (texture == nullptr) continue; - allTexturesAreReady &= texture->getIsLoaded(); - } - - if (allTexturesAreReady) { - auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); - for (size_t i = 0; i < m_textures.size(); i++) { - auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); - if (textureVlk == nullptr) continue; - - updateHelper.texture(textureBegin + i, textureVlk); - } - } -} - -void ISimpleMaterialVLK::createAndUpdateUBODescriptorSet() { - auto shaderVLK = std::dynamic_pointer_cast(m_shader); - auto descLayout = shaderVLK->getUboDescriptorLayout(); - - descriptors[GShaderPermutationVLK::UBO_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; - - auto updateHelper = descriptors[GShaderPermutationVLK::UBO_SET_INDEX]->beginUpdate(); - for (size_t i = 0; i < m_ubos.size(); i++) { - updateHelper.ubo(i, m_ubos[i]); - } -} - - -ISimpleMaterialVLK::ISimpleMaterialVLK(const HGDeviceVLK &device, - const std::string &vertexShader, const std::string &pixelShader, - const std::vector> &ubos, - const std::vector &textures) : m_device(device) { - m_shader = device->getShader(vertexShader, pixelShader, nullptr); - - auto shaderVLK = std::dynamic_pointer_cast(m_shader); - auto &shaderLayout = shaderVLK->getShaderLayout(); - - auto uboSetLayout = shaderLayout.setLayouts[GShaderPermutationVLK::UBO_SET_INDEX]; - if (ubos.size() != uboSetLayout.uboBindings.length) { - std::cerr << "not enough ubos for shaderName = " << shaderVLK->getShaderCombinedName() << std::endl; - } - for (unsigned int i = uboSetLayout.uboBindings.start; i <= uboSetLayout.uboBindings.end; i++) { - auto it = uboSetLayout.uboSizesPerBinding.find(i); - if (it != std::end(uboSetLayout.uboSizesPerBinding)) { - auto uboIndex = i - uboSetLayout.uboBindings.start; - if (ubos[uboIndex] == nullptr) { - std::cerr << "UBO is not set for " - << "shader = " << shaderVLK->getShaderCombinedName() - << " set = " << 1 - << " binding" << i - << std::endl; - } - - if (it->second != ubos[uboIndex]->getSize()) { - std::cout << "buffers missmatch! for" - << " shaderName = " << shaderVLK->getShaderCombinedName() - << " set = " << 1 - << " binding = " << i - << " expected size " << (it->second) - << ", provided size = " << (ubos[uboIndex]->getSize()) - << std::endl; - } - } - } - - auto imageSetLayout = shaderLayout.setLayouts[GShaderPermutationVLK::IMAGE_SET_INDEX]; - if (imageSetLayout.imageBindings.length != textures.size()) { - std::cout << "image count mismatch! for" - << " shaderName = " << shaderVLK->getShaderCombinedName() - << " set = " << 1 - << " expected count " << uboSetLayout.imageBindings.length - << ", provided count = " << textures.size() - << std::endl; - } - - m_textures = textures; - m_ubos = ubos; - - createImageDescriptorSet(); - createAndUpdateUBODescriptorSet(); +//void ISimpleMaterialVLK::createImageDescriptorSet() { +// auto shaderVLK = std::dynamic_pointer_cast(m_shader); +// auto descLayout = shaderVLK->getImageDescriptorLayout(); +// +// descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; +// +// int textureBegin = shaderVLK->getTextureBindingStart(); +// +// auto blackTexture = m_device->getBlackTexturePixel(); +// auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); +// +// { +// auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); +// for (int i = 0; i < shaderVLK->getTextureCount(); i++) { +// updateHelper.texture(textureBegin + i, blackTextureVlk); +// } +// } +//} +// +// +//void ISimpleMaterialVLK::updateImageDescriptorSet() { +// bool allTexturesAreReady = true; +// +// auto shaderVLK = std::dynamic_pointer_cast(m_shader); +// int textureBegin = shaderVLK->getTextureBindingStart(); +// +// for (auto& texture : m_textures) { +// if (texture == nullptr) continue; +// allTexturesAreReady &= texture->getIsLoaded(); +// } +// +// if (allTexturesAreReady) { +// auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); +// for (size_t i = 0; i < m_textures.size(); i++) { +// auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); +// if (textureVlk == nullptr) continue; +// +// updateHelper.texture(textureBegin + i, textureVlk); +// } +// } +//} +// +//void ISimpleMaterialVLK::createAndUpdateUBODescriptorSet() { +// auto shaderVLK = std::dynamic_pointer_cast(m_shader); +// auto descLayout = shaderVLK->getUboDescriptorLayout(); +// +// descriptors[GShaderPermutationVLK::UBO_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; +// +// auto updateHelper = descriptors[GShaderPermutationVLK::UBO_SET_INDEX]->beginUpdate(); +// for (size_t i = 0; i < m_ubos.size(); i++) { +// updateHelper.ubo(i, m_ubos[i]); +// } +//} + +ISimpleMaterialVLK::ISimpleMaterialVLK(const HGShaderPermutation &shader, + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : + m_shader(shader), descriptors(descriptorSets) { } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 84e308888..558f4aef0 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -15,32 +15,24 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: - explicit ISimpleMaterialVLK(const HGDeviceVLK &device, const std::string &vertexShader, const std::string &pixelShader, - - const std::vector> &ubos, - const std::vector> &textures); + explicit ISimpleMaterialVLK(const HGShaderPermutation &m_shader, + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); ~ISimpleMaterialVLK() override = default; HGShaderPermutation getShader() { return m_shader; } - void createImageDescriptorSet(); - void updateImageDescriptorSet(); +// void createImageDescriptorSet(); +// void updateImageDescriptorSet(); - void createAndUpdateUBODescriptorSet(); +// void createAndUpdateUBODescriptorSet(); const std::array, MAX_SHADER_DESC_SETS> &getDescriptorSets() { return descriptors; } private: - HGDeviceVLK m_device; - - std::vector m_textures = {}; - std::vector> m_ubos = {}; - - std::array, MAX_SHADER_DESC_SETS> descriptors; HGShaderPermutation m_shader; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp new file mode 100644 index 000000000..de01ec357 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -0,0 +1,44 @@ +// +// Created by Deamon on 17.02.23. +// + +#include "MaterialBuilderVLK.h" +#include "../GDeviceVulkan.h" +#include "../shaders/GShaderPermutationVLK.h" +#include "ISimpleMaterialVLK.h" + +MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &device, + const std::vector &shaderFiles) : m_device(device) { + + m_shader = std::dynamic_pointer_cast(device)->getShader( + shaderFiles[0], + shaderFiles[1], nullptr); +} + +MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, + const std::function &ds)> &callback) { + + auto shaderVLK = std::dynamic_pointer_cast(m_shader); + + auto ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint)); + callback(ds); + + descriptorSets[bindPoint] = ds; + + return *this; +} + +MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::shared_ptr &ds) { + //TODO: check DS layout compatibility + + descriptorSets[bindPoint] = ds; + + return *this; +} + +std::shared_ptr MaterialBuilderVLK::toMaterial() { + return std::make_shared( + m_shader, + descriptorSets + ); +} diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h new file mode 100644 index 000000000..a6c83ca10 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -0,0 +1,43 @@ +// +// Created by Deamon on 17.02.23. +// + +#ifndef AWEBWOWVIEWERCPP_MATERIALBUILDERVLK_H +#define AWEBWOWVIEWERCPP_MATERIALBUILDERVLK_H + +#include +#include +#include "../../interface/IDevice.h" +#include "ISimpleMaterialVLK.h" +#include "../descriptorSets/GDescriptorSet.h" + +class MaterialBuilderVLK { +public: + MaterialBuilderVLK(MaterialBuilderVLK const& ) = delete; + MaterialBuilderVLK& operator=(MaterialBuilderVLK const& ) = delete; + + static MaterialBuilderVLK fromShader(const std::shared_ptr &device, + const std::vector &shaderFiles) { + return {device, shaderFiles}; + } + + MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); + MaterialBuilderVLK& createDescriptorSet(int bindPoint, const std::function &ds)> &callback); + std::shared_ptr toMaterial(); + + ~MaterialBuilderVLK() = default; +private: + MaterialBuilderVLK(const std::shared_ptr &device, + const std::vector &shaderFiles); + + +private: + //States + const std::shared_ptr &m_device; + + HGShaderPermutation m_shader; + std::array, MAX_SHADER_DESC_SETS> descriptorSets; +}; + + +#endif //AWEBWOWVIEWERCPP_MATERIALBUILDERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 55729f896..8d80f4220 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -50,14 +50,14 @@ GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderVertName, std::s } -void GShaderPermutationVLK::createUBODescriptorLayout() { +void GShaderPermutationVLK::createSetDescriptorLayouts() { std::vector metas = {fragShaderMeta, vertShaderMeta}; - hUboDescriptorSetLayout = std::make_shared(m_device, metas, UBO_SET_INDEX); -} + for (int i = 0; i < combinedShaderLayout.setLayouts.size(); i++) { + auto &setLayout = combinedShaderLayout.setLayouts[i]; + if (setLayout.imageBindings.length == 0 && setLayout.uboBindings.length == 0) continue; -void GShaderPermutationVLK::createImageDescriptorLayout() { - std::vector metas = {fragShaderMeta, vertShaderMeta}; - hImageDescriptorSetLayout = std::make_shared(m_device, metas, IMAGE_SET_INDEX); + descriptorSetLayouts[i] = std::make_shared(m_device, metas, i); + } } void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const std::string &fragExtraDef) { @@ -72,18 +72,17 @@ void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const this->createShaderLayout(); - this->createUBODescriptorLayout(); - this->createImageDescriptorLayout(); + this->createSetDescriptorLayouts(); this->createPipelineLayout(); } int GShaderPermutationVLK::getTextureBindingStart() { - return shaderLayout.setLayouts[1].imageBindings.start; + return combinedShaderLayout.setLayouts[1].imageBindings.start; } int GShaderPermutationVLK::getTextureCount() { - return shaderLayout.setLayouts[1].imageBindings.length; + return combinedShaderLayout.setLayouts[1].imageBindings.length; } inline void makeMin(unsigned int &a, const unsigned int b) { @@ -100,7 +99,7 @@ void GShaderPermutationVLK::createShaderLayout() { for (int i = 0; i < this->vertShaderMeta->uboBindings.size(); i++) { auto &uboVertBinding = this->vertShaderMeta->uboBindings[i]; - auto &setLayout = shaderLayout.setLayouts[uboVertBinding.set]; + auto &setLayout = combinedShaderLayout.setLayouts[uboVertBinding.set]; setLayout.uboSizesPerBinding[uboVertBinding.binding] = uboVertBinding.size; makeMin(setLayout.uboBindings.start, uboVertBinding.binding); @@ -109,7 +108,7 @@ void GShaderPermutationVLK::createShaderLayout() { for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { auto &uboFragBinding = this->fragShaderMeta->uboBindings[i]; - auto &setLayout = shaderLayout.setLayouts[uboFragBinding.set]; + auto &setLayout = combinedShaderLayout.setLayouts[uboFragBinding.set]; auto it = setLayout.uboSizesPerBinding.find(uboFragBinding.binding); if (it != std::end(setLayout.uboSizesPerBinding)) { @@ -130,7 +129,7 @@ void GShaderPermutationVLK::createShaderLayout() { //Image stuff for (int i = 0; i < this->vertShaderMeta->imageBindings.size(); i++) { auto &imageVertBinding = this->vertShaderMeta->imageBindings[i]; - auto &setLayout = shaderLayout.setLayouts[imageVertBinding.set]; + auto &setLayout = combinedShaderLayout.setLayouts[imageVertBinding.set]; if (setLayout.uboSizesPerBinding.find(imageVertBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageVertBinding.set @@ -146,7 +145,7 @@ void GShaderPermutationVLK::createShaderLayout() { for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { auto &imageFragBinding = this->fragShaderMeta->imageBindings[i]; - auto &setLayout = shaderLayout.setLayouts[imageFragBinding.set]; + auto &setLayout = combinedShaderLayout.setLayouts[imageFragBinding.set]; if (setLayout.uboSizesPerBinding.find(imageFragBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageFragBinding.set @@ -160,7 +159,7 @@ void GShaderPermutationVLK::createShaderLayout() { makeMax(setLayout.imageBindings.end, imageFragBinding.binding); } //Cleanup - for (auto &shaderLayout : shaderLayout.setLayouts) { + for (auto &shaderLayout : combinedShaderLayout.setLayouts) { { auto &data = shaderLayout.uboBindings; if (shaderLayout.uboBindings.start < 100) { @@ -182,8 +181,8 @@ void GShaderPermutationVLK::createShaderLayout() { void GShaderPermutationVLK::createPipelineLayout() { std::array descLayouts = { - this->getUboDescriptorLayout()->getSetLayout(), - this->getImageDescriptorLayout()->getSetLayout() + this->getDescriptorLayout(0)->getSetLayout(), + this->getDescriptorLayout(1)->getSetLayout() }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index cd64ddb86..be0769e5b 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -34,8 +34,9 @@ class GShaderPermutationVLK : public IShaderPermutation { VkShaderModule getVertexModule() {return vertShaderModule;} VkShaderModule getFragmentModule() {return fragShaderModule;} - const std::shared_ptr getImageDescriptorLayout() {return hImageDescriptorSetLayout;} - const std::shared_ptr getUboDescriptorLayout() {return hUboDescriptorSetLayout;} + + + const std::shared_ptr getDescriptorLayout(int bindPoint) {return descriptorSetLayouts[bindPoint];} virtual int getTextureBindingStart(); virtual int getTextureCount(); @@ -48,7 +49,7 @@ class GShaderPermutationVLK : public IShaderPermutation { } const CombinedShaderLayout &getShaderLayout() { - return shaderLayout; + return combinedShaderLayout; }; VkPipelineLayout getPipelineLayout() { @@ -66,8 +67,7 @@ class GShaderPermutationVLK : public IShaderPermutation { VkPipelineLayout pipelineLayout; - std::shared_ptr hUboDescriptorSetLayout; - std::shared_ptr hImageDescriptorSetLayout; + std::array, MAX_SHADER_DESC_SETS> descriptorSetLayouts; std::shared_ptr m_device; private: @@ -78,11 +78,9 @@ class GShaderPermutationVLK : public IShaderPermutation { std::string m_shaderNameVert; std::string m_shaderNameFrag; - CombinedShaderLayout shaderLayout; - - void createUBODescriptorLayout(); + CombinedShaderLayout combinedShaderLayout; - void createImageDescriptorLayout(); + void createSetDescriptorLayouts(); void createShaderLayout(); void createPipelineLayout(); diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp similarity index 100% rename from wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.cpp rename to wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h similarity index 100% rename from wowViewerLib/src/gapi/vulkan/syncronization/GFenceVLK.h rename to wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp b/wowViewerLib/src/gapi/vulkan/synchronization/GSemaphoreVLK.cpp similarity index 100% rename from wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.cpp rename to wowViewerLib/src/gapi/vulkan/synchronization/GSemaphoreVLK.cpp diff --git a/wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h b/wowViewerLib/src/gapi/vulkan/synchronization/GSemaphoreVLK.h similarity index 100% rename from wowViewerLib/src/gapi/vulkan/syncronization/GSemaphoreVLK.h rename to wowViewerLib/src/gapi/vulkan/synchronization/GSemaphoreVLK.h From 77bfa17f1c08ed518ef6d5cb56763faca8f5b0a1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 19 Feb 2023 03:23:11 +0200 Subject: [PATCH 032/212] progress --- src/minimapGenerator/storage/CMinimapDataDB.h | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 19 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 367 +++++++----------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 40 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 72 +++- .../src/gapi/vulkan/GFrameBufferVLK.h | 12 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- .../CommandBufferRecorder.h | 4 + .../RenderPassHelper.cpp | 12 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 18 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 9 +- wowViewerLib/src/renderer/IRenderParameters.h | 1 + .../renderer/mapScene/FrameDependentData.h | 3 + 13 files changed, 276 insertions(+), 285 deletions(-) diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index 1e931e9a9..826478a4e 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -5,7 +5,7 @@ #ifndef AWEBWOWVIEWERCPP_CMINIMAPDATADB_H #define AWEBWOWVIEWERCPP_CMINIMAPDATADB_H -#include "../../../3rdparty/sqlite_orm//sqlite_orm.h" +#include "../../../3rdparty/sqlite_orm/sqlite_orm.h" #include "../entities.h" #include "../minimapGenerator.h" namespace CMinimapDataDB { diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 3509d799d..ec47daf55 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -125,7 +125,24 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( } } - //5. Draw the mesh + //5. Set view port + +// swapChainCmd.setViewPort(); + + //5. Set view port +// swapChainCmd.setScissors(defaultScissor); + + // //Set scissors +// VkRect2D defaultScissor = {}; +// defaultScissor.offset = {0, 0}; +// defaultScissor.extent = { +// static_cast(drawStage->viewPortDimensions.maxs[0]), +// static_cast(drawStage->viewPortDimensions.maxs[1]) +// }; +// +// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); + + //6. Draw the mesh swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } })); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index c44730a93..4d2fc7e1c 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -165,7 +165,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -264,13 +264,8 @@ void GDeviceVLK::initialize() { vmaCreateAllocator(&allocatorInfo, &vmaAllocator); //--------------- - createSwapChain(); - createImageViews(); + createSwapChainAndFramebuffer(); - createRenderPass(); - - createDepthResources(); - createFramebuffers(); createCommandPool(); createCommandPoolForUpload(); @@ -287,12 +282,35 @@ void GDeviceVLK::initialize() { } -void GDeviceVLK::recreateSwapChain() { - createSwapChain(); - createImageViews(); +void GDeviceVLK::createSwapChainAndFramebuffer() { + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); + VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); + VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); + + createSwapChain(swapChainSupport, surfaceFormat, extent); + + uint32_t imageCount; + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + + //Create swapchainImages and framebuffer + std::vector swapChainImages = {}; + swapChainImages.resize(imageCount); - createDepthResources(); - createFramebuffers(); + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); + + swapChainExtent = extent; + + //Create imageView + std::vector swapChainImageViews; + createSwapChainImageViews(swapChainImages, swapChainImageViews, surfaceFormat.format); + + std::vector swapChainTextures; + swapChainTextures.resize(swapChainImages.size()); + for (int i = 0; i < swapChainImages.size(); i++) { + swapChainTextures[i] = std::make_shared(*this, swapChainImages[i], swapChainImageViews[i]); + } + + createFramebuffers(swapChainTextures, extent); } void GDeviceVLK::setupDebugMessenger() { @@ -306,12 +324,8 @@ void GDeviceVLK::setupDebugMessenger() { } } -void GDeviceVLK::createSwapChain() { - SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); - - VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); +void GDeviceVLK::createSwapChain(SwapChainSupportDetails &swapChainSupport, VkSurfaceFormatKHR &surfaceFormat, VkExtent2D &extent) { VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); - VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); uint32_t imageCount = MAX_FRAMES_IN_FLIGHT; if ((imageCount > swapChainSupport.capabilities.maxImageCount && (swapChainSupport.capabilities.maxImageCount != 0)) @@ -359,16 +373,9 @@ void GDeviceVLK::createSwapChain() { std::cout << "error = " << error << std::endl << std::flush; throw std::runtime_error("failed to create swap chain!"); } - - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); - swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); - - swapChainImageFormat = surfaceFormat.format; - swapChainExtent = extent; } -void GDeviceVLK::createImageViews() { +void GDeviceVLK::createSwapChainImageViews(std::vector &swapChainImages, std::vector &swapChainImageViews, VkFormat swapChainImageFormat) { swapChainImageViews.resize(swapChainImages.size()); for (size_t i = 0; i < swapChainImages.size(); i++) { @@ -417,7 +424,7 @@ VkFormat GDeviceVLK::findDepthFormat() { ); } -void GDeviceVLK::createRenderPass() { +void GDeviceVLK::createSwapChainRenderPass(VkFormat swapChainImageFormat) { swapchainRenderPass = std::make_shared(this->device, std::vector({swapChainImageFormat}), findDepthFormat(), @@ -438,104 +445,17 @@ uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, Vk throw std::runtime_error("failed to find suitable memory type!"); } +void GDeviceVLK::createFramebuffers(std::vector &swapChainTextures, VkExtent2D &extent) { + swapChainFramebuffers.resize(swapChainTextures.size()); -VkImageView GDeviceVLK::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels) { - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = format; - viewInfo.subresourceRange.aspectMask = aspectFlags; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = mipLevels; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - VkImageView imageView; - if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { - throw std::runtime_error("failed to create texture image view!"); - } - - return imageView; -} - - -void GDeviceVLK::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, - VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, - VkImage& image, VkDeviceMemory& imageMemory, VkImageLayout vkLaylout) { - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = mipLevels; - imageInfo.arrayLayers = 1; - imageInfo.format = format; - imageInfo.tiling = tiling; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usage; - imageInfo.samples = numSamples; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -// if (indices.graphicsFamily != indices.presentFamily) { -// imageInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; -// } else { -// imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -// } - - if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { - throw std::runtime_error("failed to create image!"); - } - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, image, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties); - - if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate image memory!"); - } - - vkBindImageMemory(device, image, imageMemory, 0); -} - -void GDeviceVLK::createDepthResources() { - VkFormat depthFormat = findDepthFormat(); -// - createImage(swapChainExtent.width, swapChainExtent.height, 1, VK_SAMPLE_COUNT_1_BIT, depthFormat, - VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - depthImage, depthImageMemory, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1); - -// transitionImageLayout(depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1); -} - -void GDeviceVLK::createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size()); - - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - VkImageView attachments[] = { - swapChainImageViews[i], - depthImageView - }; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.pNext = NULL; - framebufferInfo.flags = 0; - framebufferInfo.renderPass = swapchainRenderPass->getRenderPass(); - framebufferInfo.attachmentCount = 2; - framebufferInfo.pAttachments = &attachments[0]; - framebufferInfo.width = swapChainExtent.width; - framebufferInfo.height = swapChainExtent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create framebuffer!"); - } + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + swapChainFramebuffers[i] = std::make_shared( + *this, + swapChainTextures[i], + extent.width, + extent.height, + swapchainRenderPass + ); } } @@ -714,13 +634,12 @@ void GDeviceVLK::createCommandPoolForUpload(){ void GDeviceVLK::createCommandBuffers() { for (auto & commandBuffer : fbCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, false, indices.graphicsFamily.value()); + commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily.value()); } for (auto & commandBuffer : swapChainCommandBuffers) { commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily.value()); } - for (auto & commandBuffer : uploadCommandBuffers) { commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.transferFamily.value()); } @@ -766,22 +685,36 @@ float GDeviceVLK::getAnisLevel() { } void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { - int uploadFrame = getUpdateFrameNumber(); + int currentDrawFrame = getDrawFrameNumber(); this->waitInDrawStageAndDeps.beginMeasurement(); - uploadFences[uploadFrame]->wait(std::numeric_limits::max()); - inFlightFences[uploadFrame]->wait(std::numeric_limits::max()); - uploadFences[uploadFrame]->reset(); + uploadFences[currentDrawFrame]->wait(std::numeric_limits::max()); + inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); + uploadFences[currentDrawFrame]->reset(); this->waitInDrawStageAndDeps.endMeasurement(); - auto &uploadCmdBuf = uploadCommandBuffers[uploadFrame]; - auto &swapChainCmdBuf = swapChainCommandBuffers[uploadFrame]; - auto &frameBufCmdBuf = fbCommandBuffers[uploadFrame]; + auto &uploadCmdBuf = uploadCommandBuffers[currentDrawFrame]; + auto &swapChainCmdBuf = swapChainCommandBuffers[currentDrawFrame]; + auto &frameBufCmdBuf = fbCommandBuffers[currentDrawFrame]; + + uint32_t imageIndex = -1; { - auto uploadCmd = std::move(uploadCmdBuf->beginRecord(nullptr)); - auto swapChainCmd = std::move(swapChainCmdBuf->beginRecord(nullptr)); - auto frameBufCmd = std::move(frameBufCmdBuf->beginRecord(nullptr)); + auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); + auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); + + { + //Wait for SwapChain CMD buffer to become available + inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); + inFlightFences[currentDrawFrame]->reset(); + } + auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); + + { + //Begin render pass for Swap chain + this->getNextSwapImageIndex(imageIndex); + this->beginSwapChainRenderPass(imageIndex, swapChainCmd); + } for (int i = 0; i < renderFuncs.size(); i++) { dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); @@ -793,11 +726,75 @@ void GDeviceVLK::drawFrame(const std::vector> & {}, {}, {uploadCmdBuf->getNativeCmdBuffer()}, - {uploadSemaphores[uploadFrame]->getNativeSemaphore()}, - uploadFences[uploadFrame]->getNativeFence() + {uploadSemaphores[currentDrawFrame]->getNativeSemaphore()}, + uploadFences[currentDrawFrame]->getNativeFence() + ); + + submitQueue( + graphicsQueue, + { + uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), + imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() + }, + {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, + + {frameBufCmdBuf->getNativeCmdBuffer(), swapChainCmdBuf->getNativeCmdBuffer()}, + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + inFlightFences[currentDrawFrame]->getNativeFence() + ); + + presentQueue( + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + {swapChain}, + {imageIndex} ); + + executeDeallocators(); +} + +RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd) { + int currentDrawFrame = getDrawFrameNumber(); + + //Begin render pass for swap CMD buffer. + //It used to execute secondary command buffer, but now this is altered + + return swapChainCmd.beginRenderPass(false, + swapchainRenderPass, + swapChainFramebuffers[imageIndex], + {0,0}, + {swapChainExtent.width, swapChainExtent.height}, + {0, 0, 0}, + 1.0f + ); +} + +void GDeviceVLK::getNextSwapImageIndex(uint32_t &imageIndex) { + int currentDrawFrame = getDrawFrameNumber(); + + VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + std::cout << "got VK_ERROR_OUT_OF_DATE_KHR" << std::endl << std::flush; + createSwapChainAndFramebuffer(); + + return; + } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + std::cout << "error happened " << result << std::endl << std::flush; +// throw std::runtime_error("failed to acquire swap chain image!"); + } + + if (imageIndex >= inFlightFences.size()) { + std::cout << "imageIndex >= inFlightFences.size()" << std::endl; + } + +// std::cout << "imageIndex = " << imageIndex << " currentDrawFrame = " << currentDrawFrame << std::endl << std::flush; + + if (((imageIndex+1)&3) != currentDrawFrame) { +// std::cout << "imageIndex != currentDrawFrame" << std::endl; + } } + void GDeviceVLK::updateBuffers(std::vector &frameDepedantData) { // aggregationBufferForUpload.resize(maxUniformBufferSize); /* @@ -1017,100 +1014,6 @@ void GDeviceVLK::submitDrawCommands() { return; } - int currentDrawFrame = getDrawFrameNumber(); - - uint32_t imageIndex; - VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); - - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - std::cout << "got VK_ERROR_OUT_OF_DATE_KHR" << std::endl << std::flush; - recreateSwapChain(); - - return; - } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - std::cout << "error happened " << result << std::endl << std::flush; -// throw std::runtime_error("failed to acquire swap chain image!"); - } - - if (imageIndex >= inFlightFences.size()) { - std::cout << "imageIndex >= inFlightFences.size()" << std::endl; - } - -// std::cout << "imageIndex = " << imageIndex << " currentDrawFrame = " << currentDrawFrame << std::endl << std::flush; - - if (((imageIndex+1)&3) != currentDrawFrame) { -// std::cout << "imageIndex != currentDrawFrame" << std::endl; - } - - inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); - inFlightFences[currentDrawFrame]->reset(); - - //Fill command buffer - //TODO:!!! - //This stuff creates commands that would write into the frameBuffer of the frame - //the problem is that it depends on the imageIndex, which cant be known beforehand - //Also, we would need info on the current settings of the clear color and invertZ stuff here - auto swapChainCmd = swapChainCommandBuffers[currentDrawFrame]; -// { -// VkCommandBufferBeginInfo beginInfo = {}; -// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; -// beginInfo.pNext = NULL; -// beginInfo.pInheritanceInfo = NULL; -// -// if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { -// throw std::runtime_error("failed to begin recording command buffer!"); -// } -// -// std::array clearValues = {}; -// clearValues[0].color = {clearColor[0], clearColor[1], clearColor[2], 1.0f}; -// clearValues[1].depthStencil = {getInvertZ() ? 0.0f : 1.0f, 0}; -// -// VkRenderPassBeginInfo renderPassInfo = {}; -// renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; -// renderPassInfo.pNext = NULL; -// renderPassInfo.renderPass = swapchainRenderPass->getRenderPass(); -// renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; -// renderPassInfo.renderArea.offset = {0, 0}; -// renderPassInfo.renderArea.extent = swapChainExtent; -// renderPassInfo.clearValueCount = static_cast(clearValues.size()); -// renderPassInfo.pClearValues = clearValues.data(); -// -// vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); -// -// if (renderCommandBuffersNotNull[currentDrawFrame]) { -// vkCmdExecuteCommands(commandBufferForFilling, 1, &renderCommandBuffers[currentDrawFrame]); -// } -// -// vkCmdEndRenderPass(commandBufferForFilling); -// -// if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { -// throw std::runtime_error("failed to record command buffer!"); -// } -// } - - auto fbCommandBuffer = fbCommandBuffers[currentDrawFrame]; - - submitQueue( - graphicsQueue, - { - uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), - imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() - }, - {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, - - {fbCommandBuffer->getNativeCmdBuffer(), swapChainCmd->getNativeCmdBuffer()}, - {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, - inFlightFences[currentDrawFrame]->getNativeFence() - ); - - presentQueue( - {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, - {swapChain}, - {imageIndex} - ); - - executeDeallocators(); } void GDeviceVLK::submitQueue( VkQueue queue, @@ -1160,7 +1063,7 @@ void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { framebufferResized = false; - recreateSwapChain(); + createSwapChainAndFramebuffer(); return; } else if (result != VK_SUCCESS) { std::cout << "failed to present swap chain image!" << std::endl << std::flush; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index c344d1163..56162df8b 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -20,6 +20,8 @@ class GM2MeshVLK; class GPipelineVLK; class GRenderPassVLK; class GDescriptorPoolVLK; +class CmdBufRecorder; +class RenderPassHelper; typedef std::shared_ptr HPipelineVLK; @@ -37,6 +39,7 @@ class gMeshTemplate; #include "IDeviceVulkan.h" #include "synchronization/GFenceVLK.h" #include "synchronization/GSemaphoreVLK.h" +#include "commandBuffer/commandBufferRecorder/RenderPassHelper.h" #include @@ -145,7 +148,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &waitSemaphores, const std::vector &waitStages, const std::vector &commandBuffers, @@ -210,25 +213,22 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &swapChainImages, std::vector &swapChainImageViews, VkFormat swapChainImageFormat); + + void createSwapChainRenderPass(VkFormat swapChainImageFormat); + + void createFramebuffers(std::vector &swapChainTextures, VkExtent2D &extent); void createCommandPool(); void createCommandPoolForUpload(); void createCommandBuffers(); void createSyncObjects(); - void createDepthResources(); - - - VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); - void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory, VkImageLayout vkLaylout); - VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels); protected: struct BlpCacheRecord { @@ -305,11 +305,11 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this swapChainImages; - VkFormat swapChainImageFormat; + + VkExtent2D swapChainExtent; - std::vector swapChainImageViews; - std::vector swapChainFramebuffers; + + std::vector> swapChainFramebuffers; std::shared_ptr swapchainRenderPass; @@ -318,10 +318,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> fbCommandBuffers = {nullptr}; std::array, MAX_FRAMES_IN_FLIGHT> swapChainCommandBuffers = {nullptr}; std::array, MAX_FRAMES_IN_FLIGHT> uploadCommandBuffers = {nullptr}; @@ -382,6 +378,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_createdRenderPasses; void executeDeallocators(); + + RenderPassHelper beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd); + + void getNextSwapImageIndex(uint32_t &imageIndex); }; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index bb2c6c59c..7269c91a5 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -1,10 +1,10 @@ // // Created by Deamon on 12/11/2020. // - #include #include "GFrameBufferVLK.h" #include "textures/GTextureVLK.h" + #include "GRenderPassVLK.h" void GFrameBufferVLK::iterateOverAttachments(const std::vector &textureAttachments, std::function callback) { @@ -29,6 +29,52 @@ void GFrameBufferVLK::iterateOverAttachments(const std::vector & } } +//Support for swapchain framebuffer +GFrameBufferVLK::GFrameBufferVLK(IDevice &device, + const HGTexture &colorImage, + int width, int height, + const std::shared_ptr &renderPass) + : mdevice(dynamic_cast(device)), + m_renderPass(renderPass), + m_attachmentTextures({colorImage}) { + + { + // Find a suitable depth format + VkFormat fbDepthFormat = mdevice.findDepthFormat(); + + std::shared_ptr h_depthTexture; + h_depthTexture.reset(new GTextureVLK( + mdevice, + width, height, + false, false, + true, + fbDepthFormat, + VK_SAMPLE_COUNT_1_BIT, + 1, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + )); + + m_depthTexture = h_depthTexture; + } + + std::array attachments = { + std::dynamic_pointer_cast(colorImage)->texture.view, + std::dynamic_pointer_cast(m_depthTexture)->texture.view + }; + + VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + fbufCreateInfo.pNext = nullptr; + fbufCreateInfo.flags = 0; + fbufCreateInfo.renderPass = m_renderPass->getRenderPass(); + fbufCreateInfo.attachmentCount = attachments.size(); + fbufCreateInfo.pAttachments = attachments.data(); + fbufCreateInfo.width = width; + fbufCreateInfo.height = height; + fbufCreateInfo.layers = 1; + + ERR_GUARD_VULKAN(vkCreateFramebuffer(mdevice.getVkDevice(), &fbufCreateInfo, nullptr, &m_frameBuffer)); +} + GFrameBufferVLK::GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, @@ -52,9 +98,9 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, 1, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT )); - attachmentTextures.push_back(h_texture); + m_attachmentTextures.push_back(h_texture); attachments.push_back(h_texture->texture.view); - attachmentFormats.push_back(textureFormat); + m_attachmentFormats.push_back(textureFormat); if (multiSampleCnt > 1) { std::shared_ptr h_texture; @@ -68,11 +114,9 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, 1, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT )); - attachmentTextures.push_back(h_texture); + m_attachmentTextures.push_back(h_texture); attachments.push_back(h_texture->texture.view); } - - }); //Depth attachment @@ -92,7 +136,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT )); - depthTexture = h_depthTexture; + m_depthTexture = h_depthTexture; attachments.push_back(h_depthTexture->texture.view); } @@ -120,14 +164,20 @@ GFrameBufferVLK::~GFrameBufferVLK() { } void GFrameBufferVLK::readRGBAPixels(int x, int y, int width, int height, void *outputdata) { -// Check blit support for source and destination + if (m_attachmentFormats.empty()) { + //Cant read from swapchain framebuffer + return; + } + + + // Check blit support for source and destination VkFormatProperties formatProps; VkPhysicalDevice physicalDevice = mdevice.getVkPhysicalDevice(); int attachmentIndex = 0; - VkFormat colorFormat = attachmentFormats[attachmentIndex]; + VkFormat colorFormat = m_attachmentFormats[attachmentIndex]; bool supportsBlit = false; // Check if the device supports blitting from optimal images (the swapchain images are in optimal format) @@ -358,11 +408,11 @@ HGTexture GFrameBufferVLK::getAttachment(int index) { index = 2*index+1; } - return attachmentTextures[index]; + return m_attachmentTextures[index]; } HGTexture GFrameBufferVLK::getDepthTexture() { - return depthTexture; + return m_depthTexture; } void GFrameBufferVLK::bindFrameBuffer() { diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index 6133aa4bf..65a81f4aa 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -13,6 +13,10 @@ class GFrameBufferVLK : public IFrameBuffer { public: GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, int width, int height); + GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, + int width, int height, + const std::shared_ptr &renderPass); + ~GFrameBufferVLK() override; void readRGBAPixels(int x, int y, int width, int height, void *data) override; @@ -24,7 +28,7 @@ class GFrameBufferVLK : public IFrameBuffer { static void iterateOverAttachments(const std::vector &textureAttachments, std::function callback); VkFramebuffer getFrameBuffer() {return m_frameBuffer;}; - int getColorOrDataAttachmentCount() { return attachmentFormats.size(); }; + int getColorOrDataAttachmentCount() { return m_attachmentFormats.size(); }; private: GDeviceVLK &mdevice; @@ -32,11 +36,11 @@ class GFrameBufferVLK : public IFrameBuffer { std::shared_ptr m_renderPass; VkFramebuffer m_frameBuffer; - std::vector attachmentTextures; - HGTexture depthTexture; + std::vector m_attachmentTextures; + HGTexture m_depthTexture; //Used only in readRGBAPixels function - std::vector attachmentFormats; + std::vector m_attachmentFormats; int m_multiSampleCnt; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 778c64677..68b0a7e70 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -124,7 +124,7 @@ void GBufferVLK::resize(int newLength) { } destroyBuffer(currentBuffer); - newBuffer = currentBuffer; + currentBuffer = newBuffer; } std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 552b02809..9e83b21d4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -24,6 +24,8 @@ class CmdBufRecorder { friend RenderPassHelper; CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); + CmdBufRecorder(const CmdBufRecorder&) = delete; + CmdBufRecorder operator=(const CmdBufRecorder&) = delete; ~CmdBufRecorder(); uint32_t getQueueFamily(); @@ -42,6 +44,8 @@ class CmdBufRecorder { void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); + void setViewport(); + void setScissors(); void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp index 058898843..dd1dc627f 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp @@ -12,12 +12,12 @@ // ---------------------------------------- RenderPassHelper::RenderPassHelper(CmdBufRecorder &cmdBufRecorder, - bool isAboutToExecSecondaryCMD, - const std::shared_ptr &renderPassVlk, - const std::shared_ptr &frameBuffer, - const std::array &areaOffset, - const std::array &areaSize, - const std::array &colorClearColor, float depthClear + bool isAboutToExecSecondaryCMD, + const std::shared_ptr &renderPassVlk, + const std::shared_ptr &frameBuffer, + const std::array &areaOffset, + const std::array &areaSize, + const std::array &colorClearColor, float depthClear ) : m_cmdBufRecorder(cmdBufRecorder) { auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor, depthClear); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index ad0970622..39382d1d7 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -43,7 +43,18 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, stagingBufferCreated = false; } +GTextureVLK::GTextureVLK(IDeviceVulkan &device, VkImageView imageView, VkImage image) : + m_device(device) { + //This image is used as holder for framebuffer data (swapchain framebuffer one) + texture.image = image; + texture.view = imageView; + + //this is texture for use in framebuffer, that's why it is set as initialized + m_loaded = true; + m_uploaded = true; + stagingBufferCreated = false; +} GTextureVLK::~GTextureVLK() { destroyBuffer(); @@ -52,9 +63,6 @@ GTextureVLK::~GTextureVLK() { void GTextureVLK::createBuffer() { } - - - void GTextureVLK::destroyBuffer() { if (!m_uploaded) return; @@ -69,8 +77,6 @@ void GTextureVLK::destroyBuffer() { vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); vkDestroySampler(l_device->getVkDevice(), l_texture.sampler, nullptr); vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); - - }); } @@ -84,8 +90,8 @@ void GTextureVLK::unbind() { bool GTextureVLK::getIsLoaded() { return m_loaded; } - static int pureTexturesUploaded = 0; + void GTextureVLK::loadData(int width, int height, void *data, ITextureFormat textureFormat) { // std::cout << "pureTexturesUploaded = " << pureTexturesUploaded++ << std::endl; std::vector unifiedBuffer((uint8_t *)data, (uint8_t *)data + (width*height*4)); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index b5e2e3a45..826454c13 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -25,6 +25,11 @@ class GTextureVLK : public ITexture { VkSampleCountFlagBits numSamples, int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags); + + explicit GTextureVLK(IDeviceVulkan &device, + VkImageView imageView, + VkImage image); + void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, std::vector unitedBuffer); public: ~GTextureVLK() override; @@ -46,7 +51,6 @@ class GTextureVLK : public ITexture { auto &l_stagingBuffer = m_tempUpdateData->stagingBuffer; auto &l_stagingBufferAlloc = m_tempUpdateData->stagingBufferAlloc; - m_device.addDeallocationRecord([l_tempUpdateData, l_device, l_stagingBuffer, l_stagingBufferAlloc]() { vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingBuffer, l_stagingBufferAlloc); @@ -60,9 +64,8 @@ class GTextureVLK : public ITexture { bool postLoad() override;; struct Texture { - VkSampler sampler; + VkSampler sampler = VK_NULL_HANDLE; VkImage image; - VkImageLayout imageLayout; VkImageView view; } texture; private: diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index cdc126423..c5d080f20 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -6,6 +6,7 @@ #define AWEBWOWVIEWERCPP_IRENDERPARAMETERS_H #include +#include #include "frame/FrameInputParams.h" class IRenderFunction { diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 8a420e9b3..9469b8b20 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -6,6 +6,9 @@ #define AWEBWOWVIEWERCPP_FRAMEDEPENDENTDATA_H #include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif #include "mathfu/glsl_mappings.h" struct FrameDependantData { From 682957578711f1bc6566089b7a085ab6d40fb96a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 19 Feb 2023 04:20:14 +0200 Subject: [PATCH 033/212] progress --- .../src/gapi/vulkan/GDeviceVulkan.cpp | 28 ++++++------------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 1 + .../src/gapi/vulkan/textures/GTextureVLK.cpp | 12 ++++++-- .../src/gapi/vulkan/textures/GTextureVLK.h | 9 ++++-- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 4d2fc7e1c..ceee34923 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -263,6 +263,10 @@ void GDeviceVLK::initialize() { vmaCreateAllocator(&allocatorInfo, &vmaAllocator); //--------------- + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + uniformBufferOffsetAlign = deviceProperties.limits.minUniformBufferOffsetAlignment; + maxUniformBufferSize = deviceProperties.limits.maxUniformBufferRange; +//--------------- createSwapChainAndFramebuffer(); @@ -272,11 +276,6 @@ void GDeviceVLK::initialize() { createCommandBuffers(); createSyncObjects(); - - vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); - uniformBufferOffsetAlign = deviceProperties.limits.minUniformBufferOffsetAlignment; - maxUniformBufferSize = deviceProperties.limits.maxUniformBufferRange; - std::cout << "uniformBufferOffsetAlign = " << uniformBufferOffsetAlign << std::endl; std::cout << "maxUniformBufferSize = " << maxUniformBufferSize << std::endl; } @@ -304,10 +303,14 @@ void GDeviceVLK::createSwapChainAndFramebuffer() { std::vector swapChainImageViews; createSwapChainImageViews(swapChainImages, swapChainImageViews, surfaceFormat.format); + //Create swapchain renderPass + createSwapChainRenderPass(surfaceFormat.format); + + //Create textures for automatic cleanup std::vector swapChainTextures; swapChainTextures.resize(swapChainImages.size()); for (int i = 0; i < swapChainImages.size(); i++) { - swapChainTextures[i] = std::make_shared(*this, swapChainImages[i], swapChainImageViews[i]); + swapChainTextures[i] = std::make_shared(*this, swapChainImages[i], swapChainImageViews[i], false); } createFramebuffers(swapChainTextures, extent); @@ -432,19 +435,6 @@ void GDeviceVLK::createSwapChainRenderPass(VkFormat swapChainImageFormat) { true); } -uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - throw std::runtime_error("failed to find suitable memory type!"); -} - void GDeviceVLK::createFramebuffers(std::vector &swapChainTextures, VkExtent2D &extent) { swapChainFramebuffers.resize(swapChainTextures.size()); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 56162df8b..81e52abde 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -228,7 +228,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); + VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) override; protected: struct BlpCacheRecord { diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index b1b8f5690..b275153a5 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -19,6 +19,7 @@ class IDeviceVulkan { const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) = 0; virtual VmaAllocator getVMAAllocator() = 0; + virtual VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) = 0; //TODO: bool getIsAnisFiltrationSupported() {return true;}; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 39382d1d7..9acbd53da 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -43,7 +43,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, stagingBufferCreated = false; } -GTextureVLK::GTextureVLK(IDeviceVulkan &device, VkImageView imageView, VkImage image) : +GTextureVLK::GTextureVLK(IDeviceVulkan &device, const VkImage &image, const VkImageView &imageView, bool dumbParam) : m_device(device) { //This image is used as holder for framebuffer data (swapchain framebuffer one) @@ -194,6 +194,14 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat textureFormatGPU, VkSampleCountFlagBits numSamples, int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) { + if (!isDepthTexture) { + m_device.findSupportedFormat( + {textureFormatGPU}, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + ); + } + //3. Create Image on GPU side VkImageCreateInfo imageCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; @@ -238,7 +246,7 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te // This feature is optional, so we must check if it's supported on the device if (m_device.getIsAnisFiltrationSupported()) { // Use max. level of anisotropy for this example - sampler.maxAnisotropy = std::min(m_device.getAnisLevel(), vulkanMipMapCount); + sampler.maxAnisotropy = std::min(m_device.getAnisLevel(), 16.0); sampler.anisotropyEnable = VK_TRUE; } else { // The device does not support anisotropic filtering diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 826454c13..9cc2051d6 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -15,7 +15,6 @@ class GCommandBuffer; class GTextureVLK : public ITexture { friend class GFrameBufferVLK; public: - explicit GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex); //Used for rendering to texture in framebuffer explicit GTextureVLK(IDeviceVulkan &device, int width, int height, @@ -26,9 +25,13 @@ class GTextureVLK : public ITexture { int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags); + //Dumb param is introduced only so that compiler would not invoke constructor with two bools, instead with one explicit GTextureVLK(IDeviceVulkan &device, - VkImageView imageView, - VkImage image); + const VkImage &image, + const VkImageView &imageView, + bool dumbParam); + + explicit GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex); void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, std::vector unitedBuffer); public: From e9fc1c67f128a8a6902aecc6820fabe942098c60 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 21 Feb 2023 02:46:39 +0200 Subject: [PATCH 034/212] UI is being rendered, hooray --- .../renderer/uiScene/FrontendUIRenderer.cpp | 3 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 37 +++--- .../vulkan/FrontendUIRenderForwardVLK.h | 2 - wowViewerLib/CMakeLists.txt | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 65 +++++------ wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 32 +----- .../gapi/vulkan/GVertexBufferBindingsVLK.cpp | 3 +- .../gapi/vulkan/GVertexBufferBindingsVLK.h | 6 + .../src/gapi/vulkan/TextureManagerVLK.cpp | 58 ++++++++++ .../src/gapi/vulkan/TextureManagerVLK.h | 58 ++++++++++ .../src/gapi/vulkan/buffers/GBufferVLK.h | 17 +-- .../CommandBufferRecorder.cpp | 107 ++++++++++++++++-- .../CommandBufferRecorder.h | 23 +++- .../TextureUploadHelper.cpp | 24 ++-- .../TextureUploadHelper.h | 4 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 8 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 22 ++-- .../src/gapi/vulkan/textures/GTextureVLK.h | 6 +- .../src/gapi/vulkan/utils/MutexLockedVector.h | 30 +++++ 20 files changed, 366 insertions(+), 143 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index da31c9e17..78a965da5 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -58,6 +58,9 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrcreateVertexBuffer(cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); auto iboBuffer = this->createIndexBuffer(cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vboBuffer->uploadData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + iboBuffer->uploadData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + auto vertexBufferBindings = this->createVAO(vboBuffer, iboBuffer); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index ec47daf55..13557fd96 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -24,9 +24,6 @@ void FrontendUIRenderForwardVLK::createBuffers() { uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_imguiUbo = std::make_shared>(uboBuffer); - - m_imguiVAO = m_device->createVertexBufferBindings(); - m_imguiVAO->addVertexBufferBinding(nullptr, std::vector(imguiBindings.begin(), imguiBindings.end())); } HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { @@ -38,7 +35,11 @@ HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { } HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { - //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m_imguiVAO = m_device->createVertexBufferBindings(); + m_imguiVAO->addVertexBufferBinding(vertexBuffer, std::vector(imguiBindings.begin(), imguiBindings.end())); + m_imguiVAO->setIndexBuffer(indexBuffer); + return m_imguiVAO; } @@ -107,11 +108,16 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( for (auto const &mesh : *meshes) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); + auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); + +// auto indexBuffer = (vulkanBindings->m_indexBuffer.get())->g_hIndexBuffer; +// auto vertexBuffer = ((GVertexBufferVLK *)binding->m_bindings[0].vertexBuffer.get())->g_hVertexBuffer; + //1. Bind VBOs - swapChainCmd.bindVertexBuffer(l_this->vboBuffer); + swapChainCmd.bindVertexBuffers(vulkanBindings->getVertexBuffers()); //2. Bind IBOs - swapChainCmd.bindIndexBuffer(l_this->iboBuffer); + swapChainCmd.bindIndexBuffer(vulkanBindings->getIndexBuffer()); //3. Bind pipeline auto pipeline = meshVlk->getPipeLineForRenderPass(l_this->m_lastRenderPass, false); @@ -126,23 +132,12 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( } //5. Set view port + swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); -// swapChainCmd.setViewPort(); - - //5. Set view port -// swapChainCmd.setScissors(defaultScissor); - - // //Set scissors -// VkRect2D defaultScissor = {}; -// defaultScissor.offset = {0, 0}; -// defaultScissor.extent = { -// static_cast(drawStage->viewPortDimensions.maxs[0]), -// static_cast(drawStage->viewPortDimensions.maxs[1]) -// }; -// -// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); + //6. Set view port + swapChainCmd.setScissors(); - //6. Draw the mesh + //7. Draw the mesh swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } })); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 179da60a2..362681017 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -42,8 +42,6 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; - HGVertexBufferBindings m_imguiVAO; - void createBuffers(); std::shared_ptr m_lastRenderPass; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 3fadb6418..5b6501b69 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -506,7 +506,7 @@ if (LINK_VULKAN) src/gapi/vulkan/synchronization/GFenceVLK.cpp src/gapi/vulkan/synchronization/GFenceVLK.h src/renderer/vulkan/IRenderFunctionVLK.h - src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h) + src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h src/gapi/vulkan/TextureManagerVLK.cpp src/gapi/vulkan/TextureManagerVLK.h src/gapi/vulkan/utils/MutexLockedVector.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index ceee34923..2e5893a2c 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -24,6 +24,7 @@ #include "buffers/GBufferVLK.h" #include "synchronization/GFenceVLK.h" #include "../../renderer/vulkan/IRenderFunctionVLK.h" +#include "commandBuffer/commandBufferRecorder/TextureUploadHelper.h" #include const int WIDTH = 1900; @@ -164,8 +165,10 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create } -GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) { - enableValidationLayers = true; +GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ + enableValidationLayers = false; + + m_textureManager->initialize(); if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -278,6 +281,14 @@ void GDeviceVLK::initialize() { std::cout << "uniformBufferOffsetAlign = " << uniformBufferOffsetAlign << std::endl; std::cout << "maxUniformBufferSize = " << maxUniformBufferSize << std::endl; + + m_blackPixelTexture = createTexture(false, false); + unsigned int zero = 0; + m_blackPixelTexture->loadData(1,1,&zero, ITextureFormat::itRGBA); + + m_whitePixelTexture = createTexture(false, false); + unsigned int ff = 0xffffffff; + m_whitePixelTexture->loadData(1,1,&ff, ITextureFormat::itRGBA); } @@ -700,14 +711,20 @@ void GDeviceVLK::drawFrame(const std::vector> & } auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); + //Do Texture update + { + auto textureVector = m_textureManager->getReadyToUploadTextures(); + textureUploadStrategy(textureVector.get(), frameBufCmd, uploadCmd); + } + { //Begin render pass for Swap chain this->getNextSwapImageIndex(imageIndex); - this->beginSwapChainRenderPass(imageIndex, swapChainCmd); - } + auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); - for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); + for (int i = 0; i < renderFuncs.size(); i++) { + dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); + } } } @@ -753,8 +770,8 @@ RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBu swapChainFramebuffers[imageIndex], {0,0}, {swapChainExtent.width, swapChainExtent.height}, - {0, 0, 0}, - 1.0f + {0.117647, 0.207843, 0.392157}, + 0.0f ); } @@ -952,39 +969,11 @@ HGVertexBufferBindings GDeviceVLK::createVertexBufferBindings() { } HGTexture GDeviceVLK::createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) { -// std::shared_ptr h_texture; -// h_texture.reset(new GBlpTextureVLK(*this, texture, xWrapTex, yWrapTex)); -// -// return h_texture; - - BlpCacheRecord blpCacheRecord; - blpCacheRecord.texture = texture.get(); -// blpCacheRecord.wrapX = xWrapTex; -// blpCacheRecord.wrapY = yWrapTex; - - auto i = loadedTextureCache.find(blpCacheRecord); - if (i != loadedTextureCache.end()) { - if (!i->second.expired()) { - return i->second.lock(); - } else { - loadedTextureCache.erase(i); - } - } - - std::shared_ptr hgTexture; - hgTexture.reset(new GBlpTextureVLK(*this, texture, xWrapTex, yWrapTex)); - - std::weak_ptr weakPtr(hgTexture); - loadedTextureCache[blpCacheRecord] = weakPtr; - - return hgTexture; + return m_textureManager->createBlpTexture(texture); } HGTexture GDeviceVLK::createTexture(bool xWrapTex, bool yWrapTex) { - std::shared_ptr h_texture; - h_texture.reset(new GTextureVLK(*this, xWrapTex, yWrapTex)); - - return h_texture; + return m_textureManager->createTexture(); } HGMesh GDeviceVLK::createMesh(gMeshTemplate &meshTemplate) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 81e52abde..8d434685b 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -22,6 +22,7 @@ class GRenderPassVLK; class GDescriptorPoolVLK; class CmdBufRecorder; class RenderPassHelper; +class TextureManagerVLK; typedef std::shared_ptr HPipelineVLK; @@ -40,6 +41,7 @@ class gMeshTemplate; #include "synchronization/GFenceVLK.h" #include "synchronization/GSemaphoreVLK.h" #include "commandBuffer/commandBufferRecorder/RenderPassHelper.h" +#include "TextureManagerVLK.h" #include @@ -63,8 +65,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; - // void drawStageAndDeps(HDrawStage drawStage) override; - - // void drawM2Meshes(std::vector &meshes); bool getIsVulkanAxisSystem() override {return true;} void initUploadThread() override; @@ -231,23 +224,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) override; protected: - struct BlpCacheRecord { - BlpTexture* texture; - - - bool operator==(const BlpCacheRecord &other) const { - return - (texture == other.texture); - }; - }; - struct BlpCacheRecordHasher { - std::size_t operator()(const BlpCacheRecord& k) const { - using std::hash; - return hash{}(k.texture); - }; - }; - std::unordered_map, BlpCacheRecordHasher> loadedTextureCache; - struct PipelineCacheRecord { HGShaderPermutation shader; std::shared_ptr renderPass; @@ -306,7 +282,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> swapChainFramebuffers; @@ -346,7 +321,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_textureManager; protected: //Caches std::unordered_map m_shaderPermuteCache; diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp index a15f2f085..3ebe3e0f8 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp @@ -64,7 +64,7 @@ VkFormat gBindingToVkFormat(GBindingType gType, uint32_t size, bool normalized ) void GVertexBufferBindingsVLK::setIndexBuffer(HGIndexBuffer indexBuffer) { - //Not used in VULKAN + m_indexBuffer = indexBuffer; } void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) { @@ -94,6 +94,7 @@ void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vert bindingIdx++; m_BufferBindingsVLK.push_back(bufferFormatHolder); + m_vertexBuffers.push_back(vertexBuffer); // } } diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h index 407c909ab..eac793072 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h @@ -23,6 +23,8 @@ struct vkBufferFormatHolder { class GVertexBufferBindingsVLK : public IVertexBufferBindings { private: std::vector m_BufferBindingsVLK; + std::vector m_vertexBuffers; + HGIndexBuffer m_indexBuffer = nullptr; public: explicit GVertexBufferBindingsVLK(); ~GVertexBufferBindingsVLK() override; @@ -36,6 +38,10 @@ class GVertexBufferBindingsVLK : public IVertexBufferBindings { void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) override; std::vector &getVLKFormat(); + + const HGIndexBuffer &getIndexBuffer() {return m_indexBuffer;}; + const std::vector &getVertexBuffers() {return m_vertexBuffers;}; + }; #endif //WEBWOWVIEWERCPP_GVERTEXBUFFERBINDINGS_H diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp new file mode 100644 index 000000000..c3a62bbbe --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -0,0 +1,58 @@ +// +// Created by Deamon on 2/20/2023. +// + +#include "GDeviceVulkan.h" +#include "TextureManagerVLK.h" +#include "textures/GBlpTextureVLK.h" + +TextureManagerVLK::TextureManagerVLK(IDevice &device) : mdevice(device) { +} + +void TextureManagerVLK::initialize() { + createUpdateCallback(); +} + +HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { + BlpCacheRecord blpCacheRecord; + blpCacheRecord.texture = texture.get(); +// blpCacheRecord.wrapX = xWrapTex; +// blpCacheRecord.wrapY = yWrapTex; + + auto i = loadedTextureCache.find(blpCacheRecord); + if (i != loadedTextureCache.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + loadedTextureCache.erase(i); + } + } + + auto hgTexture = std::make_shared(static_cast(mdevice), texture, false, false, onUpdateCallback); + + std::weak_ptr weakPtr(hgTexture); + { + std::lock_guard lock(this->blpTextureLoadMutex); + m_blpTextLoadQueue.push_back(weakPtr); + } + loadedTextureCache[blpCacheRecord] = weakPtr; + + return hgTexture; +} + +HGTexture TextureManagerVLK::createTexture() { + std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), false, false, onUpdateCallback); + + return h_texture; +} + +void TextureManagerVLK::createUpdateCallback() { + auto weak_this = this->weak_from_this(); + onUpdateCallback = [weak_this](const std::weak_ptr& texture) -> void { + if (auto shared_this = weak_this.lock()) { + std::lock_guard lock(shared_this->textUpdateMutex); + + shared_this->m_texturesReadyToBeUploaded.push_back(std::weak_ptr(texture)); + } + }; +} diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h new file mode 100644 index 000000000..dbea300fc --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -0,0 +1,58 @@ +// +// Created by Deamon on 2/20/2023. +// + +#ifndef AWEBWOWVIEWERCPP_TEXTUREMANAGERVLK_H +#define AWEBWOWVIEWERCPP_TEXTUREMANAGERVLK_H + +#include +#include +#include "utils/MutexLockedVector.h" +#include "../../engine/texture/BlpTexture.h" +#include "textures/GTextureVLK.h" + +class TextureManagerVLK : public std::enable_shared_from_this { +public: + TextureManagerVLK(IDevice &device); + void initialize(); + + + HGTexture createBlpTexture(HBlpTexture &texture); + HGTexture createTexture(); + + MutexLockedVector> getReadyToUploadTextures() { + return MutexLockedVector>(m_texturesReadyToBeUploaded, textUpdateMutex, true); + } + +protected: + struct BlpCacheRecord { + BlpTexture* texture; + + bool operator==(const BlpCacheRecord &other) const { + return + (texture == other.texture); + }; + }; + struct BlpCacheRecordHasher { + std::size_t operator()(const BlpCacheRecord& k) const { + using std::hash; + return hash{}(k.texture); + }; + }; + std::unordered_map, BlpCacheRecordHasher> loadedTextureCache; + +private: + IDevice &mdevice; + + std::function&)> onUpdateCallback = nullptr; + void createUpdateCallback(); + + std::mutex textUpdateMutex; + std::vector> m_texturesReadyToBeUploaded; + + std::mutex blpTextureLoadMutex; + std::list> m_blpTextLoadQueue; +}; + + +#endif //AWEBWOWVIEWERCPP_TEXTUREMANAGERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 4d2290ac8..42195cb9c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -15,20 +15,7 @@ typedef std::shared_ptr HGBufferVLK; #include "../GDeviceVulkan.h" #include "IBufferVLK.h" - -template -class MutexLockedVector { -public: - MutexLockedVector(std::vector &vec, std::mutex &m) : m_vec(vec), m_lockGuard(std::lock_guard(m)) { - - } - const std::vector &get() const { - return m_vec; - } -private: - std::vector &m_vec; - std::lock_guard m_lockGuard; -}; +#include "../utils/MutexLockedVector.h" class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; @@ -59,7 +46,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords() { - return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx); + return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); } void resize(int newLength); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index f6ee42c37..b46cf4baa 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -64,6 +64,9 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( throw std::runtime_error("tried to start render pass with another pass being active already"); } + createViewPortTypes(areaOffset, areaSize); + createDefaultScissors(areaOffset, areaSize); + m_currentRenderPass = renderPassVlk; return RenderPassHelper( *this, @@ -89,24 +92,42 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr m_currentDescriptorSet[bindIndex] = descriptorSet; } -void CmdBufRecorder::bindIndexBuffer(std::shared_ptr &bufferVlk) { +void CmdBufRecorder::bindIndexBuffer(const std::shared_ptr &buffer) { + auto bufferVlk = std::dynamic_pointer_cast(buffer); if (m_currentIndexBuffer == bufferVlk) return; - vkCmdBindIndexBuffer(m_gCmdBuffer.m_cmdBuffer, bufferVlk->getGPUBuffer(), 0, VK_INDEX_TYPE_UINT16); + VkDeviceSize offset = bufferVlk->getOffset(); + vkCmdBindIndexBuffer(m_gCmdBuffer.m_cmdBuffer, bufferVlk->getGPUBuffer(), offset, VK_INDEX_TYPE_UINT16); m_currentIndexBuffer = bufferVlk; } -void CmdBufRecorder::bindVertexBuffer(std::shared_ptr &bufferVlk){ - if (m_currentVertexBuffer == bufferVlk) return; +void CmdBufRecorder::bindVertexBuffers(const std::vector> &buffers){ + if (buffers.empty()) return; - constexpr const int firstBinding = 0; - constexpr const int bindingCount = 1; - const std::array vbos = {bufferVlk->getGPUBuffer()}; - const std::array offsets = {0}; + int firstBinding = 0; - vkCmdBindVertexBuffers(m_gCmdBuffer.m_cmdBuffer, firstBinding, bindingCount, vbos.data(), offsets.data()); + std::vector vbos = {}; + std::vector offsets = {}; + + for (int i = 0; i < buffers.size(); i++) { + auto bufferVlk = std::dynamic_pointer_cast(buffers[i]); + + //firstBinding == i <- means we can only skip the start of the list; + if (firstBinding == i && m_currentVertexBuffers[i] == bufferVlk) { + firstBinding++; + continue; + } + + vbos.push_back(bufferVlk->getGPUBuffer()); + offsets.push_back(bufferVlk->getOffset()); + + m_currentVertexBuffers[i] = bufferVlk; + } - m_currentVertexBuffer = bufferVlk; + int bindingCount = vbos.size(); + if (vbos.empty()) return; + + vkCmdBindVertexBuffers(m_gCmdBuffer.m_cmdBuffer, firstBinding, bindingCount, vbos.data(), offsets.data()); } void CmdBufRecorder::bindPipeline(std::shared_ptr &pipeline) { @@ -148,7 +169,7 @@ void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, const std regions.data()); } -void CmdBufRecorder:: submitBufferUploads(const std::shared_ptr &bufferVLK) { +void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &bufferVLK) { auto submitRecords = bufferVLK->getSubmitRecords(); if (submitRecords.get().empty()) @@ -160,3 +181,67 @@ void CmdBufRecorder:: submitBufferUploads(const std::shared_ptr &b submitRecords.get().size(), submitRecords.get().data()); } + +void CmdBufRecorder::setViewPort() { + +} +void CmdBufRecorder::setViewPort(ViewportType viewportType) { + const constexpr uint32_t firstViewport = 0; + const constexpr uint32_t viewportCount = 1; + + vkCmdSetViewport(m_gCmdBuffer.m_cmdBuffer, firstViewport, viewportCount, &viewportsForThisStage[(int)viewportType]); +} + +void CmdBufRecorder::setScissors() { + const constexpr uint32_t firstScissor = 0; + const constexpr uint32_t scissorCount = 1; + vkCmdSetScissor(m_gCmdBuffer.m_cmdBuffer, firstScissor, scissorCount, &defaultScissor); +} + + +void CmdBufRecorder::createViewPortTypes(const std::array &areaOffset, + const std::array &areaSize) { + VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; + usualViewport.width = areaSize[0]; + usualViewport.height = areaSize[1]; + usualViewport.x = areaOffset[0]; + usualViewport.y = areaOffset[1]; + bool invertZ = false; + if (invertZ) { + usualViewport.minDepth = 0; + usualViewport.maxDepth = 0.990f; + } else { + usualViewport.minDepth = 0.06f; + usualViewport.maxDepth = 1.0f; + } + + VkViewport &mapAreaViewport = viewportsForThisStage[(int)ViewportType::vp_mapArea]; + mapAreaViewport = usualViewport; + if (invertZ) { + mapAreaViewport.minDepth = 0.991f; + mapAreaViewport.maxDepth = 0.996f; + } else { + mapAreaViewport.minDepth = 0.04f; + mapAreaViewport.maxDepth = 0.05f; + } + + VkViewport &skyBoxViewport = viewportsForThisStage[(int)ViewportType::vp_skyBox]; + skyBoxViewport = usualViewport; + if (invertZ) { + skyBoxViewport.minDepth = 0.997f; + skyBoxViewport.maxDepth = 1.0f; + } else { + skyBoxViewport.minDepth = 0; + skyBoxViewport.maxDepth = 0.03f; + } +} + +void CmdBufRecorder::createDefaultScissors(const std::array &areaOffset, + const std::array &areaSize) { + defaultScissor = {}; + defaultScissor.offset = {areaOffset[0], areaOffset[1]}; + defaultScissor.extent = { + static_cast(areaSize[0]), + static_cast(areaSize[1]) + }; +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 9e83b21d4..1ac676055 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -21,6 +21,7 @@ class GCommandBuffer; class CmdBufRecorder { public: + enum class ViewportType: int {vp_none = -1, vp_usual = 0, vp_mapArea = 1, vp_skyBox = 2, vp_MAX = 3}; friend RenderPassHelper; CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); @@ -38,8 +39,8 @@ class CmdBufRecorder { const std::array &areaSize, const std::array &colorClearColor, float depthClear); - void bindIndexBuffer(std::shared_ptr &bufferVlk); - void bindVertexBuffer(std::shared_ptr &bufferVlk); + void bindIndexBuffer(const std::shared_ptr &bufferVlk); + void bindVertexBuffers(const std::vector> &bufferVlk); void bindPipeline(std::shared_ptr &pipeline); void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); @@ -52,15 +53,29 @@ class CmdBufRecorder { void submitBufferUploads(const std::shared_ptr &bufferVLK); friend class RenderPassHelper; + + void setViewPort(); + void setViewPort(ViewportType viewportType); private: const GCommandBuffer &m_gCmdBuffer; //States std::shared_ptr m_currentRenderPass = nullptr; std::shared_ptr m_currentPipeline = nullptr; - std::shared_ptr m_currentIndexBuffer = nullptr; - std::shared_ptr m_currentVertexBuffer = nullptr; + std::shared_ptr m_currentIndexBuffer = nullptr; + std::array, 2> m_currentVertexBuffers; std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + + + //Viewports + std::array viewportsForThisStage; + VkRect2D defaultScissor; + + void createViewPortTypes(const std::array &areaOffset, + const std::array &areaSize); + + void createDefaultScissors(const std::array &areaOffset, + const std::array &areaSize); }; #endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index 7e5b1dac9..714dd8fbb 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -18,12 +18,15 @@ struct TransitionParams { void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, - const std::vector &textures, + const std::vector> &textures, const TransitionParams &transitionParams) { std::vector imageMemoryBarriers; imageMemoryBarriers.reserve(textures.size()); - for ( auto &textureVlk : textures) { + for ( auto &wtextureVlk : textures) { + if (wtextureVlk.expired()) continue; + auto textureVlk = wtextureVlk.lock(); + // Image memory barriers for the texture image VkImageMemoryBarrier &imageMemoryBarrier = imageMemoryBarriers.emplace_back(); @@ -45,7 +48,7 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, imageMemoryBarrier.dstAccessMask = transitionParams.dstAccessMask; imageMemoryBarrier.oldLayout = transitionParams.oldLayout; imageMemoryBarrier.newLayout = transitionParams.newLayout; - imageMemoryBarrier.image = textureVlk.texture.image; + imageMemoryBarrier.image = textureVlk->texture.image; imageMemoryBarrier.srcQueueFamilyIndex = transitionParams.srcQueueFamilyIndex; imageMemoryBarrier.dstQueueFamilyIndex = transitionParams.dstQueueFamilyIndex; } @@ -60,9 +63,11 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, ); } -void textureUploadStrategy(std::vector &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) { +void textureUploadStrategy(const std::vector> &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) { + if (textures.empty()) return; + // ------------------------------------ - // 1. Transition ownage to upload queue + // 1. Transition ownership to upload queue // ------------------------------------ { @@ -84,12 +89,15 @@ void textureUploadStrategy(std::vector &textures, CmdBufRecorder &r // 2. Do copy of texture to GPU memory // ------------------------------------ - for ( auto &textureVlk : textures) { - auto updateRecord = textureVlk.getAndPlanDestroy(); + for ( auto &wtextureVlk : textures) { + if (wtextureVlk.expired()) continue; + auto textureVlk = wtextureVlk.lock(); + + auto updateRecord = textureVlk->getAndPlanDestroy(); uploadCmdBufRecorder.copyBufferToImage( updateRecord->stagingBuffer, - textureVlk.texture.image, + textureVlk->texture.image, updateRecord->bufferCopyRegions ); } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h index 82e743584..dec9bacaa 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -9,7 +9,9 @@ #include "../../textures/GTextureVLK.h" #include "CommandBufferRecorder.h" -void textureUploadStrategy(std::vector &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); +void textureUploadStrategy(const std::vector> &textures, + CmdBufRecorder &renderCmdBufRecorder, + CmdBufRecorder &uploadCmdBufRecorder); #endif //AWEBWOWVIEWERCPP_TEXTUREUPLOADHELPER_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index f591bf755..b62f79986 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -6,8 +6,11 @@ #include "../../../engine/persistance/helper/ChunkFileReader.h" #include "../../../engine/texture/DxtDecompress.h" -GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex) - : GTextureVLK(device,xWrapTex,yWrapTex), m_texture(texture) { +GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, + HBlpTexture texture, + bool xWrapTex, bool yWrapTex, + const std::function&)> &onUpdateCallback) + : GTextureVLK(device,xWrapTex,yWrapTex, onUpdateCallback), m_texture(texture) { } GBlpTextureVLK::~GBlpTextureVLK() { @@ -86,7 +89,6 @@ bool GBlpTextureVLK::postLoad() { } } - void GBlpTextureVLK::decompressAndUpload(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) { } \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index 6eacec2b9..63b94dea7 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -10,7 +10,7 @@ class GBlpTextureVLK : public GTextureVLK { public: - explicit GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex); + explicit GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback); ~GBlpTextureVLK() override; void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 9acbd53da..14e0d23be 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -6,7 +6,8 @@ #include "GTextureVLK.h" #include "../../interface/IDevice.h" -GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex) : m_device(device) { +GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) + : m_device(device), m_onDataUpdate(onUpdateCallback) { this->m_wrapX = xWrapTex; this->m_wrapY = yWrapTex; @@ -27,8 +28,6 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, m_width = width; m_height = height; - createBuffer(); - createVulkanImageObject( isDepthTexture, textureFormatGPU, @@ -43,8 +42,11 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, stagingBufferCreated = false; } -GTextureVLK::GTextureVLK(IDeviceVulkan &device, const VkImage &image, const VkImageView &imageView, bool dumbParam) : - m_device(device) { +GTextureVLK::GTextureVLK(IDeviceVulkan &device, + const VkImage &image, + const VkImageView &imageView, + bool dumbParam) : + m_device(device) { //This image is used as holder for framebuffer data (swapchain framebuffer one) texture.image = image; @@ -76,7 +78,12 @@ void GTextureVLK::destroyBuffer() { [l_device, l_texture, l_imageAllocation]() { vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); vkDestroySampler(l_device->getVkDevice(), l_texture.sampler, nullptr); - vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); + if (l_imageAllocation != nullptr) { + vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); + } else { + //This is swapchain image. Deleting swapchain image leads to exception +// vkDestroyImage(l_device->getVkDevice(), l_texture.image, nullptr); + } }); } @@ -93,7 +100,6 @@ bool GTextureVLK::getIsLoaded() { static int pureTexturesUploaded = 0; void GTextureVLK::loadData(int width, int height, void *data, ITextureFormat textureFormat) { -// std::cout << "pureTexturesUploaded = " << pureTexturesUploaded++ << std::endl; std::vector unifiedBuffer((uint8_t *)data, (uint8_t *)data + (width*height*4)); @@ -189,6 +195,8 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & stagingBufferCreated = true; + if (m_onDataUpdate) + m_onDataUpdate(this->weak_from_this()); } void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat textureFormatGPU, diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 9cc2051d6..53062268e 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -12,7 +12,7 @@ class GCommandBuffer; #include "../../interface/textures/ITexture.h" -class GTextureVLK : public ITexture { +class GTextureVLK : public ITexture, public std::enable_shared_from_this { friend class GFrameBufferVLK; public: //Used for rendering to texture in framebuffer @@ -31,7 +31,7 @@ class GTextureVLK : public ITexture { const VkImageView &imageView, bool dumbParam); - explicit GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex); + explicit GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback); void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, std::vector unitedBuffer); public: @@ -90,6 +90,8 @@ class GTextureVLK : public ITexture { VmaAllocation imageAllocation = VK_NULL_HANDLE; VmaAllocationInfo imageAllocationInfo = {}; + std::function&)> m_onDataUpdate = nullptr; + protected: IDeviceVulkan &m_device; diff --git a/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h b/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h new file mode 100644 index 000000000..336c86d92 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h @@ -0,0 +1,30 @@ +// +// Created by Deamon on 2/21/2023. +// + +#ifndef AWEBWOWVIEWERCPP_MUTEXLOCKEDVECTOR_H +#define AWEBWOWVIEWERCPP_MUTEXLOCKEDVECTOR_H + +#include +#include + +template +class MutexLockedVector { +public: + MutexLockedVector(std::vector &vec, std::mutex &m, bool clearOnDestroy) : m_vec(vec), m_lockGuard(std::lock_guard(m)), m_clearOnDestroy(clearOnDestroy) { + + } + ~MutexLockedVector() { + if (m_clearOnDestroy) + m_vec.clear(); + }; + const std::vector &get() const { + return m_vec; + } +private: + bool m_clearOnDestroy; + std::vector &m_vec; + std::lock_guard m_lockGuard; +}; + +#endif //AWEBWOWVIEWERCPP_MUTEXLOCKEDVECTOR_H From 34770bb751bdbfa0d675bcd39036a92ee45f9111 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 22 Feb 2023 01:22:38 +0200 Subject: [PATCH 035/212] Texture loading works stable, but the memory leaks --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- wowViewerLib/CMakeLists.txt | 2 +- .../src/gapi/interface/textures/ITexture.h | 10 +++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 36 +++--------- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 5 ++ .../src/gapi/vulkan/TextureManagerVLK.cpp | 18 ++++++ .../src/gapi/vulkan/TextureManagerVLK.h | 2 + .../src/gapi/vulkan/bindable/DSBindable.h | 56 +++++++++++++++++++ .../src/gapi/vulkan/buffers/GBufferVLK.h | 3 +- .../src/gapi/vulkan/buffers/IBufferVLK.h | 5 +- .../vulkan/descriptorSets/DescriptorRecord.h | 40 ++++++++++++- .../DescriptorResourceCallBack.h | 29 ++++++++++ .../descriptorSets/GDescriptorPoolVLK.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 39 +++++++------ .../vulkan/descriptorSets/GDescriptorSet.h | 23 ++++++-- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 10 ++-- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 13 +++-- .../src/gapi/vulkan/textures/GTextureVLK.h | 7 ++- 19 files changed, 232 insertions(+), 72 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 13557fd96..aed75d38e 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -73,7 +73,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate // ubos, // texturesVLK); - std::weak_ptr weakPtr(material); + std::weak_ptr weakPtr = material; m_materialCache[materialTemplate] = weakPtr; return material; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 5b6501b69..e514c19c0 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -506,7 +506,7 @@ if (LINK_VULKAN) src/gapi/vulkan/synchronization/GFenceVLK.cpp src/gapi/vulkan/synchronization/GFenceVLK.h src/renderer/vulkan/IRenderFunctionVLK.h - src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h src/gapi/vulkan/TextureManagerVLK.cpp src/gapi/vulkan/TextureManagerVLK.h src/gapi/vulkan/utils/MutexLockedVector.h) + src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h src/gapi/vulkan/TextureManagerVLK.cpp src/gapi/vulkan/TextureManagerVLK.h src/gapi/vulkan/utils/MutexLockedVector.h src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h src/gapi/vulkan/bindable/DSBindable.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/gapi/interface/textures/ITexture.h b/wowViewerLib/src/gapi/interface/textures/ITexture.h index b6eb3698c..7421bd3d0 100644 --- a/wowViewerLib/src/gapi/interface/textures/ITexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ITexture.h @@ -15,6 +15,12 @@ enum class ITextureFormat { itDepth32 }; +enum class TextureStatus { + TSNotLoaded, + TSHasUpdates, + TSLoaded +}; + class ITexture { public: virtual ~ITexture() {}; @@ -23,9 +29,7 @@ class ITexture { virtual void readData(std::vector &buff) = 0; virtual bool getIsLoaded() = 0; - virtual bool postLoad() = 0; - - + virtual TextureStatus postLoad() = 0; virtual void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 2e5893a2c..c52fa2266 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -713,8 +713,15 @@ void GDeviceVLK::drawFrame(const std::vector> & //Do Texture update { + m_textureManager->processBLPTextures(); auto textureVector = m_textureManager->getReadyToUploadTextures(); textureUploadStrategy(textureVector.get(), frameBufCmd, uploadCmd); + //The next loop updates DescriptorSets + for(auto &wtexture : textureVector.get()) { + if( auto texture = wtexture.lock()) { + texture->executeOnChange(); + } + } } { @@ -898,34 +905,7 @@ void GDeviceVLK::updateBuffers(std::vector &frameDepedantDa */ } -void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) { - //TODO: REWRITE THIS PART FFS!!! - - std::vector textures; - textures.reserve(meshes.size() * 3); - - int texturesLoaded = 0; - - for (const auto &hmesh : meshes) { - GMeshVLK * mesh = (GMeshVLK *) hmesh.get(); -// mesh->material()->updateImageDescriptorSet(); - -// for (int i = 0; i < mesh->textureCount(); i++) { -// textures.push_back(mesh->m_texture[i]); -// } - } - - - - std::sort(textures.begin(), textures.end()); - textures.erase( unique( textures.begin(), textures.end() ), textures.end() ); - - for (const auto &texture : textures) { - if (texture == nullptr) continue; - if (texture->postLoad()) texturesLoaded++; - if (texturesLoaded > 4) break; - } -} +void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) {} std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) { std::string combinedName = vertexName + " " + fragmentName; diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index b275153a5..781baebcb 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -9,6 +9,7 @@ #include "descriptorSets/GDescriptorSetLayout.h" #include "descriptorSets/GDescriptorPoolVLK.h" +#include "../interface/textures/ITexture.h" class IDeviceVulkan { public: virtual ~IDeviceVulkan() = default; @@ -21,11 +22,15 @@ class IDeviceVulkan { virtual VmaAllocator getVMAAllocator() = 0; virtual VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) = 0; + virtual std::shared_ptr getWhiteTexturePixel() = 0; + virtual std::shared_ptr getBlackTexturePixel() = 0; + //TODO: bool getIsAnisFiltrationSupported() {return true;}; //TODO: bool getIsCompressedTexturesSupported() {return true;}; virtual float getAnisLevel() = 0; + }; #endif //AWEBWOWVIEWERCPP_IDEVICEVULKAN_H diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index c3a62bbbe..12a67f54e 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -56,3 +56,21 @@ void TextureManagerVLK::createUpdateCallback() { } }; } + +void TextureManagerVLK::processBLPTextures() { + std::lock_guard lock(this->blpTextureLoadMutex); + + auto i = m_blpTextLoadQueue.begin(); + while (i != m_blpTextLoadQueue.end()) + { + if (auto texture = i->lock()) { + if (texture->postLoad() == TextureStatus::TSHasUpdates) { + m_blpTextLoadQueue.erase(i++); + } else { + i++; + } + } else { + m_blpTextLoadQueue.erase(i++); + } + } +} diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index dbea300fc..8a11308a7 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -24,6 +24,8 @@ class TextureManagerVLK : public std::enable_shared_from_this return MutexLockedVector>(m_texturesReadyToBeUploaded, textUpdateMutex, true); } + void processBLPTextures(); + protected: struct BlpCacheRecord { BlpTexture* texture; diff --git a/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h b/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h new file mode 100644 index 000000000..3597f36e8 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h @@ -0,0 +1,56 @@ +// +// Created by Deamon on 2/21/2023. +// + +#ifndef AWEBWOWVIEWERCPP_DSBINDABLE_H +#define AWEBWOWVIEWERCPP_DSBINDABLE_H + +#include +#include +#include + +class IDSBindable { +public: + IDSBindable(bool clearListOnExecution) : m_clearListExecution(clearListOnExecution){ + } + + std::unique_ptr>::const_iterator> addOnHandleChange(const std::function &callback) { + std::lock_guard lock(m_callbackMtx); + + m_onHandleChangeList.push_back(callback); + if (m_clearListExecution) { + return nullptr; + } else { + return std::make_unique>::const_iterator>( + std::prev(m_onHandleChangeList.end()) + ); + } + }; + + void eraseOnHandleChange(std::unique_ptr>::const_iterator> &iterator) { + std::lock_guard lock(m_callbackMtx); + + m_onHandleChangeList.erase(*iterator); + iterator = nullptr; + }; + + void executeOnChange() { + std::lock_guard lock(m_callbackMtx); + + for (auto &callBack : m_onHandleChangeList) { + callBack(); + } + + if (m_clearListExecution) { + m_onHandleChangeList.clear(); + } + } + +private: + bool m_clearListExecution; + + std::mutex m_callbackMtx; + std::list> m_onHandleChangeList; +}; + +#endif //AWEBWOWVIEWERCPP_DSBINDABLE_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 42195cb9c..a497c0e67 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -16,11 +16,12 @@ typedef std::shared_ptr HGBufferVLK; #include "../GDeviceVulkan.h" #include "IBufferVLK.h" #include "../utils/MutexLockedVector.h" +#include "../bindable/DSBindable.h" class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; public: - explicit GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize); + GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize); ~GBufferVLK() override; //Doesn't make actual upload, only queues it. diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h index f7fce3ae1..4028740e7 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h @@ -7,9 +7,12 @@ #include #include "../../interface/buffers/IBuffer.h" +#include "../bindable/DSBindable.h" -class IBufferVLK : public IBuffer { +class IBufferVLK : public IBuffer, public IDSBindable { public: + IBufferVLK() : IDSBindable(false) {}; + virtual VkBuffer getGPUBuffer() = 0; virtual size_t getOffset() = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h index 797a7821a..ea9701a24 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -6,17 +6,55 @@ #define AWEBWOWVIEWERCPP_DESCRIPTORRECORD_H #include +#include #include "../buffers/IBufferVLK.h" #include "../textures/GTextureVLK.h" -struct DescriptorRecord { + + +class DescriptorRecord { +public: enum class DescriptorRecordType { None, UBO, UBODynamic, Texture }; + DescriptorRecord() = delete; + + explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const std::shared_ptr &texture, const std::function &OnHandleChange) { + this->descType = DescriptorRecord::DescriptorRecordType::Texture; + this->textureVlk = texture; + + iteratorUnique = texture->addOnHandleChange(OnHandleChange); + } + explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const std::shared_ptr &buffer, const std::function &OnHandleChange) { + this->descType = descType; + this->buffer = buffer; + + iteratorUnique = buffer->addOnHandleChange(OnHandleChange); + } + + ~DescriptorRecord() { + if (iteratorUnique) { + if (buffer) { + buffer->eraseOnHandleChange(iteratorUnique); + } else if (textureVlk) { + textureVlk->eraseOnHandleChange(iteratorUnique); + } + } + } + + typedef std::list>::const_iterator RecordInter; + +public: DescriptorRecordType descType = DescriptorRecordType::None; + std::shared_ptr buffer = nullptr; std::shared_ptr textureVlk = nullptr; + +private: + //holds record inside buffer/textureVlk. And frees it on destruction + //It's safe to have this iterator here, cause class holds element with shared_ptr above ^ + std::unique_ptr iteratorUnique = nullptr; }; #endif //AWEBWOWVIEWERCPP_DESCRIPTORRECORD_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h new file mode 100644 index 000000000..484e05169 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h @@ -0,0 +1,29 @@ +// +// Created by Deamon on 2/21/2023. +// + +#ifndef AWEBWOWVIEWERCPP_DESCRIPTORRESOURCECALLBACK_H +#define AWEBWOWVIEWERCPP_DESCRIPTORRESOURCECALLBACK_H + +#include +#include +#include +#include "GDescriptorSet.h" + +class DescriptorResourceCallback { +public: + DescriptorResourceCallback() { + } + + ~DescriptorResourceCallback() { + if (m_onRelease) { + m_onRelease(m_iterator); + } + } +private: + std::list>::const_iterator m_iterator; + std::function>::const_iterator)> m_onRelease; +}; + + +#endif //AWEBWOWVIEWERCPP_DESCRIPTORRESOURCECALLBACK_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index f303de5ce..b857ff3ad 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -9,7 +9,7 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) { uniformsAvailable = 5*4096; imageAvailable = 4096 * 4; - setsAvailable = 4096; + setsAvailable = 4096 * 4; std::array poolSizes = {}; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 408d186fe..2a0c8050c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -65,15 +65,20 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptrtexture.view; - imageInfo.sampler = textureVlk->texture.sampler; + if (!textureVlk->getIsLoaded()) { + auto blackTexture = std::dynamic_pointer_cast(m_set.m_device->getBlackTexturePixel()); + imageInfo.imageView = blackTexture->texture.view; + imageInfo.sampler = blackTexture->texture.sampler; + } else { + imageInfo.imageView = textureVlk->texture.view; + imageInfo.sampler = textureVlk->texture.sampler; + } VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -101,8 +106,7 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt throw std::runtime_error("descriptor mismatch for UBO dynamic"); } - m_boundDescriptors[bindIndex].descType = DescriptorRecord::DescriptorRecordType::UBODynamic; - m_boundDescriptors[bindIndex].buffer = buffer; + assignBoundDescriptors(bindIndex, buffer, DescriptorRecord::DescriptorRecordType::UBODynamic); m_updateBindPoints[bindIndex] = true; VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); @@ -144,8 +148,7 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptrdescType == DescriptorRecord::DescriptorRecordType::UBO) { + ubo(bindPoint, m_boundDescriptors[bindPoint]->buffer); + } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBODynamic) { + ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint]->buffer); + } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::Texture) { + texture(bindPoint, m_boundDescriptors[bindPoint]->textureVlk); } } auto noSetBitSet = - m_set.getDescSetLayout()->getRequiredBindPoints() & m_updateBindPoints.flip(); + m_set.getDescSetLayout()->getRequiredBindPoints() & ~m_updateBindPoints; if (!noSetBitSet.none()) { std::string notSetBits; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 3802d96f6..56dc3c8f1 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -16,9 +16,10 @@ class GDescriptorPoolVLK; #include "../textures/GTextureVLK.h" #include "GDescriptorSetLayout.h" #include "DescriptorRecord.h" +#include "../bindable/DSBindable.h" -class GDescriptorSet { +class GDescriptorSet : std::enable_shared_from_this { public: explicit GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout); ~GDescriptorSet(); @@ -33,7 +34,7 @@ class GDescriptorSet { class SetUpdateHelper { public: - explicit SetUpdateHelper(GDescriptorSet &set, std::array &boundDescriptors) : + explicit SetUpdateHelper(GDescriptorSet &set, std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors) : m_set(set), m_boundDescriptors(boundDescriptors) {} ~SetUpdateHelper(); @@ -46,9 +47,23 @@ class GDescriptorSet { //TODO: add version of this array texture case (aka bindless) SetUpdateHelper& texture(int bindIndex, const std::shared_ptr &textureVlk); + template + void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, DescriptorRecord::DescriptorRecordType descType) { + static_assert(std::is_base_of::value, "T should inherit from B"); + + auto ds_weak = m_set.weak_from_this(); + + auto callback = ([ds_weak]() -> void { + if (auto ds = ds_weak.lock()) { + ds->update(); + } + }); + + m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); + } private: GDescriptorSet &m_set; - std::array &m_boundDescriptors; + std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &m_boundDescriptors; std::vector imageInfos; std::vector bufferInfos; @@ -68,7 +83,7 @@ class GDescriptorSet { bool m_firstUpdate = true; - std::array boundDescriptors; + std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> boundDescriptors; // Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea // //Defines amount of frames that the updates has to be copied from previous frame diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index b62f79986..0156c43c9 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -73,11 +73,11 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe GTextureVLK::createTexture(hmipmaps, textureFormatGPU, unitedBuffer); } -bool GBlpTextureVLK::postLoad() { - if (m_loaded) return false; +TextureStatus GBlpTextureVLK::postLoad() { + if (m_loaded) return TextureStatus::TSLoaded; if (!m_uploaded) { - if (m_texture == nullptr) return false; - if (m_texture->getStatus() != FileStatus::FSLoaded) return false; + if (m_texture == nullptr) return TextureStatus::TSNotLoaded; + if (m_texture->getStatus() != FileStatus::FSLoaded) return TextureStatus::TSNotLoaded; } if (m_uploaded) { @@ -85,7 +85,7 @@ bool GBlpTextureVLK::postLoad() { } else { this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); // m_texture = nullptr; - return false; + return TextureStatus::TSHasUpdates; } } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index 63b94dea7..4021b9469 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -14,7 +14,7 @@ class GBlpTextureVLK : public GTextureVLK { ~GBlpTextureVLK() override; void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; - bool postLoad() override; + TextureStatus postLoad() override; private: void decompressAndUpload(TextureFormat textureFormat, const HMipmapsVector &hmipmaps); private: diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 14e0d23be..1fb5667ce 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -7,7 +7,7 @@ #include "../../interface/IDevice.h" GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) - : m_device(device), m_onDataUpdate(onUpdateCallback) { + : m_device(device), m_onDataUpdate(onUpdateCallback), IDSBindable(true) { this->m_wrapX = xWrapTex; this->m_wrapY = yWrapTex; @@ -19,7 +19,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool isDepthTexture, const VkFormat textureFormatGPU, VkSampleCountFlagBits numSamples, - int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device) { + int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device), IDSBindable(true) { //For use in frameBuffer this->m_wrapX = xWrapTex; @@ -46,7 +46,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, const VkImage &image, const VkImageView &imageView, bool dumbParam) : - m_device(device) { + m_device(device), IDSBindable(true) { //This image is used as holder for framebuffer data (swapchain framebuffer one) texture.image = image; @@ -295,13 +295,14 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te ERR_GUARD_VULKAN(vkCreateImageView(m_device.getVkDevice(), &view, nullptr, &texture.view)); } -bool GTextureVLK::postLoad() { - if (m_loaded) return false; +TextureStatus GTextureVLK::postLoad() { + if (m_loaded) return TextureStatus::TSLoaded; if (m_uploaded) { m_loaded = true; + return TextureStatus::TSLoaded; } - return false; + return TextureStatus::TSNotLoaded; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 53062268e..bec08d990 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -10,9 +10,10 @@ class GCommandBuffer; #include "../IDeviceVulkan.h" #include "../../interface/textures/ITexture.h" +#include "../bindable/DSBindable.h" -class GTextureVLK : public ITexture, public std::enable_shared_from_this { +class GTextureVLK : public ITexture, public std::enable_shared_from_this, public IDSBindable { friend class GFrameBufferVLK; public: //Used for rendering to texture in framebuffer @@ -61,10 +62,12 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this Date: Wed, 22 Feb 2023 12:22:36 +0200 Subject: [PATCH 036/212] No more memory leaks. The application is closable --- src/ui/renderer/uiScene/ImGUIPlan.h | 1 + wowViewerLib/CMakeLists.txt | 27 +- .../shaders/src/spirv/dumpShaderFields.h | 1 + .../src/engine/shader/ShaderDefinitions.h | 966 +++++++++--------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 7 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 6 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 13 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 2 +- .../vulkan/commandBuffer/CommandBuffer.cpp | 2 + .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 6 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 8 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 2 +- .../src/renderer/frame/SceneComposer.cpp | 8 +- .../src/renderer/frame/SceneComposer.h | 4 + 14 files changed, 552 insertions(+), 501 deletions(-) diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index 8c1d3621b..0ec7796e1 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -30,6 +30,7 @@ namespace ImGuiFramePlan { ~ImGUIParam() { if (m_imData.CmdLists != nullptr) { for (int i = 0; i < m_imData.CmdListsCount; i++) { + m_imData.CmdLists[i]->ClearFreeMemory(); IM_FREE(m_imData.CmdLists[i]); } delete m_imData.CmdLists; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index e514c19c0..30e337b2c 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -582,6 +582,13 @@ if (NOT MSVC) endif() endif() endif() + + + +add_library(WoWViewerLib STATIC ${SOURCE_FILES} ${OPENGL20_IMPLEMENTATION} ${OPENGL33_IMPLEMENTATION} ${OPENGL4x_IMPLEMENTATION} ${VULKAN_IMPLEMENTATION}) +if (NOT MSVC) + target_compile_options(WoWViewerLib PUBLIC -Werror=return-type) +endif() if (MSVC) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("/std:c++17" _cpp_17_flag_supported) @@ -589,18 +596,13 @@ if (MSVC) if (_cpp_17_flag_supported) message("/std:c++17 is supported") #target_compile_options(AWebWoWViewerCpp "/std:c++17") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /std:c++17") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /std:c++17") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /std:c++latest") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /std:c++latest") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /std:c++17") - #target_compile_options(AWebWoWViewerCpp /std:c++17) + target_compile_options(WoWViewerLib PRIVATE "/std:c++latest") endif() endif() - -add_library(WoWViewerLib STATIC ${SOURCE_FILES} ${OPENGL20_IMPLEMENTATION} ${OPENGL33_IMPLEMENTATION} ${OPENGL4x_IMPLEMENTATION} ${VULKAN_IMPLEMENTATION}) -if (NOT MSVC) - target_compile_options(WoWViewerLib PUBLIC -Werror=return-type) -endif() if (LINK_VULKAN) target_compile_definitions(WoWViewerLib PUBLIC ${VOLK_STATIC_DEFINES}) endif() @@ -608,8 +610,13 @@ endif() foreach(X IN LISTS My_Vectorize_Compile_Options) target_compile_options(WoWViewerLib PRIVATE ${X}) endforeach() -target_compile_features(WoWViewerLib PRIVATE cxx_std_17) -set_property(TARGET WoWViewerLib PROPERTY CXX_STANDARD 17) +if (NOT MSVC) + target_compile_features(WoWViewerLib PRIVATE cxx_std_17) + set_property(TARGET WoWViewerLib PROPERTY CXX_STANDARD 17) +else() + target_compile_features(WoWViewerLib PRIVATE cxx_std_20) +# set_property(TARGET WoWViewerLib PROPERTY CXX_STANDARD 17) +endif() if (LINK_OPENMP) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index 7e8448539..88b60df6f 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -7,6 +7,7 @@ #include #include +#include #include #include "fileHelpers.h" #include "webGLSLCompiler.h" diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index de002d162..1290ab289 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -195,9 +195,41 @@ const std::unordered_map> attributesPe { "aIndex", 4}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -215,19 +247,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -235,7 +264,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -245,16 +274,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "aColorSecond", 8}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,17 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, - {0,3,32}, + {0,1,112}, }, { { - {3,3,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -347,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -371,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -391,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -407,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -427,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -446,11 +430,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,17 +499,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,32}, {0,0,368}, + {0,3,32}, }, { { - {0,0,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -535,12 +520,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {8,8,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -551,16 +544,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -586,15 +578,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -605,10 +597,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -620,15 +613,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,4,288}, + {0,3,16}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -639,13 +634,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, - }, - { - { - {0,0,0}, - {5,6,2}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, + }, + { + { + {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -656,17 +658,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,288}, - {0,3,16}, {0,0,368}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,20 +678,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -701,16 +693,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -736,14 +727,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -769,15 +761,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -788,11 +780,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -804,15 +795,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -838,15 +830,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -872,15 +864,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -906,14 +898,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,2,16}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -939,14 +932,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -957,11 +951,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -972,15 +967,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1006,15 +1000,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1025,11 +1019,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,15 +1036,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,4,64}, + {0,3,256}, + {0,0,368}, + {0,1,14144}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1059,12 +1058,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {5,8,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1109,15 +1111,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,1,14144}, {0,0,368}, + {0,2,160}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1143,15 +1147,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1177,15 +1181,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,16}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1196,11 +1201,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1211,18 +1217,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,4,64}, - {0,3,256}, + {0,4,48}, {0,0,368}, - {0,1,14144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,12 +1240,11 @@ const std::unordered_map shaderMetaInfo = { {1,5, "uTexture"}, {1,6, "uTexture2"}, {1,7, "uTexture3"}, - {1,8, "uTexture4"}, }, { { {0,0,0}, - {5,8,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1287,11 +1290,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -1321,15 +1324,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1340,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1355,16 +1360,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,2,96}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1390,15 +1393,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1409,12 +1413,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, + {1,5, "uTexture"}, }, { { - {3,3,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,14 +1429,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1458,16 +1463,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, {0,0,368}, + {0,2,96}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1478,14 +1483,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1496,17 +1498,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,14144}, + {0,4,96}, {0,0,368}, - {0,2,160}, + {0,1,14144}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1517,11 +1519,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1532,11 +1538,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -1552,12 +1559,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1571,51 +1578,23 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { { 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - { - 2, { - {"_0_2_bumpScale", true, 0, 1, 4, 0}, - {"_0_2_uTextMat[0]", true, 16, 4, 4, 2}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, - }}, - {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1638,7 +1617,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1919,13 +1901,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -1941,23 +1937,28 @@ const std::unordered_mapgetRequiredExtensions(extensions, extensionCnt); - std::vector extensionsVec(extensions, extensions+extensionCnt); + std::vector extensionsVec(extensions, extensions+extensionCnt); if (enableValidationLayers) { extensionsVec.push_back("VK_EXT_debug_report"); extensionsVec.push_back("VK_EXT_debug_utils"); @@ -1128,10 +1128,9 @@ HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, } } - std::shared_ptr hgPipeline; - hgPipeline.reset(new GPipelineVLK(*this, m_bindings, renderPass, + std::shared_ptr hgPipeline = std::make_shared(*this, m_bindings, renderPass, shader, element, backFaceCulling, triCCW, blendMode, - depthCulling, depthWrite, invertZ)); + depthCulling, depthWrite, invertZ); std::weak_ptr weakPtr(hgPipeline); loadedPipeLines[pipelineCacheRecord] = weakPtr; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index 038c49dde..e627e8d47 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -73,7 +73,13 @@ GPipelineVLK::GPipelineVLK(IDevice &device, } GPipelineVLK::~GPipelineVLK() { + auto l_deviceVlk = m_device.getVkDevice(); + auto l_pipelineVlk = graphicsPipeline; + m_device.addDeallocationRecord( + [l_deviceVlk, l_pipelineVlk]() { + vkDestroyPipeline(l_deviceVlk, l_pipelineVlk, nullptr); + }); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 68b0a7e70..650e95237 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -116,7 +116,8 @@ void GBufferVLK::resize(int newLength) { subBuffer->m_size ); - vmaVirtualFree(currentBuffer.virtualBlock, subBuffer->m_alloc); + deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); + subBuffer->m_offset = offset; subBuffer->m_alloc = alloc; @@ -150,11 +151,9 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy } } -void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it) { - if(auto subBuffer = it->lock()) { - deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - } - +void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &m_alloc) { + deallocateSubBuffer(currentBuffer, m_alloc); + currentSubBuffers.erase(it); } @@ -186,7 +185,7 @@ GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, } GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { - m_parentBuffer->deleteSubBuffer(m_iterator); + m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc); } void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index a497c0e67..2f71bc515 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -105,7 +105,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubBuffer(int sizeInBytes); - void deleteSubBuffer(std::list>::const_iterator &it); + void deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &m_alloc); private: void createBuffer(BufferInternal &buffer); void destroyBuffer(BufferInternal &buffer); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index 9a59847d4..c23df65d2 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -47,4 +47,6 @@ void GCommandBuffer::createCommandBufVLK() { if (vkAllocateCommandBuffers(m_device.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { throw std::runtime_error("failed to allocate command buffers!"); } + + m_cmdBufWasCreated = true; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 0156c43c9..f5e7ecdeb 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -78,14 +78,12 @@ TextureStatus GBlpTextureVLK::postLoad() { if (!m_uploaded) { if (m_texture == nullptr) return TextureStatus::TSNotLoaded; if (m_texture->getStatus() != FileStatus::FSLoaded) return TextureStatus::TSNotLoaded; - } - if (m_uploaded) { - return GTextureVLK::postLoad(); - } else { this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); // m_texture = nullptr; return TextureStatus::TSHasUpdates; + } else { + return GTextureVLK::postLoad(); } } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 1fb5667ce..352ecff82 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -7,7 +7,7 @@ #include "../../interface/IDevice.h" GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) - : m_device(device), m_onDataUpdate(onUpdateCallback), IDSBindable(true) { + : m_device(device), m_onDataUpdate(onUpdateCallback), IDSBindable(false) { this->m_wrapX = xWrapTex; this->m_wrapY = yWrapTex; @@ -19,7 +19,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool isDepthTexture, const VkFormat textureFormatGPU, VkSampleCountFlagBits numSamples, - int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device), IDSBindable(true) { + int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device), IDSBindable(false) { //For use in frameBuffer this->m_wrapX = xWrapTex; @@ -46,7 +46,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, const VkImage &image, const VkImageView &imageView, bool dumbParam) : - m_device(device), IDSBindable(true) { + m_device(device), IDSBindable(false) { //This image is used as holder for framebuffer data (swapchain framebuffer one) texture.image = image; @@ -115,7 +115,7 @@ void GTextureVLK::loadData(int width, int height, void *data, ITextureFormat tex createTexture(mipmapsVector, VK_FORMAT_R8G8B8A8_UNORM, unifiedBuffer); } -void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat &textureFormatGPU, std::vector unitedBuffer) {// Copy data to an optimal tiled image +void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat &textureFormatGPU, const std::vector &unitedBuffer) {// Copy data to an optimal tiled image if (m_uploaded) { std::cout << "oops!" << std::endl << std::flush; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index bec08d990..f2fe967d7 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -34,7 +34,7 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); - void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, std::vector unitedBuffer); + void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, const std::vector &unitedBuffer); public: ~GTextureVLK() override; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 40e4992bc..e66aaccb5 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -36,7 +36,13 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon while (!this->m_isTerminating) { std::unique_lock lock{cullingQueueMutex}; auto &l_cullingQueue = m_cullingQueue; - cullingCondVar.wait(lock, [&l_cullingQueue]() { return !l_cullingQueue.empty(); }); + auto &l_terminated = this->m_isTerminating; + cullingCondVar.wait(lock, [&l_cullingQueue, &l_terminated]() { + return !l_cullingQueue.empty() || l_terminated; + }); + + if (l_terminated) + continue; auto frameScenario = m_cullingQueue.front(); m_cullingQueue.pop(); diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 493c1a48b..5e864f145 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -52,6 +52,10 @@ class SceneComposer { ~SceneComposer() { m_isTerminating = true; + { + std::lock_guard l{ cullingQueueMutex }; + cullingCondVar.notify_one(); + } cullingThread.join(); loadingResourcesThread.join(); } From 48bdc1900a1a2bd0541bebab51e00ead4489b21a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 23 Feb 2023 05:52:50 +0200 Subject: [PATCH 037/212] many fixes. vulkan validation is fixed. eliminated QOTF (queue ownership transfer) --- src/ui/FrontendUI.cpp | 17 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 15 +- .../vulkan/FrontendUIRenderForwardVLK.h | 1 + .../src/engine/shader/ShaderDefinitions.h | 952 +++++++++--------- wowViewerLib/src/engine/texture/BlpTexture.h | 3 +- wowViewerLib/src/gapi/interface/IDevice.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 88 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 20 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 13 + .../src/gapi/vulkan/bindable/DSBindable.h | 1 + .../TextureUploadHelper.cpp | 91 +- .../vulkan/descriptorSets/DescriptorRecord.h | 4 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 6 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 1 + .../src/gapi/vulkan/textures/GTextureVLK.cpp | 11 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 14 +- 17 files changed, 649 insertions(+), 591 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 36f7fa62d..b7421f853 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1333,13 +1333,16 @@ bool FrontendUI::fillAdtSelectionminimap(std::array, 6 isWMOMap = m_wdtFile->mphd->flags.wdt_uses_global_map_obj != 0; - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - if (m_wdtFile->mapFileDataIDs[i*64 + j].minimapTexture > 0) { - auto texture = m_api->cacheStorage->getTextureCache()->getFileId(m_wdtFile->mapFileDataIDs[i*64 + j].minimapTexture); - minimap[i][j] = m_api->hDevice->createBlpTexture(texture, false, false); - } else { - minimap[i][j] = nullptr; + if (!isWMOMap) { + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + if (m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture > 0) { + auto texture = m_api->cacheStorage->getTextureCache()->getFileId( + m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture); + minimap[i][j] = m_api->hDevice->createBlpTexture(texture, false, false); + } else { + minimap[i][j] = nullptr; + } } } } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index aed75d38e..cba244d0d 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -19,8 +19,8 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic } void FrontendUIRenderForwardVLK::createBuffers() { - vboBuffer = m_device->createIndexBuffer(1024*1024); - iboBuffer = m_device->createVertexBuffer(1024*1024); + iboBuffer = m_device->createIndexBuffer(1024*1024); + vboBuffer = m_device->createVertexBuffer(1024*1024); uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_imguiUbo = std::make_shared>(uboBuffer); @@ -88,12 +88,17 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { - auto meshes = std::make_unique>(); + auto meshes = std::make_shared>(); this->consumeFrameInput(frameInputParams, *meshes); + { + //Prevents material from being created over and over again + m_previousMeshes = meshes; + } + //Record commands to update buffer and draw auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); - return createRenderFuncVLK(std::move([meshes = std::move(meshes), l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) { + return createRenderFuncVLK(std::move([meshes, l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) { // --------------------- // Upload stuff // --------------------- @@ -141,4 +146,6 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } })); + + } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 362681017..7984ab8ae 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -45,6 +45,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { void createBuffers(); std::shared_ptr m_lastRenderPass; + std::shared_ptr> m_previousMeshes = nullptr; }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 1290ab289..de002d162 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -195,41 +195,9 @@ const std::unordered_map> attributesPe { "aIndex", 4}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -247,16 +215,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -264,7 +235,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -274,6 +245,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "aColorSecond", 8}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, + {0,3,32}, }, { { - {1,1,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +347,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +371,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,16}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +391,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +407,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,4,96}, + {0,0,368}, }, { { @@ -413,13 +427,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,11 +446,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,17 +514,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,2,144}, + {0,1,14144}, {0,0,368}, - {0,3,32}, }, { { - {3,3,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -520,20 +535,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -544,15 +551,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -578,15 +586,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -597,11 +605,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -613,17 +620,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,4,288}, - {0,3,16}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -634,20 +639,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,16 +656,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,288}, + {0,3,16}, {0,0,368}, - {0,2,16}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -678,11 +677,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -693,15 +701,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -727,15 +736,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -761,15 +769,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -780,10 +788,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,16 +804,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -830,15 +838,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,1,12}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -864,15 +872,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -898,15 +906,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -932,15 +939,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -951,12 +957,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -967,14 +972,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,4,16}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1000,15 +1006,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1019,13 +1025,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1036,18 +1040,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,4,64}, - {0,3,256}, - {0,0,368}, - {0,1,14144}, + {0,4,32}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1058,15 +1059,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {5,8,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1111,17 +1109,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,1,14144}, {0,0,368}, - {0,2,160}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1147,15 +1143,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1181,16 +1177,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1201,12 +1196,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,16 +1211,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, + {0,4,64}, + {0,3,256}, {0,0,368}, + {0,1,14144}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1240,11 +1236,12 @@ const std::unordered_map shaderMetaInfo = { {1,5, "uTexture"}, {1,6, "uTexture2"}, {1,7, "uTexture3"}, + {1,8, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {5,8,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1290,11 +1287,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -1324,15 +1321,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1340,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1360,14 +1355,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,2,96}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1393,16 +1390,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1413,12 +1409,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, }, { { + {3,3,1}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1429,15 +1425,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1463,16 +1458,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,48}, {0,0,368}, - {0,2,96}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1483,11 +1478,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1498,17 +1496,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, {0,1,14144}, + {0,0,368}, + {0,2,160}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1519,15 +1517,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, }, { { {0,0,0}, - {5,9,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1538,12 +1532,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,48}, {0,0,368}, }, { @@ -1559,12 +1552,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {8,8,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1578,23 +1571,7 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1616,11 +1593,23 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"waterfallShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_0_4_values0", true, 0, 1, 4, 0}, + {"_0_4_values1", true, 16, 1, 4, 0}, + {"_0_4_values2", true, 32, 1, 4, 0}, + {"_0_4_values3", true, 48, 1, 4, 0}, + {"_0_4_values4", true, 64, 1, 4, 0}, + {"_0_4_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1937,28 +1941,23 @@ const std::unordered_map texture; int32_t width; int32_t height; diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index d3c6cc034..b93a6770c 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -41,6 +41,7 @@ typedef std::shared_ptr HGM2Mesh; typedef std::shared_ptr HGParticleMesh; typedef std::shared_ptr HGOcclusionQuery; typedef std::shared_ptr HGTexture; +typedef std::weak_ptr WGTexture; typedef std::shared_ptr HGPUFence; typedef std::shared_ptr HFrameBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 8b0fff902..64a48abae 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -38,8 +38,13 @@ const std::vector deviceExtensions = { }; static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + std::cerr << "error "; + std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl << std::flush; + + return VK_FALSE; } @@ -237,6 +242,8 @@ void GDeviceVLK::initialize() { pickPhysicalDevice(); createLogicalDevice(); + + findQueueFamilies(physicalDevice); //--------------- //Init AMD's VMA VmaVulkanFunctions vma_vulkan_func{}; @@ -292,11 +299,68 @@ void GDeviceVLK::initialize() { } +std::vector VkFormatFeatureFlagBitsGetStrings(VkFormatFeatureFlags value) { + std::vector strings; + if (value == 0) { strings.push_back("None"); return strings; } + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_BIT"); + if (VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT & value) strings.push_back("FORMAT_FEATURE_STORAGE_IMAGE_BIT"); + if (VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT & value) strings.push_back("FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"); + if (VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT & value) strings.push_back("FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"); + if (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT & value) strings.push_back("FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"); + if (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT & value) strings.push_back("FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"); + if (VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT & value) strings.push_back("FORMAT_FEATURE_VERTEX_BUFFER_BIT"); + if (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT & value) strings.push_back("FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"); + if (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & value) strings.push_back("FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"); + if (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & value) strings.push_back("FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"); + if (VK_FORMAT_FEATURE_BLIT_SRC_BIT & value) strings.push_back("FORMAT_FEATURE_BLIT_SRC_BIT"); + if (VK_FORMAT_FEATURE_BLIT_DST_BIT & value) strings.push_back("FORMAT_FEATURE_BLIT_DST_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"); + if (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & value) strings.push_back("FORMAT_FEATURE_TRANSFER_SRC_BIT"); + if (VK_FORMAT_FEATURE_TRANSFER_DST_BIT & value) strings.push_back("FORMAT_FEATURE_TRANSFER_DST_BIT"); + if (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT & value) strings.push_back("FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"); + if (VK_FORMAT_FEATURE_DISJOINT_BIT & value) strings.push_back("FORMAT_FEATURE_DISJOINT_BIT"); + if (VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT & value) strings.push_back("FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT"); + if (VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR & value) strings.push_back("FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR"); + if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT & value) strings.push_back("FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT"); + if (VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT & value) strings.push_back("FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT"); + if (VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR & value) strings.push_back("FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"); + return strings; +} + void GDeviceVLK::createSwapChainAndFramebuffer() { SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); + VkFormatProperties swapChainFormatProps; + vkGetPhysicalDeviceFormatProperties(physicalDevice, surfaceFormat.format, &swapChainFormatProps); + + //auto linearTilingFeatures = VkFormatFeatureFlagBitsGetStrings(swapChainFormatProps.linearTilingFeatures); + //auto optimalTilingFeatures = VkFormatFeatureFlagBitsGetStrings(swapChainFormatProps.optimalTilingFeatures); + + //std::cout << "linear tiling features = "; + //for (auto feature : linearTilingFeatures) std::cout << feature << " "; + //std::cout << std::endl; + + //std::cout << "optimal tiling features = "; + //for (auto feature : optimalTilingFeatures) std::cout << feature << " "; + //std::cout << std::endl; + + //VkImageFormatProperties imageFormatProperties; + //ERR_GUARD_VULKAN(vkGetPhysicalDeviceImageFormatProperties(physicalDevice, + // surfaceFormat.format, + // VK_IMAGE_TYPE_2D, + // VK_IMAGE_TILING_OPTIMAL, + // VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + // 0, + // &imageFormatProperties)); + + createSwapChain(swapChainSupport, surfaceFormat, extent); uint32_t imageCount; @@ -364,7 +428,6 @@ void GDeviceVLK::createSwapChain(SwapChainSupportDetails &swapChainSupport, VkSu createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - indices = findQueueFamilies(physicalDevice); uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()}; // if (indices.graphicsFamily != indices.presentFamily) { @@ -486,8 +549,6 @@ void GDeviceVLK::pickPhysicalDevice() { void GDeviceVLK::createLogicalDevice() { - QueueFamilyIndices indices = findQueueFamilies(physicalDevice); - std::vector queueCreateInfos; std::set uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value(), indices.transferFamily.value()}; @@ -534,14 +595,11 @@ void GDeviceVLK::createLogicalDevice() { } bool GDeviceVLK::isDeviceSuitable(VkPhysicalDevice device) { - QueueFamilyIndices indices = findQueueFamilies(device); - + findQueueFamilies(device); return indices.isComplete(); } -GDeviceVLK::QueueFamilyIndices GDeviceVLK::findQueueFamilies(VkPhysicalDevice device) { - QueueFamilyIndices indices; - +void GDeviceVLK::findQueueFamilies(VkPhysicalDevice device) { uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); @@ -578,18 +636,14 @@ GDeviceVLK::QueueFamilyIndices GDeviceVLK::findQueueFamilies(VkPhysicalDevice de if (dedicatedTransferQueue > -1) { indices.transferFamily = dedicatedTransferQueue; } - - return indices; } void GDeviceVLK::createCommandPool() { - QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); - VkCommandPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.pNext = NULL; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); + poolInfo.queueFamilyIndex = indices.graphicsFamily.value(); if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); @@ -600,13 +654,11 @@ void GDeviceVLK::createCommandPool() { } } void GDeviceVLK::createCommandPoolForUpload(){ - QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); - VkCommandPoolCreateInfo renderPoolInfo = {}; renderPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; renderPoolInfo.pNext = NULL; renderPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - renderPoolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); + renderPoolInfo.queueFamilyIndex = indices.graphicsFamily.value(); if (vkCreateCommandPool(device, &renderPoolInfo, nullptr, &renderCommandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create render command pool!"); @@ -616,7 +668,7 @@ void GDeviceVLK::createCommandPoolForUpload(){ uploadPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; uploadPoolInfo.pNext = NULL; uploadPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - uploadPoolInfo.queueFamilyIndex = queueFamilyIndices.transferFamily.value(); + uploadPoolInfo.queueFamilyIndex = indices.transferFamily.value(); if (vkCreateCommandPool(device, &uploadPoolInfo, nullptr, &uploadCommandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); @@ -626,7 +678,7 @@ void GDeviceVLK::createCommandPoolForUpload(){ poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.pNext = NULL; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); + poolInfo.queueFamilyIndex = indices.graphicsFamily.value(); if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPoolForImageTransfer) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 8d434685b..3d7577466 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -48,16 +48,6 @@ class gMeshTemplate; VkSampleCountFlagBits sampleCountToVkSampleCountFlagBits(uint8_t sampleCount); class GDeviceVLK : public IDevice, public std::enable_shared_from_this, public IDeviceVulkan { - struct QueueFamilyIndices { - std::optional graphicsFamily; - std::optional presentFamily; - std::optional transferFamily; - - bool isComplete() { - return graphicsFamily.has_value() && presentFamily.has_value(); - } - }; - struct SwapChainSupportDetails { VkSurfaceCapabilitiesKHR capabilities; std::vector formats; @@ -99,6 +89,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thiswaitInDrawStageAndDeps.getTimePerFrame(); @@ -175,10 +169,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback; @@ -204,7 +194,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this +#include #include "descriptorSets/GDescriptorSetLayout.h" #include "descriptorSets/GDescriptorPoolVLK.h" #include "../interface/textures/ITexture.h" +struct QueueFamilyIndices { + std::optional graphicsFamily; + std::optional presentFamily; + std::optional transferFamily; + + bool isComplete() { + return graphicsFamily.has_value() && presentFamily.has_value(); + } +}; + class IDeviceVulkan { public: virtual ~IDeviceVulkan() = default; @@ -31,6 +42,8 @@ class IDeviceVulkan { bool getIsCompressedTexturesSupported() {return true;}; virtual float getAnisLevel() = 0; + virtual const QueueFamilyIndices &getQueueFamilyIndices() = 0; + }; #endif //AWEBWOWVIEWERCPP_IDEVICEVULKAN_H diff --git a/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h b/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h index 3597f36e8..76e038cd8 100644 --- a/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h +++ b/wowViewerLib/src/gapi/vulkan/bindable/DSBindable.h @@ -13,6 +13,7 @@ class IDSBindable { public: IDSBindable(bool clearListOnExecution) : m_clearListExecution(clearListOnExecution){ } + virtual ~IDSBindable() {}; std::unique_ptr>::const_iterator> addOnHandleChange(const std::function &callback) { std::lock_guard lock(m_callbackMtx); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index 714dd8fbb..b0c51563e 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -77,11 +77,12 @@ void textureUploadStrategy(const std::vector> &textur .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcStageMask = VK_PIPELINE_STAGE_HOST_BIT, .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT }; +// transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); } @@ -101,31 +102,31 @@ void textureUploadStrategy(const std::vector> &textur updateRecord->bufferCopyRegions ); } - - // -------------------------------------------------------- - // 3. Transition ownership from upload queue to render queue - // -------------------------------------------------------- - { - if (uploadCmdBufRecorder.getQueueFamily() == renderCmdBufRecorder.getQueueFamily()) { - TransitionParams transitionParams = { - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), - .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), - .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, - .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT - }; - - transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); - } else { +// +// // -------------------------------------------------------- +// // 3. Transition ownership from upload queue to render queue +// // -------------------------------------------------------- +// { +// if (uploadCmdBufRecorder.getQueueFamily() == renderCmdBufRecorder.getQueueFamily()) { +// TransitionParams transitionParams = { +// .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, +// .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, +// .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, +// .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, +// .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), +// .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), +// .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, +// .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT +// }; +// +// transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); +// } else { //Change access mask TransitionParams transitionParams = { .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = 0, .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -133,37 +134,37 @@ void textureUploadStrategy(const std::vector> &textur }; transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); - } - - //Change ownership - { - TransitionParams transitionParams = { - .srcAccessMask = 0, - .dstAccessMask = 0, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), - .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), - .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, - .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT - }; - - transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); - transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); - } +// } +// +// //Change ownership +// { +// TransitionParams transitionParams = { +// .srcAccessMask = 0, +// .dstAccessMask = 0, +// .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, +// .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, +// .srcQueueFamilyIndex = uploadCmdBufRecorder.getQueueFamily(), +// .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), +// .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, +// .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT +// }; +// +// transitionLayoutAndOwnageTextures(uploadCmdBufRecorder, textures, transitionParams); +// transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); +// } - { + /* { TransitionParams transitionParams = { .srcAccessMask = 0, .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .srcQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), + .dstQueueFamilyIndex = renderCmdBufRecorder.getQueueFamily(), .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, .dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT }; transitionLayoutAndOwnageTextures(renderCmdBufRecorder, textures, transitionParams); - } - } + }*/ + //} } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h index ea9701a24..73fd8dbec 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -24,7 +24,9 @@ class DescriptorRecord { this->descType = DescriptorRecord::DescriptorRecordType::Texture; this->textureVlk = texture; - iteratorUnique = texture->addOnHandleChange(OnHandleChange); + if (texture != nullptr) { + iteratorUnique = texture->addOnHandleChange(OnHandleChange); + } } explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const std::shared_ptr &buffer, const std::function &OnHandleChange) { this->descType = descType; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 2a0c8050c..26b856c87 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -65,13 +65,15 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptrgetIsLoaded()) { + if (textureVlk == nullptr || !textureVlk->getIsLoaded()) { auto blackTexture = std::dynamic_pointer_cast(m_set.m_device->getBlackTexturePixel()); imageInfo.imageView = blackTexture->texture.view; imageInfo.sampler = blackTexture->texture.sampler; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index f5e7ecdeb..3bb72df95 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -14,7 +14,7 @@ GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, } GBlpTextureVLK::~GBlpTextureVLK() { -// std::cout << "error!" << std::endl; + std::cout << "destroyed blp text!" << std::endl; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index 4021b9469..c9f3a44d4 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -17,6 +17,7 @@ class GBlpTextureVLK : public GTextureVLK { TextureStatus postLoad() override; private: void decompressAndUpload(TextureFormat textureFormat, const HMipmapsVector &hmipmaps); + void freeMipmaps() override {m_texture = nullptr;}; private: HBlpTexture m_texture; }; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 352ecff82..82e75229d 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -218,14 +218,17 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = numSamples; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; + // Set initial layout of the image to undefined imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.extent = {static_cast(m_width), static_cast(m_height), 1}; imageCreateInfo.usage = imageUsageFlags; - // imageCreateInfo.queueFamilyIndexCount = 2; - // std::array families = {indicies.graphicsFamily.value(), indicies.transferFamily.value()}; - // imageCreateInfo.pQueueFamilyIndices = &families[0]; + + imageCreateInfo.queueFamilyIndexCount = 2; + auto &indicies = m_device.getQueueFamilyIndices(); + std::array families = {indicies.graphicsFamily.value(), indicies.transferFamily.value()}; + imageCreateInfo.pQueueFamilyIndices = families.data(); VmaAllocationCreateInfo allocImageCreateInfo = {}; allocImageCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index f2fe967d7..24007b6a4 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -55,10 +55,17 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_thisstagingBuffer; auto &l_stagingBufferAlloc = m_tempUpdateData->stagingBufferAlloc; - m_device.addDeallocationRecord([l_tempUpdateData, l_device, l_stagingBuffer, l_stagingBufferAlloc]() { + auto w_this = weak_from_this(); + + m_device.addDeallocationRecord([w_this, l_device, l_stagingBuffer, l_stagingBufferAlloc]() { vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingBuffer, l_stagingBufferAlloc); - delete l_tempUpdateData; + if (auto texture = w_this.lock()) { + delete texture->m_tempUpdateData; + texture->m_tempUpdateData = nullptr; + + } + }); m_tempUpdateData = nullptr; @@ -80,7 +87,6 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this HGTextureVLK; From 1f2291c87c22d1c3f62d370f3d95f4a3e860fa1d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 23 Feb 2023 12:54:38 +0200 Subject: [PATCH 038/212] more stability --- .../vulkan/descriptorSets/GDescriptorSet.cpp | 11 +++----- .../vulkan/descriptorSets/GDescriptorSet.h | 28 +++++++++++++------ .../src/gapi/vulkan/textures/GTextureVLK.cpp | 1 - 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 26b856c87..a8f77d1b2 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -19,13 +19,10 @@ GDescriptorSet::SetUpdateHelper GDescriptorSet::beginUpdate() { if (!m_firstUpdate) { //In this implementation of descriptor set, the descriptor set is getting free'd on update //and new one is created - auto l_descriptorSet = m_descriptorSet; - auto l_parentPool = m_parentPool; - auto l_hDescriptorSetLayout = m_hDescriptorSetLayout; - m_device->addDeallocationRecord([l_parentPool, l_descriptorSet, l_hDescriptorSetLayout]() { - l_parentPool->deallocate(l_hDescriptorSetLayout, l_descriptorSet); - }); - + + //This deallocate already have deallocate queue queue submission inside + m_parentPool->deallocate(m_hDescriptorSetLayout, m_descriptorSet); + m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); } return SetUpdateHelper(*this, boundDescriptors); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 56dc3c8f1..ff1f7bd9e 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -19,7 +19,7 @@ class GDescriptorPoolVLK; #include "../bindable/DSBindable.h" -class GDescriptorSet : std::enable_shared_from_this { +class GDescriptorSet : public std::enable_shared_from_this { public: explicit GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout); ~GDescriptorSet(); @@ -51,15 +51,25 @@ class GDescriptorSet : std::enable_shared_from_this { void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, DescriptorRecord::DescriptorRecordType descType) { static_assert(std::is_base_of::value, "T should inherit from B"); - auto ds_weak = m_set.weak_from_this(); - - auto callback = ([ds_weak]() -> void { - if (auto ds = ds_weak.lock()) { - ds->update(); + bool createDescRecord = !m_boundDescriptors[bindPoint]; + if (!createDescRecord) { + if constexpr (std::is_base_of::value) { + createDescRecord = (m_boundDescriptors[bindPoint]->buffer != object); + } else if constexpr (std::is_base_of::value) { + createDescRecord = (m_boundDescriptors[bindPoint]->textureVlk != object); } - }); - - m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); + } + if (createDescRecord) { + auto ds_weak = m_set.weak_from_this(); + + auto callback = ([ds_weak]() -> void { + if (auto ds = ds_weak.lock()) { + ds->update(); + } + }); + + m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); + } } private: GDescriptorSet &m_set; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 82e75229d..2c0c0e5c6 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -73,7 +73,6 @@ void GTextureVLK::destroyBuffer() { auto &l_imageAllocation = imageAllocation; - m_device.addDeallocationRecord( [l_device, l_texture, l_imageAllocation]() { vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); From 221063a72fee898bcaaba346932edd2741f4b2cc Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 23 Feb 2023 22:32:52 +0200 Subject: [PATCH 039/212] material as textureId in imgui --- CMakeLists.txt | 4 +- src/ui/FrontendUI.cpp | 36 +-- src/ui/FrontendUI.h | 12 +- .../mapConstructionWindow.cpp | 264 ------------------ .../mapConstructionWindow.h | 48 ---- .../MinimapGenerationWindow.cpp | 2 +- .../MinimapGenerationWindow.h | 6 +- src/ui/imguiLib/imguiCustomConfig.h | 4 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 5 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 10 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 17 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 + .../src/gapi/interface/materials/IMaterial.h | 13 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 28 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 16 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 3 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 34 ++- wowViewerLib/src/gapi/vulkan/GPipelineVLK.h | 20 +- .../src/gapi/vulkan/GRenderPassVLK.cpp | 10 +- wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h | 12 +- .../CommandBufferRecorder.cpp | 2 +- .../CommandBufferRecorder.h | 2 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 58 +--- .../vulkan/materials/ISimpleMaterialVLK.h | 12 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 19 ++ .../vulkan/materials/MaterialBuilderVLK.h | 4 + .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 7 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 3 +- 28 files changed, 166 insertions(+), 487 deletions(-) delete mode 100644 src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.cpp delete mode 100644 src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a4620b999..a6abd6af9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,9 +195,7 @@ set(SOURCE_FILES src/exporters/gltfExporter/GLTFExporter.cpp src/exporters/gltfExporter/GLTFExporter.h - src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.cpp - src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.h - src/ui/imguiLib/groupPanel/groupPanel.cpp + src/ui/imguiLib/groupPanel/groupPanel.cpp src/ui/imguiLib/groupPanel/groupPanel.h src/main.cpp diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index b7421f853..0deb53bc7 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -19,7 +19,6 @@ #include #include "imguiLib/fileBrowser/imfilebrowser.h" #include "../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" -#include "childWindow/mapConstructionWindow/mapConstructionWindow.h" #include "../persistance/CascRequestProcessor.h" #include "../../wowViewerLib/src/engine/objects/scenes/map.h" #include "../../wowViewerLib/src/engine/camera/firstPersonCamera.h" @@ -48,7 +47,7 @@ FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { void FrontendUI::composeUI() { if (mapCanBeOpened) { - if (!adtMinimapFilled && fillAdtSelectionminimap(adtSelectionMinimap, isWmoMap, mapCanBeOpened )) { + if (!adtMinimapFilled && fillAdtSelectionminimap(isWmoMap, mapCanBeOpened )) { // fillAdtSelectionminimap = nullptr; adtMinimapFilled = true; } @@ -117,7 +116,6 @@ void FrontendUI::composeUI() { showSettingsDialog(); showQuickLinksDialog(); - showMapConstructionDialog(); showMapSelectionDialog(); showMakeScreenshotDialog(); showCurrentStatsDialog(); @@ -311,16 +309,6 @@ void FrontendUI::filterMapList(std::string text) { } } } -void FrontendUI::showMapConstructionDialog() { - if (!showMapConstruction) return; - - if (m_mapConstructionWindow == nullptr) - m_mapConstructionWindow = std::make_shared(m_api); - - showMapConstruction = m_mapConstructionWindow->render(); - -} - void FrontendUI::showMapSelectionDialog() { if (showSelectMap) { if (mapList.size() == 0) { @@ -383,7 +371,8 @@ void FrontendUI::showMapSelectionDialog() { prevMapRec = mapRec; isWmoMap = false; - adtSelectionMinimap = {}; + adtSelectionMinimapTextures = {}; + adtSelectionMinimapMaterials = {}; if (mapRec.WdtFileID > 0) { getAdtSelectionMinimap(mapRec.WdtFileID); } else { @@ -462,8 +451,8 @@ void FrontendUI::showAdtSelectionMinimap() { const float defaultImageDimension = 100; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { - if (adtSelectionMinimap[i][j] != nullptr) { - if (ImGui::ImageButton(adtSelectionMinimap[i][j], + if (adtSelectionMinimapMaterials[i][j] != nullptr) { + if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j], ImVec2(defaultImageDimension * minimapZoom, defaultImageDimension * minimapZoom))) { auto mousePos = ImGui::GetMousePos(); ImGuiStyle &style = ImGui::GetStyle(); @@ -1319,8 +1308,7 @@ void FrontendUI::getMapList(std::vector &mapList) { m_api->databaseHandler->getMapArray(mapList); } -bool FrontendUI::fillAdtSelectionminimap(std::array, 64> &minimap, bool &isWMOMap, - bool &wdtFileExists) { +bool FrontendUI::fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists) { if (m_wdtFile == nullptr) return false; if (m_wdtFile->getStatus() == FileStatus::FSRejected) { @@ -1337,11 +1325,14 @@ bool FrontendUI::fillAdtSelectionminimap(std::array, 6 for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { if (m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture > 0) { - auto texture = m_api->cacheStorage->getTextureCache()->getFileId( + auto blpTexture = m_api->cacheStorage->getTextureCache()->getFileId( m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture); - minimap[i][j] = m_api->hDevice->createBlpTexture(texture, false, false); + auto textureObj = m_api->hDevice->createBlpTexture(blpTexture, false, false); + adtSelectionMinimapTextures[i][j] = textureObj; + adtSelectionMinimapMaterials[i][j] = m_uiRenderer->createUIMaterial({textureObj}); } else { - minimap[i][j] = nullptr; + adtSelectionMinimapTextures[i][j] = nullptr; + adtSelectionMinimapMaterials[i][j] = nullptr; } } } @@ -1746,6 +1737,7 @@ void FrontendUI::showMinimapGenerationSettingsDialog() { if(showMinimapGeneratorSettings) { if (m_minimapGenerationWindow == nullptr) m_minimapGenerationWindow = std::make_shared(m_api, + m_uiRenderer, m_processor, showMinimapGeneratorSettings); @@ -1807,5 +1799,5 @@ void FrontendUI::createFontTexture() { // Upload texture to graphics system // Store our identifier - io.Fonts->TexID = this->m_uiRenderer->uploadFontTexture(pixels, width, height); + io.Fonts->TexID = this->m_uiRenderer->createUIMaterial({this->m_uiRenderer->uploadFontTexture(pixels, width, height)}); } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 38d126bae..952ecd699 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -15,7 +15,6 @@ #include #include "../../wowViewerLib/src/include/database/dbStructs.h" #include "../../wowViewerLib/src/engine/objects/iScene.h" -#include "childWindow/mapConstructionWindow/mapConstructionWindow.h" #include "../minimapGenerator/minimapGenerator.h" #include "../persistance/CascRequestProcessor.h" #include "../minimapGenerator/storage/CMinimapDataDB.h" @@ -88,7 +87,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &mapList); std::string getCurrentAreaName(); - bool fillAdtSelectionminimap(std::array, 64> &minimap, bool &isWMOMap, bool &wdtFileExists); + bool fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists); void unloadScene(); @@ -96,12 +95,14 @@ class FrontendUI : public IScene, public std::enable_shared_from_this, 64> adtSelectionMinimap; + std::array, 64> adtSelectionMinimapTextures; + std::array, 64> adtSelectionMinimapMaterials; void emptyMinimap() { for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { - adtSelectionMinimap[i][j] = nullptr; + adtSelectionMinimapTextures[i][j] = nullptr; + adtSelectionMinimapMaterials[i][j] = nullptr; } } } @@ -186,8 +187,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this exporter; int exporterFramesReady = 0; - std::shared_ptr m_mapConstructionWindow = nullptr; - std::shared_ptr m_minimapGenerationWindow = nullptr; + std::shared_ptr m_minimapGenerationWindow = nullptr; //Test export diff --git a/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.cpp b/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.cpp deleted file mode 100644 index 5a8b14cef..000000000 --- a/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// -// Created by Deamon on 10/4/2020. -// - -#include "imgui.h" -#include "imgui_internal.h" -#include "mapConstructionWindow.h" -#include "../../../../wowViewerLib/src/engine/algorithms/mathHelper.h" - -MapConstructionWindow::MapConstructionWindow(HApiContainer mApi) : m_api(mApi) {} - -bool MapConstructionWindow::render() { - bool isNotClosed = true; - if (mapList.size() == 0) { - m_api->databaseHandler->getMapArray(mapList); - } - - if (mapCanBeOpened) { - if (!adtMinimapFilled && fillAdtSelectionminimap(adtSelectionMinimap, isWmoMap, mapCanBeOpened )) { -// fillAdtSelectionminimap = nullptr; - adtMinimapFilled = true; - } - } - - if (refilterIsNeeded) { - filterMapList(std::string(&filterText[0])); - mapListStringMap = {}; - for (int i = 0; i < filteredMapList.size(); i++) { - auto mapRec = filteredMapList[i]; - - std::vector mapStrRec; - mapStrRec.push_back(std::to_string(mapRec.ID)); - mapStrRec.push_back(mapRec.MapName); - mapStrRec.push_back(mapRec.MapDirectory); - mapStrRec.push_back(std::to_string(mapRec.WdtFileID)); - mapStrRec.push_back(std::to_string(mapRec.MapType)); - - mapListStringMap.push_back(mapStrRec); - } - - refilterIsNeeded = false; - } - - ImGui::Begin("Map construction dialog", &isNotClosed); - { - ImGui::Columns(2, NULL, true); - { - ImGui::BeginChild("Map Select Dialog for map constr", ImVec2(0, 0)); - { - if (!mapCanBeOpened) { - ImGui::Text("Cannot open this map."); - ImGui::Text("WDT file either does not exist in CASC repository or is encrypted"); - } else if (!isWmoMap) { - ImGui::SliderFloat("Zoom", &minimapZoom, 0.1, 10); - // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - showAdtSelectionMinimap(); - } else { - ImGui::Text("This is WMO map."); - } - - } - ImGui::EndChild(); - } - - ImGui::NextColumn(); - - { - //Filter - if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), ImGuiInputTextFlags_AlwaysInsertMode)) { - refilterIsNeeded = true; - } - //The table - ImGui::BeginChild("Map Select Dialog Left panel"); - ImGui::Columns(5, "mycolumns"); // 5-ways, with border - ImGui::Separator(); - ImGui::Text("ID"); - ImGui::NextColumn(); - ImGui::Text("MapName"); - ImGui::NextColumn(); - ImGui::Text("MapDirectory"); - ImGui::NextColumn(); - ImGui::Text("WdtFileID"); - ImGui::NextColumn(); - ImGui::Text("MapType"); - ImGui::NextColumn(); - ImGui::Separator(); - static int selected = -1; - for (int i = 0; i < filteredMapList.size(); i++) { - auto mapRec = filteredMapList[i]; - - if (ImGui::Selectable(mapListStringMap[i][0].c_str(), selected == i, ImGuiSelectableFlags_SpanAllColumns)) { - if (mapRec.ID != prevMapId) { - mapCanBeOpened = true; - adtMinimapFilled = false; - prevMapRec = mapRec; - - isWmoMap = false; - adtSelectionMinimap = {}; - currentlySelectedWdtFile = m_api->cacheStorage->getWdtFileCache()->getFileId(mapRec.WdtFileID); - } - prevMapId = mapRec.ID; - selected = i; - } - bool hovered = ImGui::IsItemHovered(); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][1].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][2].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][3].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][4].c_str()); - ImGui::NextColumn(); - } - ImGui::Columns(1); - ImGui::Separator(); - ImGui::EndChild(); - } - } - ImGui::End(); - - return isNotClosed; -} - -bool MapConstructionWindow::fillAdtSelectionminimap(std::array, 64> &minimap, bool &isWMOMap, - bool &wdtFileExists) { - if (currentlySelectedWdtFile == nullptr) return false; - - if (currentlySelectedWdtFile->getStatus() == FileStatus::FSRejected) { - wdtFileExists = false; - isWMOMap = false; - return false; - } - - if (currentlySelectedWdtFile->getStatus() != FileStatus::FSLoaded) return false; - - isWMOMap = currentlySelectedWdtFile->mphd->flags.wdt_uses_global_map_obj != 0; - - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - if (currentlySelectedWdtFile->mapFileDataIDs[i*64 + j].minimapTexture > 0) { - auto texture = m_api->cacheStorage->getTextureCache()->getFileId(currentlySelectedWdtFile->mapFileDataIDs[i*64 + j].minimapTexture); - minimap[i][j] = m_api->hDevice->createBlpTexture(texture, false, false); - } else { - minimap[i][j] = nullptr; - } - } - } - return true; -} - -template -struct my_equal1 { - my_equal1( const std::locale& loc ) : loc_(loc) {} - bool operator()(charT ch1, charT ch2) { - return std::toupper(ch1, loc_) == std::toupper(ch2, loc_); - } -private: - const std::locale& loc_; -}; - -template -int ci_find_substr_1( const T& str1, const T& str2, const std::locale& loc = std::locale() ) -{ - typename T::const_iterator it = std::search( str1.begin(), str1.end(), - str2.begin(), str2.end(), my_equal1(loc) ); - if ( it != str1.end() ) return it - str1.begin(); - else return -1; // not found -} - -void MapConstructionWindow::filterMapList(std::string text) { - filteredMapList = {}; - for (int i = 0; i < mapList.size(); i++) { - auto ¤tRec = mapList[i]; - if (text == "" || - ( - (ci_find_substr_1(currentRec.MapName, text) != std::string::npos) || - (ci_find_substr_1(currentRec.MapDirectory, text) != std::string::npos) - ) - ) { - filteredMapList.push_back(currentRec); - } - } -} - -void MapConstructionWindow::showAdtSelectionMinimap() { - ImGui::BeginChild("Adt selection minimap", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | - ImGuiWindowFlags_AlwaysVerticalScrollbar); - - if (minimapZoom < 0.001) - minimapZoom = 0.001f; - - float oldRealScrollX = ImGui::GetScrollX() + (ImGui::GetCurrentWindow()->InnerRect.GetWidth() / 2.0f); - float oldRealScrollY = ImGui::GetScrollY() + (ImGui::GetCurrentWindow()->InnerRect.GetHeight() / 2.0f); - - float oldScrollPercX = oldRealScrollX / (std::ceil(64*100*prevMinimapZoom) + (ImGui::GetCurrentWindow()->WindowPadding.x * 2.0f)); - float oldScrollPercY = oldRealScrollY / (std::ceil(64*100*prevMinimapZoom) + (ImGui::GetCurrentWindow()->WindowPadding.y * 2.0f)); - - if (prevMinimapZoom != minimapZoom) { - auto windowSize = ImGui::GetWindowSize(); -// ImGui::SetScrollX((windowSize.x / 2.0f) * ((ImGui::GetScrollX() + 1.0f) * minimapZoom / prevMinimapZoom - 1.0f)); -// ImGui::SetScrollY((windowSize.y / 2.0f) * ((ImGui::GetScrollY() + 1.0f) * minimapZoom / prevMinimapZoom - 1.0f)); - -// ImGui::SetScrollX((minimapZoom / prevMinimapZoom) * (ImGui::GetScrollX()/ImGui::GetScrollMaxX())); -// ImGui::SetScrollY((minimapZoom / prevMinimapZoom) * (ImGui::GetScrollY()/ImGui::GetScrollMaxY())); - - } - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); -// ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - - const float defaultImageDimension = 100; - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - if (adtSelectionMinimap[i][j] != nullptr) { - if (ImGui::ImageButton(adtSelectionMinimap[i][j], - ImVec2(defaultImageDimension * minimapZoom, defaultImageDimension * minimapZoom))) { - auto mousePos = ImGui::GetMousePos(); - ImGuiStyle &style = ImGui::GetStyle(); - - - mousePos.x += ImGui::GetScrollX() - ImGui::GetWindowPos().x - style.WindowPadding.x; - mousePos.y += ImGui::GetScrollY() - ImGui::GetWindowPos().y - style.WindowPadding.y; - - mousePos.x = ((mousePos.x / minimapZoom) / defaultImageDimension); - mousePos.y = ((mousePos.y / minimapZoom) / defaultImageDimension); - - mousePos.x = (32.0f - mousePos.x) * MathHelper::TILESIZE; - mousePos.y = (32.0f - mousePos.y) * MathHelper::TILESIZE; - -// worldPosX = mousePos.y; -// worldPosY = mousePos.x; - } - } else { - ImGui::Dummy(ImVec2(100 * minimapZoom, 100 * minimapZoom)); - } - - ImGui::SameLine(0, 0); - } - ImGui::NewLine(); - } - ImGui::PopStyleVar(); - ImGui::PopStyleVar(); - ImGui::PopStyleVar(); - - if (prevMinimapZoom != minimapZoom) { -// ImGui::BeginChild("Adt selection minimap", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | -// ImGuiWindowFlags_AlwaysVerticalScrollbar); - - float newScrollX = oldScrollPercX * (std::ceil(64*100*minimapZoom) + (ImGui::GetCurrentWindow()->WindowPadding.x * 2.0f)) - (ImGui::GetCurrentWindow()->InnerRect.GetWidth() / 2.0f); - float newScrollY = oldScrollPercY * (std::ceil(64*100*minimapZoom) + (ImGui::GetCurrentWindow()->WindowPadding.y * 2.0f)) - (ImGui::GetCurrentWindow()->InnerRect.GetHeight() / 2.0f); - - ImGui::SetScrollX(newScrollX); - ImGui::SetScrollY(newScrollY); - prevMinimapZoom = minimapZoom; - -// ImGui::EndChild(); - } - - ImGui::EndChild(); - -} \ No newline at end of file diff --git a/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.h b/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.h deleted file mode 100644 index 4412278fa..000000000 --- a/src/ui/childWindow/mapConstructionWindow/mapConstructionWindow.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by Deamon on 10/4/2020. -// - -#ifndef AWEBWOWVIEWERCPP_MAPCONSTRUCTIONWINDOW_H -#define AWEBWOWVIEWERCPP_MAPCONSTRUCTIONWINDOW_H - - -#include "../../../../wowViewerLib/src/engine/ApiContainer.h" - -class MapConstructionWindow { -private: - HApiContainer m_api; - - std::vector mapList = {}; - std::vector filteredMapList = {}; - std::vector> mapListStringMap = {}; - - bool showMapConstruction = false; - - - bool mapCanBeOpened = true; - bool adtMinimapFilled = false; - bool isWmoMap = false; - - int prevMapId = -1; - MapRecord prevMapRec; - - std::shared_ptr currentlySelectedWdtFile = nullptr; - std::array, 64> adtSelectionMinimap; - - float minimapZoom = 1; - float prevMinimapZoom = 1; - - std::array filterText = {0}; - bool refilterIsNeeded = false; - void filterMapList(std::string text); - - bool fillAdtSelectionminimap(std::array, 64> &minimap, bool &isWMOMap, bool &wdtFileExists); - void showAdtSelectionMinimap(); -public: - MapConstructionWindow(HApiContainer mApi); - - bool render(); -}; - - -#endif //AWEBWOWVIEWERCPP_MAPCONSTRUCTIONWINDOW_H diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 6af7e8de4..9a3401401 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -74,7 +74,7 @@ void MinimapGenerationWindow::render() { const int imageSize = 512; - if (ImGui::ImageButton2(texture, "previewImage", + if (ImGui::ImageButton2(m_renderer->createUIMaterial({texture}), "previewImage", ImVec2(imageSize, imageSize), ImVec2(0,1), ImVec2(1,0))) diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h index 5742fda70..55f7d8d51 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.h @@ -9,11 +9,12 @@ #include "../../../minimapGenerator/entities.h" #include "../../../minimapGenerator/minimapGenerator.h" #include "../../../minimapGenerator/storage/CMinimapDataDB.h" +#include "../../renderer/uiScene/FrontendUIRenderer.h" class MinimapGenerationWindow { public: - MinimapGenerationWindow(HApiContainer api, HRequestProcessor processor, bool &showMinimapGeneratorSettings) : - m_showMinimapGeneratorSettings(showMinimapGeneratorSettings) { + MinimapGenerationWindow(HApiContainer api, const std::shared_ptr &renderer, HRequestProcessor processor, bool &showMinimapGeneratorSettings) : + m_showMinimapGeneratorSettings(showMinimapGeneratorSettings), m_renderer(renderer) { m_api = api; m_processor = processor; @@ -30,6 +31,7 @@ class MinimapGenerationWindow { private: HApiContainer m_api; HRequestProcessor m_processor; + std::shared_ptr m_renderer; bool &m_showMinimapGeneratorSettings; diff --git a/src/ui/imguiLib/imguiCustomConfig.h b/src/ui/imguiLib/imguiCustomConfig.h index d499519e0..14db6cafc 100644 --- a/src/ui/imguiLib/imguiCustomConfig.h +++ b/src/ui/imguiLib/imguiCustomConfig.h @@ -1,8 +1,8 @@ #ifndef AWEBWOWVIEWERCPP_IMGUICUSTOMCONFIG_H #define AWEBWOWVIEWERCPP_IMGUICUSTOMCONFIG_H -#include "../../../wowViewerLib/src/gapi/interface/IDevice.h" -#define ImTextureID HGTexture +#include "../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +#define ImTextureID std::shared_ptr diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 78a965da5..21d46260e 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -107,10 +107,7 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrIdxOffset * 2; meshTemplate.end = pcmd->ElemCount; - UIMaterialTemplate materialTemplate; - materialTemplate.texture = pcmd->TextureId; - - auto material = this->createUIMaterial(materialTemplate); + auto material = pcmd->TextureId; meshes.push_back(this->createMesh(meshTemplate, material)); } } diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 8e1fbabd6..6327f854a 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -17,6 +17,16 @@ static const std::array imguiBindings = {{ {+imguiShader::Attribute::Color, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, col)}, }}; +static const PipelineTemplate s_imguiPipelineTemplate = { + DrawElementMode::TRIANGLES, + true, + true, + false, + false, + EGxBlendEnum::GxBlend_Alpha, + 0xFF +}; + class FrontendUIRenderer : public IRendererParameters, public IFrontendUIBufferCreate { public: diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index cba244d0d..fc9028206 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -14,6 +14,7 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic hDevice), m_device(hDevice) { m_lastRenderPass = m_device->getSwapChainRenderPass(); + m_emptyImguiVAO = createVAO(nullptr,nullptr); createBuffers(); } @@ -36,11 +37,11 @@ HGIndexBuffer FrontendUIRenderForwardVLK::createIndexBuffer(int sizeInBytes) { HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers - auto m_imguiVAO = m_device->createVertexBufferBindings(); - m_imguiVAO->addVertexBufferBinding(vertexBuffer, std::vector(imguiBindings.begin(), imguiBindings.end())); - m_imguiVAO->setIndexBuffer(indexBuffer); + auto imguiVAO = m_device->createVertexBufferBindings(); + imguiVAO->addVertexBufferBinding(vertexBuffer, std::vector(imguiBindings.begin(), imguiBindings.end())); + imguiVAO->setIndexBuffer(indexBuffer); - return m_imguiVAO; + return imguiVAO; } HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { @@ -55,6 +56,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate auto &l_imguiUbo = m_imguiUbo; auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}) + .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() .ubo(1, l_imguiUbo->getSubBuffer()); @@ -112,7 +114,6 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( for (auto const &mesh : *meshes) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); - auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); // auto indexBuffer = (vulkanBindings->m_indexBuffer.get())->g_hIndexBuffer; @@ -125,11 +126,11 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( swapChainCmd.bindIndexBuffer(vulkanBindings->getIndexBuffer()); //3. Bind pipeline - auto pipeline = meshVlk->getPipeLineForRenderPass(l_this->m_lastRenderPass, false); - swapChainCmd.bindPipeline(pipeline); + auto material = meshVlk->material(); + swapChainCmd.bindPipeline(material->getPipeline()); //4. Bind Descriptor sets - auto const &descSets = meshVlk->material()->getDescriptorSets(); + auto const &descSets = material->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { swapChainCmd.bindDescriptorSet(i, descSets[i]); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 7984ab8ae..791278beb 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -46,6 +46,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { std::shared_ptr m_lastRenderPass; std::shared_ptr> m_previousMeshes = nullptr; + + HGVertexBufferBindings m_emptyImguiVAO = nullptr; }; diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index 559374429..d7f5f288a 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -8,6 +8,19 @@ #include #include "../IDevice.h" +struct PipelineTemplate { + DrawElementMode element; + + int8_t triCCW = 1; //counter-clockwise + bool depthWrite = true; + bool depthCulling = true; + bool backFaceCulling = true; + EGxBlendEnum blendMode; + + uint8_t colorMask = 0xFF; +}; + + class IMaterial { public: virtual ~IMaterial() = default; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 64a48abae..8939cd449 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -506,7 +506,7 @@ void GDeviceVLK::createSwapChainRenderPass(VkFormat swapChainImageFormat) { std::vector({swapChainImageFormat}), findDepthFormat(), VK_SAMPLE_COUNT_1_BIT, - true); + false, true); } void GDeviceVLK::createFramebuffers(std::vector &swapChainTextures, VkExtent2D &extent) { @@ -1097,13 +1097,16 @@ std::shared_ptr GDeviceVLK::getRenderPass( std::vector textureAttachments, ITextureFormat depthAttachment, VkSampleCountFlagBits sampleCountFlagBits, + bool invertZ, bool isSwapChainPass ) { for (auto &renderPassAvalability : m_createdRenderPasses) { if (renderPassAvalability.attachments.size() == textureAttachments.size() && renderPassAvalability.depthAttachment == depthAttachment && renderPassAvalability.sampleCountFlagBits == sampleCountFlagBits && - renderPassAvalability.isSwapChainPass == isSwapChainPass) + renderPassAvalability.sampleCountFlagBits == sampleCountFlagBits && + renderPassAvalability.isSwapChainPass == isSwapChainPass && + renderPassAvalability.invertZ == invertZ) { //Check frame definition bool notEqual = false; @@ -1127,10 +1130,11 @@ std::shared_ptr GDeviceVLK::getRenderPass( VkFormat fbDepthFormat = findDepthFormat(); auto renderPass = std::make_shared(this->device, - attachmentFormats, - findDepthFormat(), - sampleCountFlagBits, - false + attachmentFormats, + findDepthFormat(), + sampleCountFlagBits, + invertZ, + false ); RenderPassAvalabilityStruct avalabilityStruct; @@ -1149,16 +1153,15 @@ std::shared_ptr GDeviceVLK::getSwapChainRenderPass() { return swapchainRenderPass; } -HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, - HGShaderPermutation shader, - std::shared_ptr renderPass, +HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings, + const HGShaderPermutation &shader, + const std::shared_ptr &renderPass, DrawElementMode element, int8_t backFaceCulling, int8_t triCCW, EGxBlendEnum blendMode, int8_t depthCulling, - int8_t depthWrite, - bool invertZ) { + int8_t depthWrite) { PipelineCacheRecord pipelineCacheRecord; pipelineCacheRecord.shader = shader; @@ -1169,7 +1172,6 @@ HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, pipelineCacheRecord.blendMode = blendMode; pipelineCacheRecord.depthCulling = depthCulling; pipelineCacheRecord.depthWrite = depthWrite; - pipelineCacheRecord.invertZ = invertZ; auto i = loadedPipeLines.find(pipelineCacheRecord); if (i != loadedPipeLines.end()) { @@ -1182,7 +1184,7 @@ HPipelineVLK GDeviceVLK::createPipeline(HGVertexBufferBindings m_bindings, std::shared_ptr hgPipeline = std::make_shared(*this, m_bindings, renderPass, shader, element, backFaceCulling, triCCW, blendMode, - depthCulling, depthWrite, invertZ); + depthCulling, depthWrite); std::weak_ptr weakPtr(hgPipeline); loadedPipeLines[pipelineCacheRecord] = weakPtr; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 3d7577466..fa27916ca 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -115,20 +115,20 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) override ; - HPipelineVLK createPipeline(HGVertexBufferBindings m_bindings, - HGShaderPermutation shader, - std::shared_ptr renderPass, + HPipelineVLK createPipeline(const HGVertexBufferBindings &m_bindings, + const HGShaderPermutation &shader, + const std::shared_ptr &renderPass, DrawElementMode element, int8_t backFaceCulling, int8_t triCCW, EGxBlendEnum blendMode, int8_t depthCulling, - int8_t depthWrite, - bool invertZ); + int8_t depthWrite); std::shared_ptr getRenderPass(std::vector textureAttachments, ITextureFormat depthAttachment, VkSampleCountFlagBits sampleCountFlagBits, + bool invertZ, bool isSwapChainPass); std::shared_ptr getSwapChainRenderPass(); @@ -223,7 +223,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.triCCW) << 4) ^ (hash{}(k.depthCulling) << 8) ^ (hash{}(k.depthWrite) << 10) ^ - (hash{}(k.invertZ) << 12) ^ (hash{}(k.blendMode) << 14) ^ (hash{}(k.element) << 16); }; @@ -339,6 +336,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this renderPass; VkSampleCountFlagBits sampleCountFlagBits; bool isSwapChainPass; + bool invertZ; }; std::vector m_createdRenderPasses; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index 7269c91a5..b1a8bf644 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -140,7 +140,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, attachments.push_back(h_depthTexture->texture.view); } - m_renderPass = mdevice.getRenderPass(textureAttachments, depthAttachment, sampleCountToVkSampleCountFlagBits(multiSampleCnt), false); + bool invertZ = true; + m_renderPass = mdevice.getRenderPass(textureAttachments, depthAttachment, sampleCountToVkSampleCountFlagBits(multiSampleCnt), invertZ, false); VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; fbufCreateInfo.pNext = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index e627e8d47..fbabe6d68 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -38,12 +38,11 @@ GPipelineVLK::GPipelineVLK(IDevice &device, const std::shared_ptr &renderPass, const HGShaderPermutation &shader, DrawElementMode element, - int8_t backFaceCulling, - int8_t triCCW, + bool backFaceCulling, + bool triCCW, EGxBlendEnum blendMode, - int8_t depthCulling, - int8_t depthWrite, - bool invertZ) : m_device(dynamic_cast(device)) { + bool depthCulling, + bool depthWrite) : m_device(dynamic_cast(device)) { GVertexBufferBindingsVLK* bufferBindingsVlk = dynamic_cast(m_bindings.get()); auto &arrVLKFormat = bufferBindingsVlk->getVLKFormat(); @@ -68,8 +67,8 @@ GPipelineVLK::GPipelineVLK(IDevice &device, blendMode, depthCulling, depthWrite, - invertZ, - vertexBindingDescriptions, vertexAttributeDescriptions); + vertexBindingDescriptions, + vertexAttributeDescriptions); } GPipelineVLK::~GPipelineVLK() { @@ -85,14 +84,13 @@ GPipelineVLK::~GPipelineVLK() { void GPipelineVLK::createPipeline( GShaderPermutationVLK *shaderVLK, - std::shared_ptr renderPass, + const std::shared_ptr &renderPass, DrawElementMode m_element, - int8_t m_backFaceCulling, - int8_t m_triCCW, + bool backFaceCulling, + bool triCCW, EGxBlendEnum m_blendMode, - int8_t m_depthCulling, - int8_t m_depthWrite, - bool invertZ, + bool depthCulling, + bool depthWrite, const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions) { @@ -175,8 +173,8 @@ void GPipelineVLK::createPipeline( rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = m_backFaceCulling ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE; - rasterizer.frontFace = m_triCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; + rasterizer.cullMode = backFaceCulling ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE; + rasterizer.frontFace = triCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; VkPipelineMultisampleStateCreateInfo multisampling = {}; @@ -210,9 +208,9 @@ void GPipelineVLK::createPipeline( depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.pNext = NULL; depthStencil.flags = 0; - depthStencil.depthTestEnable = m_depthCulling ? VK_TRUE : VK_FALSE; - depthStencil.depthWriteEnable = m_depthWrite ? VK_TRUE : VK_FALSE; - depthStencil.depthCompareOp = invertZ ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencil.depthTestEnable = depthCulling ? VK_TRUE : VK_FALSE; + depthStencil.depthWriteEnable = depthWrite ? VK_TRUE : VK_FALSE; + depthStencil.depthCompareOp = renderPass->getInvertZ() ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL; depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.stencilTestEnable = VK_FALSE; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h index 6eca7a33c..f5e35cd60 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h @@ -17,24 +17,22 @@ class GPipelineVLK { const std::shared_ptr &renderPass, const HGShaderPermutation &shader, DrawElementMode element, - int8_t backFaceCulling, - int8_t triCCW, + bool backFaceCulling, + bool triCCW, EGxBlendEnum blendMode, - int8_t depthCulling, - int8_t depthWrite, - bool invertZ); + bool depthCulling, + bool depthWrite); ~GPipelineVLK(); void createPipeline( GShaderPermutationVLK *shaderVLK, - std::shared_ptr renderPass, + const std::shared_ptr &renderPass, DrawElementMode m_element, - int8_t m_backFaceCulling, - int8_t m_triCCW, + bool m_backFaceCulling, + bool m_triCCW, EGxBlendEnum m_blendMode, - int8_t m_depthCulling, - int8_t m_depthWrite, - bool invertZ, + bool m_depthCulling, + bool m_depthWrite, const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions); diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp index 77b9142bc..95c3f8687 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp @@ -6,8 +6,12 @@ #include "GRenderPassVLK.h" -GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, std::vector textureAttachments, VkFormat depthAttachmentFormat, - VkSampleCountFlagBits sampleCountBit, bool isSwapChainPass) { +GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, + std::vector textureAttachments, + VkFormat depthAttachmentFormat, + VkSampleCountFlagBits sampleCountBit, + bool invertZ, + bool isSwapChainPass) : m_invertZ(invertZ) { m_sampleCountBit = sampleCountBit; std::vector attachments; @@ -154,7 +158,7 @@ std::vector GRenderPassVLK::produceClearColorVec(std::array textureAttachments, - VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, + GRenderPassVLK(VkDevice vkDevice, + std::vector textureAttachments, + VkFormat depthAttachment, + VkSampleCountFlagBits sampleCountBit, + bool invertZ, bool isSwapChainPass); VkSampleCountFlagBits getSampleCountBit(); VkRenderPass getRenderPass(); std::vector produceClearColorVec(std::array colorClearColor, float depthClear); + bool getInvertZ() { + return m_invertZ; + } private: VkSampleCountFlagBits m_sampleCountBit; VkRenderPass renderPass; + bool m_invertZ = false; + enum class AttachmentType { atColor, atData, diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index b46cf4baa..628a166a1 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -130,7 +130,7 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector &pipeline) { +void CmdBufRecorder::bindPipeline(const std::shared_ptr &pipeline) { if (m_currentPipeline == pipeline) return; vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline()); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 1ac676055..3cb12979d 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -41,7 +41,7 @@ class CmdBufRecorder { void bindIndexBuffer(const std::shared_ptr &bufferVlk); void bindVertexBuffers(const std::vector> &bufferVlk); - void bindPipeline(std::shared_ptr &pipeline); + void bindPipeline(const std::shared_ptr &pipeline); void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index f25ae426c..2f2733552 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -5,63 +5,9 @@ #include "ISimpleMaterialVLK.h" #include "../shaders/GShaderPermutationVLK.h" #include "../textures/GTextureVLK.h" - -//void ISimpleMaterialVLK::createImageDescriptorSet() { -// auto shaderVLK = std::dynamic_pointer_cast(m_shader); -// auto descLayout = shaderVLK->getImageDescriptorLayout(); -// -// descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; -// -// int textureBegin = shaderVLK->getTextureBindingStart(); -// -// auto blackTexture = m_device->getBlackTexturePixel(); -// auto blackTextureVlk = std::dynamic_pointer_cast(blackTexture); -// -// { -// auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); -// for (int i = 0; i < shaderVLK->getTextureCount(); i++) { -// updateHelper.texture(textureBegin + i, blackTextureVlk); -// } -// } -//} -// -// -//void ISimpleMaterialVLK::updateImageDescriptorSet() { -// bool allTexturesAreReady = true; -// -// auto shaderVLK = std::dynamic_pointer_cast(m_shader); -// int textureBegin = shaderVLK->getTextureBindingStart(); -// -// for (auto& texture : m_textures) { -// if (texture == nullptr) continue; -// allTexturesAreReady &= texture->getIsLoaded(); -// } -// -// if (allTexturesAreReady) { -// auto updateHelper = descriptors[GShaderPermutationVLK::IMAGE_SET_INDEX]->beginUpdate(); -// for (size_t i = 0; i < m_textures.size(); i++) { -// auto textureVlk = std::dynamic_pointer_cast(m_textures[i]); -// if (textureVlk == nullptr) continue; -// -// updateHelper.texture(textureBegin + i, textureVlk); -// } -// } -//} -// -//void ISimpleMaterialVLK::createAndUpdateUBODescriptorSet() { -// auto shaderVLK = std::dynamic_pointer_cast(m_shader); -// auto descLayout = shaderVLK->getUboDescriptorLayout(); -// -// descriptors[GShaderPermutationVLK::UBO_SET_INDEX] = m_device->createDescriptorSet(descLayout) ; -// -// auto updateHelper = descriptors[GShaderPermutationVLK::UBO_SET_INDEX]->beginUpdate(); -// for (size_t i = 0; i < m_ubos.size(); i++) { -// updateHelper.ubo(i, m_ubos[i]); -// } -//} - ISimpleMaterialVLK::ISimpleMaterialVLK(const HGShaderPermutation &shader, + const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : - m_shader(shader), descriptors(descriptorSets) { + m_shader(shader), m_pipeline(pipeline), descriptors(descriptorSets) { } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 558f4aef0..71eb1ebad 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -15,7 +15,8 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: - explicit ISimpleMaterialVLK(const HGShaderPermutation &m_shader, + explicit ISimpleMaterialVLK(const HGShaderPermutation &shader, + const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); ~ISimpleMaterialVLK() override = default; @@ -23,19 +24,18 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this return m_shader; } -// void createImageDescriptorSet(); -// void updateImageDescriptorSet(); - -// void createAndUpdateUBODescriptorSet(); - const std::array, MAX_SHADER_DESC_SETS> &getDescriptorSets() { return descriptors; } + HPipelineVLK getPipeline() { + return m_pipeline; + } private: std::array, MAX_SHADER_DESC_SETS> descriptors; HGShaderPermutation m_shader; + HPipelineVLK m_pipeline; }; typedef std::shared_ptr HMaterialVLK; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index de01ec357..4f1b18aa6 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -36,9 +36,28 @@ MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::sh return *this; } +MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindings &bindings, + const std::shared_ptr &renderPass, + const PipelineTemplate &pipelineTemplate) { + m_pipeline = std::dynamic_pointer_cast(m_device)->createPipeline( + bindings, + m_shader, + renderPass, + pipelineTemplate.element, + pipelineTemplate.backFaceCulling, + pipelineTemplate.triCCW, + pipelineTemplate.blendMode, + pipelineTemplate.depthCulling, + pipelineTemplate.depthWrite + ); + + return *this; +} + std::shared_ptr MaterialBuilderVLK::toMaterial() { return std::make_shared( m_shader, + m_pipeline, descriptorSets ); } diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index a6c83ca10..2978cbf7b 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -23,6 +23,9 @@ class MaterialBuilderVLK { MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); MaterialBuilderVLK& createDescriptorSet(int bindPoint, const std::function &ds)> &callback); + MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, + const std::shared_ptr &renderPass, + const PipelineTemplate &pipelineTemplate); std::shared_ptr toMaterial(); ~MaterialBuilderVLK() = default; @@ -36,6 +39,7 @@ class MaterialBuilderVLK { const std::shared_ptr &m_device; HGShaderPermutation m_shader; + HPipelineVLK m_pipeline; std::array, MAX_SHADER_DESC_SETS> descriptorSets; }; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 7cb5289ec..27f91a09e 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -36,15 +36,14 @@ GMeshVLK::GMeshVLK(IDevice &device, } //Works under assumption that meshes do not change the renderpass, on which they are rendered, too often -std::shared_ptr GMeshVLK::getPipeLineForRenderPass(const std::shared_ptr &renderPass, bool invertedZ) { - if (m_lastRenderPass != renderPass || m_lastInvertedZ != invertedZ) { +std::shared_ptr GMeshVLK::getPipeLineForRenderPass(const std::shared_ptr &renderPass) { + if (m_lastRenderPass != renderPass) { m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, m_material->getShader(), renderPass, m_element, m_backFaceCulling, m_triCCW, m_blendMode, m_depthCulling, - m_depthWrite, invertedZ); + m_depthWrite); m_lastRenderPass = renderPass; - m_lastInvertedZ = invertedZ; } return m_lastPipelineForRenderPass; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 5fb37d63c..058dc47c2 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -26,7 +26,7 @@ class GMeshVLK : public IMesh { MeshType getMeshType() override; public: - std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass, bool invertedZ); + std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); auto material() const -> const HMaterialVLK& { return m_material; } protected: MeshType m_meshType; @@ -52,7 +52,6 @@ class GMeshVLK : public IMesh { std::vector descriptorSetsUpdated; std::shared_ptr m_lastRenderPass = nullptr; - bool m_lastInvertedZ = false; std::shared_ptr m_lastPipelineForRenderPass; private: GDeviceVLK &m_device; From 9e4f134a97b56c5ca07fe5830c3a7225d44fa366 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 24 Feb 2023 01:11:00 +0200 Subject: [PATCH 040/212] less memory consumption --- .../uiScene/IFrontendUIBufferCreate.h | 2 +- .../renderer/uiScene/materials/UIMaterial.h | 43 ++++++++++++------- .../vulkan/FrontendUIRenderForwardVLK.cpp | 11 ++--- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index 30f857cf0..b789a1961 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -18,7 +18,7 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; - virtual HMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) = 0; + virtual HMaterial createUIMaterial(const HGTexture &hgtexture) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index 7a4f21e42..0349caf7e 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -11,24 +11,37 @@ #include "../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" -struct UIMaterialTemplate { - HGTexture texture; +namespace wtf { + template>>> + struct KeyContainer { + KeyContainer(const std::weak_ptr &weakPtr) { + w_key = weakPtr; + key = weakPtr.lock().get(); + } - bool operator==(const UIMaterialTemplate &other) const { - return (texture == other.texture); - }; -}; + bool operator ==(const KeyContainer &r_key) const { + return std::owner_less()(r_key.w_key, w_key); + } -//------------------------------------------------------- -// HASHer and CACHE CLASS -//------------------------------------------------------- + bool isExpired() { + return w_key.expired(); + } -struct UIMaterialHasher { - std::size_t operator()(const UIMaterialTemplate& k) const { - using std::hash; - return hash{}(k.texture.get()); + std::weak_ptr w_key; + typename T::element_type *key; + }; +} +namespace std { + template + struct hash> + { + std::size_t operator()(const wtf::KeyContainer& k) const + { + return (std::hash()(k.key)); + } }; -}; -typedef std::unordered_map, UIMaterialHasher> UiMaterialCache; +} + +typedef std::unordered_map, std::weak_ptr> UiMaterialCache; #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index fc9028206..cc29c1f9c 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -44,8 +44,9 @@ HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vert return imguiVAO; } -HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate &materialTemplate) { - auto i = m_materialCache.find(materialTemplate); +HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtexture) { + auto weakTexture = std::weak_ptr(hgtexture); + auto i = m_materialCache.find(weakTexture); if (i != m_materialCache.end()) { if (!i->second.expired()) { return i->second.lock(); @@ -61,9 +62,9 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate ds->beginUpdate() .ubo(1, l_imguiUbo->getSubBuffer()); }) - .createDescriptorSet(1, [&materialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(1, [&hgtexture](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(materialTemplate.texture)); + .texture(5, std::dynamic_pointer_cast(hgtexture)); }) .toMaterial(); @@ -76,7 +77,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const UIMaterialTemplate // texturesVLK); std::weak_ptr weakPtr = material; - m_materialCache[materialTemplate] = weakPtr; + m_materialCache[weakTexture] = weakPtr; return material; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 791278beb..2b4b2ba9c 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -26,7 +26,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; - HMaterial createUIMaterial(const UIMaterialTemplate &materialTemplate) override; + HMaterial createUIMaterial(const HGTexture &hgtexture) override; private: diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 3bb72df95..9aa18fda6 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -14,7 +14,7 @@ GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, } GBlpTextureVLK::~GBlpTextureVLK() { - std::cout << "destroyed blp text!" << std::endl; +// std::cout << "destroyed blp text!" << std::endl; } From ad600831b7b9f401cbcb25cbe52360fe8a423346 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 24 Feb 2023 01:59:01 +0200 Subject: [PATCH 041/212] small change --- src/persistance/CascRequestProcessor.cpp | 4 +- .../renderer/uiScene/materials/UIMaterial.h | 33 +-------------- wowViewerLib/CMakeLists.txt | 2 +- .../src/engine/objects/m2/m2Object.cpp | 1 - .../src/include/custom_container_key.h | 40 +++++++++++++++++++ 5 files changed, 45 insertions(+), 35 deletions(-) create mode 100644 wowViewerLib/src/include/custom_container_key.h diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 50210aa93..4abd93dc2 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -170,9 +170,9 @@ void CascRequestProcessor::processFileRequest(std::string &fileName, CacheHolder fileContent = this->tryGetFile(this->m_storage, fileNameToPass, openFlags); if (fileContent == nullptr) { if (fileDataId > 0) { - std::cout << "Could read fileDataId " << fileDataId << " from local " << std::endl << std::flush; + std::cout << "Could not read fileDataId " << fileDataId << " from local " << std::endl << std::flush; } else { - std::cout << "Could read file " << fileName << " from local " << std::endl << std::flush; + std::cout << "Could not read file " << fileName << " from local " << std::endl << std::flush; } } } diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index 0349caf7e..e8699bb64 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -9,38 +9,9 @@ #include "../../../../wowViewerLib/src/gapi/interface/textures/ITexture.h" #include "../../../../wowViewerLib/src/gapi/interface/buffers/IBufferChunk.h" #include "../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" -#include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +#include "../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +#include "../../../../wowViewerLib/src/include/custom_container_key.h" -namespace wtf { - template>>> - struct KeyContainer { - KeyContainer(const std::weak_ptr &weakPtr) { - w_key = weakPtr; - key = weakPtr.lock().get(); - } - - bool operator ==(const KeyContainer &r_key) const { - return std::owner_less()(r_key.w_key, w_key); - } - - bool isExpired() { - return w_key.expired(); - } - - std::weak_ptr w_key; - typename T::element_type *key; - }; -} -namespace std { - template - struct hash> - { - std::size_t operator()(const wtf::KeyContainer& k) const - { - return (std::hash()(k.key)); - } - }; -} typedef std::unordered_map, std::weak_ptr> UiMaterialCache; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 30e337b2c..044effb9e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -328,7 +328,7 @@ set(SOURCE_FILES src/renderer/buffers/IVertexBufferDynamicTemplate.h src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h - src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h) + src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h src/include/custom_container_key.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index e598d9680..7591d6a95 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1850,7 +1850,6 @@ HBlpTexture M2Object::getBlpTextureData(int textureInd) { } HGTexture M2Object::getTexture(int textureInd) { - std::unordered_map &loadedTextureCache = loadedTextures; M2Texture* textureDefinition = m_m2Geom->getM2Data()->textures.getElement(textureInd); HBlpTexture blpData = getBlpTextureData(textureInd); diff --git a/wowViewerLib/src/include/custom_container_key.h b/wowViewerLib/src/include/custom_container_key.h new file mode 100644 index 000000000..49248c479 --- /dev/null +++ b/wowViewerLib/src/include/custom_container_key.h @@ -0,0 +1,40 @@ +// +// Created by Deamon on 2/24/2023. +// + +#ifndef AWEBWOWVIEWERCPP_CUSTOM_CONTAINER_KEY_H +#define AWEBWOWVIEWERCPP_CUSTOM_CONTAINER_KEY_H + +#include + +namespace wtf { + template>>> + struct KeyContainer { + KeyContainer(const std::weak_ptr &weakPtr) { + w_key = weakPtr; + key = weakPtr.lock().get(); + } + + bool operator ==(const KeyContainer &r_key) const { + return std::owner_less()(r_key.w_key, w_key); + } + + bool isExpired() { + return w_key.expired(); + } + + std::weak_ptr w_key; + typename T::element_type *key; + }; +} +namespace std { + template + struct hash> + { + std::size_t operator()(const wtf::KeyContainer& k) const + { + return (std::hash()(k.key)); + } + }; +} +#endif //AWEBWOWVIEWERCPP_CUSTOM_CONTAINER_KEY_H From 4aaab3ad33486bac1a6d6bbb21f4543be62f4fcb Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 27 Feb 2023 05:55:35 +0200 Subject: [PATCH 042/212] approaching map rendering --- src/ui/FrontendUI.cpp | 135 ++++++++++----- src/ui/FrontendUI.h | 4 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 1 - .../src/engine/objects/scenes/map.cpp | 159 +++++++++--------- wowViewerLib/src/engine/objects/scenes/map.h | 4 +- .../src/engine/texture/BlpTexture.cpp | 7 +- wowViewerLib/src/renderer/IRenderParameters.h | 4 +- wowViewerLib/src/renderer/IRenderer.h | 2 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 1 + .../src/renderer/mapScene/MapSceneParams.h | 3 + .../src/renderer/mapScene/MapScenePlan.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 13 ++ .../src/renderer/mapScene/MapSceneRenderer.h | 4 +- .../mapScene/MapSceneRendererFactory.h | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 15 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- 16 files changed, 218 insertions(+), 138 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 0deb53bc7..bb1206e66 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -34,6 +34,7 @@ #include "../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "renderer/uiScene/IFrontendUIBufferCreate.h" #include "renderer/uiScene/FrontendUIRendererFactory.h" +#include "../../wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h" FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { m_api = api; @@ -547,7 +548,7 @@ void FrontendUI::showMainMenu() { showMinimapGeneratorSettings = true; } if (ImGui::MenuItem("Test export")) { - if (currentScene != nullptr) { + if (m_currentScene != nullptr) { exporter = std::make_shared("./gltf/"); // currentScene->exportScene(exporter.get()); exporterFramesReady = 0; @@ -969,7 +970,7 @@ void FrontendUI::showQuickLinksDialog() { openM2SceneByfdid(3732303, replacementTextureFDids); } if (ImGui::Button("Bugged ADT (SL)", ImVec2(-1, 0))) { - currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); + m_currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); } ImGui::Separator(); ImGui::Text("Models for billboard checking"); @@ -1322,20 +1323,26 @@ bool FrontendUI::fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists) { isWMOMap = m_wdtFile->mphd->flags.wdt_uses_global_map_obj != 0; if (!isWMOMap) { - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - if (m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture > 0) { - auto blpTexture = m_api->cacheStorage->getTextureCache()->getFileId( - m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture); - auto textureObj = m_api->hDevice->createBlpTexture(blpTexture, false, false); - adtSelectionMinimapTextures[i][j] = textureObj; - adtSelectionMinimapMaterials[i][j] = m_uiRenderer->createUIMaterial({textureObj}); - } else { - adtSelectionMinimapTextures[i][j] = nullptr; - adtSelectionMinimapMaterials[i][j] = nullptr; + if (m_wdtFile->mphd->flags.wdt_has_maid) { + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + if (m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture > 0) { + auto blpTexture = m_api->cacheStorage->getTextureCache()->getFileId( + m_wdtFile->mapFileDataIDs[i * 64 + j].minimapTexture); + auto textureObj = m_api->hDevice->createBlpTexture(blpTexture, false, false); + adtSelectionMinimapTextures[i][j] = textureObj; + adtSelectionMinimapMaterials[i][j] = m_uiRenderer->createUIMaterial({textureObj}); + } else { + adtSelectionMinimapTextures[i][j] = nullptr; + adtSelectionMinimapMaterials[i][j] = nullptr; + } } + } } + else { + std::cout << "wdtId = " << prevMapRec.WdtFileID << std::endl; + } } return true; } @@ -1480,12 +1487,56 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { // return nullptr; //} +HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, + int width, int height, + bool produceDoubleCamera, + bool swapDebugCamera, + const std::shared_ptr ¤tScene) { + + auto result = std::make_shared(); + result->scene = currentScene; + + float farPlaneRendering = apiContainer.getConfig()->farPlane; + float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; + + float nearPlane = 1.0; + float fov = toRadian(45.0); + + float canvasAspect = (float)width / (float)height; + + result->matricesForCulling = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); + result->cameraMatricesForRendering = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); + result->cameraMatricesForDebugCamera = nullptr; + + if (produceDoubleCamera && apiContainer.debugCamera != nullptr) + result->cameraMatricesForDebugCamera = apiContainer.debugCamera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); + + + //Frustum matrix with reversed Z + bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); + if (isInfZSupported) + { + float f = 1.0f / tan(fov / 2.0f); + result->cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); + if (result->cameraMatricesForDebugCamera != nullptr) { + result->cameraMatricesForDebugCamera->perspectiveMat = result->cameraMatricesForDebugCamera->perspectiveMat; + } + } + + result->clearColor = apiContainer.getConfig()->clearColor; + + if (result->cameraMatricesForDebugCamera && swapDebugCamera) { + std::swap(result->cameraMatricesForDebugCamera, result->cameraMatricesForRendering); + } + + return result; +} + HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, double deltaTime) { if (m_minimapGenerationWindow != nullptr) { m_minimapGenerationWindow->process(); } - HFrameScenario scenario = std::make_shared(); { ViewPortDimensions dimension = { @@ -1493,6 +1544,21 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do {canvWidth, canvHeight} }; + if (m_currentScene) { + auto wowSceneFrameInput = std::make_shared>(); + wowSceneFrameInput->delta = deltaTime * (1000.0f); + wowSceneFrameInput->viewPortDimensions = dimension; + wowSceneFrameInput->invertedZ = true; + wowSceneFrameInput->clearScreen = true; + wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, + canvWidth, canvHeight, + m_api->getConfig()->doubleCameraDebug, + m_api->getConfig()->swapMainAndDebug, + m_currentScene); + + scenario->cullFunctions.push_back(m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput)); + } + auto uiFrameInput = std::make_shared>(); uiFrameInput->delta = deltaTime * (1000.0f); uiFrameInput->viewPortDimensions = dimension; @@ -1501,7 +1567,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto clearColor = m_api->getConfig()->clearColor; - scenario->cullFunctions.push_back(m_uiRenderer->createPlan(uiFrameInput)); + scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput)); // auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); // auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); @@ -1595,26 +1661,30 @@ bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { } void FrontendUI::openWMOSceneByfdid(int WMOFdid) { - currentScene = std::make_shared(m_api, WMOFdid); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_currentScene = std::make_shared(m_api, WMOFdid); m_api->camera->setCameraPos(0, 0, 0); } void FrontendUI::openMapByIdAndFilename(int mapId, std::string mapName, float x, float y, float z) { - currentScene = std::make_shared(m_api, mapId, mapName); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_currentScene = std::make_shared(m_api, mapId, mapName); m_api->camera = std::make_shared(); m_api->camera->setCameraPos(x,y,z); m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { - currentScene = std::make_shared(m_api, mapId, wdtFileId); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_currentScene = std::make_shared(m_api, mapId, wdtFileId); m_api->camera = std::make_shared(); m_api->camera->setCameraPos(x,y,z); m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementTextureIds) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); auto m2Scene = std::make_shared(m_api, m2Fdid); - currentScene = m2Scene; + m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(replacementTextureIds); @@ -1626,8 +1696,10 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText } void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + auto m2Scene = std::make_shared(m_api, m2FileName); - currentScene = m2Scene; + m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(replacementTextureIds); m_api->camera = std::make_shared(); @@ -1639,7 +1711,8 @@ void FrontendUI::unloadScene() { if (m_api->cacheStorage) { m_api->cacheStorage->actuallDropCache(); } - currentScene = std::make_shared(); + m_sceneRenderer = nullptr; + m_currentScene = std::make_shared(); } @@ -1771,26 +1844,6 @@ void FrontendUI::createDatabaseHandler() { filteredMapList = {}; } -void FrontendUI::update(HFrontendUIBufferCreate renderer) { - auto m_device = m_api->hDevice; - -// if (exporter != nullptr) { -// if (m_processor->completedAllJobs() && !m_api->hDevice->wasTexturesUploaded()) { -// exporterFramesReady++; -// } -// if (exporterFramesReady > 5) { -// exporter->saveToFile("model.gltf"); -// exporter = nullptr; -// } -// } - - auto *draw_data = ImGui::GetDrawData(); - if (draw_data == nullptr) - return; - - -} - void FrontendUI::createFontTexture() { ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 952ecd699..274efd9b7 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -24,6 +24,7 @@ #include "../../wowViewerLib/src/exporters/IExporter.h" #include "renderer/uiScene/IFrontendUIBufferCreate.h" #include "renderer/uiScene/FrontendUIRenderer.h" +#include "../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -71,7 +72,8 @@ class FrontendUI : public IScene, public std::enable_shared_from_this currentScene = nullptr; + std::shared_ptr m_sceneRenderer = nullptr; + std::shared_ptr m_currentScene = nullptr; bool tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index cc29c1f9c..d7df1dc51 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -83,7 +83,6 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtextur } HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - //TODO: return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 2efb52a64..d3e87315a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -360,9 +360,7 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config return hmesh; } -void Map::makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { -// std::cout << "Map::checkCulling finished called" << std::endl; -// std::cout << "m_wdtfile->getIsLoaded() = " << m_wdtfile->getIsLoaded() << std::endl; +void Map::makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { cullCreateVarsCounter.beginMeasurement(); Config* config = this->m_api->getConfig(); @@ -371,6 +369,9 @@ void Map::makeFramePlan(FrameInputParams &frameInputParams, HMap mathfu::mat4 &frustumMat = frameInputParams.frameParameters->matricesForCulling->perspectiveMat; mathfu::mat4 &lookAtMat4 = frameInputParams.frameParameters->matricesForCulling->lookAtMat; + mapRenderPlan->renderingMatrices = frameInputParams.frameParameters->cameraMatricesForRendering; + mapRenderPlan->deltaTime = frameInputParams.delta; + size_t adtRenderedThisFramePrev = mapRenderPlan->adtArray.size(); mapRenderPlan->adtArray = {}; mapRenderPlan->adtArray.reserve(adtRenderedThisFramePrev); @@ -1408,82 +1409,82 @@ void Map::doPostLoad(const HMapRenderPlan &renderPlan) { } }; -//void Map::update(const HMapRenderPlan &renderPlan) { -// mathfu::vec3 cameraVec3 = updateStage->cameraMatrices->cameraPos.xyz(); -// mathfu::mat4 &frustumMat = updateStage->cameraMatrices->perspectiveMat; -// mathfu::mat4 &lookAtMat = updateStage->cameraMatrices->lookAtMat; -// animTime_t deltaTime = updateStage->delta; -// -// Config* config = this->m_api->getConfig(); -// -// auto &m2ToDraw = renderPlan->m2Array.getDrawn(); -// { -// m2UpdateframeCounter.beginMeasurement(); -// -// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 200), -// [&](tbb::blocked_range r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto& m2Object = m2ToDraw[i]; -// m2Object->update(deltaTime, cameraVec3, lookAtMat); -// } -// }, tbb::simple_partitioner()); -// -// m2UpdateframeCounter.endMeasurement(); -// } -// -// wmoGroupUpdate.beginMeasurement(); -// for (const auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { -// if (wmoGroupObject == nullptr) continue; -// wmoGroupObject->update(); -// } -// wmoGroupUpdate.endMeasurement(); -// -// adtUpdate.beginMeasurement(); -// for (const auto &adtObjectRes : renderPlan->adtArray) { -// adtObjectRes->adtObject->update(deltaTime); -// } -// adtUpdate.endMeasurement(); -// -// //2. Calc distance every 100 ms -// m2calcDistanceCounter.beginMeasurement(); -// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), -// [&](tbb::blocked_range r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto &m2Object = m2ToDraw[i]; -// if (m2Object == nullptr) continue; -// m2Object->calcDistance(cameraVec3); -// } -// }, tbb::auto_partitioner() -// ); -// m2calcDistanceCounter.endMeasurement(); -// -// //Cleanup ADT every 10 seconds -// adtCleanupCounter.beginMeasurement(); -// if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { -// for (int i = 0; i < 64; i++) { -// for (int j = 0; j < 64; j++) { -// auto adtObj = mapTiles[i][j]; -// //Free obj, if it was unused for 10 secs -// if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { -//// std::cout << "try to free adtObj" << std::endl; -// -// mapTiles[i][j] = nullptr; -// } -// } -// } -// -// adtFreeLambda(false, true, this->m_currentTime + updateStage->delta); -// } -// adtCleanupCounter.endMeasurement(); -// this->m_currentTime += updateStage->delta; -// -// m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); -// m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); -// m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); -// m_api->getConfig()->m2calcDistanceTime = m2calcDistanceCounter.getTimePerFrame(); -// m_api->getConfig()->adtCleanupTime = adtCleanupCounter.getTimePerFrame(); -// //Collect meshes -//} +void Map::update(const HMapRenderPlan &renderPlan) { + mathfu::vec3 cameraVec3 = renderPlan->renderingMatrices->cameraPos.xyz(); + mathfu::mat4 &frustumMat = renderPlan->renderingMatrices->perspectiveMat; + mathfu::mat4 &lookAtMat = renderPlan->renderingMatrices->lookAtMat; + animTime_t deltaTime = renderPlan->deltaTime; + + Config* config = this->m_api->getConfig(); + + auto &m2ToDraw = renderPlan->m2Array.getDrawn(); + { + m2UpdateframeCounter.beginMeasurement(); + + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 200), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto& m2Object = m2ToDraw[i]; + m2Object->update(deltaTime, cameraVec3, lookAtMat); + } + }, tbb::simple_partitioner()); + + m2UpdateframeCounter.endMeasurement(); + } + + wmoGroupUpdate.beginMeasurement(); + for (const auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->update(); + } + wmoGroupUpdate.endMeasurement(); + + adtUpdate.beginMeasurement(); + for (const auto &adtObjectRes : renderPlan->adtArray) { + adtObjectRes->adtObject->update(deltaTime); + } + adtUpdate.endMeasurement(); + + //2. Calc distance every 100 ms + m2calcDistanceCounter.beginMeasurement(); + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object == nullptr) continue; + m2Object->calcDistance(cameraVec3); + } + }, tbb::auto_partitioner() + ); + m2calcDistanceCounter.endMeasurement(); + + //Cleanup ADT every 10 seconds + adtCleanupCounter.beginMeasurement(); + if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + auto adtObj = mapTiles[i][j]; + //Free obj, if it was unused for 10 secs + if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { +// std::cout << "try to free adtObj" << std::endl; + + mapTiles[i][j] = nullptr; + } + } + } + + adtFreeLambda(false, true, this->m_currentTime + deltaTime); + } + adtCleanupCounter.endMeasurement(); + this->m_currentTime += deltaTime; + + m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); + m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); + m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); + m_api->getConfig()->m2calcDistanceTime = m2calcDistanceCounter.getTimePerFrame(); + m_api->getConfig()->adtCleanupTime = adtCleanupCounter.getTimePerFrame(); + //Collect meshes +} void Map::updateBuffers(const HMapRenderPlan &renderPlan) { for (auto &m2Object : renderPlan->m2Array.getDrawn()) { diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index fffb899d2..b576dfdad 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -203,7 +203,7 @@ class Map : public IScene, public IMapApi { // std::cout << "Map destroyed " << std::endl; }; - void makeFramePlan(FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); + void makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); void setMandatoryADTs(std::vector> &mandatoryADTs) { m_mandatoryADT = mandatoryADTs; @@ -218,8 +218,6 @@ class Map : public IScene, public IMapApi { void update(const HMapRenderPlan &renderPlan); void updateBuffers(const HMapRenderPlan &renderPlan); -// void produceUpdateStage(HUpdateStage &updateStage) override; -// void produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) override; private: void checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, diff --git a/wowViewerLib/src/engine/texture/BlpTexture.cpp b/wowViewerLib/src/engine/texture/BlpTexture.cpp index a37271983..7da38e0ed 100644 --- a/wowViewerLib/src/engine/texture/BlpTexture.cpp +++ b/wowViewerLib/src/engine/texture/BlpTexture.cpp @@ -148,12 +148,11 @@ HMipmapsVector parseMipmaps(BlpFile *blpFile, TextureFormat textureFormat) { void BlpTexture::process(HFileContent blpFile, const std::string &fileName) { /* Post load for texture data. Can't define them through declarative definition */ /* Determine texture format */ -// std::cout << fileName << std::endl; int fileSize = blpFile->size(); -// std::cout << fileSize << std::endl; - BlpFile *pBlpFile = (BlpFile *) &(*blpFile.get())[0]; + BlpFile *pBlpFile = (BlpFile *) blpFile->data(); if (pBlpFile->fileIdent != '2PLB') { - std::cout << pBlpFile->fileIdent; + std::cerr << "Wrong ident for BLP2 file " << pBlpFile->fileIdent << " " << fileName << std::endl; + throw std::runtime_error("Wrong ident for BLP2 file"); } this->m_textureFormat = getTextureType(pBlpFile); diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index c5d080f20..7381e6a97 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -19,13 +19,15 @@ typedef std::function CullLambda; template class IRendererParameters : public std::enable_shared_from_this> { public: + virtual ~IRendererParameters() = default; + virtual std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) = 0; virtual std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) = 0; //This function is to be used to display data in UI virtual std::shared_ptr getLastCreatedPlan() = 0; - CullLambda createPlan(const std::shared_ptr> &frameInputParams) { + CullLambda createCullUpdateRenderChain(const std::shared_ptr> &frameInputParams) { auto this_s = this->shared_from_this(); return [frameInputParams, this_s]() -> SceneUpdateLambda { diff --git a/wowViewerLib/src/renderer/IRenderer.h b/wowViewerLib/src/renderer/IRenderer.h index ce53f1392..4fea6cadd 100644 --- a/wowViewerLib/src/renderer/IRenderer.h +++ b/wowViewerLib/src/renderer/IRenderer.h @@ -9,7 +9,7 @@ class IRenderer { public: - virtual ~IRenderer() = 0; + virtual ~IRenderer() = default; }; typedef std::shared_ptr HIRenderer; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 819dbf23d..b7be95738 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -10,6 +10,7 @@ class IMapSceneBufferCreate { public: + virtual ~IMapSceneBufferCreate() = default; virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h index aa1d83663..4e7592bad 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h @@ -9,9 +9,12 @@ #include "../../engine/CameraMatrices.h" struct MapSceneParams { + std::shared_ptr scene; HCameraMatrices matricesForCulling; HCameraMatrices cameraMatricesForRendering; HCameraMatrices cameraMatricesForDebugCamera; + + mathfu::vec4 clearColor; }; typedef std::shared_ptr HMapSceneParams; diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index b18ba6345..fa44a6972 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -15,6 +15,7 @@ struct MapRenderPlan { int areaId = -1; int parentAreaId = -1; + animTime_t deltaTime; HCameraMatrices renderingMatrices; //Result of culling test diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index f70b05b9a..eb121bf9e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -3,3 +3,16 @@ // #include "MapSceneRenderer.h" + +std::shared_ptr +MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { +// auto &scenes = frameInputParams->frameParameters->scene; + +// for (auto &scene : scenes) { + auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); + auto mapPlan = std::make_shared(); + mapScene->makeFramePlan(*frameInputParams, mapPlan); +// } + + return mapPlan; +} diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 4ca4096dc..8616c6c73 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -14,7 +14,9 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer() = default; - ~MapSceneRenderer() override = 0; + ~MapSceneRenderer() override = default; + + std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override;; }; //typedef FrameInputParams MapSceneRendererInputParams; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h index ee1fe9f96..904419a48 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h @@ -10,6 +10,7 @@ #include "MapSceneRenderer.h" class MapSceneRendererFactory { +public: static std::shared_ptr createForwardRenderer(HGDevice &device); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index ccdc7a6fa..a674f623a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -3,6 +3,7 @@ // #include "MapSceneRenderForwardVLK.h" +#include "../../vulkan/IRenderFunctionVLK.h" MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { @@ -44,14 +45,18 @@ HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { - return nullptr; + auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); + + mapScene->doPostLoad(framePlan); + mapScene->update(framePlan); + + + return createRenderFuncVLK([](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + + }); } std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { return nullptr; } -std::shared_ptr -MapSceneRenderForwardVLK::processCulling(const std::shared_ptr> &frameInputParams) { - return nullptr; -} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 9be65be59..bcc741c5c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -12,8 +12,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { public: explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); + ~MapSceneRenderForwardVLK() override = default; - std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; std::shared_ptr getLastCreatedPlan() override; From b9dfde320db66d88bc3106cbe9f5240164111724 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 1 Mar 2023 07:41:59 +0200 Subject: [PATCH 043/212] propagated renderer class into bunch of places --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 11 ---- .../glsl/forwardRendering/adtShader.vert | 5 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 12 +--- wowViewerLib/src/engine/geometry/m2Geom.h | 2 +- .../src/engine/geometry/wmoGroupGeom.cpp | 60 ++++++------------- .../src/engine/geometry/wmoGroupGeom.h | 17 +----- .../src/engine/objects/adt/adtObject.cpp | 21 +------ .../src/engine/objects/m2/m2Object.cpp | 6 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/scenes/map.cpp | 32 +++++----- wowViewerLib/src/engine/objects/scenes/map.h | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 19 +++--- .../src/engine/objects/wmo/wmoGroupObject.h | 8 +-- .../src/engine/objects/wmo/wmoObject.cpp | 19 +----- .../src/engine/objects/wmo/wmoObject.h | 2 +- .../src/engine/persistance/adtFile.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 3 +- .../src/gapi/interface/meshes/IMesh.h | 9 --- .../src/renderer/frame/FrameInputParams.h | 2 - .../renderer/mapScene/IMapSceneBufferCreate.h | 30 ++++++++++ .../src/renderer/mapScene/MapSceneParams.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 1 + .../src/renderer/mapScene/MapSceneRenderer.h | 31 +++++++++- .../vulkan/MapSceneRenderForwardVLK.cpp | 33 +++++++++- .../vulkan/MapSceneRenderForwardVLK.h | 4 ++ 25 files changed, 160 insertions(+), 180 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index d7df1dc51..0b9ca600a 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -68,14 +68,6 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtextur }) .toMaterial(); -// -// std::vector> ubos = {m_imguiUbo->getSubBuffer()}; -// std::vector texturesVLK = {std::dynamic_pointer_cast(materialTemplate.texture)}; -// auto material = std::make_shared(m_device, -// "imguiShader", "imguiShader", -// ubos, -// texturesVLK); - std::weak_ptr weakPtr = material; m_materialCache[weakTexture] = weakPtr; @@ -116,9 +108,6 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( const auto &meshVlk = std::dynamic_pointer_cast(mesh); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); -// auto indexBuffer = (vulkanBindings->m_indexBuffer.get())->g_hIndexBuffer; -// auto vertexBuffer = ((GVertexBufferVLK *)binding->m_bindings[0].vertexBuffer.get())->g_hVertexBuffer; - //1. Bind VBOs swapChainCmd.bindVertexBuffers(vulkanBindings->getVertexBuffers()); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 8bb322838..70a279e98 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -13,7 +13,6 @@ layout(location = 0) in vec3 aPos; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; -layout(location = 4) in float aIndex; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; @@ -47,8 +46,8 @@ void main() { X 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ - float iX = mod(aIndex, 17.0); - float iY = floor(aIndex/17.0); + float iX = mod(gl_VertexIndex, 17.0); + float iY = floor(gl_VertexIndex/17.0); if (iX > 8.01) { iY = iY + 0.5; diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index a2e9f443f..5d34273f0 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -200,16 +200,6 @@ chunkDef M2Geom::m2FileTable = { } }; -static GBufferBinding staticM2Bindings[6] = { - {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 48, 0 }, - {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, 48, 12}, // bonesWeight - {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, 48, 16}, // bones - {+m2Shader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, 48, 20}, // normal - {+m2Shader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 48, 32}, // texcoord - {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, 48, 40} // texcoord -}; - - void M2Geom::process(HFileContent m2File, const std::string &fileName) { this->m2File = m2File; @@ -323,7 +313,7 @@ void M2Geom::initTracks(CM2SequenceLoad * cm2SequenceLoad) { } HGVertexBuffer M2Geom::getVBO(const HMapSceneBufferCreate &sceneRenderer) { - if (vertexVbo.get() == nullptr) { + if (vertexVbo == nullptr) { if (m_m2Data->vertices.size == 0) { return nullptr; } diff --git a/wowViewerLib/src/engine/geometry/m2Geom.h b/wowViewerLib/src/engine/geometry/m2Geom.h index ce0008942..733b80e67 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.h +++ b/wowViewerLib/src/engine/geometry/m2Geom.h @@ -72,7 +72,7 @@ class M2Geom : public PersistentFile { bool useFileId = false; int m_modelFileId; - HGVertexBuffer vertexVbo = HGVertexBuffer(nullptr); + HGVertexBuffer vertexVbo = nullptr; std::unordered_map vaoMap; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 80aed2501..0d92d67ab 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -384,28 +384,15 @@ HGIndexBuffer WmoGroupGeom::getIBO(const HMapSceneBufferCreate &sceneRenderer) { return indexVBO; } -static const std::array staticWMOBindings = {{ - {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, pos) }, - {+wmoShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, normal)}, - {+wmoShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate)}, - {+wmoShader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate2)}, - {+wmoShader::Attribute::aTexCoord3, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate3)}, - {+wmoShader::Attribute::aTexCoord4, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate4)}, - {+wmoShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color)}, - {+wmoShader::Attribute::aColor2, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color2)}, - {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} -}}; - -PACK( -struct LiquidVertexFormat { - mathfu::vec4_packed pos_transp; - mathfu::vec2_packed uv; -}); - -static GBufferBinding staticWMOWaterBindings[2] = { - {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, - {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)} -}; +HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { + if (vertexBufferBindings == nullptr) { + + vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer)); + } + + return vertexBufferBindings; +} + int WmoGroupGeom::getLegacyWaterType(int a) { a = a + 1; @@ -435,10 +422,8 @@ int WmoGroupGeom::getLegacyWaterType(int a) { return a; } -HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &device) { - return nullptr; - //TODO: - /* +HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { + if (vertexWaterBufferBindings == nullptr) { if (this->m_mliq == nullptr) return nullptr; @@ -447,10 +432,8 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi mathfu::vec3 pos(m_mliq->basePos.x, m_mliq->basePos.y, m_mliq->basePos.z); - for (int j = 0; j < m_mliq->yverts; j++) - { - for (int i = 0; i < m_mliq->xverts; i++) - { + for (int j = 0; j < m_mliq->yverts; j++) { + for (int i = 0; i < m_mliq->xverts; i++) { int p = j*m_mliq->xverts + i; LiquidVertexFormat lvfVertex; @@ -499,31 +482,22 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HGDevice &devi } } - waterIBO = device->createIndexBuffer(); + waterIBO = sceneRenderer->createWaterIndexBuffer(iboBuffer.size() * sizeof(uint16_t)); waterIBO->uploadData( &iboBuffer[0], iboBuffer.size() * sizeof(uint16_t)); - waterVBO = device->createVertexBuffer(); + waterVBO = sceneRenderer->createWaterVertexBuffer(lVertices.size() * sizeof(LiquidVertexFormat)); waterVBO->uploadData( &lVertices[0], lVertices.size() * sizeof(LiquidVertexFormat) ); - vertexWaterBufferBindings = device->createVertexBufferBindings(); - vertexWaterBufferBindings->setIndexBuffer(waterIBO); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = waterVBO; - - vertexBinding.bindings = std::vector(&staticWMOWaterBindings[0], &staticWMOWaterBindings[1]); - - vertexWaterBufferBindings->addVertexBufferBinding(vertexBinding); - vertexWaterBufferBindings->save(); + vertexWaterBufferBindings = sceneRenderer->createWaterVAO(waterVBO, waterIBO); waterIndexSize = iboBuffer.size(); } return vertexWaterBufferBindings; - */ + } diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index 5058c14b2..b75e56d79 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -12,20 +12,6 @@ #include "../../include/sharedFile.h" #include "../../renderer/mapScene/IMapSceneBufferCreate.h" -PACK( - struct WMOVertex { - C3Vector pos; - C3Vector normal; - C2Vector textCoordinate; - C2Vector textCoordinate2; - C2Vector textCoordinate3; - C2Vector textCoordinate4; - CImVector color; - CImVector color2; - CImVector colorSecond; - } -); - class WmoGroupGeom : public PersistentFile { public: WmoGroupGeom(std::string fileName){ m_fileName = fileName; }; @@ -40,7 +26,8 @@ class WmoGroupGeom : public PersistentFile { bool hasWater() const {return m_mliq != nullptr; }; - HGVertexBufferBindings getWaterVertexBindings(const HGDevice &device); + HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer); + HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer); int getFileDataId() const {return m_fileDataId;} const std::string &getFileName() const {return m_fileName;} diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 4cf65057a..31734741b 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -17,22 +17,13 @@ PACK( struct AdtVertex { mathfu::vec3_packed pos; - float helpIndex = 0.0f; mathfu::vec3_packed normal; mathfu::vec4_packed mccv; mathfu::vec4_packed mclv; } ); -PACK( - struct LiquidVertexFormat { - mathfu::vec4_packed pos_transp; - mathfu::vec2_packed uv; - } -); - static std::array adtVertexBufferBinding = {{ - {+adtShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, helpIndex)}, {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, @@ -44,15 +35,6 @@ static std::array adtVertexBufferLODBinding = {{ {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} }}; -static GBufferBinding staticWaterBindings[2] = { - {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, - {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)}, -// {+waterShader::Attribute::aDepth, 1, GBindingType::GFLOAT, false, 24, 0 }, -// {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 24, 4}, - -}; - - void AdtObject::loadingFinished() { // std::cout << "AdtObject::loadingFinished finished called"; @@ -482,8 +464,7 @@ void AdtObject::createVBO() { for (int i = 0; i <= m_adtFile->mcnkRead; i++) { for (int j = 0; j < 9 * 9 + 8 * 8; j++) { AdtVertex &adtVertex = vboArray.emplace_back(); - /* 1.1 help index */ - adtVertex.helpIndex = j; + /* 1.2 Heights */ float iX = fmod(j, 17.0f); float iY = floor(j/17.0f); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 7591d6a95..a585a0abb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -888,7 +888,7 @@ void M2Object::doLoadMainFile(){ this->createAABB(); } -void M2Object:: doLoadGeom(){ +void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ //0. If loading procedures were already done - exit if (this->m_loaded) return; @@ -934,7 +934,7 @@ void M2Object:: doLoadGeom(){ //3. Do post load procedures m_skinGeom->fixData(m_m2Geom->getM2Data()); - this->createVertexBindings(); + this->createVertexBindings(sceneRenderer); this->createMeshes(); m_boneMasterData = std::make_shared(m_m2Geom, m_skelGeom, m_parentSkelGeom); @@ -1885,7 +1885,7 @@ HBlpTexture M2Object::getHardCodedTexture(int textureInd) { return texture; } -void M2Object::createVertexBindings() { +void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; //2. Create buffer binding and fill it diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index d958e8906..c9b34d0cb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -263,7 +263,7 @@ class M2Object { bool getHasBoundingBox() {return m_hasAABB;} void doLoadMainFile(); - void doLoadGeom(); + void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); void uploadGeneratorBuffers(mathfu::mat4 &viewMat); M2CameraResult updateCamera(double deltaTime, int cameraViewId); @@ -288,7 +288,7 @@ class M2Object { void drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); - void createVertexBindings(); + void createVertexBindings(const HMapSceneBufferCreate &sceneRenderer); int getCameraNum() { if (!getGetIsLoaded()) return 0; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index d3e87315a..070884056 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -22,13 +22,13 @@ #endif #include "../../algorithms/mathHelper_culling.h" -static GBufferBinding fullScreen[1] = { +std::array fullScreen = {{ {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, -}; +}}; -static GBufferBinding skyConusBinding[1] = { +std::array skyConusBinding = {{ {+drawQuad::Attribute::position, 4, GBindingType::GFLOAT, false, 0, 0}, -}; +}}; std::array skyConusVBO = { { @@ -262,7 +262,7 @@ std::array skyConusIBO = { HGVertexBufferBindings createSkyBindings(IDevice *device) { //TODO: - /* + auto skyIBO = device->createIndexBuffer(); skyIBO->uploadData( skyConusIBO.data(), @@ -277,19 +277,15 @@ HGVertexBufferBindings createSkyBindings(IDevice *device) { auto skyBindings = device->createVertexBufferBindings(); skyBindings->setIndexBuffer(skyIBO); - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = skyVBO; - - vertexBinding.bindings = std::vector(&skyConusBinding[0], &skyConusBinding[1]); - - skyBindings->addVertexBufferBinding(vertexBinding); + skyBindings->addVertexBufferBinding(skyVBO, + std::vector(skyConusBinding.begin(), skyConusBinding.end())); skyBindings->save(); -*/ + return nullptr; } -Map::Map(HApiContainer api, int mapId, std::string mapName) { +Map::Map(HApiContainer api, int mapId, const std::string &mapName) { initMapTiles(); m_mapId = mapId; m_api = api; this->mapName = mapName; @@ -1330,7 +1326,7 @@ void Map::createAdtFreeLamdas() { -void Map::doPostLoad(const HMapRenderPlan &renderPlan) { +void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan) { int processedThisFrame = 0; int wmoProcessedThisFrame = 0; int wmoGroupsProcessedThisFrame = 0; @@ -1341,17 +1337,17 @@ void Map::doPostLoad(const HMapRenderPlan &renderPlan) { } for (auto &m2Object : renderPlan->m2Array.getToLoadGeom()) { if (m2Object == nullptr) continue; - m2Object->doLoadGeom(); + m2Object->doLoadGeom(sceneRenderer); } // } for (auto &wmoObject : renderPlan->wmoArray.getToLoad()) { if (wmoObject == nullptr) continue; - wmoObject->doPostLoad(); + wmoObject->doPostLoad(sceneRenderer); } for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToLoad()) { if (wmoGroupObject == nullptr) continue; - wmoGroupObject->doPostLoad(); + wmoGroupObject->doPostLoad(sceneRenderer); wmoGroupsProcessedThisFrame++; if (wmoGroupsProcessedThisFrame > 20) break; } @@ -1396,7 +1392,7 @@ void Map::doPostLoad(const HMapRenderPlan &renderPlan) { GVertexBufferBinding vertexBinding; vertexBinding.vertexBuffer = quadVBO; - vertexBinding.bindings = std::vector(&fullScreen[0], &fullScreen[1]); + vertexBinding.bindings = std::vector(fullScreen.begin(), fullScreen.end()); quadBindings->addVertexBufferBinding(vertexBinding); quadBindings->save(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index b576dfdad..d5b73a903 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -161,7 +161,7 @@ class Map : public IScene, public IMapApi { explicit Map() { } public: - explicit Map(HApiContainer api, int mapId, std::string mapName);; + explicit Map(HApiContainer api, int mapId, const std::string &mapName);; explicit Map(HApiContainer api, int mapId, int wdtFileDataId) { initMapTiles(); @@ -214,7 +214,7 @@ class Map : public IScene, public IMapApi { m_adtConfigHolder = adtConfig; } - void doPostLoad(const HMapRenderPlan &renderPlan); + void doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan); void update(const HMapRenderPlan &renderPlan); void updateBuffers(const HMapRenderPlan &renderPlan); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 4c3799504..56f4d0bef 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -294,7 +294,7 @@ static const struct { }; -bool WmoGroupObject::doPostLoad() { +bool WmoGroupObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (this->m_loaded) return false; if (!this->m_loading) { @@ -304,7 +304,7 @@ bool WmoGroupObject::doPostLoad() { if ((m_geom == nullptr) || (m_geom->getStatus() != FileStatus::FSLoaded) || (!m_wmoApi->isLoaded())) return false; - this->postLoad(); + this->postLoad(sceneRenderer); this->m_loaded = true; this->m_loading = false; return true; @@ -385,18 +385,18 @@ void WmoGroupObject::startLoading() { } } -void WmoGroupObject::postLoad() { +void WmoGroupObject::postLoad(const HMapSceneBufferCreate &sceneRenderer) { this->m_useLocalLightingForM2 = ((m_geom->mogp->flags.INTERIOR) > 0) && ((m_geom->mogp->flags.EXTERIOR_LIT) == 0); m_localGroupBorder = m_geom->mogp->boundingBox; this->createWorldGroupBB(m_geom->mogp->boundingBox, *m_modelMatrix); this->loadDoodads(); - this->createMeshes(); - this->createWaterMeshes(); + this->createMeshes(sceneRenderer); + this->createWaterMeshes(sceneRenderer); } -void WmoGroupObject::createMeshes() { +void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { Config *config = m_api->getConfig(); int minBatch = config->wmoMinBatch; @@ -410,8 +410,7 @@ void WmoGroupObject::createMeshes() { PointerChecker &materials = m_wmoApi->getMaterials(); HGDevice device = m_api->hDevice; - //TODO: - HGVertexBufferBindings binding = nullptr; //m_geom->getVertexBindings(device); + HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer); // vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); @@ -626,10 +625,10 @@ void WmoGroupObject::setLiquidType() { } } -void WmoGroupObject::createWaterMeshes() { +void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(device); + HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer); if (binding == nullptr) return; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index a18ff1ed3..8f0640d66 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -47,7 +47,7 @@ class WmoGroupObject { bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; - bool doPostLoad(); + bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); void update(); void uploadGeneratorBuffers(); void checkGroupFrustum(bool &drawDoodads, bool &drawGroup, @@ -101,9 +101,9 @@ class WmoGroupObject { void updateWorldGroupBBWithM2(); void checkDoodads(M2ObjectListContainer &wmoM2Candidates); - void postLoad(); - void createMeshes(); - void createWaterMeshes(); + void postLoad(const HMapSceneBufferCreate &sceneRenderer); + void createMeshes(const HMapSceneBufferCreate &sceneRenderer); + void createWaterMeshes(const HMapSceneBufferCreate &sceneRenderer); int to_wmo_liquid (int x); void setLiquidType(); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 616e9a736..7e4c3dd41 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -320,7 +320,7 @@ void WmoObject::createWorldPortals() { } } -bool WmoObject::doPostLoad() { +bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (mainGeom != nullptr && mainGeom->getStatus() == FileStatus::FSLoaded){ this->createGroupObjects(); @@ -351,23 +351,6 @@ bool WmoObject::doPostLoad() { return false; } -// for (auto &groupObject : groupObjects) { -// if (groupsProcessedThisFrame > 3) return false; -// groupObject->doPostLoad(); -// } -// for (auto &groupObjectLod : groupObjectsLod1) { -// if (groupsProcessedThisFrame > 3) return false; -// if (groupObjectLod != nullptr) { -// if (groupObjectLod->doPostLoad()) groupsProcessedThisFrame++;; -// } -// } -// for (auto &groupObjectLod2 : groupObjectsLod2) { -// if (groupsProcessedThisFrame > 3) return false; -// if (groupObjectLod2 != nullptr) { -// if (groupObjectLod2->doPostLoad()) groupsProcessedThisFrame++;; -// } -// } - return false; } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index eeab79280..4a8fb7ab3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -126,7 +126,7 @@ class WmoObject : public IWmoApi { void checkFog(mathfu::vec3 &cameraPos, std::vector &fogResults); - bool doPostLoad(); + bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); void update(); void uploadGeneratorBuffers(); diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index f0643923f..a470f5cf5 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -596,8 +596,8 @@ inline void addSquare(int offset, int x, int y, std::vector &strips) { void AdtFile::createTriangleStrip() { if (mcnkRead < 0) return; -// strips = std::vector(); -// stripOffsets = std::vector(); + strips = std::vector(); + stripOffsets = std::vector(); for (int i = 0; i <= mcnkRead; i++) { SMChunk &mcnkObj = mapTile[i]; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index de002d162..508cceb7d 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -79,7 +79,7 @@ struct adtLodShader { struct adtShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; @@ -192,7 +192,6 @@ const std::unordered_map> attributesPe { "aColor", 1}, { "aVertexLighting", 2}, { "aNormal", 3}, - { "aIndex", 4}, } }, { "drawBBShader", diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index c7b8650fb..041542cc0 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -55,21 +55,12 @@ class gMeshTemplate { public: gMeshTemplate(HGVertexBufferBindings bindings) : bindings(bindings) {} HGVertexBufferBindings bindings; - HGShaderPermutation shader; MeshType meshType = MeshType::eGeneralMesh; - int8_t triCCW = 1; //counter-clockwise - bool depthWrite = true; - bool depthCulling = true; - bool backFaceCulling = true; - EGxBlendEnum blendMode; bool skybox = false; - uint8_t colorMask = 0xFF; - int start; int end; - DrawElementMode element; std::vector texture = {}; bool scissorEnabled = false; diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index cd00d6480..29cd0472b 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -6,8 +6,6 @@ #define AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H #include -#include "../../engine/CameraMatrices.h" -#include "../../engine/objects/iScene.h" #include "../../include/iostuff.h" struct ViewPortDimensions{ diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index b7be95738..5bb256d55 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -7,10 +7,40 @@ #include #include "../../gapi/interface/IDevice.h" +#include "../../engine/persistance/header/commonFileStructs.h" + + +PACK( + struct WMOVertex { + C3Vector pos; + C3Vector normal; + C2Vector textCoordinate; + C2Vector textCoordinate2; + C2Vector textCoordinate3; + C2Vector textCoordinate4; + CImVector color; + CImVector color2; + CImVector colorSecond; + } +); + +PACK( + struct LiquidVertexFormat { + mathfu::vec4_packed pos_transp; + mathfu::vec2_packed uv; + } +); + class IMapSceneBufferCreate { public: virtual ~IMapSceneBufferCreate() = default; + + virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; +// virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h index 4e7592bad..b6941cc0b 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h @@ -7,6 +7,7 @@ #include "../../engine/CameraMatrices.h" +#include "../../engine/objects/iScene.h" struct MapSceneParams { std::shared_ptr scene; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index eb121bf9e..d2443a58c 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -3,6 +3,7 @@ // #include "MapSceneRenderer.h" +#include "../../engine/objects/scenes/map.h" std::shared_ptr MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 8616c6c73..091cb16f1 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -8,8 +8,37 @@ #include "../IRenderer.h" #include "../IRenderParameters.h" -#include "../../engine/objects/scenes/map.h" #include "IMapSceneBufferCreate.h" +#include "MapSceneParams.h" +#include "MapScenePlan.h" + +#include "../../engine/shader/ShaderDefinitions.h" + +static const std::array staticWMOBindings = {{ + {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, pos) }, + {+wmoShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, normal)}, + {+wmoShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate)}, + {+wmoShader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate2)}, + {+wmoShader::Attribute::aTexCoord3, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate3)}, + {+wmoShader::Attribute::aTexCoord4, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate4)}, + {+wmoShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color)}, + {+wmoShader::Attribute::aColor2, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color2)}, + {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} +}}; + +static std::array staticWaterBindings = {{ + {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, + {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)} +}}; + +static std::array staticM2Bindings = {{ + {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 48, 0 }, + {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, 48, 12}, // bonesWeight + {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, 48, 16}, // bones + {+m2Shader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, 48, 20}, // normal + {+m2Shader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 48, 32}, // texcoord + {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, 48, 40} // texcoord +}}; class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index a674f623a..0b25941a0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -4,12 +4,40 @@ #include "MapSceneRenderForwardVLK.h" #include "../../vulkan/IRenderFunctionVLK.h" +#include "../../../engine/objects/scenes/map.h" MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { } +// ------------------ +// Buffer creation +// ------------------ + +HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto wmoVAO = m_device->createVertexBufferBindings(); + wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); + wmoVAO->setIndexBuffer(indexBuffer); + + return wmoVAO; +} +HGVertexBufferBindings MapSceneRenderForwardVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2VAO = m_device->createVertexBufferBindings(); + m2VAO->addVertexBufferBinding(vertexBuffer, std::vector(staticM2Bindings.begin(), staticM2Bindings.end())); + m2VAO->setIndexBuffer(indexBuffer); + + return m2VAO; +} +HGVertexBufferBindings MapSceneRenderForwardVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto waterVAO = m_device->createVertexBufferBindings(); + waterVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); + waterVAO->setIndexBuffer(indexBuffer); + + return waterVAO; +}; -//Buffer creation HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { return HGVertexBuffer(); } @@ -45,9 +73,10 @@ HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + auto hthis = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - mapScene->doPostLoad(framePlan); + mapScene->doPostLoad(hthis, framePlan); mapScene->update(framePlan); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index bcc741c5c..6b3538658 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -21,6 +21,10 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { //------------------------------------- // Buffer creation //------------------------------------- + virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; From e7270c53e1e4275a9c7a2f9e2209cdab9672fece Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 5 Mar 2023 13:08:36 +0200 Subject: [PATCH 044/212] get rid of pipeline template params from mesh template --- .../renderer/uiScene/FrontendUIRenderer.cpp | 4 -- .../vulkan/FrontendUIRenderForwardVLK.cpp | 8 +++- .../src/engine/managers/CRibbonEmitter.cpp | 24 +++++----- .../managers/particles/particleEmitter.cpp | 19 ++++---- .../src/engine/objects/ViewsObjects.cpp | 17 +++---- .../src/engine/objects/adt/adtObject.cpp | 15 ++++--- .../src/engine/objects/m2/m2Object.cpp | 45 ++++++++++--------- .../src/engine/objects/scenes/map.cpp | 35 ++++++--------- .../src/engine/objects/wmo/wmoGroupObject.cpp | 25 ++++++----- .../engine/persistance/header/wmoFileHeader.h | 2 +- .../src/gapi/interface/meshes/IMesh.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 8 ++-- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 24 +++++----- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 2 + wowViewerLib/src/gapi/vulkan/GPipelineVLK.h | 11 +++++ .../src/gapi/vulkan/TextureManagerVLK.cpp | 5 ++- .../src/gapi/vulkan/TextureManagerVLK.h | 5 ++- .../CommandBufferRecorder.cpp | 31 ++++++++++--- .../CommandBufferRecorder.h | 6 ++- .../vulkan/materials/ISimpleMaterialVLK.cpp | 24 +++++++++- .../vulkan/materials/ISimpleMaterialVLK.h | 3 ++ .../vulkan/materials/MaterialBuilderVLK.cpp | 3 ++ .../vulkan/materials/MaterialBuilderVLK.h | 1 + .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 4 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 29 +----------- .../src/gapi/vulkan/meshes/GMeshVLK.h | 17 +++---- .../renderer/mapScene/IMapSceneBufferCreate.h | 5 ++- .../src/renderer/mapScene/MapSceneRenderer.h | 8 +++- .../vulkan/MapSceneRenderForwardVLK.cpp | 16 +++++++ .../vulkan/MapSceneRenderForwardVLK.h | 11 +++-- 30 files changed, 238 insertions(+), 171 deletions(-) diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 21d46260e..6a703fb58 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -90,10 +90,6 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrgetIsVulkanAxisSystem()) { diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 0b9ca600a..ceb344ee6 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -129,8 +129,12 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( //5. Set view port swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); - //6. Set view port - swapChainCmd.setScissors(); + //6. Set scissors + if (meshVlk->scissorEnabled()) { + swapChainCmd.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); + } else { + swapChainCmd.setDefaultScissors(); + } //7. Draw the mesh swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 6b6593ef6..fea6fb20e 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -5,6 +5,7 @@ #include "../shader/ShaderDefinitions.h" #include "../../../3rdparty/mathfu/include/mathfu/glsl_mappings.h" #include "../../gapi/UniformBufferStructures.h" +#include "../../gapi/interface/materials/IMaterial.h" static std::array staticRibbonBindings = {{ {+ribbonShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, pos) }, // 0 @@ -114,31 +115,32 @@ void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &mat HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); - //Create mesh - gMeshTemplate meshTemplate(frame[k].m_bindings); - meshTemplate.depthWrite = !(material.flags & 0x10); - meshTemplate.depthCulling = !(material.flags & 0x8); - meshTemplate.backFaceCulling = !(material.flags & 0x4); + //TODO: + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; + pipelineTemplate.depthWrite = !(material.flags & 0x10);; + pipelineTemplate.depthCulling = !(material.flags & 0x8);; + pipelineTemplate.backFaceCulling = !(material.flags & 0x4);; + pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; - meshTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; //Let's assume ribbons are always at least transparent - if (meshTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + if (pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; } + //Create mesh + gMeshTemplate meshTemplate(frame[k].m_bindings); meshTemplate.start = 0; meshTemplate.end = 0; - meshTemplate.element = DrawElementMode::TRIANGLE_STRIP; meshTemplate.texture = std::vector(1, nullptr); HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); - - auto blendMode = meshTemplate.blendMode; + auto blendMode = pipelineTemplate.blendMode; auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; std::shared_ptr> meshRibbonWideBlockPS = nullptr; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index f3102c2a6..af9f95574 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -14,6 +14,7 @@ #include "../../persistance/header/M2FileHeader.h" #include "../../../gapi/UniformBufferStructures.h" #include "generators/CSplineGenerator.h" +#include "../../../gapi/interface/materials/IMaterial.h" HGIndexBuffer ParticleEmitter::m_indexVBO = nullptr; @@ -302,21 +303,21 @@ void ParticleEmitter::createMesh() { //Create mesh gMeshTemplate meshTemplate(frame[i].m_bindings); - + PipelineTemplate pipelineTemplate; uint8_t blendMode = m_data->old.blendingType; - meshTemplate.meshType = MeshType::eParticleMesh; - meshTemplate.depthWrite = blendMode <= 1; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; - - meshTemplate.blendMode = + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = blendMode <= 1; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = blendMode < PaticleBlendingModeToEGxBlendEnum1.size() ? PaticleBlendingModeToEGxBlendEnum1[blendMode] : EGxBlendEnum::GxBlend_Opaque; + + meshTemplate.meshType = MeshType::eParticleMesh; meshTemplate.start = 0; meshTemplate.end = 0; - meshTemplate.element = DrawElementMode::TRIANGLES; bool multitex = m_data->old.flags_per_number.hex_10000000 > 0; HBlpTexture tex0 = nullptr; @@ -335,7 +336,7 @@ void ParticleEmitter::createMesh() { } meshTemplate.texture.resize((multitex) ? 3 : 1); - auto l_blendMode = meshTemplate.blendMode; + auto l_blendMode = pipelineTemplate.blendMode; std::shared_ptr> meshParticleWideBlockPS = nullptr; meshParticleWideBlockPS->setUpdateHandler([this, l_blendMode](auto &data, const HFrameDependantData &frameDepedantData) { Particle::meshParticleWideBlockPS &blockPS = data; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 5dc971040..9faaec11e 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -11,6 +11,7 @@ #include "../algorithms/mathHelper_culling_sse.h" #endif #include "../algorithms/mathHelper_culling.h" +#include "../../gapi/interface/materials/IMaterial.h" void ExteriorView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { { @@ -142,21 +143,17 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st //Create mesh gMeshTemplate meshTemplate(portalPointsFrame.m_bindings); + PipelineTemplate pipelineTemplate; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = !apiContainer->getConfig()->renderPortalsIgnoreDepth; - meshTemplate.backFaceCulling = false; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = !apiContainer->getConfig()->renderPortalsIgnoreDepth; + pipelineTemplate.backFaceCulling = false; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - - //Let's assume ribbons are always at least transparent - if (meshTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - } + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; meshTemplate.start = 0; meshTemplate.end = indiciesArray.size(); - meshTemplate.element = DrawElementMode::TRIANGLES; std::shared_ptr> drawPortalShaderMeshWideBlockPS = nullptr; drawPortalShaderMeshWideBlockPS->setUpdateHandler([](auto &data, const HFrameDependantData &frameDepedantData) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 31734741b..4f75790fe 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -13,6 +13,7 @@ #include "../../persistance/header/adtFileHeader.h" #include "tbb/parallel_for.h" #include "tbb/blocked_range2d.h" +#include "../../../gapi/interface/materials/IMaterial.h" PACK( struct AdtVertex { @@ -636,17 +637,19 @@ void AdtObject::createMeshes() { HGShaderPermutation hgShaderPermutation = device->getShader("adtShader", "adtShader", nullptr); gMeshTemplate aTemplate(adtVertexBindings); + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.triCCW = 1; + pipelineTemplate.depthWrite = 1; + pipelineTemplate.depthCulling = 1; + pipelineTemplate.backFaceCulling = 1; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + aTemplate.meshType = MeshType::eAdtMesh; - aTemplate.triCCW = 1; - aTemplate.depthWrite = 1; - aTemplate.depthCulling = 1; - aTemplate.backFaceCulling = 1; - aTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; aTemplate.start = m_adtFile->stripOffsets[i] * 2; aTemplate.end = m_adtFile->stripOffsets[i + 1] - m_adtFile->stripOffsets[i]; - aTemplate.element = DrawElementMode::TRIANGLES; // aTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); // aTemplate.ubo[1] = nullptr; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index a585a0abb..a04dcb75e 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -16,6 +16,7 @@ #include "../../../gapi/interface/IOcclusionQuery.h" #include "../../../gapi/interface/IDevice.h" #include "../../../gapi/interface/meshes/IM2Mesh.h" +#include "../../../gapi/interface/materials/IMaterial.h" //Shader stuff enum class M2PixelShader : int { @@ -1256,19 +1257,19 @@ void M2Object::createBoundingBoxMesh() { HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", nullptr); //TODO: + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = EGxBlendEnum ::GxBlend_Alpha; + gMeshTemplate meshTemplate(/*m_api->hDevice->getBBVertexBinding()*/ nullptr); - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; // meshTemplate.colorMask = 0; meshTemplate.start = 0; meshTemplate.end = 36; - meshTemplate.blendMode = EGxBlendEnum ::GxBlend_Alpha; - - meshTemplate.element = DrawElementMode::TRIANGLES; - // std::shared_ptr> bbBlockVS = m_api->hDevice->createUniformBufferChunk(sizeof(bbModelWideBlockVS)); std::shared_ptr> bbBlockVS = nullptr; @@ -1352,16 +1353,17 @@ HGM2Mesh M2Object::createWaterfallMesh() { int renderFlagIndex = m2Batch->materialIndex; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; - meshTemplate.triCCW = 1; + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.triCCW = 1; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16)) * 2; meshTemplate.end = skinSection->indexCount; - meshTemplate.element = DrawElementMode::TRIANGLES; meshTemplate.skybox = m_boolSkybox; HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; @@ -1539,25 +1541,26 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", "m2Shader", &cacheRecord); gMeshTemplate meshTemplate(finalBufferBindings); + PipelineTemplate pipelineTemplate; int renderFlagIndex = m2Batch->materialIndex; auto renderFlag = m_m2Data->materials[renderFlagIndex]; - meshTemplate.depthWrite = !(renderFlag->flags & 0x10); - meshTemplate.depthCulling = !(renderFlag->flags & 0x8); - meshTemplate.backFaceCulling = !(renderFlag->flags & 0x4); - meshTemplate.triCCW = 1; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); + pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); + pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); + pipelineTemplate.triCCW = 1; if (overrideBlend) { - meshTemplate.blendMode = blendMode; + pipelineTemplate.blendMode = blendMode; } else { - meshTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; - blendMode = meshTemplate.blendMode; + pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; + blendMode = pipelineTemplate.blendMode; } meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; - meshTemplate.element = DrawElementMode::TRIANGLES; meshTemplate.skybox = m_boolSkybox; HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 070884056..4f2008a02 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -21,14 +21,13 @@ #include "../../algorithms/mathHelper_culling_sse.h" #endif #include "../../algorithms/mathHelper_culling.h" +#include "../../../gapi/interface/materials/IMaterial.h" std::array fullScreen = {{ {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, }}; -std::array skyConusBinding = {{ - {+drawQuad::Attribute::position, 4, GBindingType::GFLOAT, false, 0, 0}, -}}; + std::array skyConusVBO = { { @@ -260,27 +259,19 @@ std::array skyConusIBO = { 121 , 97 , 121 , }; -HGVertexBufferBindings createSkyBindings(IDevice *device) { - //TODO: - - auto skyIBO = device->createIndexBuffer(); +HGVertexBufferBindings createSkyBindings(const HMapSceneBufferCreate &sceneRenderer) { + auto skyIBO = sceneRenderer->createSkyIndexBuffer(skyConusIBO.size() * sizeof(uint16_t)); skyIBO->uploadData( skyConusIBO.data(), skyConusIBO.size() * sizeof(uint16_t)); - auto skyVBO = device->createVertexBuffer(); + auto skyVBO = sceneRenderer->createSkyVertexBuffer(skyConusVBO.size() * sizeof(mathfu::vec4_packed)); skyVBO->uploadData( skyConusVBO.data(), skyConusVBO.size() * sizeof(mathfu::vec4_packed) ); - auto skyBindings = device->createVertexBufferBindings(); - skyBindings->setIndexBuffer(skyIBO); - - skyBindings->addVertexBufferBinding(skyVBO, - std::vector(skyConusBinding.begin(), skyConusBinding.end())); - skyBindings->save(); - + auto skyBindings = sceneRenderer->createSkyVAO(skyVBO, skyIBO); return nullptr; } @@ -333,16 +324,18 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config ///2. Create mesh auto shader = device->getShader("skyConus", "skyConus", nullptr); gMeshTemplate meshTemplate(skyBindings); + PipelineTemplate pipelineTemplate; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = conusFor0x4Sky ? EGxBlendEnum::GxBlend_Alpha : EGxBlendEnum::GxBlend_Opaque; + pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; + meshTemplate.meshType = MeshType::eGeneralMesh; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; meshTemplate.skybox = true; - meshTemplate.blendMode = conusFor0x4Sky ? EGxBlendEnum::GxBlend_Alpha : EGxBlendEnum::GxBlend_Opaque; meshTemplate.texture.resize(0); - meshTemplate.element = DrawElementMode::TRIANGLE_STRIP; if (conusFor0x4Sky) { meshTemplate.start = 198 * 2; meshTemplate.end = 102; @@ -1399,7 +1392,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende */ } if (skyMesh == nullptr) { - auto skyMeshBinding = createSkyBindings(m_api->hDevice.get()); + auto skyMeshBinding = createSkyBindings(sceneRenderer); skyMesh = createSkyMesh(m_api->hDevice.get(), skyMeshBinding, m_api->getConfig(), false); skyMesh0x4Sky = createSkyMesh(m_api->hDevice.get(), skyMeshBinding, m_api->getConfig(), true); } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 56f4d0bef..a2c357648 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -7,6 +7,7 @@ #include "../../../gapi/interface/IDevice.h" #include "../../../gapi/UniformBufferStructures.h" #include "../../persistance/header/wmoFileHeader.h" +#include "../../../gapi/interface/materials/IMaterial.h" #include /* @@ -480,15 +481,17 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { auto blendMode = material.blendMode; meshTemplate.meshType = MeshType::eWmoMesh; - meshTemplate.depthWrite = blendMode <= 1; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = !(material.flags.F_UNCULLED); - meshTemplate.blendMode = static_cast(blendMode); + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = blendMode <= 1; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = !(material.flags.F_UNCULLED); + + pipelineTemplate.blendMode = static_cast(blendMode); meshTemplate.start = renderBatch.first_index * 2; meshTemplate.end = renderBatch.num_indices; - meshTemplate.element = DrawElementMode::TRIANGLES; bool isSecondTextSpec = material.shader == 8; @@ -646,15 +649,18 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere HGShaderPermutation shaderPermutation = device->getShader("waterShader", "waterShader", nullptr); gMeshTemplate meshTemplate(binding); + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; auto blendMode = material.blendMode; float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; meshTemplate.meshType = MeshType::eWmoMesh; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + std::vector liquidTypeData; int basetextureFDID = 0; @@ -693,7 +699,6 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere meshTemplate.start = 0; meshTemplate.end = m_geom->waterIndexSize; - meshTemplate.element = DrawElementMode::TRIANGLES; auto l_liquidType = liquid_type; diff --git a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h index 658608c34..2a615fb24 100644 --- a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h @@ -38,7 +38,7 @@ struct SMOMaterial { uint32_t F_UNFOGGED : 1; // disable fog shading (rarely used) uint32_t F_UNCULLED : 1; // two-sided uint32_t F_EXTLIGHT : 1; // darkened, the intern face of windows are flagged 0x08 - uint32_t F_SIDN : 1; // (bright at night, unshaded) (used on windows and lamps in Stormwind, for example) (see emissive color) + uint32_t F_SIDN : 1; // (bright at night, unshaded) (used on windows and lamps in Stormwind, for example) (see emissive color) uint32_t F_WINDOW : 1; // lighting related (flag checked in CMapObj::UpdateSceneMaterials) uint32_t F_CLAMP_S : 1; // tex clamp S (force this material's textures to use clamp s addressing) uint32_t F_CLAMP_T : 1; // tex clamp T (force this material's textures to use clamp t addressing) diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 041542cc0..3112efebd 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -65,7 +65,7 @@ class gMeshTemplate { bool scissorEnabled = false; std::array scissorOffset = {0,0}; - std::array scissorSize = {0,0}; + std::array scissorSize = {0,0}; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 8939cd449..78cb3b2ba 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1157,11 +1157,11 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings const HGShaderPermutation &shader, const std::shared_ptr &renderPass, DrawElementMode element, - int8_t backFaceCulling, - int8_t triCCW, + bool backFaceCulling, + bool triCCW, EGxBlendEnum blendMode, - int8_t depthCulling, - int8_t depthWrite) { + bool depthCulling, + bool depthWrite) { PipelineCacheRecord pipelineCacheRecord; pipelineCacheRecord.shader = shader; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index fa27916ca..1ffe29670 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -119,11 +119,11 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &renderPass, DrawElementMode element, - int8_t backFaceCulling, - int8_t triCCW, + bool backFaceCulling, + bool triCCW, EGxBlendEnum blendMode, - int8_t depthCulling, - int8_t depthWrite); + bool depthCulling, + bool depthWrite); std::shared_ptr getRenderPass(std::vector textureAttachments, ITextureFormat depthAttachment, @@ -218,11 +218,11 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this renderPass; DrawElementMode element; - int8_t backFaceCulling; - int8_t triCCW; + bool backFaceCulling; + bool triCCW; EGxBlendEnum blendMode; - int8_t depthCulling; - int8_t depthWrite; + bool depthCulling; + bool depthWrite; bool operator==(const PipelineCacheRecord &other) const { @@ -242,10 +242,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.shader.get()) ^ hash{}(k.renderPass.get()) ^ - (hash{}(k.backFaceCulling) << 2) ^ - (hash{}(k.triCCW) << 4) ^ - (hash{}(k.depthCulling) << 8) ^ - (hash{}(k.depthWrite) << 10) ^ + (hash{}(k.backFaceCulling) << 2) ^ + (hash{}(k.triCCW) << 4) ^ + (hash{}(k.depthCulling) << 8) ^ + (hash{}(k.depthWrite) << 10) ^ (hash{}(k.blendMode) << 14) ^ (hash{}(k.element) << 16); }; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp index fbabe6d68..d9e16651d 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp @@ -59,6 +59,8 @@ GPipelineVLK::GPipelineVLK(IDevice &device, m_pipelineLayout = shaderVLK->getPipelineLayout(); + m_isTransparent = blendMode > EGxBlendEnum::GxBlend_AlphaKey || !depthWrite; + createPipeline(shaderVLK, renderPass, element, diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h index f5e35cd60..54ac6c8bc 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h @@ -39,11 +39,22 @@ class GPipelineVLK { VkPipelineLayout getLayout() { return m_pipelineLayout; }; VkPipeline getPipeline() { return graphicsPipeline; }; + bool getIsTransparent() const { + return m_isTransparent; + } + + const std::shared_ptr getRenderPass() { + return m_renderPass; + } private: GDeviceVLK &m_device; VkPipelineLayout m_pipelineLayout; VkPipeline graphicsPipeline; + + std::shared_ptr m_renderPass; + + bool m_isTransparent = false; }; diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index 12a67f54e..0b3d1b2e6 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -14,8 +14,9 @@ void TextureManagerVLK::initialize() { } HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { - BlpCacheRecord blpCacheRecord; - blpCacheRecord.texture = texture.get(); + BlpCacheRecord blpCacheRecord = { + .texture = std::weak_ptr(texture) + }; // blpCacheRecord.wrapX = xWrapTex; // blpCacheRecord.wrapY = yWrapTex; diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 8a11308a7..8a65d0fc8 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -10,6 +10,7 @@ #include "utils/MutexLockedVector.h" #include "../../engine/texture/BlpTexture.h" #include "textures/GTextureVLK.h" +#include "../../include/custom_container_key.h" class TextureManagerVLK : public std::enable_shared_from_this { public: @@ -28,7 +29,7 @@ class TextureManagerVLK : public std::enable_shared_from_this protected: struct BlpCacheRecord { - BlpTexture* texture; + wtf::KeyContainer> texture; bool operator==(const BlpCacheRecord &other) const { return @@ -38,7 +39,7 @@ class TextureManagerVLK : public std::enable_shared_from_this struct BlpCacheRecordHasher { std::size_t operator()(const BlpCacheRecord& k) const { using std::hash; - return hash{}(k.texture); + return hash{}(k.texture); }; }; std::unordered_map, BlpCacheRecordHasher> loadedTextureCache; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 628a166a1..4447bec4c 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -182,9 +182,6 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff submitRecords.get().data()); } -void CmdBufRecorder::setViewPort() { - -} void CmdBufRecorder::setViewPort(ViewportType viewportType) { const constexpr uint32_t firstViewport = 0; const constexpr uint32_t viewportCount = 1; @@ -192,12 +189,36 @@ void CmdBufRecorder::setViewPort(ViewportType viewportType) { vkCmdSetViewport(m_gCmdBuffer.m_cmdBuffer, firstViewport, viewportCount, &viewportsForThisStage[(int)viewportType]); } -void CmdBufRecorder::setScissors() { +void CmdBufRecorder::setScissors(const std::array &areaOffset, + const std::array &areaSize) { const constexpr uint32_t firstScissor = 0; const constexpr uint32_t scissorCount = 1; - vkCmdSetScissor(m_gCmdBuffer.m_cmdBuffer, firstScissor, scissorCount, &defaultScissor); + + VkRect2D vkRect2D = { + .offset = { + areaOffset[0], + areaOffset[1] + }, + .extent = { + areaSize[0], + areaSize[1] + } + }; + + vkCmdSetScissor(m_gCmdBuffer.m_cmdBuffer, firstScissor, scissorCount, &vkRect2D); + + m_currentScissorsIsDefault = false; } +void CmdBufRecorder::setDefaultScissors() { + if (m_currentScissorsIsDefault) return; + + const constexpr uint32_t firstScissor = 0; + const constexpr uint32_t scissorCount = 1; + vkCmdSetScissor(m_gCmdBuffer.m_cmdBuffer, firstScissor, scissorCount, &defaultScissor); + + m_currentScissorsIsDefault = true; +} void CmdBufRecorder::createViewPortTypes(const std::array &areaOffset, const std::array &areaSize) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 3cb12979d..c84125f8e 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -45,8 +45,9 @@ class CmdBufRecorder { void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); - void setViewport(); - void setScissors(); + void setScissors(const std::array &areaOffset, + const std::array &areaSize); + void setDefaultScissors(); void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); @@ -65,6 +66,7 @@ class CmdBufRecorder { std::shared_ptr m_currentIndexBuffer = nullptr; std::array, 2> m_currentVertexBuffers; std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + bool m_currentScissorsIsDefault = false; //Viewports diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index 2f2733552..46ac4ce6b 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -5,9 +5,31 @@ #include "ISimpleMaterialVLK.h" #include "../shaders/GShaderPermutationVLK.h" #include "../textures/GTextureVLK.h" +#include "../GPipelineVLK.h" + + ISimpleMaterialVLK::ISimpleMaterialVLK(const HGShaderPermutation &shader, + const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : - m_shader(shader), m_pipeline(pipeline), descriptors(descriptorSets) { + m_shader(shader), m_pipelineTemplate(pipelineTemplate), + m_pipeline(pipeline), descriptors(descriptorSets) { + +} + +//Works under assumption that meshes do not change the renderpass, on which they are rendered, too often +std::shared_ptr ISimpleMaterialVLK::getPipeLineForRenderPass(const std::shared_ptr &renderPass) { + +//TODO: Come up with more elegant way of recreating pipeline, when the renderPass changes(for example, when multiview is activated) + +// if (m_pipeline->getRenderPass() != renderPass) { +// m_pipeline = m_device.createPipeline(m_bindings, +// getShader(), renderPass, material()->getPipeline(), +// m_backFaceCulling, m_triCCW, +// m_blendMode, m_depthCulling, +// m_depthWrite); +// +// } + return m_pipeline; } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 71eb1ebad..b755eafcb 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -16,6 +16,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: explicit ISimpleMaterialVLK(const HGShaderPermutation &shader, + const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); ~ISimpleMaterialVLK() override = default; @@ -30,12 +31,14 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this HPipelineVLK getPipeline() { return m_pipeline; } + std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); private: std::array, MAX_SHADER_DESC_SETS> descriptors; HGShaderPermutation m_shader; HPipelineVLK m_pipeline; + PipelineTemplate m_pipelineTemplate; }; typedef std::shared_ptr HMaterialVLK; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index 4f1b18aa6..0577d114b 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -39,6 +39,8 @@ MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::sh MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindings &bindings, const std::shared_ptr &renderPass, const PipelineTemplate &pipelineTemplate) { + + m_pipelineTemplate = pipelineTemplate; m_pipeline = std::dynamic_pointer_cast(m_device)->createPipeline( bindings, m_shader, @@ -57,6 +59,7 @@ MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindi std::shared_ptr MaterialBuilderVLK::toMaterial() { return std::make_shared( m_shader, + m_pipelineTemplate, m_pipeline, descriptorSets ); diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 2978cbf7b..6c6467b8f 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -40,6 +40,7 @@ class MaterialBuilderVLK { HGShaderPermutation m_shader; HPipelineVLK m_pipeline; + PipelineTemplate m_pipelineTemplate; std::array, MAX_SHADER_DESC_SETS> descriptorSets; }; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index 4638af075..726ae4904 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -3,11 +3,13 @@ // #include "GM2MeshVLK.h" +#include "../GPipelineVLK.h" + GM2MeshVLK::GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate, const HMaterialVLK &material) : GMeshVLK(device, meshTemplate, material){ - m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ; + m_isTransparent = material->getPipeline()->getIsTransparent(); } void GM2MeshVLK::setLayer(int layer) { diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 27f91a09e..5abe8bab1 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -15,43 +15,16 @@ GMeshVLK::GMeshVLK(IDevice &device, m_bindings = meshTemplate.bindings; - m_depthWrite = (int8_t) (meshTemplate.depthWrite ? 1u : 0u); - m_depthCulling = (int8_t) (meshTemplate.depthCulling ? 1 : 0); - m_backFaceCulling = (int8_t) (meshTemplate.backFaceCulling ? 1 : 0); - m_triCCW = meshTemplate.triCCW; - - m_isScissorsEnabled = meshTemplate.scissorEnabled ? 1 : 0; + m_isScissorsEnabled = meshTemplate.scissorEnabled; if (m_isScissorsEnabled) { m_scissorSize = meshTemplate.scissorSize; m_scissorOffset = meshTemplate.scissorOffset; } - m_colorMask = meshTemplate.colorMask; - - m_blendMode = meshTemplate.blendMode; - m_start = meshTemplate.start; m_end = meshTemplate.end; - m_element = meshTemplate.element; -} - -//Works under assumption that meshes do not change the renderpass, on which they are rendered, too often -std::shared_ptr GMeshVLK::getPipeLineForRenderPass(const std::shared_ptr &renderPass) { - if (m_lastRenderPass != renderPass) { - m_lastPipelineForRenderPass = m_device.createPipeline(m_bindings, - m_material->getShader(), renderPass, m_element, - m_backFaceCulling, m_triCCW, - m_blendMode, m_depthCulling, - m_depthWrite); - m_lastRenderPass = renderPass; - } - - return m_lastPipelineForRenderPass; } - - - GMeshVLK::~GMeshVLK() { } diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 058dc47c2..8de8b98b3 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -26,26 +26,19 @@ class GMeshVLK : public IMesh { MeshType getMeshType() override; public: - std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); auto material() const -> const HMaterialVLK& { return m_material; } + auto scissorOffset() const -> const std::array& { return m_scissorOffset; } + auto scissorSize() const -> const std::array& { return m_scissorSize; } + auto scissorEnabled() const -> const bool {return m_isScissorsEnabled;}; protected: MeshType m_meshType; bool m_isTransparent = false; - int8_t m_depthWrite; - int8_t m_depthCulling; - int8_t m_backFaceCulling; - - int8_t m_triCCW = 1; - EGxBlendEnum m_blendMode; - int8_t m_isScissorsEnabled = -1; + bool m_isScissorsEnabled = false; std::array m_scissorOffset = {0,0}; - std::array m_scissorSize = {0,0}; - - uint8_t m_colorMask = 0; + std::array m_scissorSize = {0,0}; - DrawElementMode m_element; //Vulkan specific diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 5bb256d55..4eff33727 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -39,7 +39,7 @@ class IMapSceneBufferCreate { virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; -// virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; @@ -52,6 +52,9 @@ class IMapSceneBufferCreate { virtual HGVertexBuffer createWaterVertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createWaterIndexBuffer(int sizeInBytes) = 0; + + virtual HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 091cb16f1..1aa1762f0 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -26,12 +26,12 @@ static const std::array staticWMOBindings = {{ {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; -static std::array staticWaterBindings = {{ +static const std::array staticWaterBindings = {{ {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)} }}; -static std::array staticM2Bindings = {{ +static const std::array staticM2Bindings = {{ {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 48, 0 }, {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, 48, 12}, // bonesWeight {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, 48, 16}, // bones @@ -40,6 +40,10 @@ static std::array staticM2Bindings = {{ {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, 48, 40} // texcoord }}; +static const std::array skyConusBinding = {{ + {+drawQuad::Attribute::position, 4, GBindingType::GFLOAT, false, 0, 0}, +}}; + class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer() = default; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 0b25941a0..244e8ab34 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -38,6 +38,15 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createWaterVAO(HGVertexBuffer v return waterVAO; }; +HGVertexBufferBindings MapSceneRenderForwardVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto skyVAO = m_device->createVertexBufferBindings(); + skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); + skyVAO->setIndexBuffer(indexBuffer); + + return skyVAO; +} + HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { return HGVertexBuffer(); } @@ -70,6 +79,13 @@ HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) return HGIndexBuffer(); } +HGVertexBuffer MapSceneRenderForwardVLK::createSkyVertexBuffer(int sizeInBytes) { + return HGVertexBuffer(); +}; +HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { + return HGIndexBuffer(); +} + std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 6b3538658..420b229e1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -21,9 +21,10 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { //------------------------------------- // Buffer creation //------------------------------------- - virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; - virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; - virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; @@ -37,10 +38,14 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBuffer createWaterVertexBuffer(int sizeInBytes) override; HGIndexBuffer createWaterIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) override; private: HGDeviceVLK m_device; + }; From 8e276e2cfd5c3a3ae549588cf45ffa8c88a95575 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 12 Mar 2023 23:57:32 +0200 Subject: [PATCH 045/212] making m2 render again --- src/ui/FrontendUI.cpp | 10 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 2 +- wowViewerLib/CMakeLists.txt | 15 +- wowViewerLib/shaders/CMakeLists.txt | 2 +- .../shaders/glsl/common/commonM2Material.glsl | 163 +++++++++++------- .../glsl/common/commonWMOMaterial.glsl | 8 +- .../glsl/forwardRendering/adtShader.frag | 11 +- .../glsl/forwardRendering/adtShader.vert | 6 +- .../glsl/forwardRendering/m2Shader.frag | 2 - .../glsl/forwardRendering/skyConus.vert | 2 +- .../shaders/src/spirv/dumpShaderFields.h | 4 - .../src/engine/algorithms/mathHelper.h | 7 - .../src/engine/objects/adt/adtObject.cpp | 18 +- .../src/engine/objects/adt/adtObject.h | 4 - .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 9 +- .../m2/m2Helpers/M2MeshBufferUpdater.h | 2 +- .../src/engine/objects/m2/m2Object.cpp | 163 ++++++++++-------- wowViewerLib/src/engine/objects/m2/m2Object.h | 13 +- .../src/engine/objects/scenes/map.cpp | 66 +++---- wowViewerLib/src/engine/objects/scenes/map.h | 11 +- .../src/engine/shader/ShaderDefinitions.h | 25 +-- .../src/gapi/UniformBufferStructures.h | 18 +- .../src/gapi/interface/buffers/IBufferChunk.h | 2 + .../src/gapi/interface/materials/IMaterial.h | 2 +- .../gapi/interface/meshes/ITransparentMesh.h | 2 +- wowViewerLib/src/gapi/interface/sortLambda.h | 41 ++--- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 31 +++- .../src/gapi/vulkan/buffers/GBufferVLK.h | 9 +- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 5 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 2 +- .../vulkan/materials/MaterialBuilderVLK.h | 10 ++ .../src/gapi/vulkan/meshes/GMeshVLK.h | 2 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 2 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 11 ++ .../renderer/mapScene/MapSceneRenderer.cpp | 89 ++++++++++ .../src/renderer/mapScene/MapSceneRenderer.h | 18 +- .../mapScene/MapSceneRendererFactory.cpp | 4 +- .../mapScene/MapSceneRendererFactory.h | 2 +- .../mapScene/materials/IMaterialStructs.h | 35 ++++ .../vulkan/MapSceneRenderForwardVLK.cpp | 144 ++++++++++++++-- .../vulkan/MapSceneRenderForwardVLK.h | 27 ++- .../vulkan/materials/IMaterialInstance.h | 28 +++ 42 files changed, 707 insertions(+), 320 deletions(-) create mode 100644 wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index bb1206e66..6584cc031 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1661,12 +1661,12 @@ bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { } void FrontendUI::openWMOSceneByfdid(int WMOFdid) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, WMOFdid); m_api->camera->setCameraPos(0, 0, 0); } void FrontendUI::openMapByIdAndFilename(int mapId, std::string mapName, float x, float y, float z) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, mapName); m_api->camera = std::make_shared(); @@ -1674,7 +1674,7 @@ void FrontendUI::openMapByIdAndFilename(int mapId, std::string mapName, float x, m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, wdtFileId); m_api->camera = std::make_shared(); @@ -1682,7 +1682,7 @@ void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, m_api->camera->setMovementSpeed(movementSpeed); } void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementTextureIds) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2Fdid); m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(replacementTextureIds); @@ -1696,7 +1696,7 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText } void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2FileName); m_currentScene = m2Scene; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 6327f854a..3a2d478eb 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -33,7 +33,7 @@ class FrontendUIRenderer : public IRendererParameters processCulling(const std::shared_ptr> &frameInputParams) override { return nullptr; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 044effb9e..c46b941bc 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -328,7 +328,10 @@ set(SOURCE_FILES src/renderer/buffers/IVertexBufferDynamicTemplate.h src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h - src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h src/include/custom_container_key.h) + src/gapi/interface/materials/IMaterial.h + src/renderer/mapScene/MapSceneParams.h + src/include/custom_container_key.h + src/renderer/mapScene/materials/IMaterialStructs.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -506,7 +509,15 @@ if (LINK_VULKAN) src/gapi/vulkan/synchronization/GFenceVLK.cpp src/gapi/vulkan/synchronization/GFenceVLK.h src/renderer/vulkan/IRenderFunctionVLK.h - src/gapi/vulkan/descriptorSets/DescriptorRecord.h src/gapi/vulkan/materials/MaterialBuilderVLK.cpp src/gapi/vulkan/materials/MaterialBuilderVLK.h src/gapi/vulkan/TextureManagerVLK.cpp src/gapi/vulkan/TextureManagerVLK.h src/gapi/vulkan/utils/MutexLockedVector.h src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h src/gapi/vulkan/bindable/DSBindable.h) + src/gapi/vulkan/descriptorSets/DescriptorRecord.h + src/gapi/vulkan/materials/MaterialBuilderVLK.cpp + src/gapi/vulkan/materials/MaterialBuilderVLK.h + src/gapi/vulkan/TextureManagerVLK.cpp + src/gapi/vulkan/TextureManagerVLK.h + src/gapi/vulkan/utils/MutexLockedVector.h + src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h + src/gapi/vulkan/bindable/DSBindable.h + src/renderer/mapScene/vulkan/materials/IMaterialInstance.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 6bc864297..972f6591f 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -29,7 +29,7 @@ if(NOT ANDROID) src/spirv/spirv_refl_main.cpp src/spirv/webGLSLCompiler.cpp src/spirv/webGLSLCompiler.h - src/spirv/dumpShaderFields.h src/spirv/dumpShaderMetaData.h src/spirv/dumpGLSLShader.h) + src/spirv/dumpShaderFields.h src/spirv/dumpGLSLShader.h) add_executable(spirv_reflection ${SPIRV_REF_SOURCES}) set_target_properties(spirv_reflection PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index 1128d0477..1150063a2 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -241,6 +241,7 @@ void calcM2FragMaterial(const in int uPixelShader, matDiffuse = meshColor * tex.rgb * tex2.rgb; discardAlpha = tex.a * tex2.a; canDiscard = true; + break; } } @@ -279,66 +280,106 @@ void calcM2VertexMat(in int vertexShader, float edgeScanVal = edgeScan(vertexPosInView, normal); vMeshColorAlpha = color_Transparency; - if ( vertexShader == 0 ) {//Diffuse_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 1 ) {//Diffuse_Env - vTexCoord = envCoord; - } else if ( vertexShader == 2 ) {//Diffuse_T1_T2 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 3 ) {//Diffuse_T1_Env - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = envCoord; - } else if ( vertexShader == 4 ) {//Diffuse_Env_T1 - vTexCoord = envCoord; - vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 5 ) {//Diffuse_Env_Env - vTexCoord = envCoord; - vTexCoord2 = envCoord; - } else if ( vertexShader == 6 ) {//Diffuse_T1_Env_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000) ).xy; - vTexCoord2 = envCoord; - vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 7 ) {//Diffuse_T1_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 8 ) {//Diffuse_T1_T1_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 9 ) {//Diffuse_EdgeFade_T1 - vMeshColorAlpha.a *= edgeScanVal; - vTexCoord = ((textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy).xy; - } else if ( vertexShader == 10 ) {//Diffuse_T2 - vTexCoord = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 11 ) {//Diffuse_T1_Env_T2 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = envCoord; - vTexCoord3 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 12 ) {//Diffuse_EdgeFade_T1_T2 - vMeshColorAlpha.a *= edgeScanVal; - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 13 ) {//Diffuse_EdgeFade_Env - vMeshColorAlpha.a *= edgeScanVal; - vTexCoord = envCoord; - } else if ( vertexShader == 14 ) {//Diffuse_T1_T2_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - vTexCoord3 = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 15 ) {//Diffuse_T1_T2_T3 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - vTexCoord3 = vTexCoord3; - } else if ( vertexShader == 16 ) {//Color_T1_T2_T3 - vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0); - vMeshColorAlpha = vec4((in_col0.rgb * 0.500000).r, (in_col0.rgb * 0.500000).g, (in_col0.rgb * 0.500000).b, in_col0.a); - vTexCoord = (textMat[1] * vec4(texCoord2, 0.000000, 1.000000)).xy; - vTexCoord2 = vec2(0.000000, 0.000000); - vTexCoord3 = vTexCoord3; - } else if ( vertexShader == 17 ) {//BW_Diffuse_T1 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; - } else if ( vertexShader == 18 ) {//BW_Diffuse_T1_T2 - vTexCoord = (textMat[0] * vec4(texCoord, 0.000000, 1.000000)).xy; + + switch(vertexShader) { + case (0): { //Diffuse_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (1): { //Diffuse_Env + vTexCoord = envCoord; + break; + } + case (2): { //Diffuse_T1_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + break; + } + case (3): { //Diffuse_T1_Env + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = envCoord; + break; + } + case (4): { //Diffuse_Env_T1 + vTexCoord = envCoord; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (5): { //Diffuse_Env_Env + vTexCoord = envCoord; + vTexCoord2 = envCoord; + break; + } + case (6): { //Diffuse_T1_Env_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0) ).xy; + vTexCoord2 = envCoord; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (7): { //Diffuse_T1_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (8): { //Diffuse_T1_T1_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (9): { //Diffuse_EdgeFade_T1 + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = ((textMat[0] * vec4(texCoord, 0.0, 1.0)).xy).xy; + break; + } + case (10): { //Diffuse_T2 + vTexCoord = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + break; + } + case (11): { //Diffuse_T1_Env_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = envCoord; + vTexCoord3 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + break; + } + case (12): { //Diffuse_EdgeFade_T1_T2 + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + break; + } + case (13): { //Diffuse_EdgeFade_Env + vMeshColorAlpha.a *= edgeScanVal; + vTexCoord = envCoord; + break; + } + case (14): { //Diffuse_T1_T2_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + vTexCoord3 = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (15): { //Diffuse_T1_T2_T3 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + vTexCoord3 = vTexCoord3; + break; + } + case (16): { //Color_T1_T2_T3 + vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0); + vMeshColorAlpha = vec4((in_col0.rgb * 0.5).r, (in_col0.rgb * 0.5).g, (in_col0.rgb * 0.5).b, in_col0.a); + vTexCoord = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; + vTexCoord2 = vec2(0.0, 0.0); + vTexCoord3 = vTexCoord3; + break; + } + case (17): { //BW_Diffuse_T1 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } + case (18): { //BW_Diffuse_T1_T2 + vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; + break; + } } } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl index 06a292f84..c69abed68 100644 --- a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl @@ -86,7 +86,7 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, finalOpacity = tex.a; } else if (pixelShader == 7) { //MapObjTwoLayerEnvMetal - vec4 colorMix = mix(tex2, tex, vColor2.a); + vec4 colorMix = mix(tex2, tex, 1.0 - vColor2.a); matDiffuse = colorMix.rgb ; emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; @@ -220,9 +220,9 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); vec4 texMixed = tex_2 * alphaVec2Normalized.r + - tex_3 * alphaVec2Normalized.g + - tex_4 * alphaVec2Normalized.b + - tex_5 * alphaVec2Normalized.a; + tex_3 * alphaVec2Normalized.g + + tex_4 * alphaVec2Normalized.b + + tex_5 * alphaVec2Normalized.a; emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 930a8a027..e656f93a2 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -29,17 +29,18 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=3) uniform modelWideBlockPS { +layout(std140, binding=1) uniform meshWideBlockVSPS { + vec4 uPos; ivec4 uUseHeightMixFormula; - -}; - -layout(std140, set=0, binding=4) uniform meshWideBlockPS { vec4 uHeightScale; vec4 uHeightOffset; +}; + +layout(std140, binding=2) uniform meshWideBlockPS { mat4 animationMat[4]; }; + layout(location = 0) out vec4 outColor; const InteriorLightParam intLight = { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 70a279e98..e6e94d6b5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -18,8 +18,12 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, binding=2) uniform meshWideBlockVS { + +layout(std140, binding=1) uniform meshWideBlockVSPS { vec4 uPos; + ivec4 uUseHeightMixFormula; + vec4 uHeightScale; + vec4 uHeightOffset; }; mat3 blizzTranspose(mat4 value) { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 0a8b3ff44..e25bf3362 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -50,9 +50,7 @@ layout(std140, set=0, binding=3) uniform modelWideBlockPS { //Individual meshes layout(std140, set=0, binding=4) uniform meshWideBlockPS { ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; - vec4 uFogColorAndAlphaTest; vec4 uTexSampleAlpha; - vec4 uPcColor; }; layout(set=1,binding=5) uniform sampler2D uTexture; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert index a522edec8..90adf9c02 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert @@ -14,7 +14,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, set=0, binding=2) uniform meshWideBlockVS { +layout(std140, set=0, binding=1) uniform meshWideBlockVS { vec4 skyColor[6]; }; diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index 88b60df6f..520cd82ee 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -95,9 +95,6 @@ void dumpMembers(spirv_cross::WebGLSLCompiler &glsl, std::vector &f if (parentTypeId == spirv_cross::TypeID(0)) { parentTypeId = memberType.self; } -// -// auto submemberType = glsl.get_type(submemberTypeId); -// int structSize = submemberType.vecsize * submemberType.columns*(submemberType.width/8); if (arrayLiteral) { for (int j = 0; j < arraySize; j++) { @@ -332,7 +329,6 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { for (int j = 0; j < uboType.member_types.size(); j++) { auto uboParentType = glsl.get_type(uboType.parent_type); -// glsl.get_member_name auto memberSize = glsl.get_declared_struct_member_size(uboParentType, j); auto offset = glsl.type_struct_member_offset(uboParentType, j); auto memberName = glsl.get_member_name(uboType.parent_type, j); diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index 3804a36de..01c4a0b7f 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -97,13 +97,6 @@ class MathHelper { }; static inline const mathfu::mat4 &getAdtToWorldMat4() { - -// mathfu::mat4 adtToWorldMat4 = mathfu::mat4::Identity(); -// adtToWorldMat4 *= MathHelper::RotationX(toRadian(90)); -// adtToWorldMat4 *= MathHelper::RotationY(toRadian(90)); -// adtToWorldMat4 *= mathfu::mat4::FromTranslationVector(mathfu::vec3(32*TILESIZE, 0, 32*TILESIZE)); -// adtToWorldMat4 *= mathfu::mat4::FromScaleVector(mathfu::vec3(-1, 1, -1)); - static const mathfu::mat4 adtToWorldMat4 = { {0, -1, 0, 0}, {0, 0, 1, 0}, diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 4f75790fe..fa93e22e4 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -24,7 +24,7 @@ PACK( } ); -static std::array adtVertexBufferBinding = {{ +static std::array adtVertexBufferBinding = {{ {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, @@ -618,7 +618,8 @@ void AdtObject::createMeshes() { auto adtFileTex = m_adtFileTex; auto adtFile = m_adtFile; -// adtWideBlockPS = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::modelWideBlockPS)); + /* + adtWideBlockPS = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::modelWideBlockPS)); adtWideBlockPS = nullptr; int useHeightMixFormula = m_wdtFile->mphd->flags.adt_has_height_texturing > 0; // int useHeightMixFormula = 1; @@ -639,10 +640,10 @@ void AdtObject::createMeshes() { gMeshTemplate aTemplate(adtVertexBindings); PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.triCCW = 1; - pipelineTemplate.depthWrite = 1; - pipelineTemplate.depthCulling = 1; - pipelineTemplate.backFaceCulling = 1; + pipelineTemplate.triCCW = true; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; @@ -734,7 +735,7 @@ void AdtObject::createMeshes() { HGMesh hgMesh = device->createMesh(aTemplate); adtMeshes[i] = hgMesh; } - } + }*/ } void AdtObject::loadAlphaTextures() { @@ -862,10 +863,9 @@ void AdtObject::update(animTime_t deltaTime ) { if (!m_loaded) { return; } - if (adtWideBlockPS == nullptr) return; +// if (adtWideBlockPS == nullptr) return; for (int i = 0; i < 256; i++) { - for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { texturesPerMCNK[i].animTexture[j] = mathfu::mat4::Identity(); if (m_adtFileTex->mtxp_len > 0) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 82ae8dbc8..910d12f9a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -125,10 +125,6 @@ class AdtObject { HGVertexBufferBindings lodVertexBindings; - std::shared_ptr> adtWideBlockPS; - - - private: std::vector alphaTextures; HBlpTexture lodDiffuseTexture = nullptr; diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index d1b8ce7ca..16c4f935b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -8,7 +8,6 @@ float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile){ auto textMaterial = m2SkinProfile->batches[batchIndex]; - int renderFlagIndex = textMaterial->materialIndex; mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object.subMeshColors); float transparency = M2Object::getTextureWeight(m2SkinProfile, m2Object.m_m2Geom->getM2Data(), batchIndex, 0, m2Object.transparencies); @@ -66,8 +65,6 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object uTexSampleAlpha[i] = M2Object::getTextureWeight(m2SkinProfile, m2Data, batchIndex, i, m2Object->transparencies); } - - float uAlphaTest; if (blendMode == EGxBlendEnum::GxBlend_AlphaKey) { uAlphaTest = 128.0f/255.0f * finalTransparency; //Maybe move this to shader logic? @@ -83,16 +80,14 @@ void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object meshblockPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; meshblockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; meshblockPS.BlendMode = static_cast(blendMode); - meshblockPS.uFogColorAndAlphaTest = mathfu::vec4(mathfu::vec3(0,0,0), uAlphaTest); - meshblockPS.uTexSampleAlpha = uTexSampleAlpha; }); } -void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, M2MaterialInst &materialData, +void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat) { - M2Batch *textMaterial = m2SkinProfile->batches.getElement(materialData.batchIndex); + M2Batch *textMaterial = m2SkinProfile->batches.getElement(batchIndex); M2SkinSection *submesh = m2SkinProfile->skinSections.getElement(textMaterial->skinSectionIndex); mathfu::vec4 sortCenterPosition = mathfu::vec4(mathfu::vec3(submesh->sortCenterPosition), 1.0); diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index 2385ffcba..8e7c067e8 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -26,7 +26,7 @@ class M2MeshBufferUpdater { static inline mathfu::vec3 &getFogColor(EGxBlendEnum blendMode, mathfu::vec3 &originalFogColor); - static void updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, M2MaterialInst &materialData, + static void updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat); }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index a04dcb75e..7b4cd9651 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -825,13 +825,13 @@ void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) { if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { for (int i = 0; i < this->m_meshNaturalArray.size(); i++) { //Update info for sorting - M2MeshBufferUpdater::updateSortData(this->m_meshNaturalArray[i], *this, m_materialArray[i], m2File, + M2MeshBufferUpdater::updateSortData(this->m_meshNaturalArray[i], *this, i, m2File, skinData, modelViewMat); } for (int i = 0; i < this->m_meshForcedTranspArray.size(); i++) { //Update info for sorting if (this->m_meshForcedTranspArray[i] != nullptr) { - M2MeshBufferUpdater::updateSortData(this->m_meshForcedTranspArray[i], *this, m_materialArray[i], m2File, + M2MeshBufferUpdater::updateSortData(this->m_meshForcedTranspArray[i], *this, i, m2File, skinData, modelViewMat); } } @@ -936,7 +936,7 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ m_skinGeom->fixData(m_m2Geom->getM2Data()); this->createVertexBindings(sceneRenderer); - this->createMeshes(); + this->createMeshes(sceneRenderer); m_boneMasterData = std::make_shared(m_m2Geom, m_skelGeom, m_parentSkelGeom); @@ -961,6 +961,7 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ return; } + //deltaTime = miliseconds void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat) { if (!this->m_loaded) return; @@ -1047,7 +1048,7 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v } } -void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat) { +void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { if (!this->m_loaded) return; mathfu::mat4 modelViewMat = viewMat * m_placementMatrix; @@ -1055,6 +1056,46 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat) { M2Data * m2File = this->m_m2Geom->getM2Data(); M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); + //Update materials + { + auto placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); + placementMatrix.uPlacementMat = m_placementMatrix; + m_modelWideDataBuff->m_placementMatrix->save(); + } + { + auto bonesData = m_modelWideDataBuff->m_bonesData->getObject(); + int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); + std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, bonesData.uBoneMatrixes); + + m_modelWideDataBuff->m_bonesData->save(); + } + { + auto modelFragmentData = m_modelWideDataBuff->m_modelFragmentData->getObject(); + static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); + mathfu::vec4 localDiffuse = diffuseNon; + + modelFragmentData.intLight.uInteriorAmbientColorAndApplyInteriorLight = + mathfu::vec4_packed(mathfu::vec4( + m_ambientColorOverride.xyz(), + m_useLocalDiffuseColor == 1 ? 1.0 : 0 + )); + + modelFragmentData.intLight.uInteriorDirectColorAndApplyExteriorLight = + mathfu::vec4_packed(mathfu::vec4( + m_localDiffuseColorV.xyz(), + m_useLocalDiffuseColor == 1 ? 0.0 : 1 + )); + + modelFragmentData.interiorExteriorBlend = + mathfu::vec4_packed(mathfu::vec4( + (m_useLocalDiffuseColor == 1) ? 1.0 : 0.0, + 0,0,0)); + + //Lights + M2MeshBufferUpdater::fillLights(*this, modelFragmentData); + m_modelWideDataBuff->m_modelFragmentData->save(); + } + //Manually update vertices for dynamics updateDynamicMeshes(); @@ -1423,6 +1464,36 @@ HGM2Mesh M2Object::createWaterfallMesh() { return nullptr; } +void M2Object::createMaterials(const HMapSceneBufferCreate &sceneRenderer) { + //Create materials + const auto &materials = m_skinGeom->getSkinData()->skinSections; + + for (int i = 0; i < materials.size; i++) { + M2SkinSection * material = materials[i]; + + PipelineTemplate pipelineTemplate; + + int renderFlagIndex = m2Batch->materialIndex; + auto renderFlag = m_m2Data->materials[renderFlagIndex]; + + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); + pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); + pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); + pipelineTemplate.triCCW = true; + + if (overrideBlend) { + pipelineTemplate.blendMode = blendMode; + } else { + pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; + blendMode = pipelineTemplate.blendMode; + } + + sceneRenderer->createM2Material() + + } +} + void M2Object::createMeshes() { /* 1. Free previous subMeshArray */ this->m_meshNaturalArray.clear(); @@ -1439,17 +1510,19 @@ void M2Object::createMeshes() { /* 2. Fill the materialArray */ std::vector batchesRequiringDynamicVao = {}; - M2Array* batches = &m_skinGeom->getSkinData()->batches; + const auto &batches = m_skinGeom->getSkinData()->batches; if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { - for (int i = 0; i < batches->size; i++) { - auto m2Batch = skinProfile->batches[i]; + + + for (int i = 0; i < batches.size; i++) { + auto m2Batch = batches[i]; auto skinSection = skinProfile->skinSections[m2Batch->skinSectionIndex]; if (!checkifBonesAreInRange(skinProfile, skinSection)) { batchesRequiringDynamicVao.push_back(i); continue; } - M2MaterialInst material; + EGxBlendEnum mainBlendMode; HGM2Mesh hmesh = createSingleMesh(m_m2Data, i, 0, bufferBindings, m2Batch, skinSection, material, mainBlendMode, false); @@ -1458,7 +1531,7 @@ void M2Object::createMeshes() { continue; this->m_materialArray.push_back(material); - this->m_meshNaturalArray.push_back(hmesh); + this->m_meshNaturalArray.push_back({hmesh, i}); M2MeshBufferUpdater::assignUpdateEvents(hmesh, this, m_materialArray[m_materialArray.size() - 1], m_m2Data, skinProfile); @@ -1541,23 +1614,7 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", "m2Shader", &cacheRecord); gMeshTemplate meshTemplate(finalBufferBindings); - PipelineTemplate pipelineTemplate; - - int renderFlagIndex = m2Batch->materialIndex; - auto renderFlag = m_m2Data->materials[renderFlagIndex]; - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); - pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); - pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); - pipelineTemplate.triCCW = 1; - - if (overrideBlend) { - pipelineTemplate.blendMode = blendMode; - } else { - pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; - blendMode = pipelineTemplate.blendMode; - } meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; @@ -1573,9 +1630,11 @@ M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrecti //Make mesh //TODO: auto hmesh = m_api->hDevice->createMesh(meshTemplate); + hmesh->setLayer(m2Batch->materialLayer); + hmesh->setPriorityPlane(m2Batch->priorityPlane); + hmesh->setQuery(nullptr); - - return nullptr; + return hmesh; } void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { @@ -1619,8 +1678,6 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorvertexCount << " vertices " << "at update frame =" << frameNum << std::endl; } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index c9b34d0cb..f143671e2 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -88,8 +88,7 @@ class M2Object { std::shared_ptr m_boneMasterData = nullptr; HGVertexBufferBindings bufferBindings = nullptr; - std::shared_ptr> vertexModelWideUniformBuffer = nullptr; - std::shared_ptr> fragmentModelWideUniformBuffer = nullptr; + std::shared_ptr m_modelWideDataBuff = nullptr; HGMesh boundingBoxMesh = nullptr; @@ -133,12 +132,13 @@ class M2Object { std::unordered_map loadedTextures; - std::vector m_meshNaturalArray; - std::vector m_meshForcedTranspArray; + //Tuple of Mesh and batchIndex + std::vector> m_meshNaturalArray; + std::vector> m_meshForcedTranspArray; //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; - std::vector m_materialArray; + std::vector m_materialArray; AnimationManager *m_animationManager; bool m_interiorAmbientWasSet = false; // For static only @@ -163,6 +163,7 @@ class M2Object { bool checkifBonesAreInRange(M2SkinProfile *skinProfile, M2SkinSection *mesh); + void createMaterials(const HMapSceneBufferCreate &sceneRenderer); void createMeshes(); void createBoundingBoxMesh(); @@ -265,7 +266,7 @@ class M2Object { void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); - void uploadGeneratorBuffers(mathfu::mat4 &viewMat); + void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); void drawDebugLight(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 4f2008a02..5273e5a23 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -295,35 +295,9 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) { m_sceneWideBlockVSPSChunk = nullptr; } -HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config *config, bool conusFor0x4Sky) { - std::shared_ptr> skyVs = nullptr; - skyVs->setUpdateHandler([config, conusFor0x4Sky](auto &data, const HFrameDependantData &frameDepedantData) -> void { - auto &meshblockVS = data; - - if (!conusFor0x4Sky) { - meshblockVS.skyColor[0] = frameDepedantData->SkyTopColor; - meshblockVS.skyColor[1] = frameDepedantData->SkyMiddleColor; - meshblockVS.skyColor[2] = frameDepedantData->SkyBand1Color; - meshblockVS.skyColor[3] = frameDepedantData->SkyBand2Color; - meshblockVS.skyColor[4] = frameDepedantData->SkySmogColor; - meshblockVS.skyColor[5] = frameDepedantData->SkyFogColor; - } else { - auto EndFogColorV4_1 = mathfu::vec4(frameDepedantData->EndFogColor, 0.0); - auto EndFogColorV4_2 = mathfu::vec4(frameDepedantData->EndFogColor, 1.0); - meshblockVS.skyColor[0] = EndFogColorV4_1; - meshblockVS.skyColor[1] = EndFogColorV4_1; - meshblockVS.skyColor[2] = EndFogColorV4_1; - meshblockVS.skyColor[3] = EndFogColorV4_1; - meshblockVS.skyColor[4] = EndFogColorV4_1; - meshblockVS.skyColor[5] = EndFogColorV4_2; - } - }); - - //TODO: Pass m_skyConeAlpha to fragment shader +std::tuple> createSkyMesh(const HMapSceneBufferCreate &sceneRenderer, + const HGVertexBufferBindings &skyBindings, bool conusFor0x4Sky) { - ///2. Create mesh - auto shader = device->getShader("skyConus", "skyConus", nullptr); - gMeshTemplate meshTemplate(skyBindings); PipelineTemplate pipelineTemplate; pipelineTemplate.depthWrite = false; pipelineTemplate.depthCulling = true; @@ -331,6 +305,11 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config pipelineTemplate.blendMode = conusFor0x4Sky ? EGxBlendEnum::GxBlend_Alpha : EGxBlendEnum::GxBlend_Opaque; pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; + auto material = sceneRenderer->createSkyMeshMaterial(pipelineTemplate); + //TODO: Pass m_skyConeAlpha to fragment shader + + gMeshTemplate meshTemplate(skyBindings); + meshTemplate.meshType = MeshType::eGeneralMesh; meshTemplate.skybox = true; @@ -345,8 +324,8 @@ HGMesh createSkyMesh(IDevice *device, HGVertexBufferBindings skyBindings, Config } //Make mesh - HGMesh hmesh = device->createMesh(meshTemplate); - return hmesh; + HGMesh hmesh = sceneRenderer->createMesh(meshTemplate, material); + return {hmesh, material}; } void Map::makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { @@ -1393,8 +1372,8 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende } if (skyMesh == nullptr) { auto skyMeshBinding = createSkyBindings(sceneRenderer); - skyMesh = createSkyMesh(m_api->hDevice.get(), skyMeshBinding, m_api->getConfig(), false); - skyMesh0x4Sky = createSkyMesh(m_api->hDevice.get(), skyMeshBinding, m_api->getConfig(), true); + std::tie(skyMesh, skyMeshMat) = createSkyMesh(sceneRenderer, skyMeshBinding, false); + std::tie(skyMesh0x4Sky, skyMeshMat0x4) = createSkyMesh(sceneRenderer, skyMeshBinding, true); } }; @@ -1476,6 +1455,29 @@ void Map::update(const HMapRenderPlan &renderPlan) { } void Map::updateBuffers(const HMapRenderPlan &renderPlan) { + { + auto &meshblockVS = skyMeshMat0x4->m_skyColors->getObject(); + auto EndFogColorV4_1 = mathfu::vec4(renderPlan->frameDependentData->EndFogColor, 0.0); + auto EndFogColorV4_2 = mathfu::vec4(renderPlan->frameDependentData->EndFogColor, 1.0); + meshblockVS.skyColor[0] = EndFogColorV4_1; + meshblockVS.skyColor[1] = EndFogColorV4_1; + meshblockVS.skyColor[2] = EndFogColorV4_1; + meshblockVS.skyColor[3] = EndFogColorV4_1; + meshblockVS.skyColor[4] = EndFogColorV4_1; + meshblockVS.skyColor[5] = EndFogColorV4_2; + skyMeshMat0x4->m_skyColors->save(); + } + { + auto &meshblockVS = skyMeshMat->m_skyColors->getObject(); + meshblockVS.skyColor[0] = renderPlan->frameDependentData->SkyTopColor; + meshblockVS.skyColor[1] = renderPlan->frameDependentData->SkyMiddleColor; + meshblockVS.skyColor[2] = renderPlan->frameDependentData->SkyBand1Color; + meshblockVS.skyColor[3] = renderPlan->frameDependentData->SkyBand2Color; + meshblockVS.skyColor[4] = renderPlan->frameDependentData->SkySmogColor; + meshblockVS.skyColor[5] = renderPlan->frameDependentData->SkyFogColor; + skyMeshMat->m_skyColors->save(); + } + for (auto &m2Object : renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { // m2Object->uploadGeneratorBuffers(renderPlan->matricesForCulling->lookAtMat); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index d5b73a903..26870ec3a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -36,13 +36,7 @@ class Map : public IScene, public IMapApi { } } protected: - FrameCounter mapProduceUpdateCounter; - FrameCounter interiorViewCollectMeshCounter; - FrameCounter exteriorViewCollectMeshCounter; - FrameCounter m2CollectMeshCounter; - FrameCounter sortMeshCounter; - FrameCounter collectBuffersCounter; - FrameCounter sortBuffersCounter; + FrameCounter mapUpdateCounter; FrameCounter m2UpdateframeCounter; @@ -92,7 +86,10 @@ class Map : public IScene, public IMapApi { HGVertexBufferBindings quadBindings; float m_skyConeAlpha = 0.0; HGMesh skyMesh = nullptr; + std::shared_ptr skyMeshMat = nullptr; + HGMesh skyMesh0x4Sky = nullptr; + std::shared_ptr skyMeshMat0x4 = nullptr; //Map mode std::unordered_map> m_m2MapObjects = {}; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 508cceb7d..ccf93cd97 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -659,8 +659,8 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,288}, - {0,3,16}, + {0,2,256}, + {0,1,64}, {0,0,368}, }, { @@ -1359,11 +1359,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,368}, - {0,2,96}, + {0,1,96}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1749,8 +1749,8 @@ const std::unordered_map class IBufferChunk { public: + using structureType = T; + virtual ~IBufferChunk() = default; virtual T &getObject() = 0; virtual void save() = 0; diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index d7f5f288a..01aea4ffd 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -11,7 +11,7 @@ struct PipelineTemplate { DrawElementMode element; - int8_t triCCW = 1; //counter-clockwise + bool triCCW = true; //counter-clockwise bool depthWrite = true; bool depthCulling = true; bool backFaceCulling = true; diff --git a/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h b/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h index cd31190c3..de40c2d0f 100644 --- a/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h @@ -7,7 +7,7 @@ #include "IMesh.h" -class ITransparentMesh : public IMesh { +class ITransparentMesh : virtual public IMesh { friend class IDevice; protected: float m_sortDistance = 0; diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index fa64b141a..56bb59039 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -1,6 +1,8 @@ -[](const HGMesh &indexA, const HGMesh &indexB) { - IMesh * pA = indexA.get(); - IMesh* pB = indexB.get(); +#include "IDevice.h" + +static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { + ITransparentMesh * pA = dynamic_cast(indexA.get()); + ITransparentMesh * pB = dynamic_cast(indexB.get()); // HGMesh pA = sortedArrayPtr[indexA]; // HGMesh pB = sortedArrayPtr[indexB]; @@ -26,20 +28,24 @@ if (pA->getIsTransparent() && pB->getIsTransparent()) { if (((pA->getMeshType() == MeshType::eM2Mesh || pA->getMeshType() == MeshType::eParticleMesh) && (pB->getMeshType() == MeshType::eM2Mesh || pB->getMeshType() == MeshType::eParticleMesh))) { - if (pA->priorityPlane()!= pB->priorityPlane()) { - return pB->priorityPlane() > pA->priorityPlane(); + IM2Mesh *pA1 = dynamic_cast(pA); + IM2Mesh *pB1 = dynamic_cast(pB); + + if (pA1->priorityPlane()!= pB1->priorityPlane()) { + return pB1->priorityPlane() > pA1->priorityPlane(); } - if (pA->getSortDistance() < pB->getSortDistance()) { + if (pA1->getSortDistance() < pB1->getSortDistance()) { return true; } - if (pA->getSortDistance() > pB->getSortDistance()) { + if (pA1->getSortDistance() > pB1->getSortDistance()) { return false; } - if (pA->getM2Object() == pB->getM2Object()) { - if (pB->layer() != pA->layer()) { - return pB->layer() < pA->layer(); +// if (pA1->getM2Object() == pB1->getM2Object()) { + if (pA1->bindings() == pB1->bindings()) { + if (pB1->layer() != pA1->layer()) { + return pB1->layer() < pA1->layer(); } } } else { @@ -63,21 +69,6 @@ return pA->bindings() > pB->bindings(); } - if (pA->getGxBlendMode() != pB->getGxBlendMode()) { - return pA->getGxBlendMode() < pB->getGxBlendMode(); - } - - int minTextureCount = pA->textureCount() < pB->textureCount() ? pA->textureCount() : pB->textureCount(); - for (int i = 0; i < minTextureCount; i++) { - if (pA->texture()[i] != pB->texture()[i]) { - return pA->texture()[i] < pB->texture()[i]; - } - } - - if (pA->textureCount() != pB->textureCount()) { - return pA->textureCount() < pB->textureCount(); - } - if (pA->start() != pB->start()) { return pA->start() < pB->start(); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 650e95237..3fb27c9c3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -65,11 +65,23 @@ void GBufferVLK::destroyBuffer(BufferInternal &buffer) { ); } -VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { +VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { + bool minAddressStrategy = fakeSize != -1 && fakeSize > sizeInBytes; + VmaVirtualAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.size = sizeInBytes; //Size in bytes + if (minAddressStrategy) { + allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT; + } - return vmaVirtualAllocate(buffer.virtualBlock, &allocCreateInfo, &alloc, &offset); + auto result = vmaVirtualAllocate(buffer.virtualBlock, &allocCreateInfo, &alloc, &offset); + if (minAddressStrategy) { + if (result == VK_SUCCESS && (offset+fakeSize) > m_bufferSize) { + vmaVirtualFree(buffer.virtualBlock, alloc); + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + } + return result; } void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc) { @@ -105,7 +117,7 @@ void GBufferVLK::resize(int newLength) { if (subBuffer != nullptr) { VmaVirtualAllocation alloc; VkDeviceSize offset; - VkResult res = allocateSubBuffer(newBuffer, subBuffer->m_size, alloc, offset); + VkResult res = allocateSubBuffer(newBuffer, subBuffer->m_size, subBuffer->m_fakeSize, alloc, offset); if (res != VK_SUCCESS) { std::cerr << "Could not allocate sub-buffer during resize " << std::endl; @@ -128,17 +140,20 @@ void GBufferVLK::resize(int newLength) { currentBuffer = newBuffer; } -std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes) { +//fakeSize is used to make sure the subBuffer has enough bytes left till end of main buffer. +//used for allocating data for UBO, when you don't want to suballocate whole size. +//For example if only one bone matrix is used out 220, sizeInBytes will be size of one matrix, while fakeSize is 220 matrices +std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes, int fakeSize) { VmaVirtualAllocation alloc; VkDeviceSize offset; - VkResult res = allocateSubBuffer(currentBuffer, sizeInBytes, alloc, offset); + VkResult res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc, offset); if(res == VK_SUCCESS) { auto subBuffer = std::make_shared( shared_from_this(), alloc, - offset, sizeInBytes, + offset, sizeInBytes, fakeSize, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset); currentSubBuffers.push_back(subBuffer); subBuffer->m_iterator = std::prev(currentSubBuffers.end()); @@ -176,11 +191,13 @@ void GBufferVLK::save(int length) { GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, VmaVirtualAllocation alloc, - VkDeviceSize offset, int size, + VkDeviceSize offset, + int size, int fakeSize, uint8_t *dataPointer) : m_parentBuffer(parent) { m_alloc = alloc; m_offset = offset; m_size = size; + m_fakeSize = fakeSize; m_dataPointer = dataPointer; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 2f71bc515..20dceeac7 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -75,7 +75,9 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this>::const_iterator m_iterator; }; @@ -104,13 +107,13 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubBuffer(int sizeInBytes); + std::shared_ptr getSubBuffer(int sizeInBytes, int fakeSize = -1); void deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &m_alloc); private: void createBuffer(BufferInternal &buffer); void destroyBuffer(BufferInternal &buffer); - VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, VmaVirtualAllocation &alloc, VkDeviceSize &offset); + VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset); void deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index 3bc53989a..0d0f18ec3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -12,8 +12,9 @@ template class CBufferChunkVLK : public IBufferChunk { public: - CBufferChunkVLK(const std::shared_ptr &mainBuffer) { - subBuffer = mainBuffer->getSubBuffer(sizeof(T)); + CBufferChunkVLK(const std::shared_ptr &mainBuffer, int realSize = -1) { + if (realSize <= sizeof(T)) realSize = sizeof(T); + subBuffer = mainBuffer->getSubBuffer(realSize,sizeof(T)); } T &getObject() override { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index a8f77d1b2..40c5f157b 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -197,7 +197,7 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { } auto noSetBitSet = - m_set.getDescSetLayout()->getRequiredBindPoints() & ~m_updateBindPoints; + m_set.getDescSetLayout()->getRequiredBindPoints() & (~m_updateBindPoints); if (!noSetBitSet.none()) { std::string notSetBits; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 6c6467b8f..2c1ead9ab 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -9,6 +9,7 @@ #include #include "../../interface/IDevice.h" #include "ISimpleMaterialVLK.h" +#include "../../../renderer/mapScene/vulkan/materials/IMaterialInstance.h" #include "../descriptorSets/GDescriptorSet.h" class MaterialBuilderVLK { @@ -28,6 +29,15 @@ class MaterialBuilderVLK { const PipelineTemplate &pipelineTemplate); std::shared_ptr toMaterial(); + template + std::shared_ptr toMaterial(const std::function &initializer) { + return std::make_shared>(initializer, + m_shader, + m_pipelineTemplate, + m_pipeline, + descriptorSets); + } + ~MaterialBuilderVLK() = default; private: MaterialBuilderVLK(const std::shared_ptr &device, diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 8de8b98b3..4c840d896 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -11,7 +11,7 @@ #include "../descriptorSets/GDescriptorSet.h" #include "../materials/ISimpleMaterialVLK.h" -class GMeshVLK : public IMesh { +class GMeshVLK : virtual public IMesh { friend class GDeviceVLK; public: explicit GMeshVLK(IDevice &device, diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 8d80f4220..2e75dfc02 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -142,7 +142,7 @@ void GShaderPermutationVLK::createShaderLayout() { makeMin(setLayout.imageBindings.start, imageVertBinding.binding); makeMax(setLayout.imageBindings.end, imageVertBinding.binding); } - for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { + for (int i = 0; i < this->fragShaderMeta->imageBindings.size(); i++) { auto &imageFragBinding = this->fragShaderMeta->imageBindings[i]; auto &setLayout = combinedShaderLayout.setLayouts[imageFragBinding.set]; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 4eff33727..3d7b0b7fb 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -8,6 +8,7 @@ #include #include "../../gapi/interface/IDevice.h" #include "../../engine/persistance/header/commonFileStructs.h" +#include "materials/IMaterialStructs.h" PACK( @@ -55,6 +56,16 @@ class IMapSceneBufferCreate { virtual HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) = 0; + + + virtual std::shared_ptr createM2ModelMat(int bonesCount) = 0; + virtual std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) = 0; + + virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; + + virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index d2443a58c..98932db53 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -4,6 +4,7 @@ #include "MapSceneRenderer.h" #include "../../engine/objects/scenes/map.h" +#include "../../gapi/interface/sortLambda.h" std::shared_ptr MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { @@ -17,3 +18,91 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan) { + mapProduceUpdateCounter.beginMeasurement(); + + //Create meshes + auto hopaqueMeshes = std::make_shared>(); + auto htransparentMeshes = std::make_shared>(); + + auto opaqueMeshes = *hopaqueMeshes; + auto transparentMeshes = *htransparentMeshes; + + opaqueMeshes.reserve(30000); + transparentMeshes.reserve(30000); + + const auto& cullStage = renderPlan; + auto fdd = cullStage->frameDependentData; + + int m_viewRenderOrder = 0; + + //TODO: find a way to forward this data here + /* + if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && + (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { + if (fdd->overrideValuesWithFinalFog) { + if (skyMesh0x4Sky != nullptr) { + transparentMeshes.push_back(skyMesh0x4Sky); + skyMesh0x4Sky->setSortDistance(0); + + } + } + if ((m_skyConeAlpha > 0) ) { + if (skyMesh != nullptr) + opaqueMeshes.push_back(skyMesh); + } + } + */ + + // Put everything into one array and sort + interiorViewCollectMeshCounter.beginMeasurement(); + bool renderPortals = m_config->renderPortals; + for (auto &view : cullStage->viewsHolder.getInteriorViews()) { + view->collectMeshes(opaqueMeshes, transparentMeshes); + if (renderPortals) { +// view->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); + } + } + interiorViewCollectMeshCounter.endMeasurement(); + + exteriorViewCollectMeshCounter.beginMeasurement(); + { + auto exteriorView = cullStage->viewsHolder.getExterior(); + if (exteriorView != nullptr) { + exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); + if (renderPortals) { +// exteriorView->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); + } + } + } + exteriorViewCollectMeshCounter.endMeasurement(); + + m2CollectMeshCounter.beginMeasurement(); + if (m_config->renderM2) { + for (auto &m2Object : cullStage->m2Array.getDrawn()) { + if (m2Object == nullptr) continue; + m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); + m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); + } + } + m2CollectMeshCounter.endMeasurement(); + + //No need to sort array which has only one element + sortMeshCounter.beginMeasurement(); + if (transparentMeshes.size() > 1) { + tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); + } + sortMeshCounter.endMeasurement(); + + mapProduceUpdateCounter.endMeasurement(); + + + m_config->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); + m_config->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); + m_config->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); + m_config->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); + m_config->sortMeshTime = sortMeshCounter.getTimePerFrame(); + m_config->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); + m_config->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); +} diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 1aa1762f0..705d2ae41 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -13,6 +13,7 @@ #include "MapScenePlan.h" #include "../../engine/shader/ShaderDefinitions.h" +#include "../../engine/algorithms/FrameCounter.h" static const std::array staticWMOBindings = {{ {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, pos) }, @@ -46,10 +47,23 @@ static const std::array skyConusBinding = {{ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: - MapSceneRenderer() = default; + MapSceneRenderer(Config *config) : m_config(config) {}; ~MapSceneRenderer() override = default; - std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override;; + std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; + + void collectMeshes(const std::shared_ptr &renderPlan); + +private: + FrameCounter mapProduceUpdateCounter; + FrameCounter interiorViewCollectMeshCounter; + FrameCounter exteriorViewCollectMeshCounter; + FrameCounter m2CollectMeshCounter; + FrameCounter sortMeshCounter; + FrameCounter collectBuffersCounter; + FrameCounter sortBuffersCounter; + + Config *m_config; }; //typedef FrameInputParams MapSceneRendererInputParams; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index 2bebc03c5..6865586d4 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -5,10 +5,10 @@ #include "MapSceneRendererFactory.h" #include "vulkan/MapSceneRenderForwardVLK.h" -std::shared_ptr MapSceneRendererFactory::createForwardRenderer(HGDevice &device) { +std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - return std::make_shared(std::dynamic_pointer_cast(device)); + return std::make_shared(std::dynamic_pointer_cast(device), config); default: return nullptr; } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h index 904419a48..31486ea2e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h @@ -11,7 +11,7 @@ class MapSceneRendererFactory { public: - static std::shared_ptr createForwardRenderer(HGDevice &device); + static std::shared_ptr createForwardRenderer(const HGDevice &device, Config * config); }; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h new file mode 100644 index 000000000..8e0fc5532 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -0,0 +1,35 @@ +// +// Created by Deamon on 3/5/2023. +// + +#ifndef AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H +#define AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H + +#include "../../../gapi/interface/materials/IMaterial.h" +#include "../../../gapi/UniformBufferStructures.h" + +struct M2MaterialTemplate { + const HGTexture texture0 = nullptr; + const HGTexture texture1 = nullptr; + const HGTexture texture2 = nullptr; +}; + +class IM2ModelData { +public: + std::shared_ptr> m_placementMatrix = nullptr; + std::shared_ptr> m_bonesData = nullptr; + std::shared_ptr> m_modelFragmentData = nullptr; +}; + +class IM2Material : public IMaterial { +public: + std::shared_ptr> m_vertexData = nullptr; + std::shared_ptr> m_fragmentData = nullptr; +}; + +class ISkyMeshMaterial : public IMaterial { +public: + std::shared_ptr> m_skyColors = nullptr; +}; + +#endif //AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 244e8ab34..58440bbda 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -5,10 +5,45 @@ #include "MapSceneRenderForwardVLK.h" #include "../../vulkan/IRenderFunctionVLK.h" #include "../../../engine/objects/scenes/map.h" - -MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(HGDeviceVLK hDevice) : m_device(hDevice) { - +#include "../../../gapi/vulkan/materials/MaterialBuilderVLK.h" +#include "../../../gapi/vulkan/meshes/GMeshVLK.h" +#include "../../../gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "materials/IMaterialInstance.h" + +MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : + m_device(hDevice), MapSceneRenderer(config) { + iboBuffer = m_device->createIndexBuffer(1024*1024); + + vboM2Buffer = m_device->createVertexBuffer(1024*1024); + vboAdtBuffer = m_device->createVertexBuffer(1024*1024); + vboWMOBuffer = m_device->createVertexBuffer(1024*1024); + vboWaterBuffer = m_device->createVertexBuffer(1024*1024); + vboSkyBuffer = m_device->createVertexBuffer(1024*1024); + + uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); + + m_emptyM2VAO = createM2VAO(nullptr, nullptr); + + //Framebuffers for rendering + auto const dataFormat = { ITextureFormat::itRGBA }; + + m_renderPass = hDevice->getRenderPass(dataFormat, ITextureFormat::itDepth32, + sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), + true, false); + + for (auto & colorFrameBuffer : m_colorFrameBuffers) { + colorFrameBuffer = std::make_shared( + *hDevice, + dataFormat, + ITextureFormat::itDepth32, + hDevice->getMaxSamplesCnt(), + 640, 480 + ); + } + + sceneWideChunk = std::make_shared>(uboBuffer); } + // ------------------ // Buffer creation // ------------------ @@ -41,49 +76,115 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createWaterVAO(HGVertexBuffer v HGVertexBufferBindings MapSceneRenderForwardVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto skyVAO = m_device->createVertexBufferBindings(); - skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); + skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(skyConusBinding.begin(), skyConusBinding.end())); skyVAO->setIndexBuffer(indexBuffer); return skyVAO; } HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { - return HGVertexBuffer(); + return vboM2Buffer->getSubBuffer(sizeInBytes); } HGIndexBuffer MapSceneRenderForwardVLK::createM2IndexBuffer(int sizeInBytes) { - return HGIndexBuffer(); + return iboBuffer->getSubBuffer(sizeInBytes); } HGVertexBuffer MapSceneRenderForwardVLK::createADTVertexBuffer(int sizeInBytes) { - return HGVertexBuffer(); + return vboAdtBuffer->getSubBuffer(sizeInBytes); } HGIndexBuffer MapSceneRenderForwardVLK::createADTIndexBuffer(int sizeInBytes) { - return HGIndexBuffer(); + return iboBuffer->getSubBuffer(sizeInBytes); } HGVertexBuffer MapSceneRenderForwardVLK::createWMOVertexBuffer(int sizeInBytes) { - return HGVertexBuffer(); + return vboWMOBuffer->getSubBuffer(sizeInBytes); } HGIndexBuffer MapSceneRenderForwardVLK::createWMOIndexBuffer(int sizeInBytes) { - return HGIndexBuffer(); + return iboBuffer->getSubBuffer(sizeInBytes); } HGVertexBuffer MapSceneRenderForwardVLK::createWaterVertexBuffer(int sizeInBytes) { - return HGVertexBuffer(); + return vboWaterBuffer->getSubBuffer(sizeInBytes); } HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) { - return HGIndexBuffer(); + return iboBuffer->getSubBuffer(sizeInBytes); } HGVertexBuffer MapSceneRenderForwardVLK::createSkyVertexBuffer(int sizeInBytes) { - return HGVertexBuffer(); + return vboSkyBuffer->getSubBuffer(sizeInBytes);; }; HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { - return HGIndexBuffer(); + return iboBuffer->getSubBuffer(sizeInBytes); +} + +struct BufferChunkHelper { +public: + template + static const inline std::shared_ptr> cast(const std::shared_ptr> &chunk) { + return std::dynamic_pointer_cast>(chunk); + } + + template + static const inline void create(const HGBufferVLK &parentBuffer, std::shared_ptr> &chunk, int realSize = -1) { + chunk = std::make_shared>(parentBuffer, realSize); + } +}; + + +std::shared_ptr +MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) { + + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexData = std::make_shared>(uboBuffer); + auto fragmentData = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelper::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, BufferChunkHelper::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo(2, BufferChunkHelper::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(3, BufferChunkHelper::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) + .ubo(4, vertexData->getSubBuffer()) + .ubo(5, fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(6, std::dynamic_pointer_cast(m2MaterialTemplate.texture0)) + .texture(7, std::dynamic_pointer_cast(m2MaterialTemplate.texture1)) + .texture(8, std::dynamic_pointer_cast(m2MaterialTemplate.texture2)); + }) + .toMaterial([&vertexData, &fragmentData](IM2Material *instance) -> void { + instance->m_fragmentData = fragmentData; + instance->m_vertexData = vertexData; + }); + + return material; +} + +std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto skyColors = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelper::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, skyColors->getSubBuffer()); + }) + .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { + instance->m_skyColors = skyColors; + }); + + return material; } std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, @@ -96,6 +197,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha mapScene->update(framePlan); + return createRenderFuncVLK([](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { }); @@ -105,3 +207,17 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { return nullptr; } +std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount) { + auto result = std::make_shared(); + + BufferChunkHelper::create(uboBuffer, result->m_placementMatrix); + BufferChunkHelper::create(uboBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelper::create(uboBuffer, result->m_modelFragmentData); + + return result; +} + +HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { + return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); +} + diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 420b229e1..ddbc9b62b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -8,10 +8,11 @@ #include "../MapSceneRenderer.h" #include "../../../gapi/vulkan/GDeviceVulkan.h" +#include "../materials/IMaterialStructs.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { public: - explicit MapSceneRenderForwardVLK(HGDeviceVLK hDevice); + explicit MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config); ~MapSceneRenderForwardVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; @@ -26,7 +27,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; - HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; @@ -41,10 +41,33 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) override; HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) override; + + std::shared_ptr createM2ModelMat(int bonesCount) override; + std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; + + HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; private: HGDeviceVLK m_device; + HGBufferVLK vboM2Buffer; + HGBufferVLK vboAdtBuffer; + HGBufferVLK vboWMOBuffer; + HGBufferVLK vboWaterBuffer; + HGBufferVLK vboSkyBuffer; + + HGBufferVLK iboBuffer; + HGBufferVLK uboBuffer; + + std::shared_ptr> sceneWideChunk; + + std::shared_ptr m_renderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + + HGVertexBufferBindings m_emptyM2VAO = nullptr; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h new file mode 100644 index 000000000..bc0c70292 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h @@ -0,0 +1,28 @@ +// +// Created by Deamon on 3/8/2023. +// + +#ifndef AWEBWOWVIEWERCPP_IMATERIALINSTANCE_H +#define AWEBWOWVIEWERCPP_IMATERIALINSTANCE_H + + +#include "../../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" +#include "../../materials/IMaterialStructs.h" + +template +class IMaterialInstance : public ISimpleMaterialVLK, public IMaterialClass { +public: + inline IMaterialInstance( + const std::function &initializer, + const HGShaderPermutation &shader, + const PipelineTemplate &pipelineTemplate, + const HPipelineVLK &pipeline, + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : + ISimpleMaterialVLK(shader, pipelineTemplate, pipeline, descriptorSets) { + + initializer(this); + } +}; + + +#endif //AWEBWOWVIEWERCPP_IMATERIALINSTANCE_H From 51d171c453f86c0790c647ae9ec639aea2f756e6 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 16 Mar 2023 01:34:00 +0200 Subject: [PATCH 046/212] m2 mesh creation --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- .../objects/m2/m2Helpers/M2MaterialInst.h | 6 - .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 81 +++----- .../m2/m2Helpers/M2MeshBufferUpdater.h | 3 +- .../src/engine/objects/m2/m2Object.cpp | 191 +++++++----------- wowViewerLib/src/engine/objects/m2/m2Object.h | 22 +- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/m2Scene.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 6 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 6 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 3 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 10 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 7 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 1 + .../mapScene/materials/IMaterialStructs.h | 9 +- 15 files changed, 136 insertions(+), 217 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index ceb344ee6..f60084b5b 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -75,7 +75,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtextur } HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); } std::unique_ptr FrontendUIRenderForwardVLK::update( diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MaterialInst.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MaterialInst.h index 682ac2ae9..18623d92f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MaterialInst.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MaterialInst.h @@ -15,12 +15,6 @@ class M2MaterialInst; class M2MaterialInst { public: - bool isRendered= false; - bool isTransparent= false; - - int textureCount; - std::array textures; - int layer = 0; int renderFlagIndex = -1; int batchIndex = -1; diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 16c4f935b..3ee67a89d 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -21,67 +21,46 @@ float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int b return finalTransparency; } -void M2MeshBufferUpdater::assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object, M2MaterialInst &materialData, M2Data * m2Data, M2SkinProfile * m2SkinProfile) { - auto blendMode = hmesh->getGxBlendMode(); - int batchIndex = materialData.batchIndex; - auto vertexShader = materialData.vertexShader; - +void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr &m2Material, int batchIndex, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile){ std::shared_ptr> meshWideBlockVS = nullptr; - meshWideBlockVS->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, vertexShader](auto &data, const HFrameDependantData &frameDepedantData){ - auto m2Data = m2Object->m_m2Geom->getM2Data(); - - auto batch = m2SkinProfile->batches[batchIndex]; - int renderFlagIndex = batch->materialIndex; - auto renderFlag = m2Data->materials[renderFlagIndex]; + auto batch = m2SkinProfile->batches[batchIndex]; + int renderFlagIndex = batch->materialIndex; + auto renderFlag = m2Data->materials[renderFlagIndex]; - mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object->subMeshColors); + mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object->subMeshColors); + float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); - float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); + //2. Update VS buffer + auto &meshblockVS = m2Material->m_vertexData->getObject(); + meshblockVS.Color_Transparency = mathfu::vec4_packed(mathfu::vec4(meshColor.x, meshColor.y, meshColor.z, finalTransparency)); + meshblockVS.isSkyBox = m2Object->m_boolSkybox ? 1 : 0; + meshblockVS.VertexShader = m2Material->vertexShader; + meshblockVS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; - auto &meshblockVS = data; - meshblockVS.Color_Transparency = mathfu::vec4_packed(mathfu::vec4(meshColor.x, meshColor.y, meshColor.z, finalTransparency)); - meshblockVS.isSkyBox = m2Object->m_boolSkybox ? 1 : 0; - meshblockVS.VertexShader = vertexShader; - meshblockVS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; + fillTextureMatrices(*m2Object, batchIndex, m2Data, m2SkinProfile, meshblockVS.uTextMat); - fillTextureMatrices(*m2Object, batchIndex, m2Data, m2SkinProfile, meshblockVS.uTextMat); - }); //3. Update individual PS buffer - auto pixelShader = materialData.pixelShader; - std::shared_ptr> meshWideBlockPS = nullptr; - meshWideBlockPS->setUpdateHandler([m2Object, m2SkinProfile, blendMode, batchIndex, pixelShader](auto &data, const HFrameDependantData &frameDepedantData) { - auto m2Data = m2Object->m_m2Geom->getM2Data(); - - auto batch = m2SkinProfile->batches[batchIndex]; - int renderFlagIndex = batch->materialIndex; - auto renderFlag = m2Data->materials[renderFlagIndex]; - - float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); - - mathfu::vec4 uTexSampleAlpha = mathfu::vec4(1.0, 1.0, 1.0, 1.0); - for (int i = 0; i < std::max(batch->textureCount, 4); i++) { - uTexSampleAlpha[i] = M2Object::getTextureWeight(m2SkinProfile, m2Data, batchIndex, i, m2Object->transparencies); - } - - float uAlphaTest; - if (blendMode == EGxBlendEnum::GxBlend_AlphaKey) { - uAlphaTest = 128.0f/255.0f * finalTransparency; //Maybe move this to shader logic? - } else { - uAlphaTest = 1.0f/255.0f; - } + float uAlphaTest; + if (m2Material->blendMode == EGxBlendEnum::GxBlend_AlphaKey) { + uAlphaTest = 128.0f/255.0f * finalTransparency; //Maybe move this to shader logic? + } else { + uAlphaTest = 1.0f/255.0f; + } -// mathfu::vec3 uFogColor = getFogColor(blendMode, uGlobalFogColor); + //Fill values into buffer + mathfu::vec4 uTexSampleAlpha = mathfu::vec4(1.0, 1.0, 1.0, 1.0); + for (int i = 0; i < std::max(batch->textureCount, 4); i++) { + uTexSampleAlpha[i] = M2Object::getTextureWeight(m2SkinProfile, m2Data, batchIndex, i, m2Object->transparencies); + } - //Fill values into buffer - auto &meshblockPS = data; - meshblockPS.PixelShader = pixelShader; - meshblockPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; - meshblockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; - meshblockPS.BlendMode = static_cast(blendMode); - meshblockPS.uTexSampleAlpha = uTexSampleAlpha; - }); + auto &meshBlockPS = m2Material->m_fragmentData->getObject(); + meshBlockPS.PixelShader = m2Material->pixelShader; + meshBlockPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; + meshBlockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; + meshBlockPS.BlendMode = static_cast(m2Material->blendMode); + meshBlockPS.uTexSampleAlpha = uTexSampleAlpha; } void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index 8e7c067e8..e15cfb69a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -16,7 +16,8 @@ class M2MeshBufferUpdater { public: static float calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile); - static void assignUpdateEvents(HGM2Mesh &hmesh, M2Object *m2Object, M2MaterialInst &materialData, M2Data * m2Data, M2SkinProfile * m2SkinProfile); + + static void updateMaterialData(const std::shared_ptr &m2Material, int batchIndex, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile); static void fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 7b4cd9651..84d2f38eb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -823,15 +823,15 @@ void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) { M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { - for (int i = 0; i < this->m_meshNaturalArray.size(); i++) { + for (int i = 0; i < this->m_meshArray.size(); i++) { //Update info for sorting - M2MeshBufferUpdater::updateSortData(this->m_meshNaturalArray[i], *this, i, m2File, + M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshArray[i]), *this, i, m2File, skinData, modelViewMat); } for (int i = 0; i < this->m_meshForcedTranspArray.size(); i++) { //Update info for sorting - if (this->m_meshForcedTranspArray[i] != nullptr) { - M2MeshBufferUpdater::updateSortData(this->m_meshForcedTranspArray[i], *this, i, m2File, + if (std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { + M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshForcedTranspArray[i]), *this, i, m2File, skinData, modelViewMat); } } @@ -1234,7 +1234,7 @@ void M2Object::drawBB(mathfu::vec3 &color) { } -bool M2Object::prepearMaterial(M2MaterialInst &materialData, int batchIndex) { +bool M2Object::prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex) { auto &skinSections = m_skinGeom->getSkinData()->skinSections; M2Array* batches = &m_skinGeom->getSkinData()->batches; @@ -1243,7 +1243,6 @@ bool M2Object::prepearMaterial(M2MaterialInst &materialData, int batchIndex) { M2Batch* m2Batch = batches->getElement(batchIndex); auto skinSection = skinSections[m2Batch->skinSectionIndex]; - { auto meshGroup = (skinSection->skinSectionId / 100); if ((meshGroup < this->m_meshIds.size()) && (skinSection->skinSectionId > 0) && @@ -1251,42 +1250,28 @@ bool M2Object::prepearMaterial(M2MaterialInst &materialData, int batchIndex) { return false; } } -// materialArray.push(materialData); - - auto op_count = m2Batch->textureCount; - auto renderFlagIndex = m2Batch->materialIndex; - auto isTransparent = (m2File->materials[renderFlagIndex]->blending_mode >= 2) || - ((m2File->materials[renderFlagIndex]->flags & 0x10) > 0); - - materialData.layer = m2Batch->materialLayer; - materialData.isRendered = true; - materialData.isTransparent = isTransparent; - materialData.renderFlagIndex = m2Batch->materialIndex; - materialData.batchIndex = batchIndex; - materialData.flags = m2Batch->flags; - materialData.priorityPlane = m2Batch->priorityPlane; + auto textureCount = m2Batch->textureCount; if (m_api->getConfig()->useWotlkLogic) { std::string vertexShader; std::string pixelShader; getShaderNames(m2Batch, vertexShader, pixelShader); - //TODO: this his hack!!! - if (pixelShader == "") { - materialData.pixelShader = 0; + //TODO: this is hack!!! + if (pixelShader.empty()) { + materialTemplate.pixelShader = 0; } else { - materialData.pixelShader = pixelShaderTable.at(pixelShader); + materialTemplate.pixelShader = pixelShaderTable.at(pixelShader); } } else { //Legion logic - materialData.pixelShader = getPixelShaderId(m2Batch->textureCount, m2Batch->shader_id); - materialData.vertexShader = getVertexShaderId(m2Batch->textureCount, m2Batch->shader_id); + materialTemplate.pixelShader = getPixelShaderId(m2Batch->textureCount, m2Batch->shader_id); + materialTemplate.vertexShader = getVertexShaderId(m2Batch->textureCount, m2Batch->shader_id); } - materialData.textureCount = op_count; - for (int j = 0; j < op_count; j++) { + for (int j = 0; j < textureCount; j++) { auto m2TextureIndex = *m2File->texture_lookup_table[m2Batch->textureComboIndex + j]; - materialData.textures[j] = getTexture(m2TextureIndex); + materialTemplate.textures[j] = getTexture(m2TextureIndex); } return true; @@ -1399,7 +1384,7 @@ HGM2Mesh M2Object::createWaterfallMesh() { pipelineTemplate.depthWrite = false; pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; - pipelineTemplate.triCCW = 1; + pipelineTemplate.triCCW = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; @@ -1464,39 +1449,10 @@ HGM2Mesh M2Object::createWaterfallMesh() { return nullptr; } -void M2Object::createMaterials(const HMapSceneBufferCreate &sceneRenderer) { - //Create materials - const auto &materials = m_skinGeom->getSkinData()->skinSections; - - for (int i = 0; i < materials.size; i++) { - M2SkinSection * material = materials[i]; - - PipelineTemplate pipelineTemplate; - - int renderFlagIndex = m2Batch->materialIndex; - auto renderFlag = m_m2Data->materials[renderFlagIndex]; - - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); - pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); - pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); - pipelineTemplate.triCCW = true; - - if (overrideBlend) { - pipelineTemplate.blendMode = blendMode; - } else { - pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; - blendMode = pipelineTemplate.blendMode; - } - - sceneRenderer->createM2Material() - - } -} -void M2Object::createMeshes() { +void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { /* 1. Free previous subMeshArray */ - this->m_meshNaturalArray.clear(); + this->m_meshArray.clear(); this->m_meshForcedTranspArray.clear(); this->m_materialArray.clear(); @@ -1513,45 +1469,35 @@ void M2Object::createMeshes() { const auto &batches = m_skinGeom->getSkinData()->batches; if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { - - - for (int i = 0; i < batches.size; i++) { - auto m2Batch = batches[i]; + for (int batchIndex = 0; batchIndex < batches.size; batchIndex++) { + auto m2Batch = batches[batchIndex]; auto skinSection = skinProfile->skinSections[m2Batch->skinSectionIndex]; if (!checkifBonesAreInRange(skinProfile, skinSection)) { - batchesRequiringDynamicVao.push_back(i); + batchesRequiringDynamicVao.push_back(batchIndex); continue; } EGxBlendEnum mainBlendMode; - HGM2Mesh hmesh = createSingleMesh(m_m2Data, i, 0, bufferBindings, m2Batch, skinSection, material, - mainBlendMode, false); + HGM2Mesh hmesh = createSingleMesh(sceneRenderer, m_m2Data, batchIndex, 0, bufferBindings, m2Batch, skinSection, mainBlendMode, false); if (hmesh == nullptr) continue; - this->m_materialArray.push_back(material); - this->m_meshNaturalArray.push_back({hmesh, i}); - M2MeshBufferUpdater::assignUpdateEvents(hmesh, this, m_materialArray[m_materialArray.size() - 1], m_m2Data, - skinProfile); + this->m_meshArray.emplace_back(hmesh, batchIndex); if (mainBlendMode == EGxBlendEnum::GxBlend_Opaque) { EGxBlendEnum blendMode = EGxBlendEnum::GxBlend_Alpha; - M2MaterialInst materialTransp; - HGM2Mesh hmeshTrans = createSingleMesh(m_m2Data, i, 0, bufferBindings, m2Batch, skinSection, - materialTransp, blendMode, true); - - this->m_materialArray.push_back(material); - this->m_meshForcedTranspArray.push_back(hmeshTrans); - M2MeshBufferUpdater::assignUpdateEvents(hmeshTrans, this, m_materialArray[m_materialArray.size() - 1], - m_m2Data, skinProfile); + HGM2Mesh hmeshTrans = createSingleMesh(sceneRenderer, m_m2Data, batchIndex, 0, bufferBindings, m2Batch, skinSection, blendMode, true); + this->m_meshForcedTranspArray.emplace_back(hmeshTrans, batchIndex); } else { - m_meshForcedTranspArray.push_back(nullptr); + m_meshForcedTranspArray.emplace_back(nullptr, -1); } } // Create meshes requiring dynamic + //TODO: + /* for (int j = 0; j < batchesRequiringDynamicVao.size(); j++) { int i = batchesRequiringDynamicVao[j]; auto m2Batch = skinProfile->batches[i]; @@ -1587,61 +1533,61 @@ void M2Object::createMeshes() { } dynamicMeshes.push_back(dynamicMeshData); - } + }*/ } else { - m_meshNaturalArray.push_back(createWaterfallMesh()); + m_meshArray.push_back({createWaterfallMesh(), 0}); } } HGM2Mesh -M2Object::createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, const M2Batch *m2Batch, - const M2SkinSection *skinSection, M2MaterialInst &material, EGxBlendEnum &blendMode, bool overrideBlend) { - - if (!prepearMaterial(material, i)) return nullptr; - - M2ShaderCacheRecord cacheRecord{}; - cacheRecord.vertexShader = material.vertexShader; - cacheRecord.pixelShader = material.pixelShader; - cacheRecord.unlit = true; - cacheRecord.alphaTestOn = true; - cacheRecord.unFogged = true; - cacheRecord.unShadowed = true; - if (skinSection->boneInfluences > 0) { - cacheRecord.boneInfluences = skinSection->boneInfluences; +M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, + const M2Data *m_m2Data, int batchIndex, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, + const M2Batch *m2Batch, const M2SkinSection *skinSection, + EGxBlendEnum &blendMode, bool overrideBlend) { + + M2MaterialTemplate materialTemplate; + + if (!prepearMaterial(materialTemplate, batchIndex)) return nullptr; + + gMeshTemplate meshTemplate(finalBufferBindings); + + int materialIndex = m2Batch->materialIndex; + auto renderFlag = m_m2Data->materials[materialIndex]; + + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); + pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); + pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); + pipelineTemplate.triCCW = true; + if (overrideBlend) { + pipelineTemplate.blendMode = blendMode; } else { - cacheRecord.boneInfluences = skinSection->boneCount > 0 ? 1 : 0; + pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; + blendMode = pipelineTemplate.blendMode; } - HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("m2Shader", "m2Shader", &cacheRecord); - gMeshTemplate meshTemplate(finalBufferBindings); + auto renderFlagIndex = m2Batch->materialIndex; + auto isTransparent = (m_m2Data->materials[renderFlagIndex]->blending_mode >= 2) || + ((m_m2Data->materials[renderFlagIndex]->flags & 0x10) > 0); + auto m2Material = sceneRenderer->createM2Material(m_modelWideDataBuff, pipelineTemplate, materialTemplate); + this->m_materialArray.emplace_back(m2Material); meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; meshTemplate.skybox = m_boolSkybox; - HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; - meshTemplate.texture.resize(4); + auto m2Mesh = sceneRenderer->createM2Mesh(meshTemplate, m2Material, isTransparent, m2Batch->materialLayer, m2Batch->priorityPlane); - for (int j = 0; j < material.textureCount; j++) { - meshTemplate.texture[j] = material.textures[j]; - } - - //Make mesh - //TODO: - auto hmesh = m_api->hDevice->createMesh(meshTemplate); - hmesh->setLayer(m2Batch->materialLayer); - hmesh->setPriorityPlane(m2Batch->priorityPlane); - hmesh->setQuery(nullptr); - - return hmesh; + return m2Mesh; } void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; - int maxBatch = std::min(m_api->getConfig()->m2MaxBatch, (const int &) this->m_meshNaturalArray.size()); + int maxBatch = std::min(m_api->getConfig()->m2MaxBatch, (const int &) this->m_meshArray.size()); if (m_api->getConfig()->renderM2) { for (int i = minBatch; i < maxBatch; i++) { @@ -1649,10 +1595,10 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorm_meshNaturalArray[i]; + HGM2Mesh mesh = std::get<0>(this->m_meshArray[i]); if (finalTransparency < 0.999 && i < this->m_meshForcedTranspArray.size() && - this->m_meshForcedTranspArray[i] != nullptr) { - mesh = this->m_meshForcedTranspArray[i]; + std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { + mesh = std::get<0>(this->m_meshForcedTranspArray[i]); } if (mesh->getIsTransparent()) { @@ -1723,7 +1669,6 @@ void M2Object::initParticleEmitters() { } void M2Object::initRibbonEmitters() { -// return; ribbonEmitters = std::vector(); // ribbonEmitters.reserve(m_m2Geom->getM2Data()->ribbon_emitters.size); auto m2Data = m_m2Geom->getM2Data(); @@ -2001,18 +1946,18 @@ void M2Object::updateDynamicMeshes() { // std::cout << "Saved " << skinSection->vertexCount << " vertices " << "at update frame =" << frameNum << std::endl; } } -void M2Object::setReplaceTextures(std::vector &replaceTextures) { +void M2Object::setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextures) { m_replaceTextures = replaceTextures; if (m_loaded) { - createMeshes(); // recreate meshes + createMeshes(sceneRenderer); // recreate meshes } } -void M2Object::setMeshIds(std::vector &meshIds) { +void M2Object::setMeshIds(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) { m_meshIds = meshIds; if (m_loaded) { - createMeshes(); // recreate meshes + createMeshes(sceneRenderer); // recreate meshes } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index f143671e2..d241f9234 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -132,13 +132,14 @@ class M2Object { std::unordered_map loadedTextures; - //Tuple of Mesh and batchIndex - std::vector> m_meshNaturalArray; + //Material + std::vector> m_materialArray; + //Tuple of Mesh and BatchIndex std::vector> m_meshForcedTranspArray; + std::vector> m_meshArray; //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; - std::vector m_materialArray; AnimationManager *m_animationManager; bool m_interiorAmbientWasSet = false; // For static only @@ -163,8 +164,7 @@ class M2Object { bool checkifBonesAreInRange(M2SkinProfile *skinProfile, M2SkinSection *mesh); - void createMaterials(const HMapSceneBufferCreate &sceneRenderer); - void createMeshes(); + void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void createBoundingBoxMesh(); static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; @@ -197,8 +197,8 @@ class M2Object { void setLoadParams(int skinNum, std::vector meshIds, std::vector replaceTextures); - void setReplaceTextures(std::vector &replaceTextures); - void setMeshIds(std::vector &meshIds); + void setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextures); + void setMeshIds(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds); void setReplaceParticleColors(std::array, 3> &particleColorReplacement); void resetReplaceParticleColor(); bool getReplaceParticleColors(std::array, 3> &particleColorReplacement); @@ -240,7 +240,7 @@ class M2Object { bool getGetIsLoaded() { return m_loaded; }; mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; - bool prepearMaterial(M2MaterialInst &materialData, int materialIndex); + bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { @@ -297,8 +297,10 @@ class M2Object { return m_m2Geom->m_m2Data->cameras.size; } - HGM2Mesh createSingleMesh(const M2Data *m_m2Data, int i, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, const M2Batch *m2Batch, - const M2SkinSection *skinSection, M2MaterialInst &material, EGxBlendEnum &blendMode, bool overrideBlend); + HGM2Mesh createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, + const M2Data *m_m2Data, int i, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, + const M2Batch *m2Batch, const M2SkinSection *skinSection, + EGxBlendEnum &blendMode, bool overrideBlend); HGM2Mesh createWaterfallMesh(); void updateDynamicMeshes(); diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index ba38b80e1..b9f0110de 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -54,7 +54,7 @@ extern "C" { extern void offerFileAsDownload(std::string filename, std::string mime); } -void M2Scene::setReplaceTextureArray(std::vector &replaceTextureArray) { +void M2Scene::setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextureArray) { //std::cout << "replaceTextureArray.size == " << replaceTextureArray.size() << std::endl; //std::cout << "m_m2Object == " << m_m2Object << std::endl; if (m_m2Object == nullptr) return; @@ -73,7 +73,7 @@ void M2Scene::setReplaceTextureArray(std::vector &replaceTextureArray) { } } - m_m2Object->setReplaceTextures(replaceTextures); + m_m2Object->setReplaceTextures(sceneRenderer, replaceTextures); } void M2Scene::setMeshIdArray(std::vector &meshIds) { diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index 03590f8d0..0c9c22ae5 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -40,7 +40,7 @@ class M2Scene : public Map { } - void setReplaceTextureArray(std::vector &replaceTextureArray) ; + void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextureArray) ; void setMeshIdArray(std::vector &meshIds) ; void setReplaceParticleColors(std::array, 3> &particleColorReplacement) ; void resetReplaceParticleColor() ; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index ccf93cd97..3c836895f 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1214,7 +1214,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,64}, + {0,4,32}, {0,3,256}, {0,0,368}, {0,1,14144}, @@ -2171,9 +2171,7 @@ const std::unordered_mapgetPipeline()->getIsTransparent(); +GM2MeshVLK::GM2MeshVLK(const gMeshTemplate &meshTemplate, + const HMaterialVLK &material) : GMeshVLK(meshTemplate, material){ } void GM2MeshVLK::setLayer(int layer) { diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index 5ad71b8e4..958a96c94 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -10,8 +10,7 @@ class GM2MeshVLK : public GMeshVLK, public IM2Mesh { friend class GDeviceVLK; protected: - GM2MeshVLK(IDevice &device, const gMeshTemplate &meshTemplate, - const HMaterialVLK &material); + GM2MeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material); public: void setLayer(int layer) override; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 5abe8bab1..a7346ca0a 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -7,11 +7,11 @@ #include "GMeshVLK.h" #include "../textures/GTextureVLK.h" #include "../shaders/GShaderPermutationVLK.h" +#include "../GPipelineVLK.h" -GMeshVLK::GMeshVLK(IDevice &device, - const gMeshTemplate &meshTemplate, - const HMaterialVLK &material -) : m_device(dynamic_cast(device)), m_meshType(meshTemplate.meshType), m_material(material) { +GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, + const HMaterialVLK &material +) : m_meshType(meshTemplate.meshType), m_material(material) { m_bindings = meshTemplate.bindings; @@ -21,6 +21,8 @@ GMeshVLK::GMeshVLK(IDevice &device, m_scissorOffset = meshTemplate.scissorOffset; } + m_isTransparent = material->getPipeline()->getIsTransparent(); + m_start = meshTemplate.start; m_end = meshTemplate.end; } diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 4c840d896..dfa48232e 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -14,10 +14,8 @@ class GMeshVLK : virtual public IMesh { friend class GDeviceVLK; public: - explicit GMeshVLK(IDevice &device, - const gMeshTemplate &meshTemplate, - const HMaterialVLK &material - ); + explicit GMeshVLK(const gMeshTemplate &meshTemplate, + const HMaterialVLK &material); public: ~GMeshVLK() override; @@ -47,7 +45,6 @@ class GMeshVLK : virtual public IMesh { std::shared_ptr m_lastRenderPass = nullptr; std::shared_ptr m_lastPipelineForRenderPass; private: - GDeviceVLK &m_device; HMaterialVLK m_material; }; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 3d7b0b7fb..e41c0af17 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -66,6 +66,7 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; + virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, bool isTransparent, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 8e0fc5532..ad8ec8bda 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -9,9 +9,9 @@ #include "../../../gapi/UniformBufferStructures.h" struct M2MaterialTemplate { - const HGTexture texture0 = nullptr; - const HGTexture texture1 = nullptr; - const HGTexture texture2 = nullptr; + int vertexShader; + int pixelShader; + std::array textures = {nullptr, nullptr, nullptr}; }; class IM2ModelData { @@ -23,6 +23,9 @@ class IM2ModelData { class IM2Material : public IMaterial { public: + int vertexShader; + int pixelShader; + EGxBlendEnum blendMode; std::shared_ptr> m_vertexData = nullptr; std::shared_ptr> m_fragmentData = nullptr; }; From 9956b5322e668395937362a771db2b1dd248279d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 16 Mar 2023 22:56:59 +0200 Subject: [PATCH 047/212] 1 step from rendering m2 --- src/ui/FrontendUI.cpp | 4 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 8 +- .../glsl/forwardRendering/m2Shader.frag | 14 +-- .../glsl/forwardRendering/m2Shader.vert | 5 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 15 +-- .../src/engine/objects/m2/m2Object.cpp | 35 ++++--- wowViewerLib/src/engine/objects/m2/m2Object.h | 12 +-- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/m2Scene.h | 2 +- .../src/engine/objects/scenes/map.cpp | 54 +---------- .../src/engine/shader/ShaderDefinitions.h | 42 +++++---- .../src/gapi/interface/meshes/IM2Mesh.h | 1 - .../gapi/interface/meshes/ITransparentMesh.h | 2 + .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 8 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 32 ++++--- .../vulkan/descriptorSets/GDescriptorSet.h | 2 +- .../descriptorSets/GDescriptorSetLayout.cpp | 9 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 4 + .../vulkan/materials/ISimpleMaterialVLK.h | 1 + .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 6 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 4 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 2 +- .../renderer/mapScene/MapSceneRenderer.cpp | 67 +++++++++++++- .../src/renderer/mapScene/MapSceneRenderer.h | 8 +- .../mapScene/materials/IMaterialStructs.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 92 +++++++++++++++++-- .../vulkan/MapSceneRenderForwardVLK.h | 2 + 27 files changed, 280 insertions(+), 157 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 6584cc031..df6132e6a 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1685,7 +1685,7 @@ void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementText m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2Fdid); m_currentScene = m2Scene; - m2Scene->setReplaceTextureArray(replacementTextureIds); + m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); m_api->camera = std::make_shared(); @@ -1700,7 +1700,7 @@ void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &rep auto m2Scene = std::make_shared(m_api, m2FileName); m_currentScene = m2Scene; - m2Scene->setReplaceTextureArray(replacementTextureIds); + m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); m_api->camera = std::make_shared(); m_api->camera->setCameraPos(0, 0, 0); diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 6a703fb58..3bd10836d 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -93,11 +93,11 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrgetIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((fb_height - clip_rect.w)* uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x) * uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + meshTemplate.scissorOffset = {static_cast(clip_rect.x * uiScale), static_cast((fb_height - clip_rect.w)* uiScale)}; + meshTemplate.scissorSize = {static_cast((clip_rect.z - clip_rect.x) * uiScale), static_cast((clip_rect.w - clip_rect.y)* uiScale)}; } else { - meshTemplate.scissorOffset = {(int)(clip_rect.x * uiScale), (int)((clip_rect.y) * uiScale)}; - meshTemplate.scissorSize = {(int)((clip_rect.z - clip_rect.x)* uiScale), (int)((clip_rect.w - clip_rect.y)* uiScale)}; + meshTemplate.scissorOffset = {static_cast(clip_rect.x * uiScale), static_cast((clip_rect.y) * uiScale)}; + meshTemplate.scissorSize = {static_cast((clip_rect.z - clip_rect.x)* uiScale), static_cast((clip_rect.w - clip_rect.y)* uiScale)}; } meshTemplate.start = pcmd->IdxOffset * 2; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index e25bf3362..0b355f033 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -34,11 +34,11 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=1) uniform modelWideBlockVS { +layout(std140, set=0, binding=1) uniform placementMat { mat4 uPlacementMat; - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; }; + //Whole model layout(std140, set=0, binding=3) uniform modelWideBlockPS { InteriorLightParam intLight; @@ -48,15 +48,15 @@ layout(std140, set=0, binding=3) uniform modelWideBlockPS { }; //Individual meshes -layout(std140, set=0, binding=4) uniform meshWideBlockPS { +layout(std140, set=0, binding=5) uniform meshWideBlockPS { ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; vec4 uTexSampleAlpha; }; -layout(set=1,binding=5) uniform sampler2D uTexture; -layout(set=1,binding=6) uniform sampler2D uTexture2; -layout(set=1,binding=7) uniform sampler2D uTexture3; -layout(set=1,binding=8) uniform sampler2D uTexture4; +layout(set=1,binding=6) uniform sampler2D uTexture; +layout(set=1,binding=7) uniform sampler2D uTexture2; +layout(set=1,binding=8) uniform sampler2D uTexture3; +layout(set=1,binding=9) uniform sampler2D uTexture4; void main() { /* Animation support */ diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 7267361f3..5a366feec 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -31,11 +31,14 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { // Whole model layout(std140, set=0, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; +}; + +layout(std140, set=0, binding=2) uniform boneMats { mat4 uBoneMatrixes[MAX_MATRIX_NUM]; }; //Individual meshes -layout(std140, set=0, binding=2) uniform meshWideBlockVS { +layout(std140, set=0, binding=4) uniform meshWideBlockVS { ivec4 vertexShader_IsAffectedByLight; vec4 color_Transparency; mat4 uTextMat[2]; diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 5d34273f0..e9d57258a 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -402,21 +402,8 @@ HGVertexBufferBindings M2Geom::getVAO(const HMapSceneBufferCreate &sceneRenderer HGIndexBuffer iboBuffer = skinGeom->getIBO(sceneRenderer); - //2. Create buffer binding and fill it - //TODO: - /* - bufferBindings = device->createVertexBufferBindings(); - bufferBindings->setIndexBuffer(iboBuffer); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = vboBuffer; - vertexBinding.bindings = std::vector(&staticM2Bindings[0], &staticM2Bindings[6]); - - bufferBindings->addVertexBufferBinding(vertexBinding); - bufferBindings->save(); - + bufferBindings = sceneRenderer->createM2VAO(vertexVbo, iboBuffer); vaoMap[skinGeom] = bufferBindings; - */ } return bufferBindings; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 84d2f38eb..bf1e64777 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -825,13 +825,13 @@ void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) { if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { for (int i = 0; i < this->m_meshArray.size(); i++) { //Update info for sorting - M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshArray[i]), *this, i, m2File, + M2MeshBufferUpdater::updateSortData(this->m_meshArray[i], *this, i, m2File, skinData, modelViewMat); } for (int i = 0; i < this->m_meshForcedTranspArray.size(); i++) { //Update info for sorting - if (std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { - M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshForcedTranspArray[i]), *this, i, m2File, + if (this->m_meshForcedTranspArray[i] != nullptr) { + M2MeshBufferUpdater::updateSortData(this->m_meshForcedTranspArray[i], *this, i, m2File, skinData, modelViewMat); } } @@ -1096,8 +1096,12 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_modelFragmentData->save(); } + for (auto [material, batchIndex] : m_materialArray) { + M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); + } + //Manually update vertices for dynamics - updateDynamicMeshes(); +// updateDynamicMeshes(); int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); @@ -1269,7 +1273,7 @@ bool M2Object::prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIn materialTemplate.vertexShader = getVertexShaderId(m2Batch->textureCount, m2Batch->shader_id); } - for (int j = 0; j < textureCount; j++) { + for (int j = 0; j < std::min(textureCount, 4); j++) { auto m2TextureIndex = *m2File->texture_lookup_table[m2Batch->textureComboIndex + j]; materialTemplate.textures[j] = getTexture(m2TextureIndex); } @@ -1277,8 +1281,9 @@ bool M2Object::prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIn return true; } -void M2Object::createBoundingBoxMesh() { +void M2Object::createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer) { + return; //Create bounding box mesh HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", nullptr); @@ -1456,7 +1461,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { this->m_meshForcedTranspArray.clear(); this->m_materialArray.clear(); - createBoundingBoxMesh(); + createBoundingBoxMesh(sceneRenderer); if (bufferBindings == nullptr) return; @@ -1483,15 +1488,15 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { if (hmesh == nullptr) continue; - this->m_meshArray.emplace_back(hmesh, batchIndex); + this->m_meshArray.emplace_back(hmesh); if (mainBlendMode == EGxBlendEnum::GxBlend_Opaque) { EGxBlendEnum blendMode = EGxBlendEnum::GxBlend_Alpha; HGM2Mesh hmeshTrans = createSingleMesh(sceneRenderer, m_m2Data, batchIndex, 0, bufferBindings, m2Batch, skinSection, blendMode, true); - this->m_meshForcedTranspArray.emplace_back(hmeshTrans, batchIndex); + this->m_meshForcedTranspArray.emplace_back(hmeshTrans); } else { - m_meshForcedTranspArray.emplace_back(nullptr, -1); + m_meshForcedTranspArray.emplace_back(nullptr); } } @@ -1572,13 +1577,13 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, ((m_m2Data->materials[renderFlagIndex]->flags & 0x10) > 0); auto m2Material = sceneRenderer->createM2Material(m_modelWideDataBuff, pipelineTemplate, materialTemplate); - this->m_materialArray.emplace_back(m2Material); + this->m_materialArray.emplace_back(m2Material, batchIndex); meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; meshTemplate.skybox = m_boolSkybox; - auto m2Mesh = sceneRenderer->createM2Mesh(meshTemplate, m2Material, isTransparent, m2Batch->materialLayer, m2Batch->priorityPlane); + auto m2Mesh = sceneRenderer->createM2Mesh(meshTemplate, m2Material, m2Batch->materialLayer, m2Batch->priorityPlane); return m2Mesh; } @@ -1595,10 +1600,10 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector(this->m_meshArray[i]); + HGM2Mesh mesh = this->m_meshArray[i]; if (finalTransparency < 0.999 && i < this->m_meshForcedTranspArray.size() && - std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { - mesh = std::get<0>(this->m_meshForcedTranspArray[i]); + this->m_meshForcedTranspArray[i] != nullptr) { + mesh = this->m_meshForcedTranspArray[i]; } if (mesh->getIsTransparent()) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index d241f9234..5f859e152 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -132,11 +132,11 @@ class M2Object { std::unordered_map loadedTextures; - //Material - std::vector> m_materialArray; - //Tuple of Mesh and BatchIndex - std::vector> m_meshForcedTranspArray; - std::vector> m_meshArray; + //Tuple of Material and BatchIndex + std::vector, int>> m_materialArray; + + std::vector m_meshForcedTranspArray; + std::vector m_meshArray; //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; @@ -165,7 +165,7 @@ class M2Object { void createMeshes(const HMapSceneBufferCreate &sceneRenderer); - void createBoundingBoxMesh(); + void createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer); static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; static float getTextureWeight(M2SkinProfile *skinData, M2Data *m2data, int batchIndex, int textureIndex, const std::vector &transparencies) ; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index b9f0110de..337f50076 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -76,8 +76,8 @@ void M2Scene::setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, m_m2Object->setReplaceTextures(sceneRenderer, replaceTextures); } -void M2Scene::setMeshIdArray(std::vector &meshIds) { - m_m2Object->setMeshIds(meshIds); +void M2Scene::setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) { + m_m2Object->setMeshIds(sceneRenderer, meshIds); } int M2Scene::getCameraNum() { diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index 0c9c22ae5..3152d1c77 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -41,7 +41,7 @@ class M2Scene : public Map { } void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextureArray) ; - void setMeshIdArray(std::vector &meshIds) ; + void setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) ; void setReplaceParticleColors(std::array, 3> &particleColorReplacement) ; void resetReplaceParticleColor() ; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 5273e5a23..827cb7092 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1480,7 +1480,8 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { for (auto &m2Object : renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->matricesForCulling->lookAtMat); + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); } } @@ -2050,57 +2051,6 @@ IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrice return [renderMats, config](auto &data, const HFrameDependantData &fdd) -> void { auto *blockPSVS = &data; - blockPSVS->uLookAtMat = renderMats->lookAtMat; - blockPSVS->uPMatrix = renderMats->perspectiveMat; - blockPSVS->uInteriorSunDir = renderMats->interiorDirectLightDir; - blockPSVS->uViewUp = renderMats->viewUp; - - blockPSVS->extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; - blockPSVS->extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; - blockPSVS->extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; - blockPSVS->extLight.uExteriorDirectColor = fdd->exteriorDirectColor; - blockPSVS->extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); - blockPSVS->extLight.uAdtSpecMult = mathfu::vec4(config->adtSpecMult, 0, 0, 1.0); - -// float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); - float fogEnd = config->farPlane; - if (config->disableFog || !fdd->FogDataFound) { - fogEnd = 100000000.0f; - fdd->FogScaler = 0; - fdd->FogDensity = 0; - } - - float fogStart = std::max(config->farPlane - 250, 0); - fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); - - - blockPSVS->fogData.densityParams = mathfu::vec4( - fogStart, - fogEnd, - fdd->FogDensity / 1000, - 0); - blockPSVS->fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); - blockPSVS->fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); - blockPSVS->fogData.heightDensity_and_endColor = mathfu::vec4( - fdd->FogHeightDensity, - fdd->EndFogColor.x, - fdd->EndFogColor.y, - fdd->EndFogColor.z - ); - blockPSVS->fogData.sunAngle_and_sunColor = mathfu::vec4( - fdd->SunFogAngle, - fdd->SunFogColor.x * fdd->SunFogStrength, - fdd->SunFogColor.y * fdd->SunFogStrength, - fdd->SunFogColor.z * fdd->SunFogStrength - ); - blockPSVS->fogData.heightColor_and_endFogDistance = mathfu::vec4( - fdd->FogHeightColor, - (fdd->EndFogColorDistance > 0) ? - fdd->EndFogColorDistance : - 1000.0f - ); - blockPSVS->fogData.sunPercentage = mathfu::vec4( - (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); }; } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 3c836895f..a4f401899 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1214,10 +1214,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,32}, + {0,5,32}, {0,3,256}, {0,0,368}, - {0,1,14144}, + {0,1,64}, }, { { @@ -1232,15 +1232,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,8,4}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1499,13 +1499,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,1,14144}, + {0,2,14080}, + {0,1,64}, {0,0,368}, - {0,2,160}, + {0,4,160}, }, { { - {2,2,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1777,10 +1778,10 @@ const std::unordered_map class CBufferChunkVLK : public IBufferChunk { public: CBufferChunkVLK(const std::shared_ptr &mainBuffer, int realSize = -1) { - if (realSize <= sizeof(T)) realSize = sizeof(T); - subBuffer = mainBuffer->getSubBuffer(realSize,sizeof(T)); + int realSize1 = realSize; + + if (realSize <= (int)sizeof(T)) + realSize1 = sizeof(T); + + subBuffer = mainBuffer->getSubBuffer(realSize1,sizeof(T)); } T &getObject() override { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 40c5f157b..68ab6272a 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -36,11 +36,12 @@ void GDescriptorSet::update() { // The operations described by pDescriptorWrites are performed first, followed by the operations described by pDescriptorCopies. // // So, writes first, copies second. T_T -void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites) { +void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo) { vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); m_firstUpdate = false; + // m_updateBitSet |= updatedBindsBitSet; // // for (int i = 0; updatedBindsBitSet.size(); i++) { @@ -62,23 +63,21 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptrgetIsLoaded()) { auto blackTexture = std::dynamic_pointer_cast(m_set.m_device->getBlackTexturePixel()); - imageInfo.imageView = blackTexture->texture.view; - imageInfo.sampler = blackTexture->texture.sampler; - } else { - imageInfo.imageView = textureVlk->texture.view; - imageInfo.sampler = textureVlk->texture.sampler; + texture = blackTexture; } + imageInfo.imageView = texture->texture.view; + imageInfo.sampler = texture->texture.sampler; + VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptor.dstSet = m_set.getDescSet(); @@ -91,6 +90,10 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptrgetOffset(); bufferInfo.range = buffer->getSize(); - VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptor.dstSet = m_set.getDescSet(); @@ -202,7 +204,9 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { if (!noSetBitSet.none()) { std::string notSetBits; for (int i = 0; i < noSetBitSet.size(); i++) { - notSetBits += " " + std::to_string(i); + if(noSetBitSet[i]) { + notSetBits += " " + std::to_string(i); + } } std::cerr << "required descriptors " << notSetBits << " were not set during update" << std::endl; @@ -210,8 +214,6 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { } - m_set.writeToDescriptorSets(updates); - - + m_set.writeToDescriptorSets(updates, imageInfos); } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index ff1f7bd9e..3e2735471 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -25,7 +25,7 @@ class GDescriptorSet : public std::enable_shared_from_this { ~GDescriptorSet(); void update(); - void writeToDescriptorSets(std::vector &descriptorWrites); + void writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo); const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 67981ee4e..a238974bc 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -49,7 +49,14 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); if (uboBinding.size > 0) { - m_requiredUBOSize.insert({uboBinding.binding,uboBinding.size}); + if (m_requiredUBOSize.find(uboBinding.binding) == m_requiredUBOSize.end()) { + m_requiredUBOSize.insert({uboBinding.binding, uboBinding.size}); + } else { + if (m_requiredUBOSize.at(uboBinding.binding) != uboBinding.size) { + std::cerr << "Size mismatch for ubo for binding " << uboBinding.binding << std::endl; + throw std::runtime_error("UBO size mismatch"); + } + } } m_totalUbos++; diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index 46ac4ce6b..0550a843c 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -33,3 +33,7 @@ std::shared_ptr ISimpleMaterialVLK::getPipeLineForRenderPass(const return m_pipeline; } + +EGxBlendEnum ISimpleMaterialVLK::getBlendMode() { + return m_pipelineTemplate.blendMode; +} diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index b755eafcb..a00cba5ba 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -32,6 +32,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this return m_pipeline; } std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); + EGxBlendEnum getBlendMode(); private: std::array, MAX_SHADER_DESC_SETS> descriptors; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index 269764c9b..7c76ba1b4 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -23,4 +23,8 @@ void GM2MeshVLK::setSortDistance(float distance) { } float GM2MeshVLK::getSortDistance() { return m_sortDistance; -} \ No newline at end of file +} + +EGxBlendEnum GM2MeshVLK::getGxBlendMode() { + return material()->getBlendMode(); +} diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index 958a96c94..7edb3574c 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -8,8 +8,7 @@ #include "GMeshVLK.h" class GM2MeshVLK : public GMeshVLK, public IM2Mesh { - friend class GDeviceVLK; -protected: +public: GM2MeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material); public: @@ -17,5 +16,6 @@ class GM2MeshVLK : public GMeshVLK, public IM2Mesh { void setPriorityPlane(int priorityPlane) override; void setSortDistance(float distance) override; float getSortDistance() override; + EGxBlendEnum getGxBlendMode() override; }; #endif //AWEBWOWVIEWERCPP_GM2MESH_H diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index e41c0af17..644e6ee77 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -66,7 +66,7 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; - virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, bool isTransparent, int layer, int priorityPlane) = 0; + virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 98932db53..ad632179f 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -19,7 +19,10 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan) { +std::tuple< + std::shared_ptr>, + std::shared_ptr> +> MapSceneRenderer::collectMeshes(const std::shared_ptr &renderPlan) { mapProduceUpdateCounter.beginMeasurement(); //Create meshes @@ -105,4 +108,66 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende m_config->sortMeshTime = sortMeshCounter.getTimePerFrame(); m_config->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); m_config->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); + + return {hopaqueMeshes, htransparentMeshes}; +} + +void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, + const HCameraMatrices &renderingMatrices, + const HFrameDependantData &fdd + ) { + auto &blockPSVS = sceneWideChunk->getObject(); + blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; + blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; + blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; + blockPSVS.uViewUp = renderingMatrices->viewUp; + + blockPSVS.extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; + blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; + blockPSVS.extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; + blockPSVS.extLight.uExteriorDirectColor = fdd->exteriorDirectColor; + blockPSVS.extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); + blockPSVS.extLight.uAdtSpecMult = mathfu::vec4(m_config->adtSpecMult, 0, 0, 1.0); + +// float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); + float fogEnd = m_config->farPlane; + if (m_config->disableFog || !fdd->FogDataFound) { + fogEnd = 100000000.0f; + fdd->FogScaler = 0; + fdd->FogDensity = 0; + } + + float fogStart = std::max(m_config->farPlane - 250, 0); + fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); + + + blockPSVS.fogData.densityParams = mathfu::vec4( + fogStart, + fogEnd, + fdd->FogDensity / 1000, + 0); + blockPSVS.fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); + blockPSVS.fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); + blockPSVS.fogData.heightDensity_and_endColor = mathfu::vec4( + fdd->FogHeightDensity, + fdd->EndFogColor.x, + fdd->EndFogColor.y, + fdd->EndFogColor.z + ); + blockPSVS.fogData.sunAngle_and_sunColor = mathfu::vec4( + fdd->SunFogAngle, + fdd->SunFogColor.x * fdd->SunFogStrength, + fdd->SunFogColor.y * fdd->SunFogStrength, + fdd->SunFogColor.z * fdd->SunFogStrength + ); + blockPSVS.fogData.heightColor_and_endFogDistance = mathfu::vec4( + fdd->FogHeightColor, + (fdd->EndFogColorDistance > 0) ? + fdd->EndFogColorDistance : + 1000.0f + ); + blockPSVS.fogData.sunPercentage = mathfu::vec4( + (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); + + sceneWideChunk->save(); } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 705d2ae41..5aa2cf1f4 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -52,7 +52,13 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; - void collectMeshes(const std::shared_ptr &renderPlan); + std::tuple< + std::shared_ptr>, + std::shared_ptr> + > collectMeshes(const std::shared_ptr &renderPlan); + void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, + const HCameraMatrices &renderingMatrices, + const HFrameDependantData &fdd); private: FrameCounter mapProduceUpdateCounter; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index ad8ec8bda..e65b7d25a 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -11,7 +11,7 @@ struct M2MaterialTemplate { int vertexShader; int pixelShader; - std::array textures = {nullptr, nullptr, nullptr}; + std::array textures = {nullptr, nullptr, nullptr, nullptr}; }; class IM2ModelData { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 58440bbda..be330a735 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -8,6 +8,7 @@ #include "../../../gapi/vulkan/materials/MaterialBuilderVLK.h" #include "../../../gapi/vulkan/meshes/GMeshVLK.h" #include "../../../gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" #include "materials/IMaterialInstance.h" MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : @@ -157,15 +158,21 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & }) .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(6, std::dynamic_pointer_cast(m2MaterialTemplate.texture0)) - .texture(7, std::dynamic_pointer_cast(m2MaterialTemplate.texture1)) - .texture(8, std::dynamic_pointer_cast(m2MaterialTemplate.texture2)); + .texture(6, std::dynamic_pointer_cast(m2MaterialTemplate.textures[0])) + .texture(7, std::dynamic_pointer_cast(m2MaterialTemplate.textures[1])) + .texture(8, std::dynamic_pointer_cast(m2MaterialTemplate.textures[2])) + .texture(9, std::dynamic_pointer_cast(m2MaterialTemplate.textures[3])); }) .toMaterial([&vertexData, &fragmentData](IM2Material *instance) -> void { instance->m_fragmentData = fragmentData; instance->m_vertexData = vertexData; }); + material->blendMode = pipelineTemplate.blendMode; + material->vertexShader = m2MaterialTemplate.vertexShader; + material->pixelShader = m2MaterialTemplate.pixelShader; + + return material; } @@ -187,19 +194,80 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } +inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh) { + const auto &meshVlk = std::dynamic_pointer_cast(mesh); + auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); + + //1. Bind VBOs + cmdBuf.bindVertexBuffers(vulkanBindings->getVertexBuffers()); + + //2. Bind IBOs + cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); + + //3. Bind pipeline + auto material = meshVlk->material(); + cmdBuf.bindPipeline(material->getPipeline()); + + //4. Bind Descriptor sets + auto const &descSets = material->getDescriptorSets(); + for (int i = 0; i < descSets.size(); i++) { + if (descSets[i] != nullptr) { + cmdBuf.bindDescriptorSet(i, descSets[i]); + } + } + + //5. Set view port + cmdBuf.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + + //6. Set scissors + if (meshVlk->scissorEnabled()) { + cmdBuf.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); + } else { + cmdBuf.setDefaultScissors(); + } + + //7. Draw the mesh + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); +} + std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { - auto hthis = std::dynamic_pointer_cast(this->shared_from_this()); + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - mapScene->doPostLoad(hthis, framePlan); + mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); + updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData); + + auto [opaqueMeshes, transparentMeshes] = collectMeshes(framePlan); + return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + // --------------------- + // Upload stuff + // --------------------- + uploadCmd.submitBufferUploads(l_this->uboBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); - return createRenderFuncVLK([](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + uploadCmd.submitBufferUploads(l_this->iboBuffer); + // ---------------------- + // Draw meshes + // ---------------------- + + for (auto const &mesh : *opaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(swapChainCmd, mesh); + } + + for (auto const &mesh : *transparentMeshes) { + MapSceneRenderForwardVLK::drawMesh(swapChainCmd, mesh); + } }); } @@ -218,6 +286,16 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon } HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(*m_device, meshTemplate, std::dynamic_pointer_cast(material)); + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); +} + +HGM2Mesh +MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + int layer, int priorityPlane) { + + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); + mesh->setLayer(layer); + mesh->setPriorityPlane(priorityPlane); + return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index ddbc9b62b..1d040b376 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -16,6 +16,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { ~MapSceneRenderForwardVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh); std::shared_ptr getLastCreatedPlan() override; @@ -49,6 +50,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; + HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; private: HGDeviceVLK m_device; From b1a5dd450757d04641be2f27c3810ba31e241bf4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 17 Mar 2023 10:05:56 +0200 Subject: [PATCH 048/212] something is still wrong with updates for UBO --- .../src/gapi/vulkan/GDeviceVulkan.cpp | 4 +-- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 6 ++++- .../src/gapi/vulkan/buffers/GBufferVLK.h | 3 ++- .../vulkan/descriptorSets/GDescriptorSet.cpp | 26 +++++++++++++++++++ .../vulkan/descriptorSets/GDescriptorSet.h | 9 ++++++- .../renderer/mapScene/MapSceneRenderer.cpp | 4 +-- .../vulkan/MapSceneRenderForwardVLK.cpp | 5 ++-- 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 78cb3b2ba..ceb613fb5 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -171,7 +171,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ - enableValidationLayers = false; + enableValidationLayers = true; m_textureManager->initialize(); @@ -978,7 +978,7 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName } HGBufferVLK GDeviceVLK::createUniformBuffer(size_t initialSize) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize); + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); return h_uniformBuffer; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 3fb27c9c3..80f78cb35 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -4,9 +4,10 @@ #include "GBufferVLK.h" -GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize) : m_device(device) { +GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment) : m_device(device) { m_usageFlags = usageFlags; m_bufferSize = maxSize; + m_alignment = alignment; createBuffer(currentBuffer); } @@ -73,6 +74,9 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, if (minAddressStrategy) { allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT; } + if (m_alignment > 0) { + allocCreateInfo.alignment = m_alignment; + } auto result = vmaVirtualAllocate(buffer.virtualBlock, &allocCreateInfo, &alloc, &offset); if (minAddressStrategy) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 20dceeac7..e4412f46d 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -21,7 +21,7 @@ typedef std::shared_ptr HGBufferVLK; class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; public: - GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize); + GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment = -1); ~GBufferVLK() override; //Doesn't make actual upload, only queues it. @@ -56,6 +56,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { class SetUpdateHelper { public: explicit SetUpdateHelper(GDescriptorSet &set, std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors) : - m_set(set), m_boundDescriptors(boundDescriptors) {} + m_set(set), m_boundDescriptors(boundDescriptors) { + //So that the resize of these vectors would not lead to pointer invalidation in updates vector + bufferInfos.reserve(32); + imageInfos.reserve(32); + } ~SetUpdateHelper(); + // SetUpdateHelper is non-copyable + SetUpdateHelper(const SetUpdateHelper&) = delete; + SetUpdateHelper& operator=(const SetUpdateHelper&) = delete; SetUpdateHelper& ubo(int bindIndex, const std::shared_ptr &buffer); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index ad632179f..23202da1a 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -29,8 +29,8 @@ std::tuple< auto hopaqueMeshes = std::make_shared>(); auto htransparentMeshes = std::make_shared>(); - auto opaqueMeshes = *hopaqueMeshes; - auto transparentMeshes = *htransparentMeshes; + auto &opaqueMeshes = *hopaqueMeshes; + auto &transparentMeshes = *htransparentMeshes; opaqueMeshes.reserve(30000); transparentMeshes.reserve(30000); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index be330a735..ca388cf4f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -29,7 +29,8 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C auto const dataFormat = { ITextureFormat::itRGBA }; m_renderPass = hDevice->getRenderPass(dataFormat, ITextureFormat::itDepth32, - sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), + VK_SAMPLE_COUNT_1_BIT, +// sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), true, false); for (auto & colorFrameBuffer : m_colorFrameBuffers) { @@ -37,7 +38,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C *hDevice, dataFormat, ITextureFormat::itDepth32, - hDevice->getMaxSamplesCnt(), + 1, 640, 480 ); } From 242160cb1e94ed4929e63c769951b1e9f4d45aa1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 17 Mar 2023 23:37:47 +0200 Subject: [PATCH 049/212] wip ffxglow --- CMakeLists.txt | 2 +- .../glsl/forwardRendering/drawQuad.vert | 2 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 4 +- .../src/engine/objects/m2/m2Object.cpp | 10 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 8 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 18 +++- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 12 +-- .../src/renderer/frame/FrameInputParams.h | 4 +- .../renderer/mapScene/MapSceneRenderer.cpp | 14 ++- .../src/renderer/mapScene/MapSceneRenderer.h | 25 ++--- .../vulkan/MapSceneRenderForwardVLK.cpp | 84 ++++++++++++----- .../vulkan/MapSceneRenderForwardVLK.h | 9 ++ .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 92 +++++++++++++++++++ .../mapScene/vulkan/passes/FFXGlowPassVLK.h | 28 ++++++ 14 files changed, 255 insertions(+), 57 deletions(-) create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a6abd6af9..dbe8a9f2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ set(SOURCE_FILES src/ui/renderer/uiScene/ImGUIPlan.h src/ui/renderer/uiScene/IFrontendUIBufferCreate.h src/ui/renderer/uiScene/materials/UIMaterial.h - ) + src/ui/renderer/uiScene/vulkan/FFXGlowPassVLK.cpp src/ui/renderer/uiScene/vulkan/FFXGlowPassVLK.h) set(SOURCE_FILES_VULKAN diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert index e5aa19760..8f238526f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert @@ -5,7 +5,7 @@ precision highp int; layout (location = 0) in vec2 position; -layout(std140, binding=2) uniform meshWideBlockVS { +layout(std140, set=0, binding=2) uniform meshWideBlockVS { vec4 uWidth_uHeight_uX_uY; }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 3ee67a89d..89410c1e3 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -22,8 +22,6 @@ float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int b } void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr &m2Material, int batchIndex, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile){ - std::shared_ptr> meshWideBlockVS = nullptr; - auto batch = m2SkinProfile->batches[batchIndex]; int renderFlagIndex = batch->materialIndex; auto renderFlag = m2Data->materials[renderFlagIndex]; @@ -39,6 +37,7 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr meshblockVS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; fillTextureMatrices(*m2Object, batchIndex, m2Data, m2SkinProfile, meshblockVS.uTextMat); + m2Material->m_vertexData->save(); //3. Update individual PS buffer @@ -61,6 +60,7 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr meshBlockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; meshBlockPS.BlendMode = static_cast(m2Material->blendMode); meshBlockPS.uTexSampleAlpha = uTexSampleAlpha; + m2Material->m_fragmentData->save(); } void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index bf1e64777..1678eafff 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1058,19 +1058,19 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa //Update materials { - auto placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); + auto &placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); placementMatrix.uPlacementMat = m_placementMatrix; m_modelWideDataBuff->m_placementMatrix->save(); } { - auto bonesData = m_modelWideDataBuff->m_bonesData->getObject(); + auto &bonesData = m_modelWideDataBuff->m_bonesData->getObject(); int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, bonesData.uBoneMatrixes); m_modelWideDataBuff->m_bonesData->save(); } { - auto modelFragmentData = m_modelWideDataBuff->m_modelFragmentData->getObject(); + auto &modelFragmentData = m_modelWideDataBuff->m_modelFragmentData->getObject(); static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); mathfu::vec4 localDiffuse = diffuseNon; @@ -1562,8 +1562,8 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); - pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); - pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); + pipelineTemplate.depthCulling = false; !(renderFlag->flags & 0x8); + pipelineTemplate.backFaceCulling = false; !(renderFlag->flags & 0x4); pipelineTemplate.triCCW = true; if (overrideBlend) { pipelineTemplate.blendMode = blendMode; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index ceb613fb5..fa6a9e2c7 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1182,8 +1182,12 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings } } - std::shared_ptr hgPipeline = std::make_shared(*this, m_bindings, renderPass, - shader, element, backFaceCulling, triCCW, blendMode, + std::shared_ptr hgPipeline = std::make_shared(*this, + m_bindings, renderPass, + shader, element, + backFaceCulling, + triCCW, + blendMode, depthCulling, depthWrite); std::weak_ptr weakPtr(hgPipeline); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 80f78cb35..2cfedf533 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -67,7 +67,7 @@ void GBufferVLK::destroyBuffer(BufferInternal &buffer) { } VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { - bool minAddressStrategy = fakeSize != -1 && fakeSize > sizeInBytes; + bool minAddressStrategy = sizeInBytes < fakeSize && fakeSize > 0; VmaVirtualAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.size = sizeInBytes; //Size in bytes @@ -137,11 +137,21 @@ void GBufferVLK::resize(int newLength) { subBuffer->m_offset = offset; subBuffer->m_alloc = alloc; + subBuffer->m_dataPointer = (uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData+offset; } } destroyBuffer(currentBuffer); currentBuffer = newBuffer; + + for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ + auto subBuffer = it->lock(); + if (subBuffer != nullptr) { + subBuffer->executeOnChange(); + } + } + + executeOnChange(); } //fakeSize is used to make sure the subBuffer has enough bytes left till end of main buffer. @@ -165,8 +175,8 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy } else { - resize(m_bufferSize*2); - return getSubBuffer(sizeInBytes); + resize(std::max(m_bufferSize*2, m_bufferSize + fakeSize)); + return getSubBuffer(sizeInBytes, fakeSize); } } @@ -242,5 +252,5 @@ void GBufferVLK::GSubBufferVLK::save(int length) { } size_t GBufferVLK::GSubBufferVLK::getSize() { - return m_size; + return m_fakeSize; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index acab72df5..2ca1f1288 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -13,27 +13,27 @@ template class CBufferChunkVLK : public IBufferChunk { public: CBufferChunkVLK(const std::shared_ptr &mainBuffer, int realSize = -1) { - int realSize1 = realSize; + m_realSize = realSize; - if (realSize <= (int)sizeof(T)) - realSize1 = sizeof(T); + if (m_realSize <= 0) + m_realSize = sizeof(T); - subBuffer = mainBuffer->getSubBuffer(realSize1,sizeof(T)); + subBuffer = mainBuffer->getSubBuffer(m_realSize,sizeof(T)); } T &getObject() override { return *(T*)subBuffer->getPointer(); }; void save() override { - subBuffer->save(sizeof(T)); + subBuffer->save(m_realSize); }; const std::shared_ptr getSubBuffer() { return subBuffer; } private: + int m_realSize = 0; std::shared_ptr subBuffer = nullptr; - }; diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 29cd0472b..1d1d17886 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -9,8 +9,8 @@ #include "../../include/iostuff.h" struct ViewPortDimensions{ - std::array mins; - std::array maxs; + std::array mins; + std::array maxs; }; template diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 23202da1a..84653b201 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -114,11 +114,21 @@ std::tuple< void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, - const HFrameDependantData &fdd + const HFrameDependantData &fdd, + bool isVulkan ) { + + static const mathfu::mat4 vulkanMatrixFix = mathfu::mat4(1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1.0/2.0, 1/2.0, + 0, 0, 0, 1).Transpose(); + + auto &blockPSVS = sceneWideChunk->getObject(); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; - blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; + if (isVulkan) { + blockPSVS.uPMatrix = vulkanMatrixFix*renderingMatrices->perspectiveMat; + } blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; blockPSVS.uViewUp = renderingMatrices->viewUp; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 5aa2cf1f4..fd8fa9e02 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -15,7 +15,7 @@ #include "../../engine/shader/ShaderDefinitions.h" #include "../../engine/algorithms/FrameCounter.h" -static const std::array staticWMOBindings = {{ +static const std::vector staticWMOBindings = {{ {+wmoShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, pos) }, {+wmoShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, normal)}, {+wmoShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(WMOVertex), offsetof(WMOVertex, textCoordinate)}, @@ -27,21 +27,23 @@ static const std::array staticWMOBindings = {{ {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; -static const std::array staticWaterBindings = {{ +static const std::vector staticWaterBindings = {{ {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, {+waterShader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, uv)} }}; -static const std::array staticM2Bindings = {{ - {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 48, 0 }, - {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, 48, 12}, // bonesWeight - {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, 48, 16}, // bones - {+m2Shader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, 48, 20}, // normal - {+m2Shader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, 48, 32}, // texcoord - {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, 48, 40} // texcoord +static const std::vector staticM2Bindings = {{ + {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(M2Vertex), 0 }, + {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(M2Vertex), 12}, // bonesWeight + {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, sizeof(M2Vertex), 16}, // bones + {+m2Shader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(M2Vertex), 20}, // normal + {+m2Shader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(M2Vertex), 32}, // texcoord + {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, sizeof(M2Vertex), 40} // texcoord }}; -static const std::array skyConusBinding = {{ +static_assert(sizeof(M2Vertex) == 48); + +static const std::vector skyConusBinding = {{ {+drawQuad::Attribute::position, 4, GBindingType::GFLOAT, false, 0, 0}, }}; @@ -58,7 +60,8 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public > collectMeshes(const std::shared_ptr &renderPlan); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, - const HFrameDependantData &fdd); + const HFrameDependantData &fdd, + bool isVulkan); private: FrameCounter mapProduceUpdateCounter; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index ca388cf4f..1aae31d3a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -24,26 +24,22 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_emptyM2VAO = createM2VAO(nullptr, nullptr); + m_emptySkyVAO = createSkyVAO(nullptr, nullptr); //Framebuffers for rendering - auto const dataFormat = { ITextureFormat::itRGBA }; + auto const dataFormat = { ITextureFormat::itRGBA}; m_renderPass = hDevice->getRenderPass(dataFormat, ITextureFormat::itDepth32, VK_SAMPLE_COUNT_1_BIT, // sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), true, false); - for (auto & colorFrameBuffer : m_colorFrameBuffers) { - colorFrameBuffer = std::make_shared( - *hDevice, - dataFormat, - ITextureFormat::itDepth32, - 1, - 640, 480 - ); - } + + createFrameBuffers(); sceneWideChunk = std::make_shared>(uboBuffer); + + assignFFXGlowUBOConsts(); } // ------------------ @@ -61,7 +57,7 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer ver HGVertexBufferBindings MapSceneRenderForwardVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto m2VAO = m_device->createVertexBufferBindings(); - m2VAO->addVertexBufferBinding(vertexBuffer, std::vector(staticM2Bindings.begin(), staticM2Bindings.end())); + m2VAO->addVertexBufferBinding(vertexBuffer, staticM2Bindings); m2VAO->setIndexBuffer(indexBuffer); return m2VAO; @@ -182,7 +178,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria auto skyColors = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo(0, BufferChunkHelper::cast(l_sceneWideChunk)->getSubBuffer()) @@ -195,6 +191,8 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } + + inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); @@ -237,14 +235,24 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); + if (frameInputParams->viewPortDimensions.maxs[0] != m_width || + frameInputParams->viewPortDimensions.maxs[1] != m_height) { + m_width = frameInputParams->viewPortDimensions.maxs[0]; + m_height = frameInputParams->viewPortDimensions.maxs[1]; + + createFrameBuffers(); + createFFXGlowMats(); + } + mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); + mapScene->updateBuffers(framePlan); - - updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData); + updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); + assignFFXGlowUBOConsts(); auto [opaqueMeshes, transparentMeshes] = collectMeshes(framePlan); - return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { // --------------------- // Upload stuff // --------------------- @@ -261,14 +269,26 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // ---------------------- // Draw meshes // ---------------------- - - for (auto const &mesh : *opaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(swapChainCmd, mesh); + { + auto passHelper = frameBufCmd.beginRenderPass(false, + l_this->m_renderPass, + l_this->m_colorFrameBuffers[l_this->m_device->getDrawFrameNumber()], + {0,0},//frameInputParams->viewPortDimensions.mins, + {640, 480},//frameInputParams->viewPortDimensions.maxs, + {0, 0, 0},//todo + true + ); + + for (auto const &mesh: *opaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh); + } + + for (auto const &mesh: *transparentMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh); + } } - for (auto const &mesh : *transparentMeshes) { - MapSceneRenderForwardVLK::drawMesh(swapChainCmd, mesh); - } + }); } @@ -300,3 +320,25 @@ MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::s return mesh; } + +void MapSceneRenderForwardVLK::createFrameBuffers() { + { + auto const dataFormat = {ITextureFormat::itRGBA}; + + for (auto &colorFrameBuffer: m_colorFrameBuffers) { + colorFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itDepth32, + 1, + m_width, m_height + ); + } + } + +} + +void MapSceneRenderForwardVLK::createFFXGlowMats() { + for () +} + diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 1d040b376..3eaa94915 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -54,6 +54,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; + int m_width = 640; + int m_height = 480; HGBufferVLK vboM2Buffer; HGBufferVLK vboAdtBuffer; @@ -66,11 +68,18 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr> sceneWideChunk; + std::shared_ptr m_renderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + HGVertexBufferBindings m_emptyM2VAO = nullptr; + HGVertexBufferBindings m_emptySkyVAO = nullptr; + + void assignFFXGlowUBOConsts(); + void createFrameBuffers(); + void createFFXGlowMats(); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp new file mode 100644 index 000000000..0a761acfe --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -0,0 +1,92 @@ +// +// Created by Deamon on 3/17/2023. +// + +#include "FFXGlowPassVLK.h" +#include "../../../../gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" + +FFXGlowPassVLK::FFXGlowPassVLK(HGBufferVLK uboBuffer) { + m_ffxGlowVs = std::make_shared>(uboBuffer); + for (auto &ffxGlowPs : m_ffxGlowPSs) { + ffxGlowPs = std::make_shared>(uboBuffer); + } +} + +void FFXGlowPassVLK::assignFFXGlowUBOConsts() { + auto &ffxGlowVs = m_ffxGlowVs->getObject(); + ffxGlowVs = {1,1,0,0}; + m_ffxGlowVs->save(); + + static const std::array, 6> texOffsets = {{ + //X & Y + {{-1, 0, 0, -1}}, + {{2, 2, -1, -1}}, + + //X & Y + {{-6, -1, 1, 6}}, + {{0, 0, 0, 0}}, + + //X & Y + {{0, 0, 0, 0}}, + {{10, 2, -2, -10}}, + }}; + + for (int i = 0; i < 3; i++) { + auto ffxGlowPs1 = m_ffxGlowPSs[i]->getObject(); + std::copy(std::begin(texOffsets[i*2]), std::end(texOffsets[i*2]), std::begin(ffxGlowPs1.texOffsetX)); + std::copy(std::begin(texOffsets[i*2+1]), std::end(texOffsets[i*2+1]), std::begin(ffxGlowPs1.texOffsetY)); + m_ffxGlowPSs[i]->save(); + } +} + +void FFXGlowPassVLK::createFrameBuffers(const HGDeviceVLK &device, int m_width, int m_height) { + { + auto const dataFormat = {ITextureFormat::itRGBA}; + int targetWidth = m_width >> 2; + int targetHeight = m_height >> 2; + + for (auto &colorFrameBuffer: m_GlowFrameB1) { + colorFrameBuffer = std::make_shared( + *device, + dataFormat, + ITextureFormat::itDepth32, + 1, + targetWidth, targetHeight + ); + } + for (auto &colorFrameBuffer: m_GlowFrameB2) { + colorFrameBuffer = std::make_shared( + *device, + dataFormat, + ITextureFormat::itDepth32, + 1, + targetWidth, targetHeight + ); + } + } +} + +std::shared_ptr +FFXGlowPassVLK::createFFxGlowMat( + const std::shared_ptr> &ffxGlowVs, + const std::shared_ptr> &ffxGlowPS, + const PipelineTemplate &pipelineTemplate, + const ) { + + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}) + .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(2, BufferChunkHelper::cast(ffxGlowVs)->getSubBuffer()) + .ubo(4, BufferChunkHelper::cast(ffxGlowPS)->getSubBuffer()); + }) + .createDescriptorSet(1, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(2, BufferChunkHelper::cast(ffxGlowVs)->getSubBuffer()) + .ubo(4, BufferChunkHelper::cast(ffxGlowPS)->getSubBuffer()); + }) + .toMaterial(); + + return material; +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h new file mode 100644 index 000000000..50d8d507d --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h @@ -0,0 +1,28 @@ +// +// Created by Deamon on 3/17/2023. +// + +#ifndef AWEBWOWVIEWERCPP_FFXGLOWPASSVLK_H +#define AWEBWOWVIEWERCPP_FFXGLOWPASSVLK_H + +#include + +#include "../../MapSceneRenderer.h" +#include "../../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../materials/IMaterialStructs.h" + +class FFXGlowPassVLK { +public: + FFXGlowPassVLK(HGBufferVLK uboBuffer); + void assignFFXGlowUBOConsts(); + void createFrameBuffers(const HGDeviceVLK &device, int m_width, int m_height); +private: + std::shared_ptr> m_ffxGlowVs; + std::array>,3> m_ffxGlowPSs; + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_GlowFrameB1; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_GlowFrameB2; +}; + + +#endif //AWEBWOWVIEWERCPP_FFXGLOWPASSVLK_H From 8eb2637232614de216e0370617663106dc8f0451 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 18 Mar 2023 22:46:42 +0200 Subject: [PATCH 050/212] m2 rendering and FFXGlow --- CMakeLists.txt | 2 +- wowViewerLib/CMakeLists.txt | 9 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 2 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 3 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 11 ++ .../CommandBufferRecorder.cpp | 6 +- .../CommandBufferRecorder.h | 4 +- .../TextureUploadHelper.cpp | 13 -- .../TextureUploadHelper.h | 16 ++ .../src/renderer/mapScene/MapSceneRenderer.h | 7 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 95 +++++---- .../vulkan/MapSceneRenderForwardVLK.h | 11 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 186 ++++++++++++++++-- .../mapScene/vulkan/passes/FFXGlowPassVLK.h | 44 ++++- 16 files changed, 322 insertions(+), 93 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbe8a9f2f..c2405b206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ set(SOURCE_FILES src/ui/renderer/uiScene/ImGUIPlan.h src/ui/renderer/uiScene/IFrontendUIBufferCreate.h src/ui/renderer/uiScene/materials/UIMaterial.h - src/ui/renderer/uiScene/vulkan/FFXGlowPassVLK.cpp src/ui/renderer/uiScene/vulkan/FFXGlowPassVLK.h) + ) set(SOURCE_FILES_VULKAN diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index c46b941bc..d77c0b39e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -319,7 +319,8 @@ set(SOURCE_FILES src/renderer/frame/SceneScenario.h src/renderer/mapScene/MapSceneRenderer.cpp src/renderer/mapScene/MapSceneRenderer.h - src/renderer/mapScene/MapSceneRendererFactory.cpp src/renderer/mapScene/MapSceneRendererFactory.h + src/renderer/mapScene/MapSceneRendererFactory.cpp + src/renderer/mapScene/MapSceneRendererFactory.h src/renderer/IRenderer.h src/renderer/IRenderParameters.h src/renderer/frame/FrameInputParams.h @@ -486,6 +487,8 @@ if (LINK_VULKAN) src/gapi/vulkan/GRenderPassVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h + src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h + src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.h src/gapi/vulkan/buffers/IBufferVLK.h @@ -607,8 +610,8 @@ if (MSVC) if (_cpp_17_flag_supported) message("/std:c++17 is supported") #target_compile_options(AWebWoWViewerCpp "/std:c++17") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /std:c++latest") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /std:c++latest") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /std:c++17") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /std:c++17") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /std:c++17") target_compile_options(WoWViewerLib PRIVATE "/std:c++latest") endif() diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 89410c1e3..14cbdd024 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -50,7 +50,7 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr //Fill values into buffer mathfu::vec4 uTexSampleAlpha = mathfu::vec4(1.0, 1.0, 1.0, 1.0); - for (int i = 0; i < std::max(batch->textureCount, 4); i++) { + for (int i = 0; i < std::min(batch->textureCount, 4); i++) { uTexSampleAlpha[i] = M2Object::getTextureWeight(m2SkinProfile, m2Data, batchIndex, i, m2Object->transparencies); } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 1678eafff..61302f617 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1562,8 +1562,8 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); - pipelineTemplate.depthCulling = false; !(renderFlag->flags & 0x8); - pipelineTemplate.backFaceCulling = false; !(renderFlag->flags & 0x4); + pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); + pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); pipelineTemplate.triCCW = true; if (overrideBlend) { pipelineTemplate.blendMode = blendMode; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 827cb7092..5321ca6cf 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -23,9 +23,6 @@ #include "../../algorithms/mathHelper_culling.h" #include "../../../gapi/interface/materials/IMaterial.h" -std::array fullScreen = {{ - {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, -}}; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index fa6a9e2c7..d3befd979 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -171,7 +171,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ - enableValidationLayers = true; + enableValidationLayers = false; m_textureManager->initialize(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index 2ca1f1288..9cbcfa95a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -36,5 +36,16 @@ class CBufferChunkVLK : public IBufferChunk { std::shared_ptr subBuffer = nullptr; }; +namespace BufferChunkHelperVLK { + template + static const inline std::shared_ptr> cast(const std::shared_ptr> &chunk) { + return std::dynamic_pointer_cast>(chunk); + } + + template + static const inline void create(const HGBufferVLK &parentBuffer, std::shared_ptr> &chunk, int realSize = -1) { + chunk = std::make_shared>(parentBuffer, realSize); + } +}; #endif //AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 4447bec4c..d7632b43f 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -64,7 +64,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( throw std::runtime_error("tried to start render pass with another pass being active already"); } - createViewPortTypes(areaOffset, areaSize); + createViewPortTypes(areaOffset, areaSize, renderPassVlk->getInvertZ()); createDefaultScissors(areaOffset, areaSize); m_currentRenderPass = renderPassVlk; @@ -221,13 +221,13 @@ void CmdBufRecorder::setDefaultScissors() { } void CmdBufRecorder::createViewPortTypes(const std::array &areaOffset, - const std::array &areaSize) { + const std::array &areaSize, + bool invertZ) { VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; usualViewport.width = areaSize[0]; usualViewport.height = areaSize[1]; usualViewport.x = areaOffset[0]; usualViewport.y = areaOffset[1]; - bool invertZ = false; if (invertZ) { usualViewport.minDepth = 0; usualViewport.maxDepth = 0.990f; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index c84125f8e..cc432ee78 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -55,7 +55,6 @@ class CmdBufRecorder { friend class RenderPassHelper; - void setViewPort(); void setViewPort(ViewportType viewportType); private: const GCommandBuffer &m_gCmdBuffer; @@ -74,7 +73,8 @@ class CmdBufRecorder { VkRect2D defaultScissor; void createViewPortTypes(const std::array &areaOffset, - const std::array &areaSize); + const std::array &areaSize, + bool invertZ); void createDefaultScissors(const std::array &areaOffset, const std::array &areaSize); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index b0c51563e..ec717921e 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -4,19 +4,6 @@ #include "TextureUploadHelper.h" - -struct TransitionParams { - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; -}; - - void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, const std::vector> &textures, const TransitionParams &transitionParams) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h index dec9bacaa..3fd22755f 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -9,6 +9,22 @@ #include "../../textures/GTextureVLK.h" #include "CommandBufferRecorder.h" +struct TransitionParams { + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; +}; + + +void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, + const std::vector> &textures, + const TransitionParams &transitionParams); + void textureUploadStrategy(const std::vector> &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index fd8fa9e02..0e6cdeca2 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -44,9 +44,14 @@ static const std::vector staticM2Bindings = {{ static_assert(sizeof(M2Vertex) == 48); static const std::vector skyConusBinding = {{ - {+drawQuad::Attribute::position, 4, GBindingType::GFLOAT, false, 0, 0}, + {+skyConus::Attribute::aPosition, 4, GBindingType::GFLOAT, false, 0, 0}, }}; +static const std::vector fullScreenQuad = {{ + {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, +}}; + + class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer(Config *config) : m_config(config) {}; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 1aae31d3a..98af582d2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -21,6 +21,29 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C vboWaterBuffer = m_device->createVertexBuffer(1024*1024); vboSkyBuffer = m_device->createVertexBuffer(1024*1024); + { + const float epsilon = 0.f; + std::array vertexBuffer = { + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, 1.0f - epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, 1.f - epsilon)) + }; + std::vector indexBuffer = { + 0, 1, 2, + 2, 1, 3 + }; + m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + m_drawQuadVao = m_device->createVertexBufferBindings(); + m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); + m_drawQuadVao->setIndexBuffer(m_iboQuad); + m_drawQuadVao->save(); + } + uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_emptyM2VAO = createM2VAO(nullptr, nullptr); @@ -34,12 +57,11 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C // sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), true, false); + glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); createFrameBuffers(); sceneWideChunk = std::make_shared>(uboBuffer); - - assignFFXGlowUBOConsts(); } // ------------------ @@ -119,20 +141,6 @@ HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -struct BufferChunkHelper { -public: - template - static const inline std::shared_ptr> cast(const std::shared_ptr> &chunk) { - return std::dynamic_pointer_cast>(chunk); - } - - template - static const inline void create(const HGBufferVLK &parentBuffer, std::shared_ptr> &chunk, int realSize = -1) { - chunk = std::make_shared>(parentBuffer, realSize); - } -}; - - std::shared_ptr MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, @@ -146,10 +154,10 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelper::cast(l_sceneWideChunk)->getSubBuffer()) - .ubo(1, BufferChunkHelper::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) - .ubo(2, BufferChunkHelper::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(3, BufferChunkHelper::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) .ubo(4, vertexData->getSubBuffer()) .ubo(5, fragmentData->getSubBuffer()); }) @@ -181,7 +189,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelper::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) .ubo(1, skyColors->getSubBuffer()); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { @@ -229,6 +237,10 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } +static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { + return {vec[0], vec[1], vec[2]}; +} + std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { @@ -241,15 +253,27 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha m_height = frameInputParams->viewPortDimensions.maxs[1]; createFrameBuffers(); - createFFXGlowMats(); + + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(std::dynamic_pointer_cast(m_colorFrameBuffers[i]->getAttachment(0))); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + m_device->getSwapChainRenderPass()); + } + } mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); mapScene->updateBuffers(framePlan); + glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); - assignFFXGlowUBOConsts(); + auto [opaqueMeshes, transparentMeshes] = collectMeshes(framePlan); return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { @@ -265,6 +289,8 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); // ---------------------- // Draw meshes @@ -273,9 +299,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, l_this->m_colorFrameBuffers[l_this->m_device->getDrawFrameNumber()], - {0,0},//frameInputParams->viewPortDimensions.mins, - {640, 480},//frameInputParams->viewPortDimensions.maxs, - {0, 0, 0},//todo + frameInputParams->viewPortDimensions.mins, + frameInputParams->viewPortDimensions.maxs, + vec4ToArr3(frameInputParams->frameParameters->clearColor), true ); @@ -288,7 +314,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } } - + l_this->glowPass->doPass(frameBufCmd, swapChainCmd, + l_this->m_device->getSwapChainRenderPass(), + frameInputParams->viewPortDimensions); }); } @@ -299,9 +327,9 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount) { auto result = std::make_shared(); - BufferChunkHelper::create(uboBuffer, result->m_placementMatrix); - BufferChunkHelper::create(uboBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); - BufferChunkHelper::create(uboBuffer, result->m_modelFragmentData); + BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); + BufferChunkHelperVLK::create(uboBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); return result; } @@ -336,9 +364,4 @@ void MapSceneRenderForwardVLK::createFrameBuffers() { } } -} - -void MapSceneRenderForwardVLK::createFFXGlowMats() { - for () -} - +} \ No newline at end of file diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 3eaa94915..dd67bc386 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -9,6 +9,7 @@ #include "../MapSceneRenderer.h" #include "../../../gapi/vulkan/GDeviceVulkan.h" #include "../materials/IMaterialStructs.h" +#include "passes/FFXGlowPassVLK.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { public: @@ -57,6 +58,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { int m_width = 640; int m_height = 480; + std::unique_ptr glowPass; + HGBufferVLK vboM2Buffer; HGBufferVLK vboAdtBuffer; HGBufferVLK vboWMOBuffer; @@ -66,6 +69,11 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; + HGBufferVLK m_vboQuad; + HGBufferVLK m_iboQuad; + + HGVertexBufferBindings m_drawQuadVao = nullptr; + std::shared_ptr> sceneWideChunk; @@ -76,10 +84,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; - void assignFFXGlowUBOConsts(); void createFrameBuffers(); - - void createFFXGlowMats(); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 0a761acfe..e052cfc49 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -5,15 +5,125 @@ #include "FFXGlowPassVLK.h" #include "../../../../gapi/vulkan/buffers/IBufferChunkVLK.h" #include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" +#include "../../../../gapi/vulkan/GVertexBufferBindingsVLK.h" -FFXGlowPassVLK::FFXGlowPassVLK(HGBufferVLK uboBuffer) { +FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device), m_drawQuadVao(quadVAO) { m_ffxGlowVs = std::make_shared>(uboBuffer); - for (auto &ffxGlowPs : m_ffxGlowPSs) { - ffxGlowPs = std::make_shared>(uboBuffer); + for (auto &ffxGaussPs : m_ffxGaussPSs) { + ffxGaussPs = std::make_shared>(uboBuffer); } + m_ffxGlowPS = std::make_shared>(uboBuffer); + + { + auto const dataFormat = {ITextureFormat::itRGBA}; + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, + VK_SAMPLE_COUNT_1_BIT, +// sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), + true, false); + } + + + +} + +void FFXGlowPassVLK::updateDimensions(int width, int height, + const std::vector> &inputColorTextures, + const std::shared_ptr &finalRenderPass) { + + createFrameBuffers(width, height); + assert(inputColorTextures.size() == IDevice::MAX_FRAMES_IN_FLIGHT); + + PipelineTemplate glowPipelineTemplate; + glowPipelineTemplate.element = DrawElementMode::TRIANGLES; + glowPipelineTemplate.depthWrite = false; + glowPipelineTemplate.depthCulling = false; + glowPipelineTemplate.backFaceCulling = false; + glowPipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + std::array, 4> inputTextures; + //Fill input textures array + inputTextures[0] = inputColorTextures[i]; + for (int j = 0; j < GAUSS_PASS_COUNT; j++) + inputTextures[j + 1] = std::dynamic_pointer_cast(getTargetFrameBuffer(j, i)->getAttachment(0)); + + + // Create materials + for (int j = 0; j < GAUSS_PASS_COUNT; j++) { + ffxGaussMat[i][j] = createFFXGaussMat( + m_ffxGlowVs, + m_ffxGaussPSs[j], + inputTextures[j], + glowPipelineTemplate, + m_renderPass + ); + } + + ffxGlowMat[i] = createFFXGlowMat(m_ffxGlowVs, + m_ffxGlowPS, + inputColorTextures[i], + std::dynamic_pointer_cast(getTargetFrameBuffer(GAUSS_PASS_COUNT-1, i)->getAttachment(0)), + glowPipelineTemplate, + finalRenderPass + ); + } +} + + +void FFXGlowPassVLK::drawMaterial (CmdBufRecorder& cmdBuf, const std::shared_ptr &mat) { + //1. Bind VBOs + auto vulkanBindings = std::dynamic_pointer_cast(m_drawQuadVao); + cmdBuf.bindVertexBuffers(vulkanBindings->getVertexBuffers()); + + //2. Bind IBOs + cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); + + //3. Bind pipeline + auto material = std::dynamic_pointer_cast(mat); + cmdBuf.bindPipeline(material->getPipeline()); + + //4. Bind Descriptor sets + auto const &descSets = material->getDescriptorSets(); + for (int i = 0; i < descSets.size(); i++) { + if (descSets[i] != nullptr) { + cmdBuf.bindDescriptorSet(i, descSets[i]); + } + } + + //7. Draw the mesh + cmdBuf.drawIndexed(6, 1, 0, 0); } -void FFXGlowPassVLK::assignFFXGlowUBOConsts() { +void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, + const std::shared_ptr &finalRenderPass, + ViewPortDimensions &viewPortDimensions) { + auto currentFrame = m_device->getDrawFrameNumber(); + { + + for (int i = 0; i < GAUSS_PASS_COUNT; i++) { + auto passHelper = frameBufCmd.beginRenderPass( + false, + m_renderPass, + getTargetFrameBuffer(i, currentFrame), + viewPortDimensions.mins, + {viewPortDimensions.maxs[0] >> 2, viewPortDimensions.maxs[1] >> 2}, + {0, 0, 0},//todo + true + ); + frameBufCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + frameBufCmd.setDefaultScissors(); + drawMaterial(frameBufCmd, ffxGaussMat[currentFrame][i]); + } + } + + { + swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + swapChainCmd.setDefaultScissors(); + drawMaterial(swapChainCmd, ffxGlowMat[currentFrame]); + } +} + +void FFXGlowPassVLK::assignFFXGlowUBOConsts(float glow) { auto &ffxGlowVs = m_ffxGlowVs->getObject(); ffxGlowVs = {1,1,0,0}; m_ffxGlowVs->save(); @@ -32,15 +142,19 @@ void FFXGlowPassVLK::assignFFXGlowUBOConsts() { {{10, 2, -2, -10}}, }}; - for (int i = 0; i < 3; i++) { - auto ffxGlowPs1 = m_ffxGlowPSs[i]->getObject(); + for (int i = 0; i < GAUSS_PASS_COUNT; i++) { + auto &ffxGlowPs1 = m_ffxGaussPSs[i]->getObject(); std::copy(std::begin(texOffsets[i*2]), std::end(texOffsets[i*2]), std::begin(ffxGlowPs1.texOffsetX)); std::copy(std::begin(texOffsets[i*2+1]), std::end(texOffsets[i*2+1]), std::begin(ffxGlowPs1.texOffsetY)); - m_ffxGlowPSs[i]->save(); + m_ffxGaussPSs[i]->save(); } + + auto &ffxGlowPS = m_ffxGlowPS->getObject(); + ffxGlowPS = {1,1,0,glow}; + m_ffxGlowPS->save(); } -void FFXGlowPassVLK::createFrameBuffers(const HGDeviceVLK &device, int m_width, int m_height) { +void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { { auto const dataFormat = {ITextureFormat::itRGBA}; int targetWidth = m_width >> 2; @@ -48,7 +162,7 @@ void FFXGlowPassVLK::createFrameBuffers(const HGDeviceVLK &device, int m_width, for (auto &colorFrameBuffer: m_GlowFrameB1) { colorFrameBuffer = std::make_shared( - *device, + *m_device, dataFormat, ITextureFormat::itDepth32, 1, @@ -57,7 +171,7 @@ void FFXGlowPassVLK::createFrameBuffers(const HGDeviceVLK &device, int m_width, } for (auto &colorFrameBuffer: m_GlowFrameB2) { colorFrameBuffer = std::make_shared( - *device, + *m_device, dataFormat, ITextureFormat::itDepth32, 1, @@ -67,24 +181,56 @@ void FFXGlowPassVLK::createFrameBuffers(const HGDeviceVLK &device, int m_width, } } +std::shared_ptr FFXGlowPassVLK::getTargetFrameBuffer(int GAUSS_PASS_I, int frameInFlightI) { + return (GAUSS_PASS_I & 1) ? + m_GlowFrameB1[frameInFlightI] : + m_GlowFrameB2[frameInFlightI]; +} + std::shared_ptr -FFXGlowPassVLK::createFFxGlowMat( - const std::shared_ptr> &ffxGlowVs, - const std::shared_ptr> &ffxGlowPS, +FFXGlowPassVLK::createFFXGaussMat( + const std::shared_ptr> &ffxGaussVs, + const std::shared_ptr> &ffxGaussPS, + const std::shared_ptr &texture, const PipelineTemplate &pipelineTemplate, - const ) { + const std::shared_ptr &targetRenderPass) { auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}) - .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) + .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(2, BufferChunkHelperVLK::cast(ffxGaussVs)->getSubBuffer()) + .ubo(4, BufferChunkHelperVLK::cast(ffxGaussPS)->getSubBuffer()); + }) + .createDescriptorSet(1, [texture](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, texture); + }) + .toMaterial(); + + return material; +} + +std::shared_ptr +FFXGlowPassVLK::createFFXGlowMat( + const std::shared_ptr> &ffxGlowVs, + const std::shared_ptr> &ffxGlowPS, + const std::shared_ptr &screenTex, + const std::shared_ptr &blurTex, + const PipelineTemplate &pipelineTemplate, + const std::shared_ptr &targetRenderPass) { + + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}) + .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelper::cast(ffxGlowVs)->getSubBuffer()) - .ubo(4, BufferChunkHelper::cast(ffxGlowPS)->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(ffxGlowVs)->getSubBuffer()) + .ubo(4, BufferChunkHelperVLK::cast(ffxGlowPS)->getSubBuffer()); }) - .createDescriptorSet(1, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { + .createDescriptorSet(1, [screenTex, blurTex](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelper::cast(ffxGlowVs)->getSubBuffer()) - .ubo(4, BufferChunkHelper::cast(ffxGlowPS)->getSubBuffer()); + .texture(5, screenTex) + .texture(6, blurTex); }) .toMaterial(); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h index 50d8d507d..fdc6331fc 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h @@ -13,15 +13,51 @@ class FFXGlowPassVLK { public: - FFXGlowPassVLK(HGBufferVLK uboBuffer); - void assignFFXGlowUBOConsts(); - void createFrameBuffers(const HGDeviceVLK &device, int m_width, int m_height); + + FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); + void assignFFXGlowUBOConsts(float glow); + void updateDimensions(int width, int height, + const std::vector> &inputColorTextures, + const std::shared_ptr &finalRenderPass); + + void doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, + const std::shared_ptr &finalRenderPass, + ViewPortDimensions &viewPortDimensions); + private: + static constexpr int GAUSS_PASS_COUNT = 3; + HGDeviceVLK m_device; + + std::shared_ptr m_renderPass; + HGVertexBufferBindings m_drawQuadVao = nullptr; + std::shared_ptr> m_ffxGlowVs; - std::array>,3> m_ffxGlowPSs; + std::array>, GAUSS_PASS_COUNT> m_ffxGaussPSs; + std::shared_ptr> m_ffxGlowPS; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_GlowFrameB1; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_GlowFrameB2; + + std::array, GAUSS_PASS_COUNT>, IDevice::MAX_FRAMES_IN_FLIGHT> ffxGaussMat; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> ffxGlowMat; + + std::shared_ptr createFFXGaussMat(const std::shared_ptr> &ffxGlowVs, + const std::shared_ptr> &ffxGlowPS, + const std::shared_ptr &texture, + const PipelineTemplate &pipelineTemplate, + const std::shared_ptr &targetRenderPass); + + std::shared_ptr createFFXGlowMat(const std::shared_ptr> &ffxGlowVs, + const std::shared_ptr> &ffxGlowPS, + const std::shared_ptr &screenTex, + const std::shared_ptr &blurTex, + const PipelineTemplate &pipelineTemplate, + const std::shared_ptr &targetRenderPass); + + void createFrameBuffers(int width, int height); + + std::shared_ptr getTargetFrameBuffer(int GAUSS_PASS_I, int frameInFlightI); + inline void drawMaterial (CmdBufRecorder& cmdBuffer, const std::shared_ptr &mat); }; From 28100f302465412a0361d426dcaba1d8683241c0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 20 Mar 2023 23:57:26 +0200 Subject: [PATCH 051/212] Compilable, but particle's VBO is not getting resized --- wowViewerLib/CMakeLists.txt | 4 +- .../src/engine/managers/CRibbonEmitter.cpp | 162 ++++++++-------- .../src/engine/managers/CRibbonEmitter.h | 2 +- .../src/engine/managers/animationManager.cpp | 4 +- .../src/engine/managers/animationManager.h | 7 +- .../managers/particles/particleEmitter.cpp | 175 ++++++++---------- .../managers/particles/particleEmitter.h | 9 +- .../src/engine/objects/ViewsObjects.cpp | 11 +- .../src/engine/objects/ViewsObjects.h | 8 +- .../src/engine/objects/adt/adtObject.cpp | 4 +- .../src/engine/objects/adt/adtObject.h | 6 +- .../src/engine/objects/m2/m2Object.cpp | 26 ++- wowViewerLib/src/engine/objects/m2/m2Object.h | 10 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 10 +- .../src/engine/objects/wmo/wmoGroupObject.h | 5 +- wowViewerLib/src/gapi/interface/IDevice.h | 8 +- .../src/gapi/interface/meshes/IM2Mesh.h | 12 +- .../src/gapi/interface/meshes/ISortableMesh.h | 27 +++ .../gapi/interface/meshes/ITransparentMesh.h | 24 --- wowViewerLib/src/gapi/interface/sortLambda.h | 19 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 21 +-- .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 16 +- .../gapi/vulkan/meshes/GSortableMeshVLK.cpp | 10 + .../src/gapi/vulkan/meshes/GSortableMeshVLK.h | 25 +++ .../renderer/mapScene/IMapSceneBufferCreate.h | 7 + .../renderer/mapScene/MapSceneRenderer.cpp | 11 +- .../src/renderer/mapScene/MapSceneRenderer.h | 15 +- .../mapScene/materials/IMaterialStructs.h | 9 + .../vulkan/MapSceneRenderForwardVLK.cpp | 66 ++++++- .../vulkan/MapSceneRenderForwardVLK.h | 11 ++ 31 files changed, 406 insertions(+), 320 deletions(-) create mode 100644 wowViewerLib/src/gapi/interface/meshes/ISortableMesh.h delete mode 100644 wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h create mode 100644 wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index d77c0b39e..95e2a53ed 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -327,7 +327,7 @@ set(SOURCE_FILES src/renderer/mapScene/FrameDependentData.h src/renderer/buffers/IVertexBufferDynamicTemplate.cpp src/renderer/buffers/IVertexBufferDynamicTemplate.h - src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ITransparentMesh.h + src/gapi/interface/IRendererProxy.h src/gapi/interface/meshes/ISortableMesh.h src/renderer/mapScene/IMapSceneBufferCreate.h src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h @@ -520,7 +520,7 @@ if (LINK_VULKAN) src/gapi/vulkan/utils/MutexLockedVector.h src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h src/gapi/vulkan/bindable/DSBindable.h - src/renderer/mapScene/vulkan/materials/IMaterialInstance.h) + src/renderer/mapScene/vulkan/materials/IMaterialInstance.h src/gapi/vulkan/meshes/GSortableMeshVLK.cpp src/gapi/vulkan/meshes/GSortableMeshVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index fea6fb20e..92a319402 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -91,86 +91,86 @@ CRibbonEmitter::CRibbonEmitter(HApiContainer api, M2Object *object, extern EGxBlendEnum M2BlendingModeToEGxBlendEnum [8]; void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &materials, std::vector &textureIndicies) { auto device = m_api->hDevice; - - //Create Buffers - auto ribbonBindings = std::vector(staticRibbonBindings.begin(), staticRibbonBindings.end()); - for (int k = 0; k < 4; k++) { - //TODO: - /* - frame[k].m_indexVBO = device->createIndexBuffer(); - frame[k].m_bufferVBO = device->createVertexBuffer(); - */ - - frame[k].m_bindings = device->createVertexBufferBindings(); - frame[k].m_bindings->setIndexBuffer(frame[k].m_indexVBO); - - frame[k].m_bindings->addVertexBufferBinding(frame[k].m_bufferVBO, ribbonBindings); - frame[k].m_bindings->save(); - - - //Get shader - for(int i = 0; i < materials.size(); i++) { - auto &material = materials[i]; - auto &textureIndex = textureIndicies[i]; - - HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); - - - //TODO: - PipelineTemplate pipelineTemplate; - pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; - pipelineTemplate.depthWrite = !(material.flags & 0x10);; - pipelineTemplate.depthCulling = !(material.flags & 0x8);; - pipelineTemplate.backFaceCulling = !(material.flags & 0x4);; - pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; - - - //Let's assume ribbons are always at least transparent - if (pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { - pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - } - - //Create mesh - gMeshTemplate meshTemplate(frame[k].m_bindings); - - meshTemplate.start = 0; - meshTemplate.end = 0; - - meshTemplate.texture = std::vector(1, nullptr); - HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); - meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); - - auto blendMode = pipelineTemplate.blendMode; - auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; - std::shared_ptr> meshRibbonWideBlockPS = nullptr; - - meshRibbonWideBlockPS->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](auto &data, const HFrameDependantData &frameDepedantData) { - Ribbon::meshRibbonWideBlockPS& blockPS = data; - - blockPS.uAlphaTest = -1.0f; - blockPS.uPixelShader = 0; - blockPS.uBlendMode = static_cast(blendMode); - - mathfu::mat4 textureTransformMat = mathfu::mat4::Identity(); - if (textureTransformLookupIndex >= 0) { - textureTransformMat = m2Object->getTextureTransformByLookup(textureTransformLookupIndex); - } - - auto textureTranslate = textureTransformMat.GetColumn(3); - blockPS.textureTranslate0 = textureTranslate.x; - blockPS.textureTranslate1 = textureTranslate.y; - blockPS.textureTranslate2 = textureTranslate.z; - - blockPS.textureScale0 = textureTransformMat.GetColumn(0).Length(); - blockPS.textureScale1 = textureTransformMat.GetColumn(1).Length(); - blockPS.textureScale2 = textureTransformMat.GetColumn(2).Length(); - - }); - - - frame[k].m_meshes.push_back(device->createMesh(meshTemplate)); - } - } +// +// //Create Buffers +// auto ribbonBindings = std::vector(staticRibbonBindings.begin(), staticRibbonBindings.end()); +// for (int k = 0; k < 4; k++) { +// //TODO: +// /* +// frame[k].m_indexVBO = device->createIndexBuffer(); +// frame[k].m_bufferVBO = device->createVertexBuffer(); +// */ +// +// frame[k].m_bindings = device->createVertexBufferBindings(); +// frame[k].m_bindings->setIndexBuffer(frame[k].m_indexVBO); +// +// frame[k].m_bindings->addVertexBufferBinding(frame[k].m_bufferVBO, ribbonBindings); +// frame[k].m_bindings->save(); +// +// +// //Get shader +// for(int i = 0; i < materials.size(); i++) { +// auto &material = materials[i]; +// auto &textureIndex = textureIndicies[i]; +// +// HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); +// +// +// //TODO: +// PipelineTemplate pipelineTemplate; +// pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; +// pipelineTemplate.depthWrite = !(material.flags & 0x10);; +// pipelineTemplate.depthCulling = !(material.flags & 0x8);; +// pipelineTemplate.backFaceCulling = !(material.flags & 0x4);; +// pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; +// +// +// //Let's assume ribbons are always at least transparent +// if (pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { +// pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; +// } +// +// //Create mesh +// gMeshTemplate meshTemplate(frame[k].m_bindings); +// +// meshTemplate.start = 0; +// meshTemplate.end = 0; +// +// meshTemplate.texture = std::vector(1, nullptr); +// HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); +// meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); +// +// auto blendMode = pipelineTemplate.blendMode; +// auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; +// std::shared_ptr> meshRibbonWideBlockPS = nullptr; +// +// meshRibbonWideBlockPS->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](auto &data, const HFrameDependantData &frameDepedantData) { +// Ribbon::meshRibbonWideBlockPS& blockPS = data; +// +// blockPS.uAlphaTest = -1.0f; +// blockPS.uPixelShader = 0; +// blockPS.uBlendMode = static_cast(blendMode); +// +// mathfu::mat4 textureTransformMat = mathfu::mat4::Identity(); +// if (textureTransformLookupIndex >= 0) { +// textureTransformMat = m2Object->getTextureTransformByLookup(textureTransformLookupIndex); +// } +// +// auto textureTranslate = textureTransformMat.GetColumn(3); +// blockPS.textureTranslate0 = textureTranslate.x; +// blockPS.textureTranslate1 = textureTranslate.y; +// blockPS.textureTranslate2 = textureTranslate.z; +// +// blockPS.textureScale0 = textureTransformMat.GetColumn(0).Length(); +// blockPS.textureScale1 = textureTransformMat.GetColumn(1).Length(); +// blockPS.textureScale2 = textureTransformMat.GetColumn(2).Length(); +// +// }); +// +// +// frame[k].m_meshes.push_back(device->createMesh(meshTemplate)); +// } +// } } //----- (00A199E0) -------------------------------------------------------- @@ -860,7 +860,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV this->m_ribbonEmitterflags.m_initialized = 1; } -void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { // auto &currFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; // if (currFrame.isDead) return; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index 26fc6a79e..6c2cbcb7f 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -115,7 +115,7 @@ class CRibbonEmitter { //CTexture **SetTexture(unsigned int a2, CTexture *a3); //int ReplaceTexture(unsigned int a2, CTexture *a3); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); }; diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index dd65f5971..d9b72b9ee 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -738,7 +738,7 @@ void AnimationManager::update( std::vector &subMeshColors, std::vector &transparencies, std::vector &lights, - std::vector &particleEmitters, + std::vector> &particleEmitters, std::vector &ribbonEmitters) { @@ -1191,7 +1191,7 @@ void AnimationManager::calcCamera(M2CameraResult &camera, int cameraId, mathfu:: camera.diagFov = fov; } -void AnimationManager::calcParticleEmitters(std::vector &particleEmitters, +void AnimationManager::calcParticleEmitters(const std::vector> &particleEmitters, std::vector &bonesMatrices) { auto &peRecords = boneMasterData->getM2Geom()->getM2Data()->particle_emitters; if (peRecords.size <= 0) return; diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index f962c9a5c..557b5e74a 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -63,7 +63,7 @@ class AnimationManager { std::vector &subMeshColors, std::vector &transparencies, std::vector &lights, - std::vector &particleEmitters, + std::vector> &particleEmitters, std::vector &ribbonEmitters /*cameraDetails, particleEmitters*/); @@ -84,8 +84,9 @@ class AnimationManager { void calcLights(std::vector &lights, std::vector &bonesMatrices); - void calcParticleEmitters(std::vector &particleEmitters, - std::vector &bonesMatrices); + void calcParticleEmitters( + const std::vector> &particleEmitters, + std::vector &bonesMatrices); void calcRibbonEmitters(std::vector &ribbonEmitters); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index af9f95574..b5a084abb 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -21,15 +21,6 @@ HGIndexBuffer ParticleEmitter::m_indexVBO = nullptr; static const size_t MAX_PARTICLES_PER_EMITTER = 2000; -static const std::array staticM2ParticleBindings = {{ - {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, - {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, - {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, - {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, - {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, -}}; - - enum class ParticleVertexShader : int { None = -1, Particle_Color_T2 = 0, @@ -90,7 +81,7 @@ static const struct { }; -ParticleEmitter::ParticleEmitter(HApiContainer api, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw) : m_seed(rand()), m_api(api), m2Object(m2Object) { +ParticleEmitter::ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw) : m_seed(rand()), m_api(api), m2Object(m2Object) { if (!randTableInited) { for (int i = 0; i < 128; i++) { @@ -218,6 +209,7 @@ ParticleEmitter::ParticleEmitter(HApiContainer api, M2Particle *particle, M2Obje } selectShaderId(); + createMesh(sceneRenderer); } void ParticleEmitter::selectShaderId() { @@ -253,7 +245,7 @@ void ParticleEmitter::selectShaderId() { } } -std::array PaticleBlendingModeToEGxBlendEnum1 = +static const std::array ParticleBlendingModeToEGxBlendEnum = { EGxBlendEnum::GxBlend_Opaque, EGxBlendEnum::GxBlend_AlphaKey, @@ -265,12 +257,12 @@ std::array PaticleBlendingModeToEGxBlendEnum1 = EGxBlendEnum::GxBlend_BlendAdd }; -void ParticleEmitter::createMesh() { +void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; if (m_indexVBO == nullptr) { //TODO: - //m_indexVBO = device->createIndexBuffer(); + m_indexVBO = sceneRenderer->createM2IndexBuffer(MAX_PARTICLES_PER_EMITTER*6*sizeof(uint16_t)); int vo = 0; for (int i = 0; i < MAX_PARTICLES_PER_EMITTER; i++) { szIndexBuff.push_back(vo + 0); @@ -284,40 +276,22 @@ void ParticleEmitter::createMesh() { m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); } - //Create Buffers - auto bindingVector = std::vector(staticM2ParticleBindings.begin(), - staticM2ParticleBindings.end()); - for (int i = 0; i < 4; i++) { - //TODO: -// frame[i].m_bufferVBO = device->createVertexBufferDynamic(10 * sizeof(ParticleBuffStructQuad)); - - frame[i].m_bindings = device->createVertexBufferBindings(); - frame[i].m_bindings->setIndexBuffer(m_indexVBO); - frame[i].m_bindings->addVertexBufferBinding(frame[i].m_bufferVBO, bindingVector); - frame[i].m_bindings->save(); - - //Get shader - HGShaderPermutation shaderPermutation = device->getShader("m2ParticleShader", "m2ParticleShader", nullptr); - - //Create mesh - gMeshTemplate meshTemplate(frame[i].m_bindings); + //Create Material + { PipelineTemplate pipelineTemplate; uint8_t blendMode = m_data->old.blendingType; - pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = blendMode <= 1; pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; pipelineTemplate.blendMode = - blendMode < PaticleBlendingModeToEGxBlendEnum1.size() ? - PaticleBlendingModeToEGxBlendEnum1[blendMode] : + blendMode < ParticleBlendingModeToEGxBlendEnum.size() ? + ParticleBlendingModeToEGxBlendEnum[blendMode] : EGxBlendEnum::GxBlend_Opaque; - - meshTemplate.meshType = MeshType::eParticleMesh; - meshTemplate.start = 0; - meshTemplate.end = 0; + M2ParticleMaterialTemplate particleTemplate; bool multitex = m_data->old.flags_per_number.hex_10000000 > 0; HBlpTexture tex0 = nullptr; @@ -326,37 +300,34 @@ void ParticleEmitter::createMesh() { } else { tex0 = m2Object->getBlpTextureData(this->m_data->old.texture); } - meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); + particleTemplate.textures[0] = device->createBlpTexture(tex0, true, true); if (multitex) { HBlpTexture tex1 = m2Object->getBlpTextureData(this->m_data->old.texture_1); HBlpTexture tex2 = m2Object->getBlpTextureData(this->m_data->old.texture_2); - meshTemplate.texture[1] = device->createBlpTexture(tex1, true, true); - meshTemplate.texture[2] = device->createBlpTexture(tex2, true, true); + particleTemplate.textures[1] = device->createBlpTexture(tex1, true, true); + particleTemplate.textures[2] = device->createBlpTexture(tex2, true, true); } - meshTemplate.texture.resize((multitex) ? 3 : 1); - - auto l_blendMode = pipelineTemplate.blendMode; - std::shared_ptr> meshParticleWideBlockPS = nullptr; - meshParticleWideBlockPS->setUpdateHandler([this, l_blendMode](auto &data, const HFrameDependantData &frameDepedantData) { - Particle::meshParticleWideBlockPS &blockPS = data; - uint8_t blendMode = m_data->old.blendingType; - if (blendMode == 0) { - blockPS.uAlphaTest = -1.0f; - } else if (blendMode == 1) { - blockPS.uAlphaTest = 0.501960814f; - } else { - blockPS.uAlphaTest = 0.0039215689f; - } - int uPixelShader = particleMaterialShader[this->shaderId].pixelShader; + m_material = sceneRenderer->createM2ParticleMaterial(pipelineTemplate, particleTemplate); + } + + + //Create Buffers + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + //TODO: + frame[i].m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(10 * sizeof(ParticleBuffStructQuad)); + + frame[i].m_bindings = sceneRenderer->createM2ParticleVAO(frame[i].m_bufferVBO,m_indexVBO); - blockPS.uPixelShader = uPixelShader; - blockPS.uBlendMode = static_cast(l_blendMode); - }); + //Create mesh + gMeshTemplate meshTemplate(frame[i].m_bindings); - frame[i].m_mesh = device->createMesh(meshTemplate); + meshTemplate.meshType = MeshType::eParticleMesh; + meshTemplate.start = 0; + meshTemplate.end = 0; + frame[i].m_mesh = sceneRenderer->createSortableMesh(meshTemplate, m_material, m_data->old.textureTileRotation); } } @@ -435,11 +406,6 @@ void ParticleEmitter::InternalUpdate(animTime_t delta) { void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathfu::vec3 invMatTransl, mathfu::mat4 *frameOfReference, mathfu::mat4 &viewMatrix) { if (getGenerator() == nullptr) return; - //TODO: -// if () { -// createMesh(); -// } - // if (this->particles.size() <= 0 && !isEnabled) return; m_prevPosition = m_emitterModelMatrix.TranslationVector3D(); @@ -657,8 +623,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { this->calculateQuadToViewEtc(nullptr, viewMatrix); // FrameOfRerefence mat is null since it's not used -// int frame = m_api->hDevice->getUpdateFrameNumber(); - int frameNum = 0; + int frameNum = m_api->hDevice->getDrawFrameNumber(); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; size_t maxFutureSize = particles.size() * sizeof(ParticleBuffStructQuad); if ((m_data->old.flags & 0x60000) == 0x60000) { @@ -666,7 +631,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { } //TODO: - //vboBufferDynamic->resize(maxFutureSize); + vboBufferDynamic->resize(maxFutureSize); szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); szVertexCnt = 0; @@ -1098,37 +1063,57 @@ ParticleEmitter::BuildQuadT3( } -void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { -// if (getGenerator() == nullptr) return; -// -// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; -// if (!currentFrame.active) -// return; -// -// HGParticleMesh mesh = frame[m_api->hDevice->getUpdateFrameNumber()].m_mesh; -// mesh->setRenderOrder(renderOrder); -// if (mesh->getIsTransparent()) { -// transparentMeshes.push_back(mesh); -// } else { -// opaqueMeshes.push_back(mesh); -// } +void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { + if (getGenerator() == nullptr) return; + + auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + if (!currentFrame.active) + return; + + HGParticleMesh mesh = frame[m_api->hDevice->getDrawFrameNumber()].m_mesh; + if (mesh->getIsTransparent()) { + transparentMeshes.push_back(mesh); + } else { + opaqueMeshes.push_back(mesh); + } } void ParticleEmitter::updateBuffers() { -// if (getGenerator() == nullptr) return; -// -// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; -// currentFrame.active = szVertexCnt > 0; -// -// if (!currentFrame.active) -// return; -// -//// currentFrame.m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); -// currentFrame.m_bufferVBO->save(szVertexCnt * sizeof(ParticleBuffStructQuad)); -// -// currentFrame.m_mesh->setEnd(szVertexCnt * 6); -// currentFrame.m_mesh->setSortDistance(m_currentBonePos); -// currentFrame.m_mesh->setPriorityPlane(m_data->old.textureTileRotation); + if (getGenerator() == nullptr) return; + + auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + currentFrame.active = szVertexCnt > 0; + + if (!currentFrame.active) + return; + +// currentFrame.m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); + currentFrame.m_bufferVBO->save(szVertexCnt * sizeof(ParticleBuffStructQuad)); + + currentFrame.m_mesh->setEnd(szVertexCnt * 6); + currentFrame.m_mesh->setSortDistance(m_currentBonePos); + + //Update material + { + Particle::meshParticleWideBlockPS &blockPS = m_material->m_fragmentData->getObject(); + uint8_t blendMode = m_data->old.blendingType; + if (blendMode == 0) { + blockPS.uAlphaTest = -1.0f; + } else if (blendMode == 1) { + blockPS.uAlphaTest = 0.501960814f; + } else { + blockPS.uAlphaTest = 0.0039215689f; + } + + int uPixelShader = particleMaterialShader[this->shaderId].pixelShader; + + blockPS.uPixelShader = uPixelShader; + blockPS.uBlendMode = static_cast(blendMode < ParticleBlendingModeToEGxBlendEnum.size() ? + ParticleBlendingModeToEGxBlendEnum[blendMode] : + EGxBlendEnum::GxBlend_Opaque); + + m_material->m_fragmentData->save(); + } } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index e7dd12d88..0550fbc57 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -56,7 +56,7 @@ struct CParticleMaterialFlags { class ParticleEmitter { public: - ParticleEmitter(HApiContainer api, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw); + ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw); ~ParticleEmitter() { delete generator; } @@ -67,7 +67,7 @@ class ParticleEmitter { CParticleGenerator * getGenerator(){ return generator; } - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); int flags = 6; @@ -193,9 +193,10 @@ class ParticleEmitter { HGParticleMesh m_mesh = nullptr; bool active = false; } ; - std::array frame; + std::shared_ptr m_material = nullptr; + std::array frame; - void createMesh(); + void createMesh(const HMapSceneBufferCreate &sceneRenderer); static HGIndexBuffer m_indexVBO; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 9faaec11e..f37497c4f 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -13,7 +13,7 @@ #include "../algorithms/mathHelper_culling.h" #include "../../gapi/interface/materials/IMaterial.h" -void ExteriorView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { +void ExteriorView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { { auto inserter = std::back_inserter(opaqueMeshes); std::copy(this->m_opaqueMeshes.begin(), this->m_opaqueMeshes.end(), inserter); @@ -28,7 +28,7 @@ void ExteriorView::collectMeshes(std::vector &opaqueMeshes, std::vector< } -void GeneralView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { +void GeneralView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { for (auto& wmoGroup : wmoGroupArray.getToDraw()) { wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); } @@ -82,8 +82,9 @@ static std::array DrawPortalBindings = { //24 }; -void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, std::vector &opaqueMeshes, std::vector &transparentMeshes) { - +void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, std::vector &opaqueMeshes, std::vector &transparentMeshes) { +//TODO: + return; std::vector indiciesArray; std::vector verticles; int k = 0; @@ -163,7 +164,7 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st }); - transparentMeshes.push_back(hDevice->createMesh(meshTemplate)); +// transparentMeshes.push_back(hDevice->createMesh(meshTemplate)); } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 4904813a6..cde914ee9 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -49,10 +49,10 @@ class GeneralView { std::vector m_meshes = {}; } portalPointsFrame; - virtual void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes); + virtual void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); - void produceTransformedPortalMeshes(HApiContainer &apiContainer,std::vector &opaqueMeshes, std::vector &transparentMeshes); + void produceTransformedPortalMeshes(HApiContainer &apiContainer,std::vector &opaqueMeshes, std::vector &transparentMeshes); void addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos); }; @@ -67,10 +67,10 @@ class ExteriorView : public GeneralView { public: std::vector> drawnADTs = {}; std::vector m_opaqueMeshes = {}; - std::vector m_transparentMeshes = {}; + std::vector m_transparentMeshes = {}; public: - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) override; + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) override; }; class FrameViewsHolder { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index fa93e22e4..2c4643ff4 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -146,7 +146,7 @@ void AdtObject::loadWmos() { } } -HGMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { +HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water if (liquidInstance.offset_exists_bitmap > 0 && liquidInstance.height > 0) { @@ -761,7 +761,7 @@ void AdtObject::loadAlphaTextures() { -void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { if (m_freeStrategy != nullptr) m_freeStrategy(false, true, m_mapApi->getCurrentSceneTime()); if (!m_loaded) return; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 910d12f9a..f093def0d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -43,7 +43,7 @@ class AdtObject { FileStatus getLoadedStatus(); - void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void collectMeshesLod(std::vector &renderedThisFrame); void update(animTime_t deltaTime); @@ -133,7 +133,7 @@ class AdtObject { std::array adtMeshes = {}; //16x16, then layer - std::array, 16*16> waterMeshes = {}; + std::array, 16*16> waterMeshes = {}; std::vector adtLodMeshes; std::vector tileAabb; @@ -172,7 +172,7 @@ class AdtObject { void loadM2s(); void loadWmos(); void loadWater(); - HGMesh createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos); + HGSortableMesh createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos); bool checkNonLodChunkCulling(ADTObjRenderRes &adtFrustRes, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 61302f617..ebd2fe62f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -95,7 +95,7 @@ enum class M2VertexShader : int { inline constexpr const int operator+ (M2PixelShader const val) { return static_cast(val); }; inline constexpr const int operator+ (M2VertexShader const val) { return static_cast(val); }; -EGxBlendEnum M2BlendingModeToEGxBlendEnum [8] = +const static EGxBlendEnum M2BlendingModeToEGxBlendEnum [8] = { EGxBlendEnum::GxBlend_Opaque, EGxBlendEnum::GxBlend_AlphaKey, @@ -459,9 +459,6 @@ int getShaderNames(M2Batch *m2Batch, std::string &vertexShader, std::string &pix M2Object::~M2Object() { delete m_animationManager; - for (auto obj: particleEmitters) { - delete obj; - } for (auto obj: ribbonEmitters) { delete obj; } @@ -946,7 +943,7 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ this->initSubmeshColors(); this->initTransparencies(); this->initLights(); - this->initParticleEmitters(); + this->initParticleEmitters(sceneRenderer); this->initRibbonEmitters(); @@ -1328,7 +1325,8 @@ void M2Object::createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer) blockVS.uColor = mathfu::vec4_packed(mathfu::vec4(0.1f, 0.7f, 0.1f, 0.1f)); }); - boundingBoxMesh = m_api->hDevice->createMesh(meshTemplate); + //TODO: +// boundingBoxMesh = sceneRenderer->createSortableMesh(meshTemplate); } bool M2Object::checkifBonesAreInRange(M2SkinProfile *skinProfile, M2SkinSection *skinSection) { @@ -1588,7 +1586,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, return m2Mesh; } -void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; @@ -1655,21 +1653,21 @@ void M2Object::initTransparencies() { void M2Object::initLights() { lights = std::vector(m_m2Geom->getM2Data()->lights.size); } -void M2Object::initParticleEmitters() { -// return; - particleEmitters = std::vector(); -// particleEmitters.reserve(m_m2Geom->getM2Data()->particle_emitters.size); +void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) { + particleEmitters.clear(); + particleEmitters.reserve(m_m2Geom->getM2Data()->particle_emitters.size); for (int i = 0; i < m_m2Geom->getM2Data()->particle_emitters.size; i++) { int txacVal = 0; if (m_m2Geom->txacMParticle.size() > 0) { txacVal = m_m2Geom->txacMParticle[i].value; } - ParticleEmitter *emitter = new ParticleEmitter(m_api, m_m2Geom->getM2Data()->particle_emitters.getElement(i), this, m_m2Geom, txacVal); - particleEmitters.push_back(emitter); + auto emitter = std::make_unique(m_api, sceneRenderer,m_m2Geom->getM2Data()->particle_emitters.getElement(i), this, m_m2Geom, txacVal); if (m_m2Geom->exp2 != nullptr && emitter->getGenerator() != nullptr) { emitter->getGenerator()->getAniProp()->zSource = m_m2Geom->exp2->content.getElement(i)->zSource; } + + particleEmitters.push_back(std::move(emitter)); } } @@ -1817,7 +1815,7 @@ mathfu::mat4 M2Object::getTextureTransformByLookup(int textureTrasformlookup) { } -void M2Object::drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void M2Object::drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { // return; // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 5f859e152..3a48570d2 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -90,7 +90,7 @@ class M2Object { HGVertexBufferBindings bufferBindings = nullptr; std::shared_ptr m_modelWideDataBuff = nullptr; - HGMesh boundingBoxMesh = nullptr; + HGSortableMesh boundingBoxMesh = nullptr; mathfu::vec4 m_ambientColorOverride; bool m_setAmbientColor = false; @@ -127,7 +127,7 @@ class M2Object { std::vector subMeshColors; std::vector transparencies; std::vector lights; - std::vector particleEmitters; + std::vector> particleEmitters; std::vector ribbonEmitters; std::unordered_map loadedTextures; @@ -157,7 +157,7 @@ class M2Object { void initSubmeshColors(); void initTransparencies(); void initLights(); - void initParticleEmitters(); + void initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer); void initRibbonEmitters(); void sortMaterials(mathfu::Matrix &modelViewMat); @@ -241,7 +241,7 @@ class M2Object { mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { // if (hasModf0x2Flag) { @@ -287,7 +287,7 @@ class M2Object { m_ambientColorOverride = ambientColor; } - void drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void createVertexBindings(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index a2c357648..b80f46ba3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -715,8 +715,9 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere } }); - HGMesh hmesh = device->createMesh(meshTemplate); - m_waterMeshArray.push_back(hmesh); + //TODO: +// HGMesh hmesh = device->createMesh(meshTemplate); +// m_waterMeshArray.push_back(hmesh); } void WmoGroupObject::loadDoodads() { @@ -1224,9 +1225,12 @@ void WmoGroupObject::setModelFileId(int fileId) { m_modelFileId = fileId; } -void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { if (!m_loaded) return; for (auto &i : this->m_meshArray) { + opaqueMeshes.push_back(i); + } + for (auto &i : this->m_sortableMeshArray) { if (i->getIsTransparent()) { opaqueMeshes.push_back(i); } else { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 8f0640d66..6d427e2d7 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -43,7 +43,7 @@ class WmoGroupObject { void setModelFileName(std::string modelName); void setModelFileId(int fileId); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; @@ -81,7 +81,8 @@ class WmoGroupObject { std::shared_ptr> vertexModelWideUniformBuffer = nullptr; std::shared_ptr> fragmentModelWideUniformBuffer = nullptr; std::vector m_meshArray = {}; - std::vector m_waterMeshArray = {}; + std::vector m_sortableMeshArray = {}; + std::vector m_waterMeshArray = {}; SMOGroupInfo *m_main_groupInfo; diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index b93a6770c..7949a82cb 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -17,6 +17,7 @@ class IUniformBuffer; class ITexture; class IShaderPermutation; class IMesh; +class ISortableMesh; class IM2Mesh; class IDevice; class IGPUFence; @@ -38,15 +39,17 @@ typedef std::shared_ptr HGUniformBuffer; typedef std::shared_ptr HGShaderPermutation; typedef std::shared_ptr HGMesh; typedef std::shared_ptr HGM2Mesh; -typedef std::shared_ptr HGParticleMesh; +typedef std::shared_ptr HGSortableMesh; +typedef std::shared_ptr HGParticleMesh; typedef std::shared_ptr HGOcclusionQuery; typedef std::shared_ptr HGTexture; typedef std::weak_ptr WGTexture; typedef std::shared_ptr HGPUFence; typedef std::shared_ptr HFrameBuffer; -#include "meshes/IMesh.h" #include "meshes/IM2Mesh.h" +#include "meshes/IMesh.h" +#include "meshes/ISortableMesh.h" #include "IOcclusionQuery.h" #include "IShaderPermutation.h" #include "buffers/IBuffer.h" @@ -157,6 +160,7 @@ class IDevice { virtual int getUploadSize() {return 0;}; virtual unsigned int getFrameNumber() = 0; + virtual unsigned int getDrawFrameNumber() = 0; virtual void increaseFrameNumber() = 0; virtual void submitDrawCommands() {}; diff --git a/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h b/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h index 2d1cd1808..50632a1bf 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IM2Mesh.h @@ -5,20 +5,16 @@ #ifndef AWEBWOWVIEWERCPP_IM2MESH_H #define AWEBWOWVIEWERCPP_IM2MESH_H -#include "ITransparentMesh.h" +#include "ISortableMesh.h" -class IM2Mesh : public ITransparentMesh { +class IM2Mesh : virtual public ISortableMesh { protected: - int m_priorityPlane = 0; int m_layer = 0; public: + IM2Mesh(int layer, int priority) : ISortableMesh(priority) { m_layer = layer;} ~IM2Mesh() override = default; - auto priorityPlane() -> int { return m_priorityPlane; } - auto layer() -> int& { return m_layer; } - - virtual void setPriorityPlane(int priorityPlane) = 0; - virtual void setLayer(int layer) = 0; + auto layer() const -> int { return m_layer; } }; #endif //AWEBWOWVIEWERCPP_IM2MESH_H diff --git a/wowViewerLib/src/gapi/interface/meshes/ISortableMesh.h b/wowViewerLib/src/gapi/interface/meshes/ISortableMesh.h new file mode 100644 index 000000000..80ddaa442 --- /dev/null +++ b/wowViewerLib/src/gapi/interface/meshes/ISortableMesh.h @@ -0,0 +1,27 @@ +// +// Created by Deamon on 19.12.22. +// + +#ifndef AWEBWOWVIEWERCPP_ISORTABLEMESH_H +#define AWEBWOWVIEWERCPP_ISORTABLEMESH_H + +#include "IMesh.h" + +class ISortableMesh : virtual public IMesh { + friend class IDevice; +protected: + float m_sortDistance = 0; + int m_priorityPlane = 0; +public: + explicit ISortableMesh(int priorityPlane) { m_priorityPlane = priorityPlane; }; + ~ISortableMesh() override = default; + + auto sortDistance() -> float { return m_sortDistance; } + auto priorityPlane() const-> int { return m_priorityPlane; } + + void setSortDistance(float distance) { m_sortDistance = distance; }; + float getSortDistance() { return m_sortDistance;}; + + virtual EGxBlendEnum getGxBlendMode() = 0; +}; +#endif //AWEBWOWVIEWERCPP_ISORTABLEMESH_H diff --git a/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h b/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h deleted file mode 100644 index 49cd5476a..000000000 --- a/wowViewerLib/src/gapi/interface/meshes/ITransparentMesh.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by Deamon on 19.12.22. -// - -#ifndef AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H -#define AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H - -#include "IMesh.h" - -class ITransparentMesh : virtual public IMesh { - friend class IDevice; -protected: - float m_sortDistance = 0; -public: - ~ITransparentMesh() override = default; - - auto sortDistance() -> float { return m_sortDistance; } - - virtual void setSortDistance(float distance) = 0; - virtual float getSortDistance() = 0; - - virtual EGxBlendEnum getGxBlendMode() = 0; -}; -#endif //AWEBWOWVIEWERCPP_ITRANSPARENTMESH_H diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index 56bb59039..3217b3c8b 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -1,8 +1,8 @@ #include "IDevice.h" static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { - ITransparentMesh * pA = dynamic_cast(indexA.get()); - ITransparentMesh * pB = dynamic_cast(indexB.get()); + ISortableMesh * pA = dynamic_cast(indexA.get()); + ISortableMesh * pB = dynamic_cast(indexB.get()); // HGMesh pA = sortedArrayPtr[indexA]; // HGMesh pB = sortedArrayPtr[indexB]; @@ -28,8 +28,8 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { if (pA->getIsTransparent() && pB->getIsTransparent()) { if (((pA->getMeshType() == MeshType::eM2Mesh || pA->getMeshType() == MeshType::eParticleMesh) && (pB->getMeshType() == MeshType::eM2Mesh || pB->getMeshType() == MeshType::eParticleMesh))) { - IM2Mesh *pA1 = dynamic_cast(pA); - IM2Mesh *pB1 = dynamic_cast(pB); + ISortableMesh *pA1 = dynamic_cast(pA); + ISortableMesh *pB1 = dynamic_cast(pB); if (pA1->priorityPlane()!= pB1->priorityPlane()) { return pB1->priorityPlane() > pA1->priorityPlane(); @@ -43,9 +43,12 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { } // if (pA1->getM2Object() == pB1->getM2Object()) { - if (pA1->bindings() == pB1->bindings()) { - if (pB1->layer() != pA1->layer()) { - return pB1->layer() < pA1->layer(); + if (pA1->bindings() == pB1->bindings() && pA->getMeshType() == pB->getMeshType() && pB->getMeshType() == MeshType::eM2Mesh) { + IM2Mesh *pA2 = dynamic_cast(pA); + IM2Mesh *pB2 = dynamic_cast(pB); + + if (pB2->layer() != pA2->layer()) { + return pB2->layer() < pA2->layer(); } } } else { @@ -56,7 +59,7 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { return false; } } - }else { + } else { if (pA->getSortDistance() > pB->getSortDistance()) { return true; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 1ffe29670..ac05e75b2 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -66,7 +66,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thisgetBlendMode(); -} diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index 7edb3574c..756d9fa72 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -5,17 +5,13 @@ #ifndef AWEBWOWVIEWERCPP_GM2MESH_H #define AWEBWOWVIEWERCPP_GM2MESH_H -#include "GMeshVLK.h" +#include "../../interface/meshes/IM2Mesh.h" +#include "GSortableMeshVLK.h" -class GM2MeshVLK : public GMeshVLK, public IM2Mesh { +class GM2MeshVLK : public GSortableMeshVLK, public IM2Mesh { public: - GM2MeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material); - -public: - void setLayer(int layer) override; - void setPriorityPlane(int priorityPlane) override; - void setSortDistance(float distance) override; - float getSortDistance() override; - EGxBlendEnum getGxBlendMode() override; + GM2MeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, int priorityPlane, int layer); + ~GM2MeshVLK() override = default ; }; + #endif //AWEBWOWVIEWERCPP_GM2MESH_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp new file mode 100644 index 000000000..917714acd --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp @@ -0,0 +1,10 @@ +// +// Created by Deamon on 3/20/2023. +// + +#include "GSortableMeshVLK.h" + +GSortableMeshVLK::GSortableMeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, + int priorityPlane) : GMeshVLK(meshTemplate, material), ISortableMesh(priorityPlane) { + +} diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h new file mode 100644 index 000000000..a5b380d38 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h @@ -0,0 +1,25 @@ +// +// Created by Deamon on 3/20/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GSORTABLEMESHVLK_H +#define AWEBWOWVIEWERCPP_GSORTABLEMESHVLK_H + + +#include "GMeshVLK.h" +#include "../../interface/meshes/ISortableMesh.h" + +class GSortableMeshVLK : public GMeshVLK, public virtual ISortableMesh { +public: + GSortableMeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, + int priorityPlane); + + ~GSortableMeshVLK() override = default; + + EGxBlendEnum getGxBlendMode() override { + return material()->getBlendMode(); + } +}; + + +#endif //AWEBWOWVIEWERCPP_GSORTABLEMESHVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 644e6ee77..c072927ed 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -39,12 +39,15 @@ class IMapSceneBufferCreate { virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; + virtual HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) = 0; + virtual HGVertexBuffer createADTVertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createADTIndexBuffer(int sizeInBytes) = 0; @@ -63,9 +66,13 @@ class IMapSceneBufferCreate { const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) = 0; + virtual std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2MaterialTemplate) = 0; + virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; + virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 84653b201..f196d4e8f 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -19,16 +19,9 @@ MapSceneRenderer::processCulling(const std::shared_ptr>, - std::shared_ptr> -> MapSceneRenderer::collectMeshes(const std::shared_ptr &renderPlan) { +void MapSceneRenderer::collectMeshes(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes) { mapProduceUpdateCounter.beginMeasurement(); - //Create meshes - auto hopaqueMeshes = std::make_shared>(); - auto htransparentMeshes = std::make_shared>(); - auto &opaqueMeshes = *hopaqueMeshes; auto &transparentMeshes = *htransparentMeshes; @@ -108,8 +101,6 @@ std::tuple< m_config->sortMeshTime = sortMeshCounter.getTimePerFrame(); m_config->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); m_config->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); - - return {hopaqueMeshes, htransparentMeshes}; } void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 0e6cdeca2..50c64662f 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -51,6 +51,14 @@ static const std::vector fullScreenQuad = {{ {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, }}; +static const std::vector staticM2ParticleBindings = {{ + {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, + {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, + {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, + {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, + {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, +}}; + class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: @@ -59,10 +67,9 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; - std::tuple< - std::shared_ptr>, - std::shared_ptr> - > collectMeshes(const std::shared_ptr &renderPlan); + void collectMeshes(const std::shared_ptr &renderPlan, + const std::shared_ptr> &hopaqueMeshes, + const std::shared_ptr> &htransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index e65b7d25a..7bdf08c85 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -14,6 +14,11 @@ struct M2MaterialTemplate { std::array textures = {nullptr, nullptr, nullptr, nullptr}; }; +struct M2ParticleMaterialTemplate { + std::array textures = {nullptr, nullptr, nullptr}; +}; + + class IM2ModelData { public: std::shared_ptr> m_placementMatrix = nullptr; @@ -29,6 +34,10 @@ class IM2Material : public IMaterial { std::shared_ptr> m_vertexData = nullptr; std::shared_ptr> m_fragmentData = nullptr; }; +class IM2ParticleMaterial : public IMaterial { +public: + std::shared_ptr> m_fragmentData = nullptr; +}; class ISkyMeshMaterial : public IMaterial { public: diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 98af582d2..92c9e0215 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -10,12 +10,14 @@ #include "../../../gapi/vulkan/buffers/IBufferChunkVLK.h" #include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" #include "materials/IMaterialInstance.h" +#include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer(1024*1024); vboM2Buffer = m_device->createVertexBuffer(1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); vboAdtBuffer = m_device->createVertexBuffer(1024*1024); vboWMOBuffer = m_device->createVertexBuffer(1024*1024); vboWaterBuffer = m_device->createVertexBuffer(1024*1024); @@ -47,6 +49,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_emptyM2VAO = createM2VAO(nullptr, nullptr); + m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); //Framebuffers for rendering @@ -84,6 +87,15 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createM2VAO(HGVertexBuffer vert return m2VAO; } +HGVertexBufferBindings MapSceneRenderForwardVLK::createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2ParticleVAO = m_device->createVertexBufferBindings(); + m2ParticleVAO->addVertexBufferBinding(vertexBuffer, staticM2ParticleBindings); + m2ParticleVAO->setIndexBuffer(indexBuffer); + + return m2ParticleVAO; +} + HGVertexBufferBindings MapSceneRenderForwardVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto waterVAO = m_device->createVertexBufferBindings(); @@ -106,6 +118,10 @@ HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { return vboM2Buffer->getSubBuffer(sizeInBytes); } +HGVertexBuffer MapSceneRenderForwardVLK::createM2ParticleVertexBuffer(int sizeInBytes) { + return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); +} + HGIndexBuffer MapSceneRenderForwardVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } @@ -133,10 +149,10 @@ HGVertexBuffer MapSceneRenderForwardVLK::createWaterVertexBuffer(int sizeInBytes HGIndexBuffer MapSceneRenderForwardVLK::createWaterIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } - HGVertexBuffer MapSceneRenderForwardVLK::createSkyVertexBuffer(int sizeInBytes) { return vboSkyBuffer->getSubBuffer(sizeInBytes);; }; + HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } @@ -181,6 +197,35 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & return material; } +std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleMaterial( + const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2ParticleMatTemplate) { + + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[0])) + .texture(6, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[1])) + .texture(7, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[2])); + }) + .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +} + + + std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto skyColors = std::make_shared>(uboBuffer); @@ -199,8 +244,6 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } - - inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh) { const auto &meshVlk = std::dynamic_pointer_cast(mesh); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); @@ -274,8 +317,11 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); + //Create meshes + auto opaqueMeshes = std::make_shared>(); + auto transparentMeshes = std::make_shared>(); - auto [opaqueMeshes, transparentMeshes] = collectMeshes(framePlan); + collectMeshes(framePlan, opaqueMeshes, transparentMeshes); return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { // --------------------- // Upload stuff @@ -338,17 +384,19 @@ HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const H return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); } +HGSortableMesh MapSceneRenderForwardVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane); + return mesh; +} + HGM2Mesh MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); - mesh->setLayer(layer); - mesh->setPriorityPlane(priorityPlane); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } - void MapSceneRenderForwardVLK::createFrameBuffers() { { auto const dataFormat = {ITextureFormat::itRGBA}; @@ -364,4 +412,4 @@ void MapSceneRenderForwardVLK::createFrameBuffers() { } } -} \ No newline at end of file +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index dd67bc386..0cf97d329 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -26,12 +26,15 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { //------------------------------------- HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; + virtual HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; + HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; @@ -48,9 +51,15 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; + HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; private: HGDeviceVLK m_device; @@ -61,6 +70,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::unique_ptr glowPass; HGBufferVLK vboM2Buffer; + HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboAdtBuffer; HGBufferVLK vboWMOBuffer; HGBufferVLK vboWaterBuffer; @@ -82,6 +92,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; + HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; void createFrameBuffers(); From bc671e95bf3e08c5eaa4c11d5c1632e59fe2eb06 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 21 Mar 2023 15:29:46 +0200 Subject: [PATCH 052/212] particles are working somewhat, but are not diplayed correctly --- .../forwardRendering/m2ParticleShader.frag | 1 - .../managers/particles/particleEmitter.cpp | 16 +- .../managers/particles/particleEmitter.h | 3 + .../src/engine/objects/scenes/map.cpp | 413 ------------------ .../src/engine/shader/ShaderDefinitions.h | 3 +- .../src/gapi/UniformBufferStructures.h | 1 - .../src/gapi/interface/buffers/IBuffer.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 9 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 3 + .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- 11 files changed, 30 insertions(+), 424 deletions(-) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index f94806c6b..8e4d74677 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -23,7 +23,6 @@ layout(std140, binding=0) uniform sceneWideBlockVSPS { layout(std140, binding=4) uniform meshWideBlockPS { vec4 uAlphaTestv; ivec4 uPixelShaderBlendModev; - vec4 uTextureTranslate; }; layout(set=1,binding=5) uniform sampler2D uTexture; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index b5a084abb..ed2dbef31 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -259,6 +259,7 @@ static const std::array ParticleBlendingModeToEGxBlendEnum = void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; + m_sceneRenderer = sceneRenderer; if (m_indexVBO == nullptr) { //TODO: @@ -315,9 +316,10 @@ void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { //Create Buffers for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { - //TODO: - frame[i].m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(10 * sizeof(ParticleBuffStructQuad)); + makeVAOForFrame(m_sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); + + frame[i].m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(10 * sizeof(ParticleBuffStructQuad)); frame[i].m_bindings = sceneRenderer->createM2ParticleVAO(frame[i].m_bufferVBO,m_indexVBO); //Create mesh @@ -330,6 +332,10 @@ void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { frame[i].m_mesh = sceneRenderer->createSortableMesh(meshTemplate, m_material, m_data->old.textureTileRotation); } } +void ParticleEmitter::makeVAOForFrame(const HMapSceneBufferCreate &sceneRenderer, particleFrame &currFrame, int size) { + currFrame.m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(size); + currFrame.m_bindings = sceneRenderer->createM2ParticleVAO(currFrame.m_bufferVBO,m_indexVBO); +} bool ParticleEmitter::randTableInited = false; @@ -630,8 +636,10 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { maxFutureSize *= 2; } - //TODO: - vboBufferDynamic->resize(maxFutureSize); + if (maxFutureSize > vboBufferDynamic->getSize()) { + makeVAOForFrame(m_sceneRenderer, frame[frameNum], maxFutureSize); + vboBufferDynamic = frame[frameNum].m_bufferVBO; + } szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); szVertexCnt = 0; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 0550fbc57..18f632224 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -79,6 +79,8 @@ class ParticleEmitter { static bool randTableInited; private: HApiContainer m_api; + HMapSceneBufferCreate m_sceneRenderer; + M2Particle *m_data; M2Object *m2Object; @@ -201,6 +203,7 @@ class ParticleEmitter { static HGIndexBuffer m_indexVBO; void GetSpin(CParticle2 &p, float &baseSpin, float &deltaSpin) const; + void makeVAOForFrame(const HMapSceneBufferCreate &sceneRenderer, particleFrame &frame, int size); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 5321ca6cf..d97053d23 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1589,419 +1589,6 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDefObj1 &ma animTime_t Map::getCurrentSceneTime() { return m_currentTime; } -//void Map::produceUpdateStage(HUpdateStage &updateStage) { -// mapProduceUpdateCounter.beginMeasurement(); -// mapUpdateCounter.beginMeasurement(); -// this->update(updateStage); -// mapUpdateCounter.endMeasurement(); -// -// //Create meshes -// updateStage->opaqueMeshes = std::make_shared(); -// updateStage->transparentMeshes = std::make_shared(); -// -// auto &opaqueMeshes = updateStage->opaqueMeshes->meshes; -// auto transparentMeshes = std::vector(); -// -// opaqueMeshes.reserve(30000); -// transparentMeshes.reserve(30000); -// -// auto cullStage = updateStage->cullResult; -// auto fdd = cullStage->frameDependentData; -// -// if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && -// (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { -// if (fdd->overrideValuesWithFinalFog) { -// if (skyMesh0x4Sky != nullptr) { -// transparentMeshes.push_back(skyMesh0x4Sky); -// skyMesh0x4Sky->setSortDistance(0); -// -// } -// } -// if ((m_skyConeAlpha > 0) ) { -// if (skyMesh != nullptr) -// opaqueMeshes.push_back(skyMesh); -// } -// } -// -// // Put everything into one array and sort -// interiorViewCollectMeshCounter.beginMeasurement(); -// bool renderPortals = m_api->getConfig()->renderPortals; -// for (auto &view : cullStage->viewsHolder.getInteriorViews()) { -// view->collectMeshes(opaqueMeshes, transparentMeshes); -// if (renderPortals) { -// view->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); -// } -// } -// interiorViewCollectMeshCounter.endMeasurement(); -// -// exteriorViewCollectMeshCounter.beginMeasurement(); -// { -// auto exteriorView = cullStage->viewsHolder.getExterior(); -// if (exteriorView != nullptr) { -// exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); -// if (renderPortals) { -// exteriorView->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); -// } -// } -// } -// exteriorViewCollectMeshCounter.endMeasurement(); -// -// m2CollectMeshCounter.beginMeasurement(); -// if (m_api->getConfig()->renderM2) { -// for (auto &m2Object : cullStage->m2Array.getDrawn()) { -// if (m2Object == nullptr) continue; -// m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); -// m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); -// } -// } -// m2CollectMeshCounter.endMeasurement(); -// -// //No need to sort array which has only one element -// sortMeshCounter.beginMeasurement(); -// if (transparentMeshes.size() > 1) { -// tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), -// #include "../../../gapi/interface/sortLambda.h" -// ); -// -// updateStage->transparentMeshes->meshes = transparentMeshes; -// -// } else { -// auto &targetTranspMeshes = updateStage->transparentMeshes->meshes; -// for (int i = 0; i < transparentMeshes.size(); i++) { -// targetTranspMeshes.push_back(transparentMeshes[i]); -// } -// } -// sortMeshCounter.endMeasurement(); -// -// //Collect textures for upload -// auto &textureToUpload = updateStage->texturesForUpload; -// textureToUpload.reserve(10000); -// for (auto &mesh: updateStage->transparentMeshes->meshes) { -// for (auto &text : mesh->texture()) { -// if (text != nullptr && !text->getIsLoaded()) { -// textureToUpload.push_back(text); -// } -// } -// } -// for (auto &mesh: updateStage->opaqueMeshes->meshes) { -// for (auto &text : mesh->texture()) { -// if (text != nullptr && !text->getIsLoaded()) { -// textureToUpload.push_back(text); -// } -// } -// } -// -// tbb::parallel_sort(textureToUpload.begin(), textureToUpload.end(), -// [](auto &first, auto &end) { return first < end; } -// ); -// textureToUpload.erase(unique(textureToUpload.begin(), textureToUpload.end()), textureToUpload.end()); -// -// //1. Collect buffers -// collectBuffersCounter.beginMeasurement(); -// std::vector &bufferChunks = updateStage->uniformBufferChunks; -// bufferChunks.reserve((opaqueMeshes.size() + updateStage->transparentMeshes->meshes.size()) * 5); -// int renderIndex = 0; -// for (const auto &mesh : opaqueMeshes) { -// for (int i = 0; i < 5; i++ ) { -// auto bufferChunk = mesh->getUniformBuffer(i); -// -// if (bufferChunk != nullptr) { -// bufferChunks.push_back(bufferChunk); -// } -// } -// } -// for (const auto &mesh : updateStage->transparentMeshes->meshes) { -// for (int i = 0; i < 5; i++ ) { -// auto bufferChunk = mesh->getUniformBuffer(i); -// -// if (bufferChunk != nullptr) { -// bufferChunks.push_back(bufferChunk); -// } -// } -// } -// collectBuffersCounter.endMeasurement(); -// -// sortBuffersCounter.beginMeasurement(); -// tbb::parallel_sort(bufferChunks.begin(), bufferChunks.end(), -// [](auto &first, auto &end) { return first < end; } -// ); -// bufferChunks.erase(unique(bufferChunks.begin(), bufferChunks.end()), bufferChunks.end()); -// sortBuffersCounter.endMeasurement(); -// -// mapProduceUpdateCounter.endMeasurement(); -// -// -// m_api->getConfig()->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); -// m_api->getConfig()->mapUpdateTime = mapUpdateCounter.getTimePerFrame(); -// m_api->getConfig()->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); -// m_api->getConfig()->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); -// m_api->getConfig()->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); -// m_api->getConfig()->sortMeshTime = sortMeshCounter.getTimePerFrame(); -// m_api->getConfig()->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); -// m_api->getConfig()->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); -//} - -//void Map::produceDrawStage(HDrawStage &resultDrawStage, std::vector &updateStages) { -// //Smash all meshes into one array -// -// auto opaqueMeshes = std::make_shared(); -// auto transparentMeshes = std::make_shared(); -// for (auto &updateStage : updateStages) { -// auto cullStage = updateStage->cullResult; -// -// //Create scenewide uniform -// resultDrawStage->frameDepedantData = updateStage->cullResult->frameDependentData; -// -// opaqueMeshes->meshes.insert(std::end(opaqueMeshes->meshes), -// std::begin(updateStage->opaqueMeshes->meshes), -// std::end(updateStage->opaqueMeshes->meshes)); -// transparentMeshes->meshes.insert(std::end(transparentMeshes->meshes), -// std::begin(updateStage->transparentMeshes->meshes), -// std::end(updateStage->transparentMeshes->meshes)); -// } -// -// //Sort transparent meshes. Again -// tbb::parallel_sort(transparentMeshes->meshes.begin(), transparentMeshes->meshes.end(), -//#include "../../../gapi/interface/sortLambda.h" -// ); -// -// resultDrawStage->opaqueMeshes = opaqueMeshes; -// resultDrawStage->transparentMeshes = transparentMeshes; -// -// HDrawStage origResultDrawStage = resultDrawStage; -// bool frameBufferSupported = m_api->hDevice->getIsRenderbufferSupported(); -// -// auto config = m_api->getConfig(); -// -// auto renderMats = resultDrawStage->matricesForRendering; -// if (renderMats != nullptr) { -// resultDrawStage->sceneWideBlockVSPSChunk = m_api->hDevice->createUniformBufferChunk(sizeof(sceneWideBlockVSPS)); -// resultDrawStage->sceneWideBlockVSPSChunk->setUpdateHandler( -// this->generateSceneWideChunk(renderMats, config) -// ); -// updateStages[0]->uniformBufferChunks.push_back(resultDrawStage->sceneWideBlockVSPSChunk); -// } -// -// -// -// if (frameBufferSupported ) { -// //Create a copy of exiting resultDrawStage -// auto resultDrawStageCpy = std::make_shared(); -// *resultDrawStageCpy = *resultDrawStage; -// //Assign a new frame buffer to copy -// resultDrawStageCpy->target = m_api->hDevice->createFrameBuffer( -// resultDrawStage->viewPortDimensions.maxs[0], -// resultDrawStage->viewPortDimensions.maxs[1], -// {ITextureFormat::itRGBA}, -// ITextureFormat::itDepth32, -// m_api->hDevice->getMaxSamplesCnt(), -// 4 -// ); -// resultDrawStageCpy->viewPortDimensions.mins = {0,0}; -// -// HDrawStage lastDrawStage = nullptr; -// HDrawStage prevDrawStage = resultDrawStageCpy; -// -// if (!config->disableGlow) { -// lastDrawStage = doGaussBlur(prevDrawStage, updateStages[0]->uniformBufferChunks); -// if (lastDrawStage != nullptr) -// prevDrawStage = lastDrawStage; -// } -// -// -// //End of effects stack -// //Make last stage to draw to initial resultDrawStage target -// prevDrawStage->target = resultDrawStage->target; -// //Replace all data in target drawStage with new data -// *resultDrawStage = *prevDrawStage; -// } -// -// -// -//} -// -//HDrawStage Map::doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const { -// if (quadBindings == nullptr) -// return nullptr; -// -// ///2 Rounds of ffxgauss4 (Horizontal and Vertical blur) -// ///With two frameBuffers -// ///Size for buffers : is 4 times less than current canvas -// int targetWidth = parentDrawStage->viewPortDimensions.maxs[0] >> 2; -// int targetHeight = parentDrawStage->viewPortDimensions.maxs[1] >> 2; -// -// auto frameB1 = m_api->hDevice->createFrameBuffer( -// targetWidth, -// targetHeight, -// {ITextureFormat::itRGBA}, -// ITextureFormat::itDepth32, -// 1, -// 2 -// ); -// auto frameB2 = m_api->hDevice->createFrameBuffer( -// targetWidth, -// targetHeight, -// {ITextureFormat::itRGBA}, -// ITextureFormat::itDepth32, -// 1, -// 2 -// ); -// -// auto vertexChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); -// uniformBufferChunks.push_back(vertexChunk); -// vertexChunk->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { -// auto &meshblockVS = self->getObject(); -// meshblockVS.x = 1; -// meshblockVS.y = 1; -// meshblockVS.z = 0; -// meshblockVS.w = 0; -// }); -// -// -// auto ffxGaussFrag = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); -// uniformBufferChunks.push_back(ffxGaussFrag); -// ffxGaussFrag->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { -// auto &meshblockVS = self->getObject(); -// static const float s_texOffsetX[4] = {-1, 0, 0, -1}; -// static const float s_texOffsetY[4] = {2, 2, -1, -1};; -// -// for (int i = 0; i < 4; i++) { -// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; -// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; -// } -// }); -// -// -// auto ffxGaussFrag2 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); -// uniformBufferChunks.push_back(ffxGaussFrag2); -// ffxGaussFrag2->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { -// auto &meshblockVS = self->getObject(); -// static const float s_texOffsetX[4] = {-6, -1, 1, 6}; -// static const float s_texOffsetY[4] = {0, 0, 0, 0};; -// -// for (int i = 0; i < 4; i++) { -// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; -// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; -// } -// }); -// auto ffxGaussFrag3 = m_api->hDevice->createUniformBufferChunk(sizeof(FXGauss::meshWideBlockPS)); -// uniformBufferChunks.push_back(ffxGaussFrag3); -// ffxGaussFrag3->setUpdateHandler([](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { -// auto &meshblockVS = self->getObject(); -// static const float s_texOffsetX[4] = {0, 0, 0, 0}; -// static const float s_texOffsetY[4] = {10, 2, -2, -10};; -// -// for (int i = 0; i < 4; i++) { -// meshblockVS.texOffsetX[i] = s_texOffsetX[i]; -// meshblockVS.texOffsetY[i] = s_texOffsetY[i]; -// } -// }); -// HGUniformBufferChunk frags[3] = {ffxGaussFrag, ffxGaussFrag2, ffxGaussFrag3}; -// -// HDrawStage prevStage = parentDrawStage; -// for (int i = 0; i < 3; i++) { -// ///1. Create draw stage -// HDrawStage drawStage = std::make_shared(); -// -// drawStage->drawStageDependencies = {prevStage}; -// drawStage->matricesForRendering = nullptr; -// drawStage->setViewPort = true; -// drawStage->viewPortDimensions = {{0, 0}, -// {parentDrawStage->viewPortDimensions.maxs[0] >> 2, -// parentDrawStage->viewPortDimensions.maxs[1] >> 2}}; -// drawStage->clearScreen = false; -// drawStage->target = ((i & 1) > 0) ? frameB1 : frameB2; -// -// ///2. Create mesh -// auto shader = m_api->hDevice->getShader("fullScreen_ffxgauss4", nullptr); -// gMeshTemplate meshTemplate(quadBindings, shader); -// meshTemplate.meshType = MeshType::eGeneralMesh; -// meshTemplate.depthWrite = false; -// meshTemplate.depthCulling = false; -// meshTemplate.backFaceCulling = false; -// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; -// -// meshTemplate.texture.resize(1); -// meshTemplate.texture[0] = prevStage->target->getAttachment(0); -// -// meshTemplate.textureCount = 1; -// -// meshTemplate.ubo[0] = nullptr; -// meshTemplate.ubo[1] = nullptr; -// meshTemplate.ubo[2] = vertexChunk; -// -// meshTemplate.ubo[3] = nullptr; -// meshTemplate.ubo[4] = frags[i]; -// -// meshTemplate.element = DrawElementMode::TRIANGLES; -// meshTemplate.start = 0; -// meshTemplate.end = 6; -// -// //Make mesh -// HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); -// drawStage->opaqueMeshes = std::make_shared(); -// drawStage->opaqueMeshes->meshes.push_back(hmesh); -// -// ///3. Reassign previous frame -// prevStage = drawStage; -// } -// -// //And the final is ffxglow to screen -// { -// auto config = m_api->getConfig();; -// -// auto glow = parentDrawStage->frameDepedantData->currentGlow; -// auto ffxGlowfragmentChunk = m_api->hDevice->createUniformBufferChunk(sizeof(mathfu::vec4_packed)); -// uniformBufferChunks.push_back(ffxGlowfragmentChunk); -// ffxGlowfragmentChunk->setUpdateHandler([glow, config](IUniformBufferChunk *self, const HFrameDependantData &frameDepedantData) -> void { -// auto &meshblockVS = self->getObject(); -// meshblockVS.x = 1; -// meshblockVS.y = 1; -// meshblockVS.z = 0; //mix_coeficient -// meshblockVS.w = glow; //glow multiplier -// }); -// -// auto shader = m_api->hDevice->getShader("ffxGlowQuad", nullptr); -// gMeshTemplate meshTemplate(quadBindings, shader); -// meshTemplate.meshType = MeshType::eGeneralMesh; -// meshTemplate.depthWrite = false; -// meshTemplate.depthCulling = false; -// meshTemplate.backFaceCulling = false; -// meshTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; -// -// meshTemplate.texture.resize(2); -// meshTemplate.texture[0] = parentDrawStage->target->getAttachment(0); -// meshTemplate.texture[1] = prevStage->target->getAttachment(0); -// -// meshTemplate.textureCount = 2; -// -// -// meshTemplate.ubo[0] = nullptr; -// meshTemplate.ubo[1] = nullptr; -// meshTemplate.ubo[2] = vertexChunk; -// -// meshTemplate.ubo[3] = nullptr; -// meshTemplate.ubo[4] = ffxGlowfragmentChunk; -// -// meshTemplate.element = DrawElementMode::TRIANGLES; -// meshTemplate.start = 0; -// meshTemplate.end = 6; -// -// //Make mesh -// HGMesh hmesh = m_api->hDevice->createMesh(meshTemplate); -// -// auto resultDrawStage = std::make_shared(); -// *resultDrawStage = *parentDrawStage; -// resultDrawStage->sceneWideBlockVSPSChunk = nullptr; //Since it's not used but this shader and it's important for vulkan -// resultDrawStage->drawStageDependencies = {prevStage}; -// resultDrawStage->transparentMeshes = nullptr; -// resultDrawStage->opaqueMeshes = std::make_shared(); -// resultDrawStage->opaqueMeshes->meshes.push_back(hmesh); -// resultDrawStage->target = nullptr; -// -// return resultDrawStage; -// } -//} void Map::loadZoneLights() { if (m_api->databaseHandler != nullptr) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a4f401899..3502e6e9c 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1461,7 +1461,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,48}, + {0,4,32}, {0,0,368}, }, { @@ -2093,7 +2093,6 @@ const std::unordered_map mutate(int newSize) = 0; virtual size_t getSize() = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index d3befd979..fa6a9e2c7 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -171,7 +171,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ - enableValidationLayers = false; + enableValidationLayers = true; m_textureManager->initialize(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 2cfedf533..64c50bcf8 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -109,6 +109,10 @@ void GBufferVLK::subUploadData(void *data, int offset, int length) { memcpy((uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset, data, length); } +std::shared_ptr GBufferVLK::mutate(int newSize) { + resize(newSize); + return shared_from_this(); +} void GBufferVLK::resize(int newLength) { m_bufferSize = newLength; @@ -211,7 +215,7 @@ GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, m_alloc = alloc; m_offset = offset; m_size = size; - m_fakeSize = fakeSize; + m_fakeSize = fakeSize > 0 ? fakeSize : m_size; m_dataPointer = dataPointer; } @@ -254,3 +258,6 @@ void GBufferVLK::GSubBufferVLK::save(int length) { size_t GBufferVLK::GSubBufferVLK::getSize() { return m_fakeSize; } +std::shared_ptr GBufferVLK::GSubBufferVLK::mutate(int newSize) { + return m_parentBuffer->getSubBuffer(newSize); +}; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index e4412f46d..093d9bb46 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -50,6 +50,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this(dataToBeUploaded, dataToBeUploadedMtx, true); } + std::shared_ptr mutate(int newSize) override; void resize(int newLength); private: HGDeviceVLK m_device; @@ -86,6 +87,8 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this mutate(int newSize) override; + VkBuffer getGPUBuffer() override { return m_parentBuffer->getGPUBuffer(); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 92c9e0215..ad7553bca 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -205,7 +205,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM auto l_fragmentData = std::make_shared>(uboBuffer); ; auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) From f8e5b9f38ecb5beb92eb8cdc705c2879fd2dce6b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 21 Mar 2023 17:49:14 +0200 Subject: [PATCH 053/212] particles work --- .../managers/particles/particleEmitter.cpp | 34 +++++++++---------- .../managers/particles/particleEmitter.h | 4 +-- .../vulkan/MapSceneRenderForwardVLK.cpp | 3 ++ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index ed2dbef31..5f42dffe6 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -209,7 +209,7 @@ ParticleEmitter::ParticleEmitter(const HApiContainer &api, const HMapSceneBuffer } selectShaderId(); - createMesh(sceneRenderer); + createMeshes(sceneRenderer); } void ParticleEmitter::selectShaderId() { @@ -257,7 +257,7 @@ static const std::array ParticleBlendingModeToEGxBlendEnum = EGxBlendEnum::GxBlend_BlendAdd }; -void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { +void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; m_sceneRenderer = sceneRenderer; @@ -316,25 +316,21 @@ void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer) { //Create Buffers for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { - - makeVAOForFrame(m_sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); - - frame[i].m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(10 * sizeof(ParticleBuffStructQuad)); - frame[i].m_bindings = sceneRenderer->createM2ParticleVAO(frame[i].m_bufferVBO,m_indexVBO); - //Create mesh - gMeshTemplate meshTemplate(frame[i].m_bindings); - - meshTemplate.meshType = MeshType::eParticleMesh; - meshTemplate.start = 0; - meshTemplate.end = 0; - - frame[i].m_mesh = sceneRenderer->createSortableMesh(meshTemplate, m_material, m_data->old.textureTileRotation); + createMesh(m_sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); } } -void ParticleEmitter::makeVAOForFrame(const HMapSceneBufferCreate &sceneRenderer, particleFrame &currFrame, int size) { +void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer, particleFrame &currFrame, int size) { currFrame.m_bufferVBO = sceneRenderer->createM2ParticleVertexBuffer(size); currFrame.m_bindings = sceneRenderer->createM2ParticleVAO(currFrame.m_bufferVBO,m_indexVBO); + + gMeshTemplate meshTemplate(currFrame.m_bindings); + + meshTemplate.meshType = MeshType::eParticleMesh; + meshTemplate.start = 0; + meshTemplate.end = 0; + + currFrame.m_mesh = sceneRenderer->createSortableMesh(meshTemplate, m_material, m_data->old.textureTileRotation); } @@ -637,7 +633,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { } if (maxFutureSize > vboBufferDynamic->getSize()) { - makeVAOForFrame(m_sceneRenderer, frame[frameNum], maxFutureSize); + createMesh(m_sceneRenderer, frame[frameNum], maxFutureSize); vboBufferDynamic = frame[frameNum].m_bufferVBO; } @@ -904,6 +900,10 @@ int ParticleEmitter::CalculateParticlePreRenderData(CParticle2 &p, ParticlePreRe return 0; } + if (p.age > getGenerator()->GetMaxLifeSpan()) { + return 0; + } + //fillTimedParticleData fillTimedParticleData(p, particlePreRenderData, seed); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 18f632224..d95febeed 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -198,12 +198,12 @@ class ParticleEmitter { std::shared_ptr m_material = nullptr; std::array frame; - void createMesh(const HMapSceneBufferCreate &sceneRenderer); + void createMeshes(const HMapSceneBufferCreate &sceneRenderer); static HGIndexBuffer m_indexVBO; void GetSpin(CParticle2 &p, float &baseSpin, float &deltaSpin) const; - void makeVAOForFrame(const HMapSceneBufferCreate &sceneRenderer, particleFrame &frame, int size); + void createMesh(const HMapSceneBufferCreate &sceneRenderer, particleFrame &frame, int size); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index ad7553bca..e456eefd0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -245,6 +245,8 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria } inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh) { + if (mesh == nullptr) return; + const auto &meshVlk = std::dynamic_pointer_cast(mesh); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); @@ -329,6 +331,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); From d55cbe93c34dd32347f91e68dfda294bc3ef4a4a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 23 Mar 2023 23:12:24 +0200 Subject: [PATCH 054/212] creation of WMO materials --- .../glsl/forwardRendering/wmoShader.frag | 10 +- .../glsl/forwardRendering/wmoShader.vert | 4 + .../src/engine/geometry/wmoGroupGeom.cpp | 4 +- .../src/engine/geometry/wmoGroupGeom.h | 2 +- wowViewerLib/src/engine/objects/iWmoApi.h | 284 ++++++++++++ .../src/engine/objects/scenes/map.cpp | 11 +- wowViewerLib/src/engine/objects/scenes/map.h | 1 + .../src/engine/objects/wmo/wmoGroupObject.cpp | 433 +----------------- .../src/engine/objects/wmo/wmoGroupObject.h | 2 - .../src/engine/objects/wmo/wmoObject.cpp | 137 +++++- .../src/engine/objects/wmo/wmoObject.h | 34 +- .../src/engine/shader/ShaderDefinitions.h | 12 +- .../src/gapi/UniformBufferStructures.h | 4 - .../gapi/interface/IVertexBufferBindings.h | 2 +- .../gapi/vulkan/GVertexBufferBindingsVLK.cpp | 8 +- .../gapi/vulkan/GVertexBufferBindingsVLK.h | 2 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 18 +- .../src/renderer/mapScene/MapSceneRenderer.h | 3 + .../mapScene/materials/IMaterialStructs.h | 14 + .../vulkan/MapSceneRenderForwardVLK.cpp | 54 ++- .../vulkan/MapSceneRenderForwardVLK.h | 20 +- 21 files changed, 577 insertions(+), 482 deletions(-) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index 9407bc6b6..342fff80e 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -22,17 +22,13 @@ layout(location=5) in vec4 vColor2; layout(location=6) in vec4 vColorSecond; layout(location=7) in vec4 vPosition; layout(location=8) in vec3 vNormal; +layout(location=9) in vec4 vWmoAmbient; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, set=0, binding=3) uniform modelWideBlockPS { - InteriorLightParam intLight; - -}; - layout(std140, set=0, binding=4) uniform meshWideBlockPS { ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; vec4 FogColor_AlphaTest; @@ -72,6 +68,10 @@ void main() { if (doDiscard) discard; + InteriorLightParam intLight; + intLight.uInteriorAmbientColorAndApplyInteriorLight = vWmoAmbient; + intLight.uInteriorDirectColorAndApplyExteriorLight = vec4(0, 0, 0, 1.0f); + vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); finalColor = vec4( calcLight( diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index b34310236..ea2515442 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -20,6 +20,7 @@ layout (location = 5) in vec2 aTexCoord4; layout (location = 6) in vec4 aColor; layout (location = 7) in vec4 aColor2; layout (location = 8) in vec4 aColorSecond; +layout (location = 9) in vec4 wmoAmbient; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; @@ -42,6 +43,7 @@ layout(location=5) out vec4 vColor2; layout(location=6) out vec4 vColorSecond; layout(location=7) out vec4 vPosition; layout(location=8) out vec3 vNormal; +layout(location=9) out vec4 vWmoAmbient; void main() { @@ -64,4 +66,6 @@ void main() { int uVertexShader = VertexShader_UseLitColor.x; calcWMOVertMat(uVertexShader, vPosition.xyz, vNormal, aTexCoord, aTexCoord2, aTexCoord3, vTexCoord, vTexCoord2, vTexCoord3); + + vWmoAmbient = wmoAmbient; } diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 0d92d67ab..34335adfa 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -384,10 +384,10 @@ HGIndexBuffer WmoGroupGeom::getIBO(const HMapSceneBufferCreate &sceneRenderer) { return indexVBO; } -HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { +HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient) { if (vertexBufferBindings == nullptr) { - vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer)); + vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer), localAmbient); } return vertexBufferBindings; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index b75e56d79..d4ec6c2be 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -26,7 +26,7 @@ class WmoGroupGeom : public PersistentFile { bool hasWater() const {return m_mliq != nullptr; }; - HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer); + HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient); HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer); int getFileDataId() const {return m_fileDataId;} diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index bcd2be59b..236bf5598 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -22,12 +22,296 @@ struct WmoGroupResult { int nodeId; }; +/* +//0 +MapObjDiffuse { + VertexShader(MapObjDiffuse_T1); + PixelShader(MapObjDiffuse); +} + +//1 +MapObjSpecular { + VertexShader(MapObjSpecular_T1); + PixelShader(MapObjSpecular); +} + +//2 +MapObjMetal { + VertexShader(MapObjSpecular_T1); + PixelShader(MapObjMetal); +} + +//3 +MapObjEnv { + VertexShader(MapObjDiffuse_T1_Refl); + PixelShader(MapObjEnv); +} + +//4 +MapObjOpaque { + VertexShader(MapObjDiffuse_T1); + PixelShader(MapObjOpaque); +} + +//5 +Effect(MapObjEnvMetal { + VertexShader(MapObjDiffuse_T1_Refl); + PixelShader(MapObjEnvMetal); +} + +//6 +Effect(MapObjComposite) //aka MapObjTwoLayerDiffuse +{ + VertexShader(MapObjDiffuse_Comp); + PixelShader(MapObjComposite); //aka MapObjTwoLayerDiffuse +} + +//7 +Effect(MapObjTwoLayerEnvMetal) +{ + VertexShader(MapObjDiffuse_Comp_Refl); + PixelShader(MapObjTwoLayerEnvMetal); +} + +//8 +Effect(TwoLayerTerrain) +{ + VertexShader(MapObjDiffuse_Comp_Terrain); + PixelShader(MapObjTwoLayerTerrain); +} + +//9 +Effect(MapObjDiffuseEmissive) +{ + VertexShader(MapObjDiffuse_Comp); + PixelShader(MapObjDiffuseEmissive); +} + +//10 +Effect(waterWindow) +{ +e //unk +} + +//11 +Effect(MapObjMaskedEnvMetal) +{ + VertexShader(MapObjDiffuse_T1_Env_T2); + PixelShader(MapObjMaskedEnvMetal); +} + +//12 +Effect(MapObjEnvMetalEmissive) +{ + VertexShader(MapObjDiffuse_T1_Env_T2); + PixelShader(MapObjEnvMetalEmissive); +} + +//13 +Effect(TwoLayerDiffuseOpaque) +{ + VertexShader(MapObjDiffuse_Comp); + PixelShader(MapObjTwoLayerDiffuseOpaque); +} + +//14 +Effect(submarineWindow) +{ + //unk +} + +//15 +Effect(TwoLayerDiffuseEmissive) +{ + VertexShader(MapObjDiffuse_Comp); + PixelShader(MapObjTwoLayerDiffuseEmissive); +} + +//16 +Effect(MapObjDiffuseTerrain) +{ + VertexShader(MapObjDiffuse_T1); + PixelShader(MapObjDiffuse); +} + +*/ + +enum class WmoVertexShader : int { + None = -1, + MapObjDiffuse_T1 = 0, + MapObjDiffuse_T1_Refl = 1, + MapObjDiffuse_T1_Env_T2 = 2, + MapObjSpecular_T1 = 3, + MapObjDiffuse_Comp = 4, + MapObjDiffuse_Comp_Refl = 5, + MapObjDiffuse_Comp_Terrain = 6, + MapObjDiffuse_CompAlpha = 7, + MapObjParallax = 8, + +}; + +enum class WmoPixelShader : int { + None = -1, + MapObjDiffuse = 0, + MapObjSpecular = 1, + MapObjMetal = 2, + MapObjEnv = 3, + MapObjOpaque = 4, + MapObjEnvMetal = 5, + MapObjTwoLayerDiffuse = 6, //MapObjComposite + MapObjTwoLayerEnvMetal = 7, + MapObjTwoLayerTerrain = 8, + MapObjDiffuseEmissive = 9, + MapObjMaskedEnvMetal = 10, + MapObjEnvMetalEmissive = 11, + MapObjTwoLayerDiffuseOpaque = 12, + MapObjTwoLayerDiffuseEmissive = 13, + MapObjAdditiveMaskedEnvMetal = 14, + MapObjTwoLayerDiffuseMod2x = 15, + MapObjTwoLayerDiffuseMod2xNA = 16, + MapObjTwoLayerDiffuseAlpha = 17, + MapObjLod = 18, + MapObjParallax = 19, + MapObjDFShader = 20 +}; + +inline constexpr const int operator+(WmoPixelShader const val) { return static_cast(val); }; + +inline constexpr const int operator+(WmoVertexShader const val) { return static_cast(val); }; + +const int MAX_WMO_SHADERS = 24; +static const struct { + int vertexShader; + int pixelShader; +} wmoMaterialShader[MAX_WMO_SHADERS] = { + //MapObjDiffuse = 0 + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjDiffuse, + }, + //MapObjSpecular = 1 + { + +WmoVertexShader::MapObjSpecular_T1, + +WmoPixelShader::MapObjSpecular, + }, + //MapObjMetal = 2 + { + +WmoVertexShader::MapObjSpecular_T1, + +WmoPixelShader::MapObjMetal, + }, + //MapObjEnv = 3 + { + +WmoVertexShader::MapObjDiffuse_T1_Refl, + +WmoPixelShader::MapObjEnv, + }, + //MapObjOpaque = 4 + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjOpaque, + }, + //MapObjEnvMetal = 5 + { + +WmoVertexShader::MapObjDiffuse_T1_Refl, + +WmoPixelShader::MapObjEnvMetal, + }, + //MapObjTwoLayerDiffuse = 6 + { + +WmoVertexShader::MapObjDiffuse_Comp, + +WmoPixelShader::MapObjTwoLayerDiffuse, + }, + //MapObjTwoLayerEnvMetal = 7 + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjTwoLayerEnvMetal, + }, + //TwoLayerTerrain = 8 + { + +WmoVertexShader::MapObjDiffuse_Comp_Terrain, + +WmoPixelShader::MapObjTwoLayerTerrain, + }, + //MapObjDiffuseEmissive = 9 + { + +WmoVertexShader::MapObjDiffuse_Comp, + +WmoPixelShader::MapObjDiffuseEmissive, + }, + //waterWindow = 10 + { + +WmoVertexShader::None, + +WmoPixelShader::None, + }, + //MapObjMaskedEnvMetal = 11 + { + +WmoVertexShader::MapObjDiffuse_T1_Env_T2, + +WmoPixelShader::MapObjMaskedEnvMetal, + }, + //MapObjEnvMetalEmissive = 12 + { + +WmoVertexShader::MapObjDiffuse_T1_Env_T2, + +WmoPixelShader::MapObjEnvMetalEmissive, + }, + //TwoLayerDiffuseOpaque = 13 + { + +WmoVertexShader::MapObjDiffuse_Comp, + +WmoPixelShader::MapObjTwoLayerDiffuseOpaque, + }, + //submarineWindow = 14 + { + +WmoVertexShader::None, + +WmoPixelShader::None, + }, + //TwoLayerDiffuseEmissive = 15 + { + +WmoVertexShader::MapObjDiffuse_Comp, + +WmoPixelShader::MapObjTwoLayerDiffuseEmissive, + }, + //MapObjDiffuseTerrain = 16 + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjDiffuse, + }, + //17 + { + +WmoVertexShader::MapObjDiffuse_T1_Env_T2, + +WmoPixelShader::MapObjAdditiveMaskedEnvMetal, + }, + //18 + { + +WmoVertexShader::MapObjDiffuse_CompAlpha, + +WmoPixelShader::MapObjTwoLayerDiffuseMod2x, + }, + //19 + { + +WmoVertexShader::MapObjDiffuse_Comp, + +WmoPixelShader::MapObjTwoLayerDiffuseMod2xNA, + }, + //20 + { + +WmoVertexShader::MapObjDiffuse_CompAlpha, + +WmoPixelShader::MapObjTwoLayerDiffuseAlpha, + }, + //21 + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjLod, + }, + //22 + { + +WmoVertexShader::MapObjParallax, + +WmoPixelShader::MapObjParallax, + }, + { + +WmoVertexShader::MapObjDiffuse_T1, + +WmoPixelShader::MapObjDFShader, + }, +}; + class IWmoApi { public: virtual std::shared_ptr getDoodad(int index) = 0; virtual SMOHeader *getWmoHeader() = 0; virtual mathfu::vec3 getAmbientColor() = 0; virtual PointerChecker &getMaterials() = 0; + virtual std::shared_ptr getMaterialInstance(int index) = 0; virtual bool isLoaded() = 0; virtual std::function getAttenFunction() = 0; virtual PointerChecker &getLightArray() = 0; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index d97053d23..a07e0fe70 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -455,7 +455,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams m_viewRenderOrder, true, mapRenderPlan->viewsHolder)) { - mapRenderPlan->wmoArray.addCand(mapRenderPlan->m_currentWMO); + mapRenderPlan->wmoArray.addToDrawn(mapRenderPlan->m_currentWMO); } cullExterior.beginMeasurement(); @@ -1081,6 +1081,8 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, viewRenderOrder, false, mapRenderPlan->viewsHolder)) { + + mapRenderPlan->wmoArray.addToDrawn(wmoCandidate); } } cullExterioFrustumWMO.endMeasurement(); @@ -1397,6 +1399,13 @@ void Map::update(const HMapRenderPlan &renderPlan) { m2UpdateframeCounter.endMeasurement(); } + wmoUpdate.beginMeasurement(); + for (const auto &wmoObject : renderPlan->wmoArray.getToDrawn()) { + if (wmoObject == nullptr) continue; + wmoObject->update(); + } + wmoUpdate.endMeasurement(); + wmoGroupUpdate.beginMeasurement(); for (const auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { if (wmoGroupObject == nullptr) continue; diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 26870ec3a..3244530cb 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -42,6 +42,7 @@ class Map : public IScene, public IMapApi { FrameCounter m2UpdateframeCounter; FrameCounter m2calcDistanceCounter; FrameCounter adtCleanupCounter; + FrameCounter wmoUpdate; FrameCounter wmoGroupUpdate; FrameCounter adtUpdate; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index b80f46ba3..7a1583110 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -10,289 +10,8 @@ #include "../../../gapi/interface/materials/IMaterial.h" #include -/* -//0 -MapObjDiffuse { - VertexShader(MapObjDiffuse_T1); - PixelShader(MapObjDiffuse); -} - -//1 -MapObjSpecular { - VertexShader(MapObjSpecular_T1); - PixelShader(MapObjSpecular); -} - -//2 -MapObjMetal { - VertexShader(MapObjSpecular_T1); - PixelShader(MapObjMetal); -} - -//3 -MapObjEnv { - VertexShader(MapObjDiffuse_T1_Refl); - PixelShader(MapObjEnv); -} - -//4 -MapObjOpaque { - VertexShader(MapObjDiffuse_T1); - PixelShader(MapObjOpaque); -} - -//5 -Effect(MapObjEnvMetal { - VertexShader(MapObjDiffuse_T1_Refl); - PixelShader(MapObjEnvMetal); -} - -//6 -Effect(MapObjComposite) //aka MapObjTwoLayerDiffuse -{ - VertexShader(MapObjDiffuse_Comp); - PixelShader(MapObjComposite); //aka MapObjTwoLayerDiffuse -} - -//7 -Effect(MapObjTwoLayerEnvMetal) -{ - VertexShader(MapObjDiffuse_Comp_Refl); - PixelShader(MapObjTwoLayerEnvMetal); -} - -//8 -Effect(TwoLayerTerrain) -{ - VertexShader(MapObjDiffuse_Comp_Terrain); - PixelShader(MapObjTwoLayerTerrain); -} - -//9 -Effect(MapObjDiffuseEmissive) -{ - VertexShader(MapObjDiffuse_Comp); - PixelShader(MapObjDiffuseEmissive); -} -//10 -Effect(waterWindow) -{ -e //unk -} - -//11 -Effect(MapObjMaskedEnvMetal) -{ - VertexShader(MapObjDiffuse_T1_Env_T2); - PixelShader(MapObjMaskedEnvMetal); -} - -//12 -Effect(MapObjEnvMetalEmissive) -{ - VertexShader(MapObjDiffuse_T1_Env_T2); - PixelShader(MapObjEnvMetalEmissive); -} - -//13 -Effect(TwoLayerDiffuseOpaque) -{ - VertexShader(MapObjDiffuse_Comp); - PixelShader(MapObjTwoLayerDiffuseOpaque); -} -//14 -Effect(submarineWindow) -{ - //unk -} - -//15 -Effect(TwoLayerDiffuseEmissive) -{ - VertexShader(MapObjDiffuse_Comp); - PixelShader(MapObjTwoLayerDiffuseEmissive); -} - -//16 -Effect(MapObjDiffuseTerrain) -{ - VertexShader(MapObjDiffuse_T1); - PixelShader(MapObjDiffuse); -} - -*/ - -enum class WmoVertexShader : int { - None = -1, - MapObjDiffuse_T1 = 0, - MapObjDiffuse_T1_Refl = 1, - MapObjDiffuse_T1_Env_T2 = 2, - MapObjSpecular_T1 = 3, - MapObjDiffuse_Comp = 4, - MapObjDiffuse_Comp_Refl = 5, - MapObjDiffuse_Comp_Terrain = 6, - MapObjDiffuse_CompAlpha = 7, - MapObjParallax = 8, - -}; - -enum class WmoPixelShader : int { - None = -1, - MapObjDiffuse = 0, - MapObjSpecular = 1, - MapObjMetal = 2, - MapObjEnv = 3, - MapObjOpaque = 4, - MapObjEnvMetal = 5, - MapObjTwoLayerDiffuse = 6, //MapObjComposite - MapObjTwoLayerEnvMetal = 7, - MapObjTwoLayerTerrain = 8, - MapObjDiffuseEmissive = 9, - MapObjMaskedEnvMetal = 10, - MapObjEnvMetalEmissive = 11, - MapObjTwoLayerDiffuseOpaque = 12, - MapObjTwoLayerDiffuseEmissive = 13, - MapObjAdditiveMaskedEnvMetal = 14, - MapObjTwoLayerDiffuseMod2x = 15, - MapObjTwoLayerDiffuseMod2xNA = 16, - MapObjTwoLayerDiffuseAlpha = 17, - MapObjLod = 18, - MapObjParallax = 19, - MapObjUnkShader = 20 -}; - -inline constexpr const int operator+(WmoPixelShader const val) { return static_cast(val); }; - -inline constexpr const int operator+(WmoVertexShader const val) { return static_cast(val); }; - -const int MAX_WMO_SHADERS = 24; -static const struct { - int vertexShader; - int pixelShader; -} wmoMaterialShader[MAX_WMO_SHADERS] = { - //MapObjDiffuse = 0 - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjDiffuse, - }, - //MapObjSpecular = 1 - { - +WmoVertexShader::MapObjSpecular_T1, - +WmoPixelShader::MapObjSpecular, - }, - //MapObjMetal = 2 - { - +WmoVertexShader::MapObjSpecular_T1, - +WmoPixelShader::MapObjMetal, - }, - //MapObjEnv = 3 - { - +WmoVertexShader::MapObjDiffuse_T1_Refl, - +WmoPixelShader::MapObjEnv, - }, - //MapObjOpaque = 4 - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjOpaque, - }, - //MapObjEnvMetal = 5 - { - +WmoVertexShader::MapObjDiffuse_T1_Refl, - +WmoPixelShader::MapObjEnvMetal, - }, - //MapObjTwoLayerDiffuse = 6 - { - +WmoVertexShader::MapObjDiffuse_Comp, - +WmoPixelShader::MapObjTwoLayerDiffuse, - }, - //MapObjTwoLayerEnvMetal = 7 - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjTwoLayerEnvMetal, - }, - //TwoLayerTerrain = 8 - { - +WmoVertexShader::MapObjDiffuse_Comp_Terrain, - +WmoPixelShader::MapObjTwoLayerTerrain, - }, - //MapObjDiffuseEmissive = 9 - { - +WmoVertexShader::MapObjDiffuse_Comp, - +WmoPixelShader::MapObjDiffuseEmissive, - }, - //waterWindow = 10 - { - +WmoVertexShader::None, - +WmoPixelShader::None, - }, - //MapObjMaskedEnvMetal = 11 - { - +WmoVertexShader::MapObjDiffuse_T1_Env_T2, - +WmoPixelShader::MapObjMaskedEnvMetal, - }, - //MapObjEnvMetalEmissive = 12 - { - +WmoVertexShader::MapObjDiffuse_T1_Env_T2, - +WmoPixelShader::MapObjEnvMetalEmissive, - }, - //TwoLayerDiffuseOpaque = 13 - { - +WmoVertexShader::MapObjDiffuse_Comp, - +WmoPixelShader::MapObjTwoLayerDiffuseOpaque, - }, - //submarineWindow = 14 - { - +WmoVertexShader::None, - +WmoPixelShader::None, - }, - //TwoLayerDiffuseEmissive = 15 - { - +WmoVertexShader::MapObjDiffuse_Comp, - +WmoPixelShader::MapObjTwoLayerDiffuseEmissive, - }, - //MapObjDiffuseTerrain = 16 - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjDiffuse, - }, - //17 - { - +WmoVertexShader::MapObjDiffuse_T1_Env_T2, - +WmoPixelShader::MapObjAdditiveMaskedEnvMetal, - }, - //18 - { - +WmoVertexShader::MapObjDiffuse_CompAlpha, - +WmoPixelShader::MapObjTwoLayerDiffuseMod2x, - }, - //19 - { - +WmoVertexShader::MapObjDiffuse_Comp, - +WmoPixelShader::MapObjTwoLayerDiffuseMod2xNA, - }, - //20 - { - +WmoVertexShader::MapObjDiffuse_CompAlpha, - +WmoPixelShader::MapObjTwoLayerDiffuseAlpha, - }, - //21 - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjLod, - }, - //22 - { - +WmoVertexShader::MapObjParallax, - +WmoPixelShader::MapObjParallax, - }, - //23 // TODO: stub for now - { - +WmoVertexShader::MapObjDiffuse_T1, - +WmoPixelShader::MapObjUnkShader, - }, -}; bool WmoGroupObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { @@ -403,174 +122,44 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { int minBatch = config->wmoMinBatch; int maxBatch = std::min(config->wmoMaxBatch, m_geom->batchesLen); - //In Taanant Jungle in Draenor some WMO has no indicies and crash :D + //In Taanant Jungle in Draenor some WMO have no indicies and crash :D if (m_geom->indicesLen == 0) { return; } - PointerChecker &materials = m_wmoApi->getMaterials(); - HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer); - -// vertexModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockVS)); - vertexModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ - WMO::modelWideBlockVS &blockVS = data; - blockVS.uPlacementMat = *m_modelMatrix; - }); - -//TODO: - -// fragmentModelWideUniformBuffer = device->createUniformBufferChunk(sizeof(WMO::modelWideBlockPS)); - fragmentModelWideUniformBuffer->setUpdateHandler([this](auto &data, const HFrameDependantData &frameDepedantData){ - WMO::modelWideBlockPS &blockPS = data; - blockPS.intLight.uInteriorAmbientColorAndApplyInteriorLight = - mathfu::vec4_packed( - mathfu::vec4( - this->getAmbientColor().xyz(), - ((this->m_geom->mogp->flags.INTERIOR > 0) && (!this->m_geom->mogp->flags.EXTERIOR_LIT)) ? 1.0f : 0.0f - ) - ); - blockPS.intLight.uInteriorDirectColorAndApplyExteriorLight = - mathfu::vec4_packed( - mathfu::vec4( - 0, 0, 0, 1.0f - ) - ); - }); + HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer, mathfu::vec4( + this->getAmbientColor().xyz(), + ((this->m_geom->mogp->flags.INTERIOR > 0) && (!this->m_geom->mogp->flags.EXTERIOR_LIT)) ? 1.0f : 0.0f + )); MOGP *mogp = m_geom->mogp; for (int j = minBatch; j < maxBatch; j++) { SMOBatch &renderBatch = m_geom->batches[j]; - int texIndex; + int materialIndex; if (renderBatch.flag_use_material_id_large) { - texIndex = renderBatch.postLegion.material_id_large; + materialIndex = renderBatch.postLegion.material_id_large; } else { - texIndex = renderBatch.material_id; - } - - const SMOMaterial &material = materials[texIndex]; - assert(material.shader < MAX_WMO_SHADERS && material.shader >= 0); - auto shaderId = material.shader; - if (shaderId >= MAX_WMO_SHADERS) { - shaderId = 0; + materialIndex = renderBatch.material_id; } -// if (shaderId == 23) { -// std::cout << "Hello" << std::endl; -// } - int pixelShader = wmoMaterialShader[shaderId].pixelShader; - int vertexShader = wmoMaterialShader[shaderId].vertexShader; - - WMOShaderCacheRecord cacheRecord{}; - cacheRecord.vertexShader = vertexShader; - cacheRecord.pixelShader = pixelShader; - cacheRecord.unlit = true; - cacheRecord.alphaTestOn = true; - cacheRecord.unFogged = true; - cacheRecord.unShadowed = true; - HGShaderPermutation shaderPermutation = device->getShader("wmoShader", "wmoShader", &cacheRecord); + auto materialInstance = m_wmoApi->getMaterialInstance(materialIndex); gMeshTemplate meshTemplate(binding); bool isBatchA = (j >= 0 && j < (m_geom->mogp->transBatchCount)); bool isBatchC = (j >= (mogp->transBatchCount + mogp->intBatchCount)); - auto blendMode = material.blendMode; meshTemplate.meshType = MeshType::eWmoMesh; - - PipelineTemplate pipelineTemplate; - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.depthWrite = blendMode <= 1; - pipelineTemplate.depthCulling = true; - pipelineTemplate.backFaceCulling = !(material.flags.F_UNCULLED); - - pipelineTemplate.blendMode = static_cast(blendMode); - meshTemplate.start = renderBatch.first_index * 2; meshTemplate.end = renderBatch.num_indices; - bool isSecondTextSpec = material.shader == 8; - - HGTexture texture1 = m_wmoApi->getTexture(material.diffuseNameIndex, false); - HGTexture texture2 = m_wmoApi->getTexture(material.envNameIndex, isSecondTextSpec); - HGTexture texture3 = m_wmoApi->getTexture(material.texture_2, false); - - meshTemplate.texture = std::vector>(9, nullptr); - meshTemplate.texture[0] = texture1; - meshTemplate.texture[1] = texture2; - meshTemplate.texture[2] = texture3; - - if (pixelShader == (int)WmoPixelShader::MapObjParallax) { - meshTemplate.texture[3] = m_wmoApi->getTexture(material.color_2, false); - meshTemplate.texture[4] = m_wmoApi->getTexture(material.flags_2, false); - meshTemplate.texture[5] = m_wmoApi->getTexture(material.runTimeData[0], false); - meshTemplate.texture.resize(6); - } else if (pixelShader == (int)WmoPixelShader::MapObjUnkShader) { - meshTemplate.texture[3] = m_wmoApi->getTexture(material.color_2, false); - meshTemplate.texture[4] = m_wmoApi->getTexture(material.flags_2, false); - meshTemplate.texture[5] = m_wmoApi->getTexture(material.runTimeData[0], false); - meshTemplate.texture[6] = m_wmoApi->getTexture(material.runTimeData[1], false); - meshTemplate.texture[7] = m_wmoApi->getTexture(material.runTimeData[2], false); - meshTemplate.texture[8] = m_wmoApi->getTexture(material.runTimeData[3], false); - } else { - meshTemplate.texture.resize(3); - } - - - std::shared_ptr> wmoMeshWideBlockVS = nullptr; - std::shared_ptr> wmoMeshWideBlockPS = nullptr; - -// -// meshTemplate.ubo[0] = nullptr; -// meshTemplate.ubo[1] = vertexModelWideUniformBuffer; -// meshTemplate.ubo[2] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockVS)); -// -// meshTemplate.ubo[3] = fragmentModelWideUniformBuffer; -// meshTemplate.ubo[4] = device->createUniformBufferChunk(sizeof(WMO::meshWideBlockPS)); - //Make mesh - HGMesh hmesh = device->createMesh(meshTemplate); + HGMesh hmesh = sceneRenderer->createMesh(meshTemplate, materialInstance); this->m_meshArray.push_back(hmesh); - - wmoMeshWideBlockVS->setUpdateHandler([this, &material, vertexShader](auto &data, const HFrameDependantData &frameDepedantData){ - WMO::meshWideBlockVS &blockVS = data; - blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; - blockVS.VertexShader = vertexShader; - }); - - wmoMeshWideBlockPS->setUpdateHandler([this, isBatchA, isBatchC, &material, blendMode, pixelShader](auto &data, const HFrameDependantData &frameDepedantData) { -// mathfu::vec4 globalAmbientColor = m_api->getGlobalAmbientColor(); - mathfu::vec4 localambientColor = this->getAmbientColor(); - mathfu::vec3 directLight = mathfu::vec3(0,0,0); - - mathfu::vec4 ambientColor = localambientColor; - //TODO: check ironforge entrance. There must be something wrong with it - if (isBatchC || isBatchA || (this->m_geom->mogp->flags.EXTERIOR > 0)) { -// ambientColor = globalAmbientColor; -// directLight = m_api->getGlobalSunColor().xyz(); - } - float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; - - auto &blockPS = data; -// blockPS.uFogStartAndFogEndAndIsBatchA = mathfu::vec4_packed( -// mathfu::vec4( -// m_api->getConfig()->getFogStart(), -// m_api->getConfig()->getFogEnd(), -// isBatchA ? 1.0 : 0.0, -// 0.0)); - - blockPS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; - blockPS.EnableAlpha = (blendMode > 0) ? 1 : 0; - blockPS.PixelShader = pixelShader; - blockPS.BlendMode = blendMode; - - blockPS.uFogColor_AlphaTest = mathfu::vec4_packed( - mathfu::vec4(0,0,0, alphaTest)); - }); } } @@ -629,6 +218,8 @@ void WmoGroupObject::setLiquidType() { } void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRenderer) { + //TODO: + return; HGDevice device = m_api->hDevice; HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 6d427e2d7..99bae9ace 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -78,8 +78,6 @@ class WmoGroupObject { mathfu::mat4 *m_modelMatrix = nullptr; int m_groupNumber; - std::shared_ptr> vertexModelWideUniformBuffer = nullptr; - std::shared_ptr> fragmentModelWideUniformBuffer = nullptr; std::vector m_meshArray = {}; std::vector m_sortableMeshArray = {}; std::vector m_waterMeshArray = {}; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 7e4c3dd41..f51c37673 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -308,10 +308,9 @@ void WmoObject::createWorldPortals() { //Calc CAAbox mathfu::vec3 min(99999,99999,99999), max(-99999,-99999,-99999); - for (int k = 0; k < portalVecs.size(); k++) { - - min = mathfu::vec3::Min(portalVecs[k], min); - max = mathfu::vec3::Max(portalVecs[k], max); + for (const auto & portalVec : portalVecs) { + min = mathfu::vec3::Min(portalVec, min); + max = mathfu::vec3::Max(portalVec, max); } CAaBox &aaBoxCopyTo = geometryPerPortal[j].aaBox; @@ -323,10 +322,12 @@ void WmoObject::createWorldPortals() { bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (mainGeom != nullptr && mainGeom->getStatus() == FileStatus::FSLoaded){ + m_sceneRenderer = sceneRenderer; this->createGroupObjects(); this->createWorldPortals(); this->createBB(mainGeom->header->bounding_box); - this->createM2Array(); + this->createMaterialCache(); + m_modelWideChunk = sceneRenderer->createWMOWideChunk(); if (mainGeom->skyBoxM2FileName != nullptr || mainGeom->skyboxM2FileId != 0) { skyBox = std::make_shared(m_api, true); @@ -357,6 +358,46 @@ bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { void WmoObject::update() { if (!m_loaded) return; + auto &modelWide = m_modelWideChunk->getObject(); + modelWide.uPlacementMat = m_placementMatrix; + m_modelWideChunk->save(); + + //Update Materials + for (int matIndex = 0; matIndex < m_materialCache.size(); matIndex++) { + auto materialInstance = m_materialCache[matIndex].lock(); + if (materialInstance == nullptr) continue; + + const SMOMaterial &material = getMaterials()[matIndex]; + assert(material.shader < MAX_WMO_SHADERS && material.shader >= 0); + auto shaderId = material.shader; + if (shaderId >= MAX_WMO_SHADERS) { + shaderId = 0; + } + int pixelShader = wmoMaterialShader[shaderId].pixelShader; + int vertexShader = wmoMaterialShader[shaderId].vertexShader; + auto blendMode = material.blendMode; + + float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; + + + //Update VS block + auto &blockVS = materialInstance->m_materialVS->getObject(); + blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; + blockVS.VertexShader = vertexShader; + materialInstance->m_materialVS->save(); + + //Update PS block + auto &blockPS = materialInstance->m_materialPS->getObject(); + blockPS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; + blockPS.EnableAlpha = (blendMode > 0) ? 1 : 0; + blockPS.PixelShader = pixelShader; + blockPS.BlendMode = blendMode; + blockPS.uFogColor_AlphaTest = mathfu::vec4_packed( + mathfu::vec4(0,0,0, alphaTest)); + materialInstance->m_materialPS->save(); + } + + for (int i= 0; i < groupObjects.size(); i++) { if(groupObjects[i] != nullptr) { groupObjects[i]->update(); @@ -386,20 +427,7 @@ void WmoObject::uploadGeneratorBuffers() { void WmoObject::collectMeshes(std::vector &renderedThisFrame){ if (!m_loaded) return; - -// for (int i= 0; i < groupObjects.size(); i++) { -// if(drawGroupWMO[i]) { -// if (groupObjects[i] != nullptr && lodGroupLevelWMO[i] == 0) { -// groupObjects[i]->collectMeshes(renderedThisFrame); -// } else if (groupObjectsLod1[i] != nullptr && lodGroupLevelWMO[i] == 1) { -// groupObjectsLod1[i]->collectMeshes(renderedThisFrame); -// } else if (groupObjectsLod2[i] != nullptr && lodGroupLevelWMO[i] == 2) { -// groupObjectsLod2[i]->collectMeshes(renderedThisFrame); -// } else if (groupObjects[i] != nullptr) { -// groupObjects[i]->collectMeshes(renderedThisFrame); -// } -// } -// } + //Draw debug portals/Lights here? } void WmoObject::drawDebugLights(){ @@ -735,7 +763,8 @@ CAaBox WmoObject::getAABB() { return this->m_bbox; } -void WmoObject::createM2Array() { +void WmoObject::createMaterialCache() { + m_materialCache = decltype(m_materialCache)(mainGeom->materialsLen); } void WmoObject::postWmoGroupObjectLoad(int groupId, int lod) { @@ -774,7 +803,7 @@ bool WmoObject::startTraversingWMOGroup( FrameViewsHolder &viewsHolder ) { if (!m_loaded) - return true; + return false; std::vector ivPerWMOGroup = std::vector(mainGeom->groupsLen); @@ -810,6 +839,8 @@ bool WmoObject::startTraversingWMOGroup( }; if (traversingFromInterior && m_api->getConfig()->usePortalCulling) { + traverseTempData.atLeastOneGroupIsDrawn = true; + std::shared_ptr nextGroupObject = groupObjects[groupId]; if (nextGroupObject->getIsLoaded() && nextGroupObject->getWmoGroupGeom()->mogp->flags2.isSplitGroupChild) { groupId = nextGroupObject->getWmoGroupGeom()->mogp->parentSplitOrFirstChildGroupIndex; @@ -862,7 +893,7 @@ bool WmoObject::startTraversingWMOGroup( } if (drawGroup) { exteriorView->wmoGroupArray.addToDraw(this->groupObjects[i]); - + traverseTempData.atLeastOneGroupIsDrawn = true; this->traverseGroupWmo( i, false, @@ -908,7 +939,7 @@ bool WmoObject::startTraversingWMOGroup( } //M2s will be collected later from separate function call - return true; + return traverseTempData.atLeastOneGroupIsDrawn; } void WmoObject::addSplitChildWMOsToView(InteriorView &interiorView, int groupId) { if (!groupObjects[groupId]->getIsLoaded()) @@ -1411,6 +1442,66 @@ PointerChecker &WmoObject::getMaterials() { return mainGeom->materials; } +std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) { + auto materialInstance = m_materialCache[materialIndex].lock(); + if (materialInstance != nullptr) return materialInstance; + + //Otherwise create goddamit material + + const SMOMaterial &material = getMaterials()[materialIndex]; + assert(material.shader < MAX_WMO_SHADERS && material.shader >= 0); + auto shaderId = material.shader; + if (shaderId >= MAX_WMO_SHADERS) { + shaderId = 0; + } +// if (shaderId == 23) { +// std::cout << "Hello" << std::endl; +// } + int pixelShader = wmoMaterialShader[shaderId].pixelShader; + int vertexShader = wmoMaterialShader[shaderId].vertexShader; + + auto blendMode = material.blendMode; + + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = blendMode <= 1; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = !(material.flags.F_UNCULLED); + + pipelineTemplate.blendMode = static_cast(blendMode); + + bool isSecondTextSpec = material.shader == 8; + + HGTexture texture1 = getTexture(material.diffuseNameIndex, false); + HGTexture texture2 = getTexture(material.envNameIndex, isSecondTextSpec); + HGTexture texture3 = getTexture(material.texture_2, false); + + WMOMaterialTemplate materialTemplate; + + materialTemplate.textures[0] = texture1; + materialTemplate.textures[1] = texture2; + materialTemplate.textures[2] = texture3; + + if (pixelShader == (int)WmoPixelShader::MapObjParallax) { + materialTemplate.textures[3] = getTexture(material.color_2, false); + materialTemplate.textures[4] = getTexture(material.flags_2, false); + materialTemplate.textures[5] = getTexture(material.runTimeData[0], false); + } else if (pixelShader == (int)WmoPixelShader::MapObjDFShader) { + materialTemplate.textures[3] = getTexture(material.color_2, false); + materialTemplate.textures[4] = getTexture(material.flags_2, false); + materialTemplate.textures[5] = getTexture(material.runTimeData[0], false); + materialTemplate.textures[6] = getTexture(material.runTimeData[1], false); + materialTemplate.textures[7] = getTexture(material.runTimeData[2], false); + materialTemplate.textures[8] = getTexture(material.runTimeData[3], false); + } + + auto wmoMaterialInstance = m_sceneRenderer->createWMOMaterial(m_modelWideChunk, + pipelineTemplate, materialTemplate); + m_materialCache[materialIndex] = wmoMaterialInstance; + + return wmoMaterialInstance; +}; + std::shared_ptr WmoObject::getSkyBoxForGroup(int groupNum) { if (!m_loaded) return nullptr; if (groupNum < 0 || groupNum >= this->groupObjects.size()) return nullptr; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 4a8fb7ab3..15e9ea8ec 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -40,11 +40,14 @@ class WmoObject : public IWmoApi { mathfu::vec4 &cameraLocal; mathfu::mat4 &transposeInverseModelMat; std::vector &transverseVisitedPortals; + + bool atLeastOneGroupIsDrawn = false; }; HApiContainer m_api; HWmoMainGeom mainGeom = nullptr; + HMapSceneBufferCreate m_sceneRenderer; bool m_loading = false; bool m_loaded = false; CAaBox m_bbox; @@ -75,6 +78,9 @@ class WmoObject : public IWmoApi { std::unordered_map diffuseTextures; std::unordered_map specularTextures; + std::shared_ptr> m_modelWideChunk; + std::vector> m_materialCache; + HGMesh transformedAntiPortals; void createPlacementMatrix(SMMapObjDef &mapObjDef); @@ -110,10 +116,11 @@ class WmoObject : public IWmoApi { virtual SMOHeader *getWmoHeader() override; mathfu::vec3 getAmbientColor() override; - virtual PointerChecker &getMaterials() override; + PointerChecker &getMaterials() override; + std::shared_ptr getMaterialInstance(int index) override; - virtual PointerChecker &getLightArray() override; - virtual std::vector &getPortalInfos() override { + PointerChecker &getLightArray() override; + std::vector &getPortalInfos() override { return geometryPerPortal; }; @@ -130,7 +137,7 @@ class WmoObject : public IWmoApi { void update(); void uploadGeneratorBuffers(); - void createM2Array(); + void createMaterialCache(); void updateBB() override ; CAaBox getAABB(); @@ -194,9 +201,11 @@ class WMOListContainer { private: std::vector> wmoCandidates; std::vector> wmoToLoad; + std::vector> wmoToDrawn; bool candCanHaveDuplicates = false; bool toLoadCanHaveDuplicates = false; + bool toDrawmCanHaveDuplicates = false; void inline removeDuplicates(std::vector> &array) { if (array.size() < 1000) { @@ -250,6 +259,23 @@ class WMOListContainer { return wmoToLoad; } + + void addToDrawn(const std::shared_ptr &toDrawn) { + if (!toDrawn->isLoaded()) { + wmoToDrawn.push_back(toDrawn); + toDrawmCanHaveDuplicates = true; + } + } + + const std::vector> &getToDrawn() { + if (this->toDrawmCanHaveDuplicates) { + removeDuplicates(wmoToDrawn); + toDrawmCanHaveDuplicates = false; + } + + return wmoToDrawn; + } + }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 3502e6e9c..b81b6e179 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -145,7 +145,7 @@ struct renderFrameBufferShader { struct wmoShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; @@ -265,6 +265,7 @@ const std::unordered_map> attributesPe { "aColor", 6}, { "aColor2", 7}, { "aColorSecond", 8}, + { "wmoAmbient", 9}, } }, { "imguiShader", @@ -331,11 +332,10 @@ const std::unordered_map shaderMetaInfo = { { {0,4,32}, {0,0,368}, - {0,3,32}, }, { { - {3,3,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2186,12 +2186,6 @@ const std::unordered_map &bindings) = 0; + virtual void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings, bool isInstanceInputRate = false) = 0; }; #endif //AWEBWOWVIEWERCPP_IVERTEXBUFFERBINDINGS_H diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp index 3ebe3e0f8..470b95740 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp @@ -67,8 +67,8 @@ void GVertexBufferBindingsVLK::setIndexBuffer(HGIndexBuffer indexBuffer) { m_indexBuffer = indexBuffer; } -void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) { - int bindingIdx = 0; +void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings, bool isInstanceInputRate) { + // for (auto &gVertexBinding : m_bindings) { uint32_t stride = 0; if (bindings[0].stride != 0) { @@ -77,10 +77,11 @@ void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vert stride = bindings[0].size * ((bindings[0].type == GBindingType::GFLOAT) ? 4 : 1); } + int bindingIdx = m_BufferBindingsVLK.size(); vkBufferFormatHolder bufferFormatHolder; bufferFormatHolder.bindingDescription.binding = bindingIdx; bufferFormatHolder.bindingDescription.stride = stride; - bufferFormatHolder.bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + bufferFormatHolder.bindingDescription.inputRate = !isInstanceInputRate ?VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE; for (auto &gBinding : bindings) { VkVertexInputAttributeDescription attributeDescription = {}; @@ -91,7 +92,6 @@ void GVertexBufferBindingsVLK::addVertexBufferBinding(const HGVertexBuffer &vert bufferFormatHolder.attributeDescription.push_back(attributeDescription); } - bindingIdx++; m_BufferBindingsVLK.push_back(bufferFormatHolder); m_vertexBuffers.push_back(vertexBuffer); diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h index eac793072..1e9163cf8 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.h @@ -35,7 +35,7 @@ class GVertexBufferBindingsVLK : public IVertexBufferBindings { void save() override; void setIndexBuffer(HGIndexBuffer indexBuffer) override; - void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings) override; + void addVertexBufferBinding(const HGVertexBuffer &vertexBuffer, const std::vector &bindings, bool isInstanceInputRate = false) override; std::vector &getVLKFormat(); diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index c072927ed..18518d193 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -37,7 +37,11 @@ class IMapSceneBufferCreate { public: virtual ~IMapSceneBufferCreate() = default; - virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; +//------------------------------------- +// Buffer creation +//------------------------------------- + + virtual HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) = 0; virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; @@ -60,6 +64,9 @@ class IMapSceneBufferCreate { virtual HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) = 0; virtual HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) = 0; +//------------------------------------- +// Material creation +//------------------------------------- virtual std::shared_ptr createM2ModelMat(int bonesCount) = 0; virtual std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, @@ -71,6 +78,15 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; + virtual std::shared_ptr> createWMOWideChunk() = 0; + + virtual std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) = 0; +//------------------------------------- +// Mesh creation +//------------------------------------- + virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 50c64662f..843d902a6 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -26,6 +26,9 @@ static const std::vector staticWMOBindings = {{ {+wmoShader::Attribute::aColor2, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(WMOVertex), offsetof(WMOVertex, color2)}, {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; +static const std::vector staticWmoGroupAmbient = {{ + {+wmoShader::Attribute::wmoAmbient, 3, GBindingType::GFLOAT, false, sizeof(mathfu::vec4_packed), 0}, +}}; static const std::vector staticWaterBindings = {{ {+waterShader::Attribute::aPositionTransp, 4, GBindingType::GFLOAT, false, sizeof(LiquidVertexFormat), offsetof(LiquidVertexFormat, pos_transp)}, diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 7bdf08c85..a91f4b20b 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -18,6 +18,14 @@ struct M2ParticleMaterialTemplate { std::array textures = {nullptr, nullptr, nullptr}; }; +struct WMOMaterialTemplate { + std::shared_ptr> m_modelWide; + + std::array textures = {nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr}; +}; + class IM2ModelData { public: @@ -44,4 +52,10 @@ class ISkyMeshMaterial : public IMaterial { std::shared_ptr> m_skyColors = nullptr; }; +class IWMOMaterial : public IMaterial { +public: + std::shared_ptr> m_materialVS= nullptr; + std::shared_ptr> m_materialPS = nullptr; +}; + #endif //AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index e456eefd0..946ed81dc 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -22,6 +22,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C vboWMOBuffer = m_device->createVertexBuffer(1024*1024); vboWaterBuffer = m_device->createVertexBuffer(1024*1024); vboSkyBuffer = m_device->createVertexBuffer(1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); { const float epsilon = 0.f; @@ -51,6 +52,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_emptyM2VAO = createM2VAO(nullptr, nullptr); m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); + m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; @@ -71,10 +73,20 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C // Buffer creation // ------------------ -HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto wmoVAO = m_device->createVertexBufferBindings(); + + HGVertexBuffer ambientBuffer = nullptr; + if (vertexBuffer != nullptr) { + ambientBuffer = vboWMOGroupAmbient->getSubBuffer(sizeof(mathfu::vec4_packed)); + auto packedAmbient = mathfu::vec4_packed(localAmbient); + static_assert(sizeof(packedAmbient) == 16); static_assert(sizeof(mathfu::vec4_packed) == 16); + + ambientBuffer->uploadData(&packedAmbient, sizeof(mathfu::vec4_packed)); + } wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); + wmoVAO->addVertexBufferBinding(ambientBuffer, std::vector(staticWmoGroupAmbient.begin(), staticWmoGroupAmbient.end()), true); wmoVAO->setIndexBuffer(indexBuffer); return wmoVAO; @@ -224,6 +236,46 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM return material; } +std::shared_ptr> MapSceneRenderForwardVLK::createWMOWideChunk() { + return std::make_shared>(uboBuffer); +} + +std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) { + auto l_vertexData = std::make_shared>(uboBuffer); ; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + + auto &l_sceneWideChunk = sceneWideChunk; + auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}) + .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) + .ubo(2, l_vertexData->getSubBuffer()) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[0])) + .texture(6, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[1])) + .texture(7, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[2])) + .texture(8, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[3])) + .texture(9, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[4])) + .texture(10, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[5])) + .texture(11, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[6])) + .texture(12, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[7])) + .texture(13, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[8])); + }) + .toMaterial([&l_vertexData, &l_fragmentData](IWMOMaterial *instance) -> void { + instance->m_materialVS = l_vertexData; + instance->m_materialPS = l_fragmentData; + }); + + return material; +} + std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 0cf97d329..725534eaf 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -24,7 +24,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { //------------------------------------- // Buffer creation //------------------------------------- - HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; @@ -33,7 +33,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; - virtual HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; + HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; @@ -47,6 +47,10 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) override; HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) override; +//------------------------------------- +// Material creation +//------------------------------------- + std::shared_ptr createM2ModelMat(int bonesCount) override; std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, @@ -55,9 +59,19 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr> createWMOWideChunk() override; + + std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) override; + std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; +//------------------------------------- +// Mesh creation +//------------------------------------- + HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; @@ -73,6 +87,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboAdtBuffer; HGBufferVLK vboWMOBuffer; + HGBufferVLK vboWMOGroupAmbient; HGBufferVLK vboWaterBuffer; HGBufferVLK vboSkyBuffer; @@ -94,6 +109,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; + HGVertexBufferBindings m_emptyWMOVAO = nullptr; void createFrameBuffers(); }; From 49cca7baf3a135477c2fb6ad645bf813a10abaf3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 24 Mar 2023 00:08:52 +0200 Subject: [PATCH 055/212] WMO is rendered, but the particles are created inside M2Object's update. Which is not really good --- .../src/engine/objects/wmo/wmoObject.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 33 ++++++++----------- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 3 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 10 +++--- .../vulkan/descriptorSets/GDescriptorSet.cpp | 2 ++ .../src/renderer/mapScene/MapSceneRenderer.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 1 + 7 files changed, 26 insertions(+), 27 deletions(-) diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 15e9ea8ec..56407bbf1 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -261,7 +261,7 @@ class WMOListContainer { } void addToDrawn(const std::shared_ptr &toDrawn) { - if (!toDrawn->isLoaded()) { + if (toDrawn->isLoaded()) { wmoToDrawn.push_back(toDrawn); toDrawmCanHaveDuplicates = true; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index fa6a9e2c7..6a5f85938 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -171,7 +171,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ - enableValidationLayers = true; + enableValidationLayers = false; m_textureManager->initialize(); @@ -1200,27 +1200,20 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings VkDescriptorSet GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) { //1. Try to allocate from existing sets - - //Keep only one descriptor set pool for now - if (m_descriptorPools.size() == 0) { - std::shared_ptr newPool = std::make_shared(*this); - m_descriptorPools.push_back(newPool); + for (size_t i = 0; i < m_descriptorPools.size(); i++) { + desciptorPool = m_descriptorPools[i]; + auto result = desciptorPool->allocate(hDescriptorSetLayout); + if (result != nullptr) { + return result; + } } + //2. Create new descriptor set and allocate from it + { + auto newPool = std::make_shared(*this); + m_descriptorPools.push_back(newPool); - desciptorPool = m_descriptorPools[0]; - return m_descriptorPools[0]->allocate(hDescriptorSetLayout); -// -// for (size_t i = 0; i < m_descriptorPools.size(); i++) { -// descriptorSet = m_descriptorPools[i]->allocate(hDescriptorSetLayout); -// if (descriptorSet != nullptr) -// return descriptorSet; -// } -// -// //2. Create new descriptor set and allocate from it -// GDescriptorPoolVLK * newPool = new GDescriptorPoolVLK(*this); -// m_descriptorPools.push_back(newPool); -// -// return newPool->allocate(hDescriptorSetLayout); + return newPool->allocate(hDescriptorSetLayout); + } } std::shared_ptr diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 64c50bcf8..cb5a89ed1 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -137,7 +137,8 @@ void GBufferVLK::resize(int newLength) { ); deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - + + uploadFromStaging(offset, offset, subBuffer->m_size); subBuffer->m_offset = offset; subBuffer->m_alloc = alloc; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index b857ff3ad..e79a498ac 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -7,7 +7,7 @@ #include "GDescriptorPoolVLK.h" GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) { - uniformsAvailable = 5*4096; + uniformsAvailable = 40*4096; imageAvailable = 4096 * 4; setsAvailable = 4096 * 4; @@ -51,9 +51,11 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptrgetTotalUbos(); - imageAvailable -= hDescriptorSetLayout->getTotalImages(); - setsAvailable -= 1; + if (descriptorSet != nullptr) { + uniformsAvailable -= hDescriptorSetLayout->getTotalUbos(); + imageAvailable -= hDescriptorSetLayout->getTotalImages(); + setsAvailable -= 1; + } return descriptorSet; } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 9b6ef5915..2ad2905f0 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -10,6 +10,7 @@ GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, con : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); + assert(m_descriptorSet != nullptr); } GDescriptorSet::~GDescriptorSet() { m_parentPool->deallocate(m_hDescriptorSetLayout, getDescSet()); @@ -24,6 +25,7 @@ GDescriptorSet::SetUpdateHelper GDescriptorSet::beginUpdate() { m_parentPool->deallocate(m_hDescriptorSetLayout, m_descriptorSet); m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); + assert(m_descriptorSet != nullptr); } return SetUpdateHelper(*this, boundDescriptors); } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 843d902a6..eced4995a 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -27,7 +27,7 @@ static const std::vector staticWMOBindings = {{ {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; static const std::vector staticWmoGroupAmbient = {{ - {+wmoShader::Attribute::wmoAmbient, 3, GBindingType::GFLOAT, false, sizeof(mathfu::vec4_packed), 0}, + {+wmoShader::Attribute::wmoAmbient, 4, GBindingType::GFLOAT, false, sizeof(mathfu::vec4_packed), 0}, }}; static const std::vector staticWaterBindings = {{ diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 946ed81dc..e1bc8bd9f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -386,6 +386,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); From 9d02e4706c1fd4feca260d3eebb7d5af27a28b29 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 25 Mar 2023 19:15:04 +0200 Subject: [PATCH 056/212] textures are not duplicated in the memory --- src/ui/FrontendUI.cpp | 5 +- wowViewerLib/CMakeLists.txt | 4 +- .../glsl/forwardRendering/ffxgauss4.frag | 8 +- .../src/engine/objects/m2/m2Object.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 3 +- .../src/engine/shader/ShaderDefinitions.h | 967 +++++++++--------- .../src/gapi/interface/textures/ITexture.h | 3 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 56 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 5 + wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 1 + .../src/gapi/vulkan/TextureManagerVLK.cpp | 5 +- .../src/gapi/vulkan/TextureManagerVLK.h | 2 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 34 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 2 + .../CommandBufferRecorder.cpp | 9 +- .../CommandBufferRecorder.h | 3 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 3 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 19 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 5 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 4 + .../src/gapi/vulkan/textures/GTextureVLK.h | 4 + .../src/include/custom_container_key.h | 3 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 8 +- 23 files changed, 662 insertions(+), 493 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index df6132e6a..ba4f675ea 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -714,6 +714,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("Tomb of sargares hall", ImVec2(-1, 0))) { openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); } + if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { + openWMOSceneByfdid(1120838); + } if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { openWMOSceneByfdid(4419436); } @@ -1544,7 +1547,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do {canvWidth, canvHeight} }; - if (m_currentScene) { + if (m_sceneRenderer != nullptr) { auto wowSceneFrameInput = std::make_shared>(); wowSceneFrameInput->delta = deltaTime * (1000.0f); wowSceneFrameInput->viewPortDimensions = dimension; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 95e2a53ed..baef2bd9c 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -520,7 +520,9 @@ if (LINK_VULKAN) src/gapi/vulkan/utils/MutexLockedVector.h src/gapi/vulkan/descriptorSets/DescriptorResourceCallBack.h src/gapi/vulkan/bindable/DSBindable.h - src/renderer/mapScene/vulkan/materials/IMaterialInstance.h src/gapi/vulkan/meshes/GSortableMeshVLK.cpp src/gapi/vulkan/meshes/GSortableMeshVLK.h) + src/renderer/mapScene/vulkan/materials/IMaterialInstance.h + src/gapi/vulkan/meshes/GSortableMeshVLK.cpp + src/gapi/vulkan/meshes/GSortableMeshVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag b/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag index a37e3d628..523ac8bef 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag @@ -19,10 +19,10 @@ const float weight[5] = float[] (0, 0.125, 0.375, 0.375, 0.125); void main() { // receive the soze of one texel -// vec2 tex_offset = 1.0 / textureSize(texture0, 0); + vec2 tex_offset = 1.0 / textureSize(texture0, 0); // the value of one fragmentslerp - vec2 tex_offset = vec2(0.001,0.001); - vec3 result = texture(texture0, texCoord).rgb * weight[0]; +// vec2 tex_offset = vec2(0.001,0.001); +// vec3 result = texture(texture0, texCoord).rgb * weight[0]; // bool horizontal = textureDims.x > 0; // if(horizontal) // { @@ -42,7 +42,7 @@ void main() // } // out_result = vec4(result, 1.0); - result = vec3(0.0); + vec3 result = vec3(0.0); result += texture(texture0, texCoord + vec2(texOffsetX.x*tex_offset.x, texOffsetY.x*tex_offset.y)).rgb * weight[1]; result += texture(texture0, texCoord + vec2(texOffsetX.y*tex_offset.x, texOffsetY.y*tex_offset.y)).rgb * weight[2]; result += texture(texture0, texCoord + vec2(texOffsetX.z*tex_offset.x, texOffsetY.z*tex_offset.y)).rgb * weight[3]; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index ebd2fe62f..f4a406d97 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1022,7 +1022,6 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v particleCoordinatesFix; // <- actually is there in the client particleEmitters[i]->Update(deltaTime * 0.001 , transformMat, viewMatInv.TranslationVector3D(), nullptr, viewMat); - particleEmitters[i]->prepearBuffers(viewMat); } this->sortMaterials(modelViewMat); @@ -1104,6 +1103,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); for (int i = minParticle; i < maxParticle; i++) { + particleEmitters[i]->prepearBuffers(viewMat); particleEmitters[i]->updateBuffers(); } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index f51c37673..05e47fb19 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1444,7 +1444,8 @@ PointerChecker &WmoObject::getMaterials() { std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) { auto materialInstance = m_materialCache[materialIndex].lock(); - if (materialInstance != nullptr) return materialInstance; + if (materialInstance != nullptr) + return materialInstance; //Otherwise create goddamit material diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b81b6e179..37b7e8cb2 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,11 +430,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -479,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -513,12 +499,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,32}, {0,0,368}, }, { @@ -534,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {8,8,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -550,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -585,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -604,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -619,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -638,16 +633,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, - }, - { - { - {0,0,0}, - {5,6,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, + }, + { + { + {0,0,0}, + {5,13,9}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -655,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -676,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -700,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -735,14 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -768,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -787,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -837,15 +829,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -871,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -905,14 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,2,16}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -938,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -956,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -971,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1005,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1039,15 +1035,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,5,32}, + {0,3,256}, + {0,0,368}, + {0,1,64}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1058,12 +1057,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1108,15 +1110,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,2,14080}, + {0,1,64}, {0,0,368}, + {0,4,160}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1142,15 +1147,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1176,15 +1181,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,16}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1195,11 +1201,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1210,18 +1217,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,5,32}, - {0,3,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1232,15 +1237,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,11 +1290,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -1320,15 +1324,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1339,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1354,16 +1360,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,15 +1393,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1408,12 +1413,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, + {1,5, "uTexture"}, }, { { - {3,3,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,14 +1429,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1457,16 +1463,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1477,14 +1483,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1495,18 +1498,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,14080}, - {0,1,64}, + {0,4,96}, {0,0,368}, - {0,4,160}, + {0,1,14144}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1517,11 +1519,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1532,11 +1538,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -1552,12 +1559,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1571,11 +1578,27 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { { 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, + } + }, + { + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, @@ -1593,18 +1616,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"drawFrustumShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, + }}, + {"drawBBShader", { { - 4, { - {"_0_4_values0", true, 0, 1, 4, 0}, - {"_0_4_values1", true, 16, 1, 4, 0}, - {"_0_4_values2", true, 32, 1, 4, 0}, - {"_0_4_values3", true, 48, 1, 4, 0}, - {"_0_4_values4", true, 64, 1, 4, 0}, - {"_0_4_baseColor", true, 80, 1, 4, 0}, + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -1945,23 +1944,29 @@ const std::unordered_map &buff) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 6a5f85938..110a36db8 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -237,12 +237,48 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma vkSurface = callback->createSurface(vkInstance); } +std::unordered_set GDeviceVLK::get_enabled_extensions() { + /* + * From the link above: + * If `pProperties` is NULL, then the number of extensions properties + * available is returned in `pPropertyCount`. + * + * Basically, gets the number of extensions. + */ + uint32_t count = 0; + VkResult result = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &count, nullptr); + if (result != VK_SUCCESS) { + // Throw an exception or log the error + } + + std::vector extensionProperties(count); + + // Get the extensions + result = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &count, extensionProperties.data()); + if (result != VK_SUCCESS) { + // Throw an exception or log the error + } + + std::unordered_set extensions; + + std::cout << "enabled extensions : " << std::endl; + for (auto & extension : extensionProperties) { + extensions.insert(extension.extensionName); + std::cout << "- " << extension.extensionName << std::endl; + } + std::cout << "enabled extensions end" << std::endl; + + return extensions; +} + void GDeviceVLK::initialize() { setupDebugMessenger(); pickPhysicalDevice(); createLogicalDevice(); + std::unordered_set enabledExtensions = get_enabled_extensions(); + findQueueFamilies(physicalDevice); //--------------- //Init AMD's VMA @@ -298,6 +334,21 @@ void GDeviceVLK::initialize() { m_whitePixelTexture->loadData(1,1,&ff, ITextureFormat::itRGBA); } +void GDeviceVLK::setObjectName(uint64_t object, VkObjectType objectType, const char *name) +{ + // Check for valid function pointer (may not be present if not running in a debugging application) + if (vkSetDebugUtilsObjectNameEXT != nullptr) + { + VkDebugUtilsObjectNameInfoEXT nameInfo = {}; + nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + nameInfo.pNext = nullptr; + nameInfo.objectType = objectType; + nameInfo.objectHandle = object; + nameInfo.pObjectName = name; + vkSetDebugUtilsObjectNameEXT(device, &nameInfo); + } +} + std::vector VkFormatFeatureFlagBitsGetStrings(VkFormatFeatureFlags value) { std::vector strings; @@ -575,8 +626,9 @@ void GDeviceVLK::createLogicalDevice() { createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + std::vector enabledDeviceExtensions = deviceExtensions; + createInfo.enabledExtensionCount = enabledDeviceExtensions.size(); + createInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data(); if (enableValidationLayers) { createInfo.enabledLayerCount = static_cast(validationLayers.size()); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index ac05e75b2..91d059192 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -61,6 +61,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this get_enabled_extensions(); unsigned int getFrameNumber() override { return m_frameNumber; }; unsigned int getUpdateFrameNumber() ; @@ -133,6 +134,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getSwapChainRenderPass(); + void setObjectName(uint64_t object, VkObjectType objectType, const char *name) override; + void submitDrawCommands() override; void submitQueue( VkQueue queue, @@ -264,6 +267,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this lock(m_textureAllocation); auto i = loadedTextureCache.find(blpCacheRecord); if (i != loadedTextureCache.end()) { @@ -29,7 +30,7 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { } } - auto hgTexture = std::make_shared(static_cast(mdevice), texture, false, false, onUpdateCallback); + auto hgTexture = std::make_shared(static_cast(mdevice), texture, true, true, onUpdateCallback); std::weak_ptr weakPtr(hgTexture); { @@ -42,7 +43,7 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { } HGTexture TextureManagerVLK::createTexture() { - std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), false, false, onUpdateCallback); + std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), true, true, onUpdateCallback); return h_texture; } diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 8a65d0fc8..9ab4a1f30 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -47,6 +47,8 @@ class TextureManagerVLK : public std::enable_shared_from_this private: IDevice &mdevice; + std::mutex m_textureAllocation; + std::function&)> onUpdateCallback = nullptr; void createUpdateCallback(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index cb5a89ed1..40f1179f3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -3,6 +3,7 @@ // #include "GBufferVLK.h" +#include "../vk_mem_alloc.h" GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment) : m_device(device) { m_usageFlags = usageFlags; @@ -159,13 +160,39 @@ void GBufferVLK::resize(int newLength) { executeOnChange(); } +static inline uint8_t BitScanMSB(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} + //fakeSize is used to make sure the subBuffer has enough bytes left till end of main buffer. //used for allocating data for UBO, when you don't want to suballocate whole size. //For example if only one bone matrix is used out 220, sizeInBytes will be size of one matrix, while fakeSize is 220 matrices std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes, int fakeSize) { VmaVirtualAllocation alloc; VkDeviceSize offset; + + std::unique_lock lock(m_mutex,std::defer_lock); + lock.lock(); VkResult res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc, offset); + lock.unlock(); if(res == VK_SUCCESS) { @@ -174,13 +201,18 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy alloc, offset, sizeInBytes, fakeSize, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset); + + lock.lock(); currentSubBuffers.push_back(subBuffer); subBuffer->m_iterator = std::prev(currentSubBuffers.end()); + lock.unlock(); return subBuffer; } else { - resize(std::max(m_bufferSize*2, m_bufferSize + fakeSize)); + lock.lock(); + resize(std::max(m_bufferSize*2, BitScanMSB(m_bufferSize + fakeSize) << 1)); + lock.unlock(); return getSubBuffer(sizeInBytes, fakeSize); } } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 093d9bb46..7669b632e 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -73,6 +73,8 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this dataToBeUploaded; + + std::mutex m_mutex; private: class GSubBufferVLK : public IBufferVLK { friend class GBufferVLK; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index d7632b43f..c007f632b 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -81,7 +81,7 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR // Also, implement "Pipeline Layout Compatibility" thing from spec - if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; +// if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; auto vkDescSet = descriptorSet->getDescSet(); constexpr uint32_t vkDescCnt = 1; @@ -186,7 +186,10 @@ void CmdBufRecorder::setViewPort(ViewportType viewportType) { const constexpr uint32_t firstViewport = 0; const constexpr uint32_t viewportCount = 1; - vkCmdSetViewport(m_gCmdBuffer.m_cmdBuffer, firstViewport, viewportCount, &viewportsForThisStage[(int)viewportType]); + if (m_currentViewport != viewportType) { + vkCmdSetViewport(m_gCmdBuffer.m_cmdBuffer, firstViewport, viewportCount, &viewportsForThisStage[(int) viewportType]); + m_currentViewport = viewportType; + } } void CmdBufRecorder::setScissors(const std::array &areaOffset, @@ -223,6 +226,8 @@ void CmdBufRecorder::setDefaultScissors() { void CmdBufRecorder::createViewPortTypes(const std::array &areaOffset, const std::array &areaSize, bool invertZ) { + m_currentViewport = ViewportType::vp_none; + VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; usualViewport.width = areaSize[0]; usualViewport.height = areaSize[1]; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index cc432ee78..9a6c78295 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -66,12 +66,13 @@ class CmdBufRecorder { std::array, 2> m_currentVertexBuffers; std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; bool m_currentScissorsIsDefault = false; - + ViewportType m_currentViewport = ViewportType::vp_none; //Viewports std::array viewportsForThisStage; VkRect2D defaultScissor; + void createViewPortTypes(const std::array &areaOffset, const std::array &areaSize, bool invertZ); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index e79a498ac..434135d21 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -48,7 +48,8 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptr //for std::stringstream #include "GBlpTextureVLK.h" #include "../../../engine/persistance/helper/ChunkFileReader.h" #include "../../../engine/texture/DxtDecompress.h" +inline static std::string addrToStr(void *addr) { + std::stringstream ss; + ss << (void *)addr; + return ss.str(); +} + GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, - HBlpTexture texture, + const HBlpTexture &texture, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) : GTextureVLK(device,xWrapTex,yWrapTex, onUpdateCallback), m_texture(texture) { + + std::string blpAddress_str = addrToStr(texture.get()); + std::string selfAddr_str = addrToStr(this); + + if (texture->getTextureName() == "3071385") { + std::cout << "3071385 loaded" << std::endl; + } + + m_debugName = "Texture FDID " + texture->getTextureName() + " blp ptr: "+ blpAddress_str + " self ptr :" + selfAddr_str ; } GBlpTextureVLK::~GBlpTextureVLK() { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index c9f3a44d4..f2fb7ec51 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -10,8 +10,11 @@ class GBlpTextureVLK : public GTextureVLK { public: - explicit GBlpTextureVLK(IDeviceVulkan &device, HBlpTexture texture, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback); + explicit GBlpTextureVLK(IDeviceVulkan &device, const HBlpTexture &texture, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback); ~GBlpTextureVLK() override; + GBlpTextureVLK(const GBlpTextureVLK&) = delete; + GBlpTextureVLK(const GBlpTextureVLK&&) = delete; + void createTexture(TextureFormat textureFormat, const HMipmapsVector &hmipmaps) override; TextureStatus postLoad() override; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 2c0c0e5c6..3619fad6d 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -235,6 +235,10 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te vmaCreateImage(m_device.getVMAAllocator(), &imageCreateInfo, &allocImageCreateInfo, &texture.image, &imageAllocation, &imageAllocationInfo); + if (!m_debugName.empty()) { + m_device.setObjectName((uint64_t) texture.image, VK_OBJECT_TYPE_IMAGE, m_debugName.c_str()); + + } // Create a texture sampler // In Vulkan textures are accessed by samplers diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 24007b6a4..bd4f5d0a4 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -31,6 +31,9 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); @@ -114,6 +117,7 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this &r_key) const { - return std::owner_less()(r_key.w_key, w_key); + bool result = !std::owner_less()(r_key.w_key, w_key) && !std::owner_less()(w_key,r_key.w_key); + return result; } bool isExpired() { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index e1bc8bd9f..d00a4e384 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -57,9 +57,9 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; - m_renderPass = hDevice->getRenderPass(dataFormat, ITextureFormat::itDepth32, - VK_SAMPLE_COUNT_1_BIT, -// sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, +// VK_SAMPLE_COUNT_1_BIT, + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), true, false); glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); @@ -462,7 +462,7 @@ void MapSceneRenderForwardVLK::createFrameBuffers() { *m_device, dataFormat, ITextureFormat::itDepth32, - 1, + m_device->getMaxSamplesCnt(), m_width, m_height ); } From 7db3b4808138e8778077f177f48b4a2e544ce4f2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 26 Mar 2023 15:36:53 +0300 Subject: [PATCH 057/212] some stuff --- src/ui/FrontendUI.cpp | 2 +- .../glsl/common/commonWMOMaterial.glsl | 369 +++---- wowViewerLib/src/engine/cache/cache.h | 6 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 4 - .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 951 +++++++++--------- wowViewerLib/src/gapi/interface/IDevice.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 50 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 70 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 6 +- 11 files changed, 769 insertions(+), 697 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index ba4f675ea..805bca00c 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1522,7 +1522,7 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, float f = 1.0f / tan(fov / 2.0f); result->cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); if (result->cameraMatricesForDebugCamera != nullptr) { - result->cameraMatricesForDebugCamera->perspectiveMat = result->cameraMatricesForDebugCamera->perspectiveMat; + result->cameraMatricesForDebugCamera->perspectiveMat = result->cameraMatricesForRendering->perspectiveMat; } } diff --git a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl index c69abed68..97e75319e 100644 --- a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl @@ -34,199 +34,224 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, return; } } - - // float distFade_1070 = clamp(((in_vpos.z * pc_miscParams.z) + pc_miscParams.w), 0, 1); float distFade = 1.0; - if ( pixelShader == -1 ) { - matDiffuse = tex.rgb * tex2.rgb; - finalOpacity = tex.a; - } else if (pixelShader == 0) { //MapObjDiffuse - - matDiffuse = tex.rgb; - finalOpacity = tex.a; - - } else if (pixelShader == 1) { //MapObjSpecular - - matDiffuse = tex.rgb; - specular = calcSpec(tex.a); - - finalOpacity = tex.a; - } else if (pixelShader == 2) { //MapObjMetal - - matDiffuse = tex.rgb ; - specular = calcSpec(((tex * 4.0) * tex.a).x); - - finalOpacity = tex.a; - } else if (pixelShader == 3) { //MapObjEnv - matDiffuse = tex.rgb ; - - emissive = tex2.rgb * tex.a * distFade; - finalOpacity = 1.0; - - } else if (pixelShader == 4) { //MapObjOpaque - - matDiffuse = tex.rgb ; - finalOpacity = 1.0; - - } else if (pixelShader == 5) { //MapObjEnvMetal - - matDiffuse = tex.rgb ; - emissive = (((tex.rgb * tex.a) * tex2.rgb) * distFade); - - finalOpacity = 1.0; - - } else if (pixelShader == 6) { //MapObjTwoLayerDiffuse - - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, tex2.a); - matDiffuse = mix(layer2, layer1, vColor2.a); - - finalOpacity = tex.a; - } else if (pixelShader == 7) { //MapObjTwoLayerEnvMetal - - vec4 colorMix = mix(tex2, tex, 1.0 - vColor2.a); - - matDiffuse = colorMix.rgb ; - emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; - - finalOpacity = tex.a; - - } else if (pixelShader == 8) { //MapObjTwoLayerTerrain - - vec3 layer1 = tex.rgb; - vec3 layer2 = tex2.rgb; - - matDiffuse = mix(layer2, layer1, vColor2.a); - specular = calcSpec(tex2.a * (1.0 - vColor2.a)); - - finalOpacity = tex.a; - - } else if (pixelShader == 9) { //MapObjDiffuseEmissive - - matDiffuse = tex.rgb ; - emissive = tex2.rgb * tex2.a * vColor2.a; - - finalOpacity = tex.a; - - } else if (pixelShader == 10) { //MapObjMaskedEnvMetal - - float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0); - matDiffuse = - mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a); + switch (pixelShader) { + case (-1) : { + matDiffuse = tex.rgb * tex2.rgb; + finalOpacity = tex.a; + break; + } + case (0): { //MapObjDiffuse + matDiffuse = tex.rgb; + finalOpacity = tex.a; + break; + } + case (1) : { //MapObjSpecular + matDiffuse = tex.rgb; + specular = calcSpec(tex.a); - finalOpacity = tex.a; + finalOpacity = tex.a; + break; + } + case (2) : { //MapObjMetal + matDiffuse = tex.rgb ; + specular = calcSpec(((tex * 4.0) * tex.a).x); - } else if (pixelShader == 11) { //MapObjEnvMetalEmissive - matDiffuse = tex.rgb ; - emissive = - ( - ((tex.rgb * tex.a) * tex2.rgb) + - ((tex3.rgb * tex3.a) * vColor2.a) - ); - finalOpacity = tex.a; + finalOpacity = tex.a; + break; + } + case (3): { //MapObjEnv + matDiffuse = tex.rgb ; - } else if (pixelShader == 12) { //MapObjTwoLayerDiffuseOpaque - matDiffuse = mix(tex2.rgb, tex.rgb, vColor2.a); + emissive = tex2.rgb * tex.a * distFade; + finalOpacity = 1.0; + break; + } + case (4) : { //MapObjOpaque - finalOpacity = 1.0; - } else if (pixelShader == 13) { //MapObjTwoLayerDiffuseEmissive - vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a)); + matDiffuse = tex.rgb ; + finalOpacity = 1.0; + break; + } + case (5) : { //MapObjEnvMetal + matDiffuse = tex.rgb ; + emissive = (((tex.rgb * tex.a) * tex2.rgb) * distFade); - matDiffuse = mix(t1diffuse, tex.rgb, vColor2.a); + finalOpacity = 1.0; + break; + } + case (6): { //MapObjTwoLayerDiffuse + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, tex2.a); + matDiffuse = mix(layer2, layer1, vColor2.a); - emissive = (tex2.rgb * tex2.a) * (1.0 - vColor2.a); + finalOpacity = tex.a; + break; + } + case (7): { //MapObjTwoLayerEnvMetal + vec4 colorMix = mix(tex, tex2, 1.0 - vColor2.a); - finalOpacity = tex.a; - } else if (pixelShader == 14) { //MapObjAdditiveMaskedEnvMetal - matDiffuse = mix( - (tex.rgb * tex2.rgb * 2.0) + (tex3.rgb * clamp(tex3.a * vColor2.a, 0.0, 1.0)), - tex.rgb, - vec3(tex.a) - ); - finalOpacity = 1.0; - } else if (pixelShader == 15) { //MapObjTwoLayerDiffuseMod2x - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); - vec3 layer3 = mix(layer2, layer1, vec3(vColor2.a)); + matDiffuse = colorMix.rgb ; + emissive = (colorMix.rgb * colorMix.a) * tex3.rgb * distFade; - matDiffuse = layer3 * tex3.rgb * 2.0; - finalOpacity = tex.a; - } if (pixelShader == 16) { //MapObjTwoLayerDiffuseMod2xNA - vec3 layer1 = ((tex.rgb * tex2.rgb) * 2.0); + finalOpacity = tex.a; + break; + } + case (8): { //MapObjTwoLayerTerrain + vec3 layer1 = tex.rgb; + vec3 layer2 = tex2.rgb; - matDiffuse = mix(tex.rgb, layer1, vec3(vColor2.a)) ; - finalOpacity = tex.a; - } if (pixelShader == 17) { //MapObjTwoLayerDiffuseAlpha - vec3 layer1 = tex.rgb; - vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); - vec3 layer3 = mix(layer2, layer1, vec3(tex3.a)); + matDiffuse = mix(layer2, layer1, vColor2.a); + specular = calcSpec(tex2.a * (1.0 - vColor2.a)); - matDiffuse = ((layer3 * tex3.rgb) * 2.0); - finalOpacity = tex.a; - } if (pixelShader == 18) { //MapObjLod - matDiffuse = tex.rgb ; - finalOpacity = tex.a; - } if (pixelShader == 19) { //MapObjParallax - vec4 tex_6 = texture(s_texture6, vTexCoord2).rgba; + finalOpacity = tex.a; + break; + } + case (9): { //MapObjDiffuseEmissive + matDiffuse = tex.rgb ; + emissive = tex2.rgb * tex2.a * vColor2.a; - mat3 TBN = contangent_frame(normalInView, -vertexPosInView, vTexCoord2); + finalOpacity = tex.a; + break; + } + case (10): { //MapObjMaskedEnvMetal + float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0); + matDiffuse = + mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a); - float cosAlpha = dot(normalize(vertexPosInView.xyz), normalInView); - vec2 dotResult = (TBN * (normalize(-vertexPosInView.xyz) / cosAlpha)).xy; + finalOpacity = tex.a; + break; + } + case (11): { //MapObjEnvMetalEmissive + matDiffuse = tex.rgb ; + emissive = + ( + ((tex.rgb * tex.a) * tex2.rgb) + + ((tex3.rgb * tex3.a) * vColor2.a) + ); + finalOpacity = tex.a; + break; + } + case (12): { //MapObjTwoLayerDiffuseOpaque + matDiffuse = mix(tex2.rgb, tex.rgb, vColor2.a); - vec4 tex_4 = texture(s_texture4, vTexCoord2 - (dotResult * tex_6.r * 0.25)).rgba; - vec4 tex_5 = texture(s_texture5, vTexCoord3 - (dotResult * tex_6.r * 0.25)).rgba; - vec4 tex_3 = texture(s_texture3, vTexCoord2).rgba; + finalOpacity = 1.0; + break; + } + case (13): { //MapObjTwoLayerDiffuseEmissive + vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a)); - vec3 mix1 = tex_5.rgb + tex_4.rgb * tex_4.a; - vec3 mix2 = (tex_3.rgb - mix1) * tex_6.g + mix1; - vec3 mix3 = tex_3.rgb * tex_6.b + (tex_5.rgb * tex_5.a * (1.0 - tex3.b)); + matDiffuse = mix(t1diffuse, tex.rgb, vColor2.a); - vec4 tex_2 = texture(s_texture3, vColorSecond.bg).rgba; - vec3 tex_2_mult = tex_2.rgb * tex_2.a; + emissive = (tex2.rgb * tex2.a) * (1.0 - vColor2.a); - vec3 emissive_component; - if (vColor2.a> 0.0) - { - vec4 tex = texture(s_texture, vTexCoord).rgba; - matDiffuse = (tex.rgb - mix2 ) * vColor2.a + mix2; - emissive_component = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; - } else { - emissive_component = tex_2_mult; - matDiffuse = mix2; + finalOpacity = tex.a; + break; + } + case (14): { //MapObjAdditiveMaskedEnvMetal + matDiffuse = mix( + (tex.rgb * tex2.rgb * 2.0) + (tex3.rgb * clamp(tex3.a * vColor2.a, 0.0, 1.0)), + tex.rgb, + vec3(tex.a) + ); + finalOpacity = 1.0; + break; } + case (15): { //MapObjTwoLayerDiffuseMod2x + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); + vec3 layer3 = mix(layer2, layer1, vec3(vColor2.a)); + + matDiffuse = layer3 * tex3.rgb * 2.0; + finalOpacity = tex.a; + break; + } + case(16): { //MapObjTwoLayerDiffuseMod2xNA + vec3 layer1 = ((tex.rgb * tex2.rgb) * 2.0); - emissive = (mix3 - (mix3 * vColor2.a)) + (emissive_component * tex_2.rgb); - } if (pixelShader == 20) { //MapObjUnkShader - vec4 tex_1 = texture(s_texture, posToTexCoord(vertexPosInView.xyz, normalInView.xyz)); - vec4 tex_2 = texture(s_texture2, vTexCoord); - vec4 tex_3 = texture(s_texture3, vTexCoord2); - vec4 tex_4 = texture(s_texture4, vTexCoord3); - vec4 tex_5 = texture(s_texture5, vTexCoord4); - - vec4 tex_6 = texture(s_texture6, vTexCoord).rgba; - vec4 tex_7 = texture(s_texture7, vTexCoord2).rgba; - vec4 tex_8 = texture(s_texture8, vTexCoord3).rgba; - vec4 tex_9 = texture(s_texture9, vTexCoord4).rgba; - - float secondColorSum = dot(vColorSecond.bgr, vec3(1.0)); - vec4 alphaVec = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004) * vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); - float maxAlpha = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); - vec4 alphaVec2 = (1.0 - clamp(vec4(maxAlpha) - alphaVec, 0.0, 1.0)); - alphaVec2 = alphaVec2 * alphaVec; - - vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); - - vec4 texMixed = tex_2 * alphaVec2Normalized.r + - tex_3 * alphaVec2Normalized.g + - tex_4 * alphaVec2Normalized.b + - tex_5 * alphaVec2Normalized.a; - - emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; - vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk - matDiffuse = (diffuseColor - texMixed.rgb) * vColorSecond.a + texMixed.rgb; + matDiffuse = mix(tex.rgb, layer1, vec3(vColor2.a)) ; + finalOpacity = tex.a; + break; + } + case(17): { //MapObjTwoLayerDiffuseAlpha + vec3 layer1 = tex.rgb; + vec3 layer2 = mix(layer1, tex2.rgb, vec3(tex2.a)); + vec3 layer3 = mix(layer2, layer1, vec3(tex3.a)); + + matDiffuse = ((layer3 * tex3.rgb) * 2.0); + finalOpacity = tex.a; + break; + } + case (18): { //MapObjLod + matDiffuse = tex.rgb ; + finalOpacity = tex.a; + break; + } + case (19): { //MapObjParallax + vec4 tex_6 = texture(s_texture6, vTexCoord2).rgba; + + mat3 TBN = contangent_frame(normalInView, -vertexPosInView, vTexCoord2); + + float cosAlpha = dot(normalize(vertexPosInView.xyz), normalInView); + vec2 dotResult = (TBN * (normalize(-vertexPosInView.xyz) / cosAlpha)).xy; + + vec4 tex_4 = texture(s_texture4, vTexCoord2 - (dotResult * tex_6.r * 0.25)).rgba; + vec4 tex_5 = texture(s_texture5, vTexCoord3 - (dotResult * tex_6.r * 0.25)).rgba; + vec4 tex_3 = texture(s_texture3, vTexCoord2).rgba; + + vec3 mix1 = tex_5.rgb + tex_4.rgb * tex_4.a; + vec3 mix2 = (tex_3.rgb - mix1) * tex_6.g + mix1; + vec3 mix3 = tex_3.rgb * tex_6.b + (tex_5.rgb * tex_5.a * (1.0 - tex3.b)); + + vec4 tex_2 = texture(s_texture3, vColorSecond.bg).rgba; + vec3 tex_2_mult = tex_2.rgb * tex_2.a; + + vec3 emissive_component; + if (vColor2.a> 0.0) + { + vec4 tex = texture(s_texture, vTexCoord).rgba; + matDiffuse = (tex.rgb - mix2 ) * vColor2.a + mix2; + emissive_component = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; + } else { + emissive_component = tex_2_mult; + matDiffuse = mix2; + } + + emissive = (mix3 - (mix3 * vColor2.a)) + (emissive_component * tex_2.rgb); + break; + } + case (20): { //MapObjUnkShader + vec4 tex_1 = texture(s_texture, posToTexCoord(vertexPosInView.xyz, normalInView.xyz)); + vec4 tex_2 = texture(s_texture2, vTexCoord); + vec4 tex_3 = texture(s_texture3, vTexCoord2); + vec4 tex_4 = texture(s_texture4, vTexCoord3); + vec4 tex_5 = texture(s_texture5, vTexCoord4); + + vec4 tex_6 = texture(s_texture6, vTexCoord).rgba; + vec4 tex_7 = texture(s_texture7, vTexCoord2).rgba; + vec4 tex_8 = texture(s_texture8, vTexCoord3).rgba; + vec4 tex_9 = texture(s_texture9, vTexCoord4).rgba; + + float secondColorSum = dot(vColorSecond.bgr, vec3(1.0)); + vec4 alphaVec = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004) * vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); + float maxAlpha = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); + vec4 alphaVec2 = (1.0 - clamp(vec4(maxAlpha) - alphaVec, 0.0, 1.0)); + alphaVec2 = alphaVec2 * alphaVec; + + vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); + + vec4 texMixed = tex_2 * alphaVec2Normalized.r + + tex_3 * alphaVec2Normalized.g + + tex_4 * alphaVec2Normalized.b + + tex_5 * alphaVec2Normalized.a; + + emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; + vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk + matDiffuse = (diffuseColor - texMixed.rgb) * vColorSecond.a + texMixed.rgb; + break; + } } } diff --git a/wowViewerLib/src/engine/cache/cache.h b/wowViewerLib/src/engine/cache/cache.h index 2af3e4ce4..2dff22464 100644 --- a/wowViewerLib/src/engine/cache/cache.h +++ b/wowViewerLib/src/engine/cache/cache.h @@ -161,13 +161,11 @@ class Cache { } } std::shared_ptr sharedPtr = std::make_shared(id); - std::weak_ptr weakPtr(sharedPtr); - m_cache[fileName] = weakPtr; + m_cache[fileName] = sharedPtr; cacheLck.unlock(); - - m_fileRequestProcessor->requestFile(fileName, this->holderType, weakPtr); + m_fileRequestProcessor->requestFile(fileName, this->holderType, sharedPtr); return sharedPtr; } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 7a1583110..663a58cca 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -10,10 +10,6 @@ #include "../../../gapi/interface/materials/IMaterial.h" #include - - - - bool WmoGroupObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (this->m_loaded) return false; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 05e47fb19..c2bf2bdc8 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -323,10 +323,10 @@ bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (mainGeom != nullptr && mainGeom->getStatus() == FileStatus::FSLoaded){ m_sceneRenderer = sceneRenderer; + this->createMaterialCache(); this->createGroupObjects(); this->createWorldPortals(); this->createBB(mainGeom->header->bounding_box); - this->createMaterialCache(); m_modelWideChunk = sceneRenderer->createWMOWideChunk(); if (mainGeom->skyBoxM2FileName != nullptr || mainGeom->skyboxM2FileId != 0) { @@ -1443,6 +1443,8 @@ PointerChecker &WmoObject::getMaterials() { } std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) { + assert(materialIndex < m_materialCache.size()); + auto materialInstance = m_materialCache[materialIndex].lock(); if (materialInstance != nullptr) return materialInstance; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 37b7e8cb2..b81b6e179 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,16}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,4,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,11 +445,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -464,12 +479,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,11 +513,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -519,20 +534,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +550,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +585,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +604,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +619,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +638,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, - }, + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +655,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +676,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +700,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +735,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +768,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +787,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +803,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,15 +837,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,1,12}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -863,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +905,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +938,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +956,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +971,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,4,16}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1005,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1024,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,18 +1039,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,5,32}, - {0,3,256}, - {0,0,368}, - {0,1,64}, + {0,4,32}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1057,15 +1058,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1110,18 +1108,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,2,14080}, - {0,1,64}, {0,0,368}, - {0,4,160}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1147,15 +1142,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1181,16 +1176,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1201,12 +1195,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,16 +1210,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,5,32}, + {0,3,256}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1237,14 +1232,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1290,11 +1286,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -1324,15 +1320,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1339,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1360,14 +1354,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1393,16 +1389,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1413,12 +1408,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, }, { { + {3,3,1}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1429,15 +1424,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1463,16 +1457,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1483,11 +1477,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1498,17 +1495,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, + {0,2,14080}, + {0,1,64}, {0,0,368}, - {0,1,14144}, + {0,4,160}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1519,15 +1517,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, }, { { {0,0,0}, - {5,9,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1538,12 +1532,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,48}, {0,0,368}, }, { @@ -1559,12 +1552,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {8,8,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1578,23 +1571,7 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1616,6 +1593,18 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"waterfallShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_0_4_values0", true, 0, 1, 4, 0}, + {"_0_4_values1", true, 16, 1, 4, 0}, + {"_0_4_values2", true, 32, 1, 4, 0}, + {"_0_4_values3", true, 48, 1, 4, 0}, + {"_0_4_values4", true, 64, 1, 4, 0}, + {"_0_4_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1944,29 +1945,23 @@ const std::unordered_map(this->shared_from_this()); uploadSemaphores[i] = std::make_shared(this->shared_from_this()); + frameBufSemaphores[i] = std::make_shared(this->shared_from_this()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { inFlightFences[i] = std::make_shared(this->shared_from_this(), true); + frameBufFences[i] = std::make_shared(this->shared_from_this(), true); uploadFences[i] = std::make_shared(this->shared_from_this(), true); } } @@ -792,28 +794,24 @@ float GDeviceVLK::getAnisLevel() { void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { int currentDrawFrame = getDrawFrameNumber(); - this->waitInDrawStageAndDeps.beginMeasurement(); - uploadFences[currentDrawFrame]->wait(std::numeric_limits::max()); - inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); - uploadFences[currentDrawFrame]->reset(); - this->waitInDrawStageAndDeps.endMeasurement(); - - auto &uploadCmdBuf = uploadCommandBuffers[currentDrawFrame]; auto &swapChainCmdBuf = swapChainCommandBuffers[currentDrawFrame]; auto &frameBufCmdBuf = fbCommandBuffers[currentDrawFrame]; uint32_t imageIndex = -1; { - auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); - auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); - { - //Wait for SwapChain CMD buffer to become available - inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); - inFlightFences[currentDrawFrame]->reset(); + this->waitInDrawStageAndDeps.beginMeasurement(); + //Wait for frameBuf CMD buffer to become available + frameBufFences[currentDrawFrame]->wait(std::numeric_limits::max()); + uploadFences[currentDrawFrame]->wait(std::numeric_limits::max()); + frameBufFences[currentDrawFrame]->reset(); + uploadFences[currentDrawFrame]->reset(); + this->waitInDrawStageAndDeps.endMeasurement(); } - auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); + + auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); + auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); //Do Texture update { @@ -828,6 +826,14 @@ void GDeviceVLK::drawFrame(const std::vector> & } } + //Wait for swapchain + { + inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); + inFlightFences[currentDrawFrame]->reset(); + } + + auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); + { //Begin render pass for Swap chain this->getNextSwapImageIndex(imageIndex); @@ -851,12 +857,23 @@ void GDeviceVLK::drawFrame(const std::vector> & submitQueue( graphicsQueue, { - uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), + uploadSemaphores[currentDrawFrame]->getNativeSemaphore() + }, + {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}, + {frameBufCmdBuf->getNativeCmdBuffer()}, + {frameBufSemaphores[currentDrawFrame]->getNativeSemaphore()}, + frameBufFences[currentDrawFrame]->getNativeFence() + ); + + submitQueue( + graphicsQueue, + { + frameBufSemaphores[currentDrawFrame]->getNativeSemaphore(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() }, {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, - {frameBufCmdBuf->getNativeCmdBuffer(), swapChainCmdBuf->getNativeCmdBuffer()}, + {swapChainCmdBuf->getNativeCmdBuffer()}, {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, inFlightFences[currentDrawFrame]->getNativeFence() ); @@ -1262,6 +1279,7 @@ GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr(*this); + desciptorPool = newPool; m_descriptorPools.push_back(newPool); return newPool->allocate(hDescriptorSetLayout); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 91d059192..c9aac62bd 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -291,6 +291,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> inFlightFences; + std::array, MAX_FRAMES_IN_FLIGHT> frameBufFences; std::array, MAX_FRAMES_IN_FLIGHT> uploadFences; std::array, MAX_FRAMES_IN_FLIGHT> imageAvailableSemaphores; @@ -298,6 +299,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> renderFinishedSemaphores; std::array, MAX_FRAMES_IN_FLIGHT> uploadSemaphores; + std::array, MAX_FRAMES_IN_FLIGHT> frameBufSemaphores; std::vector> m_descriptorPools; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 40f1179f3..e38e9f642 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -139,7 +139,7 @@ void GBufferVLK::resize(int newLength) { deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - uploadFromStaging(offset, offset, subBuffer->m_size); + addSubBufferForUpload(subBuffer); subBuffer->m_offset = offset; subBuffer->m_alloc = alloc; @@ -236,6 +236,66 @@ void GBufferVLK::save(int length) { uploadFromStaging(0, 0, length); } +void GBufferVLK::addSubBufferForUpload(const std::shared_ptr &buffer) { + std::lock_guard lock(dataToBeUploadedMtx); + + subBuffersForUpload.emplace_back(buffer); +} + +MutexLockedVector GBufferVLK::getSubmitRecords() { + { + std::lock_guard lock(dataToBeUploadedMtx); + + struct uploadInterval {size_t start; size_t size;}; + std::vector intervals; + for (const auto &subBuffer : subBuffersForUpload) { + auto &newInterval = intervals.emplace_back(); + newInterval = {.start = subBuffer->getOffset(), .size = subBuffer->getSize()}; + } + + std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b ) -> bool { + return a.start < b.start; + }); + + if (!intervals.empty()) { + auto currInterval = intervals[0]; + const static auto calcIntervalEnd = [](decltype(currInterval) interval, int aligment) -> size_t { + return aligment > 0 ? + ((interval.start + interval.size + aligment - 1) / aligment) * aligment: + interval.start + interval.size; + }; + + size_t currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); + + for (int i = 1; i < intervals.size(); i++) { + auto &nextInterval = intervals[i]; + if (currIntervalEnd < nextInterval.start) { + VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); + vbCopyRegion.srcOffset = currInterval.start; + vbCopyRegion.dstOffset = currInterval.start; + vbCopyRegion.size = currInterval.size; + + currInterval = intervals[i]; + currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); + } else { + assert(nextInterval.start - currInterval.start >= 0); + currInterval.size = (nextInterval.start - currInterval.start) + nextInterval.size; + currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); + } + } + + VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); + vbCopyRegion.srcOffset = currInterval.start; + vbCopyRegion.dstOffset = currInterval.start; + vbCopyRegion.size = currInterval.size; + } + subBuffersForUpload.clear(); + } + + + return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); +} + //---------------------------------------------------------------- // SubBuffer thing //---------------------------------------------------------------- @@ -263,7 +323,8 @@ void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { memcpy(m_dataPointer, data, length); - m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); + m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); +// m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length) { @@ -273,7 +334,7 @@ void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length memcpy(m_dataPointer + offset, data, length); - m_parentBuffer->uploadFromStaging(m_offset+offset, m_offset+offset, length); + m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); } void *GBufferVLK::GSubBufferVLK::getPointer() { @@ -285,7 +346,8 @@ void GBufferVLK::GSubBufferVLK::save(int length) { std::cerr << "invalid dataSize" << std::endl; } - m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); + m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); +// m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } size_t GBufferVLK::GSubBufferVLK::getSize() { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 7669b632e..2cc38519e 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -28,6 +28,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this &buffer); void *getPointer() override { return currentBuffer.stagingBufferAllocInfo.pMappedData;}; //Submits data edited with Pointer @@ -46,9 +47,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords() { - return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); - } + MutexLockedVector getSubmitRecords(); std::shared_ptr mutate(int newSize) override; void resize(int newLength); @@ -110,6 +109,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> currentSubBuffers; + std::list> subBuffersForUpload; // uploadCache = {}; public: From 5f75802edfb528a66421c28760edc9dde03ac108 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 1 Apr 2023 01:50:00 +0300 Subject: [PATCH 058/212] less ubo size, mesh blocks for M2 are now static --- .../dataExporter/DataExporterClass.cpp | 97 +- .../dataExporter/DataExporterClass.h | 157 ++- src/ui/FrontendUI.cpp | 11 +- src/ui/FrontendUI.h | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 - wowViewerLib/CMakeLists.txt | 2 +- .../shaders/glsl/common/commonM2Material.glsl | 57 +- .../glsl/forwardRendering/m2Shader.frag | 72 +- .../glsl/forwardRendering/m2Shader.vert | 47 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 122 +- .../m2/m2Helpers/M2MeshBufferUpdater.h | 12 +- .../src/engine/objects/m2/m2Object.cpp | 87 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 3 +- .../persistance/header/skinFileHeader.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1014 +++++++++-------- .../src/gapi/UniformBufferStructures.h | 43 +- wowViewerLib/src/gapi/interface/IDevice.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 7 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 23 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 4 +- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 2 +- .../CommandBufferRecorder.cpp | 7 +- wowViewerLib/src/include/config.h | 3 + .../src/renderer/frame/SceneComposer.cpp | 123 +- .../src/renderer/frame/SceneComposer.h | 32 +- .../ProdConsumerIOConnector.cpp | 5 + .../ProdConsumerIOConnector.h | 59 + .../renderer/mapScene/IMapSceneBufferCreate.h | 2 +- .../mapScene/materials/IMaterialStructs.h | 8 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 26 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- 31 files changed, 1292 insertions(+), 743 deletions(-) create mode 100644 wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp create mode 100644 wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h diff --git a/src/exporters/dataExporter/DataExporterClass.cpp b/src/exporters/dataExporter/DataExporterClass.cpp index fd362369f..5314a61d1 100644 --- a/src/exporters/dataExporter/DataExporterClass.cpp +++ b/src/exporters/dataExporter/DataExporterClass.cpp @@ -5,17 +5,23 @@ #include "DataExporterClass.h" #include "../../../wowViewerLib/src/include/string_utils.h" -DataExporterClass::DataExporterClass(HApiContainer apiContainer) { +DataExporter::DataExporterClass::DataExporterClass(HApiContainer apiContainer) : m_storage(DataExporter::makeStorage("dataExport.db3")) { m_apiContainer = apiContainer; processedFiles = 0; outputLog.open ("m2Log.txt"); csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); + + m_storage.pragma.synchronous(0); + m_storage.pragma.journal_mode(sqlite_orm::journal_mode::MEMORY); + m_storage.sync_schema(); } -void DataExporterClass::process() { +void DataExporter::DataExporterClass::process() { if (finished) return; + bool useFileId = true; + if (m_m2Geom == nullptr) { while (csv->read_row(currentFileDataId, currentFileName)) { @@ -23,6 +29,7 @@ void DataExporterClass::process() { break; } if (!endsWith(currentFileName, ".m2")) { + std::cout << "export ended on " << currentFileName << std::endl; finished = true; return; } @@ -33,6 +40,35 @@ void DataExporterClass::process() { m_m2Geom = nullptr; if (m_m2Geom != nullptr && m_m2Geom->getStatus() == FileStatus::FSLoaded) { + if (m_m2Geom->getM2Data()->magic != '02DM') { + m_m2Geom = nullptr; + m_skinGeom = nullptr; + return; + } + if (m_skinGeom == nullptr) { + Cache *skinGeomCache = m_apiContainer->cacheStorage->getSkinGeomCache(); + if (m_m2Geom->skinFileDataIDs.size() > 0) { + assert(m_m2Geom->skinFileDataIDs.size() > 0); + m_skinGeom = skinGeomCache->getFileId(m_m2Geom->skinFileDataIDs[0]); +// } else if (!useFileId){ +// assert(m_nameTemplate.size() > 0); +// std::string skinFileName = m_nameTemplate + "00.skin"; +// m_skinGeom = skinGeomCache->get(skinFileName); + } + return; + } + if (m_skinGeom->getStatus() == FileStatus::FSNotLoaded) return; + if (m_skinGeom->getStatus() == FileStatus::FSRejected) { + m_m2Geom = nullptr; + m_skinGeom = nullptr; + return; + }; + + int md2Id = exportDBM2(); + if (md2Id > 0) { + exportDBSkin(md2Id); + } + if (m_m2Geom->m_m2Data->particle_emitters.size > 0 || m_m2Geom->m_m2Data->ribbon_emitters.size > 0) { outputLog << currentFileName << " "; @@ -91,6 +127,63 @@ void DataExporterClass::process() { } + m_skinGeom = nullptr; m_m2Geom = nullptr; } } + +int DataExporter::DataExporterClass::exportDBM2() { + const auto m2Data = m_m2Geom->m_m2Data; + + DBM2 dbm2; + dbm2.fileDataId = currentFileDataId; + dbm2.fileName = currentFileName; + dbm2.global_flags = *(uint32_t *)&m2Data->global_flags; + dbm2.global_loops_count = m2Data->global_loops.size; + dbm2.sequences_count = m2Data->sequences.size; + dbm2.sequence_lookups_count = m2Data->sequence_lookups.size; + dbm2.bones_count = m2Data->bones.size; + dbm2.key_bone_lookup_count = m2Data->key_bone_lookup.size; + dbm2.vertices_count = m2Data->vertices.size; + dbm2.colors_count = m2Data->colors.size; + dbm2.textures_count = m2Data->textures.size; + dbm2.texture_weights_count = m2Data->texture_weights.size; + dbm2.texture_transforms_count = m2Data->texture_transforms.size; + dbm2.replacable_texture_lookup_count = m2Data->replacable_texture_lookup.size; + dbm2.materials_count = m2Data->materials.size; + dbm2.bone_lookup_table_count = m2Data->bone_lookup_table.size; + dbm2.texture_lookup_table_count = m2Data->texture_lookup_table.size; + dbm2.tex_unit_lookup_table_count = m2Data->tex_unit_lookup_table.size; + dbm2.transparency_lookup_table_count = m2Data->transparency_lookup_table.size; + dbm2.texture_transforms_lookup_table_count = m2Data->texture_transforms_lookup_table.size; + dbm2.collision_triangles_count = m2Data->collision_triangles.size; + dbm2.collision_vertices_count = m2Data->collision_vertices.size; + dbm2.collision_normals_count = m2Data->collision_normals.size; + dbm2.attachments_count = m2Data->attachments.size; + dbm2.attachment_lookup_table_count = m2Data->attachment_lookup_table.size; + dbm2.events_count = m2Data->events.size; + dbm2.lights_count = m2Data->lights.size; + dbm2.cameras_count = m2Data->cameras.size; + dbm2.camera_lookup_table_count = m2Data->camera_lookup_table.size; + dbm2.ribbon_emitters_count = m2Data->ribbon_emitters.size; + dbm2.particle_emitters_count = m2Data->particle_emitters.size; + dbm2.blend_map_overrides_count = m2Data->blend_map_overrides.size; + + return m_storage.insert(dbm2); +} + +void DataExporter::DataExporterClass::exportDBSkin(int id) { + auto skinProfile = m_skinGeom->getSkinData(); + M2Array &batches = skinProfile->batches; + for (int batchIndex = 0; batchIndex < batches.size; batchIndex++) { + auto const batch = skinProfile->batches.getElement(batchIndex); + + DataExporter::DBM2Batch dbm2Batch; + *dynamic_cast(&dbm2Batch) = *batch; + + dbm2Batch.m2Id = id; + dbm2Batch.batchIndex = batchIndex; + + m_storage.insert(dbm2Batch); + } +} diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index c68043069..c4a70882f 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -13,28 +13,151 @@ #include "../../../wowViewerLib/src/engine/objects/m2/m2Object.h" #include "../../database/csvtest/csv.h" #include +#include "../../../3rdparty/sqlite_orm/sqlite_orm.h" -class DataExporterClass { -public: - DataExporterClass(HApiContainer apiContainer); - void process(); - bool isDone() { - return finished; - } -private: - HApiContainer m_apiContainer; - int currentFileDataId; - std::string currentFileName; +namespace DataExporter { + struct DBM2Batch : public M2Batch { + int m2Id = -1; + int batchIndex = -1; + }; - HM2Geom m_m2Geom = nullptr; - io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>> *csv ; + struct DBSkinSection { + int m2Id = -1; + M2SkinSection skinSection; + }; + + struct DBM2 { + int m2Id = -1; + int fileDataId; + std::string fileName; + int global_flags; + int global_loops_count; + int sequences_count; + int sequence_lookups_count; + int bones_count; + int key_bone_lookup_count; + int vertices_count; + int colors_count; + int textures_count; + int texture_weights_count; + int texture_transforms_count; + int replacable_texture_lookup_count; + int materials_count; + int bone_lookup_table_count; + int texture_lookup_table_count; + int tex_unit_lookup_table_count; + int transparency_lookup_table_count; + int texture_transforms_lookup_table_count; + int collision_triangles_count; + int collision_vertices_count; + int collision_normals_count; + int attachments_count; + int attachment_lookup_table_count; + int events_count; + int lights_count; + int cameras_count; + int camera_lookup_table_count; + int ribbon_emitters_count; + int particle_emitters_count; + int blend_map_overrides_count; + }; + + inline static auto makeStorage(const std::string &dataBaseFile) { + using namespace sqlite_orm; + return make_storage(dataBaseFile, + make_table("M2", + make_column("id", &DBM2::m2Id, autoincrement(), primary_key()), + make_column("fileDataId", &DBM2::fileDataId), + make_column("fileName", &DBM2::fileName), + make_column("global_flags", &DBM2::global_flags), + make_column("global_loops_count", &DBM2::global_loops_count), + make_column("sequences_count", &DBM2::sequences_count), + make_column("sequence_lookups_count", &DBM2::sequence_lookups_count), + make_column("bones_count", &DBM2::bones_count), + make_column("key_bone_lookup_count", &DBM2::key_bone_lookup_count), + make_column("vertices_count", &DBM2::vertices_count), + make_column("colors_count", &DBM2::colors_count), + make_column("textures_count", &DBM2::textures_count), + make_column("texture_weights_count", &DBM2::texture_weights_count), + make_column("texture_transforms_count", &DBM2::texture_transforms_count), + make_column("replacable_texture_lookup_count", &DBM2::replacable_texture_lookup_count), +#ifdef _MSC_VER + make_column("materials_count", &DBM2::materials_count), + make_column("bone_lookup_table_count", &DBM2::bone_lookup_table_count), + make_column("texture_lookup_table_count", &DBM2::texture_lookup_table_count), + make_column("tex_unit_lookup_table_count", &DBM2::tex_unit_lookup_table_count), + make_column("transparency_lookup_table_count", &DBM2::transparency_lookup_table_count), + make_column("texture_transforms_lookup_table_count", &DBM2::texture_transforms_lookup_table_count), + make_column("collision_triangles_count", &DBM2::collision_triangles_count), + make_column("collision_vertices_count", &DBM2::collision_vertices_count), + make_column("collision_normals_count", &DBM2::collision_normals_count), + make_column("attachments_count", &DBM2::attachments_count), + make_column("attachment_lookup_table_count", &DBM2::attachment_lookup_table_count), + make_column("events_count", &DBM2::events_count), + make_column("lights_count", &DBM2::lights_count), + make_column("cameras_count", &DBM2::cameras_count), + make_column("camera_lookup_table_count", &DBM2::camera_lookup_table_count), +#endif + make_column("ribbon_emitters_count", &DBM2::ribbon_emitters_count), + make_column("particle_emitters_count", &DBM2::particle_emitters_count) + //make_column("blend_map_overrides_count", &DBM2::blend_map_overrides_count) + ), + make_table("M2Batch", + make_column("m2Id", &DBM2Batch::m2Id), + make_column("batchIndex", &DBM2Batch::batchIndex), + make_column("_flags", &DBM2Batch::flags), + make_column("priorityPlane", &DBM2Batch::priorityPlane), + make_column("shader_id", &DBM2Batch::shader_id), + make_column("skinSectionIndex", &DBM2Batch::skinSectionIndex), + make_column("geosetIndex", &DBM2Batch::geosetIndex), + make_column("colorIndex", &DBM2Batch::colorIndex), + make_column("materialIndex", &DBM2Batch::materialIndex), + make_column("materialLayer", &DBM2Batch::materialLayer), + make_column("textureCount", &DBM2Batch::textureCount), + make_column("textureComboIndex", &DBM2Batch::textureComboIndex), + make_column("textureCoordComboIndex", &DBM2Batch::textureCoordComboIndex), + make_column("textureWeightComboIndex", &DBM2Batch::textureWeightComboIndex), + make_column("textureTransformComboIndex", &DBM2Batch::textureTransformComboIndex), + foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), + unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) + ) + ); + }; + + class DataExporterClass { + public: + DataExporterClass(HApiContainer apiContainer); + void process(); + bool isDone() { + return finished; + } + private: + HApiContainer m_apiContainer; + + int currentFileDataId; + std::string currentFileName; + + HM2Geom m_m2Geom = nullptr; + HSkinGeom m_skinGeom = nullptr; + io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>> *csv ; + + bool finished = false; + int processedFiles = 0; + + std::ofstream outputLog; + + + + decltype(DataExporter::makeStorage("")) m_storage; + + int exportDBM2(); + + void exportDBSkin(int id); + }; +} - bool finished = false; - int processedFiles = 0; - std::ofstream outputLog; -}; #endif //AWEBWOWVIEWERCPP_DATAEXPORTERCLASS_H diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 805bca00c..4ee91281e 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -28,7 +28,6 @@ #include "../persistance/HttpRequestProcessor.h" #include "../exporters/gltfExporter/GLTFExporter.h" #include "../../wowViewerLib/src/engine/objects/scenes/NullScene.h" -#include "../exporters/dataExporter/DataExporterClass.h" #include "../database/CSqliteDB.h" #include "../database/CEmptySqliteDB.h" #include "../../wowViewerLib/src/gapi/UniformBufferStructures.h" @@ -47,6 +46,11 @@ FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { } void FrontendUI::composeUI() { + if (m_dataExporter != nullptr) { + m_dataExporter->process(); + if (m_dataExporter->isDone()) + m_dataExporter = nullptr; + } if (mapCanBeOpened) { if (!adtMinimapFilled && fillAdtSelectionminimap(isWmoMap, mapCanBeOpened )) { // fillAdtSelectionminimap = nullptr; @@ -161,6 +165,9 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::NewLine(); if (ImGui::CollapsingHeader("Elapsed times")) { + ImGui::Text("Elapsed time on deviceDrawFrame : %.3f ms", m_api->getConfig()->deviceDrawFrame); + ImGui::Text("Elapsed time on composerDrawTimePerFrame : %.3f ms", m_api->getConfig()->composerDrawTimePerFrame); + ImGui::Text("Elapsed time on drawFuncGeneration : %.3f ms", m_api->getConfig()->drawFuncGeneration); ImGui::Text("Elapsed time on culling : %.3f ms", m_api->getConfig()->cullingTimePerFrame); ImGui::Text("- Elapsed time on cullCreateVarsCounter: %.3f ms", m_api->getConfig()->cullCreateVarsCounter); ImGui::Text("- Elapsed time on cullGetCurrentWMOCounter: %.3f ms", m_api->getConfig()->cullGetCurrentWMOCounter); @@ -555,7 +562,7 @@ void FrontendUI::showMainMenu() { } } if (ImGui::MenuItem("Test data export")) { - dataExporter = new DataExporterClass(m_api); + m_dataExporter = std::make_shared(m_api); } ImGui::Separator(); if (ImGui::MenuItem("Make screenshot")) { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 274efd9b7..1c5f53c2b 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -193,7 +193,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_dataExporter = nullptr; std::shared_ptr m_databaseUpdateWorkflow = nullptr; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index f60084b5b..14f14eacb 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -140,6 +140,4 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } })); - - } diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index baef2bd9c..122203e1a 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -566,7 +566,7 @@ if (LINK_VULKAN) # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() #Add volk loader - set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c src/gapi/vulkan/context/vulkan_context.h) + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c src/gapi/vulkan/context/vulkan_context.h src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h) endif() diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index 1150063a2..afca5c8c9 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -1,20 +1,20 @@ #include "commonFunctions.glsl" void calcM2FragMaterial(const in int uPixelShader, - in sampler2D texSampler1, - in sampler2D texSampler2, - in sampler2D texSampler3, - in sampler2D texSampler4, - const in vec2 inUv1, - const in vec2 inUv2, - const in vec2 inUv3, - const in vec3 meshColor, - const in float meshOpacity, - const in vec3 texSampleAlpha, - const in int blendMode, +in sampler2D texSampler1, +in sampler2D texSampler2, +in sampler2D texSampler3, +in sampler2D texSampler4, +const in vec2 inUv1, +const in vec2 inUv2, +const in vec2 inUv3, +const in vec3 meshColor, +const in float meshOpacity, +const in vec3 texSampleAlpha, +const in int blendMode, - out vec3 matDiffuse, out vec3 specular, - out float finalOpacity, out bool discardThisFragment) +out vec3 matDiffuse, out vec3 specular, +out float finalOpacity, out bool discardThisFragment) { vec4 genericParams[3]; genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 ); @@ -252,7 +252,7 @@ void calcM2FragMaterial(const in int uPixelShader, } else if (blendMode == 1) { finalOpacity = meshOpacity; if (canDiscard && discardAlpha < 0.501960814) - doDiscard = true; + doDiscard = true; } else if (blendMode == 0) { finalOpacity = meshOpacity; } else { @@ -263,24 +263,22 @@ void calcM2FragMaterial(const in int uPixelShader, } void calcM2VertexMat(in int vertexShader, - in vec3 vertexPosInView, - in vec3 normal, - in vec2 texCoord, - in vec2 texCoord2, - in vec4 color_Transparency, - in mat4 textMat[2], - out vec4 vMeshColorAlpha, - out vec2 vTexCoord, - out vec2 vTexCoord2, - out vec2 vTexCoord3) { +in vec3 vertexPosInView, +in vec3 normal, +in vec2 texCoord, +in vec2 texCoord2, +in mat4 textMat[2], +out float edgeFade, +out vec2 vTexCoord, +out vec2 vTexCoord2, +out vec2 vTexCoord3) { vTexCoord2 = vec2(0.0); vTexCoord3 = vec2(0.0); vec2 envCoord = posToTexCoord(vertexPosInView, normal); float edgeScanVal = edgeScan(vertexPosInView, normal); - vMeshColorAlpha = color_Transparency; - + edgeFade = 1.0; switch(vertexShader) { case (0): { //Diffuse_T1 vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; @@ -328,7 +326,7 @@ void calcM2VertexMat(in int vertexShader, break; } case (9): { //Diffuse_EdgeFade_T1 - vMeshColorAlpha.a *= edgeScanVal; + edgeFade = edgeScanVal; vTexCoord = ((textMat[0] * vec4(texCoord, 0.0, 1.0)).xy).xy; break; } @@ -343,13 +341,13 @@ void calcM2VertexMat(in int vertexShader, break; } case (12): { //Diffuse_EdgeFade_T1_T2 - vMeshColorAlpha.a *= edgeScanVal; + edgeFade = edgeScanVal; vTexCoord = (textMat[0] * vec4(texCoord, 0.0, 1.0)).xy; vTexCoord2 = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; break; } case (13): { //Diffuse_EdgeFade_Env - vMeshColorAlpha.a *= edgeScanVal; + edgeFade = edgeScanVal; vTexCoord = envCoord; break; } @@ -367,7 +365,6 @@ void calcM2VertexMat(in int vertexShader, } case (16): { //Color_T1_T2_T3 vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0); - vMeshColorAlpha = vec4((in_col0.rgb * 0.5).r, (in_col0.rgb * 0.5).g, (in_col0.rgb * 0.5).b, in_col0.a); vTexCoord = (textMat[1] * vec4(texCoord2, 0.0, 1.0)).xy; vTexCoord2 = vec2(0.0, 0.0); vTexCoord3 = vTexCoord3; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 0b355f033..d47fba723 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -24,8 +24,7 @@ layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; layout(location=2) in vec2 vTexCoord3; layout(location=3) in vec3 vNormal; -layout(location=4) in vec3 vPosition; -layout(location=5) in vec4 vMeshColorAlpha; +layout(location=4) in vec4 vPosition_EdgeFade; layout(location=0) out vec4 outputColor; @@ -38,19 +37,32 @@ layout(std140, set=0, binding=1) uniform placementMat { mat4 uPlacementMat; }; - //Whole model -layout(std140, set=0, binding=3) uniform modelWideBlockPS { +layout(std140, set=0, binding=2) uniform modelWideBlockPS { InteriorLightParam intLight; LocalLight pc_lights[4]; ivec4 lightCountAndBcHack; vec4 interiorExteriorBlend; }; +layout(std140, set=0, binding=4) uniform m2Colors { + vec4 colors[256]; +}; + +layout(std140, set=0, binding=5) uniform textureWeights { + vec4 textureWeight[16]; +}; + +layout(std140, set=0, binding=6) uniform textureMatrices { + mat4 textureMatrix[64]; +}; + //Individual meshes -layout(std140, set=0, binding=5) uniform meshWideBlockPS { - ivec4 PixelShader_UnFogged_IsAffectedByLight_blendMode; - vec4 uTexSampleAlpha; +layout(std140, set=0, binding=7) uniform meshWideBlockVSPS { + ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; + ivec4 PixelShader_UnFogged_blendMode; + ivec4 textureWeightIndexes; + ivec4 colorIndex_applyWeight; }; layout(set=1,binding=6) uniform sampler2D uTexture; @@ -65,11 +77,29 @@ void main() { vec2 texCoord3 = vTexCoord3.xy; vec4 finalColor = vec4(0); + + vec3 uTexSampleAlpha = vec3( + textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightIndexes.x / 4][textureWeightIndexes.x % 4], + textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightIndexes.y / 4][textureWeightIndexes.y % 4], + textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightIndexes.z / 4][textureWeightIndexes.z % 4] + ); + + vec4 vMeshColorAlpha = vec4( + colorIndex_applyWeight.x < 0 ? vec4(1.0,1.0,1.0,1.0) : colors[colorIndex_applyWeight.x] + ); + if (colorIndex_applyWeight.y > 0) + vMeshColorAlpha.a *= + textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightIndexes.x / 4][textureWeightIndexes.x % 4]; + + vMeshColorAlpha *= vPosition_EdgeFade.w; + + //Accumulate and apply lighting + vec3 meshResColor = vMeshColorAlpha.rgb; vec3 accumLight = vec3(0.0); - if ((PixelShader_UnFogged_IsAffectedByLight_blendMode.z == 1)) { - vec3 vPos3 = vPosition.xyz; + if ((vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { + vec3 vPos3 = vPosition_EdgeFade.xyz; vec3 vNormal3 = normalize(vNormal.xyz); vec3 lightColor = vec3(0.0); int count = int(pc_lights[0].attenuation.w); @@ -97,12 +127,16 @@ void main() { //finalColor.rgb = finalColor.rgb * lightColor; } +//---------------------- +// Calc Diffuse and Specular +//--------------------- + float finalOpacity = 0.0; vec3 matDiffuse; vec3 specular; - int uPixelShader = PixelShader_UnFogged_IsAffectedByLight_blendMode.x; - int blendMode = PixelShader_UnFogged_IsAffectedByLight_blendMode.w; + int uPixelShader = PixelShader_UnFogged_blendMode.x; + int blendMode = PixelShader_UnFogged_blendMode.z; bool doDiscard = false; @@ -118,11 +152,15 @@ void main() { if (doDiscard) discard; +// ------------------------------ +// Apply lighting +// ------------------------------ + finalColor = vec4( calcLight( matDiffuse, vNormal, - PixelShader_UnFogged_IsAffectedByLight_blendMode.z > 0, + vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, interiorExteriorBlend.x, scene, intLight, @@ -136,7 +174,11 @@ void main() { outputColor = finalColor; - int uUnFogged = PixelShader_UnFogged_IsAffectedByLight_blendMode.y; +// ------------------------------ +// Apply Fog +// ------------------------------ + + int uUnFogged = PixelShader_UnFogged_blendMode.y; if (uUnFogged == 0) { vec3 sunDir = mix( @@ -146,10 +188,8 @@ void main() { ) .xyz; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, PixelShader_UnFogged_IsAffectedByLight_blendMode.w); + finalColor = makeFog(fogData, finalColor, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); } -// finalColor.rgb = finalColor.rgb; - //Forward rendering without lights outputColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 5a366feec..3f1f19581 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -33,15 +33,29 @@ layout(std140, set=0, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; }; -layout(std140, set=0, binding=2) uniform boneMats { +layout(std140, set=0, binding=3) uniform boneMats { mat4 uBoneMatrixes[MAX_MATRIX_NUM]; }; + +layout(std140, set=0, binding=4) uniform m2Colors { + vec4 colors[256]; +}; + +layout(std140, set=0, binding=5) uniform textureWeights { + vec4 textureWeight[16]; +}; + +layout(std140, set=0, binding=6) uniform textureMatrices { + mat4 textureMatrix[64]; +}; + //Individual meshes -layout(std140, set=0, binding=4) uniform meshWideBlockVS { - ivec4 vertexShader_IsAffectedByLight; - vec4 color_Transparency; - mat4 uTextMat[2]; +layout(std140, set=0, binding=7) uniform meshWideBlockVSPS { + ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; + ivec4 PixelShader_UnFogged_blendMode; + ivec4 textureWeightIndexes; + ivec4 colorIndex_applyWeight; }; //Shader output @@ -49,8 +63,7 @@ layout(location=0) out vec2 vTexCoord; layout(location=1) out vec2 vTexCoord2; layout(location=2) out vec2 vTexCoord3; layout(location=3) out vec3 vNormal; -layout(location=4) out vec3 vPosition; -layout(location=5) out vec4 vMeshColorAlpha; +layout(location=4) out vec4 vPosition_EdgeFade; void main() { @@ -65,7 +78,6 @@ void main() { boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; - mat4 placementMat; placementMat = uPlacementMat; @@ -75,16 +87,27 @@ void main() { vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; - int uVertexShader = vertexShader_IsAffectedByLight.x; + int uVertexShader = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; + + mat4 textMat[2]; + int textMatIndex1 = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; + int textMatIndex2 =vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; + + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + + float edgeFade = 1.0; + calcM2VertexMat(uVertexShader, vertexPosInView.xyz, normal, aTexCoord, aTexCoord2, - color_Transparency, uTextMat, - vMeshColorAlpha, vTexCoord, vTexCoord2, vTexCoord3); + textMat, edgeFade, + vTexCoord, vTexCoord2, vTexCoord3); + gl_Position = scene.uPMatrix * vertexPosInView; vNormal = normal; - vPosition = vertexPosInView.xyz; + vPosition_EdgeFade = vec4(vertexPosInView.xyz, edgeFade); } diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 14cbdd024..f8d71a2a8 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -9,8 +9,8 @@ float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile){ auto textMaterial = m2SkinProfile->batches[batchIndex]; - mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object.subMeshColors); - float transparency = M2Object::getTextureWeight(m2SkinProfile, m2Object.m_m2Geom->getM2Data(), batchIndex, 0, m2Object.transparencies); + mathfu::vec4 meshColor = getCombinedColor(m2SkinProfile, batchIndex, m2Object.subMeshColors); + float transparency = getTextureWeight(m2SkinProfile, m2Object.m_m2Geom->getM2Data(), batchIndex, 0, m2Object.transparencies); float finalTransparency = meshColor.w; if ( textMaterial->textureCount && !(textMaterial->flags & 0x40)) { finalTransparency *= transparency; @@ -26,19 +26,32 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr int renderFlagIndex = batch->materialIndex; auto renderFlag = m2Data->materials[renderFlagIndex]; - mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object->subMeshColors); + mathfu::vec4 meshColor = getCombinedColor(m2SkinProfile, batchIndex, m2Object->subMeshColors); float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); - //2. Update VS buffer - auto &meshblockVS = m2Material->m_vertexData->getObject(); - meshblockVS.Color_Transparency = mathfu::vec4_packed(mathfu::vec4(meshColor.x, meshColor.y, meshColor.z, finalTransparency)); - meshblockVS.isSkyBox = m2Object->m_boolSkybox ? 1 : 0; - meshblockVS.VertexShader = m2Material->vertexShader; - meshblockVS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; - - fillTextureMatrices(*m2Object, batchIndex, m2Data, m2SkinProfile, meshblockVS.uTextMat); - m2Material->m_vertexData->save(); - + std::array textureMatrixIndexes = {-1, -1}; + getTextureMatrixIndexes(*m2Object, batchIndex, m2Data, m2SkinProfile, textureMatrixIndexes); + + //2. Update VSPS buffer + auto &meshblockVSPS = m2Material->m_vertexFragmentData->getObject(); + meshblockVSPS.VertexShader = m2Material->vertexShader; + meshblockVSPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; + meshblockVSPS.textureMatIndex1 = textureMatrixIndexes[0]; + meshblockVSPS.textureMatIndex2 = textureMatrixIndexes[1]; + meshblockVSPS.PixelShader = m2Material->pixelShader; + meshblockVSPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; + meshblockVSPS.BlendMode = static_cast(m2Material->blendMode); + meshblockVSPS.applyWeight = batch->textureCount && !(batch->flags & 0x40); + meshblockVSPS.colorIndex = batch->colorIndex; + meshblockVSPS.textureWeightIndexes[0] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 0); + meshblockVSPS.textureWeightIndexes[1] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 1); + meshblockVSPS.textureWeightIndexes[2] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 2); + meshblockVSPS.textureWeightIndexes[3] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 3); + + meshblockVSPS.PixelShader = m2Material->pixelShader; + meshblockVSPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; + + m2Material->m_vertexFragmentData->save(); //3. Update individual PS buffer float uAlphaTest; @@ -47,24 +60,10 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr } else { uAlphaTest = 1.0f/255.0f; } - - //Fill values into buffer - mathfu::vec4 uTexSampleAlpha = mathfu::vec4(1.0, 1.0, 1.0, 1.0); - for (int i = 0; i < std::min(batch->textureCount, 4); i++) { - uTexSampleAlpha[i] = M2Object::getTextureWeight(m2SkinProfile, m2Data, batchIndex, i, m2Object->transparencies); - } - - auto &meshBlockPS = m2Material->m_fragmentData->getObject(); - meshBlockPS.PixelShader = m2Material->pixelShader; - meshBlockPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; - meshBlockPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; - meshBlockPS.BlendMode = static_cast(m2Material->blendMode); - meshBlockPS.uTexSampleAlpha = uTexSampleAlpha; - m2Material->m_fragmentData->save(); } void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, - const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat) { + const M2Data * m2File, const M2SkinProfile *m2SkinProfile, const mathfu::mat4 &modelViewMat) { M2Batch *textMaterial = m2SkinProfile->batches.getElement(batchIndex); M2SkinSection *submesh = m2SkinProfile->skinSections.getElement(textMaterial->skinSectionIndex); @@ -136,9 +135,8 @@ mathfu::mat4 M2MeshBufferUpdater::getTextureMatrix(const M2Object &m2Object, int return m2Object.textAnimMatrices[textureMatIndex]; } -void M2MeshBufferUpdater::fillTextureMatrices(const M2Object &m2Object, int batchIndex, M2Data *m2Data, - M2SkinProfile *m2SkinProfile, mathfu::mat4 *uTextMat) { - +void M2MeshBufferUpdater::getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, + const M2SkinProfile *m2SkinProfile, std::array &o_textureMatIndexes) { auto textureAnim = m2SkinProfile->batches[batchIndex]->textureTransformComboIndex; if (m2Object.m_m2Geom->m_wfv1 != nullptr) { @@ -149,13 +147,71 @@ void M2MeshBufferUpdater::fillTextureMatrices(const M2Object &m2Object, int batc if (textureAnim < m2Data->texture_transforms_lookup_table.size) textureMatIndex = *m2Data->texture_transforms_lookup_table[textureAnim]; - uTextMat[0] = M2MeshBufferUpdater::getTextureMatrix(m2Object, textureMatIndex, m2Data); + o_textureMatIndexes[0] = textureMatIndex; textureMatIndex = -1; if (textureAnim+1 < m2Data->texture_transforms_lookup_table.size) textureMatIndex = *m2Data->texture_transforms_lookup_table[textureAnim+1]; - uTextMat[1] = M2MeshBufferUpdater::getTextureMatrix(m2Object, textureMatIndex, m2Data); + o_textureMatIndexes[1] = textureMatIndex; +} + +mathfu::vec4 M2MeshBufferUpdater::getCombinedColor( + M2SkinProfile *skinData, + int batchIndex, + const std::vector &subMeshColors +) { + int colorIndex = skinData->batches[batchIndex]->colorIndex; + mathfu::vec4 submeshColor = mathfu::vec4(1,1,1,1); + + if ((colorIndex >= 0) && (subMeshColors.size() > colorIndex)) { + const mathfu::vec4 &color = subMeshColors[colorIndex]; + submeshColor = color; + } + + return submeshColor; +} + +float M2MeshBufferUpdater::getTextureWeight( + M2SkinProfile *skinData, + M2Data * m2Data, + int batchIndex, + int textureIndex, + const std::vector &transparencies) { + float transparency = 1.0; + + int transpIndex = getTextureWeightIndex(skinData, m2Data, batchIndex, textureIndex); + + if ((transpIndex >= 0) && (transparencies.size() > transpIndex)) { + transparency = transparencies[transpIndex]; + } + + return transparency; +} + +int +M2MeshBufferUpdater::getTextureWeightIndex(const M2SkinProfile *skinData, const M2Data *m2Data, int batchIndex, + int textureIndex) { + if (textureIndex >= skinData->batches[batchIndex]->textureCount) { + return -1; + } + + int transpLookupIndex = skinData->batches[batchIndex]->textureWeightComboIndex + textureIndex; + int transpIndex = -1; + if ((transpLookupIndex >= 0) && (transpLookupIndex < m2Data->transparency_lookup_table.size)) { + transpIndex = *m2Data->transparency_lookup_table[transpLookupIndex]; + } + return transpIndex; +} + +void M2MeshBufferUpdater::fillTextureMatrices(const M2Object &m2Object, int batchIndex, M2Data *m2Data, + M2SkinProfile *m2SkinProfile, mathfu::mat4 *uTextMat) { + + std::array textureMatrixIndexes; + getTextureMatrixIndexes(m2Object, batchIndex, m2Data, m2SkinProfile, textureMatrixIndexes); + + uTextMat[0] = M2MeshBufferUpdater::getTextureMatrix(m2Object, textureMatrixIndexes[0], m2Data); + uTextMat[1] = M2MeshBufferUpdater::getTextureMatrix(m2Object, textureMatrixIndexes[1], m2Data); } mathfu::vec3 &M2MeshBufferUpdater::getFogColor(EGxBlendEnum blendMode, mathfu::vec3 &originalFogColor) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index e15cfb69a..013235c3a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -22,13 +22,23 @@ class M2MeshBufferUpdater { static void fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS); static mathfu::mat4 getTextureMatrix(const M2Object &m2Object, int textureMatIndex, M2Data *m2Data); + + static inline void getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, + const M2SkinProfile *m2SkinProfile, std::array &o_textureMatIndexes); + + static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; + static float getTextureWeight(M2SkinProfile *skinData, M2Data *m2data, int batchIndex, int textureIndex, const std::vector &transparencies) ; + static void fillTextureMatrices(const M2Object &m2Object, int batchIndex, M2Data *m2Data, M2SkinProfile *m2SkinProfile, mathfu::mat4 *uTextMat); static inline mathfu::vec3 &getFogColor(EGxBlendEnum blendMode, mathfu::vec3 &originalFogColor); static void updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, - const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat); + const M2Data * m2File, const M2SkinProfile *m2SkinProfile, const mathfu::mat4 &modelViewMat); + + static inline int getTextureWeightIndex(const M2SkinProfile *skinData, const M2Data *m2Data, + int batchIndex, int textureIndex); }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index f4a406d97..da10fb93c 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -697,44 +697,6 @@ float M2Object::getHeight(){ return this->aabb.max.z -this->aabb.min.z; } -mathfu::vec4 M2Object::getCombinedColor( - M2SkinProfile *skinData, - int batchIndex, - const std::vector &subMeshColors -) { - int colorIndex = skinData->batches[batchIndex]->colorIndex; - mathfu::vec4 submeshColor = mathfu::vec4(1,1,1,1); - - if ((colorIndex >= 0) && (subMeshColors.size() > colorIndex)) { - const mathfu::vec4 &color = subMeshColors[colorIndex]; - submeshColor = color; - } - - return submeshColor; -} - -float M2Object::getTextureWeight( - M2SkinProfile *skinData, - M2Data * m2Data, - int batchIndex, - int textureIndex, - const std::vector &transparencies) { - float transparency = 1.0; - - int transpLookupIndex = skinData->batches[batchIndex]->textureWeightComboIndex + textureIndex; - int transpIndex = -1; - if ((transpLookupIndex >= 0) && (transpLookupIndex < m2Data->transparency_lookup_table.size)) { - transpIndex = *m2Data->transparency_lookup_table[transpLookupIndex]; - } - - if ((transpIndex >= 0) && (transparencies.size() > transpIndex)) { - transparency = transparencies[transpIndex]; - } - - return transparency; -} - - uint8_t miniLogic(const CImVector *a2) { uint8_t v7 = a2->r; @@ -1023,7 +985,7 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v particleEmitters[i]->Update(deltaTime * 0.001 , transformMat, viewMatInv.TranslationVector3D(), nullptr, viewMat); } - this->sortMaterials(modelViewMat); + this->sortMaterials(modelViewMat); //Ribbon Emitters mathfu::vec3 nullPos(0,0,0); @@ -1058,13 +1020,37 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa placementMatrix.uPlacementMat = m_placementMatrix; m_modelWideDataBuff->m_placementMatrix->save(); } - { + if (bonesMatrices.size() > 0) { auto &bonesData = m_modelWideDataBuff->m_bonesData->getObject(); int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, bonesData.uBoneMatrixes); m_modelWideDataBuff->m_bonesData->save(); } + if (subMeshColors.size() > 0) { + auto &m2Colors = m_modelWideDataBuff->m_colors->getObject(); + int m2ColorsCnt = (int) std::min(subMeshColors.size(), (size_t) MAX_M2COLORS_NUM); + + std::copy(subMeshColors.data(), subMeshColors.data() + m2ColorsCnt, m2Colors.colors); + m_modelWideDataBuff->m_colors->save(); + } + + if (transparencies.size() > 0) { + auto &textureWeights = m_modelWideDataBuff->m_textureWeights->getObject(); + int textureWeightsCnt = (int) std::min(transparencies.size(), (size_t) MAX_TEXTURE_WEIGHT_NUM); + + std::copy(transparencies.data(), transparencies.data() + textureWeightsCnt, textureWeights.textureWeight); + m_modelWideDataBuff->m_textureWeights->save(); + } + + if (textAnimMatrices.size() > 0) { + auto &textureMatrices = m_modelWideDataBuff->m_textureMatrices->getObject(); + int textureMatricesCnt = (int) std::min(textAnimMatrices.size(), (size_t) MAX_TEXTURE_MATRIX_NUM); + + std::copy(textAnimMatrices.data(), textAnimMatrices.data() + textureMatricesCnt, textureMatrices.textureMatrix); + m_modelWideDataBuff->m_textureMatrices->save(); + } + { auto &modelFragmentData = m_modelWideDataBuff->m_modelFragmentData->getObject(); static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); @@ -1092,9 +1078,9 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_modelFragmentData->save(); } - for (auto [material, batchIndex] : m_materialArray) { - M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); - } +// for (auto [material, batchIndex] : m_materialArray) { +// M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); +// } //Manually update vertices for dynamics // updateDynamicMeshes(); @@ -1540,6 +1526,14 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } else { m_meshArray.push_back({createWaterfallMesh(), 0}); } + + { + M2Data *m2File = this->m_m2Geom->getM2Data(); + M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); + for (auto [material, batchIndex]: m_materialArray) { + M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); + } + } } HGM2Mesh @@ -1900,7 +1894,12 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) bufferBindings = m_m2Geom->getVAO(sceneRenderer, m_skinGeom.get()); //3. Create model wide uniform buffer - m_modelWideDataBuff = sceneRenderer->createM2ModelMat(m_m2Geom->m_m2Data->bones.size); + m_modelWideDataBuff = sceneRenderer->createM2ModelMat( + m_m2Geom->m_m2Data->bones.size, + m_m2Geom->m_m2Data->colors.size, + m_m2Geom->m_m2Data->texture_weights.size, + m_m2Geom->m_m2Data->texture_transforms.size + ); } void M2Object::updateDynamicMeshes() { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 3a48570d2..bca64e93f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -167,8 +167,7 @@ class M2Object { void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer); - static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; - static float getTextureWeight(M2SkinProfile *skinData, M2Data *m2data, int batchIndex, int textureIndex, const std::vector &transparencies) ; + public: void setAlwaysDraw(bool value) { m_alwaysDraw = value; diff --git a/wowViewerLib/src/engine/persistance/header/skinFileHeader.h b/wowViewerLib/src/engine/persistance/header/skinFileHeader.h index 9897e9766..c61a05006 100644 --- a/wowViewerLib/src/engine/persistance/header/skinFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/skinFileHeader.h @@ -34,7 +34,7 @@ struct M2Batch uint16_t shader_id; // See below. uint16_t skinSectionIndex; // A duplicate entry of a submesh from the list above. uint16_t geosetIndex; // See below. - uint16_t colorIndex; // A Color out of the Colors-Block or -1 if none. + int16_t colorIndex; // A Color out of the Colors-Block or -1 if none. uint16_t materialIndex; // The renderflags used on this texture-unit. uint16_t materialLayer; // Capped at 7 (see CM2Scene::BeginDraw) uint16_t textureCount; // 1 to 4. See below. Also seems to be the number of textures to load, starting at the texture lookup in the next field (0x10). diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b81b6e179..65d647fc8 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,11 +430,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -479,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -513,12 +499,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,32}, {0,0,368}, }, { @@ -534,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {8,8,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -550,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -585,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -604,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -619,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -638,16 +633,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, - }, - { - { - {0,0,0}, - {5,6,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, + }, + { + { + {0,0,0}, + {5,13,9}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -655,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -676,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -700,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -735,14 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -768,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -787,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -837,15 +829,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -871,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -905,14 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,2,16}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -938,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -956,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -971,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1005,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1039,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1058,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1108,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,14080}, + {0,1,64}, {0,0,368}, + {0,7,64}, + {0,6,4096}, + {0,4,4096}, + {0,5,256}, }, { { - {0,0,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1142,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1176,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,16}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1195,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1210,18 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,5,32}, - {0,3,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1232,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,11 +1296,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -1320,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1339,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1354,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1408,12 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, + {1,5, "uTexture"}, }, { { - {3,3,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1457,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1477,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1495,18 +1504,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,14080}, - {0,1,64}, + {0,4,96}, {0,0,368}, - {0,4,160}, + {0,1,14144}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1517,11 +1525,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1532,11 +1544,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -1552,12 +1565,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1571,51 +1584,23 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { { 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - { - 2, { - {"_0_2_bumpScale", true, 0, 1, 4, 0}, - {"_0_2_uTextMat[0]", true, 16, 4, 4, 2}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, - }}, - {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1638,7 +1623,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1923,13 +1930,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -1945,23 +1966,29 @@ const std::unordered_map> &renderFuncs) { + this->waitInDrawStageAndDeps.beginMeasurement(); int currentDrawFrame = getDrawFrameNumber(); auto &uploadCmdBuf = uploadCommandBuffers[currentDrawFrame]; @@ -801,13 +802,13 @@ void GDeviceVLK::drawFrame(const std::vector> & uint32_t imageIndex = -1; { { - this->waitInDrawStageAndDeps.beginMeasurement(); + //Wait for frameBuf CMD buffer to become available frameBufFences[currentDrawFrame]->wait(std::numeric_limits::max()); uploadFences[currentDrawFrame]->wait(std::numeric_limits::max()); frameBufFences[currentDrawFrame]->reset(); uploadFences[currentDrawFrame]->reset(); - this->waitInDrawStageAndDeps.endMeasurement(); + } auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); @@ -845,6 +846,7 @@ void GDeviceVLK::drawFrame(const std::vector> & } } + submitQueue( uploadQueue, {}, @@ -885,6 +887,7 @@ void GDeviceVLK::drawFrame(const std::vector> & ); executeDeallocators(); + this->waitInDrawStageAndDeps.endMeasurement(); } RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index e38e9f642..eec19becc 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -70,6 +70,11 @@ void GBufferVLK::destroyBuffer(BufferInternal &buffer) { VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { bool minAddressStrategy = sizeInBytes < fakeSize && fakeSize > 0; + if (sizeInBytes == 0) { + offset = 0; + return VK_SUCCESS; + } + VmaVirtualAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.size = sizeInBytes; //Size in bytes if (minAddressStrategy) { @@ -136,10 +141,11 @@ void GBufferVLK::resize(int newLength) { (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData + subBuffer->m_offset, subBuffer->m_size ); + if (subBuffer->m_size > 0) { + deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - - addSubBufferForUpload(subBuffer); + addSubBufferForUpload(subBuffer); + } subBuffer->m_offset = offset; subBuffer->m_alloc = alloc; @@ -211,14 +217,16 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy else { lock.lock(); - resize(std::max(m_bufferSize*2, BitScanMSB(m_bufferSize + fakeSize) << 1)); + resize(std::max(m_bufferSize*2, 1 << (BitScanMSB(m_bufferSize + fakeSize)+1))); lock.unlock(); return getSubBuffer(sizeInBytes, fakeSize); } } -void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &m_alloc) { - deallocateSubBuffer(currentBuffer, m_alloc); +void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation& alloc, int subBuffersize) { + if (subBuffersize > 0) { + deallocateSubBuffer(currentBuffer, alloc); + } currentSubBuffers.erase(it); } @@ -290,6 +298,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { vbCopyRegion.size = currInterval.size; } subBuffersForUpload.clear(); + subBuffersForUpload.reserve(currentSubBuffers.size()); } @@ -313,7 +322,7 @@ GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, } GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { - m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc); + m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc, m_size); } void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 2cc38519e..ecff2c319 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -109,12 +109,12 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> currentSubBuffers; - std::list> subBuffersForUpload; + std::vector> subBuffersForUpload; // uploadCache = {}; public: std::shared_ptr getSubBuffer(int sizeInBytes, int fakeSize = -1); - void deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &m_alloc); + void deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &alloc, int subBuffersize); private: void createBuffer(BufferInternal &buffer); void destroyBuffer(BufferInternal &buffer); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index 9cbcfa95a..1d6366519 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -15,7 +15,7 @@ class CBufferChunkVLK : public IBufferChunk { CBufferChunkVLK(const std::shared_ptr &mainBuffer, int realSize = -1) { m_realSize = realSize; - if (m_realSize <= 0) + if (m_realSize < 0) m_realSize = sizeof(T); subBuffer = mainBuffer->getSubBuffer(m_realSize,sizeof(T)); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index c007f632b..0c9f40ceb 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -94,7 +94,8 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr void CmdBufRecorder::bindIndexBuffer(const std::shared_ptr &buffer) { auto bufferVlk = std::dynamic_pointer_cast(buffer); - if (m_currentIndexBuffer == bufferVlk) return; + if (m_currentIndexBuffer!= nullptr && m_currentIndexBuffer->getGPUBuffer() == bufferVlk->getGPUBuffer() && + m_currentIndexBuffer->getOffset() == bufferVlk->getOffset()) return; VkDeviceSize offset = bufferVlk->getOffset(); vkCmdBindIndexBuffer(m_gCmdBuffer.m_cmdBuffer, bufferVlk->getGPUBuffer(), offset, VK_INDEX_TYPE_UINT16); @@ -113,7 +114,9 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector(buffers[i]); //firstBinding == i <- means we can only skip the start of the list; - if (firstBinding == i && m_currentVertexBuffers[i] == bufferVlk) { + if (firstBinding == i && m_currentVertexBuffers[i] != nullptr && + m_currentVertexBuffers[i]->getGPUBuffer() == bufferVlk->getGPUBuffer() && + m_currentVertexBuffers[i]->getOffset() == bufferVlk->getOffset()) { firstBinding++; continue; } diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index bbbbe4b2a..510405eae 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -149,6 +149,9 @@ class Config { //Stuff to display in UI double cullingTimePerFrame = 0; + double composerDrawTimePerFrame = 0; + double drawFuncGeneration = 0; + double deviceDrawFrame = 0; double updateTimePerFrame = 0; double mapUpdateTime = 0; double m2UpdateTime = 0; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index e66aaccb5..7e21e799f 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -33,36 +33,60 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon cullingThread = std::thread(([&]() { using namespace std::chrono_literals; + FrameCounter frameCounter; + while (!this->m_isTerminating) { - std::unique_lock lock{cullingQueueMutex}; - auto &l_cullingQueue = m_cullingQueue; - auto &l_terminated = this->m_isTerminating; - cullingCondVar.wait(lock, [&l_cullingQueue, &l_terminated]() { - return !l_cullingQueue.empty() || l_terminated; - }); - - if (l_terminated) + auto frameScenario = cullingInput.waitForNewInput(); + if (m_isTerminating) continue; - auto frameScenario = m_cullingQueue.front(); - m_cullingQueue.pop(); - lock.unlock(); - - consumeCulling(frameScenario); + frameCounter.beginMeasurement(); - //Push into updateRenderQueue - { - std::lock_guard l{updateRenderQueueMutex}; - m_updateRenderQueue.push(frameScenario); - updateRenderCondVar.notify_one(); + //Do the culling and make function for further pipeline + if (frameScenario != nullptr) { + consumeCulling(frameScenario); } + + //Pass the culling result down the pipeline + updateInput.pushInput(frameScenario); + + frameCounter.endMeasurement(); + m_apiContainer->getConfig()->cullingTimePerFrame = frameCounter.getTimePerFrame(); } })); - //Insert one temp element for balancing - m_updateRenderQueue.push(std::make_shared()); +// updateThread = std::thread(([&]() { +// using namespace std::chrono_literals; +// FrameCounter frameCounter; +// +// while (!this->m_isTerminating) { +// auto frameScenario = updateInput.waitForNewInput(); +// if (m_isTerminating) +// continue; +// +// frameCounter.beginMeasurement(); +// +// //Do the culling and make function for further pipeline +// std::shared_ptr>> renderFuncs = std::make_shared(); +// if (frameScenario != nullptr) { +// consumeUpdate(frameScenario, *renderFuncs); +// } +// +// //Pass the culling result down the pipeline +// drawInput.pushInput(renderFuncs); +// +// frameCounter.endMeasurement(); +//// m_apiContainer->getConfig()->cullingTimePerFrame = frameCounter.getTimePerFrame(); +// } +// })); } + + + //Insert one temp element for balancing + updateInput.pushInput(nullptr); + drawInput.pushInput(nullptr); + drawInput.pushInput(nullptr); } void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { @@ -75,17 +99,28 @@ void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { } -void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { +void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions) { if (frameScenario == nullptr) return; - std::vector> renderFunctions; + drawFuncGeneration.beginMeasurement(); + for (int i = 0; i < frameScenario->drawUpdateFunction.size(); i++) { renderFunctions.push_back(std::move(frameScenario->drawUpdateFunction[i]())); } + drawFuncGeneration.endMeasurement(); + m_apiContainer->getConfig()->drawFuncGeneration = drawFuncGeneration.getTimePerFrame(); +} + +void SceneComposer::consumeDraw(const std::vector> &renderFuncs) { + deviceDrawFrame.beginMeasurement(); + m_apiContainer->hDevice->drawFrame(renderFuncs); + deviceDrawFrame.endMeasurement(); - m_apiContainer->hDevice->drawFrame(renderFunctions); + m_apiContainer->getConfig()->deviceDrawFrame = deviceDrawFrame.getTimePerFrame(); } + + #define logExecution {} //#define logExecution { \ // std::cout << "Passed "<<__FUNCTION__<<" line " << __LINE__ << std::endl;\ @@ -93,34 +128,36 @@ void SceneComposer::consumeDrawAndUpdate(HFrameScenario &frameScenario) { void SceneComposer::draw(HFrameScenario frameScenario) { + composerDrawTimePerFrame.beginMeasurement(); + if (!m_supportThreads) { processCaches(10); consumeCulling(frameScenario); - consumeDrawAndUpdate(frameScenario); - } else { - { - //Add to Queue - std::lock_guard l{cullingQueueMutex}; - m_cullingQueue.push(frameScenario); - cullingCondVar.notify_one(); - } + std::vector> renderFuncs = {}; + consumeUpdate(frameScenario,renderFuncs); + consumeDraw(renderFuncs); + } else { + cullingInput.pushInput(frameScenario); { - std::unique_lock lock{updateRenderQueueMutex}; - auto &l_updateRenderQueue = m_updateRenderQueue; - updateRenderCondVar.wait(lock, [&l_updateRenderQueue]() { return !l_updateRenderQueue.empty(); }); - - auto frameScenario = m_updateRenderQueue.front(); - m_updateRenderQueue.pop(); - lock.unlock(); - - updateTimePerFrame.beginMeasurement(); - consumeDrawAndUpdate(frameScenario); - updateTimePerFrame.endMeasurement(); - } +// if (!m_firstFrame) { + auto frameScenario = updateInput.waitForNewInput(); +// auto renderFuncs = drawInput.waitForNewInput(); + std::shared_ptr>> renderFuncs = std::make_shared(); + if (frameScenario != nullptr) { + consumeUpdate(frameScenario, *renderFuncs); + } + if (renderFuncs != nullptr) { + consumeDraw(*renderFuncs); + } + } + m_firstFrame = false; +// } } // m_apiContainer->hDevice->submitDrawCommands(); m_apiContainer->hDevice->increaseFrameNumber(); + composerDrawTimePerFrame.endMeasurement(); + m_apiContainer->getConfig()->composerDrawTimePerFrame = composerDrawTimePerFrame.getTimePerFrame(); } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 5e864f145..3c92975f5 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -13,48 +13,46 @@ #include "SceneScenario.h" #include "../../engine/algorithms/FrameCounter.h" #include "../../engine/ApiContainer.h" +#include "prodConsumerChain/ProdConsumerIOConnector.h" class SceneComposer { private: HApiContainer m_apiContainer = nullptr; private: std::thread cullingThread; + std::thread updateThread; std::thread loadingResourcesThread; bool m_supportThreads = true; bool m_isTerminating = false; + bool m_firstFrame = true; - FrameCounter updateTimePerFrame; + FrameCounter composerDrawTimePerFrame; + FrameCounter deviceDrawFrame; + FrameCounter drawFuncGeneration; void consumeCulling(HFrameScenario &frameScenario); - void consumeDrawAndUpdate(HFrameScenario &frameScenario); + void consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions); + void consumeDraw(const std::vector> &renderFuncs); void processCaches(int limit); //Flip-flop delta promises int frameMod = 0; - std::mutex cullingQueueMutex; - std::condition_variable cullingCondVar; - std::queue m_cullingQueue; - - std::mutex updateRenderQueueMutex; - std::condition_variable updateRenderCondVar; - std::queue m_updateRenderQueue; - - std::condition_variable startCulling; - std::mutex cullingMutex; - - std::condition_variable startUpdate; - std::mutex cullingUpdate; + ProdConsumerIOConnector cullingInput = {m_isTerminating}; + ProdConsumerIOConnector updateInput = {m_isTerminating}; + ProdConsumerIOConnector>>> drawInput = {m_isTerminating}; public: SceneComposer(HApiContainer apiContainer); ~SceneComposer() { m_isTerminating = true; { - std::lock_guard l{ cullingQueueMutex }; - cullingCondVar.notify_one(); + cullingInput.pushInput(nullptr); + updateInput.pushInput(nullptr); + decltype(drawInput)::value_type nullParam = nullptr; + drawInput.pushInput(nullParam); } cullingThread.join(); loadingResourcesThread.join(); diff --git a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp new file mode 100644 index 000000000..8ad6ac591 --- /dev/null +++ b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 3/26/2023. +// + +#include "ProdConsumerIOConnector.h" diff --git a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h new file mode 100644 index 000000000..9726693e7 --- /dev/null +++ b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h @@ -0,0 +1,59 @@ +// +// Created by Deamon on 3/26/2023. +// + +#ifndef AWEBWOWVIEWERCPP_PRODCONSUMERIOCONNECTOR_H +#define AWEBWOWVIEWERCPP_PRODCONSUMERIOCONNECTOR_H + +#include +#include +#include + +template +class ProdConsumerIOConnector { +public: + typedef T value_type; + + + ProdConsumerIOConnector(bool &terminating) : m_terminating(terminating) { + + } + + T waitForNewInput() { + std::unique_lock lock{m_queueMutex}; + auto &l_queue = m_queue; + auto &l_terminated = this->m_terminating; + m_condVar.wait(lock, [&l_queue, &l_terminated]() { + return !l_queue.empty() || l_terminated; + }); + + + if (l_terminated) + return std::move({}); + + auto result = std::move(l_queue.front()); + m_queue.pop(); + lock.unlock(); + + return std::move(result); + } + + void pushInput(const T &newInput) { + { + std::lock_guard l{m_queueMutex}; + m_queue.push(std::move(newInput)); + m_condVar.notify_one(); + } + } + +private: + bool &m_terminating; + std::mutex m_queueMutex; + std::condition_variable m_condVar; + std::queue m_queue; +}; + + + + +#endif //AWEBWOWVIEWERCPP_PRODCONSUMERIOCONNECTOR_H diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 18518d193..8cbff8395 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -68,7 +68,7 @@ class IMapSceneBufferCreate { // Material creation //------------------------------------- - virtual std::shared_ptr createM2ModelMat(int bonesCount) = 0; + virtual std::shared_ptr createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) = 0; virtual std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index a91f4b20b..630cec3b9 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -31,6 +31,9 @@ class IM2ModelData { public: std::shared_ptr> m_placementMatrix = nullptr; std::shared_ptr> m_bonesData = nullptr; + std::shared_ptr> m_colors = nullptr; + std::shared_ptr> m_textureWeights = nullptr; + std::shared_ptr> m_textureMatrices = nullptr; std::shared_ptr> m_modelFragmentData = nullptr; }; @@ -39,9 +42,8 @@ class IM2Material : public IMaterial { int vertexShader; int pixelShader; EGxBlendEnum blendMode; - std::shared_ptr> m_vertexData = nullptr; - std::shared_ptr> m_fragmentData = nullptr; -}; + std::shared_ptr> m_vertexFragmentData = nullptr; + }; class IM2ParticleMaterial : public IMaterial { public: std::shared_ptr> m_fragmentData = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index d00a4e384..588d34631 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -175,19 +175,21 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & const M2MaterialTemplate &m2MaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; - auto vertexData = std::make_shared>(uboBuffer); - auto fragmentData = std::make_shared>(uboBuffer); + auto vertexFragmentData = std::make_shared>(uboBuffer); + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) - .ubo(4, vertexData->getSubBuffer()) - .ubo(5, fragmentData->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)->getSubBuffer()) + .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)->getSubBuffer()) + .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) + .ubo(7, vertexFragmentData->getSubBuffer()); }) .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -196,9 +198,8 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & .texture(8, std::dynamic_pointer_cast(m2MaterialTemplate.textures[2])) .texture(9, std::dynamic_pointer_cast(m2MaterialTemplate.textures[3])); }) - .toMaterial([&vertexData, &fragmentData](IM2Material *instance) -> void { - instance->m_fragmentData = fragmentData; - instance->m_vertexData = vertexData; + .toMaterial([&vertexFragmentData](IM2Material *instance) -> void { + instance->m_vertexFragmentData = vertexFragmentData; }); material->blendMode = pipelineTemplate.blendMode; @@ -426,11 +427,14 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { return nullptr; } -std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount) { +std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); BufferChunkHelperVLK::create(uboBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); return result; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 725534eaf..2b846b083 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -51,7 +51,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { // Material creation //------------------------------------- - std::shared_ptr createM2ModelMat(int bonesCount) override; + std::shared_ptr createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) override; std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) override; From 20ad5ca9a96484b9dd3f49c67d4d8978bb2cb472 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 2 Apr 2023 19:39:15 +0300 Subject: [PATCH 059/212] skybox --- src/ui/FrontendUI.cpp | 2 +- .../src/engine/objects/ViewsObjects.cpp | 10 +++--- .../src/engine/objects/ViewsObjects.h | 3 ++ .../src/engine/objects/scenes/map.cpp | 31 +++++++++++++++++-- wowViewerLib/src/gapi/interface/sortLambda.h | 12 +++---- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 16 +++++++++- .../CommandBufferRecorder.cpp | 6 ++-- .../src/renderer/mapScene/MapScenePlan.h | 2 +- .../renderer/mapScene/MapSceneRenderer.cpp | 25 ++++++++++++++- .../src/renderer/mapScene/MapSceneRenderer.h | 4 ++- .../vulkan/MapSceneRenderForwardVLK.cpp | 24 +++++++++----- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- 12 files changed, 108 insertions(+), 29 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 4ee91281e..b57e9841c 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1551,7 +1551,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do { ViewPortDimensions dimension = { {0, 0}, - {canvWidth, canvHeight} + {static_cast(canvWidth), static_cast(canvHeight)} }; if (m_sceneRenderer != nullptr) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index f37497c4f..768949249 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -32,11 +32,6 @@ void GeneralView::collectMeshes(std::vector &opaqueMeshes, std::vectorcollectMeshes(opaqueMeshes, transparentMeshes, renderOrder); } - -// for (auto& m2 : drawnM2s) { -// m2->collectMeshes(renderedThisFrame, renderOrder); -// m2->drawParticles(renderedThisFrame , renderOrder); -// } } void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos) { @@ -181,6 +176,7 @@ void InteriorView::setM2Lights(std::shared_ptr &m2Object) { HExteriorView FrameViewsHolder::getOrCreateExterior(const MathHelper::FrustumCullingData &frustumData) { if (exteriorView == nullptr) { exteriorView = std::make_shared(); + skyBoxView = std::make_shared(); exteriorView->frustumData = frustumData; } @@ -199,3 +195,7 @@ HInteriorView FrameViewsHolder::createInterior(const MathHelper::FrustumCullingD HExteriorView FrameViewsHolder::getExterior() { return exteriorView; } + +HExteriorView FrameViewsHolder::getSkybox() { + return skyBoxView; +} diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index cde914ee9..a6a825a71 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -77,6 +77,8 @@ class FrameViewsHolder { public: HExteriorView getOrCreateExterior(const MathHelper::FrustumCullingData &frustumData); HExteriorView getExterior(); + HExteriorView getSkybox(); + HInteriorView createInterior(const MathHelper::FrustumCullingData &frustumData); const std::vector &getInteriorViews() { @@ -84,6 +86,7 @@ class FrameViewsHolder { } private: HExteriorView exteriorView = nullptr ; + HExteriorView skyBoxView = nullptr ; std::vector interiorViews = {}; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index a07e0fe70..a63345241 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -482,7 +482,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); - + auto skyBoxView = mapRenderPlan->viewsHolder.getSkybox(); if (m_wdlObject != nullptr) { m_wdlObject->checkSkyScenes( stateForConditions, @@ -494,7 +494,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams if (config->renderSkyDom) { for (auto &model : m_exteriorSkyBoxes) { if (model != nullptr) { - exteriorView->m2List.addToDraw(model); + skyBoxView->m2List.addToDraw(model); } } } @@ -1299,9 +1299,11 @@ void Map::createAdtFreeLamdas() { void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan) { int processedThisFrame = 0; + int m2ProcessedThisFrame = 0; int wmoProcessedThisFrame = 0; int wmoGroupsProcessedThisFrame = 0; // if (m_api->getConfig()->getRenderM2()) { + for (auto &m2Object : renderPlan->m2Array.getToLoadMain()) { if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); @@ -1309,6 +1311,19 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende for (auto &m2Object : renderPlan->m2Array.getToLoadGeom()) { if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); + m2ProcessedThisFrame++; + if (m2ProcessedThisFrame > 100) break; + } + + if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { + for (auto &m2Object : skyboxView->m2List.getToLoadMain()) { + if (m2Object == nullptr) continue; + m2Object->doLoadMainFile(); + } + for (auto &m2Object: skyboxView->m2List.getToLoadGeom()) { + if (m2Object == nullptr) continue; + m2Object->doLoadGeom(sceneRenderer); + } } // } @@ -1396,6 +1411,12 @@ void Map::update(const HMapRenderPlan &renderPlan) { } }, tbb::simple_partitioner()); + if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { + for (auto &m2Object : skyBoxView->m2List.getDrawn()) { + m2Object->update(deltaTime, cameraVec3, lookAtMat); + } + } + m2UpdateframeCounter.endMeasurement(); } @@ -1490,6 +1511,12 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { renderPlan->frameDependentData); } } + if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { + for (auto &m2Object : skyBoxView->m2List.getDrawn()) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } // for (auto &wmoGroupObject : cullStage->wmoGroupArray.getToDraw()) { // if (wmoGroupObject == nullptr) continue; diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index 3217b3c8b..e1b4ad89d 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -32,13 +32,13 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { ISortableMesh *pB1 = dynamic_cast(pB); if (pA1->priorityPlane()!= pB1->priorityPlane()) { - return pB1->priorityPlane() > pA1->priorityPlane(); + return pB1->priorityPlane() < pA1->priorityPlane(); } - if (pA1->getSortDistance() < pB1->getSortDistance()) { + if (pA1->getSortDistance() > pB1->getSortDistance()) { return true; } - if (pA1->getSortDistance() > pB1->getSortDistance()) { + if (pA1->getSortDistance() < pB1->getSortDistance()) { return false; } @@ -48,14 +48,14 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { IM2Mesh *pB2 = dynamic_cast(pB); if (pB2->layer() != pA2->layer()) { - return pB2->layer() < pA2->layer(); + return pB2->layer() > pA2->layer(); } } } else { - if (pA->getSortDistance() < pB->getSortDistance()) { + if (pA->getSortDistance() > pB->getSortDistance()) { return true; } - if (pA->getSortDistance() > pB->getSortDistance()) { + if (pA->getSortDistance() < pB->getSortDistance()) { return false; } } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index eec19becc..0a1677ed4 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -44,6 +44,7 @@ void GBufferVLK::createBuffer(BufferInternal &buffer) { //Create virtual buffer off this native buffer VmaVirtualBlockCreateInfo blockCreateInfo = {}; blockCreateInfo.size = m_bufferSize; + blockCreateInfo.flags = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT; VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &buffer.virtualBlock); if(res != VK_SUCCESS) @@ -95,7 +96,20 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, } void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc) { - vmaVirtualFree(buffer.virtualBlock, alloc); + + //Destruction of this virtualBlock happens only in deallocation queue. + //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, + //the virtualBlock was still not been free'd + //So there would be no error + + auto l_virtualBlock = buffer.virtualBlock; + auto l_alloc = alloc; + + m_device->addDeallocationRecord( + [l_virtualBlock, l_alloc]() { + vmaVirtualFree(l_virtualBlock, l_alloc); + + }); } void GBufferVLK::uploadData(void *data, int length) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 0c9f40ceb..b7ba78b74 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -236,7 +236,7 @@ void CmdBufRecorder::createViewPortTypes(const std::array &areaOffse usualViewport.height = areaSize[1]; usualViewport.x = areaOffset[0]; usualViewport.y = areaOffset[1]; - if (invertZ) { + if (!invertZ) { usualViewport.minDepth = 0; usualViewport.maxDepth = 0.990f; } else { @@ -246,7 +246,7 @@ void CmdBufRecorder::createViewPortTypes(const std::array &areaOffse VkViewport &mapAreaViewport = viewportsForThisStage[(int)ViewportType::vp_mapArea]; mapAreaViewport = usualViewport; - if (invertZ) { + if (!invertZ) { mapAreaViewport.minDepth = 0.991f; mapAreaViewport.maxDepth = 0.996f; } else { @@ -256,7 +256,7 @@ void CmdBufRecorder::createViewPortTypes(const std::array &areaOffse VkViewport &skyBoxViewport = viewportsForThisStage[(int)ViewportType::vp_skyBox]; skyBoxViewport = usualViewport; - if (invertZ) { + if (!invertZ) { skyBoxViewport.minDepth = 0.997f; skyBoxViewport.maxDepth = 1.0f; } else { diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index fa44a6972..b110f6fb2 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -35,7 +35,7 @@ struct MapRenderPlan { WMOListContainer wmoArray; WMOGroupListContainer wmoGroupArray; - //Settings for the frame + }; typedef std::shared_ptr HMapRenderPlan; #endif //AWEBWOWVIEWERCPP_MAPSCENEPLAN_H diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index f196d4e8f..033172b40 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -19,15 +19,25 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes) { +void MapSceneRenderer::collectMeshes(const std::shared_ptr &renderPlan, + const std::shared_ptr> &hopaqueMeshes, + const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hSkyOpaqueMeshes, + const std::shared_ptr> &hSkyTransparentMeshes) { mapProduceUpdateCounter.beginMeasurement(); auto &opaqueMeshes = *hopaqueMeshes; auto &transparentMeshes = *htransparentMeshes; + auto &skyOpaqueMeshes = *hSkyOpaqueMeshes; + auto &skyTransparentMeshes = *hSkyTransparentMeshes; + opaqueMeshes.reserve(30000); transparentMeshes.reserve(30000); + skyOpaqueMeshes.reserve(1000); + skyTransparentMeshes.reserve(1000); + const auto& cullStage = renderPlan; auto fdd = cullStage->frameDependentData; @@ -81,6 +91,15 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); } + + auto skyBoxView = cullStage->viewsHolder.getSkybox(); + if (skyBoxView) { + for (auto &m2Object : skyBoxView->m2List.getDrawn()) { + if (m2Object == nullptr) continue; + m2Object->collectMeshes(skyOpaqueMeshes, skyTransparentMeshes, m_viewRenderOrder); + m2Object->drawParticles(skyOpaqueMeshes, skyTransparentMeshes, m_viewRenderOrder); + } + } } m2CollectMeshCounter.endMeasurement(); @@ -89,6 +108,10 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende if (transparentMeshes.size() > 1) { tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); } + if (skyTransparentMeshes.size() > 1) { + tbb::parallel_sort(skyTransparentMeshes.begin(), skyTransparentMeshes.end(), SortMeshes); + } + sortMeshCounter.endMeasurement(); mapProduceUpdateCounter.endMeasurement(); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index eced4995a..070d0da16 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -72,7 +72,9 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public void collectMeshes(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, - const std::shared_ptr> &htransparentMeshes); + const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hSkyOpaqueMeshes, + const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 588d34631..55fd2e29f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -297,7 +297,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } -inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh) { +inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { if (mesh == nullptr) return; const auto &meshVlk = std::dynamic_pointer_cast(mesh); @@ -322,7 +322,7 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM } //5. Set view port - cmdBuf.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + cmdBuf.setViewPort(viewportType); //6. Set scissors if (meshVlk->scissorEnabled()) { @@ -376,8 +376,13 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto opaqueMeshes = std::make_shared>(); auto transparentMeshes = std::make_shared>(); - collectMeshes(framePlan, opaqueMeshes, transparentMeshes); - return createRenderFuncVLK([opaqueMeshes, transparentMeshes, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + auto skyOpaqueMeshes = std::make_shared>(); + auto skyTransparentMeshes = std::make_shared>(); + + collectMeshes(framePlan, opaqueMeshes, transparentMeshes, skyOpaqueMeshes, skyTransparentMeshes); + return createRenderFuncVLK([opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes, + l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { // --------------------- // Upload stuff // --------------------- @@ -409,11 +414,16 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha ); for (auto const &mesh: *opaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } + for (auto const &mesh: *skyOpaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + } + for (auto const &mesh: *skyTransparentMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } - for (auto const &mesh: *transparentMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 2b846b083..ea82ea286 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -17,7 +17,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { ~MapSceneRenderForwardVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; - inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh); + inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType); std::shared_ptr getLastCreatedPlan() override; From ceddb2a30480c535ad1396f604b02efde45e43f6 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 7 Apr 2023 21:21:09 +0300 Subject: [PATCH 060/212] adt rendering --- src/ui/FrontendUI.cpp | 4 +- .../glsl/forwardRendering/adtShader.vert | 9 +- .../src/engine/objects/adt/adtObject.cpp | 227 ++-- .../src/engine/objects/adt/adtObject.h | 11 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 11 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 + .../src/engine/shader/ShaderDefinitions.h | 1005 ++++++++--------- .../src/gapi/interface/meshes/IMesh.h | 3 - .../src/gapi/vulkan/TextureManagerVLK.cpp | 2 +- .../src/gapi/vulkan/TextureManagerVLK.h | 11 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 29 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 7 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 3 + wowViewerLib/src/include/config.h | 4 +- .../src/renderer/frame/SceneComposer.cpp | 4 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 15 +- .../src/renderer/mapScene/MapSceneRenderer.h | 28 +- .../mapScene/materials/IMaterialStructs.h | 15 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 87 +- .../vulkan/MapSceneRenderForwardVLK.h | 5 + 21 files changed, 754 insertions(+), 732 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index b57e9841c..4d78ddbca 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -165,9 +165,9 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::NewLine(); if (ImGui::CollapsingHeader("Elapsed times")) { - ImGui::Text("Elapsed time on deviceDrawFrame : %.3f ms", m_api->getConfig()->deviceDrawFrame); + ImGui::Text("Elapsed time on consumeUpdate : %.3f ms", m_api->getConfig()->consumeUpdate); + ImGui::Text("Elapsed time on consumeDraw : %.3f ms", m_api->getConfig()->consumeDraw); ImGui::Text("Elapsed time on composerDrawTimePerFrame : %.3f ms", m_api->getConfig()->composerDrawTimePerFrame); - ImGui::Text("Elapsed time on drawFuncGeneration : %.3f ms", m_api->getConfig()->drawFuncGeneration); ImGui::Text("Elapsed time on culling : %.3f ms", m_api->getConfig()->cullingTimePerFrame); ImGui::Text("- Elapsed time on cullCreateVarsCounter: %.3f ms", m_api->getConfig()->cullCreateVarsCounter); ImGui::Text("- Elapsed time on cullGetCurrentWMOCounter: %.3f ms", m_api->getConfig()->cullGetCurrentWMOCounter); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index e6e94d6b5..4ce089421 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -50,8 +50,13 @@ void main() { X 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ - float iX = mod(gl_VertexIndex, 17.0); - float iY = floor(gl_VertexIndex/17.0); + + //With current implementation ADT's VBO is combined buffer, which contains all vertexes from all MCNK of ADT + //Thus, we first need to get vertexNumber within MCNK + + int indexInMCNK = gl_VertexIndex % (9 * 9 + 8 * 8); + float iX = mod(indexInMCNK, 17.0); + float iY = floor(indexInMCNK/17.0); if (iX > 8.01) { iY = iY + 0.5; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 2c4643ff4..6e094139d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -15,37 +15,16 @@ #include "tbb/blocked_range2d.h" #include "../../../gapi/interface/materials/IMaterial.h" -PACK( - struct AdtVertex { - mathfu::vec3_packed pos; - mathfu::vec3_packed normal; - mathfu::vec4_packed mccv; - mathfu::vec4_packed mclv; - } -); - -static std::array adtVertexBufferBinding = {{ - {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, - {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, - {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, - {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, -}}; - -static std::array adtVertexBufferLODBinding = {{ - {+adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 8, 0 }, - {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} -}}; - -void AdtObject::loadingFinished() { +void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { // std::cout << "AdtObject::loadingFinished finished called"; texturesPerMCNK = std::vector(m_adtFile->mcnkRead+1); animationTranslationPerMCNK = std::vector(m_adtFile->mcnkRead+1); - createVBO(); + createVBO(sceneRenderer); loadAlphaTextures(); - createMeshes(); + createMeshes(sceneRenderer); // createIndexVBO(); calcBoundingBoxes(); @@ -428,7 +407,7 @@ void AdtObject::loadWater() { } -void AdtObject::createVBO() { +void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { /* 1. help index + Heights + texCoords + */ std::vector vboArray ; @@ -517,30 +496,21 @@ void AdtObject::createVBO() { /* 1.3 Make combinedVbo */ HGDevice device = m_api->hDevice; //TODO: -// combinedVbo = device->createVertexBuffer(); -// combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(AdtVertex)); + combinedVbo = sceneRenderer->createADTVertexBuffer(vboArray.size()*sizeof(AdtVertex)); + combinedVbo->uploadData(vboArray.data(), vboArray.size()*sizeof(AdtVertex)); /* 2. Strips */ if (m_adtFile->strips.size() > 0) { -// stripIBO = device->createIndexBuffer(); -// stripIBO->uploadData(m_adtFile->strips.data(), m_adtFile->strips.size() * sizeof(int16_t)); + stripIBO = sceneRenderer->createADTIndexBuffer(m_adtFile->strips.size() * sizeof(int16_t)); + stripIBO->uploadData(m_adtFile->strips.data(), m_adtFile->strips.size() * sizeof(int16_t)); - adtVertexBindings = device->createVertexBufferBindings(); - adtVertexBindings->setIndexBuffer(stripIBO); - - auto const adtBindings = std::vector(adtVertexBufferBinding.begin(), - adtVertexBufferBinding.end()); - - adtVertexBindings->addVertexBufferBinding(combinedVbo, adtBindings); - adtVertexBindings->save(); + adtVertexBindings = sceneRenderer->createADTVAO(combinedVbo, stripIBO); } else { stripIBO = nullptr; adtVertexBindings = nullptr; } - - //Sometimes mvli can be zero, while there is still data in floatDataBlob if (m_adtFileLod!= nullptr && m_adtFileLod->getStatus()==FileStatus::FSLoaded && m_adtFileLod->floatDataBlob_len > 0 && m_adtFileLod->mvli_len > 0) { //Generate MLLL buffers @@ -612,23 +582,22 @@ void AdtObject::calcBoundingBoxes() { } } -void AdtObject::createMeshes() { +void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; auto adtFileTex = m_adtFileTex; auto adtFile = m_adtFile; - /* - adtWideBlockPS = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::modelWideBlockPS)); - adtWideBlockPS = nullptr; int useHeightMixFormula = m_wdtFile->mphd->flags.adt_has_height_texturing > 0; -// int useHeightMixFormula = 1; auto api = m_api; - adtWideBlockPS->setUpdateHandler([api, useHeightMixFormula](auto &data, const HFrameDependantData &frameDepedantData){ - auto *adtWideblockPS = &data; - adtWideblockPS->useHeightMixFormula[0] = useHeightMixFormula; - }); + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.triCCW = true; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; if (adtVertexBindings != nullptr) { for (int i = 0; i < 256; i++) { @@ -636,106 +605,86 @@ void AdtObject::createMeshes() { //if (m_adtFile->mapTile[i].nLayers <= 0) continue; bool noLayers = m_adtFileTex->mcnkStructs[i].mcly == nullptr || m_adtFileTex->mcnkStructs[i].mclyCnt <= 0; - HGShaderPermutation hgShaderPermutation = device->getShader("adtShader", "adtShader", nullptr); - gMeshTemplate aTemplate(adtVertexBindings); - PipelineTemplate pipelineTemplate; - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.triCCW = true; - pipelineTemplate.depthWrite = true; - pipelineTemplate.depthCulling = true; - pipelineTemplate.backFaceCulling = true; - pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + ADTMaterialTemplate adtMaterialTemplate; + fillTextureForMCNK(device, i, noLayers, adtMaterialTemplate); + auto adtMaterial = sceneRenderer->createAdtMaterial(pipelineTemplate, adtMaterialTemplate); + //Create mesh + gMeshTemplate aTemplate(adtVertexBindings); aTemplate.meshType = MeshType::eAdtMesh; aTemplate.start = m_adtFile->stripOffsets[i] * 2; aTemplate.end = m_adtFile->stripOffsets[i + 1] - m_adtFile->stripOffsets[i]; -// aTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); -// aTemplate.ubo[1] = nullptr; -// aTemplate.ubo[2] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockVS)); -// aTemplate.ubo[3] = adtWideBlockPS; -// aTemplate.ubo[4] = m_api->hDevice->createUniformBufferChunk(sizeof(ADT::meshWideBlockPS)); - - aTemplate.texture = std::vector(9, nullptr); - - int chunkIndex = i; - std::shared_ptr> meshWideBlockPS = nullptr; - meshWideBlockPS->setUpdateHandler([&api, adtFileTex, noLayers, chunkIndex, this](auto &data, const HFrameDependantData &frameDepedantData) { - auto &blockPS = data; - - for (int j = 0; j < 4; j++) { - blockPS.uHeightOffset[j] = 0.0f; - blockPS.uHeightScale[j] = 1.0f; - blockPS.animationMat[j] = mathfu::mat4::Identity(); - } + HGMesh hgMesh = sceneRenderer->createMesh(aTemplate, adtMaterial); + adtMeshes[i] = hgMesh; + adtMaterials[i] = adtMaterial; + + //Upload data to static UBO + auto &matVSPS = adtMaterial->m_materialVSPS->getObject(); + matVSPS.uPos = mathfu::vec4( + this->m_adtFile->mapTile[i].position.x, + this->m_adtFile->mapTile[i].position.y, + this->m_adtFile->mapTile[i].position.z, + 0 + ); + for (int j = 0; j < 4; j++) { + matVSPS.uHeightOffset[j] = 0.0f; + matVSPS.uHeightScale[j] = 1.0f; - for (int j = 0; j < adtFileTex->mcnkStructs[chunkIndex].mclyCnt; j++) { - if ((adtFileTex->mtxp_len > 0) && !noLayers) { - auto const &textureParams = adtFileTex->mtxp[adtFileTex->mcnkStructs[chunkIndex].mcly[j].textureId]; - blockPS.uHeightOffset[j] = textureParams.heightOffset; - blockPS.uHeightScale[j] = textureParams.heightScale; - } - blockPS.animationMat[j] = this->texturesPerMCNK[chunkIndex].animTexture[j]; + } + for (int j = 0; j < adtFileTex->mcnkStructs[i].mclyCnt; j++) { + if ((adtFileTex->mtxp_len > 0) && !noLayers) { + auto const &textureParams = adtFileTex->mtxp[adtFileTex->mcnkStructs[i].mcly[j].textureId]; + matVSPS.uHeightOffset[j] = textureParams.heightOffset; + matVSPS.uHeightScale[j] = textureParams.heightScale; } - }); - - std::shared_ptr> meshWideBlockVS = nullptr; - meshWideBlockVS->setUpdateHandler([this, i](auto &data, const HFrameDependantData &frameDepedantData) { - auto &blockVS = data; - blockVS.uPos = mathfu::vec4( - this->m_adtFile->mapTile[i].position.x, - this->m_adtFile->mapTile[i].position.y, - this->m_adtFile->mapTile[i].position.z, - 0 - ); - }); - - - if (m_adtFileTex->mtxp_len > 0 && !noLayers) { - for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { - auto const &textureParams = m_adtFileTex->mtxp[m_adtFileTex->mcnkStructs[i].mcly[j].textureId]; + } + adtMaterial->m_materialVSPS->save(); + } + } +} - HGTexture layer_height = device->getWhiteTexturePixel(); - if (textureParams.flags.do_not_load_specular_or_height_texture_but_use_cubemap == 0) { - if (!feq(textureParams.heightScale, 0.0)) { - layer_height = getAdtHeightTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); - } - } +void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMaterialTemplate &adtMaterialTemplate) { + if (m_adtFileTex->mtxp_len > 0 && !noLayers) { + for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { + auto const &textureParams = m_adtFileTex->mtxp[m_adtFileTex->mcnkStructs[i].mcly[j].textureId]; - aTemplate.texture[j + 5] = layer_height; - } - } else { - for (int j = 0; j < 4; j++) { - aTemplate.texture[j + 5] = device->getWhiteTexturePixel(); + HGTexture layer_height = device->getWhiteTexturePixel(); + if (textureParams.flags.do_not_load_specular_or_height_texture_but_use_cubemap == 0) { + if (!feq(textureParams.heightScale, 0.0)) { + layer_height = getAdtHeightTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); } } - if (!noLayers) { - aTemplate.texture[4] = alphaTextures[i]; - } else { - aTemplate.texture[4] = device->getBlackTexturePixel(); - } + adtMaterialTemplate.textures[j + 5] = layer_height; + } + } else { + for (int j = 0; j < 4; j++) { + adtMaterialTemplate.textures[j + 5] = device->getWhiteTexturePixel(); + } + } - if (!noLayers) { - for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { - auto &layerDef = m_adtFileTex->mcnkStructs[i].mcly[j]; + if (!noLayers) { + adtMaterialTemplate.textures[4] = alphaTextures[i]; + } else { + adtMaterialTemplate.textures[4] = device->getBlackTexturePixel(); + } - HGTexture layer_x = getAdtTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); -// BlpTexture &layer_spec = getAdtSpecularTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); - aTemplate.texture[j] = layer_x; - } - } else { - for (int j = 0; j < 4; j++) { - aTemplate.texture[j] = device->getWhiteTexturePixel(); - } - } + if (!noLayers) { + for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { + auto &layerDef = m_adtFileTex->mcnkStructs[i].mcly[j]; - HGMesh hgMesh = device->createMesh(aTemplate); - adtMeshes[i] = hgMesh; + HGTexture layer_x = getAdtTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); +// BlpTexture &layer_spec = getAdtSpecularTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); + adtMaterialTemplate.textures[j] = layer_x; + } + } else { + for (int j = 0; j < 4; j++) { + adtMaterialTemplate.textures[j] = device->getWhiteTexturePixel(); } - }*/ + } } void AdtObject::loadAlphaTextures() { @@ -847,10 +796,10 @@ FileStatus AdtObject::getLoadedStatus() { } -void AdtObject::doPostLoad() { +void AdtObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (getLoadedStatus() == FileStatus::FSLoaded) { - this->loadingFinished(); + this->loadingFinished(sceneRenderer); m_loaded = true; } } @@ -918,6 +867,15 @@ void AdtObject::update(animTime_t deltaTime ) { } } } + + for (int i = 0; i < 256; i++) { + auto &psBlock = adtMaterials[i]->m_materialPS->getObject(); + + for (int j = 0; j < 4; j++) { + psBlock.animationMat[j] = this->texturesPerMCNK[i].animTexture[j]; + } + adtMaterials[i]->m_materialPS->save(); + } } void AdtObject::uploadGeneratorBuffers(ADTObjRenderRes &adtRes) { @@ -929,12 +887,7 @@ void AdtObject::uploadGeneratorBuffers(ADTObjRenderRes &adtRes) { for (int i = 0; i < adtMeshes.size(); i++) { bool noLayers = m_adtFileTex->mcnkStructs[i].mcly == nullptr || m_adtFileTex->mcnkStructs[i].mclyCnt <= 0; - - - - } - } HGTexture AdtObject::getAdtTexture(int textureId) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index f093def0d..95c7454ef 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -48,7 +48,7 @@ class AdtObject { void update(animTime_t deltaTime); void uploadGeneratorBuffers(ADTObjRenderRes &adtRes); - void doPostLoad(); + void doPostLoad(const HMapSceneBufferCreate &sceneRenderer); int getAreaId(int mcnk_x, int mcnk_y); @@ -89,9 +89,9 @@ class AdtObject { int length; }; - void loadingFinished(); - void createVBO(); - void createMeshes(); + void loadingFinished(const HMapSceneBufferCreate &sceneRenderer); + void createVBO(const HMapSceneBufferCreate &sceneRenderer); + void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void loadAlphaTextures(); HApiContainer m_api; @@ -132,6 +132,7 @@ class AdtObject { std::array adtMeshes = {}; + std::array, 16*16> adtMaterials = {}; //16x16, then layer std::array, 16*16> waterMeshes = {}; std::vector adtLodMeshes; @@ -188,6 +189,8 @@ class AdtObject { const MathHelper::FrustumCullingData &frustumData, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates); + + void fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMaterialTemplate &adtMaterialTemplate); }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index da10fb93c..56dc74977 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1379,8 +1379,8 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16)) * 2; meshTemplate.end = skinSection->indexCount; - meshTemplate.skybox = m_boolSkybox; +/* HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; meshTemplate.texture.resize(5); meshTemplate.texture[0] = getTexture(0); //mask @@ -1388,6 +1388,7 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshTemplate.texture[2] = getTexture(2); //noise meshTemplate.texture[3] = getTexture(3); //bumpTexture meshTemplate.texture[4] = getTexture(4); //normalTex + */ std::shared_ptr> waterFallMeshWideBlockVS = nullptr; waterFallMeshWideBlockVS->setUpdateHandler([this, skinData, m2Data, wfv3Data](auto &data, const HFrameDependantData &frameDepedantData){ @@ -1573,7 +1574,6 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; - meshTemplate.skybox = m_boolSkybox; auto m2Mesh = sceneRenderer->createM2Mesh(meshTemplate, m2Material, m2Batch->materialLayer, m2Batch->priorityPlane); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index a63345241..338a8bb9c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -308,9 +308,6 @@ std::tuple> createSkyMesh(const HMapSc gMeshTemplate meshTemplate(skyBindings); meshTemplate.meshType = MeshType::eGeneralMesh; - meshTemplate.skybox = true; - - meshTemplate.texture.resize(0); if (conusFor0x4Sky) { meshTemplate.start = 198 * 2; @@ -1097,7 +1094,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, if (candidates.size() > 0) { results = std::vector(candidates.size(), 0xFFFFFFFF); - oneapi::tbb::parallel_for(tbb::blocked_range(0, candidates.size(), 1000), + oneapi::tbb::parallel_for(tbb::blocked_range(0, candidates.size(), 2000), [&](tbb::blocked_range &r) { // for (size_t i = r.begin(); i != r.end(); ++i) { // auto &m2ObjectCandidate = tmpVector[i]; @@ -1312,7 +1309,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); m2ProcessedThisFrame++; - if (m2ProcessedThisFrame > 100) break; +// if (m2ProcessedThisFrame > 100) break; } if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { @@ -1339,7 +1336,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende } for (auto &adtObject : renderPlan->adtArray) { - adtObject->adtObject->doPostLoad(); + adtObject->adtObject->doPostLoad(sceneRenderer); } if (quadBindings == nullptr) @@ -1403,7 +1400,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { { m2UpdateframeCounter.beginMeasurement(); - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 200), + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 1000), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { auto& m2Object = m2ToDraw[i]; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 663a58cca..d5425befd 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -269,12 +269,14 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere } } + /* if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); meshTemplate.texture[0] = m_api->hDevice->createBlpTexture(htext, true, true); } else { meshTemplate.texture[0] = m_api->hDevice->getBlackTexturePixel(); } + */ //TODO: // meshTemplate.ubo[0] = nullptr;//m_api->getSceneWideUniformBuffer(); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 65d647fc8..f0d3452c7 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,16}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,4,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,11 +445,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -464,12 +479,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,11 +513,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -519,20 +534,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +550,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +585,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +604,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +619,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +638,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, - }, + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +655,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +676,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +700,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +735,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +768,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +787,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +803,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,15 +837,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,1,12}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -863,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +905,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +938,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +956,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +971,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,4,16}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1005,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1024,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1039,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1058,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1108,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,14080}, - {0,1,64}, {0,0,368}, - {0,7,64}, - {0,6,4096}, - {0,4,4096}, - {0,5,256}, }, { { - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1142,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1176,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1195,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1210,20 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1234,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,11 +1288,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -1330,15 +1322,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1341,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1356,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1391,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1410,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, }, { { + {3,3,1}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1426,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1459,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1479,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,17 +1497,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, + {0,3,14080}, + {0,1,64}, {0,0,368}, - {0,1,14144}, + {0,7,64}, + {0,6,4096}, }, { { - {1,1,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1525,15 +1520,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, }, { { {0,0,0}, - {5,9,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1544,12 +1535,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,48}, {0,0,368}, }, { @@ -1565,12 +1555,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {8,8,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1584,23 +1574,7 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1622,6 +1596,18 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"waterfallShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_0_4_values0", true, 0, 1, 4, 0}, + {"_0_4_values1", true, 16, 1, 4, 0}, + {"_0_4_values2", true, 32, 1, 4, 0}, + {"_0_4_values3", true, 48, 1, 4, 0}, + {"_0_4_values4", true, 64, 1, 4, 0}, + {"_0_4_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1966,29 +1954,23 @@ const std::unordered_map texture = {}; bool scissorEnabled = false; std::array scissorOffset = {0,0}; diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index 69def26e7..6185b8f22 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -54,7 +54,7 @@ void TextureManagerVLK::createUpdateCallback() { if (auto shared_this = weak_this.lock()) { std::lock_guard lock(shared_this->textUpdateMutex); - shared_this->m_texturesReadyToBeUploaded.push_back(std::weak_ptr(texture)); + shared_this->m_texturesReadyToBeUploadedNext.push_back(std::weak_ptr(texture)); } }; } diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 9ab4a1f30..0b3159e9e 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -22,6 +22,16 @@ class TextureManagerVLK : public std::enable_shared_from_this HGTexture createTexture(); MutexLockedVector> getReadyToUploadTextures() { + + uint32_t uploadedThisFrame = std::min(m_texturesReadyToBeUploadedNext.size(), 50); + + decltype(m_texturesReadyToBeUploaded)::const_iterator first = m_texturesReadyToBeUploadedNext.begin(); + decltype(m_texturesReadyToBeUploaded)::const_iterator last = m_texturesReadyToBeUploadedNext.begin() + uploadedThisFrame; + + m_texturesReadyToBeUploaded = decltype(m_texturesReadyToBeUploaded)(first, last); + + m_texturesReadyToBeUploadedNext.erase(m_texturesReadyToBeUploadedNext.begin(), m_texturesReadyToBeUploadedNext.begin() + uploadedThisFrame); + return MutexLockedVector>(m_texturesReadyToBeUploaded, textUpdateMutex, true); } @@ -54,6 +64,7 @@ class TextureManagerVLK : public std::enable_shared_from_this std::mutex textUpdateMutex; std::vector> m_texturesReadyToBeUploaded; + std::vector> m_texturesReadyToBeUploadedNext; std::mutex blpTextureLoadMutex; std::list> m_blpTextLoadQueue; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 0a1677ed4..c246a51dc 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -158,7 +158,7 @@ void GBufferVLK::resize(int newLength) { if (subBuffer->m_size > 0) { deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - addSubBufferForUpload(subBuffer); + addSubBufferForUpload(*it); } subBuffer->m_offset = offset; @@ -209,10 +209,13 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy VmaVirtualAllocation alloc; VkDeviceSize offset; - std::unique_lock lock(m_mutex,std::defer_lock); - lock.lock(); - VkResult res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc, offset); - lock.unlock(); + std::unique_lock lock(m_mutex, std::defer_lock); + VkResult res = VK_ERROR_OUT_OF_DEVICE_MEMORY; + if (sizeInBytes < m_bufferSize) { + lock.lock(); + res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc, offset); + lock.unlock(); + } if(res == VK_SUCCESS) { @@ -258,7 +261,7 @@ void GBufferVLK::save(int length) { uploadFromStaging(0, 0, length); } -void GBufferVLK::addSubBufferForUpload(const std::shared_ptr &buffer) { +void GBufferVLK::addSubBufferForUpload(const std::weak_ptr &buffer) { std::lock_guard lock(dataToBeUploadedMtx); subBuffersForUpload.emplace_back(buffer); @@ -270,7 +273,10 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { struct uploadInterval {size_t start; size_t size;}; std::vector intervals; - for (const auto &subBuffer : subBuffersForUpload) { + for (const auto &wsubBuffer : subBuffersForUpload) { + auto subBuffer = wsubBuffer.lock(); + if (subBuffer == nullptr) continue; + auto &newInterval = intervals.emplace_back(); newInterval = {.start = subBuffer->getOffset(), .size = subBuffer->getSize()}; } @@ -311,8 +317,9 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { vbCopyRegion.dstOffset = currInterval.start; vbCopyRegion.size = currInterval.size; } + int prevSize = subBuffersForUpload.size(); subBuffersForUpload.clear(); - subBuffersForUpload.reserve(currentSubBuffers.size()); + subBuffersForUpload.reserve(prevSize); } @@ -346,7 +353,7 @@ void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { memcpy(m_dataPointer, data, length); - m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); + m_parentBuffer->addSubBufferForUpload(weak_from_this()); // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } @@ -357,7 +364,7 @@ void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length memcpy(m_dataPointer + offset, data, length); - m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); + m_parentBuffer->addSubBufferForUpload(weak_from_this()); } void *GBufferVLK::GSubBufferVLK::getPointer() { @@ -369,7 +376,7 @@ void GBufferVLK::GSubBufferVLK::save(int length) { std::cerr << "invalid dataSize" << std::endl; } - m_parentBuffer->addSubBufferForUpload(m_iterator->lock()); + m_parentBuffer->addSubBufferForUpload(weak_from_this()); // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index ecff2c319..75e1299a4 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -20,6 +20,7 @@ typedef std::shared_ptr HGBufferVLK; class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; + class GSubBufferVLK; public: GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment = -1); ~GBufferVLK() override; @@ -28,7 +29,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this &buffer); + void addSubBufferForUpload(const std::weak_ptr &buffer); void *getPointer() override { return currentBuffer.stagingBufferAllocInfo.pMappedData;}; //Submits data edited with Pointer @@ -75,7 +76,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GBufferVLK; public: explicit GSubBufferVLK(HGBufferVLK parent, VmaVirtualAllocation alloc, VkDeviceSize offset, @@ -109,7 +110,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> currentSubBuffers; - std::vector> subBuffersForUpload; + std::vector> subBuffersForUpload; // uploadCache = {}; public: diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 2ad2905f0..1263297a7 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -139,6 +139,7 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptrgetShaderLayoutBindings(); auto &uboSizes = m_set.m_hDescriptorSetLayout->getRequiredUBOSize(); +#if (!defined(NDEBUG)) if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { std::cerr << "descriptor mismatch for UBO" << std::endl; throw std::runtime_error("descriptor mismatch for UBO"); @@ -150,6 +151,8 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr textures = {nullptr, nullptr, nullptr, nullptr}; }; @@ -26,6 +26,11 @@ struct WMOMaterialTemplate { nullptr, nullptr, nullptr}; }; +struct ADTMaterialTemplate { + std::array textures = {nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr}; +}; class IM2ModelData { public: @@ -60,4 +65,10 @@ class IWMOMaterial : public IMaterial { std::shared_ptr> m_materialPS = nullptr; }; +class IADTMaterial : public IMaterial { +public: + std::shared_ptr> m_materialVSPS = nullptr; + std::shared_ptr> m_materialPS = nullptr; +}; + #endif //AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 55fd2e29f..35ce89836 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -18,7 +18,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C vboM2Buffer = m_device->createVertexBuffer(1024*1024); vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); - vboAdtBuffer = m_device->createVertexBuffer(1024*1024); + vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); vboWMOBuffer = m_device->createVertexBuffer(1024*1024); vboWaterBuffer = m_device->createVertexBuffer(1024*1024); vboSkyBuffer = m_device->createVertexBuffer(1024*1024); @@ -47,8 +47,12 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_drawQuadVao->save(); } - uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); + uboBuffer = m_device->createUniformBuffer(1024*1024); + uboStaticBuffer = m_device->createUniformBuffer(1024*1024); + uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); + + m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); @@ -73,6 +77,15 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C // Buffer creation // ------------------ +HGVertexBufferBindings MapSceneRenderForwardVLK::createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto adtVAO = m_device->createVertexBufferBindings(); + adtVAO->addVertexBufferBinding(vertexBuffer, adtVertexBufferBinding); + adtVAO->setIndexBuffer(indexBuffer); + + return adtVAO; +}; + HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto wmoVAO = m_device->createVertexBufferBindings(); @@ -169,13 +182,48 @@ HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } + +std::shared_ptr +MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexFragmentData = std::make_shared>(uboStaticBuffer); + auto fragmentData = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}) + .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, vertexFragmentData->getSubBuffer()) + .ubo(2, fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, std::dynamic_pointer_cast(adtMaterialTemplate.textures[0])) + .texture(6, std::dynamic_pointer_cast(adtMaterialTemplate.textures[1])) + .texture(7, std::dynamic_pointer_cast(adtMaterialTemplate.textures[2])) + .texture(8, std::dynamic_pointer_cast(adtMaterialTemplate.textures[3])) + .texture(9, std::dynamic_pointer_cast(adtMaterialTemplate.textures[4])) + .texture(10, std::dynamic_pointer_cast(adtMaterialTemplate.textures[5])) + .texture(11, std::dynamic_pointer_cast(adtMaterialTemplate.textures[6])) + .texture(12, std::dynamic_pointer_cast(adtMaterialTemplate.textures[7])) + .texture(13, std::dynamic_pointer_cast(adtMaterialTemplate.textures[8])); + }) + .toMaterial([&vertexFragmentData, &fragmentData](IADTMaterial *instance) -> void { + instance->m_materialVSPS = vertexFragmentData; + instance->m_materialPS = fragmentData; + }); + + return material; +} + std::shared_ptr MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; - auto vertexFragmentData = std::make_shared>(uboBuffer); + auto vertexFragmentData = std::make_shared>(uboStaticBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}) @@ -244,8 +292,8 @@ std::shared_ptr> MapSceneRenderForwardVLK::c std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WMOMaterialTemplate &wmoMaterialTemplate) { - auto l_vertexData = std::make_shared>(uboBuffer); ; - auto l_fragmentData = std::make_shared>(uboBuffer); ; + auto l_vertexData = std::make_shared>(uboStaticBuffer); ; + auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}) @@ -297,6 +345,19 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } +std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { + auto result = std::make_shared(); + + BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); + BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); + + return result; +} + inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { if (mesh == nullptr) return; @@ -387,6 +448,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // Upload stuff // --------------------- uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); uploadCmd.submitBufferUploads(l_this->vboM2Buffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); @@ -437,19 +501,6 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { return nullptr; } -std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { - auto result = std::make_shared(); - - BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); - BufferChunkHelperVLK::create(uboBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); - - return result; -} - HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index ea82ea286..2a0b50967 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -24,6 +24,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { //------------------------------------- // Buffer creation //------------------------------------- + HGVertexBufferBindings createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; @@ -51,6 +52,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { // Material creation //------------------------------------- + std::shared_ptr createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) override; std::shared_ptr createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) override; std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, @@ -92,7 +94,9 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK vboSkyBuffer; HGBufferVLK iboBuffer; + HGBufferVLK uboStaticBuffer; HGBufferVLK uboBuffer; + HGBufferVLK uboM2BoneMatrixBuffer; HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; @@ -107,6 +111,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; + HGVertexBufferBindings m_emptyADTVAO = nullptr; HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; From 9e7b2ccce1f878c0794b9609dd9bc0f33d37f1ae Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 10 Apr 2023 03:44:55 +0300 Subject: [PATCH 061/212] water for ADT and WMO part 1 --- src/database/CSqliteDB.cpp | 8 +- .../glsl/forwardRendering/waterShader.frag | 2 +- .../src/engine/geometry/wmoGroupGeom.cpp | 80 +++--- .../src/engine/geometry/wmoGroupGeom.h | 23 +- .../src/engine/objects/adt/adtObject.cpp | 271 ++++++++++++------ .../src/engine/objects/adt/adtObject.h | 9 +- wowViewerLib/src/engine/objects/iWmoApi.h | 2 +- .../src/engine/objects/m2/m2Object.cpp | 5 +- .../src/engine/objects/scenes/map.cpp | 30 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 118 ++++---- .../src/engine/objects/wmo/wmoGroupObject.h | 22 +- .../src/engine/objects/wmo/wmoObject.cpp | 26 +- .../src/engine/objects/wmo/wmoObject.h | 6 +- .../src/gapi/UniformBufferStructures.h | 6 + wowViewerLib/src/include/database/dbStructs.h | 1 + .../renderer/mapScene/IMapSceneBufferCreate.h | 4 + .../mapScene/materials/IMaterialStructs.h | 16 ++ .../vulkan/MapSceneRenderForwardVLK.cpp | 29 ++ .../vulkan/MapSceneRenderForwardVLK.h | 5 +- 19 files changed, 416 insertions(+), 247 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index dcf1b3eac..d1ca45f82 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -115,12 +115,14 @@ const std::string liquidObjectInfoSQL_classic = R"===( )==="; const std::string liquidTypeSQL = R"===( - select ltxt.FileDataID, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol from LiquidType lt + select ltxt.FileDataID, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF from LiquidType lt left join LiquidTypeXTexture ltxt on ltxt.LiquidTypeID = lt.ID + left join LiquidMaterial lm on lt.MaterialID = lm.ID where lt.ID = ? order by ltxt.OrderIndex )==="; const std::string liquidTypeSQL_classic = R"===( - select lt.Texture_0, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol from LiquidType lt + select lt.Texture_0, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF from LiquidType lt + left join LiquidMaterial lm on lt.MaterialID = lm.ID where lt.ID = ? )==="; @@ -696,6 +698,8 @@ void CSqliteDB::getLiquidTypeData(int liquidTypeId, std::vector ltd.minimapStaticCol[0] = getFloatFromInt<0>(minimapStaticCol); ltd.minimapStaticCol[1] = getFloatFromInt<1>(minimapStaticCol); ltd.minimapStaticCol[2] = getFloatFromInt<2>(minimapStaticCol); + + ltd.LVF = getLiquidTypeInfo.getField("LVF").getInt(); } } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index e9e4e9b4c..567a26938 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -22,7 +22,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { //Individual meshes layout(std140, binding=4) uniform meshWideBlockPS { -//ivec4 waterTypeV; + //ivec4 waterTypeV; vec4 color; }; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 34335adfa..e286c1af2 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -7,6 +7,7 @@ #include "../shader/ShaderDefinitions.h" #include "../../gapi/interface/IDevice.h" #include "../algorithms/mathHelper.h" +#include "../algorithms/animate.h" #include chunkDef WmoGroupGeom::wmoGroupTable = { @@ -394,63 +395,40 @@ HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCrea } -int WmoGroupGeom::getLegacyWaterType(int a) { +LiquidTypes WmoGroupGeom::getLegacyWaterType(int a) { a = a + 1; if ( (a - 1) <= 0x13 ) { int newwater = (a - 1) & 3; if ( newwater == 1 ) { - a = 14; - return a; + return LiquidTypes::LIQUID_WMO_Ocean; } if ( newwater >= 1 ) { if ( newwater == 2 ) { - a = 19; + return LiquidTypes::LIQUID_WMO_Magma; } else if ( newwater == 3 ) { - a = 20; + return LiquidTypes::LIQUID_WMO_Slime; } - return a; } - a = 13; + return LiquidTypes::LIQUID_WMO_Water; } - return a; -} -HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { + return static_cast(a); +} +HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type) { if (vertexWaterBufferBindings == nullptr) { if (this->m_mliq == nullptr) return nullptr; - std::vector lVertices; -// lVertices.reserve((m_mliq->xverts)*(m_mliq->yverts)*3); - - mathfu::vec3 pos(m_mliq->basePos.x, m_mliq->basePos.y, m_mliq->basePos.z); - - for (int j = 0; j < m_mliq->yverts; j++) { - for (int i = 0; i < m_mliq->xverts; i++) { - int p = j*m_mliq->xverts + i; - - LiquidVertexFormat lvfVertex; - lvfVertex.pos_transp = mathfu::vec4_packed(mathfu::vec4( - pos.x + (MathHelper::UNITSIZE * i), - pos.y + (MathHelper::UNITSIZE * j), - m_liquidVerticles[p].waterVert.height, - 1.0 - )); - lvfVertex.uv = mathfu::vec2(0,0); - - lVertices.push_back(lvfVertex); - } - } - - + //Make Index Buffer std::vector iboBuffer; + iboBuffer.reserve(m_mliq->ytiles*m_mliq->xtiles); for (int j = 0; j < m_mliq->ytiles; j++) { for (int i = 0; i < m_mliq->xtiles; i++) { @@ -460,8 +438,8 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBuffe if (tile.legacyLiquidType == 15) continue; - if (liquidType == -1) { - liquidType = getLegacyWaterType(tile.legacyLiquidType); + if (m_legacyLiquidType == LiquidTypes::LIQUID_NONE) { + m_legacyLiquidType = getLegacyWaterType(tile.legacyLiquidType); } int16_t vertindexes[4] = { @@ -482,6 +460,38 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBuffe } } + //Make Vertex Buffer + std::vector lVertices; + lVertices.reserve((m_mliq->xverts)*(m_mliq->yverts)); + + mathfu::vec3 pos(m_mliq->basePos.x, m_mliq->basePos.y, m_mliq->basePos.z); + + LiquidTypes finalLiquidType = (liquid_type != LiquidTypes::LIQUID_NONE) ? liquid_type : m_legacyLiquidType; + for (int j = 0; j < m_mliq->yverts; j++) { + for (int i = 0; i < m_mliq->xverts; i++) { + int p = j*m_mliq->xverts + i; + + LiquidVertexFormat lvfVertex; + lvfVertex.pos_transp = mathfu::vec4_packed(mathfu::vec4( + pos.x + (MathHelper::UNITSIZE * i), + pos.y + (MathHelper::UNITSIZE * j), + m_liquidVerticles[p].waterVert.height, + 1.0 + )); + if (finalLiquidType == LiquidTypes::LIQUID_WMO_Magma) { + lvfVertex.uv = mathfu::vec2( + m_liquidVerticles[p].magmaVert.s * 3.0 / 256.0, + m_liquidVerticles[p].magmaVert.t * 3.0 / 256.0 + ); + } else { + lvfVertex.uv = mathfu::vec2(lvfVertex.pos_transp.x / (1600.0 / 3.0 / 16.0), + lvfVertex.pos_transp.y / (1600.0 / 3.0 / 16.0)); + } + + lVertices.push_back(lvfVertex); + } + } + waterIBO = sceneRenderer->createWaterIndexBuffer(iboBuffer.size() * sizeof(uint16_t)); waterIBO->uploadData( &iboBuffer[0], diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index d4ec6c2be..e500cace3 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -11,6 +11,23 @@ #include "../persistance/helper/ChunkFileReader.h" #include "../../include/sharedFile.h" #include "../../renderer/mapScene/IMapSceneBufferCreate.h" +enum class LiquidTypes : int +{ + LIQUID_NONE = -1, + // ... + LIQUID_WMO_Water = 13, + LIQUID_WMO_Ocean = 14, + LIQUID_Green_Lava = 15, + LIQUID_WMO_Magma = 19, + LIQUID_WMO_Slime = 20, + + LIQUID_END_BASIC_LIQUIDS = 20, + LIQUID_FIRST_NONBASIC_LIQUID_TYPE = 21, + + LIQUID_NAXX_SLIME = 21, + // ... + +}; class WmoGroupGeom : public PersistentFile { public: @@ -27,14 +44,14 @@ class WmoGroupGeom : public PersistentFile { HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient); - HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer); + HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type); int getFileDataId() const {return m_fileDataId;} const std::string &getFileName() const {return m_fileName;} private: std::function m_attenuateFunc; - int getLegacyWaterType(int a); + LiquidTypes getLegacyWaterType(int a); HGVertexBuffer getVBO(const HMapSceneBufferCreate &sceneRenderer); HGIndexBuffer getIBO(const HMapSceneBufferCreate &sceneRenderer); public: @@ -122,7 +139,7 @@ class WmoGroupGeom : public PersistentFile { HGVertexBufferBindings vertexWaterBufferBindings; int waterIndexSize = 0; - int liquidType = -1; + LiquidTypes m_legacyLiquidType = LiquidTypes::LIQUID_NONE; HGVertexBuffer waterVBO; HGIndexBuffer waterIBO; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 6e094139d..dbf740d88 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -3,6 +3,7 @@ // #include +#include #include "adtObject.h" #include "../../shader/ShaderDefinitions.h" #include "../../algorithms/mathHelper.h" @@ -34,7 +35,7 @@ void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { m_loaded = true; - loadWater(); + loadWater(sceneRenderer); } void AdtObject::loadM2s() { @@ -125,7 +126,91 @@ void AdtObject::loadWmos() { } } -HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { +struct lfv_4_5_format { + union { + struct { + int16_t s; + int16_t t; + } vert_format_5; + + struct { + char depth; + char filler1; + char filler2; + char filler3; + } vert_format_4; + }; + float height; +}; + +static_assert(sizeof(lfv_4_5_format) == 8); + +inline float getLiquidVertexHeight(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + constexpr std::bitset<5> lvf_0_1_3 = 0xB; + constexpr std::bitset<5> lvf_4_5 = 0x30; + + if ( liquidVertexFormat > 5 ) + return 0.0; + + if ( liquidVertexFormat == 0 || liquidVertexFormat == 1 || liquidVertexFormat == 3 ) // lvf == 0, 1, 3 + return vertexDataPtr[index]; + + if ( liquidVertexFormat == 4 || liquidVertexFormat == 5 ) + return ((lfv_4_5_format*) vertexDataPtr)[index].height;// lvf == 4,5 + + return 0.0;// lfv == 2 +} + +struct uv_map_entry { + int16_t s; + int16_t t; +}; + +inline mathfu::vec2 getLiquidVertexCoords(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + int16_t s = 0; + int16_t t = 0; + + if (liquidVertexFormat == 3 || liquidVertexFormat == 1) { + auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); + auto const &element = uvStart[index]; + + s = element.s; + t = element.t; + } + if (liquidVertexFormat == 5) { + auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; + + s = element.vert_format_5.s; + t = element.vert_format_5.t; + } + //For all other liquidVertexFormat are default zeroes + + return mathfu::vec2(s * 3.0 / 256.0, t * 3.0 / 256.0); +} + +inline uint8_t getLiquidDepth(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + uint8_t depth = 0; + if (liquidVertexFormat == 2) { + depth = 255; + if ( vertexDataPtr ) + depth = ((uint8_t *)vertexDataPtr)[index]; + } else if (liquidVertexFormat == 0) { + auto const depthStart = (uint8_t *) (&vertexDataPtr[totalElemSize]); + depth = depthStart[index]; + } else if (liquidVertexFormat == 3) { + auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); + auto const * depthStart = (uint8_t *) (&uvStart[totalElemSize]); + + depth = depthStart[index]; + } else if (liquidVertexFormat == 4) { + auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; + depth = element.vert_format_4.depth; + } + + return depth; +} + +HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water if (liquidInstance.offset_exists_bitmap > 0 && liquidInstance.height > 0) { @@ -133,18 +218,13 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, std::memcpy(&infoMask, &m_adtFile->mH2OBlob[liquidInstance.offset_exists_bitmap - m_adtFile->mH2OblobOffset], bitmask_size); } - float *heightPtr = nullptr; - if (liquidInstance.offset_vertex_data != 0) { - heightPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data - m_adtFile->mH2OblobOffset])); - } - + //Get Data from DB int basetextureFDID = 0; mathfu::vec3 color = mathfu::vec3(0,0,0); mathfu::vec3 minimapStaticCol = {0,0,0}; - //SmallHack + int liquidFlags = 0; - int l_liquidType = liquidInstance.liquid_type; - int l_liquidObjectType = liquidInstance.liquid_object_or_lvf; + int liquidVertexFormat = 0; if (basetextureFDID == 0 && (m_api->databaseHandler != nullptr)) { if (liquidInstance.liquid_object_or_lvf > 42) { @@ -159,10 +239,12 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, minimapStaticCol = mathfu::vec3(liqMat.minimapStaticCol[2], liqMat.minimapStaticCol[1], liqMat.minimapStaticCol[0]); liquidFlags = liqMat.flags; + liquidVertexFormat = liqMat.LVF; break; } } } else { + liquidVertexFormat = liquidInstance.liquid_object_or_lvf; std::vector liquidTypeData; m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liquidTypeData); for (auto ltd: liquidTypeData) { @@ -174,12 +256,42 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, } minimapStaticCol = mathfu::vec3(ltd.minimapStaticCol[2], ltd.minimapStaticCol[1], ltd.minimapStaticCol[0]); liquidFlags = ltd.flags; + liquidVertexFormat = ltd.LVF; break; } } } } + if (!liquidInstance.offset_vertex_data && liquidInstance.liquid_type != 2) { + liquidVertexFormat = 2; + } + + //Hack + if (liquidInstance.liquid_type == 2) { + liquidVertexFormat = 2; + } + + float *vertexDataPtr = nullptr; + if (liquidInstance.offset_vertex_data != 0) { + vertexDataPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data - m_adtFile->mH2OblobOffset])); + } + + //Set iteration restrictions for triangles + int y_begin = 0; + int x_begin = 0; + int x_end = 8; + int y_end = 8; + int totalCount = 9 * 9; + if (liquidInstance.liquid_object_or_lvf <= 41) { + x_begin = liquidInstance.x_offset; + y_begin = liquidInstance.y_offset; + x_end = liquidInstance.x_offset + liquidInstance.width; + y_end = liquidInstance.y_offset + liquidInstance.height; + + totalCount = (liquidInstance.width + 1) * (liquidInstance.height + 1) ; + } + // int baseVertexIndForInst = vertexBuffer.size(); int baseVertexIndForInst = 0; @@ -210,9 +322,10 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, -liquidInstance.min_height_level ); - bool hackBool = !((liquidInstance.liquid_object_or_lvf == 42) && (liquidInstance.liquid_type == 2)); - if (liquidInstance.liquid_object_or_lvf != 2 && heightPtr!= nullptr && hackBool) { - pos.z = heightPtr[y * (liquidInstance.width + 1) + x]; + mathfu::vec2 uv = mathfu::vec2(0,0); + if (vertexDataPtr!= nullptr) { + pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); + uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } minX = std::min(minX, pos.x); maxX = std::max(maxX, pos.x); @@ -221,7 +334,7 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, LiquidVertexFormat vertex; vertex.pos_transp = mathfu::vec4(pos, 1.0); - vertex.uv = mathfu::vec2(0,0); + vertex.uv = uv; vertexBuffer.push_back(vertex); } @@ -231,8 +344,8 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, C3Vector(mathfu::vec3(maxX, maxY, maxZ)) ); - for (int y = 0; y < liquidInstance.height; y++) { - for (int x = 0; x < liquidInstance.width; x++) { + for (int y = y_begin; y < y_end; y++) { + for (int x = x_begin; x < x_end; x++) { if (((infoMask >> (bitOffset++)) & 1) == 0) continue; int16_t vertindexes[4] = { (int16_t) (baseVertexIndForInst + y * (liquidInstance.width +1 ) + x), @@ -285,96 +398,57 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(int x_chunk, int y_chunk, HGDevice device = m_api->hDevice; - //TODO: - /* - auto waterIBO = device->createIndexBuffer(); - waterIBO->uploadData( - indexBuffer.data(), - indexBuffer.size() * sizeof(uint16_t)); + auto waterIBO = sceneRenderer->createWaterIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); + waterIBO->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); - auto waterVBO = device->createVertexBuffer(); + auto waterVBO = sceneRenderer->createWaterVertexBuffer(vertexBuffer.size() * sizeof(LiquidVertexFormat)); waterVBO->uploadData( vertexBuffer.data(), vertexBuffer.size() * sizeof(LiquidVertexFormat) ); - auto vertexWaterBufferBindings = device->createVertexBufferBindings(); - vertexWaterBufferBindings->setIndexBuffer(waterIBO); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = waterVBO; - - vertexBinding.bindings = std::vector(&staticWaterBindings[0], &staticWaterBindings[2]); - - vertexWaterBufferBindings->addVertexBufferBinding(vertexBinding); - vertexWaterBufferBindings->save(); - - + auto vertexWaterBufferBindings = sceneRenderer->createWaterVAO(waterVBO, waterIBO); //Create mesh(es) - HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterShader", nullptr); - - gMeshTemplate meshTemplate(vertexWaterBufferBindings, shaderPermutation); - + gMeshTemplate meshTemplate(vertexWaterBufferBindings); meshTemplate.meshType = MeshType::eWmoMesh; - meshTemplate.depthWrite = false; - meshTemplate.depthCulling = true; - meshTemplate.backFaceCulling = false; - meshTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + + WaterMaterialTemplate waterMaterialTemplate; + waterMaterialTemplate.color = color; + waterMaterialTemplate.liquidFlags = liquidFlags; - meshTemplate.texture = {nullptr}; if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); - meshTemplate.texture[0] = m_api->hDevice->createBlpTexture(htext, true, true); + waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); } else { - meshTemplate.texture[0] = m_api->hDevice->getBlackTexturePixel(); + waterMaterialTemplate.texture = m_api->hDevice->getBlackTexturePixel(); } - meshTemplate.ubo[0] = nullptr; //m_api->getSceneWideUniformBuffer(); - meshTemplate.ubo[1] = device->createUniformBufferChunk(sizeof(mathfu::mat4)); - meshTemplate.ubo[2] = nullptr; - - meshTemplate.ubo[3] = nullptr; - meshTemplate.ubo[4] = device->createUniformBufferChunk(16); - meshTemplate.start = 0; meshTemplate.end = indexBuffer.size(); - meshTemplate.element = DrawElementMode::TRIANGLES; - - - meshTemplate.ubo[1]->setUpdateHandler([](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData ) -> void { - mathfu::mat4 &placementMat = self->getObject(); - placementMat = mathfu::mat4::Identity(); - }); - meshTemplate.ubo[4]->setUpdateHandler([this, l_liquidType, l_liquidObjectType, color, liquidFlags, minimapStaticCol, closeRiverColor](IUniformBufferChunk* self, const HFrameDependantData &frameDepedantData) -> void { - mathfu::vec4_packed &color_ = self->getObject(); - if (!frameDepedantData->useMinimapWaterColor) { - if ((liquidFlags & 1024) > 0) {// Ocean - color_ = frameDepedantData->closeOceanColor; - } else if (liquidFlags == 15) { //River/Lake - if (frameDepedantData->useCloseRiverColorForDB) { - color_ = mathfu::vec4(closeRiverColor,0.7); - } else { - color_ = frameDepedantData->closeRiverColor; - } - } else { - color_ = mathfu::vec4(color, 0.7); - } - } else { - color_ = mathfu::vec4(minimapStaticCol, 0.7); - }; - }); - auto mesh = m_api->hDevice->createMesh(meshTemplate); + auto waterMaterial = sceneRenderer->createWaterMaterial(m_waterPlacementChunk, pipelineTemplate, waterMaterialTemplate); + m_waterMaterialArray.push_back(waterMaterial); + + auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); return mesh; - */ - return nullptr; } -void AdtObject::loadWater() { + +void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { if (m_adtFile->mH2OHeader == nullptr) return; + m_waterPlacementChunk = sceneRenderer->createWMOWideChunk(); + m_waterPlacementChunk->getObject().uPlacementMat = mathfu::mat4::Identity(); + m_waterPlacementChunk->save(); + mathfu::vec3 adtBasePos = mathfu::vec3(AdtIndexToWorldCoordinate(adt_y), AdtIndexToWorldCoordinate(adt_x), 0); for (int y_chunk = 0; y_chunk < 16; y_chunk++) { @@ -400,7 +474,7 @@ void AdtObject::loadWater() { for (int layerInd = 0; layerInd < liquidChunk.layer_count; layerInd++) { SMLiquidInstance &liquidInstance = liquidInstPtr[layerInd]; - waterMeshes[i].push_back(createWaterMeshFromInstance(x_chunk,y_chunk,liquidInstance,liquidBasePos)); + waterMeshes[i].push_back(createWaterMeshFromInstance(sceneRenderer, x_chunk,y_chunk,liquidInstance,liquidBasePos)); } } } @@ -487,7 +561,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { mclv->values[j].a / 255.0f }; } else { - //If MCLV is empty, localDiffuse doesnt exist in shader + //If MCLV is empty, localDiffuse doesn't exist in shader adtVertex.mclv = { 0.0f, 0.0f, 0.0f, 0.0f }; } } @@ -869,24 +943,37 @@ void AdtObject::update(animTime_t deltaTime ) { } for (int i = 0; i < 256; i++) { - auto &psBlock = adtMaterials[i]->m_materialPS->getObject(); + if (adtMaterials[i] != nullptr) { + auto &psBlock = adtMaterials[i]->m_materialPS->getObject(); - for (int j = 0; j < 4; j++) { - psBlock.animationMat[j] = this->texturesPerMCNK[i].animTexture[j]; + for (int j = 0; j < 4; j++) { + psBlock.animationMat[j] = this->texturesPerMCNK[i].animTexture[j]; + } + adtMaterials[i]->m_materialPS->save(); } - adtMaterials[i]->m_materialPS->save(); } } -void AdtObject::uploadGeneratorBuffers(ADTObjRenderRes &adtRes) { +void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { if (!m_loaded) return; - if (!adtRes.wasLoaded) return; + if (m_waterPlacementChunk != nullptr) { + m_waterPlacementChunk->getObject().uPlacementMat = mathfu::mat4::Identity(); + m_waterPlacementChunk->save(); + } + for (auto &waterMaterial : m_waterMaterialArray) { + auto &waterChunk = waterMaterial->m_materialPS->getObject(); + if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean + waterChunk.color = frameDependantData->closeOceanColor; + } else if (waterMaterial->liquidFlags == 15) { //River/Lake + waterChunk.color = frameDependantData->closeRiverColor; + } else { + waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); + } - for (int i = 0; i < adtMeshes.size(); i++) { - bool noLayers = m_adtFileTex->mcnkStructs[i].mcly == nullptr || m_adtFileTex->mcnkStructs[i].mclyCnt <= 0; + waterMaterial->m_materialPS->save(); } } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 95c7454ef..21f344560 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -47,7 +47,7 @@ class AdtObject { void collectMeshesLod(std::vector &renderedThisFrame); void update(animTime_t deltaTime); - void uploadGeneratorBuffers(ADTObjRenderRes &adtRes); + void uploadGeneratorBuffers(const HFrameDependantData &frameDependantData); void doPostLoad(const HMapSceneBufferCreate &sceneRenderer); int getAreaId(int mcnk_x, int mcnk_y); @@ -142,6 +142,9 @@ class AdtObject { std::vector globIndexX; std::vector globIndexY; + std::shared_ptr> m_waterPlacementChunk = nullptr; + std::vector> m_waterMaterialArray = {}; + int adt_x; int adt_y; @@ -172,8 +175,8 @@ class AdtObject { void calcBoundingBoxes(); void loadM2s(); void loadWmos(); - void loadWater(); - HGSortableMesh createWaterMeshFromInstance(int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos); + void loadWater(const HMapSceneBufferCreate &sceneRenderer); + HGSortableMesh createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos); bool checkNonLodChunkCulling(ADTObjRenderRes &adtFrustRes, diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index 236bf5598..a466cd33b 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -321,6 +321,6 @@ class IWmoApi { virtual HGTexture getTexture(int textureId, bool isSpec) = 0; virtual void updateBB() = 0; virtual void postWmoGroupObjectLoad(int groupId, int lod) = 0; - + virtual std::shared_ptr> getPlacementBuffer() = 0; }; #endif //WOWVIEWERLIB_IWMOAPI_H diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 56dc74977..a80f7cf5a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1355,6 +1355,8 @@ float wfv_convert(float value, int16_t random) { } HGM2Mesh M2Object::createWaterfallMesh() { + return nullptr; + HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterfallShader", "waterfallShader", nullptr); gMeshTemplate meshTemplate(bufferBindings); @@ -1525,7 +1527,8 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { dynamicMeshes.push_back(dynamicMeshData); }*/ } else { - m_meshArray.push_back({createWaterfallMesh(), 0}); + //TODO: +// m_meshArray.push_back({createWaterfallMesh(), 0}); } { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 338a8bb9c..70af20657 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1432,8 +1432,17 @@ void Map::update(const HMapRenderPlan &renderPlan) { wmoGroupUpdate.endMeasurement(); adtUpdate.beginMeasurement(); + { + std::unordered_set> processedADT; + for (const auto &adtObjectRes: renderPlan->adtArray) { + if (processedADT.count(adtObjectRes->adtObject) == 0) { + adtObjectRes->adtObject->update(deltaTime); + processedADT.insert(adtObjectRes->adtObject); + } + } + } for (const auto &adtObjectRes : renderPlan->adtArray) { - adtObjectRes->adtObject->update(deltaTime); + } adtUpdate.endMeasurement(); @@ -1515,14 +1524,19 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { } } -// for (auto &wmoGroupObject : cullStage->wmoGroupArray.getToDraw()) { -// if (wmoGroupObject == nullptr) continue; -// wmoGroupObject->uploadGeneratorBuffers(); -// } + for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->uploadGeneratorBuffers(renderPlan->frameDependentData); + } - for (auto &adtRes: renderPlan->adtArray) { - if (adtRes == nullptr) continue; - adtRes->adtObject->uploadGeneratorBuffers(*adtRes.get()); + { + std::unordered_set> processedADT; + for (const auto &adtObjectRes: renderPlan->adtArray) { + if (processedADT.count(adtObjectRes->adtObject) == 0) { + adtObjectRes->adtObject->uploadGeneratorBuffers(renderPlan->frameDependentData); + processedADT.insert(adtObjectRes->adtObject); + } + } } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index d5425befd..b5977ceac 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -33,9 +33,24 @@ void WmoGroupObject::update() { this->updateWorldGroupBBWithM2(); m_recalcBoundries = false; } + + } -void WmoGroupObject::uploadGeneratorBuffers() { +void WmoGroupObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { + for (auto const &waterMaterial : m_waterMaterialArray) { + auto waterChunk = waterMaterial->m_materialPS->getObject(); + + if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean + waterChunk.color = frameDependantData->closeOceanColor; + } else if (waterMaterial->liquidFlags == 15) { //River/Lake + waterChunk.color = frameDependantData->closeRiverColor; + } else { + waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); + } + + waterMaterial->m_materialPS->save(); + } } void WmoGroupObject::drawDebugLights() { @@ -160,53 +175,53 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } -int WmoGroupObject::to_wmo_liquid (int x) { +LiquidTypes WmoGroupObject::to_wmo_liquid (int x) { liquid_basic_types const basic (static_cast(x & liquid_basic_types_MASK)); switch (basic) { case liquid_basic_types_water: - return (m_geom->mogp->flags.is_not_water_but_ocean) ? LIQUID_WMO_Ocean : LIQUID_WMO_Water; + return (m_geom->mogp->flags.is_not_water_but_ocean) ? LiquidTypes::LIQUID_WMO_Ocean : LiquidTypes::LIQUID_WMO_Water; case liquid_basic_types_ocean: - return LIQUID_WMO_Ocean; + return LiquidTypes::LIQUID_WMO_Ocean; case liquid_basic_types_magma: - return LIQUID_WMO_Magma; + return LiquidTypes::LIQUID_WMO_Magma; case liquid_basic_types_slime: - return LIQUID_WMO_Slime; + return LiquidTypes::LIQUID_WMO_Slime; } - return -1; + return LiquidTypes::LIQUID_NONE; } void WmoGroupObject::setLiquidType() { if ( getWmoApi()->getWmoHeader()->flags.flag_use_liquid_type_dbc_id) { - if ( m_geom->mogp->liquidType < LIQUID_FIRST_NONBASIC_LIQUID_TYPE ) + if ( m_geom->mogp->liquidType < (int)LiquidTypes::LIQUID_FIRST_NONBASIC_LIQUID_TYPE ) { this->liquid_type = to_wmo_liquid (m_geom->mogp->liquidType - 1); } else { - this->liquid_type = m_geom->mogp->liquidType; + this->liquid_type = static_cast(m_geom->mogp->liquidType); } } else { - if ( m_geom->mogp->liquidType == LIQUID_Green_Lava ) + if ( m_geom->mogp->liquidType == (int)LiquidTypes::LIQUID_Green_Lava ) { - this->liquid_type = 0; + this->liquid_type = static_cast(0); } else { int const liquidType (m_geom->mogp->liquidType + 1); int const tmp (m_geom->mogp->liquidType); - if ( m_geom->mogp->liquidType < LIQUID_END_BASIC_LIQUIDS ) + if ( m_geom->mogp->liquidType < (int)LiquidTypes::LIQUID_END_BASIC_LIQUIDS ) { this->liquid_type = to_wmo_liquid (m_geom->mogp->liquidType); } else { - this->liquid_type = m_geom->mogp->liquidType + 1; + this->liquid_type = static_cast(m_geom->mogp->liquidType + 1); } assert (!liquidType || !(m_geom->mogp->flags.LIQUIDSURFACE)); } @@ -214,28 +229,19 @@ void WmoGroupObject::setLiquidType() { } void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRenderer) { - //TODO: - return; - HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer); - if (binding == nullptr) - return; //Get Liquid with new method setLiquidType(); - // - auto &materials = m_wmoApi->getMaterials(); - const SMOMaterial &material = materials[m_geom->m_mliq->materialId]; - assert(material.shader < MAX_WMO_SHADERS && material.shader >= 0); - auto shaderId = material.shader; - if (shaderId >= MAX_WMO_SHADERS) { - shaderId = 0; - } - HGShaderPermutation shaderPermutation = device->getShader("waterShader", "waterShader", nullptr); + HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer, liquid_type); + if (binding == nullptr) + return; + + + WaterMaterialTemplate waterMaterialTemplate; + - gMeshTemplate meshTemplate(binding); PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; @@ -243,70 +249,44 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; - auto blendMode = material.blendMode; - float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; - meshTemplate.meshType = MeshType::eWmoMesh; - - - std::vector liquidTypeData; int basetextureFDID = 0; if (m_api->databaseHandler != nullptr) { - m_api->databaseHandler->getLiquidTypeData(this->liquid_type, liquidTypeData); + m_api->databaseHandler->getLiquidTypeData(static_cast(this->liquid_type), liquidTypeData); } - mathfu::vec3 color = mathfu::vec3(0,0,0); - int liquidFlags = 0; + + waterMaterialTemplate.color = mathfu::vec3(0,0,0); + waterMaterialTemplate.liquidFlags = 0; for (auto ltd: liquidTypeData) { if (ltd.FileDataId != 0) { basetextureFDID = ltd.FileDataId; if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { - color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); + waterMaterialTemplate.color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); } - liquidFlags = ltd.flags; + waterMaterialTemplate.liquidFlags = ltd.flags; break; } } - /* if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); - meshTemplate.texture[0] = m_api->hDevice->createBlpTexture(htext, true, true); + waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); } else { - meshTemplate.texture[0] = m_api->hDevice->getBlackTexturePixel(); + waterMaterialTemplate.texture = m_api->hDevice->getBlackTexturePixel(); } - */ - //TODO: -// meshTemplate.ubo[0] = nullptr;//m_api->getSceneWideUniformBuffer(); -// meshTemplate.ubo[1] = vertexModelWideUniformBuffer; -// meshTemplate.ubo[2] = nullptr; -// -// meshTemplate.ubo[3] = nullptr; -// meshTemplate.ubo[4] = device->createUniformBufferChunk(16); + auto waterMaterial = sceneRenderer->createWaterMaterial(m_wmoApi->getPlacementBuffer(),pipelineTemplate, waterMaterialTemplate); + gMeshTemplate meshTemplate(binding); + meshTemplate.meshType = MeshType::eWmoMesh; meshTemplate.start = 0; meshTemplate.end = m_geom->waterIndexSize; - auto l_liquidType = liquid_type; - - std::shared_ptr> chunkBlock = nullptr; - - chunkBlock->setUpdateHandler([this, l_liquidType, liquidFlags, color](auto &data, const HFrameDependantData &frameDepedantData) -> void { - mathfu::vec4_packed &color_ = data; - if ((liquidFlags & 1024) > 0) {// Ocean - color_ = frameDepedantData->closeOceanColor; - } else if (liquidFlags == 15) { //River/Lake - color_ = frameDepedantData->closeRiverColor; - } else { - color_ = mathfu::vec4(color, 0.7); - } - }); - - //TODO: -// HGMesh hmesh = device->createMesh(meshTemplate); -// m_waterMeshArray.push_back(hmesh); + auto hmesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); + m_waterMeshArray.push_back(hmesh); + m_waterMaterialArray.push_back(waterMaterial); } void WmoGroupObject::loadDoodads() { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 99bae9ace..27eed94eb 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -49,7 +49,7 @@ class WmoGroupObject { bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); void update(); - void uploadGeneratorBuffers(); + void uploadGeneratorBuffers(const HFrameDependantData &frameDependantData); void checkGroupFrustum(bool &drawDoodads, bool &drawGroup, mathfu::vec4 &cameraVec4, const MathHelper::FrustumCullingData &frustumData); @@ -81,6 +81,7 @@ class WmoGroupObject { std::vector m_meshArray = {}; std::vector m_sortableMeshArray = {}; std::vector m_waterMeshArray = {}; + std::vector> m_waterMaterialArray = {}; SMOGroupInfo *m_main_groupInfo; @@ -92,7 +93,7 @@ class WmoGroupObject { bool m_loaded = false; bool m_recalcBoundries = false; - int liquid_type = -1; + LiquidTypes liquid_type = LiquidTypes::LIQUID_NONE; void startLoading(); void createWorldGroupBB (CAaBox &bbox, mathfu::mat4 &placementMatrix); @@ -104,7 +105,7 @@ class WmoGroupObject { void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void createWaterMeshes(const HMapSceneBufferCreate &sceneRenderer); - int to_wmo_liquid (int x); + LiquidTypes to_wmo_liquid (int x); void setLiquidType(); void loadDoodads(); @@ -141,21 +142,6 @@ enum liquid_basic_types liquid_basic_types_MASK = 3, }; -enum liquid_types -{ - // ... - LIQUID_WMO_Water = 13, - LIQUID_WMO_Ocean = 14, - LIQUID_Green_Lava = 15, - LIQUID_WMO_Magma = 19, - LIQUID_WMO_Slime = 20, - - LIQUID_END_BASIC_LIQUIDS = 20, - LIQUID_FIRST_NONBASIC_LIQUID_TYPE = 21, - - LIQUID_NAXX_SLIME = 21, - // ... -}; class WMOGroupListContainer { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index c2bf2bdc8..282b57064 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -290,7 +290,7 @@ void WmoObject::createWorldPortals() { center, upVector ); - mathfu::mat4 projMatInv = viewMat.Inverse(); + mathfu::mat4 viewMatInv = viewMat.Inverse(); std::vector portalTransformed(portalVecs.size()); for (int k = 0; k < portalVecs.size(); k++) { @@ -301,7 +301,7 @@ void WmoObject::createWorldPortals() { portalVecs.clear(); for (int k = 0; k < hulled.size(); k++) { - portalVecs.push_back((projMatInv * mathfu::vec4(hulled[k], 1.0)).xyz()); + portalVecs.push_back((viewMatInv * mathfu::vec4(hulled[k], 1.0)).xyz()); } geometryPerPortal[j].sortedVericles = portalVecs; @@ -329,7 +329,7 @@ bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { this->createBB(mainGeom->header->bounding_box); m_modelWideChunk = sceneRenderer->createWMOWideChunk(); - if (mainGeom->skyBoxM2FileName != nullptr || mainGeom->skyboxM2FileId != 0) { + if ((mainGeom->skyBoxM2FileName != nullptr && mainGeom->skyBoxM2FileNameLen > 0) || mainGeom->skyboxM2FileId != 0) { skyBox = std::make_shared(m_api, true); skyBox->setLoadParams(0, {},{}); @@ -418,11 +418,11 @@ void WmoObject::update() { void WmoObject::uploadGeneratorBuffers() { if (!m_loaded) return; - for (int i= 0; i < groupObjects.size(); i++) { - if(groupObjects[i] != nullptr) { - groupObjects[i]->uploadGeneratorBuffers(); - } - } +// for (int i= 0; i < groupObjects.size(); i++) { +// if(groupObjects[i] != nullptr) { +// groupObjects[i]->uploadGeneratorBuffers(); +// } +// } } void WmoObject::collectMeshes(std::vector &renderedThisFrame){ @@ -988,12 +988,18 @@ void WmoObject::traverseGroupWmo( } //2. Loop through portals of current group + int moprIndex = groupObjects[groupId]->getWmoGroupGeom()->mogp->moprIndex; int numItems = groupObjects[groupId]->getWmoGroupGeom()->mogp->moprCount; if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.showSkyBox) { - if (skyBox != nullptr) { - traverseTempData.ivPerWMOGroup[groupId]->m2List.addToDraw(skyBox); + if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.INTERIOR > 0) { + if (skyBox != nullptr) { + traverseTempData.ivPerWMOGroup[groupId]->m2List.addToDraw(skyBox); + } + } else { + //TODO: WHAT ???? + //Example: main wmo: 850548, group WMO 901743 } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 56407bbf1..dc2ffc50a 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -123,14 +123,14 @@ class WmoObject : public IWmoApi { std::vector &getPortalInfos() override { return geometryPerPortal; }; + std::shared_ptr> getPlacementBuffer() override { + return m_modelWideChunk; + } std::shared_ptr getSkyBoxForGroup (int groupNum);; - void collectMeshes(std::vector &renderedThisFrame); void createGroupObjects(); - - void checkFog(mathfu::vec3 &cameraPos, std::vector &fogResults); bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/gapi/UniformBufferStructures.h b/wowViewerLib/src/gapi/UniformBufferStructures.h index e36790105..beffaf0ba 100644 --- a/wowViewerLib/src/gapi/UniformBufferStructures.h +++ b/wowViewerLib/src/gapi/UniformBufferStructures.h @@ -183,6 +183,12 @@ namespace ADT { }; } +namespace Water { + struct meshWideBlockPS { + mathfu::vec4_packed color; + }; +} + namespace ImgUI { struct modelWideBlockVS { mathfu::mat4 projectionMat; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index fd4805c52..6125ff219 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -76,6 +76,7 @@ struct LiquidTypeData { float color1[3]; float color2[3]; int flags; + int LVF; std::array minimapStaticCol; }; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index ef9b74241..469d9216d 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -96,6 +96,10 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WMOMaterialTemplate &wmoMaterialTemplate) = 0; + + virtual std::shared_ptr createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) = 0; //------------------------------------- // Mesh creation //------------------------------------- diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 11b1ce9b0..e9304138f 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -7,6 +7,9 @@ #include "../../../gapi/interface/materials/IMaterial.h" #include "../../../gapi/UniformBufferStructures.h" +//---------------------------- +// Material Templates +//---------------------------- struct M2MaterialTemplate { int vertexShader = 0; @@ -32,6 +35,12 @@ struct ADTMaterialTemplate { nullptr, nullptr, nullptr}; }; +struct WaterMaterialTemplate { + HGTexture texture = nullptr; + mathfu::vec3 color; + int liquidFlags; +}; + class IM2ModelData { public: std::shared_ptr> m_placementMatrix = nullptr; @@ -71,4 +80,11 @@ class IADTMaterial : public IMaterial { std::shared_ptr> m_materialPS = nullptr; }; +class IWaterMaterial : public IMaterial { +public: + mathfu::vec3 color; + int liquidFlags; + std::shared_ptr> m_materialPS = nullptr; +}; + #endif //AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 35ce89836..b22a6ea57 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -57,6 +57,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); + m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; @@ -325,6 +326,34 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const return material; } +std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) { + auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; + + auto &l_sceneWideChunk = sceneWideChunk; + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}) + .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, std::dynamic_pointer_cast(waterMaterialTemplate.texture)); + }) + .toMaterial([&l_fragmentData](IWaterMaterial *instance) -> void { + instance->m_materialPS = l_fragmentData; + }); + + material->color = waterMaterialTemplate.color; + material->liquidFlags = waterMaterialTemplate.liquidFlags; + + return material; +} + std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 2a0b50967..eced2f8d3 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -66,7 +66,9 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WMOMaterialTemplate &wmoMaterialTemplate) override; - + std::shared_ptr createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) override; std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; @@ -115,6 +117,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; + HGVertexBufferBindings m_emptyWaterVAO = nullptr; void createFrameBuffers(); }; From 3510aae916a4759826a6d0467464a250919442a1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 10 Apr 2023 05:00:29 +0300 Subject: [PATCH 062/212] bring back sky cone meshes, add light to water --- .../glsl/forwardRendering/waterShader.frag | 27 +- .../glsl/forwardRendering/waterShader.vert | 8 +- .../src/engine/objects/adt/adtObject.cpp | 3 + .../src/engine/objects/scenes/map.cpp | 17 +- wowViewerLib/src/engine/objects/scenes/map.h | 2 - .../src/engine/shader/ShaderDefinitions.h | 1057 +++++++++-------- .../src/renderer/mapScene/MapScenePlan.h | 4 + .../renderer/mapScene/MapSceneRenderer.cpp | 18 - .../vulkan/MapSceneRenderForwardVLK.cpp | 20 +- 9 files changed, 615 insertions(+), 541 deletions(-) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 567a26938..f7b398615 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -10,6 +10,7 @@ precision highp int; layout(location=0) in vec3 vPosition; layout(location=1) in vec2 vTextCoords; +layout(location=2) in vec3 vNormal; layout(location=0) out vec4 outputColor; @@ -26,13 +27,35 @@ layout(std140, binding=4) uniform meshWideBlockPS { vec4 color; }; +const InteriorLightParam intLight = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + void main() { vec3 matDiffuse = color.rgb+texture(uTexture, vTextCoords).rgb; vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; + vec4 finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + 0, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vec3(0.0), + vec3(0.0), /* specular */ + vec3(0.0) + ), + 1.0 + ); + + //BlendMode is always GxBlend_Alpha - vec3 finalColor = makeFog(fogData, vec4(matDiffuse, 1.0), vPosition.xyz, sunDir.xyz, 2).rgb; + finalColor.rgb = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, 2).rgb; - outputColor = vec4(finalColor, 0.7); + outputColor = vec4(finalColor.rgb, 0.7); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index 053376e95..7d0816f68 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -24,12 +24,15 @@ layout(std140, binding=1) uniform modelWideBlockVS { //out vec2 vTexCoord; layout(location=0) out vec3 vPosition; layout(location=1) out vec2 vTextCoords; +layout(location=2) out vec3 vNormal; void main() { vec4 aPositionVec4 = vec4(aPositionTransp.xyz, 1); - mat4 cameraMatrix = scene.uLookAtMat * uPlacementMat; + mat4 viewModelMat = scene.uLookAtMat * uPlacementMat; - vec4 cameraPoint = cameraMatrix * aPositionVec4; + vec4 cameraPoint = viewModelMat * aPositionVec4; + + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); //const float posToTextPos = 1.0 / (1600.0/3.0/16.0); vTextCoords = aTexCoord;//aPositionVec4.xy * posToTextPos; @@ -37,5 +40,6 @@ void main() { gl_Position = scene.uPMatrix * cameraPoint; // vTexCoord = aTexCoord; vPosition = cameraPoint.xyz; + vNormal = normalize(viewModelMatForNormal * vec4(vec3(0,0,1.0), 0.0)).xyz; } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index dbf740d88..4825f2144 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -327,6 +327,9 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } + if (liquidVertexFormat != 1 && liquidVertexFormat != 3 && liquidVertexFormat != 5) { + uv = mathfu::vec2(pos.x * 0.6, pos.y * 0.6); + } minX = std::min(minX, pos.x); maxX = std::max(maxX, pos.x); minY = std::min(minY, pos.y); maxY = std::max(maxY, pos.y); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 70af20657..f198a6bfd 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -270,7 +270,7 @@ HGVertexBufferBindings createSkyBindings(const HMapSceneBufferCreate &sceneRende auto skyBindings = sceneRenderer->createSkyVAO(skyVBO, skyIBO); - return nullptr; + return skyBindings; } Map::Map(HApiContainer api, int mapId, const std::string &mapName) { @@ -526,7 +526,15 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams cullCombineAllObjects.endMeasurement(); + mapRenderPlan->renderSky = m_api->getConfig()->renderSkyDom && + (!m_suppressDrawingSky && (mapRenderPlan->viewsHolder.getExterior() || mapRenderPlan->currentWmoGroupIsExtLit)); + if (m_skyConeAlpha > 0) { + mapRenderPlan->skyMesh = skyMesh; + } + if (mapRenderPlan->frameDependentData->overrideValuesWithFinalFog) { + mapRenderPlan->skyMesh0x4 = skyMesh0x4Sky; + } m_api->getConfig()->cullCreateVarsCounter = cullCreateVarsCounter.getTimePerFrame(); m_api->getConfig()->cullGetCurrentWMOCounter = cullGetCurrentWMOCounter.getTimePerFrame(); @@ -1678,10 +1686,3 @@ void Map::loadZoneLights() { } } -IChunkHandlerType Map::generateSceneWideChunk(HCameraMatrices &renderMats, Config* config) { - return [renderMats, config](auto &data, const HFrameDependantData &fdd) -> void { - auto *blockPSVS = &data; - - - }; -} diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 3244530cb..b859fe52e 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -228,8 +228,6 @@ class Map : public IScene, public IMapApi { void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) override; void createAdtFreeLamdas(); - - IChunkHandlerType generateSceneWideChunk(HCameraMatrices &renderMats, Config* config); }; typedef std::shared_ptr HMapScene; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f0d3452c7..65d647fc8 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,11 +430,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -479,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -513,12 +499,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,32}, {0,0,368}, }, { @@ -534,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {8,8,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -550,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -585,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -604,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -619,53 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,5, "screenTex"}, - {1,6, "blurTex"}, - }, - { - { - {0,0,0}, - {5,6,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,2,256}, - {0,1,64}, - {0,0,368}, - }, - { - { - {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -700,16 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -735,14 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.frag.spv", { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -768,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -787,11 +745,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -837,11 +794,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, + {0,1,64}, }, { { @@ -871,15 +829,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -905,14 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -938,14 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,2,16}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -971,11 +931,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,4,32}, }, { { @@ -990,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1005,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "skyConus.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1039,11 +999,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,4,16}, }, { { @@ -1058,12 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,5,1}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1074,14 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,0}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1092,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "Texture"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1108,15 +1079,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1127,11 +1097,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1142,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,3,14080}, + {0,1,64}, + {0,0,368}, + {0,7,64}, + {0,6,4096}, + {0,4,4096}, + {0,5,256}, }, { { - {2,2,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1210,20 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,16}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1234,15 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1253,16 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1273,11 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1288,15 +1261,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "waterShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1322,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1356,16 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, - {0,1,96}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1376,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1391,15 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1410,11 +1384,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1426,14 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,48}, + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1444,11 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1459,11 +1435,10 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, }, { @@ -1479,14 +1454,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1497,19 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { - {0,3,14080}, - {0,1,64}, {0,0,368}, - {0,7,64}, - {0,6,4096}, + {0,1,96}, }, { { - {6,6,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,16 +1504,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, + {0,4,96}, {0,0,368}, + {0,1,14144}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1555,12 +1525,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { {0,0,0}, - {5,5,1}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1571,12 +1544,65 @@ const std::unordered_map shaderMetaInfo = { } } }, -}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 0, { +{ "waterfallShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,2,144}, + {0,1,14144}, + {0,0,368}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,8, "uBumpTexture"}, + }, + { + { + {0,0,0}, + {8,8,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +}; + +const std::unordered_map>> fieldDefMapPerShaderNameVert = { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, + } + }, + { + 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, @@ -1596,18 +1622,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"drawFrustumShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 352, 1, 4, 0}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, + }}, + {"drawBBShader", { { - 4, { - {"_0_4_values0", true, 0, 1, 4, 0}, - {"_0_4_values1", true, 16, 1, 4, 0}, - {"_0_4_values2", true, 32, 1, 4, 0}, - {"_0_4_values3", true, 48, 1, 4, 0}, - {"_0_4_values4", true, 64, 1, 4, 0}, - {"_0_4_baseColor", true, 80, 1, 4, 0}, + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -1954,23 +1966,29 @@ const std::unordered_map m_currentInteriorGroups = {}; bool currentWmoGroupIsExtLit = false; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 033172b40..9febbb194 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -43,24 +43,6 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende int m_viewRenderOrder = 0; - //TODO: find a way to forward this data here - /* - if (m_api->getConfig()->renderSkyDom && !m_suppressDrawingSky && - (cullStage->viewsHolder.getExterior() || cullStage->currentWmoGroupIsExtLit)) { - if (fdd->overrideValuesWithFinalFog) { - if (skyMesh0x4Sky != nullptr) { - transparentMeshes.push_back(skyMesh0x4Sky); - skyMesh0x4Sky->setSortDistance(0); - - } - } - if ((m_skyConeAlpha > 0) ) { - if (skyMesh != nullptr) - opaqueMeshes.push_back(skyMesh); - } - } - */ - // Put everything into one array and sort interiorViewCollectMeshCounter.beginMeasurement(); bool renderPortals = m_config->renderPortals; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index b22a6ea57..32ccd3f97 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -470,8 +470,14 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto skyTransparentMeshes = std::make_shared>(); collectMeshes(framePlan, opaqueMeshes, transparentMeshes, skyOpaqueMeshes, skyTransparentMeshes); + bool renderSky = framePlan->renderSky; + auto skyMesh = framePlan->skyMesh; + auto skyMesh0x4 = framePlan->skyMesh0x4; return createRenderFuncVLK([opaqueMeshes, transparentMeshes, skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { // --------------------- // Upload stuff @@ -509,11 +515,15 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha for (auto const &mesh: *opaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } - for (auto const &mesh: *skyOpaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); - } - for (auto const &mesh: *skyTransparentMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + if (renderSky) { + if (skyMesh) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); + for (auto const &mesh: *skyOpaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + } + for (auto const &mesh: *skyTransparentMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + } + if (skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *transparentMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); From 89e240f59380fdcd4d71a3a7063fa5c85844d124 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 12 Apr 2023 21:42:10 +0300 Subject: [PATCH 063/212] that's it with water for now --- src/database/CSqliteDB.cpp | 11 ++- src/ui/FrontendUI.cpp | 5 ++ .../src/engine/objects/adt/adtObject.cpp | 83 ++++++++++++++++--- wowViewerLib/src/include/database/dbStructs.h | 7 ++ .../mapScene/materials/IMaterialStructs.h | 3 + 5 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index d1ca45f82..6ec58a37a 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -100,7 +100,7 @@ const std::string lightDataSQL = R"===( )==="; const std::string liquidObjectInfoSQL = R"===( - select ltxt.FileDataID, lm.LVF, ltxt.OrderIndex, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol from LiquidObject lo + select ltxt.FileDataID, lm.LVF, ltxt.OrderIndex, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lo.FlowSpeed, lt.MaterialID from LiquidObject lo left join LiquidTypeXTexture ltxt on ltxt.LiquidTypeID = lo.LiquidTypeID left join LiquidType lt on lt.ID = lo.LiquidTypeID left join LiquidMaterial lm on lt.MaterialID = lm.ID @@ -108,20 +108,20 @@ const std::string liquidObjectInfoSQL = R"===( )==="; const std::string liquidObjectInfoSQL_classic = R"===( - select lt.Texture_0, lm.LVF, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol from LiquidObject lo + select lt.Texture_0, lm.LVF, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lo.FlowSpeed, lt.MaterialID from LiquidObject lo left join LiquidType lt on lt.ID = lo.LiquidTypeID left join LiquidMaterial lm on lt.MaterialID = lm.ID where lo.ID = ? )==="; const std::string liquidTypeSQL = R"===( - select ltxt.FileDataID, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF from LiquidType lt + select ltxt.FileDataID, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF, lt.MaterialID from LiquidType lt left join LiquidTypeXTexture ltxt on ltxt.LiquidTypeID = lt.ID left join LiquidMaterial lm on lt.MaterialID = lm.ID where lt.ID = ? order by ltxt.OrderIndex )==="; const std::string liquidTypeSQL_classic = R"===( - select lt.Texture_0, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF from LiquidType lt + select lt.Texture_0, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF, lt.MaterialID from LiquidType lt left join LiquidMaterial lm on lt.MaterialID = lm.ID where lt.ID = ? )==="; @@ -656,6 +656,8 @@ void CSqliteDB::getLiquidObjectData(int liquidObjectId, std::vector & } lm.LVF = getLiquidObjectInfo.getField("LVF").getInt(); + lm.flowSpeed = getLiquidObjectInfo.getField("FlowSpeed").getDouble(); + lm.materialId = getLiquidObjectInfo.getField("MaterialID").getInt(); int color1 = getLiquidObjectInfo.getField("Color_0").getInt(); lm.color1[0] = getFloatFromInt<0>(color1); lm.color1[1] = getFloatFromInt<1>(color1); @@ -684,6 +686,7 @@ void CSqliteDB::getLiquidTypeData(int liquidTypeId, std::vector } else { ltd.texture0Pattern = getLiquidTypeInfo.getField("Texture_0").getInt(); } + ltd.materialId = getLiquidTypeInfo.getField("MaterialID").getInt(); int color1 = getLiquidTypeInfo.getField("Color_0").getInt(); ltd.color1[0] = getFloatFromInt<0>(color1); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 4d78ddbca..c3c665780 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -724,6 +724,11 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { openWMOSceneByfdid(1120838); } + if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + m_currentScene = std::make_shared(m_api, "world/wmo/dungeon/az_karazahn/karazhan.wmo"); + m_api->camera->setCameraPos(0, 0, 0); + } if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { openWMOSceneByfdid(4419436); } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 4825f2144..9f9db68df 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -210,6 +210,50 @@ inline uint8_t getLiquidDepth(int liquidVertexFormat, float *vertexDataPtr, int return depth; } +struct LiquidObjectSettings { + bool generateTexCoordsFromPos; +}; + +const constexpr LiquidObjectSettings useTexCoordLiquidObject = { + .generateTexCoordsFromPos = false +}; +const constexpr LiquidObjectSettings usePlanarMapLiquidObject = { + .generateTexCoordsFromPos = true +}; + +const constexpr LiquidObjectSettings usePlanarMapLiquidObjectNoSky = { + .generateTexCoordsFromPos = true +}; + +const constexpr LiquidObjectSettings oceanLiquidObject = { + .generateTexCoordsFromPos = true +}; + +inline LiquidObjectSettings getLiquidSettings(int liquidObjectId, int liquidType, int materialId, bool db_generateTexCoordsFromPos) { + if (liquidObjectId < 41) { + if (materialId == 2) { + return useTexCoordLiquidObject; + } else if ( materialId == 1) { + if (liquidType == 2 || liquidType == 14) { + return oceanLiquidObject; + } else if (liquidType == 17) { + return usePlanarMapLiquidObjectNoSky; + } else { + return usePlanarMapLiquidObject; + } + } else if ( materialId == 5 && (liquidType == 350 || liquidType == 412) ) { + return usePlanarMapLiquidObjectNoSky; + } else { + return usePlanarMapLiquidObject; + } + } else if (liquidObjectId == 42 || liquidType == 14) { + return oceanLiquidObject; + } else { + return {.generateTexCoordsFromPos = db_generateTexCoordsFromPos}; + } +} + + HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water if (liquidInstance.offset_exists_bitmap > 0 && liquidInstance.height > 0) @@ -225,9 +269,11 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat int liquidFlags = 0; int liquidVertexFormat = 0; + bool generateTexCoordsFromPos = false; if (basetextureFDID == 0 && (m_api->databaseHandler != nullptr)) { - if (liquidInstance.liquid_object_or_lvf > 42) { + if (liquidInstance.liquid_object_or_lvf > 41) { + liquidVertexFormat = 2; std::vector liqMats; m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liqMats); for (auto &liqMat : liqMats) { @@ -240,6 +286,11 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat liquidFlags = liqMat.flags; liquidVertexFormat = liqMat.LVF; + generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, + liquidInstance.liquid_type, + liqMat.materialId, + liqMat.flowSpeed <=0).generateTexCoordsFromPos; + break; } } @@ -257,21 +308,28 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat minimapStaticCol = mathfu::vec3(ltd.minimapStaticCol[2], ltd.minimapStaticCol[1], ltd.minimapStaticCol[0]); liquidFlags = ltd.flags; liquidVertexFormat = ltd.LVF; + + generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, + liquidInstance.liquid_type, + ltd.materialId, + usePlanarMapLiquidObject.generateTexCoordsFromPos).generateTexCoordsFromPos; break; } } } } - if (!liquidInstance.offset_vertex_data && liquidInstance.liquid_type != 2) { - liquidVertexFormat = 2; - } - //Hack - if (liquidInstance.liquid_type == 2) { + + if (!liquidInstance.offset_vertex_data && liquidInstance.liquid_type != 2) { liquidVertexFormat = 2; } - +// +// //Hack +// if (liquidInstance.liquid_type == 2) { +// liquidVertexFormat = 2; +// } +// float *vertexDataPtr = nullptr; if (liquidInstance.offset_vertex_data != 0) { vertexDataPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data - m_adtFile->mH2OblobOffset])); @@ -325,10 +383,11 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat mathfu::vec2 uv = mathfu::vec2(0,0); if (vertexDataPtr!= nullptr) { pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); - uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } - if (liquidVertexFormat != 1 && liquidVertexFormat != 3 && liquidVertexFormat != 5) { - uv = mathfu::vec2(pos.x * 0.6, pos.y * 0.6); + if (generateTexCoordsFromPos) { + uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); + } else { + uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } minX = std::min(minX, pos.x); maxX = std::max(maxX, pos.x); @@ -976,6 +1035,10 @@ void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependant waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); } + auto time = m_mapApi->getCurrentSceneTime(); + + time + waterMaterial->m_materialPS->save(); } } diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 6125ff219..5d66a7a15 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -62,7 +62,11 @@ struct LightResult { struct LiquidMat { int FileDataId; std::string texture0Pattern; + int materialId; + int scrollSpeedX; + int scrollSpeedY; int LVF; + float flowSpeed; int OrderIndex; float color1[3]; float color2[3]; @@ -73,6 +77,9 @@ struct LiquidMat { struct LiquidTypeData { int FileDataId; std::string texture0Pattern; + int materialId; + int scrollSpeedX; + int scrollSpeedY; float color1[3]; float color2[3]; int flags; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index e9304138f..c32d80ae7 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -84,6 +84,9 @@ class IWaterMaterial : public IMaterial { public: mathfu::vec3 color; int liquidFlags; + int materialId; + float scrollSpeedX; + float scrollSpeedY; std::shared_ptr> m_materialPS = nullptr; }; From 3b04b5b25d2e313ddd1b3f98fa08967aa73702bd Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 18 Apr 2023 02:39:01 +0300 Subject: [PATCH 064/212] add portal rendering --- 3rdparty/DBImporter | 2 +- .../DatabaseUpdateWorkflow.cpp | 9 +- .../forwardRendering/drawPortalShader.frag | 2 +- .../forwardRendering/drawPortalShader.vert | 11 +- .../src/engine/algorithms/grahamScan.cpp | 59 +- .../src/engine/algorithms/mathHelper.cpp | 44 +- .../src/engine/algorithms/mathHelper.h | 4 +- .../src/engine/camera/firstPersonCamera.cpp | 4 + .../src/engine/camera/firstPersonCamera.h | 1 + .../src/engine/objects/ViewsObjects.cpp | 53 +- .../src/engine/objects/ViewsObjects.h | 4 +- .../src/engine/objects/adt/adtObject.cpp | 2 - .../src/engine/objects/scenes/map.cpp | 8 + .../src/engine/objects/wmo/wmoGroupObject.cpp | 25 +- .../src/engine/objects/wmo/wmoObject.cpp | 25 +- .../src/engine/objects/wmo/wmoObject.h | 2 + .../src/engine/shader/ShaderDefinitions.h | 988 +++++++++--------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 8 +- .../CommandBufferRecorder.cpp | 22 +- .../CommandBufferRecorder.h | 4 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 7 + .../renderer/mapScene/MapSceneRenderer.cpp | 6 - .../src/renderer/mapScene/MapSceneRenderer.h | 4 + .../mapScene/materials/IMaterialStructs.h | 5 + .../vulkan/MapSceneRenderForwardVLK.cpp | 51 +- .../vulkan/MapSceneRenderForwardVLK.h | 10 + 27 files changed, 722 insertions(+), 640 deletions(-) diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index 4c3c79c03..7188c49c3 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit 4c3c79c036308ffce91b5ea2c3d5712e64258964 +Subproject commit 7188c49c3a3ce1c309f71125876b60978b9ce213 diff --git a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp index 84e6ec533..9c007400b 100644 --- a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp +++ b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp @@ -7,6 +7,7 @@ #include "imgui_internal.h" #include "../../../persistance/httpFile/httpFile.h" #include "../../../../3rdparty/filesystem_impl/include/ghc/filesystem.hpp" +#include "../../../../3rdparty/DBImporter/fileReaders/WDC4/DB2Ver4.h" #include "../../../../3rdparty/DBImporter/fileReaders/DBD/DBDFile.h" #include "../../../../3rdparty/DBImporter/fileReaders/DBD/DBDFileStorage.h" #include "../../../../3rdparty/DBImporter/exporters/sqlite/CSQLLiteExporter.h" @@ -195,7 +196,13 @@ void DatabaseUpdateWorkflow::db2UpdateLogic() { std::shared_ptr csqlLiteExporter = std::make_shared("export.db3"); addTableLambda = [fileDBDStorage, csqlLiteExporter](std::string tableName, std::shared_ptr db2File) -> bool { - std::shared_ptr db2Base = std::make_shared(); + std::shared_ptr db2Base = nullptr; + if (*(uint32_t *)db2File->getContent()->data() == '4CDW') { + db2Base = std::make_shared(); + } else { + db2Base = std::make_shared(); + } + db2Base->process(db2File->getContent(), ""); DBDFile::BuildConfig *buildConfig = nullptr; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag index e967f262e..24312ecef 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag @@ -4,7 +4,7 @@ precision highp float; precision highp int; //Individual mesh -layout(std140, set=0, binding=4) uniform meshWideBlockPS { +layout(std140, set=0, binding=1) uniform meshWideBlockPS { vec4 uColor; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert index d8705404b..048d311b8 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert @@ -1,19 +1,24 @@ #version 450 +#extension GL_GOOGLE_include_directive: require + precision highp float; precision highp int; +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + /* vertex shader code */ layout(location = 0) in vec3 aPosition; //Whole scene layout(std140, binding=0) uniform sceneWideBlockVSPS { - mat4 uLookAtMat; - mat4 uPMatrix; + SceneWideParams scene; + PSFog fogData; }; void main() { vec4 worldPoint = vec4(aPosition.xyz, 1); - gl_Position = uPMatrix * uLookAtMat * worldPoint; + gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; } \ No newline at end of file diff --git a/wowViewerLib/src/engine/algorithms/grahamScan.cpp b/wowViewerLib/src/engine/algorithms/grahamScan.cpp index e22e610cd..8390a577f 100644 --- a/wowViewerLib/src/engine/algorithms/grahamScan.cpp +++ b/wowViewerLib/src/engine/algorithms/grahamScan.cpp @@ -1,16 +1,12 @@ //Adapted from https://github.com/kartikkukreja/blog-codes/blob/master/src/Graham%20Scan%20Convex%20Hull.cpp #include "grahamScan.h" #include +#include "mathHelper.h" using namespace std; -// Point having the least y coordinate, used for sorting other points -// according to polar angle about this point -//Point pivot; -Point p0; - // returns -1 if a -> b -> c forms a counter-clockwise turn, // +1 for a clockwise turn, 0 if they are collinear -int ccw(Point a, Point b, Point c) { +int ccw(const Point &a, const Point &b, const Point &c) { float area = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); if (area > 0) return -1; @@ -20,7 +16,7 @@ int ccw(Point a, Point b, Point c) { } // returns square of Euclidean distance between two points -float sqrDist(Point a, Point b) { +float sqrDist(Point &a, Point &b) { float dx = a.x - b.x, dy = a.y - b.y; return dx * dx + dy * dy; } @@ -43,7 +39,7 @@ void swap(Point &p1, Point &p2) // A utility function to return square of distance // between p1 and p2 -int distSq(Point p1, Point p2) +float distSq(const Point &p1, const Point &p2) { return (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y); @@ -54,30 +50,15 @@ int distSq(Point p1, Point p2) // 0 --> p, q and r are colinear // 1 --> Clockwise // 2 --> Counterclockwise -int orientation(Point p, Point q, Point r) +int orientation(const Point &p, const Point &q, const Point &r) { - int val = (q.y - p.y) * (r.x - q.x) - + float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); - if (val == 0) return 0; // colinear + if (feq(val, 0.0f, 0.00001f)) return 0; // colinear return (val > 0)? 1: 2; // clock or counterclock wise } -// A function used by library function qsort() to sort an array of -// points with respect to the first point -int compare(const void *vp1, const void *vp2) -{ - Point *p1 = (Point *)vp1; - Point *p2 = (Point *)vp2; - - // Find orientation - int o = orientation(p0, *p1, *p2); - if (o == 0) - return (distSq(p0, *p2) >= distSq(p0, *p1))? -1 : 1; - - return (o == 2)? -1: 1; -} - Point nextToTop(stack &S) { Point p = S.top(); @@ -90,29 +71,43 @@ Point nextToTop(stack &S) stack grahamScan(std::vector &points) { stack hull; // Find the bottommost point - int ymin = points[0].y, min = 0; + float ymin = points[0].y; + int min = 0; + int n = points.size(); for (int i = 1; i < n; i++) { - int y = points[i].y; + float y = points[i].y; // Pick the bottom-most or chose the left // most point in case of tie - if ((y < ymin) || (ymin == y && - points[i].x < points[min].x)) + if ((y < ymin) || (feq(ymin,y, 0.0001f) && points[i].x < points[min].x)) ymin = points[i].y, min = i; } // Place the bottom-most point at first position swap(points[0], points[min]); + // Point having the least y coordinate, used for sorting other points + // according to polar angle about this point + Point p0 = points[0]; + // Sort n-1 points with respect to the first point. // A point p1 comes before p2 in sorted ouput if p2 // has larger polar angle (in counterclockwise // direction) than p1 - p0 = points[0]; - qsort(&points[1], n-1, sizeof(Point), compare); + + std::sort(points.begin()+1, points.end(), [&p0](auto const &p1, auto const &p2) -> bool { + // Find orientation + int o = orientation(p0, p1, p2); + if (o == 0) + return feq(distSq(p0, p2),distSq(p0, p1)) + ? &p1 > &p2 // this is fallback to stabilize the sorting function + : distSq(p0, p2) >= distSq(p0, p1); + + return (o == 2); + }); // If two or more points make same angle with p0, // Remove all but the one that is farthest from p0 diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.cpp b/wowViewerLib/src/engine/algorithms/mathHelper.cpp index f43e78b5b..50416a042 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.cpp +++ b/wowViewerLib/src/engine/algorithms/mathHelper.cpp @@ -74,7 +74,7 @@ std::vector MathHelper::transformPlanesWithMat(const std::vector MathHelper::getFrustumClipsFromMatrix(const mathfu::mat4 &mat) { -#define el(x, y) (y-1) + 4*(x - 1) +#define el(x, y) (((y)-1) + 4*((x) - 1)) //The order of planes is changed to make it easier to get intersections in getIntersectionPointsFromPlanes //And to be in line of how planes are created for portal verticies in portal culling @@ -148,7 +148,7 @@ std::vector MathHelper::calculateFrustumPointsFromMat(mathfu::mat4 return points; } -bool hullSort(mathfu::vec3 a, mathfu::vec3 b, mathfu::vec2 center) { +bool hullSort(mathfu::vec3 &a, mathfu::vec3 &b, mathfu::vec2 ¢er) { if (a.x - center.x >= 0 && b.x - center.x < 0) return true; if (a.x - center.x < 0 && b.x - center.x >= 0) @@ -181,19 +181,24 @@ std::vector MathHelper::getHullPoints(std::vector &p return std::vector(0); } - mathfu::vec3* end = &hullPoints.top() + 1; - mathfu::vec3* begin = end - hullPoints.size(); - std::vector hullPointsArr(begin, end); +// mathfu::vec3* end = &hullPoints.top() + 1; +// mathfu::vec3* begin = end - hullPoints.size(); + std::vector hullPointsArr; + hullPointsArr.reserve(hullPoints.size()); + while(!hullPoints.empty()) { + hullPointsArr.push_back(hullPoints.top()); + hullPoints.pop(); + } mathfu::vec2 centerPoint = mathfu::vec2(0,0); - for (int i = 0; i< hullPoints.size(); i++) { + for (int i = 0; i< hullPointsArr.size(); i++) { centerPoint += hullPointsArr[i].xy(); } - centerPoint = centerPoint * (1.0f / hullPoints.size()); + centerPoint = centerPoint * (1.0f / hullPointsArr.size()); std::sort(hullPointsArr.begin(), hullPointsArr.end(), - [&](mathfu::vec3 a, mathfu::vec3 b) -> bool { + [&](const mathfu::vec3 &a, const mathfu::vec3 &b) -> bool { if (a.x - centerPoint.x >= 0 && b.x - centerPoint.x < 0) return true; if (a.x - centerPoint.x < 0 && b.x - centerPoint.x >= 0) @@ -462,7 +467,7 @@ bool MathHelper::planeCull(std::vector &points, std::vector vec4Points(points.size()); - const float epsilon = 0; + const float epsilon = 0.0001; for (int j = 0; j < points.size(); j++) { vec4Points[j] = mathfu::vec4(points[j].x, points[j].y, points[j].z, 1.0); @@ -471,10 +476,9 @@ bool MathHelper::planeCull(std::vector &points, std::vector &points, std::vector 0 && t2 > 0) { //p1 InFront and p2 InFront + if ((t1 >= 0) && (t2 >= 0)) { //p1 InFront and p2 InFront resultPoints.push_back(p2); - } else if (t1 > 0 && t2 < -epsilon) { //p1 InFront and p2 Behind + } else if ((t1 > 0) && (t2 < -epsilon)) { //p1 InFront and p2 Behind // float k = std::fabs(t1) / (std::fabs(t1) + std::fabs(t2)); resultPoints.push_back(MathHelper::planeLineIntersection( planes[i], p1, p2)); - } else if (t1 < -epsilon && t2 > 0) { //p1 Behind and p2 InFront + } else if ((t1 < -epsilon) && (t2 > 0)) { //p1 Behind and p2 InFront // float k = std::fabs(t1) / (std::fabs(t1) + std::fabs(t2)); resultPoints.push_back(MathHelper::planeLineIntersection( planes[i], p1, p2)); resultPoints.push_back(p2); - } else if (t2 < epsilon && t2 > -epsilon) { //P2 Inside + } else if ((t2 < epsilon) && (t2 > -epsilon)) { //P2 Inside resultPoints.push_back(p2); } } @@ -614,13 +618,13 @@ mathfu::vec3 MathHelper::getBarycentric(mathfu::vec3 &p, mathfu::vec3 &a, mathfu float d20 = mathfu::vec3::DotProduct(v2, v0); float d21 = mathfu::vec3::DotProduct(v2, v1); float denom = d00 * d11 - d01 * d01; - if ((denom < 0.0001) && (denom > -0.0001)) { + if ((denom < 0.0001f) && (denom > -0.0001f)) { return mathfu::vec3(-1, -1, -1); }; float v = (d11 * d20 - d01 * d21) / denom; float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0 - v - w; + float u = 1.0f - v - w; return mathfu::vec3(u, v, w); } @@ -678,7 +682,7 @@ int areIntersecting( // The fact that vector 2 intersected the infinite line 1 above doesn't // mean it also intersects the vector 1. Vector 1 is only a subset of that // infinite line 1, so it may have intersected that line before the vector - // started or after it ended. To know for sure, we have to repeat the + // started or after it ended. To know for sure, we have to repeat // the same test the other way round. We start by calculating the // infinite line 2 in linear equation standard form. a2 = v2y2 - v2y1; @@ -810,7 +814,7 @@ mathfu::vec3 MathHelper::calcExteriorColorDir(mathfu::mat4 lookAtMat, int time) return (lookAtRotation * sunDirWorld.xyz()); } -mathfu::vec3 MathHelper::hsv2rgb(MathHelper::hsv in) { +mathfu::vec3 MathHelper::hsv2rgb(const MathHelper::hsv &in) { double hh, p, q, t, ff; long i; mathfu::vec3 out; @@ -867,7 +871,7 @@ mathfu::vec3 MathHelper::hsv2rgb(MathHelper::hsv in) { return out; } -MathHelper::hsv MathHelper::rgb2hsv(mathfu::vec3 in) { +MathHelper::hsv MathHelper::rgb2hsv(const mathfu::vec3 &in) { hsv out; double min, max, delta; diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index 01c4a0b7f..dd6623716 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -45,8 +45,8 @@ class MathHelper { double v; // a fraction between 0 and 1 } hsv; - static hsv rgb2hsv(mathfu::vec3 in); - static mathfu::vec3 hsv2rgb(hsv in); + static hsv rgb2hsv(const mathfu::vec3 &in); + static mathfu::vec3 hsv2rgb(const hsv &in); static float fp69ToFloat(uint16_t x); diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 1ae944997..2dfc2fa08 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -151,6 +151,7 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); this->upVector = (lookAtRotation * upVector.xyz()); + updatedAtLeastOnce = true; } void FirstPersonCamera :: setCameraPos (float x, float y, float z) { //Reset camera @@ -182,6 +183,9 @@ HCameraMatrices FirstPersonCamera::getCameraMatrices(float fov, float canvasAspect, float nearPlane, float farPlane) { + if (!updatedAtLeastOnce) + tick(0.0f); + HCameraMatrices cameraMatrices = std::make_shared(); cameraMatrices->perspectiveMat = mathfu::mat4::Perspective( fov, diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.h b/wowViewerLib/src/engine/camera/firstPersonCamera.h index 84b0ea7a0..428e4a7dd 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.h @@ -33,6 +33,7 @@ class FirstPersonCamera: public ICamera { float m_moveSpeed = 1.0; bool staticCamera = false; + bool updatedAtLeastOnce = false; float ah = 0; float av = 0; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 768949249..55d1d9369 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -32,6 +32,10 @@ void GeneralView::collectMeshes(std::vector &opaqueMeshes, std::vectorcollectMeshes(opaqueMeshes, transparentMeshes, renderOrder); } + + for (auto const &mesh : portalPointsFrame.m_meshes) { + transparentMeshes.push_back(mesh); + } } void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos) { @@ -72,14 +76,7 @@ void GeneralView::setM2Lights(std::shared_ptr &m2Object) { m2Object->setUseLocalLighting(false); } -static std::array DrawPortalBindings = { - {+drawPortalShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 12, 0 }, // 0 - //24 -}; - -void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, std::vector &opaqueMeshes, std::vector &transparentMeshes) { -//TODO: - return; +void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer) { std::vector indiciesArray; std::vector verticles; int k = 0; @@ -116,29 +113,16 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st if (verticles.empty()) return; - auto hDevice = apiContainer->hDevice; - - //TODO: -// portalPointsFrame.m_indexVBO = hDevice->createIndexBuffer(); -// portalPointsFrame.m_bufferVBO = hDevice->createVertexBuffer(); - - portalPointsFrame.m_bindings = hDevice->createVertexBufferBindings(); - portalPointsFrame.m_bindings->setIndexBuffer(portalPointsFrame.m_indexVBO); - - auto const drawPortalBindings = std::vector(DrawPortalBindings.begin(), DrawPortalBindings.end()); - - portalPointsFrame.m_bindings->addVertexBufferBinding(portalPointsFrame.m_bufferVBO, drawPortalBindings); - portalPointsFrame.m_bindings->save(); - + //TODO: + portalPointsFrame.m_indexVBO = sceneRenderer->createPortalIndexBuffer((indiciesArray.size() * sizeof(uint16_t))); + portalPointsFrame.m_bufferVBO = sceneRenderer->createPortalVertexBuffer((verticles.size() * sizeof(float))); portalPointsFrame.m_indexVBO->uploadData((void *) indiciesArray.data(), (int) (indiciesArray.size() * sizeof(uint16_t))); portalPointsFrame.m_bufferVBO->uploadData((void *) verticles.data(), (int) (verticles.size() * sizeof(float))); - { - HGShaderPermutation shaderPermutation = hDevice->getShader("drawPortalShader", "drawPortalShader", nullptr); + portalPointsFrame.m_bindings = sceneRenderer->createPortalVAO(portalPointsFrame.m_bufferVBO, portalPointsFrame.m_indexVBO); - //Create mesh - gMeshTemplate meshTemplate(portalPointsFrame.m_bindings); + { PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; @@ -148,18 +132,19 @@ void GeneralView::produceTransformedPortalMeshes(HApiContainer &apiContainer, st pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + auto material = sceneRenderer->createPortalMaterial(pipelineTemplate); + auto &portalColor = material->m_materialPS->getObject(); + portalColor.uColor = {0.058, 0.058, 0.819607843, 0.3}; + material->m_materialPS->save(); + + //Create mesh + gMeshTemplate meshTemplate(portalPointsFrame.m_bindings); meshTemplate.start = 0; meshTemplate.end = indiciesArray.size(); - std::shared_ptr> drawPortalShaderMeshWideBlockPS = nullptr; - drawPortalShaderMeshWideBlockPS->setUpdateHandler([](auto &data, const HFrameDependantData &frameDepedantData) { - auto& blockPS = data; - - blockPS.uColor = {0.058, 0.058, 0.819607843, 0.3}; - }); - + auto mesh = sceneRenderer->createSortableMesh(meshTemplate, material, 0); -// transparentMeshes.push_back(hDevice->createMesh(meshTemplate)); + portalPointsFrame.m_meshes.push_back(mesh); } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index a6a825a71..a8d809544 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -46,13 +46,13 @@ class GeneralView { HGVertexBuffer m_bufferVBO; HGVertexBufferBindings m_bindings; - std::vector m_meshes = {}; + std::vector m_meshes = {}; } portalPointsFrame; virtual void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); - void produceTransformedPortalMeshes(HApiContainer &apiContainer,std::vector &opaqueMeshes, std::vector &transparentMeshes); + void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer); void addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos); }; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 9f9db68df..65aa99049 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -1037,8 +1037,6 @@ void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependant auto time = m_mapApi->getCurrentSceneTime(); - time - waterMaterial->m_materialPS->save(); } } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f198a6bfd..02909b7f0 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1394,6 +1394,14 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende std::tie(skyMesh, skyMeshMat) = createSkyMesh(sceneRenderer, skyMeshBinding, false); std::tie(skyMesh0x4Sky, skyMeshMat0x4) = createSkyMesh(sceneRenderer, skyMeshBinding, true); } + bool renderPortals = m_api->getConfig()->renderPortals; + + for (auto &view : renderPlan->viewsHolder.getInteriorViews()) { + if (renderPortals) { + view->produceTransformedPortalMeshes(sceneRenderer, m_api); + } + } + }; void Map::update(const HMapRenderPlan &renderPlan) { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index b5977ceac..dd4637440 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -40,6 +40,16 @@ void WmoGroupObject::update() { void WmoGroupObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { for (auto const &waterMaterial : m_waterMaterialArray) { auto waterChunk = waterMaterial->m_materialPS->getObject(); +/* + 1,3 - Water + 2,4 - Magma + 5 - Mercury, + 10 - Fog + 12 - LeyLine + 13 - Fel + 14 - Swamp + 18 - Azerithe +*/ if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean waterChunk.color = frameDependantData->closeOceanColor; @@ -258,6 +268,7 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere waterMaterialTemplate.color = mathfu::vec3(0,0,0); waterMaterialTemplate.liquidFlags = 0; + int waterMaterialId = 0; for (auto ltd: liquidTypeData) { if (ltd.FileDataId != 0) { basetextureFDID = ltd.FileDataId; @@ -266,6 +277,7 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere waterMaterialTemplate.color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); } waterMaterialTemplate.liquidFlags = ltd.flags; + waterMaterialId = ltd.materialId; break; } } @@ -278,6 +290,7 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere } auto waterMaterial = sceneRenderer->createWaterMaterial(m_wmoApi->getPlacementBuffer(),pipelineTemplate, waterMaterialTemplate); + waterMaterial->materialId = waterMaterialId; gMeshTemplate meshTemplate(binding); meshTemplate.meshType = MeshType::eWmoMesh; @@ -624,12 +637,12 @@ void WmoGroupObject::getBottomVertexesFromBspResult( if (m_geom->colorArray != nullptr) { auto &colorArr = m_geom->colorArray; colorUnderneath = mathfu::vec4( - bary[0] * colorArr[vertexInd1].r + bary[1] * colorArr[vertexInd1].r + - bary[2] * colorArr[vertexInd1].r, - bary[0] * colorArr[vertexInd1].g + bary[1] * colorArr[vertexInd1].g + - bary[2] * colorArr[vertexInd1].g, - bary[0] * colorArr[vertexInd1].b + bary[1] * colorArr[vertexInd1].b + - bary[2] * colorArr[vertexInd1].b, + bary[0] * colorArr[vertexInd1].r + bary[1] * colorArr[vertexInd2].r + + bary[2] * colorArr[vertexInd3].r, + bary[0] * colorArr[vertexInd1].g + bary[1] * colorArr[vertexInd2].g + + bary[2] * colorArr[vertexInd3].g, + bary[0] * colorArr[vertexInd1].b + bary[1] * colorArr[vertexInd2].b + + bary[2] * colorArr[vertexInd3].b, 0 ) * (1 / 255.0f); } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 282b57064..fefad728f 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -289,6 +289,7 @@ void WmoObject::createWorldPortals() { lookAt, center, upVector +// 1.0f ); mathfu::mat4 viewMatInv = viewMat.Inverse(); @@ -818,6 +819,8 @@ bool WmoObject::startTraversingWMOGroup( //For interior cull mathfu::mat4 MVPMat = frustumDataGlobal.perspectiveMat*frustumDataGlobal.viewMat*this->m_placementMatrix; + mathfu::mat4 MVPMatInv = MVPMat.Inverse(); + std::vector frustumPointsLocal = MathHelper::calculateFrustumPointsFromMat(MVPMat); std::vector frustumPlanesLocal = MathHelper::getFrustumClipsFromMatrix(MVPMat); // mathfu::vec4 headOfPyramidLocal = mathfu::vec4(MathHelper::getIntersection( @@ -835,6 +838,8 @@ bool WmoObject::startTraversingWMOGroup( cameraVec4, cameraLocal, transposeInverseModelMat, + MVPMat, + MVPMatInv, transverseVisitedPortals }; @@ -1092,13 +1097,31 @@ void WmoObject::traverseGroupWmo( thisPortalPlanes.reserve(lastFrustumPlanesLen); if (hackCondition) { + //Transform portal vertexes into clip space (this code should allow to use this logic with both Perspective and Ortho) + std::vector portalVerticesClip(portalVerticesVec.size()); + std::vector portalVerticesClipNearPlane(portalVerticesVec.size()); + + for (int i = 0; i < portalVerticesVec.size(); i++) { + portalVerticesClip[i] = traverseTempData.MVPMat * mathfu::vec4(portalVerticesVec[i], 1.0f); + portalVerticesClip[i] = portalVerticesClip[i]/portalVerticesClip[i].w; + } + + for (int i = 0; i < portalVerticesVec.size(); i++) { + //Project Portal vertex to near plane in clip space + portalVerticesClipNearPlane[i] = portalVerticesClip[i]; + portalVerticesClipNearPlane[i].z = 0; + //Transform back to local space + portalVerticesClipNearPlane[i] = traverseTempData.MVPMatInv * portalVerticesClipNearPlane[i]; + portalVerticesClipNearPlane[i] /= portalVerticesClipNearPlane[i].w; + } + bool flip = (relation->side > 0); int portalCnt = portalVerticesVec.size(); for (int i = 0; i < portalCnt; ++i) { int i2 = (i + 1) % portalCnt; - mathfu::vec4 n = MathHelper::createPlaneFromEyeAndVertexes(traverseTempData.cameraLocal.xyz(), + mathfu::vec4 n = MathHelper::createPlaneFromEyeAndVertexes(portalVerticesClipNearPlane[i].xyz(), portalVerticesVec[i], portalVerticesVec[i2]); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index dc2ffc50a..f0560e718 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -39,6 +39,8 @@ class WmoObject : public IWmoApi { mathfu::vec4 &cameraVec4; mathfu::vec4 &cameraLocal; mathfu::mat4 &transposeInverseModelMat; + mathfu::mat4 &MVPMat; + mathfu::mat4 &MVPMatInv; std::vector &transverseVisitedPortals; bool atLeastOneGroupIsDrawn = false; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 65d647fc8..faf1629c3 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,16}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,4,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,11 +445,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, }, { { @@ -464,12 +479,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,11 +513,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -519,20 +534,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +550,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +585,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +604,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +619,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +638,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, - }, + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +655,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +676,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +700,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +735,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +768,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +787,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +803,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,15 +837,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,1,12}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -863,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +905,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +938,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +956,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +971,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1005,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1024,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1039,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1058,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1108,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,14080}, - {0,1,64}, {0,0,368}, - {0,7,64}, - {0,6,4096}, - {0,4,4096}, - {0,5,256}, }, { { - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1142,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1176,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1195,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1210,20 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1234,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1288,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1322,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1341,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1356,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1391,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1410,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, }, { { + {3,3,1}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1426,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1459,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1479,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,17 +1497,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, + {0,3,14080}, + {0,1,64}, {0,0,368}, - {0,1,14144}, + {0,7,64}, + {0,6,4096}, }, { { - {1,1,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1525,15 +1520,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, }, { { {0,0,0}, - {5,9,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1544,12 +1535,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,48}, {0,0,368}, }, { @@ -1565,12 +1555,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {8,8,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1584,23 +1574,7 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1622,6 +1596,18 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1930,27 +1947,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_0_4_values0", true, 0, 1, 4, 0}, + {"_0_4_values1", true, 16, 1, 4, 0}, + {"_0_4_values2", true, 32, 1, 4, 0}, + {"_0_4_values3", true, 48, 1, 4, 0}, + {"_0_4_values4", true, 64, 1, 4, 0}, + {"_0_4_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1966,29 +1969,23 @@ const std::unordered_map swapChainImages = {}; swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); + ERR_GUARD_VULKAN(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data())); swapChainExtent = extent; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index b1a8bf644..1151bba1f 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -45,7 +45,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, std::shared_ptr h_depthTexture; h_depthTexture.reset(new GTextureVLK( mdevice, - width, height, + std::max(width, 1), std::max(height, 1), false, false, true, fbDepthFormat, @@ -85,6 +85,12 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, std::vector attachments; + height = std::max(height, 1); + width = std::max(width, 1); + + m_height = height; + m_width = width; + //Encapsulated for loop iterateOverAttachments(textureAttachments, [&](int i, VkFormat textureFormat) { std::shared_ptr h_texture; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index b7ba78b74..92027a10b 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -107,28 +107,34 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector vbos = {}; - std::vector offsets = {}; + assert(buffers.size() <= MAX_VERTEX_BUFFERS_PER_DRAWCALL); + + std::array vbos = {}; + std::array offsets = {}; + int vboCnt = 0; + int offsetCnt = 0; + for (int i = 0; i < buffers.size(); i++) { auto bufferVlk = std::dynamic_pointer_cast(buffers[i]); + auto pbufferVlk = bufferVlk.get(); //firstBinding == i <- means we can only skip the start of the list; if (firstBinding == i && m_currentVertexBuffers[i] != nullptr && - m_currentVertexBuffers[i]->getGPUBuffer() == bufferVlk->getGPUBuffer() && - m_currentVertexBuffers[i]->getOffset() == bufferVlk->getOffset()) { + m_currentVertexBuffers[i]->getGPUBuffer() == pbufferVlk->getGPUBuffer() && + m_currentVertexBuffers[i]->getOffset() == pbufferVlk->getOffset()) { firstBinding++; continue; } - vbos.push_back(bufferVlk->getGPUBuffer()); - offsets.push_back(bufferVlk->getOffset()); + vbos[vboCnt++] = pbufferVlk->getGPUBuffer(); + offsets[offsetCnt++] = pbufferVlk->getOffset(); m_currentVertexBuffers[i] = bufferVlk; } - int bindingCount = vbos.size(); - if (vbos.empty()) return; + int bindingCount = vboCnt; + if (vboCnt == 0) return; vkCmdBindVertexBuffers(m_gCmdBuffer.m_cmdBuffer, firstBinding, bindingCount, vbos.data(), offsets.data()); } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 9a6c78295..242f0639e 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -59,11 +59,13 @@ class CmdBufRecorder { private: const GCommandBuffer &m_gCmdBuffer; + static constexpr int MAX_VERTEX_BUFFERS_PER_DRAWCALL = 2; + //States std::shared_ptr m_currentRenderPass = nullptr; std::shared_ptr m_currentPipeline = nullptr; std::shared_ptr m_currentIndexBuffer = nullptr; - std::array, 2> m_currentVertexBuffers; + std::array, MAX_VERTEX_BUFFERS_PER_DRAWCALL> m_currentVertexBuffers; std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; bool m_currentScissorsIsDefault = false; ViewportType m_currentViewport = ViewportType::vp_none; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 469d9216d..298ddac5c 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -56,8 +56,13 @@ class IMapSceneBufferCreate { virtual HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + virtual HGVertexBufferBindings createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; + + virtual HGVertexBuffer createPortalVertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createPortalIndexBuffer(int sizeInBytes) = 0; virtual HGVertexBuffer createM2VertexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; virtual HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) = 0; @@ -100,6 +105,8 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createWaterMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WaterMaterialTemplate &waterMaterialTemplate) = 0; + + virtual std::shared_ptr createPortalMaterial(const PipelineTemplate &pipelineTemplate) = 0; //------------------------------------- // Mesh creation //------------------------------------- diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 9febbb194..92fafb890 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -48,9 +48,6 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende bool renderPortals = m_config->renderPortals; for (auto &view : cullStage->viewsHolder.getInteriorViews()) { view->collectMeshes(opaqueMeshes, transparentMeshes); - if (renderPortals) { -// view->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); - } } interiorViewCollectMeshCounter.endMeasurement(); @@ -59,9 +56,6 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); - if (renderPortals) { -// exteriorView->produceTransformedPortalMeshes(m_api, opaqueMeshes, transparentMeshes); - } } } exteriorViewCollectMeshCounter.endMeasurement(); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 3126d22f4..fecb8b6f9 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -74,6 +74,10 @@ static std::vector adtVertexBufferLODBinding = {{ {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} }}; +static std::vector drawPortalBindings = {{ + {+drawPortalShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 12, 0}, // 0 + }}; + class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index c32d80ae7..7bc877967 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -90,4 +90,9 @@ class IWaterMaterial : public IMaterial { std::shared_ptr> m_materialPS = nullptr; }; +class IPortalMaterial : public IMaterial { +public: + std::shared_ptr> m_materialPS = nullptr; +}; + #endif //AWEBWOWVIEWERCPP_IMATERIALSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 32ccd3f97..638f5f895 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -16,13 +16,14 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer(1024*1024); - vboM2Buffer = m_device->createVertexBuffer(1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); - vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); - vboWMOBuffer = m_device->createVertexBuffer(1024*1024); - vboWaterBuffer = m_device->createVertexBuffer(1024*1024); - vboSkyBuffer = m_device->createVertexBuffer(1024*1024); - vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); + vboM2Buffer = m_device->createVertexBuffer(1024*1024); + vboPortalBuffer = m_device->createVertexBuffer(1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); + vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); + vboWMOBuffer = m_device->createVertexBuffer(1024*1024); + vboWaterBuffer = m_device->createVertexBuffer(1024*1024); + vboSkyBuffer = m_device->createVertexBuffer(1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); { const float epsilon = 0.f; @@ -58,6 +59,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_emptySkyVAO = createSkyVAO(nullptr, nullptr); m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); + m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; @@ -140,6 +142,22 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createSkyVAO(HGVertexBuffer ver return skyVAO; } +HGVertexBufferBindings MapSceneRenderForwardVLK::createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto portalVAO = m_device->createVertexBufferBindings(); + portalVAO->addVertexBufferBinding(vertexBuffer, std::vector(drawPortalBindings.begin(), drawPortalBindings.end())); + portalVAO->setIndexBuffer(indexBuffer); + + return portalVAO; +}; + +HGVertexBuffer MapSceneRenderForwardVLK::createPortalVertexBuffer(int sizeInBytes) { + return vboPortalBuffer->getSubBuffer(sizeInBytes); +}; +HGIndexBuffer MapSceneRenderForwardVLK::createPortalIndexBuffer(int sizeInBytes){ + return iboBuffer->getSubBuffer(sizeInBytes); +}; + HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { return vboM2Buffer->getSubBuffer(sizeInBytes); } @@ -374,6 +392,24 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria return material; } +std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto materialPS = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}) + .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, materialPS->getSubBuffer()); + }) + .toMaterial([&materialPS](IPortalMaterial *instance) -> void { + instance->m_materialPS = materialPS; + }); + + return material; +} + std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); @@ -488,6 +524,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index eced2f8d3..16bc092f1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -30,6 +30,10 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + + HGVertexBuffer createPortalVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createPortalIndexBuffer(int sizeInBytes) override; HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; @@ -72,6 +76,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; + std::shared_ptr createPortalMaterial(const PipelineTemplate &pipelineTemplate) override; + //------------------------------------- // Mesh creation //------------------------------------- @@ -89,6 +95,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; + HGBufferVLK vboPortalBuffer; + HGBufferVLK vboAdtBuffer; HGBufferVLK vboWMOBuffer; HGBufferVLK vboWMOGroupAmbient; @@ -96,6 +104,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK vboSkyBuffer; HGBufferVLK iboBuffer; + HGBufferVLK uboStaticBuffer; HGBufferVLK uboBuffer; HGBufferVLK uboM2BoneMatrixBuffer; @@ -115,6 +124,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptyADTVAO = nullptr; HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; + HGVertexBufferBindings m_emptyPortalVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; From 796448d877bba5e1a5c50751a91229907b1e1ad2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 24 Apr 2023 19:29:49 +0300 Subject: [PATCH 065/212] proper sunDir, semi fix for portal culling, fix for blp texture color --- src/ui/FrontendUI.cpp | 3 + .../src/engine/algorithms/mathHelper.cpp | 203 ++-- .../src/engine/algorithms/mathHelper.h | 2 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 1 + .../src/engine/objects/wmo/wmoObject.cpp | 10 +- .../src/engine/shader/ShaderDefinitions.h | 977 +++++++++--------- .../src/engine/texture/BlpTexture.cpp | 77 +- wowViewerLib/src/engine/texture/BlpTexture.h | 3 +- 8 files changed, 711 insertions(+), 565 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index c3c665780..08c4fd446 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -756,6 +756,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("Stormwind mage portal", ImVec2(-1, 0))) { openM2SceneByfdid(2394711, replacementTextureFDids); } + if (ImGui::Button("kodobeasttame", ImVec2(-1, 0))) { + openM2SceneByfdid(124697, replacementTextureFDids); + } // if (ImGui::Button("Azeroth map: Lion's Rest (Legion)", ImVec2(-1, 0))) { // openMapByIdAndFilename(0, "azeroth", -8739, 944, 200); diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.cpp b/wowViewerLib/src/engine/algorithms/mathHelper.cpp index 50416a042..3ad6721a7 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.cpp +++ b/wowViewerLib/src/engine/algorithms/mathHelper.cpp @@ -473,7 +473,6 @@ bool MathHelper::planeCull(std::vector &points, std::vector &points, std::vector resultPoints; - -// mathfu::vec3 pointO; -// if (planes[i][2] != 0) { -// pointO = mathfu::vec3(0, 0, -planes[i][3] / planes[i][2]); -// } else if (planes[i][1] != 0) { -// pointO = mathfu::vec3(0, -planes[i][3] / planes[i][1], 0); -// } else if (planes[i][0] != 0) { -// pointO = mathfu::vec3(-planes[i][3] / planes[i][0], 0, 0); -// } else { -// continue; -// } + resultPoints.reserve(vec4Points.size() + (vec4Points.size() >> 1)); for (int j = 0; j < vec4Points.size(); j++) { mathfu::vec4 p1 = vec4Points[j]; mathfu::vec4 p2 = vec4Points[(j + 1) % vec4Points.size()]; - mathfu::vec3 p1_xyz = p1.xyz(); - mathfu::vec3 p2_xyz = p2.xyz(); - // InFront = plane.Distance( point ) > 0.0f // Behind = plane.Distance( point ) < 0.0f float t1 = mathfu::vec4::DotProduct(p1, planes[i]); float t2 = mathfu::vec4::DotProduct(p2, planes[i]); - if ((t1 >= 0) && (t2 >= 0)) { //p1 InFront and p2 InFront + if ((t1 >= -epsilon) && (t2 >= -epsilon)) { //p1 InFront and p2 InFront resultPoints.push_back(p2); - } else if ((t1 > 0) && (t2 < -epsilon)) { //p1 InFront and p2 Behind + } else if ((t1 >= -epsilon) && (t2 < -epsilon)) { //p1 InFront and p2 Behind // float k = std::fabs(t1) / (std::fabs(t1) + std::fabs(t2)); resultPoints.push_back(MathHelper::planeLineIntersection( planes[i], p1, p2)); - } else if ((t1 < -epsilon) && (t2 > 0)) { //p1 Behind and p2 InFront + } else if ((t1 < -epsilon) && (t2 >= -epsilon)) { //p1 Behind and p2 InFront // float k = std::fabs(t1) / (std::fabs(t1) + std::fabs(t2)); resultPoints.push_back(MathHelper::planeLineIntersection( planes[i], p1, p2)); resultPoints.push_back(p2); @@ -749,69 +735,170 @@ bool MathHelper::isAabbIntersect2d(CAaBox a, CAaBox b) { return result; } -mathfu::vec3 MathHelper::calcExteriorColorDir(mathfu::mat4 lookAtMat, int time) { + +template +constexpr float InterpTable(const std::array, tableSize> &table, float time) { + + if (time >= 0.0f) { + time = std::min(time, 1.0f); + } + + int i; + int firstIndex = 0; + int secondIndex = 0; + for (i = 0; i < table.size(); i++) { + if (time <= table[i][0]) { + break; + } + } + + firstIndex = 0; + if (i != table.size()) { + firstIndex = i; + } + if (firstIndex) { + secondIndex = firstIndex - 1; + } else { + secondIndex = table.size() - 1; + } + + float tableTimeDiff = table[firstIndex][0] - table[secondIndex][0]; + if (fabs(tableTimeDiff) < 0.001f) + return table[secondIndex][1]; + + if (tableTimeDiff < 0.0f) + tableTimeDiff = tableTimeDiff + 1.0f; + + float timeDiff = time - table[secondIndex][0]; + if (timeDiff < 0.0f) + timeDiff = timeDiff + 1.0f; + + float alpha = timeDiff / tableTimeDiff; + + float firstValue = table[firstIndex][1]; + float secondValue = table[secondIndex][1]; + //if (firstValue < secondValue) + //return table[secondIndex].y - alpha * (secondValue - firstValue); + //else + return secondValue + alpha * (firstValue - secondValue); + +} + +float doSomeConvert(float a) { + int a1; + if ( a <= 0.0f ) + { + a1 = ~(int)(float)-a; + } + else + { + a1 = (int)a; + } + + float res = (float)((float)((float)((float)(a - (float)a1) * 4.0f) + -6.0f) + * (float)((float)(a - (float)a1) * (float)(a - (float)a1))) + + 1.0f; + if ( (a1 & 1) != 0 ) + { + res = -res; + } + + return res; +} + +mathfu::vec3 MathHelper::calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int time) { // Phi Table - static const std::array, 4> phiTable = { + static constexpr std::array, 5> sunPhiTable = { { - { 0.0f, 2.2165682f }, - { 0.25f, 1.9198623f }, - { 0.5f, 2.2165682f }, - { 0.75f, 1.9198623f } + { 0.25f, 1.7453293f }, + { 0.49652779f, 0.08726646f}, + { 0.5f, 0.08726646f}, + { 0.50347221f, 0.08726646f}, + { 0.79166669f, 1.7453293f } } }; - // Theta Table + static constexpr std::array, 3> sunThetaTable = { + { + { 0.25f, 0.78539819f}, + { 0.5f, 0.78539819f}, + { 0.79166669f, 0.78539819f} + } + }; + static constexpr std::array, 5> moonPhiTable = { + { + { 0, 0.61086524f }, + { 0.0034722222f,0.61086524 }, + { 0.16666667f, 1.7453293f }, + { 0.89583331f, 1.7453293f }, + { 0.99652779f, 0.61086524f } + } + }; - static const std::array, 4> thetaTable = { + static constexpr std::array, 3> moonThetaTable = { { - {0.0f, 3.926991f}, - {0.25f, 3.926991f}, - { 0.5f, 3.926991f }, - { 0.75f, 3.926991f } + { 0.0f, 0.78539819f}, + { 0.16666667f, 0.78539819f}, + { 0.89583331f, 0.78539819f} + } + }; + + static constexpr std::array, 4> directionalLightPhiTable = { + { + { 0, 2.2165682f }, + { 0.25f, 1.9198622f }, + { 0.5f, 2.2165682f }, + { 0.75f, 1.9198622f }, + } + }; + + static constexpr std::array, 4> directionalLightThetaTable = { + { + { 0, 3.9269907f }, + { 0.25f, 3.9269907f }, + { 0.5f, 3.9269907f }, + { 0.75f, 3.9269907f }, } }; -// float phi = DayNight::InterpTable(&DayNight::phiTable, 4u, DayNight::g_dnInfo.dayProgression); -// float theta = DayNight::InterpTable(&DayNight::thetaTable, 4u, DayNight::g_dnInfo.dayProgression); - float phi = phiTable[0][1]; - float theta = thetaTable[0][1]; + + float phi = sunPhiTable[0][1]; + float theta = sunThetaTable[0][1]; //Find Index float timeF = time / 2880.0f; - int firstIndex = -1; - for (int i = 0; i < 4; i++) { - if (timeF < phiTable[i][0]) { - firstIndex = i; - break; - } - } - if (firstIndex == -1) { - firstIndex = 3; - } - { - float alpha = (phiTable[firstIndex][0] - timeF) / (thetaTable[firstIndex][0] - thetaTable[firstIndex-1][0]); - phi = phiTable[firstIndex][1]*(1.0 - alpha) + phiTable[firstIndex - 1][1]*alpha; - } - // Convert from spherical coordinates to XYZ - // x = rho * sin(phi) * cos(theta) - // y = rho * sin(phi) * sin(theta) - // z = rho * cos(phi) + phi = InterpTable<4>(directionalLightPhiTable, timeF); + theta = InterpTable<4>(directionalLightThetaTable, timeF); + +// if ( timeF >= 0.22222222f && timeF <= 0.81944448f ) +// { +// phi = InterpTable<5>(sunPhiTable, timeF); +// theta = InterpTable<3>(sunThetaTable, timeF); +// } +// else +// { +// phi = InterpTable<5>(moonPhiTable, timeF); +// theta = InterpTable<3>(moonThetaTable, timeF); +// } + constexpr float INV_PI = 1.0f / M_PI; - float sinPhi = (float) sin(phi); - float cosPhi = (float) cos(phi); + float sinPhi = doSomeConvert(phi * INV_PI - 0.5f); + float cosPhi = doSomeConvert(phi * INV_PI); - float sinTheta = (float) sin(theta); - float cosTheta = (float) cos(theta); + float sinTheta = doSomeConvert(theta * INV_PI + -0.5f); + float cosTheta = doSomeConvert(theta * INV_PI); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); mathfu::vec4 sunDirWorld = mathfu::vec4(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi, 0); +// sunDirWorld = mathfu::vec4(sunDirWorld.x, sunDirWorld.x, sunDirWorld.x, 0); + sunDirWorld = mathfu::vec4(sunDirWorld.xyz().Normalized(), 0.0f); +// mathfu::vec4 sunDirWorld = mathfu::vec4(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi, 0); // mathfu::vec4 sunDirWorld = mathfu::vec4(-0.30822, -0.30822, -0.89999998, 0); - return (lookAtRotation * sunDirWorld.xyz()); + return (lookAtMat.Inverse().Transpose() * sunDirWorld).xyz().Normalized(); } mathfu::vec3 MathHelper::hsv2rgb(const MathHelper::hsv &in) { diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index dd6623716..a3e0dc9cd 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -132,7 +132,7 @@ class MathHelper { static float distance_aux(float p, float lower, float upper); static float distanceFromAABBToPoint2DSquared(const mathfu::vec2 aabb[2], mathfu::vec2 &p); - static mathfu::vec3 calcExteriorColorDir(mathfu::mat4 lookAtMat, int time); + static mathfu::vec3 calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int time); }; const float ROUNDING_ERROR_f32 = 0.001f; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index dd4637440..2c09228b8 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -499,6 +499,7 @@ bool WmoGroupObject::getTopAndBottomTriangleFromBsp( getBottomVertexesFromBspResult(portalInfos, portalRels, bspLeafList, cameraLocal, topZ, bottomZ, tempColor); //2. Try to get top and bottom from portal planes + // (That's for case when the portal plane is horizontal) MOGP *groupInfo = this->m_geom->mogp; int moprIndex = groupInfo->moprIndex; int numItems = groupInfo->moprCount; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index fefad728f..d021da794 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1103,7 +1103,7 @@ void WmoObject::traverseGroupWmo( for (int i = 0; i < portalVerticesVec.size(); i++) { portalVerticesClip[i] = traverseTempData.MVPMat * mathfu::vec4(portalVerticesVec[i], 1.0f); - portalVerticesClip[i] = portalVerticesClip[i]/portalVerticesClip[i].w; + portalVerticesClip[i] /= portalVerticesClip[i].w; } for (int i = 0; i < portalVerticesVec.size(); i++) { @@ -1115,11 +1115,13 @@ void WmoObject::traverseGroupWmo( portalVerticesClipNearPlane[i] /= portalVerticesClipNearPlane[i].w; } + //This condition works, bcuz earlier it's verified we are inside the portal using the + //dot product AND `relation->side` bool flip = (relation->side > 0); - int portalCnt = portalVerticesVec.size(); - for (int i = 0; i < portalCnt; ++i) { - int i2 = (i + 1) % portalCnt; + int vertexCnt = portalVerticesVec.size(); + for (int i = 0; i < vertexCnt; ++i) { + int i2 = (i + 1) % vertexCnt; mathfu::vec4 n = MathHelper::createPlaneFromEyeAndVertexes(portalVerticesClipNearPlane[i].xyz(), portalVerticesVec[i], diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index faf1629c3..8c09518c0 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,11 +430,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -479,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -513,12 +499,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,32}, {0,0,368}, }, { @@ -534,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {8,8,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -550,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -585,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -604,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -619,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -638,16 +633,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, - }, - { - { - {0,0,0}, - {5,6,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, + }, + { + { + {0,0,0}, + {5,13,9}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -655,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -676,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -700,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -735,14 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -768,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -787,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -837,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -871,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -905,14 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,2,16}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -938,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -956,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -971,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1005,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1039,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1058,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1108,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,14080}, + {0,1,64}, {0,0,368}, + {0,7,64}, + {0,6,4096}, + {0,4,4096}, + {0,5,256}, }, { { - {0,0,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1142,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1176,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,16}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1195,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1210,20 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1234,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1288,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1322,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1341,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1356,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1391,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1410,12 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, + {1,5, "uTexture"}, }, { { - {3,3,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1426,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1459,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1479,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1497,19 +1504,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,14080}, - {0,1,64}, + {0,4,96}, {0,0,368}, - {0,7,64}, - {0,6,4096}, + {0,1,14144}, }, { { - {6,6,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1520,11 +1525,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uNormalTex"}, + {1,7, "uNoise"}, + {1,6, "uWhiteWater"}, + {1,5, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {5,9,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,11 +1544,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,2,144}, + {0,1,14144}, {0,0,368}, }, { @@ -1555,12 +1565,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,8, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {8,8,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1574,7 +1584,23 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1596,18 +1622,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1947,13 +1945,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -1969,23 +1981,29 @@ const std::unordered_mappreferredFormat == BLPPixelFormat::PIXEL_UNSPECIFIED) { - //If the - if (blpFile->colorEncoding == BLPColorEncoding::COLOR_PALETTE) { - uint8_t *paleteData = data; - validSize = 4 * width * height; - mipmapStruct.texture = std::vector(validSize, 0); - - for (int j = 0; j < width * height; j++) { - uint8_t colIndex = paleteData[j]; - uint8_t b = blpFile->palette[colIndex * 4 + 0]; - uint8_t g = blpFile->palette[colIndex * 4 + 1]; - uint8_t r = blpFile->palette[colIndex * 4 + 2]; - uint8_t a = paleteData[width * height + j]; - - mipmapStruct.texture[j * 4 + 0] = r; - mipmapStruct.texture[j * 4 + 1] = g; - mipmapStruct.texture[j * 4 + 2] = b; - mipmapStruct.texture[j * 4 + 3] = a; - } - } else if (blpFile->colorEncoding == BLPColorEncoding::COLOR_ARGB8888) { - //Turn BGRA into RGBA - - validSize = 4 * width * height; - mipmapStruct.texture = std::vector(validSize, 0); - for (int j = 0; j < width * height; j++) { - uint8_t b = data[j * 4 + 0]; - uint8_t g = data[j * 4 + 1]; - uint8_t r = data[j * 4 + 2]; - uint8_t a = data[j * 4 + 3]; - - mipmapStruct.texture[j * 4 + 0] = r; - mipmapStruct.texture[j * 4 + 1] = g; - mipmapStruct.texture[j * 4 + 2] = b; - mipmapStruct.texture[j * 4 + 3] = a; - } - } else { - std::copy(data, data + blpFile->lengths[i], &mipmapStruct.texture[0]); + if (blpFile->preferredFormat == BLPPixelFormat::PIXEL_UNSPECIFIED && + blpFile->colorEncoding == BLPColorEncoding::COLOR_PALETTE) + { + uint8_t* paleteData = data; + validSize = 4 * width * height; + mipmapStruct.texture = std::vector(validSize, 0); + + for (int j = 0; j < width * height; j++) { + uint8_t colIndex = paleteData[j]; + uint8_t b = blpFile->palette[colIndex * 4 + 0]; + uint8_t g = blpFile->palette[colIndex * 4 + 1]; + uint8_t r = blpFile->palette[colIndex * 4 + 2]; + uint8_t a = paleteData[width * height + j]; + + mipmapStruct.texture[j * 4 + 0] = r; + mipmapStruct.texture[j * 4 + 1] = g; + mipmapStruct.texture[j * 4 + 2] = b; + mipmapStruct.texture[j * 4 + 3] = a; + } + } + else if ((blpFile->preferredFormat == BLPPixelFormat::PIXEL_UNSPECIFIED && + blpFile->colorEncoding == BLPColorEncoding::COLOR_ARGB8888) || + (blpFile->preferredFormat == BLPPixelFormat::PIXEL_ARGB8888 && + blpFile->colorEncoding == BLPColorEncoding::COLOR_ARGB8888)) + { + //Turn BGRA into RGBA + + validSize = 4 * width * height; + mipmapStruct.texture = std::vector(validSize, 0); + for (int j = 0; j < width * height; j++) { + uint8_t b = data[j * 4 + 0]; + uint8_t g = data[j * 4 + 1]; + uint8_t r = data[j * 4 + 2]; + uint8_t a = data[j * 4 + 3]; + + mipmapStruct.texture[j * 4 + 0] = r; + mipmapStruct.texture[j * 4 + 1] = g; + mipmapStruct.texture[j * 4 + 2] = b; + mipmapStruct.texture[j * 4 + 3] = a; } } else { std::copy(data, data + blpFile->lengths[i], &mipmapStruct.texture[0]); @@ -142,6 +144,7 @@ HMipmapsVector parseMipmaps(BlpFile *blpFile, TextureFormat textureFormat) { height = (height == 0) ? 1 : height; width = (width == 0) ? 1 : width; } + return mipmaps; } diff --git a/wowViewerLib/src/engine/texture/BlpTexture.h b/wowViewerLib/src/engine/texture/BlpTexture.h index e6f07d13e..5a1a0beef 100644 --- a/wowViewerLib/src/engine/texture/BlpTexture.h +++ b/wowViewerLib/src/engine/texture/BlpTexture.h @@ -34,7 +34,7 @@ typedef std::shared_ptr> HMipmapsVector; class BlpTexture : public PersistentFile{ public: explicit BlpTexture(std::string fileName){ m_textureName = fileName;}; - explicit BlpTexture(int fileDataId){m_textureName = std::to_string(fileDataId);}; + explicit BlpTexture(int fileDataId){m_textureName = std::to_string(fileDataId); m_fileDataId = fileDataId; }; std::string getTextureName() { return m_textureName; }; void process(HFileContent blpFile, const std::string &fileName) override; @@ -47,6 +47,7 @@ class BlpTexture : public PersistentFile{ } private: std::string m_textureName; + int m_fileDataId = 0; HMipmapsVector m_mipmaps; TextureFormat m_textureFormat = TextureFormat::Undetected; From 758fe8508b4312e772d87c631da3d448f4f46ab0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 26 Apr 2023 10:43:39 +0300 Subject: [PATCH 066/212] first iteration of offsetAllocator --- 3rdparty/OffsetAllocator/CMakeLists.txt | 11 + 3rdparty/OffsetAllocator/LICENSE | 21 + 3rdparty/OffsetAllocator/README.md | 75 +++ 3rdparty/OffsetAllocator/offsetAllocator.cpp | 533 ++++++++++++++++++ 3rdparty/OffsetAllocator/offsetAllocator.hpp | 102 ++++ .../OffsetAllocator/offsetAllocatorTests.cpp | 260 +++++++++ .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 12 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 4 +- 8 files changed, 1007 insertions(+), 11 deletions(-) create mode 100644 3rdparty/OffsetAllocator/CMakeLists.txt create mode 100644 3rdparty/OffsetAllocator/LICENSE create mode 100644 3rdparty/OffsetAllocator/README.md create mode 100644 3rdparty/OffsetAllocator/offsetAllocator.cpp create mode 100644 3rdparty/OffsetAllocator/offsetAllocator.hpp create mode 100644 3rdparty/OffsetAllocator/offsetAllocatorTests.cpp diff --git a/3rdparty/OffsetAllocator/CMakeLists.txt b/3rdparty/OffsetAllocator/CMakeLists.txt new file mode 100644 index 000000000..8b913cb6d --- /dev/null +++ b/3rdparty/OffsetAllocator/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.0) + +project(offsetAllocator) + +set(SOURCE_FILES + offsetAllocator.cpp + offsetAllocator.hpp +) + +add_library(${PROJECT_NAME} ${SOURCE_FILES}) +setup_target_libs(${PROJECT_NAME}) diff --git a/3rdparty/OffsetAllocator/LICENSE b/3rdparty/OffsetAllocator/LICENSE new file mode 100644 index 000000000..60cd17caf --- /dev/null +++ b/3rdparty/OffsetAllocator/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Sebastian Aaltonen + +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. diff --git a/3rdparty/OffsetAllocator/README.md b/3rdparty/OffsetAllocator/README.md new file mode 100644 index 000000000..28b7047c0 --- /dev/null +++ b/3rdparty/OffsetAllocator/README.md @@ -0,0 +1,75 @@ +# OffsetAllocator +Fast hard realtime O(1) offset allocator with minimal fragmentation. + +Uses 256 bins with 8 bit floating point distribution (3 bit mantissa + 5 bit exponent) and a two level bitfield to find the next available bin using 2x LZCNT instructions to make all operations O(1). Bin sizes following the floating point distribution ensures hard bounds for memory overhead percentage regarless of size class. Pow2 bins would waste up to +100% memory (+50% on average). Our float bins waste up to +12.5% (+6.25% on average). + +The allocation metadata is stored in a separate data structure, making this allocator suitable for sub-allocating any resources, such as GPU heaps, buffers and arrays. Returns an offset to the first element of the allocated contiguous range. + +**Bin size table:** +``` +0->0 1->1 2->2 3->3 4->4 5->5 6->6 7->7 +8->8 9->9 10->10 11->11 12->12 13->13 14->14 15->15 +16->16 17->18 18->20 19->22 20->24 21->26 22->28 23->30 +24->32 25->36 26->40 27->44 28->48 29->52 30->56 31->60 +32->64 33->72 34->80 35->88 36->96 37->104 38->112 39->120 +40->128 41->144 42->160 43->176 44->192 45->208 46->224 47->240 +48->256 49->288 50->320 51->352 52->384 53->416 54->448 55->480 +56->512 57->576 58->640 59->704 60->768 61->832 62->896 63->960 +64->1024 65->1152 66->1280 67->1408 68->1536 69->1664 70->1792 71->1920 +72->2048 73->2304 74->2560 75->2816 76->3072 77->3328 78->3584 79->3840 +80->4096 81->4608 82->5120 83->5632 84->6144 85->6656 86->7168 87->7680 +88->8192 89->9216 90->10240 91->11264 92->12288 93->13312 94->14336 95->15360 +96->16384 97->18432 98->20480 99->22528 100->24576 101->26624 102->28672 103->30720 +104->32768 105->36864 106->40960 107->45056 108->49152 109->53248 110->57344 111->61440 +112->65536 113->73728 114->81920 115->90112 116->98304 117->106496 118->114688 119->122880 +120->131072 121->147456 122->163840 123->180224 124->196608 125->212992 126->229376 127->245760 +128->262144 129->294912 130->327680 131->360448 132->393216 133->425984 134->458752 135->491520 +136->524288 137->589824 138->655360 139->720896 140->786432 141->851968 142->917504 143->983040 +144->1048576 145->1179648 146->1310720 147->1441792 148->1572864 149->1703936 150->1835008 151->1966080 +152->2097152 153->2359296 154->2621440 155->2883584 156->3145728 157->3407872 158->3670016 159->3932160 +160->4194304 161->4718592 162->5242880 163->5767168 164->6291456 165->6815744 166->7340032 167->7864320 +168->8388608 169->9437184 170->10485760 171->11534336 172->12582912 173->13631488 174->14680064 175->15728640 +176->16777216 177->18874368 178->20971520 179->23068672 180->25165824 181->27262976 182->29360128 183->31457280 +184->33554432 185->37748736 186->41943040 187->46137344 188->50331648 189->54525952 190->58720256 191->62914560 +192->67108864 193->75497472 194->83886080 195->92274688 196->100663296 197->109051904 198->117440512 199->125829120 +200->134217728 201->150994944 202->167772160 203->184549376 204->201326592 205->218103808 206->234881024 207->251658240 +208->268435456 209->301989888 210->335544320 211->369098752 212->402653184 213->436207616 214->469762048 215->503316480 +216->536870912 217->603979776 218->671088640 219->738197504 220->805306368 221->872415232 222->939524096 223->1006632960 +224->1073741824 225->1207959552 226->1342177280 227->1476395008 228->1610612736 229->1744830464 230->1879048192 231->2013265920 +232->2147483648 233->2415919104 234->2684354560 235->2952790016 236->3221225472 237->3489660928 238->3758096384 239->4026531840 +``` + +## Integration +CMakeLists.txt exists for cmake folder include. Alternatively, just copy the OffsetAllocator.cpp and OffsetAllocator.hpp in your project. No other files are needed. + +## How to use + +``` +#include "offsetAllocator.hpp" +using namespace OffsetAllocator; + +Allocator allocator(12345); // Allocator with 12345 contiguous elements in total + +Allocation a = allocator.allocate(1337); // Allocate a 1337 element contiguous range +uint32 offset_a = a.offset; // Provides offset to the first element of the range +do_something(offset_a); + +Allocation b = allocator.allocate(123); // Allocate a 123 element contiguous range +uint32 offset_b = b.offset; // Provides offset to the first element of the range +do_something(offset_b); + +allocator.free(a); // Free allocation a +allocator.free(b); // Free allocation b +``` + +## References +This allocator is similar to the two-level segregated fit (TLSF) algorithm. + +**Comparison paper shows that TLSF algorithm provides best in class performance and fragmentation:** +https://www.researchgate.net/profile/Alfons-Crespo/publication/234785757_A_comparison_of_memory_allocators_for_real-time_applications/links/5421d8550cf2a39f4af765f4/A-comparison-of-memory-allocators-for-real-time-applications.pdf + +## Disclaimer +Early one weekend prototype. Unit tests are green, but coverage is still not 100%. Use at your own risk! + +## License +MIT license (see file: LICENSE) diff --git a/3rdparty/OffsetAllocator/offsetAllocator.cpp b/3rdparty/OffsetAllocator/offsetAllocator.cpp new file mode 100644 index 000000000..f892fc382 --- /dev/null +++ b/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -0,0 +1,533 @@ +// (C) Sebastian Aaltonen 2023 +// MIT License (see file: LICENSE) + +#include "offsetAllocator.hpp" + +#ifdef DEBUG +#include +#define ASSERT(x) assert(x) +//#define DEBUG_VERBOSE +#else +#define ASSERT(x) +#endif + +#ifdef DEBUG_VERBOSE +#include +#endif + +#ifdef _MSC_VER +#include +#endif + +#include + +namespace OffsetAllocator +{ + inline uint32 lzcnt_nonzero(uint32 v) + { +#ifdef _MSC_VER + unsigned long retVal; + _BitScanReverse(&retVal, v); + return 31 - retVal; +#else + return __builtin_clz(v); +#endif + } + + inline uint32 tzcnt_nonzero(uint32 v) + { +#ifdef _MSC_VER + unsigned long retVal; + _BitScanForward(&retVal, v); + return retVal; +#else + return __builtin_ctz(v); +#endif + } + + namespace SmallFloat + { + static constexpr uint32 MANTISSA_BITS = 3; + static constexpr uint32 MANTISSA_VALUE = 1 << MANTISSA_BITS; + static constexpr uint32 MANTISSA_MASK = MANTISSA_VALUE - 1; + + // Bin sizes follow floating point (exponent + mantissa) distribution (piecewise linear log approx) + // This ensures that for each size class, the average overhead percentage stays the same + uint32 uintToFloatRoundUp(uint32 size) + { + uint32 exp = 0; + uint32 mantissa = 0; + + if (size < MANTISSA_VALUE) + { + // Denorm: 0..(MANTISSA_VALUE-1) + mantissa = size; + } + else + { + // Normalized: Hidden high bit always 1. Not stored. Just like float. + uint32 leadingZeros = lzcnt_nonzero(size); + uint32 highestSetBit = 31 - leadingZeros; + + uint32 mantissaStartBit = highestSetBit - MANTISSA_BITS; + exp = mantissaStartBit + 1; + mantissa = (size >> mantissaStartBit) & MANTISSA_MASK; + + uint32 lowBitsMask = (1 << mantissaStartBit) - 1; + + // Round up! + if ((size & lowBitsMask) != 0) + mantissa++; + } + + return (exp << MANTISSA_BITS) + mantissa; // + allows mantissa->exp overflow for round up + } + + uint32 uintToFloatRoundDown(uint32 size) + { + uint32 exp = 0; + uint32 mantissa = 0; + + if (size < MANTISSA_VALUE) + { + // Denorm: 0..(MANTISSA_VALUE-1) + mantissa = size; + } + else + { + // Normalized: Hidden high bit always 1. Not stored. Just like float. + uint32 leadingZeros = lzcnt_nonzero(size); + uint32 highestSetBit = 31 - leadingZeros; + + uint32 mantissaStartBit = highestSetBit - MANTISSA_BITS; + exp = mantissaStartBit + 1; + mantissa = (size >> mantissaStartBit) & MANTISSA_MASK; + } + + return (exp << MANTISSA_BITS) | mantissa; + } + + uint32 floatToUint(uint32 floatValue) + { + uint32 exponent = floatValue >> MANTISSA_BITS; + uint32 mantissa = floatValue & MANTISSA_MASK; + if (exponent == 0) + { + // Denorms + return mantissa; + } + else + { + return (mantissa | MANTISSA_VALUE) << (exponent - 1); + } + } + } + + // Utility functions + uint32 findLowestSetBitAfter(uint32 bitMask, uint32 startBitIndex) + { + uint32 maskBeforeStartIndex = (1 << startBitIndex) - 1; + uint32 maskAfterStartIndex = ~maskBeforeStartIndex; + uint32 bitsAfter = bitMask & maskAfterStartIndex; + if (bitsAfter == 0) return Allocation::NO_SPACE; + return tzcnt_nonzero(bitsAfter); + } + + // Allocator... + Allocator::Allocator(uint32 size, uint32 maxAllocs) : + m_size(size), + m_maxAllocs(maxAllocs), + m_nodes(nullptr), + m_freeNodes(nullptr) + { + if (sizeof(NodeIndex) == 2) + { + ASSERT(maxAllocs <= 65536); + } + reset(); + } + + Allocator::Allocator(Allocator &&other) : + m_size(other.m_size), + m_maxAllocs(other.m_maxAllocs), + m_freeStorage(other.m_freeStorage), + m_usedBinsTop(other.m_usedBinsTop), + m_nodes(other.m_nodes), + m_freeNodes(other.m_freeNodes), + m_freeOffset(other.m_freeOffset) + { + memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS); + memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS); + + other.m_nodes = nullptr; + other.m_freeNodes = nullptr; + other.m_freeOffset = 0; + other.m_maxAllocs = 0; + other.m_usedBinsTop = 0; + } + + Allocator::Allocator(Allocator &other) : + m_size(other.m_size), + m_maxAllocs(other.m_maxAllocs), + m_freeStorage(other.m_freeStorage), + m_usedBinsTop(other.m_usedBinsTop), + m_nodes(other.m_nodes), + m_freeNodes(other.m_freeNodes), + m_freeOffset(other.m_freeOffset) + { + memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS); + memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS); + + other.m_nodes = nullptr; + other.m_freeNodes = nullptr; + other.m_freeOffset = 0; + other.m_maxAllocs = 0; + other.m_usedBinsTop = 0; + } + + + void Allocator::reset() + { + m_freeStorage = 0; + m_usedBinsTop = 0; + m_freeOffset = m_maxAllocs - 1; + + for (uint32 i = 0 ; i < NUM_TOP_BINS; i++) + m_usedBins[i] = 0; + + for (uint32 i = 0 ; i < NUM_LEAF_BINS; i++) + m_binIndices[i] = Node::unused; + + if (m_nodes) delete[] m_nodes; + if (m_freeNodes) delete[] m_freeNodes; + + m_nodes = new Node[m_maxAllocs]; + m_freeNodes = new NodeIndex[m_maxAllocs]; + + // Freelist is a stack. Nodes in inverse order so that [0] pops first. + for (uint32 i = 0; i < m_maxAllocs; i++) + { + m_freeNodes[i] = m_maxAllocs - i - 1; + } + + // Start state: Whole storage as one big node + // Algorithm will split remainders and push them back as smaller nodes + m_lastNode = insertNodeIntoBin(m_size, 0); + } + + Allocator::~Allocator() + { + delete[] m_nodes; + delete[] m_freeNodes; + } + + Allocation Allocator::allocate(uint32 size) + { + // Out of allocations? + if (m_freeOffset == 0) + { + return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE}; + } + + // Round up to bin index to ensure that alloc >= bin + // Gives us min bin index that fits the size + uint32 minBinIndex = SmallFloat::uintToFloatRoundUp(size); + + uint32 minTopBinIndex = minBinIndex >> TOP_BINS_INDEX_SHIFT; + uint32 minLeafBinIndex = minBinIndex & LEAF_BINS_INDEX_MASK; + + uint32 topBinIndex = minTopBinIndex; + uint32 leafBinIndex = Allocation::NO_SPACE; + + // If top bin exists, scan its leaf bin. This can fail (NO_SPACE). + if (m_usedBinsTop & (1 << topBinIndex)) + { + leafBinIndex = findLowestSetBitAfter(m_usedBins[topBinIndex], minLeafBinIndex); + } + + // If we didn't find space in top bin, we search top bin from +1 + if (leafBinIndex == Allocation::NO_SPACE) + { + topBinIndex = findLowestSetBitAfter(m_usedBinsTop, minTopBinIndex + 1); + + // Out of space? + if (topBinIndex == Allocation::NO_SPACE) + { + return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE}; + } + + // All leaf bins here fit the alloc, since the top bin was rounded up. Start leaf search from bit 0. + // NOTE: This search can't fail since at least one leaf bit was set because the top bit was set. + leafBinIndex = tzcnt_nonzero(m_usedBins[topBinIndex]); + } + + uint32 binIndex = (topBinIndex << TOP_BINS_INDEX_SHIFT) | leafBinIndex; + + // Pop the top node of the bin. Bin top = node.next. + uint32 nodeIndex = m_binIndices[binIndex]; + Node& node = m_nodes[nodeIndex]; + uint32 nodeTotalSize = node.dataSize; + node.dataSize = size; + node.used = true; + m_binIndices[binIndex] = node.binListNext; + if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = Node::unused; + m_freeStorage -= nodeTotalSize; +#ifdef DEBUG_VERBOSE + printf("Free storage: %u (-%u) (allocate)\n", m_freeStorage, nodeTotalSize); +#endif + + // Bin empty? + if (m_binIndices[binIndex] == Node::unused) + { + // Remove a leaf bin mask bit + m_usedBins[topBinIndex] &= ~(1 << leafBinIndex); + + // All leaf bins empty? + if (m_usedBins[topBinIndex] == 0) + { + // Remove a top bin mask bit + m_usedBinsTop &= ~(1 << topBinIndex); + } + } + + // Push back reminder N elements to a lower bin + uint32 reminderSize = nodeTotalSize - size; + if (reminderSize > 0) + { + uint32 newNodeIndex = insertNodeIntoBin(reminderSize, node.dataOffset + size); + + // Link nodes next to each other so that we can merge them later if both are free + // And update the old next neighbor to point to the new node (in middle) + if (node.neighborNext != Node::unused) m_nodes[node.neighborNext].neighborPrev = newNodeIndex; + m_nodes[newNodeIndex].neighborPrev = nodeIndex; + m_nodes[newNodeIndex].neighborNext = node.neighborNext; + node.neighborNext = newNodeIndex; + + if (m_lastNode == nodeIndex) { + m_lastNode = newNodeIndex; + } + } + + return {.offset = node.dataOffset, .metadata = nodeIndex}; + } + + void Allocator::free(Allocation allocation) + { + ASSERT(allocation.metadata != Allocation::NO_SPACE); + if (!m_nodes) return; + + uint32 nodeIndex = allocation.metadata; + Node& node = m_nodes[nodeIndex]; + + // Double delete check + ASSERT(node.used == true); + + // Merge with neighbors... + uint32 offset = node.dataOffset; + uint32 size = node.dataSize; + + if ((node.neighborPrev != Node::unused) && (m_nodes[node.neighborPrev].used == false)) + { + // Previous (contiguous) free node: Change offset to previous node offset. Sum sizes + Node& prevNode = m_nodes[node.neighborPrev]; + offset = prevNode.dataOffset; + size += prevNode.dataSize; + + // Remove node from the bin linked list and put it in the freelist + removeNodeFromBin(node.neighborPrev); + + ASSERT(prevNode.neighborNext == nodeIndex); + node.neighborPrev = prevNode.neighborPrev; + } + + if ((node.neighborNext != Node::unused) && (m_nodes[node.neighborNext].used == false)) + { + // Next (contiguous) free node: Offset remains the same. Sum sizes. + Node& nextNode = m_nodes[node.neighborNext]; + size += nextNode.dataSize; + + // Remove node from the bin linked list and put it in the freelist + removeNodeFromBin(node.neighborNext); + + if (m_lastNode == node.neighborNext) { + m_lastNode = nodeIndex; + } + + ASSERT(nextNode.neighborPrev == nodeIndex); + node.neighborNext = nextNode.neighborNext; + } + + uint32 neighborNext = node.neighborNext; + uint32 neighborPrev = node.neighborPrev; + + // Insert the removed node to freelist +#ifdef DEBUG_VERBOSE + printf("Putting node %u into freelist[%u] (free)\n", nodeIndex, m_freeOffset + 1); +#endif + m_freeNodes[++m_freeOffset] = nodeIndex; + + // Insert the (combined) free node to bin + uint32 combinedNodeIndex = insertNodeIntoBin(size, offset); + + if (m_lastNode == nodeIndex) { + m_lastNode = combinedNodeIndex; + } + + // Connect neighbors with the new combined node + if (neighborNext != Node::unused) + { + m_nodes[combinedNodeIndex].neighborNext = neighborNext; + m_nodes[neighborNext].neighborPrev = combinedNodeIndex; + } + if (neighborPrev != Node::unused) + { + m_nodes[combinedNodeIndex].neighborPrev = neighborPrev; + m_nodes[neighborPrev].neighborNext = combinedNodeIndex; + } + } + + uint32 Allocator::insertNodeIntoBin(uint32 size, uint32 dataOffset) + { + // Round down to bin index to ensure that bin >= alloc + uint32 binIndex = SmallFloat::uintToFloatRoundDown(size); + + uint32 topBinIndex = binIndex >> TOP_BINS_INDEX_SHIFT; + uint32 leafBinIndex = binIndex & LEAF_BINS_INDEX_MASK; + + // Bin was empty before? + if (m_binIndices[binIndex] == Node::unused) + { + // Set bin mask bits + m_usedBins[topBinIndex] |= 1 << leafBinIndex; + m_usedBinsTop |= 1 << topBinIndex; + } + + // Take a freelist node and insert on top of the bin linked list (next = old top) + uint32 topNodeIndex = m_binIndices[binIndex]; + uint32 nodeIndex = m_freeNodes[m_freeOffset--]; +#ifdef DEBUG_VERBOSE + printf("Getting node %u from freelist[%u]\n", nodeIndex, m_freeOffset + 1); +#endif + m_nodes[nodeIndex] = {.dataOffset = dataOffset, .dataSize = size, .binListNext = topNodeIndex}; + if (topNodeIndex != Node::unused) m_nodes[topNodeIndex].binListPrev = nodeIndex; + m_binIndices[binIndex] = nodeIndex; + + m_freeStorage += size; +#ifdef DEBUG_VERBOSE + printf("Free storage: %u (+%u) (insertNodeIntoBin)\n", m_freeStorage, size); +#endif + + return nodeIndex; + } + + void Allocator::removeNodeFromBin(uint32 nodeIndex) + { + Node &node = m_nodes[nodeIndex]; + + if (node.binListPrev != Node::unused) + { + // Easy case: We have previous node. Just remove this node from the middle of the list. + m_nodes[node.binListPrev].binListNext = node.binListNext; + if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = node.binListPrev; + } + else + { + // Hard case: We are the first node in a bin. Find the bin. + + // Round down to bin index to ensure that bin >= alloc + uint32 binIndex = SmallFloat::uintToFloatRoundDown(node.dataSize); + + uint32 topBinIndex = binIndex >> TOP_BINS_INDEX_SHIFT; + uint32 leafBinIndex = binIndex & LEAF_BINS_INDEX_MASK; + + m_binIndices[binIndex] = node.binListNext; + if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = Node::unused; + + // Bin empty? + if (m_binIndices[binIndex] == Node::unused) + { + // Remove a leaf bin mask bit + m_usedBins[topBinIndex] &= ~(1 << leafBinIndex); + + // All leaf bins empty? + if (m_usedBins[topBinIndex] == 0) + { + // Remove a top bin mask bit + m_usedBinsTop &= ~(1 << topBinIndex); + } + } + } + + // Insert the node to freelist +#ifdef DEBUG_VERBOSE + printf("Putting node %u into freelist[%u] (removeNodeFromBin)\n", nodeIndex, m_freeOffset + 1); +#endif + m_freeNodes[++m_freeOffset] = nodeIndex; + + m_freeStorage -= node.dataSize; +#ifdef DEBUG_VERBOSE + printf("Free storage: %u (-%u) (removeNodeFromBin)\n", m_freeStorage, node.dataSize); +#endif + } + + void Allocator::growSize(uint32 additionalSize) { + uint32 newNodeIndex = insertNodeIntoBin(additionalSize, m_size); + + + m_nodes[newNodeIndex].neighborPrev = m_lastNode; + m_nodes[newNodeIndex].neighborNext = Node::unused; + + m_nodes[m_lastNode].neighborNext = newNodeIndex; + + + m_lastNode = newNodeIndex; + + m_size+= additionalSize; + } + + uint32 Allocator::allocationSize(Allocation allocation) const + { + if (allocation.metadata == Allocation::NO_SPACE) return 0; + if (!m_nodes) return 0; + + return m_nodes[allocation.metadata].dataSize; + } + + StorageReport Allocator::storageReport() const + { + uint32 largestFreeRegion = 0; + uint32 freeStorage = 0; + + // Out of allocations? -> Zero free space + if (m_freeOffset > 0) + { + freeStorage = m_freeStorage; + if (m_usedBinsTop) + { + uint32 topBinIndex = 31 - lzcnt_nonzero(m_usedBinsTop); + uint32 leafBinIndex = 31 - lzcnt_nonzero(m_usedBins[topBinIndex]); + largestFreeRegion = SmallFloat::floatToUint((topBinIndex << TOP_BINS_INDEX_SHIFT) | leafBinIndex); + ASSERT(freeStorage >= largestFreeRegion); + } + } + + return {.totalFreeSpace = freeStorage, .largestFreeRegion = largestFreeRegion}; + } + + StorageReportFull Allocator::storageReportFull() const + { + StorageReportFull report; + for (uint32 i = 0; i < NUM_LEAF_BINS; i++) + { + uint32 count = 0; + uint32 nodeIndex = m_binIndices[i]; + while (nodeIndex != Node::unused) + { + nodeIndex = m_nodes[nodeIndex].binListNext; + count++; + } + report.freeRegions[i] = { .size = SmallFloat::floatToUint(i), .count = count }; + } + return report; + } +} diff --git a/3rdparty/OffsetAllocator/offsetAllocator.hpp b/3rdparty/OffsetAllocator/offsetAllocator.hpp new file mode 100644 index 000000000..cef5bd417 --- /dev/null +++ b/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -0,0 +1,102 @@ +// (C) Sebastian Aaltonen 2023 +// MIT License (see file: LICENSE) + +//#define USE_16_BIT_OFFSETS + +namespace OffsetAllocator +{ + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + + // 16 bit offsets mode will halve the metadata storage cost + // But it only supports up to 65536 maximum allocation count +#ifdef USE_16_BIT_NODE_INDICES + typedef uint16 NodeIndex; +#else + typedef uint32 NodeIndex; +#endif + + static constexpr uint32 NUM_TOP_BINS = 32; + static constexpr uint32 BINS_PER_LEAF = 8; + static constexpr uint32 TOP_BINS_INDEX_SHIFT = 3; + static constexpr uint32 LEAF_BINS_INDEX_MASK = 0x7; + static constexpr uint32 NUM_LEAF_BINS = NUM_TOP_BINS * BINS_PER_LEAF; + + struct Allocation + { + static constexpr uint32 NO_SPACE = 0xffffffff; + + uint32 offset = NO_SPACE; + NodeIndex metadata = NO_SPACE; // internal: node index + }; + + struct StorageReport + { + uint32 totalFreeSpace; + uint32 largestFreeRegion; + }; + + struct StorageReportFull + { + struct Region + { + uint32 size; + uint32 count; + }; + + Region freeRegions[NUM_LEAF_BINS]; + }; + + class Allocator + { + public: + Allocator(uint32 size, uint32 maxAllocs = 128 * 1024); + Allocator(Allocator &other); + Allocator(Allocator &&other); + + + ~Allocator(); + void reset(); + + Allocation allocate(uint32 size); + void free(Allocation allocation); + + void growSize(uint32 additionalSize); + + uint32 allocationSize(Allocation allocation) const; + StorageReport storageReport() const; + StorageReportFull storageReportFull() const; + + private: + uint32 insertNodeIntoBin(uint32 size, uint32 dataOffset); + void removeNodeFromBin(uint32 nodeIndex); + + struct Node + { + static constexpr NodeIndex unused = 0xffffffff; + + uint32 dataOffset = 0; + uint32 dataSize = 0; + NodeIndex binListPrev = unused; + NodeIndex binListNext = unused; + NodeIndex neighborPrev = unused; + NodeIndex neighborNext = unused; + bool used = false; // TODO: Merge as bit flag + }; + + uint32 m_size; + uint32 m_maxAllocs; + uint32 m_freeStorage; + + uint32 m_usedBinsTop; + uint8 m_usedBins[NUM_TOP_BINS]; + NodeIndex m_binIndices[NUM_LEAF_BINS]; + + Node* m_nodes; + NodeIndex* m_freeNodes; + uint32 m_freeOffset; + + uint32 m_lastNode; + }; +} diff --git a/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp b/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp new file mode 100644 index 000000000..5479c771e --- /dev/null +++ b/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp @@ -0,0 +1,260 @@ +#include +#include +#include "gfxTestFixture.hpp" + +#include "offsetAllocator.hpp" + +using namespace f; + +namespace OffsetAllocator +{ + namespace SmallFloat + { + extern uint32 uintToFloatRoundUp(uint32 size); + extern uint32 uintToFloatRoundDown(uint32 size); + extern uint32 floatToUint(uint32 floatValue); + } +} + +namespace offsetAllocatorTests +{ + TEST_CASE("numbers", "[SmallFloat]") + { + SECTION("uintToFloat") + { + // Denorms, exp=1 and exp=2 + mantissa = 0 are all precise. + // NOTE: Assuming 8 value (3 bit) mantissa. + // If this test fails, please change this assumption! + uint32 preciseNumberCount = 17; + for (uint32 i = 0; i < preciseNumberCount; i++) + { + uint32 roundUp = OffsetAllocator::SmallFloat::uintToFloatRoundUp(i); + uint32 roundDown = OffsetAllocator::SmallFloat::uintToFloatRoundDown(i); + REQUIRE(i == roundUp); + REQUIRE(i == roundDown); + } + + // Test some random picked numbers + struct NumberFloatUpDown + { + uint32 number; + uint32 up; + uint32 down; + }; + + NumberFloatUpDown testData[] = { + {.number = 17, .up = 17, .down = 16}, + {.number = 118, .up = 39, .down = 38}, + {.number = 1024, .up = 64, .down = 64}, + {.number = 65536, .up = 112, .down = 112}, + {.number = 529445, .up = 137, .down = 136}, + {.number = 1048575, .up = 144, .down = 143}, + }; + + for (uint32 i = 0; i < sizeof(testData) / sizeof(NumberFloatUpDown); i++) + { + NumberFloatUpDown v = testData[i]; + uint32 roundUp = OffsetAllocator::SmallFloat::uintToFloatRoundUp(v.number); + uint32 roundDown = OffsetAllocator::SmallFloat::uintToFloatRoundDown(v.number); + REQUIRE(roundUp == v.up); + REQUIRE(roundDown == v.down); + } + } + + SECTION("floatToUint") + { + // Denorms, exp=1 and exp=2 + mantissa = 0 are all precise. + // NOTE: Assuming 8 value (3 bit) mantissa. + // If this test fails, please change this assumption! + uint32 preciseNumberCount = 17; + for (uint32 i = 0; i < preciseNumberCount; i++) + { + uint32 v = OffsetAllocator::SmallFloat::floatToUint(i); + REQUIRE(i == v); + } + + // Test that float->uint->float conversion is precise for all numbers + // NOTE: Test values < 240. 240->4G = overflows 32 bit integer + for (uint32 i = 0; i < 240; i++) + { + uint32 v = OffsetAllocator::SmallFloat::floatToUint(i); + uint32 roundUp = OffsetAllocator::SmallFloat::uintToFloatRoundUp(v); + uint32 roundDown = OffsetAllocator::SmallFloat::uintToFloatRoundDown(v); + REQUIRE(i == roundUp); + REQUIRE(i == roundDown); + //if ((i%8) == 0) printf("\n"); + //printf("%u->%u ", i, v); + } + } + } + + TEST_CASE("basic", "[offsetAllocator]") + { + OffsetAllocator::Allocator allocator(1024 * 1024 * 256); + OffsetAllocator::Allocation a = allocator.allocate(1337); + uint32 offset = a.offset; + REQUIRE(offset == 0); + allocator.free(a); + } + + TEST_CASE("allocate", "[offsetAllocator]") + { + OffsetAllocator::Allocator allocator(1024 * 1024 * 256); + + SECTION("simple") + { + // Free merges neighbor empty nodes. Next allocation should also have offset = 0 + OffsetAllocator::Allocation a = allocator.allocate(0); + REQUIRE(a.offset == 0); + + OffsetAllocator::Allocation b = allocator.allocate(1); + REQUIRE(b.offset == 0); + + OffsetAllocator::Allocation c = allocator.allocate(123); + REQUIRE(c.offset == 1); + + OffsetAllocator::Allocation d = allocator.allocate(1234); + REQUIRE(d.offset == 124); + + allocator.free(a); + allocator.free(b); + allocator.free(c); + allocator.free(d); + + // End: Validate that allocator has no fragmentation left. Should be 100% clean. + OffsetAllocator::Allocation validateAll = allocator.allocate(1024 * 1024 * 256); + REQUIRE(validateAll.offset == 0); + allocator.free(validateAll); + } + + SECTION("merge trivial") + { + // Free merges neighbor empty nodes. Next allocation should also have offset = 0 + OffsetAllocator::Allocation a = allocator.allocate(1337); + REQUIRE(a.offset == 0); + allocator.free(a); + + OffsetAllocator::Allocation b = allocator.allocate(1337); + REQUIRE(b.offset == 0); + allocator.free(b); + + // End: Validate that allocator has no fragmentation left. Should be 100% clean. + OffsetAllocator::Allocation validateAll = allocator.allocate(1024 * 1024 * 256); + REQUIRE(validateAll.offset == 0); + allocator.free(validateAll); + } + + SECTION("reuse trivial") + { + // Allocator should reuse node freed by A since the allocation C fits in the same bin (using pow2 size to be sure) + OffsetAllocator::Allocation a = allocator.allocate(1024); + REQUIRE(a.offset == 0); + + OffsetAllocator::Allocation b = allocator.allocate(3456); + REQUIRE(b.offset == 1024); + + allocator.free(a); + + OffsetAllocator::Allocation c = allocator.allocate(1024); + REQUIRE(c.offset == 0); + + allocator.free(c); + allocator.free(b); + + // End: Validate that allocator has no fragmentation left. Should be 100% clean. + OffsetAllocator::Allocation validateAll = allocator.allocate(1024 * 1024 * 256); + REQUIRE(validateAll.offset == 0); + allocator.free(validateAll); + } + + SECTION("reuse complex") + { + // Allocator should not reuse node freed by A since the allocation C doesn't fits in the same bin + // However node D and E fit there and should reuse node from A + OffsetAllocator::Allocation a = allocator.allocate(1024); + REQUIRE(a.offset == 0); + + OffsetAllocator::Allocation b = allocator.allocate(3456); + REQUIRE(b.offset == 1024); + + allocator.free(a); + + OffsetAllocator::Allocation c = allocator.allocate(2345); + REQUIRE(c.offset == 1024 + 3456); + + OffsetAllocator::Allocation d = allocator.allocate(456); + REQUIRE(d.offset == 0); + + OffsetAllocator::Allocation e = allocator.allocate(512); + REQUIRE(e.offset == 456); + + OffsetAllocator::StorageReport report = allocator.storageReport(); + REQUIRE(report.totalFreeSpace == 1024 * 1024 * 256 - 3456 - 2345 - 456 - 512); + REQUIRE(report.largestFreeRegion != report.totalFreeSpace); + + allocator.free(c); + allocator.free(d); + allocator.free(b); + allocator.free(e); + + // End: Validate that allocator has no fragmentation left. Should be 100% clean. + OffsetAllocator::Allocation validateAll = allocator.allocate(1024 * 1024 * 256); + REQUIRE(validateAll.offset == 0); + allocator.free(validateAll); + } + + SECTION("zero fragmentation") + { + // Allocate 256x 1MB. Should fit. Then free four random slots and reallocate four slots. + // Plus free four contiguous slots an allocate 4x larger slot. All must be zero fragmentation! + OffsetAllocator::Allocation allocations[256]; + for (uint i = 0; i < 256; i++) + { + allocations[i] = allocator.allocate(1024 * 1024); + REQUIRE(allocations[i].offset == i * 1024 * 1024); + } + + OffsetAllocator::StorageReport report = allocator.storageReport(); + REQUIRE(report.totalFreeSpace == 0); + REQUIRE(report.largestFreeRegion == 0); + + // Free four random slots + allocator.free(allocations[243]); + allocator.free(allocations[5]); + allocator.free(allocations[123]); + allocator.free(allocations[95]); + + // Free four contiguous slot (allocator must merge) + allocator.free(allocations[151]); + allocator.free(allocations[152]); + allocator.free(allocations[153]); + allocator.free(allocations[154]); + + allocations[243] = allocator.allocate(1024 * 1024); + allocations[5] = allocator.allocate(1024 * 1024); + allocations[123] = allocator.allocate(1024 * 1024); + allocations[95] = allocator.allocate(1024 * 1024); + allocations[151] = allocator.allocate(1024 * 1024 * 4); // 4x larger + REQUIRE(allocations[243].offset != OffsetAllocator::Allocation::NO_SPACE); + REQUIRE(allocations[5].offset != OffsetAllocator::Allocation::NO_SPACE); + REQUIRE(allocations[123].offset != OffsetAllocator::Allocation::NO_SPACE); + REQUIRE(allocations[95].offset != OffsetAllocator::Allocation::NO_SPACE); + REQUIRE(allocations[151].offset != OffsetAllocator::Allocation::NO_SPACE); + + for (uint i = 0; i < 256; i++) + { + if (i < 152 || i > 154) + allocator.free(allocations[i]); + } + + OffsetAllocator::StorageReport report2 = allocator.storageReport(); + REQUIRE(report2.totalFreeSpace == 1024 * 1024 * 256); + REQUIRE(report2.largestFreeRegion == 1024 * 1024 * 256); + + // End: Validate that allocator has no fragmentation left. Should be 100% clean. + OffsetAllocator::Allocation validateAll = allocator.allocate(1024 * 1024 * 256); + REQUIRE(validateAll.offset == 0); + allocator.free(validateAll); + } + } +} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index c246a51dc..9befd3973 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -42,16 +42,8 @@ void GBufferVLK::createBuffer(BufferInternal &buffer) { &buffer.g_hBufferAlloc, nullptr)); //Create virtual buffer off this native buffer - VmaVirtualBlockCreateInfo blockCreateInfo = {}; - blockCreateInfo.size = m_bufferSize; - blockCreateInfo.flags = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT; - - VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &buffer.virtualBlock); - if(res != VK_SUCCESS) - { - std::cerr << "Failed to create virtual buffer" << std::endl; - } - + auto allocator = OffsetAllocator::Allocator(m_bufferSize); + buffer.offsetAllocator = allocator; } void GBufferVLK::destroyBuffer(BufferInternal &buffer) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 75e1299a4..6a721a7e1 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -18,6 +18,8 @@ typedef std::shared_ptr HGBufferVLK; #include "../utils/MutexLockedVector.h" #include "../bindable/DSBindable.h" +#include "../../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" + class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; class GSubBufferVLK; @@ -68,7 +70,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this Date: Wed, 26 Apr 2023 23:52:55 +0300 Subject: [PATCH 067/212] offset allocator seems to work --- .../3rdparty}/OffsetAllocator/CMakeLists.txt | 0 .../3rdparty}/OffsetAllocator/LICENSE | 0 .../3rdparty}/OffsetAllocator/README.md | 0 .../OffsetAllocator/offsetAllocator.cpp | 45 ++---- .../OffsetAllocator/offsetAllocator.hpp | 19 ++- .../OffsetAllocator/offsetAllocatorTests.cpp | 0 wowViewerLib/CMakeLists.txt | 3 + .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 7 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 144 ++++++++++-------- .../src/gapi/vulkan/buffers/GBufferVLK.h | 17 ++- 10 files changed, 122 insertions(+), 113 deletions(-) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/CMakeLists.txt (100%) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/LICENSE (100%) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/README.md (100%) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/offsetAllocator.cpp (93%) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/offsetAllocator.hpp (86%) rename {3rdparty => wowViewerLib/3rdparty}/OffsetAllocator/offsetAllocatorTests.cpp (100%) diff --git a/3rdparty/OffsetAllocator/CMakeLists.txt b/wowViewerLib/3rdparty/OffsetAllocator/CMakeLists.txt similarity index 100% rename from 3rdparty/OffsetAllocator/CMakeLists.txt rename to wowViewerLib/3rdparty/OffsetAllocator/CMakeLists.txt diff --git a/3rdparty/OffsetAllocator/LICENSE b/wowViewerLib/3rdparty/OffsetAllocator/LICENSE similarity index 100% rename from 3rdparty/OffsetAllocator/LICENSE rename to wowViewerLib/3rdparty/OffsetAllocator/LICENSE diff --git a/3rdparty/OffsetAllocator/README.md b/wowViewerLib/3rdparty/OffsetAllocator/README.md similarity index 100% rename from 3rdparty/OffsetAllocator/README.md rename to wowViewerLib/3rdparty/OffsetAllocator/README.md diff --git a/3rdparty/OffsetAllocator/offsetAllocator.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp similarity index 93% rename from 3rdparty/OffsetAllocator/offsetAllocator.cpp rename to wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp index f892fc382..faabcf7ea 100644 --- a/3rdparty/OffsetAllocator/offsetAllocator.cpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -136,9 +136,7 @@ namespace OffsetAllocator // Allocator... Allocator::Allocator(uint32 size, uint32 maxAllocs) : m_size(size), - m_maxAllocs(maxAllocs), - m_nodes(nullptr), - m_freeNodes(nullptr) + m_maxAllocs(maxAllocs) { if (sizeof(NodeIndex) == 2) { @@ -159,33 +157,13 @@ namespace OffsetAllocator memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS); memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS); - other.m_nodes = nullptr; - other.m_freeNodes = nullptr; + other.m_nodes.clear(); + other.m_freeNodes.clear(); other.m_freeOffset = 0; other.m_maxAllocs = 0; other.m_usedBinsTop = 0; } - Allocator::Allocator(Allocator &other) : - m_size(other.m_size), - m_maxAllocs(other.m_maxAllocs), - m_freeStorage(other.m_freeStorage), - m_usedBinsTop(other.m_usedBinsTop), - m_nodes(other.m_nodes), - m_freeNodes(other.m_freeNodes), - m_freeOffset(other.m_freeOffset) - { - memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS); - memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS); - - other.m_nodes = nullptr; - other.m_freeNodes = nullptr; - other.m_freeOffset = 0; - other.m_maxAllocs = 0; - other.m_usedBinsTop = 0; - } - - void Allocator::reset() { m_freeStorage = 0; @@ -198,11 +176,11 @@ namespace OffsetAllocator for (uint32 i = 0 ; i < NUM_LEAF_BINS; i++) m_binIndices[i] = Node::unused; - if (m_nodes) delete[] m_nodes; - if (m_freeNodes) delete[] m_freeNodes; + m_nodes.clear(); + m_freeNodes.clear(); - m_nodes = new Node[m_maxAllocs]; - m_freeNodes = new NodeIndex[m_maxAllocs]; + m_nodes.resize(m_maxAllocs); + m_freeNodes.resize(m_maxAllocs); // Freelist is a stack. Nodes in inverse order so that [0] pops first. for (uint32 i = 0; i < m_maxAllocs; i++) @@ -216,9 +194,7 @@ namespace OffsetAllocator } Allocator::~Allocator() - { - delete[] m_nodes; - delete[] m_freeNodes; + { } Allocation Allocator::allocate(uint32 size) @@ -314,7 +290,7 @@ namespace OffsetAllocator void Allocator::free(Allocation allocation) { ASSERT(allocation.metadata != Allocation::NO_SPACE); - if (!m_nodes) return; + if (m_nodes.empty()) return; uint32 nodeIndex = allocation.metadata; Node& node = m_nodes[nodeIndex]; @@ -473,7 +449,6 @@ namespace OffsetAllocator void Allocator::growSize(uint32 additionalSize) { uint32 newNodeIndex = insertNodeIntoBin(additionalSize, m_size); - m_nodes[newNodeIndex].neighborPrev = m_lastNode; m_nodes[newNodeIndex].neighborNext = Node::unused; @@ -488,7 +463,7 @@ namespace OffsetAllocator uint32 Allocator::allocationSize(Allocation allocation) const { if (allocation.metadata == Allocation::NO_SPACE) return 0; - if (!m_nodes) return 0; + if (m_nodes.empty()) return 0; return m_nodes[allocation.metadata].dataSize; } diff --git a/3rdparty/OffsetAllocator/offsetAllocator.hpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp similarity index 86% rename from 3rdparty/OffsetAllocator/offsetAllocator.hpp rename to wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp index cef5bd417..044e78749 100644 --- a/3rdparty/OffsetAllocator/offsetAllocator.hpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -3,6 +3,9 @@ //#define USE_16_BIT_OFFSETS +#include +#include + namespace OffsetAllocator { typedef unsigned char uint8; @@ -51,10 +54,16 @@ namespace OffsetAllocator class Allocator { public: - Allocator(uint32 size, uint32 maxAllocs = 128 * 1024); - Allocator(Allocator &other); + Allocator(uint32 size, uint32 maxAllocs = 128 * 1024*20); Allocator(Allocator &&other); + // user-defined copy assignment (copy-and-swap idiom) + Allocator& operator=(Allocator &&other) noexcept + { + Allocator(std::move(other)); + + return *this; + } ~Allocator(); void reset(); @@ -93,9 +102,9 @@ namespace OffsetAllocator uint8 m_usedBins[NUM_TOP_BINS]; NodeIndex m_binIndices[NUM_LEAF_BINS]; - Node* m_nodes; - NodeIndex* m_freeNodes; - uint32 m_freeOffset; + std::vector m_nodes; + std::vector m_freeNodes; + uint32 m_lastNode; }; diff --git a/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp similarity index 100% rename from 3rdparty/OffsetAllocator/offsetAllocatorTests.cpp rename to wowViewerLib/3rdparty/OffsetAllocator/offsetAllocatorTests.cpp diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 122203e1a..9ca6049d5 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -158,6 +158,9 @@ endif(LINK_GLEW) set(SOURCE_FILES + 3rdparty/OffsetAllocator/offsetAllocator.cpp + 3rdparty/OffsetAllocator/offsetAllocator.hpp + src/engine/shader/ShaderRuntimeData.cpp src/engine/shader/ShaderRuntimeData.cpp src/engine/shader/ShaderRuntimeData.h src/engine/opengl/header.h diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index f8d71a2a8..87ef04159 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -42,7 +42,10 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr meshblockVSPS.UnFogged = ((renderFlag->flags & 0x2) > 0) ? 1 : 0; meshblockVSPS.BlendMode = static_cast(m2Material->blendMode); meshblockVSPS.applyWeight = batch->textureCount && !(batch->flags & 0x40); - meshblockVSPS.colorIndex = batch->colorIndex; + meshblockVSPS.colorIndex = + ((batch->colorIndex >= 0) && (batch->colorIndex < m2Data->colors.size)) + ? batch->colorIndex + : -1; meshblockVSPS.textureWeightIndexes[0] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 0); meshblockVSPS.textureWeightIndexes[1] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 1); meshblockVSPS.textureWeightIndexes[2] = getTextureWeightIndex(m2SkinProfile, m2Data, batchIndex, 2); @@ -164,7 +167,7 @@ mathfu::vec4 M2MeshBufferUpdater::getCombinedColor( int colorIndex = skinData->batches[batchIndex]->colorIndex; mathfu::vec4 submeshColor = mathfu::vec4(1,1,1,1); - if ((colorIndex >= 0) && (subMeshColors.size() > colorIndex)) { + if ((colorIndex >= 0) && (colorIndex < subMeshColors.size())) { const mathfu::vec4 &color = subMeshColors[colorIndex]; submeshColor = color; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 9befd3973..ddbc0bdc6 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -10,6 +10,10 @@ GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, m_bufferSize = maxSize; m_alignment = alignment; + //Create virtual buffer off this native buffer + auto allocator = OffsetAllocator::Allocator(m_bufferSize); + offsetAllocator = std::move(allocator); + createBuffer(currentBuffer); } @@ -40,10 +44,6 @@ void GBufferVLK::createBuffer(BufferInternal &buffer) { ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, &buffer.g_hBuffer, &buffer.g_hBufferAlloc, nullptr)); - - //Create virtual buffer off this native buffer - auto allocator = OffsetAllocator::Allocator(m_bufferSize); - buffer.offsetAllocator = allocator; } void GBufferVLK::destroyBuffer(BufferInternal &buffer) { @@ -51,57 +51,70 @@ void GBufferVLK::destroyBuffer(BufferInternal &buffer) { auto l_buffer = buffer; m_device->addDeallocationRecord( [l_buffer, l_device]() { - vmaClearVirtualBlock(l_buffer.virtualBlock); - vmaDestroyVirtualBlock(l_buffer.virtualBlock); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.stagingBuffer, l_buffer.stagingBufferAlloc); vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.g_hBuffer, l_buffer.g_hBufferAlloc); } ); } -VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset) { +VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, OffsetAllocator::Allocation &alloc) { + std::unique_lock lock(m_mutex, std::defer_lock); + bool minAddressStrategy = sizeInBytes < fakeSize && fakeSize > 0; if (sizeInBytes == 0) { - offset = 0; + alloc = {.offset = 0}; return VK_SUCCESS; } - VmaVirtualAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.size = sizeInBytes; //Size in bytes - if (minAddressStrategy) { - allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT; - } + uint32_t allocatingSize = sizeInBytes; //Size in bytes if (m_alignment > 0) { - allocCreateInfo.alignment = m_alignment; + allocatingSize = allocatingSize + m_alignment; + } + lock.lock(); + alloc = this->offsetAllocator.allocate(allocatingSize); + VkResult result = VK_SUCCESS; + if (alloc.offset == OffsetAllocator::Allocation::NO_SPACE) { + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; } - auto result = vmaVirtualAllocate(buffer.virtualBlock, &allocCreateInfo, &alloc, &offset); if (minAddressStrategy) { - if (result == VK_SUCCESS && (offset+fakeSize) > m_bufferSize) { - vmaVirtualFree(buffer.virtualBlock, alloc); + if (result == VK_SUCCESS && (alloc.offset+fakeSize) > m_bufferSize) { + this->offsetAllocator.free(alloc); result = VK_ERROR_OUT_OF_DEVICE_MEMORY; } } + lock.unlock(); + if (result == VK_SUCCESS && m_alignment > 0) { + int alignDifference = alloc.offset % m_alignment; + if (alignDifference > 0) { + alloc.offset = (alloc.offset + ((m_alignment - alignDifference) % m_alignment)); + } + } + return result; } -void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc) { - - //Destruction of this virtualBlock happens only in deallocation queue. +void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc) { + //Destruction of this virtualBlock happens only in deallocation queue. //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, //the virtualBlock was still not been free'd //So there would be no error - auto l_virtualBlock = buffer.virtualBlock; - auto l_alloc = alloc; - - m_device->addDeallocationRecord( - [l_virtualBlock, l_alloc]() { - vmaVirtualFree(l_virtualBlock, l_alloc); - - }); + if (alloc.metadata != OffsetAllocator::Allocation::NO_SPACE) { + auto l_alloc = alloc; + auto l_weak = weak_from_this(); + m_device->addDeallocationRecord( + [l_alloc, l_weak]() { + auto shared = l_weak.lock(); + if (shared == nullptr) return; + + std::unique_lock lock(shared->m_mutex, std::defer_lock); + lock.lock(); + shared->offsetAllocator.free(l_alloc); + lock.unlock(); + }); + } } void GBufferVLK::uploadData(void *data, int length) { @@ -126,8 +139,14 @@ std::shared_ptr GBufferVLK::mutate(int newSize) { return shared_from_this(); } void GBufferVLK::resize(int newLength) { + std::unique_lock lock(m_mutex, std::defer_lock); + lock.lock(); + auto oldSize = m_bufferSize; + offsetAllocator.growSize(newLength - oldSize); + m_bufferSize = newLength; + BufferInternal newBuffer; createBuffer(newBuffer); @@ -135,33 +154,19 @@ void GBufferVLK::resize(int newLength) { for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ auto subBuffer = it->lock(); if (subBuffer != nullptr) { - VmaVirtualAllocation alloc; - VkDeviceSize offset; - VkResult res = allocateSubBuffer(newBuffer, subBuffer->m_size, subBuffer->m_fakeSize, alloc, offset); - - if (res != VK_SUCCESS) { - std::cerr << "Could not allocate sub-buffer during resize " << std::endl; - } - - memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData + offset, - (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData + subBuffer->m_offset, - subBuffer->m_size - ); - if (subBuffer->m_size > 0) { - deallocateSubBuffer(currentBuffer, subBuffer->m_alloc); - - addSubBufferForUpload(*it); - } - - subBuffer->m_offset = offset; - subBuffer->m_alloc = alloc; - subBuffer->m_dataPointer = (uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData+offset; + subBuffer->m_dataPointer = (uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData+subBuffer->m_alloc.offset; } } + memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData, + (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData, + oldSize + ); + destroyBuffer(currentBuffer); currentBuffer = newBuffer; + for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ auto subBuffer = it->lock(); if (subBuffer != nullptr) { @@ -170,6 +175,7 @@ void GBufferVLK::resize(int newLength) { } executeOnChange(); + lock.unlock(); } static inline uint8_t BitScanMSB(uint32_t mask) @@ -198,25 +204,22 @@ static inline uint8_t BitScanMSB(uint32_t mask) //used for allocating data for UBO, when you don't want to suballocate whole size. //For example if only one bone matrix is used out 220, sizeInBytes will be size of one matrix, while fakeSize is 220 matrices std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBytes, int fakeSize) { - VmaVirtualAllocation alloc; - VkDeviceSize offset; + OffsetAllocator::Allocation alloc; - std::unique_lock lock(m_mutex, std::defer_lock); VkResult res = VK_ERROR_OUT_OF_DEVICE_MEMORY; if (sizeInBytes < m_bufferSize) { - lock.lock(); - res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc, offset); - lock.unlock(); + res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc); } if(res == VK_SUCCESS) { auto subBuffer = std::make_shared( shared_from_this(), - alloc, - offset, sizeInBytes, fakeSize, - (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset); + alloc, + alloc.offset, sizeInBytes, fakeSize, + (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+alloc.offset); + std::unique_lock lock(m_mutex, std::defer_lock); lock.lock(); currentSubBuffers.push_back(subBuffer); subBuffer->m_iterator = std::prev(currentSubBuffers.end()); @@ -225,14 +228,13 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy } else { - lock.lock(); resize(std::max(m_bufferSize*2, 1 << (BitScanMSB(m_bufferSize + fakeSize)+1))); - lock.unlock(); + return getSubBuffer(sizeInBytes, fakeSize); } } -void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation& alloc, int subBuffersize) { +void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, const OffsetAllocator::Allocation &alloc, int subBuffersize) { if (subBuffersize > 0) { deallocateSubBuffer(currentBuffer, alloc); } @@ -273,8 +275,20 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { newInterval = {.start = subBuffer->getOffset(), .size = subBuffer->getSize()}; } + if (lastSubmittedBufferSize != m_bufferSize) { + if (lastSubmittedBufferSize > 0) { + auto& newInterval = intervals.emplace_back(); + newInterval = { .start = 0, .size = lastSubmittedBufferSize }; + } + + lastSubmittedBufferSize = m_bufferSize; + } + std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b ) -> bool { - return a.start < b.start; + return + a.start != b.start + ? a.start < b.start + : a.size < b.size; }); if (!intervals.empty()) { @@ -299,7 +313,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); } else { assert(nextInterval.start - currInterval.start >= 0); - currInterval.size = (nextInterval.start - currInterval.start) + nextInterval.size; + currInterval.size = std::max(currInterval.size, (nextInterval.start - currInterval.start) + nextInterval.size); currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); } } @@ -323,7 +337,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { //---------------------------------------------------------------- GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, - VmaVirtualAllocation alloc, + OffsetAllocator::Allocation alloc, VkDeviceSize offset, int size, int fakeSize, uint8_t *dataPointer) : m_parentBuffer(parent) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 6a721a7e1..a326641bc 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -70,18 +70,23 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this dataToBeUploaded; + OffsetAllocator::Allocator offsetAllocator = OffsetAllocator::Allocator(1000); + std::mutex m_mutex; + + //If this variable is not equal current size -> whole buffer needs to be submitted + size_t lastSubmittedBufferSize = 0; + private: class GSubBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GBufferVLK; public: - explicit GSubBufferVLK(HGBufferVLK parent, VmaVirtualAllocation alloc, VkDeviceSize offset, + explicit GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, VkDeviceSize offset, int size, int fakeSize, uint8_t * dataPointer); ~GSubBufferVLK() override; @@ -102,7 +107,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubBuffer(int sizeInBytes, int fakeSize = -1); - void deleteSubBuffer(std::list>::const_iterator &it, VmaVirtualAllocation &alloc, int subBuffersize); + void deleteSubBuffer(std::list>::const_iterator &it, const OffsetAllocator::Allocation &alloc, int subBuffersize); private: void createBuffer(BufferInternal &buffer); void destroyBuffer(BufferInternal &buffer); - VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, VmaVirtualAllocation &alloc, VkDeviceSize &offset); - void deallocateSubBuffer(BufferInternal &buffer, VmaVirtualAllocation &alloc); + VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, OffsetAllocator::Allocation &alloc); + void deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc); }; From 588f6e1f027c3ed00b20ee94dd58268b1c6d19be Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 29 Apr 2023 09:30:21 +0300 Subject: [PATCH 068/212] offset allocator works --- .../OffsetAllocator/offsetAllocator.cpp | 29 +++++----- .../OffsetAllocator/offsetAllocator.hpp | 3 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 55 +++++++++++-------- .../vulkan/descriptorSets/GDescriptorSet.h | 1 + 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp index faabcf7ea..396df5b1f 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -151,15 +151,13 @@ namespace OffsetAllocator m_freeStorage(other.m_freeStorage), m_usedBinsTop(other.m_usedBinsTop), m_nodes(other.m_nodes), - m_freeNodes(other.m_freeNodes), - m_freeOffset(other.m_freeOffset) + m_freeNodes(other.m_freeNodes) { memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS); memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS); other.m_nodes.clear(); - other.m_freeNodes.clear(); - other.m_freeOffset = 0; + other.m_freeNodes = {}; other.m_maxAllocs = 0; other.m_usedBinsTop = 0; } @@ -168,7 +166,6 @@ namespace OffsetAllocator { m_freeStorage = 0; m_usedBinsTop = 0; - m_freeOffset = m_maxAllocs - 1; for (uint32 i = 0 ; i < NUM_TOP_BINS; i++) m_usedBins[i] = 0; @@ -177,20 +174,21 @@ namespace OffsetAllocator m_binIndices[i] = Node::unused; m_nodes.clear(); - m_freeNodes.clear(); + m_freeNodes = {}; m_nodes.resize(m_maxAllocs); - m_freeNodes.resize(m_maxAllocs); - + // Freelist is a stack. Nodes in inverse order so that [0] pops first. - for (uint32 i = 0; i < m_maxAllocs; i++) + for (int i = m_maxAllocs-1; i >= 0; i--) { - m_freeNodes[i] = m_maxAllocs - i - 1; + m_freeNodes.push(i); } + // Start state: Whole storage as one big node // Algorithm will split remainders and push them back as smaller nodes m_lastNode = insertNodeIntoBin(m_size, 0); + } Allocator::~Allocator() @@ -200,7 +198,7 @@ namespace OffsetAllocator Allocation Allocator::allocate(uint32 size) { // Out of allocations? - if (m_freeOffset == 0) + if (m_freeNodes.empty()) { return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE}; } @@ -340,7 +338,7 @@ namespace OffsetAllocator #ifdef DEBUG_VERBOSE printf("Putting node %u into freelist[%u] (free)\n", nodeIndex, m_freeOffset + 1); #endif - m_freeNodes[++m_freeOffset] = nodeIndex; + m_freeNodes.push(nodeIndex); // Insert the (combined) free node to bin uint32 combinedNodeIndex = insertNodeIntoBin(size, offset); @@ -380,7 +378,8 @@ namespace OffsetAllocator // Take a freelist node and insert on top of the bin linked list (next = old top) uint32 topNodeIndex = m_binIndices[binIndex]; - uint32 nodeIndex = m_freeNodes[m_freeOffset--]; + uint32 nodeIndex = m_freeNodes.top(); + m_freeNodes.pop(); #ifdef DEBUG_VERBOSE printf("Getting node %u from freelist[%u]\n", nodeIndex, m_freeOffset + 1); #endif @@ -438,7 +437,7 @@ namespace OffsetAllocator #ifdef DEBUG_VERBOSE printf("Putting node %u into freelist[%u] (removeNodeFromBin)\n", nodeIndex, m_freeOffset + 1); #endif - m_freeNodes[++m_freeOffset] = nodeIndex; + m_freeNodes.push(nodeIndex); m_freeStorage -= node.dataSize; #ifdef DEBUG_VERBOSE @@ -474,7 +473,7 @@ namespace OffsetAllocator uint32 freeStorage = 0; // Out of allocations? -> Zero free space - if (m_freeOffset > 0) + if (!m_freeNodes.empty()) { freeStorage = m_freeStorage; if (m_usedBinsTop) diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp index 044e78749..be44e167a 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace OffsetAllocator { @@ -103,7 +104,7 @@ namespace OffsetAllocator NodeIndex m_binIndices[NUM_LEAF_BINS]; std::vector m_nodes; - std::vector m_freeNodes; + std::stack m_freeNodes; uint32 m_lastNode; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 347769478..dc1b4c265 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1272,7 +1272,7 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings VkDescriptorSet GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) { //1. Try to allocate from existing sets - for (size_t i = 0; i < m_descriptorPools.size(); i++) { + for (int i = m_descriptorPools.size() - 1; i >= 0 ; i--) { desciptorPool = m_descriptorPools[i]; auto result = desciptorPool->allocate(hDescriptorSetLayout); if (result != nullptr) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index ddbc0bdc6..c20c80666 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -22,28 +22,38 @@ GBufferVLK::~GBufferVLK() { } void GBufferVLK::createBuffer(BufferInternal &buffer) { -//Create new buffer for VBO - VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - vbInfo.size = m_bufferSize; - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo ibAllocCreateInfo = {}; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, - &buffer.stagingBuffer, - &buffer.stagingBufferAlloc, - &buffer.stagingBufferAllocInfo)); - - // No need to flush stagingBuffer memory because CPU_ONLY memory is always HOST_COHERENT. - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | m_usageFlags; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ibAllocCreateInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, - &buffer.g_hBuffer, - &buffer.g_hBufferAlloc, nullptr)); + //Create new buffer + { + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = m_bufferSize; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo stagingAllocInfo = {}; + stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + stagingAllocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, + &buffer.stagingBuffer, + &buffer.stagingBufferAlloc, + &buffer.stagingBufferAllocInfo)); + } + + { + // No need to flush stagingBuffer memory because CPU_ONLY memory is always HOST_COHERENT. + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = m_bufferSize; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | m_usageFlags; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo stagingAllocInfo = {}; + stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO; + stagingAllocInfo.flags = 0; + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, + &buffer.g_hBuffer, + &buffer.g_hBufferAlloc, nullptr)); + } } void GBufferVLK::destroyBuffer(BufferInternal &buffer) { @@ -157,7 +167,6 @@ void GBufferVLK::resize(int newLength) { subBuffer->m_dataPointer = (uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData+subBuffer->m_alloc.offset; } } - memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData, oldSize diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 637e58210..3951eac54 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -39,6 +39,7 @@ class GDescriptorSet : public std::enable_shared_from_this { //So that the resize of these vectors would not lead to pointer invalidation in updates vector bufferInfos.reserve(32); imageInfos.reserve(32); + updates.reserve(64); } ~SetUpdateHelper(); // SetUpdateHelper is non-copyable From 0a65232827eaafde1757e6c924344da92110f7b7 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 3 May 2023 01:56:54 +0300 Subject: [PATCH 069/212] minimized the samplers amount --- src/ui/FrontendUI.h | 2 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 4 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 4 +- .../uiScene/IFrontendUIBufferCreate.h | 2 +- .../renderer/uiScene/materials/UIMaterial.h | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- wowViewerLib/CMakeLists.txt | 4 +- .../src/engine/objects/adt/adtObject.cpp | 23 ++++---- .../src/engine/objects/adt/adtObject.h | 14 ++--- wowViewerLib/src/engine/objects/iWmoApi.h | 2 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 12 ++-- .../src/engine/objects/wmo/wmoObject.h | 6 +- wowViewerLib/src/gapi/interface/IDevice.cpp | 2 +- wowViewerLib/src/gapi/interface/IDevice.h | 14 +++-- .../src/gapi/interface/IFrameBuffer.h | 2 +- .../interface/textures/ISamplableTexture.h | 34 +++++++++++ .../gapi/interface/textures/ITextureSampler.h | 16 ++++++ .../src/gapi/vulkan/GDeviceVulkan.cpp | 25 ++++++--- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 15 +++-- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 26 ++++++++- .../src/gapi/vulkan/GFrameBufferVLK.h | 7 ++- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 9 +-- .../src/gapi/vulkan/TextureManagerVLK.cpp | 43 +++++++++++++- .../src/gapi/vulkan/TextureManagerVLK.h | 36 ++++++++++-- .../vulkan/descriptorSets/DescriptorRecord.h | 18 ++++-- .../vulkan/descriptorSets/GDescriptorSet.cpp | 18 ++++-- .../vulkan/descriptorSets/GDescriptorSet.h | 8 +-- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 2 +- .../vulkan/textures/GTextureSamplerVLK.cpp | 49 ++++++++++++++++ .../gapi/vulkan/textures/GTextureSamplerVLK.h | 27 +++++++++ .../src/gapi/vulkan/textures/GTextureVLK.cpp | 32 ----------- .../src/gapi/vulkan/textures/GTextureVLK.h | 1 - .../mapScene/materials/IMaterialStructs.h | 18 +++--- .../vulkan/MapSceneRenderForwardVLK.cpp | 56 +++++++++---------- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 14 ++--- .../mapScene/vulkan/passes/FFXGlowPassVLK.h | 8 +-- 39 files changed, 390 insertions(+), 177 deletions(-) create mode 100644 wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h create mode 100644 wowViewerLib/src/gapi/interface/textures/ITextureSampler.h create mode 100644 wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 1c5f53c2b..32f4cbee2 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -97,7 +97,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this, 64> adtSelectionMinimapTextures; + std::array, 64> adtSelectionMinimapTextures; std::array, 64> adtSelectionMinimapMaterials; void emptyMinimap() { diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 3bd10836d..a576488c0 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -111,8 +111,8 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrfontTexture = m_device->createTexture(false, false); - this->fontTexture->loadData(width, height, pixels, ITextureFormat::itRGBA); + this->fontTexture->getTexture()->loadData(width, height, pixels, ITextureFormat::itRGBA); return this->fontTexture; } diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 3a2d478eb..ad176c669 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -39,10 +39,10 @@ class FrontendUIRenderer : public IRendererParameters getLastCreatedPlan() override { return nullptr; } - HGTexture uploadFontTexture(unsigned char* pixels, int width, int height); + HGSamplableTexture uploadFontTexture(unsigned char* pixels, int width, int height); protected: HGDevice m_device = nullptr; - HGTexture fontTexture; + HGSamplableTexture fontTexture; UiMaterialCache m_materialCache; std::shared_ptr> m_imguiUbo = nullptr; diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index b789a1961..9d9cb7f00 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -18,7 +18,7 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; - virtual HMaterial createUIMaterial(const HGTexture &hgtexture) = 0; + virtual HMaterial createUIMaterial(const HGSamplableTexture &hgtexture) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index e8699bb64..d558230df 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -13,6 +13,6 @@ #include "../../../../wowViewerLib/src/include/custom_container_key.h" -typedef std::unordered_map, std::weak_ptr> UiMaterialCache; +typedef std::unordered_map>, std::weak_ptr> UiMaterialCache; #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 14f14eacb..b1197c9b3 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -44,7 +44,7 @@ HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vert return imguiVAO; } -HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtexture) { +HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture &hgtexture) { auto weakTexture = std::weak_ptr(hgtexture); auto i = m_materialCache.find(weakTexture); if (i != m_materialCache.end()) { @@ -64,7 +64,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGTexture &hgtextur }) .createDescriptorSet(1, [&hgtexture](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(hgtexture)); + .texture(5, hgtexture); }) .toMaterial(); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 2b4b2ba9c..8e841b9e1 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -26,7 +26,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; - HMaterial createUIMaterial(const HGTexture &hgtexture) override; + HMaterial createUIMaterial(const HGSamplableTexture &hgtexture) override; private: diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 9ca6049d5..f766d9cbe 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -335,7 +335,7 @@ set(SOURCE_FILES src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h src/include/custom_container_key.h - src/renderer/mapScene/materials/IMaterialStructs.h) + src/renderer/mapScene/materials/IMaterialStructs.h src/gapi/interface/textures/ITextureSampler.h src/gapi/interface/textures/ISamplableTexture.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -525,7 +525,7 @@ if (LINK_VULKAN) src/gapi/vulkan/bindable/DSBindable.h src/renderer/mapScene/vulkan/materials/IMaterialInstance.h src/gapi/vulkan/meshes/GSortableMeshVLK.cpp - src/gapi/vulkan/meshes/GSortableMeshVLK.h) + src/gapi/vulkan/meshes/GSortableMeshVLK.h src/gapi/vulkan/textures/GTextureSamplerVLK.cpp src/gapi/vulkan/textures/GTextureSamplerVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 65aa99049..b540f6f0f 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -765,10 +765,11 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { this->m_adtFile->mapTile[i].position.z, 0 ); + + matVSPS.useHeightMixFormula[0] = useHeightMixFormula; for (int j = 0; j < 4; j++) { matVSPS.uHeightOffset[j] = 0.0f; matVSPS.uHeightScale[j] = 1.0f; - } for (int j = 0; j < adtFileTex->mcnkStructs[i].mclyCnt; j++) { if ((adtFileTex->mtxp_len > 0) && !noLayers) { @@ -787,7 +788,7 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { auto const &textureParams = m_adtFileTex->mtxp[m_adtFileTex->mcnkStructs[i].mcly[j].textureId]; - HGTexture layer_height = device->getWhiteTexturePixel(); + auto layer_height = device->getWhiteTexturePixel(); if (textureParams.flags.do_not_load_specular_or_height_texture_but_use_cubemap == 0) { if (!feq(textureParams.heightScale, 0.0)) { layer_height = getAdtHeightTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); @@ -812,7 +813,7 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { auto &layerDef = m_adtFileTex->mcnkStructs[i].mcly[j]; - HGTexture layer_x = getAdtTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); + HGSamplableTexture layer_x = getAdtTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); // BlpTexture &layer_spec = getAdtSpecularTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); adtMaterialTemplate.textures[j] = layer_x; } @@ -833,11 +834,11 @@ void AdtObject::loadAlphaTextures() { int createdThisRun = 0; for (int i = 0; i < chunkCount; i++) { - HGTexture alphaTexture = m_api->hDevice->createTexture(false, false); + HGSamplableTexture alphaTexture = m_api->hDevice->createTexture(false, false); std::vector alphaTextureData; m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); - alphaTexture->loadData(texWidth, texHeight, &alphaTextureData[0], ITextureFormat::itRGBA); + alphaTexture->getTexture()->loadData(texWidth, texHeight, &alphaTextureData[0], ITextureFormat::itRGBA); alphaTextures.push_back(alphaTexture); } @@ -1041,7 +1042,7 @@ void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependant } } -HGTexture AdtObject::getAdtTexture(int textureId) { +HGSamplableTexture AdtObject::getAdtTexture(int textureId) { auto item = m_requestedTextures.find(textureId); if (item != m_requestedTextures.end()) { return item->second; @@ -1056,7 +1057,7 @@ HGTexture AdtObject::getAdtTexture(int textureId) { texture = m_api->cacheStorage->getTextureCache()->getFileId(filedataId); } - HGTexture h_gblpTexture = nullptr; + HGSamplableTexture h_gblpTexture = nullptr; if (texture != nullptr) { h_gblpTexture = m_api->hDevice->createBlpTexture(texture, true, true); } else { @@ -1068,7 +1069,7 @@ HGTexture AdtObject::getAdtTexture(int textureId) { return h_gblpTexture; } -HGTexture AdtObject::getAdtHeightTexture(int textureId) { +HGSamplableTexture AdtObject::getAdtHeightTexture(int textureId) { auto item = m_requestedTexturesHeight.find(textureId); if (item != m_requestedTexturesHeight.end()) { return item->second; @@ -1085,13 +1086,13 @@ HGTexture AdtObject::getAdtHeightTexture(int textureId) { texture = m_api->cacheStorage->getTextureCache()->getFileId(filedataId); } - HGTexture h_gblpTexture = m_api->hDevice->createBlpTexture(texture, true, true); + HGSamplableTexture h_gblpTexture = m_api->hDevice->createBlpTexture(texture, true, true); m_requestedTexturesHeight[textureId] = h_gblpTexture; return h_gblpTexture; } -HGTexture AdtObject::getAdtSpecularTexture(int textureId) { +HGSamplableTexture AdtObject::getAdtSpecularTexture(int textureId) { auto item = m_requestedTexturesSpec.find(textureId); if (item != m_requestedTexturesSpec.end()) { return item->second; @@ -1102,7 +1103,7 @@ HGTexture AdtObject::getAdtSpecularTexture(int textureId) { std::string matHeightText = materialTexture.substr(0, materialTexture.size() - 4) + "_s.blp"; HBlpTexture texture = m_api->cacheStorage->getTextureCache()->get(matHeightText); - HGTexture h_gblpTexture = m_api->hDevice->createBlpTexture(texture, true, true); + HGSamplableTexture h_gblpTexture = m_api->hDevice->createBlpTexture(texture, true, true); m_requestedTexturesSpec[textureId] = h_gblpTexture; return h_gblpTexture; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 21f344560..c84dd6a82 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -110,9 +110,9 @@ class AdtObject { int mostDetailedLod = 0; // 0 = most detailed LOD, 5 = least detailed lod int leastDetiledLod = 0; - std::unordered_map m_requestedTextures; - std::unordered_map m_requestedTexturesHeight; - std::unordered_map m_requestedTexturesSpec; + std::unordered_map m_requestedTextures; + std::unordered_map m_requestedTexturesHeight; + std::unordered_map m_requestedTexturesSpec; std::vector lodCommands; @@ -126,7 +126,7 @@ class AdtObject { HGVertexBufferBindings lodVertexBindings; private: - std::vector alphaTextures; + std::vector alphaTextures; HBlpTexture lodDiffuseTexture = nullptr; HBlpTexture lodNormalTexture = nullptr; @@ -158,9 +158,9 @@ class AdtObject { }; std::array objectLods; - HGTexture getAdtTexture(int textureId); - HGTexture getAdtHeightTexture(int textureId); - HGTexture getAdtSpecularTexture(int textureId); + HGSamplableTexture getAdtTexture(int textureId); + HGSamplableTexture getAdtHeightTexture(int textureId); + HGSamplableTexture getAdtSpecularTexture(int textureId); struct AnimTextures { std::array animTexture; diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index a466cd33b..06c9e3b2e 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -318,7 +318,7 @@ class IWmoApi { virtual std::vector &getPortalInfos() = 0; - virtual HGTexture getTexture(int textureId, bool isSpec) = 0; + virtual HGSamplableTexture getTexture(int textureId, bool isSpec) = 0; virtual void updateBB() = 0; virtual void postWmoGroupObjectLoad(int groupId, int lod) = 0; virtual std::shared_ptr> getPlacementBuffer() = 0; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index a80f7cf5a..feb78f2d5 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1854,7 +1854,7 @@ HBlpTexture M2Object::getBlpTextureData(int textureInd) { return blpData; } -HGTexture M2Object::getTexture(int textureInd) { +HGSamplableTexture M2Object::getTexture(int textureInd) { M2Texture* textureDefinition = m_m2Geom->getM2Data()->textures.getElement(textureInd); HBlpTexture blpData = getBlpTextureData(textureInd); @@ -1862,7 +1862,7 @@ HGTexture M2Object::getTexture(int textureInd) { if (blpData == nullptr) return nullptr; - HGTexture hgTexture = m_api->hDevice->createBlpTexture( + HGSamplableTexture hgTexture = m_api->hDevice->createBlpTexture( blpData, textureDefinition!= nullptr ? ( (textureDefinition->flags & 1) > 0 ) : false, textureDefinition!= nullptr ? ( (textureDefinition->flags & 2) > 0 ) : false diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index bca64e93f..42327675b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -277,7 +277,7 @@ class M2Object { void setDiffuseColor(CImVector& value); HBlpTexture getBlpTextureData(int textureInd); - HGTexture getTexture(int textureInd); + HGSamplableTexture getTexture(int textureInd); HBlpTexture getHardCodedTexture(int textureInd); mathfu::vec4 getM2SceneAmbientLight(); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index d021da794..857159562 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -682,7 +682,7 @@ void WmoObject::setLoadingParam(SMMapObjDefObj1 &mapObjDef) { this->m_nameSet = mapObjDef.nameSet; } -HGTexture WmoObject::getTexture(int textureId, bool isSpec) { +HGSamplableTexture WmoObject::getTexture(int textureId, bool isSpec) { if (textureId == 0) return nullptr; //Usual case //Non-usual case @@ -691,7 +691,7 @@ HGTexture WmoObject::getTexture(int textureId, bool isSpec) { return nullptr; }; - std::unordered_map &textureCache = diffuseTextures; + std::unordered_map &textureCache = diffuseTextures; if (isSpec) { textureCache = specularTextures; } @@ -714,7 +714,7 @@ HGTexture WmoObject::getTexture(int textureId, bool isSpec) { texture = m_api->cacheStorage->getTextureCache()->getFileId(textureId); } - HGTexture hgTexture = m_api->hDevice->createBlpTexture(texture, true, true); + auto hgTexture = m_api->hDevice->createBlpTexture(texture, true, true); textureCache[textureId] = hgTexture; return hgTexture; @@ -1506,9 +1506,9 @@ std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) bool isSecondTextSpec = material.shader == 8; - HGTexture texture1 = getTexture(material.diffuseNameIndex, false); - HGTexture texture2 = getTexture(material.envNameIndex, isSecondTextSpec); - HGTexture texture3 = getTexture(material.texture_2, false); + HGSamplableTexture texture1 = getTexture(material.diffuseNameIndex, false); + HGSamplableTexture texture2 = getTexture(material.envNameIndex, isSecondTextSpec); + HGSamplableTexture texture3 = getTexture(material.texture_2, false); WMOMaterialTemplate materialTemplate; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index f0560e718..5023f92fa 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -77,8 +77,8 @@ class WmoObject : public IWmoApi { std::shared_ptr skyBox = nullptr; - std::unordered_map diffuseTextures; - std::unordered_map specularTextures; + std::unordered_map diffuseTextures; + std::unordered_map specularTextures; std::shared_ptr> m_modelWideChunk; std::vector> m_materialCache; @@ -93,7 +93,7 @@ class WmoObject : public IWmoApi { friend void attenuateTransVerts(HWmoMainGeom &mainGeom, WmoGroupGeom& wmoGroupGeom); public: std::shared_ptr getDoodad(int index) override ; - HGTexture getTexture(int materialId, bool isSpec) override; + HGSamplableTexture getTexture(int materialId, bool isSpec) override; void setLoadingParam( SMMapObjDef &mapObjDef); void setLoadingParam( SMMapObjDefObj1 &mapObjDef); diff --git a/wowViewerLib/src/gapi/interface/IDevice.cpp b/wowViewerLib/src/gapi/interface/IDevice.cpp index d91595bc9..5211c199d 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.cpp +++ b/wowViewerLib/src/gapi/interface/IDevice.cpp @@ -18,7 +18,7 @@ int anisFiltrationSupported = -1; #include #endif -bool IDevice::getIsCompressedTexturesSupported() { +bool IDevice::getIsDTXCompressedTexturesSupported() { #ifdef __EMSCRIPTEN__ if (compressedTexturesSupported == -1){ auto res = emscripten_webgl_enable_extension(emscripten_webgl_get_current_context(), "WEBGL_compressed_texture_s3tc"); diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 94a1234ad..78910d18a 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -15,6 +15,7 @@ class IVertexBufferBindings; class IBuffer; class IUniformBuffer; class ITexture; +class ITextureSampler; class IShaderPermutation; class IMesh; class ISortableMesh; @@ -30,6 +31,7 @@ class gMeshTemplate; #include "syncronization/IGPUFence.h" #include "../vulkan/context/vulkan_context.h" +#include "textures/ISamplableTexture.h" typedef std::shared_ptr HGVertexBufferDynamic; typedef std::shared_ptr HGVertexBuffer; @@ -43,6 +45,8 @@ typedef std::shared_ptr HGSortableMesh; typedef std::shared_ptr HGParticleMesh; typedef std::shared_ptr HGOcclusionQuery; typedef std::shared_ptr HGTexture; +typedef std::shared_ptr HGSampler; +typedef std::shared_ptr HGSamplableTexture; typedef std::weak_ptr WGTexture; typedef std::shared_ptr HGPUFence; typedef std::shared_ptr HFrameBuffer; @@ -174,7 +178,7 @@ class IDevice { virtual void drawFrame(const std::vector> &renderFuncs) = 0; // virtual void drawStageAndDeps(HDrawStage drawStage) = 0; - virtual bool getIsCompressedTexturesSupported(); + virtual bool getIsDTXCompressedTexturesSupported(); virtual bool getIsAnisFiltrationSupported(); virtual float getAnisLevel() = 0; virtual bool getIsVulkanAxisSystem() {return false;} @@ -191,10 +195,10 @@ class IDevice { //Creates or receives framebuffer and tells it would be occupied for frameNumber frames virtual HFrameBuffer createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) = 0; - virtual HGTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) = 0; - virtual HGTexture createTexture(bool xWrapTex, bool yWrapTex) = 0; - virtual HGTexture getWhiteTexturePixel() = 0; - virtual HGTexture getBlackTexturePixel() = 0; + virtual HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) = 0; + virtual HGSamplableTexture createTexture(bool xWrapTex, bool yWrapTex) = 0; + virtual HGSamplableTexture getWhiteTexturePixel() = 0; + virtual HGSamplableTexture getBlackTexturePixel() = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate) = 0; virtual void shrinkData() {}; diff --git a/wowViewerLib/src/gapi/interface/IFrameBuffer.h b/wowViewerLib/src/gapi/interface/IFrameBuffer.h index 8e3aba2a0..33817eb74 100644 --- a/wowViewerLib/src/gapi/interface/IFrameBuffer.h +++ b/wowViewerLib/src/gapi/interface/IFrameBuffer.h @@ -10,7 +10,7 @@ class IFrameBuffer { public: virtual ~IFrameBuffer(){}; - virtual HGTexture getAttachment(int index) = 0; + virtual HGSamplableTexture getAttachment(int index) = 0; virtual HGTexture getDepthTexture() = 0; virtual void bindFrameBuffer() = 0; virtual void copyRenderBufferToTexture() = 0; diff --git a/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h b/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h new file mode 100644 index 000000000..245c0d0a1 --- /dev/null +++ b/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h @@ -0,0 +1,34 @@ +// +// Created by Deamon on 4/30/2023. +// + +#ifndef AWEBWOWVIEWERCPP_ISAMPLABLETEXTURE_H +#define AWEBWOWVIEWERCPP_ISAMPLABLETEXTURE_H + +#include +#include "ITexture.h" +#include "ITextureSampler.h" + +class ISamplableTexture { +public: + ISamplableTexture(const std::shared_ptr &texture, + const std::shared_ptr &sampler) : m_texture(texture), m_sampler(sampler) { + + }; + + auto getTexture() const { + return m_texture; + } + + auto getSampler() const { + return m_sampler; + } + +private: + std::shared_ptr m_texture; + std::shared_ptr m_sampler; +}; + +typedef std::shared_ptr HGSamplableTexture; + +#endif //AWEBWOWVIEWERCPP_ISAMPLABLETEXTURE_H diff --git a/wowViewerLib/src/gapi/interface/textures/ITextureSampler.h b/wowViewerLib/src/gapi/interface/textures/ITextureSampler.h new file mode 100644 index 000000000..9ab6a9647 --- /dev/null +++ b/wowViewerLib/src/gapi/interface/textures/ITextureSampler.h @@ -0,0 +1,16 @@ +// +// Created by Deamon on 4/29/2023. +// + +#ifndef AWEBWOWVIEWERCPP_ITEXTURESAMPLER_H +#define AWEBWOWVIEWERCPP_ITEXTURESAMPLER_H + +#include +class ITextureSampler { +public: + virtual ~ITextureSampler() {}; +}; + +typedef std::shared_ptr HGSampler; + +#endif //AWEBWOWVIEWERCPP_ITEXTURESAMPLER_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index dc1b4c265..034daea0a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -173,8 +173,6 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ enableValidationLayers = false; - m_textureManager->initialize(); - if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; exit(1); @@ -310,10 +308,14 @@ void GDeviceVLK::initialize() { vmaCreateAllocator(&allocatorInfo, &vmaAllocator); //--------------- vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures); uniformBufferOffsetAlign = deviceProperties.limits.minUniformBufferOffsetAlignment; maxUniformBufferSize = deviceProperties.limits.maxUniformBufferRange; //--------------- + m_textureManager->initialize(); +//--------------- + createSwapChainAndFramebuffer(); createCommandPool(); @@ -327,11 +329,11 @@ void GDeviceVLK::initialize() { m_blackPixelTexture = createTexture(false, false); unsigned int zero = 0; - m_blackPixelTexture->loadData(1,1,&zero, ITextureFormat::itRGBA); + m_blackPixelTexture->getTexture()->loadData(1,1,&zero, ITextureFormat::itRGBA); m_whitePixelTexture = createTexture(false, false); unsigned int ff = 0xffffffff; - m_whitePixelTexture->loadData(1,1,&ff, ITextureFormat::itRGBA); + m_whitePixelTexture->getTexture()->loadData(1,1,&ff, ITextureFormat::itRGBA); } void GDeviceVLK::setObjectName(uint64_t object, VkObjectType objectType, const char *name) @@ -787,6 +789,13 @@ void GDeviceVLK::increaseFrameNumber() { m_frameNumber++; } +bool GDeviceVLK::getIsAnisFiltrationSupported() { + return supportedFeatures.samplerAnisotropy; +}; +bool GDeviceVLK::getIsDTXCompressedTexturesSupported() { + return supportedFeatures.textureCompressionBC; +}; + float GDeviceVLK::getAnisLevel() { return deviceProperties.limits.maxSamplerAnisotropy; } @@ -1072,12 +1081,12 @@ HGVertexBufferBindings GDeviceVLK::createVertexBufferBindings() { return h_vertexBindings; } -HGTexture GDeviceVLK::createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) { - return m_textureManager->createBlpTexture(texture); +HGSamplableTexture GDeviceVLK::createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) { + return m_textureManager->createBlpTexture(texture, xWrapTex, yWrapTex); } -HGTexture GDeviceVLK::createTexture(bool xWrapTex, bool yWrapTex) { - return m_textureManager->createTexture(); +HGSamplableTexture GDeviceVLK::createTexture(bool xWrapTex, bool yWrapTex) { + return m_textureManager->createTexture(xWrapTex, yWrapTex); } HGMesh GDeviceVLK::createMesh(gMeshTemplate &meshTemplate) { diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index c9aac62bd..a7725188a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -78,6 +78,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_textureManager; protected: diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index 1151bba1f..de1d248e1 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -6,6 +6,7 @@ #include "textures/GTextureVLK.h" #include "GRenderPassVLK.h" +#include "textures/GTextureSamplerVLK.h" void GFrameBufferVLK::iterateOverAttachments(const std::vector &textureAttachments, std::function callback) { for (int i = 0; i < textureAttachments.size(); i++) { @@ -29,6 +30,19 @@ void GFrameBufferVLK::iterateOverAttachments(const std::vector & } } +static std::shared_ptr s_sampler = nullptr; + +inline void GFrameBufferVLK::initSampler(GDeviceVLK &device) { + if (s_sampler == nullptr) + s_sampler = std::make_shared(device, false, false); +} +inline void GFrameBufferVLK::initSamplableTextures() { + m_attachmentTexturesSampled.resize(m_attachmentTextures.size()); + for (int i = 0; i < m_attachmentTextures.size(); i++) { + m_attachmentTexturesSampled[i] = std::make_shared(m_attachmentTextures[i], s_sampler); + } +} + //Support for swapchain framebuffer GFrameBufferVLK::GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, @@ -38,6 +52,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, m_renderPass(renderPass), m_attachmentTextures({colorImage}) { + initSampler(mdevice); + { // Find a suitable depth format VkFormat fbDepthFormat = mdevice.findDepthFormat(); @@ -73,6 +89,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, fbufCreateInfo.layers = 1; ERR_GUARD_VULKAN(vkCreateFramebuffer(mdevice.getVkDevice(), &fbufCreateInfo, nullptr, &m_frameBuffer)); + + initSamplableTextures(); } GFrameBufferVLK::GFrameBufferVLK(IDevice &device, @@ -83,6 +101,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, m_height(height), m_width(width), m_multiSampleCnt(multiSampleCnt){ + initSampler(mdevice); + std::vector attachments; height = std::max(height, 1); @@ -160,6 +180,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, fbufCreateInfo.layers = 1; ERR_GUARD_VULKAN(vkCreateFramebuffer(mdevice.getVkDevice(), &fbufCreateInfo, nullptr, &m_frameBuffer)); + + initSamplableTextures(); } GFrameBufferVLK::~GFrameBufferVLK() { @@ -409,13 +431,13 @@ void GFrameBufferVLK::readRGBAPixels(int x, int y, int width, int height, void * vmaDestroyImage(mdevice.getVMAAllocator(), dstImage, imageAllocation); } -HGTexture GFrameBufferVLK::getAttachment(int index) { +HGSamplableTexture GFrameBufferVLK::getAttachment(int index) { //If multisampling is active - return only resolved textures if (m_multiSampleCnt > 1) { index = 2*index+1; } - return m_attachmentTextures[index]; + return m_attachmentTexturesSampled[index]; } HGTexture GFrameBufferVLK::getDepthTexture() { diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index 65a81f4aa..cda659cc6 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -20,7 +20,7 @@ class GFrameBufferVLK : public IFrameBuffer { ~GFrameBufferVLK() override; void readRGBAPixels(int x, int y, int width, int height, void *data) override; - HGTexture getAttachment(int index) override; + HGSamplableTexture getAttachment(int index) override; HGTexture getDepthTexture() override; void bindFrameBuffer() override; void copyRenderBufferToTexture() override; @@ -30,6 +30,7 @@ class GFrameBufferVLK : public IFrameBuffer { VkFramebuffer getFrameBuffer() {return m_frameBuffer;}; int getColorOrDataAttachmentCount() { return m_attachmentFormats.size(); }; + private: GDeviceVLK &mdevice; @@ -37,6 +38,7 @@ class GFrameBufferVLK : public IFrameBuffer { VkFramebuffer m_frameBuffer; std::vector m_attachmentTextures; + std::vector m_attachmentTexturesSampled; HGTexture m_depthTexture; //Used only in readRGBAPixels function @@ -46,6 +48,9 @@ class GFrameBufferVLK : public IFrameBuffer { int m_width = 0; int m_height = 0; + + inline void initSampler(GDeviceVLK &device); + inline void initSamplableTextures(); }; diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index 0dc07e94b..1de03c0c0 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -11,6 +11,7 @@ #include "descriptorSets/GDescriptorPoolVLK.h" #include "../interface/textures/ITexture.h" +#include "../interface/textures/ISamplableTexture.h" struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; @@ -33,13 +34,13 @@ class IDeviceVulkan { virtual VmaAllocator getVMAAllocator() = 0; virtual VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) = 0; - virtual std::shared_ptr getWhiteTexturePixel() = 0; - virtual std::shared_ptr getBlackTexturePixel() = 0; + virtual HGSamplableTexture getWhiteTexturePixel() = 0; + virtual HGSamplableTexture getBlackTexturePixel() = 0; //TODO: - bool getIsAnisFiltrationSupported() {return true;}; + virtual bool getIsAnisFiltrationSupported() {return true;}; //TODO: - bool getIsCompressedTexturesSupported() {return true;}; + virtual bool getIsDTXCompressedTexturesSupported() {return true;}; virtual float getAnisLevel() = 0; virtual const QueueFamilyIndices &getQueueFamilyIndices() = 0; diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index 6185b8f22..cb8e8e7e5 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -5,12 +5,48 @@ #include "GDeviceVulkan.h" #include "TextureManagerVLK.h" #include "textures/GBlpTextureVLK.h" +#include "textures/GTextureSamplerVLK.h" -TextureManagerVLK::TextureManagerVLK(IDevice &device) : mdevice(device) { +TextureManagerVLK::TextureManagerVLK(IDeviceVulkan &device) : mdevice(device) { } void TextureManagerVLK::initialize() { createUpdateCallback(); + + m_textureSamplers[0] = std::make_shared(mdevice, false, false); + m_textureSamplers[1] = std::make_shared(mdevice, false, true); + m_textureSamplers[2] = std::make_shared(mdevice, true, false); + m_textureSamplers[3] = std::make_shared(mdevice, true, true); +} + +HGSamplableTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture, bool wrapX, bool wrapY) { + auto textureVlk = createBlpTexture(texture); + + SampledTextureCacheRecord sampledTextureCacheRecord = { + .texture = std::weak_ptr(textureVlk), + .wrapX = wrapX, + .wrapY = wrapY + }; + + std::lock_guard lock(m_textureAllocation); + + auto i = sampledTextureCache.find(sampledTextureCacheRecord); + if (i != sampledTextureCache.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + sampledTextureCache.erase(i); + } + } + + auto sampler = m_textureSamplers[((wrapX ? 1 : 0) * 2) + (wrapY ? 1 : 0)]; + auto hgSamplableTexture = std::make_shared(textureVlk, sampler); + + std::weak_ptr weakPtr(hgSamplableTexture); + + sampledTextureCache[sampledTextureCacheRecord] = hgSamplableTexture; + + return hgSamplableTexture; } HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { @@ -42,10 +78,11 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { return hgTexture; } -HGTexture TextureManagerVLK::createTexture() { +HGSamplableTexture TextureManagerVLK::createTexture(bool wrapX, bool wrapY) { std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), true, true, onUpdateCallback); - return h_texture; + auto sampler = m_textureSamplers[((wrapX ? 1 : 0) * 2) + (wrapY ? 1 : 0)]; + return std::make_shared(h_texture,sampler); } void TextureManagerVLK::createUpdateCallback() { diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 0b3159e9e..1d3770bd0 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -14,12 +14,11 @@ class TextureManagerVLK : public std::enable_shared_from_this { public: - TextureManagerVLK(IDevice &device); + TextureManagerVLK(IDeviceVulkan &device); void initialize(); - - HGTexture createBlpTexture(HBlpTexture &texture); - HGTexture createTexture(); + HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool wrapX, bool wrapY); + HGSamplableTexture createTexture(bool wrapX, bool wrapY); MutexLockedVector> getReadyToUploadTextures() { @@ -54,8 +53,33 @@ class TextureManagerVLK : public std::enable_shared_from_this }; std::unordered_map, BlpCacheRecordHasher> loadedTextureCache; + + struct SampledTextureCacheRecord { + wtf::KeyContainer> texture; + bool wrapX; + bool wrapY; + + bool operator==(const SampledTextureCacheRecord &other) const { + return + (texture == other.texture) && + (wrapX == other.wrapX) && + (wrapY == other.wrapY); + }; + }; + struct SampledTextureCacheRecordHasher { + std::size_t operator()(const SampledTextureCacheRecord& k) const { + using std::hash; + return hash{}(k.texture) ^ + (hash{}(k.wrapX) << 8) ^ + (hash{}(k.wrapX) << 8); + }; + }; + std::unordered_map, SampledTextureCacheRecordHasher> sampledTextureCache; + private: - IDevice &mdevice; + HGTexture createBlpTexture(HBlpTexture &texture); +private: + IDeviceVulkan &mdevice; std::mutex m_textureAllocation; @@ -68,6 +92,8 @@ class TextureManagerVLK : public std::enable_shared_from_this std::mutex blpTextureLoadMutex; std::list> m_blpTextLoadQueue; + + std::array, 4> m_textureSamplers; }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h index 73fd8dbec..482d47124 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -20,12 +20,15 @@ class DescriptorRecord { DescriptorRecord() = delete; - explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const std::shared_ptr &texture, const std::function &OnHandleChange) { + explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const HGSamplableTexture &texture, const std::function &OnHandleChange) { this->descType = DescriptorRecord::DescriptorRecordType::Texture; - this->textureVlk = texture; + this->texture = texture; if (texture != nullptr) { - iteratorUnique = texture->addOnHandleChange(OnHandleChange); + auto textureVlk = texture->getTexture(); + if (textureVlk != nullptr) { + iteratorUnique = std::dynamic_pointer_cast(textureVlk)->addOnHandleChange(OnHandleChange); + } } } explicit DescriptorRecord(DescriptorRecord::DescriptorRecordType descType, const std::shared_ptr &buffer, const std::function &OnHandleChange) { @@ -39,8 +42,11 @@ class DescriptorRecord { if (iteratorUnique) { if (buffer) { buffer->eraseOnHandleChange(iteratorUnique); - } else if (textureVlk) { - textureVlk->eraseOnHandleChange(iteratorUnique); + } else if (texture) { + auto textureVlk = texture->getTexture(); + if (textureVlk != nullptr) { + std::dynamic_pointer_cast(textureVlk)->eraseOnHandleChange(iteratorUnique); + } } } } @@ -51,7 +57,7 @@ class DescriptorRecord { DescriptorRecordType descType = DescriptorRecordType::None; std::shared_ptr buffer = nullptr; - std::shared_ptr textureVlk = nullptr; + HGSamplableTexture texture = nullptr; private: //holds record inside buffer/textureVlk. And frees it on destruction diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 1263297a7..488c18bfd 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -5,6 +5,7 @@ #include "GDescriptorSet.h" #include "../textures/GTextureVLK.h" +#include "../textures/GTextureSamplerVLK.h" GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout) : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { @@ -57,7 +58,7 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de // ------------------------------------- GDescriptorSet::SetUpdateHelper & -GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr &textureVlk) { +GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture &samplableTextureVlk) { auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { @@ -65,7 +66,10 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptr(samplableTextureVlk->getTexture()) : nullptr; + auto samplerVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getSampler()) : nullptr; + + assignBoundDescriptors(bindIndex, samplableTextureVlk, DescriptorRecord::DescriptorRecordType::Texture); auto texture = textureVlk; VkDescriptorImageInfo &imageInfo = imageInfos.emplace_back(); @@ -73,12 +77,14 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const std::shared_ptrgetIsLoaded()) { - auto blackTexture = std::dynamic_pointer_cast(m_set.m_device->getBlackTexturePixel()); - texture = blackTexture; + auto blackTextureVlk = m_set.m_device->getBlackTexturePixel(); + + texture = std::dynamic_pointer_cast(blackTextureVlk->getTexture()); + samplerVlk = std::dynamic_pointer_cast(blackTextureVlk->getSampler()); } imageInfo.imageView = texture->texture.view; - imageInfo.sampler = texture->texture.sampler; + imageInfo.sampler = samplerVlk->getSampler(); VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -212,7 +218,7 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBODynamic) { ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint]->buffer); } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::Texture) { - texture(bindPoint, m_boundDescriptors[bindPoint]->textureVlk); + texture(bindPoint, m_boundDescriptors[bindPoint]->texture); } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 3951eac54..341d4e136 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -53,18 +53,18 @@ class GDescriptorSet : public std::enable_shared_from_this { SetUpdateHelper& ssbo(int bindIndex, const std::shared_ptr &buffer); //TODO: add version of this array texture case (aka bindless) - SetUpdateHelper& texture(int bindIndex, const std::shared_ptr &textureVlk); + SetUpdateHelper& texture(int bindIndex, const HGSamplableTexture &textureVlk); template void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, DescriptorRecord::DescriptorRecordType descType) { - static_assert(std::is_base_of::value, "T should inherit from B"); +// static_assert(std::is_base_of::value, "T should inherit from B"); bool createDescRecord = !m_boundDescriptors[bindPoint]; if (!createDescRecord) { if constexpr (std::is_base_of::value) { createDescRecord = (m_boundDescriptors[bindPoint]->buffer != object); - } else if constexpr (std::is_base_of::value) { - createDescRecord = (m_boundDescriptors[bindPoint]->textureVlk != object); + } else if constexpr (std::is_base_of::value) { + createDescRecord = (m_boundDescriptors[bindPoint]->texture != object); } } if (createDescRecord) { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index e4f093874..2b7d57e99 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -69,7 +69,7 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe auto &mipmaps = *hmipmaps; /* S3TC is not supported on mobile platforms */ - bool compressedTextSupported = m_device.getIsCompressedTexturesSupported(); + bool compressedTextSupported = m_device.getIsDTXCompressedTexturesSupported(); if (!compressedTextSupported && textureFormat != TextureFormat::BGRA) { this->decompressAndUpload(textureFormat, hmipmaps); return; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp new file mode 100644 index 000000000..adae1ac42 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp @@ -0,0 +1,49 @@ +// +// Created by Deamon on 4/29/2023. +// + +#include +#include "GTextureSamplerVLK.h" +#include "../../interface/IDevice.h" + +GTextureSamplerVLK::GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex) : m_device(deviceVlk) { + + // Create a texture sampler + // In Vulkan textures are accessed by samplers + // This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings + // Note: Similar to the samplers available with OpenGL 3.3 + VkSamplerCreateInfo sampler = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + sampler.magFilter = VK_FILTER_LINEAR; + sampler.minFilter = VK_FILTER_LINEAR; + sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler.addressModeU = xWrapTex ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler.addressModeV = yWrapTex ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler.mipLodBias = 0.0f; + sampler.compareOp = VK_COMPARE_OP_NEVER; + sampler.minLod = 0.0f; + // Set max level-of-detail to mip level count of the texture + sampler.maxLod = 64.0f;//vulkanMipMapCount; + // Enable anisotropic filtering + // This feature is optional, so we must check if it's supported on the device + if (deviceVlk.getIsAnisFiltrationSupported()) { + // Use max. level of anisotropy for this example + sampler.maxAnisotropy = std::min(deviceVlk.getAnisLevel(), 16.0); + sampler.anisotropyEnable = VK_TRUE; + } else { + // The device does not support anisotropic filtering + sampler.maxAnisotropy = 1.0; + sampler.anisotropyEnable = VK_FALSE; + } + sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + ERR_GUARD_VULKAN(vkCreateSampler(m_device.getVkDevice(), &sampler, nullptr, &m_sampler)); +} + + GTextureSamplerVLK::~GTextureSamplerVLK() { + auto *l_device = &m_device; + auto &l_sampler = m_sampler; + + m_device.addDeallocationRecord([l_device, l_sampler]() -> void { + vkDestroySampler(l_device->getVkDevice(), l_sampler, nullptr); + }); +} diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h new file mode 100644 index 000000000..08bfc3575 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h @@ -0,0 +1,27 @@ +// +// Created by Deamon on 4/29/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GTEXTURESAMPLERVLK_H +#define AWEBWOWVIEWERCPP_GTEXTURESAMPLERVLK_H + + +#include "../context/vulkan_context.h" +#include "../../interface/textures/ITextureSampler.h" +#include "../IDeviceVulkan.h" + +class GTextureSamplerVLK : public ITextureSampler { +public: + GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex); + ~GTextureSamplerVLK() override; + + VkSampler getSampler() { + return m_sampler; + } +private: + VkSampler m_sampler = VK_NULL_HANDLE; + IDeviceVulkan &m_device; +}; + + +#endif //AWEBWOWVIEWERCPP_GTEXTURESAMPLERVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 3619fad6d..dd825ab56 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -76,7 +76,6 @@ void GTextureVLK::destroyBuffer() { m_device.addDeallocationRecord( [l_device, l_texture, l_imageAllocation]() { vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); - vkDestroySampler(l_device->getVkDevice(), l_texture.sampler, nullptr); if (l_imageAllocation != nullptr) { vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); } else { @@ -237,38 +236,7 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te &imageAllocation, &imageAllocationInfo); if (!m_debugName.empty()) { m_device.setObjectName((uint64_t) texture.image, VK_OBJECT_TYPE_IMAGE, m_debugName.c_str()); - - } - - // Create a texture sampler - // In Vulkan textures are accessed by samplers - // This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings - // Note: Similar to the samplers available with OpenGL 3.3 - VkSamplerCreateInfo sampler = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - sampler.magFilter = VK_FILTER_LINEAR; - sampler.minFilter = VK_FILTER_LINEAR; - sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler.addressModeU = m_wrapX ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - sampler.addressModeV = m_wrapY ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler.mipLodBias = 0.0f; - sampler.compareOp = VK_COMPARE_OP_NEVER; - sampler.minLod = 0.0f; - // Set max level-of-detail to mip level count of the texture - sampler.maxLod = (float)vulkanMipMapCount; - // Enable anisotropic filtering - // This feature is optional, so we must check if it's supported on the device - if (m_device.getIsAnisFiltrationSupported()) { - // Use max. level of anisotropy for this example - sampler.maxAnisotropy = std::min(m_device.getAnisLevel(), 16.0); - sampler.anisotropyEnable = VK_TRUE; - } else { - // The device does not support anisotropic filtering - sampler.maxAnisotropy = 1.0; - sampler.anisotropyEnable = VK_FALSE; } - sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - ERR_GUARD_VULKAN(vkCreateSampler(m_device.getVkDevice(), &sampler, nullptr, &texture.sampler)); // Create image view // Textures are not directly accessed by the shaders and diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index bd4f5d0a4..1934a90d8 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -80,7 +80,6 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this textures = {nullptr, nullptr, nullptr, nullptr}; + std::array textures = {nullptr, nullptr, nullptr, nullptr}; }; struct M2ParticleMaterialTemplate { - std::array textures = {nullptr, nullptr, nullptr}; + std::array textures = {nullptr, nullptr, nullptr}; }; struct WMOMaterialTemplate { std::shared_ptr> m_modelWide; - std::array textures = {nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr}; + std::array textures = {nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr}; }; struct ADTMaterialTemplate { - std::array textures = {nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr}; + std::array textures = {nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr}; }; struct WaterMaterialTemplate { - HGTexture texture = nullptr; + HGSamplableTexture texture = nullptr; mathfu::vec3 color; int liquidFlags; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 638f5f895..9d92218fc 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -218,15 +218,15 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp }) .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(adtMaterialTemplate.textures[0])) - .texture(6, std::dynamic_pointer_cast(adtMaterialTemplate.textures[1])) - .texture(7, std::dynamic_pointer_cast(adtMaterialTemplate.textures[2])) - .texture(8, std::dynamic_pointer_cast(adtMaterialTemplate.textures[3])) - .texture(9, std::dynamic_pointer_cast(adtMaterialTemplate.textures[4])) - .texture(10, std::dynamic_pointer_cast(adtMaterialTemplate.textures[5])) - .texture(11, std::dynamic_pointer_cast(adtMaterialTemplate.textures[6])) - .texture(12, std::dynamic_pointer_cast(adtMaterialTemplate.textures[7])) - .texture(13, std::dynamic_pointer_cast(adtMaterialTemplate.textures[8])); + .texture(5, adtMaterialTemplate.textures[0]) + .texture(6, adtMaterialTemplate.textures[1]) + .texture(7, adtMaterialTemplate.textures[2]) + .texture(8, adtMaterialTemplate.textures[3]) + .texture(9, adtMaterialTemplate.textures[4]) + .texture(10, adtMaterialTemplate.textures[5]) + .texture(11, adtMaterialTemplate.textures[6]) + .texture(12, adtMaterialTemplate.textures[7]) + .texture(13, adtMaterialTemplate.textures[8]); }) .toMaterial([&vertexFragmentData, &fragmentData](IADTMaterial *instance) -> void { instance->m_materialVSPS = vertexFragmentData; @@ -260,10 +260,10 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & }) .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(6, std::dynamic_pointer_cast(m2MaterialTemplate.textures[0])) - .texture(7, std::dynamic_pointer_cast(m2MaterialTemplate.textures[1])) - .texture(8, std::dynamic_pointer_cast(m2MaterialTemplate.textures[2])) - .texture(9, std::dynamic_pointer_cast(m2MaterialTemplate.textures[3])); + .texture(6, m2MaterialTemplate.textures[0]) + .texture(7, m2MaterialTemplate.textures[1]) + .texture(8, m2MaterialTemplate.textures[2]) + .texture(9, m2MaterialTemplate.textures[3]); }) .toMaterial([&vertexFragmentData](IM2Material *instance) -> void { instance->m_vertexFragmentData = vertexFragmentData; @@ -293,9 +293,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM }) .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[0])) - .texture(6, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[1])) - .texture(7, std::dynamic_pointer_cast(m2ParticleMatTemplate.textures[2])); + .texture(5, m2ParticleMatTemplate.textures[0]) + .texture(6, m2ParticleMatTemplate.textures[1]) + .texture(7, m2ParticleMatTemplate.textures[2]); }) .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { instance->m_fragmentData = l_fragmentData; @@ -326,15 +326,15 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const }) .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[0])) - .texture(6, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[1])) - .texture(7, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[2])) - .texture(8, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[3])) - .texture(9, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[4])) - .texture(10, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[5])) - .texture(11, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[6])) - .texture(12, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[7])) - .texture(13, std::dynamic_pointer_cast(wmoMaterialTemplate.textures[8])); + .texture(5, wmoMaterialTemplate.textures[0]) + .texture(6, wmoMaterialTemplate.textures[1]) + .texture(7, wmoMaterialTemplate.textures[2]) + .texture(8, wmoMaterialTemplate.textures[3]) + .texture(9, wmoMaterialTemplate.textures[4]) + .texture(10, wmoMaterialTemplate.textures[5]) + .texture(11, wmoMaterialTemplate.textures[6]) + .texture(12, wmoMaterialTemplate.textures[7]) + .texture(13, wmoMaterialTemplate.textures[8]); }) .toMaterial([&l_vertexData, &l_fragmentData](IWMOMaterial *instance) -> void { instance->m_materialVS = l_vertexData; @@ -360,7 +360,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co }) .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, std::dynamic_pointer_cast(waterMaterialTemplate.texture)); + .texture(5, waterMaterialTemplate.texture); }) .toMaterial([&l_fragmentData](IWaterMaterial *instance) -> void { instance->m_materialPS = l_fragmentData; @@ -479,9 +479,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha createFrameBuffers(); { - std::vector> inputColorTextures; + std::vector> inputColorTextures; for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(std::dynamic_pointer_cast(m_colorFrameBuffers[i]->getAttachment(0))); + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); } glowPass->updateDimensions(m_width, m_height, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index e052cfc49..8b9f7db68 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -27,7 +27,7 @@ FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &ubo } void FFXGlowPassVLK::updateDimensions(int width, int height, - const std::vector> &inputColorTextures, + const std::vector &inputColorTextures, const std::shared_ptr &finalRenderPass) { createFrameBuffers(width, height); @@ -41,11 +41,11 @@ void FFXGlowPassVLK::updateDimensions(int width, int height, glowPipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { - std::array, 4> inputTextures; + std::array inputTextures; //Fill input textures array inputTextures[0] = inputColorTextures[i]; for (int j = 0; j < GAUSS_PASS_COUNT; j++) - inputTextures[j + 1] = std::dynamic_pointer_cast(getTargetFrameBuffer(j, i)->getAttachment(0)); + inputTextures[j + 1] = getTargetFrameBuffer(j, i)->getAttachment(0); // Create materials @@ -62,7 +62,7 @@ void FFXGlowPassVLK::updateDimensions(int width, int height, ffxGlowMat[i] = createFFXGlowMat(m_ffxGlowVs, m_ffxGlowPS, inputColorTextures[i], - std::dynamic_pointer_cast(getTargetFrameBuffer(GAUSS_PASS_COUNT-1, i)->getAttachment(0)), + getTargetFrameBuffer(GAUSS_PASS_COUNT-1, i)->getAttachment(0), glowPipelineTemplate, finalRenderPass ); @@ -191,7 +191,7 @@ std::shared_ptr FFXGlowPassVLK::createFFXGaussMat( const std::shared_ptr> &ffxGaussVs, const std::shared_ptr> &ffxGaussPS, - const std::shared_ptr &texture, + const HGSamplableTexture &texture, const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { @@ -215,8 +215,8 @@ std::shared_ptr FFXGlowPassVLK::createFFXGlowMat( const std::shared_ptr> &ffxGlowVs, const std::shared_ptr> &ffxGlowPS, - const std::shared_ptr &screenTex, - const std::shared_ptr &blurTex, + const HGSamplableTexture &screenTex, + const HGSamplableTexture &blurTex, const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h index fdc6331fc..c56c236df 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h @@ -17,7 +17,7 @@ class FFXGlowPassVLK { FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); void assignFFXGlowUBOConsts(float glow); void updateDimensions(int width, int height, - const std::vector> &inputColorTextures, + const std::vector &inputColorTextures, const std::shared_ptr &finalRenderPass); void doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, @@ -43,14 +43,14 @@ class FFXGlowPassVLK { std::shared_ptr createFFXGaussMat(const std::shared_ptr> &ffxGlowVs, const std::shared_ptr> &ffxGlowPS, - const std::shared_ptr &texture, + const HGSamplableTexture &texture, const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass); std::shared_ptr createFFXGlowMat(const std::shared_ptr> &ffxGlowVs, const std::shared_ptr> &ffxGlowPS, - const std::shared_ptr &screenTex, - const std::shared_ptr &blurTex, + const HGSamplableTexture &screenTex, + const HGSamplableTexture &blurTex, const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass); From 4e9b1cc005fc21e2cfeb213b2d5bfd9dee7fb183 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 20 May 2023 15:26:32 +0300 Subject: [PATCH 070/212] restore dynamic meshes for m2, labels for command buffer, restore m2 waterFall meshes --- src/ui/FrontendUI.cpp | 10 + .../OffsetAllocator/offsetAllocator.cpp | 2 + wowViewerLib/CMakeLists.txt | 6 +- .../shaders/glsl/common/commonFunctions.glsl | 1 - .../glsl/common/commonLightFunctions.glsl | 12 +- .../glsl/forwardRendering/m2Shader.frag | 30 +- .../glsl/forwardRendering/m2Shader.vert | 24 +- .../forwardRendering/waterfallShader.frag | 17 +- .../forwardRendering/waterfallShader.vert | 23 +- .../src/engine/camera/firstPersonCamera.cpp | 7 +- .../engine/camera/firstPersonOrthoCamera.cpp | 7 +- .../camera/firstPersonOrthoStaticCamera.cpp | 7 +- .../firstPersonOrthoStaticTopDownCamera.cpp | 7 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 42 +- wowViewerLib/src/engine/geometry/m2Geom.h | 9 +- .../src/engine/objects/adt/adtObject.cpp | 63 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 14 +- .../m2/m2Helpers/M2MeshBufferUpdater.h | 4 +- .../src/engine/objects/m2/m2Object.cpp | 218 ++-- wowViewerLib/src/engine/objects/m2/m2Object.h | 25 +- .../src/engine/objects/scenes/map.cpp | 3 - .../src/engine/persistance/adtFile.cpp | 5 +- .../engine/persistance/header/M2FileHeader.h | 10 +- .../persistance/helper/ChunkFileReader.h | 4 + .../src/engine/shader/ShaderDefinitions.h | 1005 +++++++++-------- .../src/gapi/UniformBufferStructures.h | 8 +- wowViewerLib/src/gapi/interface/sortLambda.h | 61 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 21 + .../src/gapi/vulkan/TextureManagerVLK.cpp | 2 - .../src/gapi/vulkan/TextureManagerVLK.h | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 12 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 9 +- .../gapi/vulkan/commandBuffer/CommandBuffer.h | 3 +- .../CommandBufferDebugLabel.cpp | 31 + .../CommandBufferDebugLabel.h | 23 + .../CommandBufferRecorder.cpp | 8 + .../CommandBufferRecorder.h | 6 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 3 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 5 + .../mapScene/materials/IMaterialStructs.h | 21 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 61 +- .../vulkan/MapSceneRenderForwardVLK.h | 4 + 42 files changed, 1029 insertions(+), 806 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 08c4fd446..47d1d5465 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -715,6 +715,16 @@ void FrontendUI::showQuickLinksDialog() { std::vector replacementTextureFDids = {}; ImGui::Begin("Quick Links", &showQuickLinks); + if (ImGui::Button("model without skin", ImVec2(-1, 0))) { + replacementTextureFDids = std::vector(17); + openM2SceneByfdid(5099010, replacementTextureFDids); + } + if (ImGui::Button("Some model", ImVec2(-1, 0))) { + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 4952373; + replacementTextureFDids[12] = 4952379; + openM2SceneByfdid(4870631, replacementTextureFDids); + } if (ImGui::Button("nightborne model", ImVec2(-1, 0))) { openM2SceneByfdid(1810676, replacementTextureFDids); } diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp index 396df5b1f..fab5f940b 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -287,6 +287,8 @@ namespace OffsetAllocator void Allocator::free(Allocation allocation) { + if (allocation.metadata == Allocation::NO_SPACE) return; + ASSERT(allocation.metadata != Allocation::NO_SPACE); if (m_nodes.empty()) return; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index f766d9cbe..0e699eec7 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -525,7 +525,11 @@ if (LINK_VULKAN) src/gapi/vulkan/bindable/DSBindable.h src/renderer/mapScene/vulkan/materials/IMaterialInstance.h src/gapi/vulkan/meshes/GSortableMeshVLK.cpp - src/gapi/vulkan/meshes/GSortableMeshVLK.h src/gapi/vulkan/textures/GTextureSamplerVLK.cpp src/gapi/vulkan/textures/GTextureSamplerVLK.h) + src/gapi/vulkan/meshes/GSortableMeshVLK.h + src/gapi/vulkan/textures/GTextureSamplerVLK.cpp + src/gapi/vulkan/textures/GTextureSamplerVLK.h + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl index edb7a119b..4d3231e0c 100644 --- a/wowViewerLib/shaders/glsl/common/commonFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFunctions.glsl @@ -2,7 +2,6 @@ #define COMMON_FUNCTION_GLSL vec2 posToTexCoord(const vec3 vertexPosInView, const vec3 normal){ - //Blizz seems to have vertex in view space as vector from "vertex to eye", while in this implementation, it's //vector from "eye to vertex". So the minus here is not needed //vec3 viewVecNormalized = -normalize(cameraPoint.xyz); diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 2870ba3bb..86484c4c6 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -59,7 +59,7 @@ vec3 calcLight( if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { float nDotL = clamp(dot(normalizedN, -(sceneParams.extLight.uExteriorDirectColorDir.xyz)), 0.0, 1.0); - float nDotUp = dot(normalizedN, sceneParams.uViewUp.xyz); + float nDotUp = dot(normalizedN, normalize(sceneParams.uViewUp.xyz)); vec3 adjAmbient = (sceneParams.extLight.uExteriorAmbientColor.rgb + precomputedLight); vec3 adjHorizAmbient = (sceneParams.extLight.uExteriorHorizontAmbientColor.rgb + precomputedLight); @@ -98,14 +98,14 @@ vec3 calcLight( vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse); vec3 linearDiffTerm = (matDiffuse * matDiffuse) * localDiffuse; - //Specular term - vec3 specTerm = specular; - //Emission term +// //Specular term +// vec3 specTerm = specular; +// //Emission term const vec3 emTerm = emissive; - result = sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) + specTerm + emTerm; + result = sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) + emTerm; } - return result; + return result + specular; } vec3 calcSpec(const in float texAlpha) { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index d47fba723..b9a251f10 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -91,7 +91,6 @@ void main() { vMeshColorAlpha.a *= textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightIndexes.x / 4][textureWeightIndexes.x % 4]; - vMeshColorAlpha *= vPosition_EdgeFade.w; //Accumulate and apply lighting @@ -130,6 +129,23 @@ void main() { //---------------------- // Calc Diffuse and Specular //--------------------- + int uVertexShader = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; + + mat4 textMat[2]; + int textMatIndex1 = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; + int textMatIndex2 = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; + + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + float edgeFade = 1.0; + + calcM2VertexMat(uVertexShader, + vPosition_EdgeFade.xyz, vNormal, + vTexCoord, vTexCoord2, + textMat, edgeFade, + texCoord, texCoord2, texCoord3); + + vMeshColorAlpha *= edgeFade; float finalOpacity = 0.0; vec3 matDiffuse; @@ -156,6 +172,8 @@ void main() { // Apply lighting // ------------------------------ +// specular *= vMeshColorAlpha.rgb; + finalColor = vec4( calcLight( matDiffuse, @@ -172,8 +190,6 @@ void main() { finalOpacity ); - outputColor = finalColor; - // ------------------------------ // Apply Fog // ------------------------------ @@ -193,12 +209,4 @@ void main() { //Forward rendering without lights outputColor = finalColor; - - //Deferred rendering - //gl_FragColor = finalColor; -// gl_FragData[0] = vec4(vec3(fs_Depth), 1.0); -// gl_FragData[1] = vec4(vPosition.xyz,0); -// gl_FragData[2] = vec4(vNormal.xyz,0); -// gl_FragData[3] = finalColor; - } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 3f1f19581..f60ddf435 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -3,7 +3,7 @@ #extension GL_GOOGLE_include_directive: require #ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 +#define MAX_MATRIX_NUM 256 #endif precision highp float; @@ -87,27 +87,13 @@ void main() { vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; - int uVertexShader = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; - - mat4 textMat[2]; - int textMatIndex1 = vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; - int textMatIndex2 =vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; - - textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; - textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; - - float edgeFade = 1.0; - - calcM2VertexMat(uVertexShader, - vertexPosInView.xyz, normal, - aTexCoord, aTexCoord2, - textMat, edgeFade, - vTexCoord, vTexCoord2, vTexCoord3); - + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = aTexCoord2; gl_Position = scene.uPMatrix * vertexPosInView; vNormal = normal; - vPosition_EdgeFade = vec4(vertexPosInView.xyz, edgeFade); + vPosition_EdgeFade = vec4(vertexPosInView.xyz, 0.0); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index ef30eeb62..34d1443af 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -19,10 +19,10 @@ layout(location=2) in vec2 vTexCoord2_animated; layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; -layout(set=1,binding=5) uniform sampler2D uMask; -layout(set=1,binding=6) uniform sampler2D uWhiteWater; -layout(set=1,binding=7) uniform sampler2D uNoise; -layout(set=1,binding=9) uniform sampler2D uNormalTex; +layout(set=1,binding=6) uniform sampler2D uMask; +layout(set=1,binding=7) uniform sampler2D uWhiteWater; +layout(set=1,binding=8) uniform sampler2D uNoise; +layout(set=1,binding=10) uniform sampler2D uNormalTex; layout(location=0) out vec4 outputColor; @@ -31,12 +31,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=1) uniform modelWideBlockVS { - mat4 uPlacementMat; - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; -}; - -layout(std140, set=0, binding=4) uniform meshWideBlockPS { +layout(std140, set=0, binding=5) uniform meshWideBlockPS { vec4 values0; vec4 values1; vec4 values2; @@ -111,8 +106,6 @@ void main() { vec3(0.0) /* emissive */ ); - - float w_clamped = clamp((1.0f - mask_val_0.w) * values1.w, 0.0f, 1.0f); float w_alpha_combined = clamp(w_clamped + mix_alpha, 0.0f, 1.0f); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index 3197eb7ff..bcf0f1729 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -32,13 +32,19 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { // Whole model layout(std140, set=0, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; +}; + +layout(std140, set=0, binding=2) uniform boneMats { mat4 uBoneMatrixes[MAX_MATRIX_NUM]; }; +layout(std140, set=0, binding=3) uniform textureMatrices { + mat4 textureMatrix[64]; +}; + //Individual meshes -layout(std140, set=0, binding=2) uniform meshWideBlockVS { - vec4 bumpScale; - mat4 uTextMat[2]; +layout(std140, set=0, binding=4) uniform meshWideBlockVS { + vec4 bumpScaleTextIndexes; }; //Shader output @@ -49,11 +55,18 @@ layout(location=3) out vec3 vNormal; layout(location=4) out vec3 vPosition; -layout(set=1,binding=8) uniform sampler2D uBumpTexture; +layout(set=1,binding=9) uniform sampler2D uBumpTexture; void main() { + float bumpScale = bumpScaleTextIndexes.x; + int textMatIndex1 = floatBitsToInt(bumpScaleTextIndexes.y); + int textMatIndex2 = floatBitsToInt(bumpScaleTextIndexes.z); + + mat4 textMat[2]; + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; - vec2 texCoord2 = (uTextMat[0] * vec4(aTexCoord2, 0, 1)).xy; + vec2 texCoord2 = (textMat[0] * vec4(aTexCoord2, 0, 1)).xy; vec4 bumpValue = texture(uBumpTexture, texCoord2); vec3 pos = (aNormal * bumpScale.x) * bumpValue.z + aPosition; diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 2dfc2fa08..f7c6498cd 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -142,15 +142,16 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { //std::cout<<"camera " << camera[0] <<" "<interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); - this->upVector = (lookAtRotation * upVector.xyz()); + this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); updatedAtLeastOnce = true; } void FirstPersonCamera :: setCameraPos (float x, float y, float z) { diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp index cb9e6dd8e..21b73087d 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp @@ -114,15 +114,16 @@ void FirstPersonOrthoCamera::tick (animTime_t timeDelta) { lookAtMat *= mathfu::mat4::FromTranslationVector(-camera) ; + mathfu::mat4 invTranspViewMat = lookAtMat.Transpose().Inverse(); + mathfu::vec4 interiorSunDir = mathfu::vec4(-0.30822f, -0.30822f, -0.89999998f, 0); - interiorSunDir = lookAtMat.Transpose().Inverse() * interiorSunDir; + interiorSunDir = invTranspViewMat * interiorSunDir; interiorSunDir = mathfu::vec4(interiorSunDir.xyz() * (1.0f / interiorSunDir.xyz().Length()), 0.0f); this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); - this->upVector = (lookAtRotation * upVector.xyz()); + this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); } void FirstPersonOrthoCamera :: setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp index ae288a7d3..9624ebf55 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp @@ -29,16 +29,17 @@ void FirstPersonOrthoStaticCamera::tick (animTime_t timeDelta) { camera.xyz(), mathfu::vec3(0,0,1), 1.0); + mathfu::mat4 invTranspViewMat = lookAtMat.Transpose().Inverse(); mathfu::vec4 interiorSunDir = mathfu::vec4(-0.30822f, -0.30822f, -0.89999998f, 0); - interiorSunDir = lookAtMat.Transpose().Inverse() * interiorSunDir; + interiorSunDir = invTranspViewMat * interiorSunDir; interiorSunDir = mathfu::vec4(interiorSunDir.xyz() * (1.0f / interiorSunDir.xyz().Length()), 0.0f); this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); - this->upVector = (lookAtRotation * upVector.xyz()); + + this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); } void FirstPersonOrthoStaticCamera::setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp index c251e2db9..8ccb5d933 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp @@ -32,15 +32,16 @@ void FirstPersonOrthoStaticTopDownCamera::tick (animTime_t timeDelta) { 0,0,0,1 ) * mathfu::mat4::FromTranslationVector(-this->camera.xyz()); + mathfu::mat4 invTranspViewMat = lookAtMat.Transpose().Inverse(); + mathfu::vec4 interiorSunDir = mathfu::vec4(-0.30822f, -0.30822f, -0.89999998f, 0); - interiorSunDir = lookAtMat.Transpose().Inverse() * interiorSunDir; + interiorSunDir = invTranspViewMat * interiorSunDir; interiorSunDir = mathfu::vec4(interiorSunDir.xyz() * (1.0f / interiorSunDir.xyz().Length()), 0.0f); this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); - this->upVector = (lookAtRotation * upVector.xyz()); + this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); } void FirstPersonOrthoStaticTopDownCamera::setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index e9d57258a..e4c3b529e 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -196,7 +196,18 @@ chunkDef M2Geom::m2FileTable = { } } }, - + { + 'FGDE', + { + [](M2Geom &file, ChunkData &chunkData) { + debuglog("Entered EDGF"); + int arrayLen = chunkData.chunkLen / sizeof(EDGF); + file.edgf_count = arrayLen; + chunkData.readValues(file.edgf, arrayLen); + debuglog("Leaving EDGF"); + } + } + }, } }; @@ -327,8 +338,9 @@ HGVertexBuffer M2Geom::getVBO(const HMapSceneBufferCreate &sceneRenderer) { return vertexVbo; } -std::array M2Geom::createDynamicVao( - IDevice &device, std::array &dynVBOs, +std::array +M2Geom::createDynamicVao(const HMapSceneBufferCreate &sceneRenderer, + std::array &dynVBOs, SkinGeom *skinGeom, M2SkinSection *skinSection) { //1. Create index buffer std::vector indicies(skinSection->indexCount); @@ -354,39 +366,25 @@ std::array M2Geom::createDynamicVao( // << " vertexCount = " << skinSection->vertexCount // << std::endl; -//TODO: -/* - auto indexIbo = device.createIndexBuffer(); + auto indexIbo = sceneRenderer->createM2IndexBuffer(indicies.size() * sizeof(uint16_t)); indexIbo->uploadData( &indicies[0], indicies.size() * sizeof(uint16_t)); - std::array result; - for (int i = 0 ; i < 4; i ++) { + std::array result; + for (int i = 0 ; i < IDevice::MAX_FRAMES_IN_FLIGHT; i ++) { //2.1. Create vertex buffer - auto vertexVboDyn = device.createVertexBufferDynamic(skinSection->vertexCount * sizeof(M2Vertex)); + auto vertexVboDyn = sceneRenderer->createM2VertexBuffer(skinSection->vertexCount * sizeof(M2Vertex)); dynVBOs[i] = vertexVboDyn; //2.2 Create VAO - HGVertexBufferBindings bufferBindings = device.createVertexBufferBindings(); - bufferBindings->setIndexBuffer(indexIbo); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = vertexVboDyn; - vertexBinding.bindings = std::vector(&staticM2Bindings[0], &staticM2Bindings[6]); - - bufferBindings->addVertexBufferBinding(vertexBinding); - bufferBindings->save(); - + HGVertexBufferBindings bufferBindings = sceneRenderer->createM2VAO(vertexVboDyn, indexIbo); result[i] = bufferBindings; } return result; - */ - - return {nullptr, nullptr, nullptr, nullptr}; } HGVertexBufferBindings M2Geom::getVAO(const HMapSceneBufferCreate &sceneRenderer, SkinGeom *skinGeom) { diff --git a/wowViewerLib/src/engine/geometry/m2Geom.h b/wowViewerLib/src/engine/geometry/m2Geom.h index 733b80e67..18824cce5 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.h +++ b/wowViewerLib/src/engine/geometry/m2Geom.h @@ -37,8 +37,10 @@ class M2Geom : public PersistentFile { void process(HFileContent m2File, const std::string &fileName) override; HGVertexBuffer getVBO(const HMapSceneBufferCreate &sceneRenderer); HGVertexBufferBindings getVAO(const HMapSceneBufferCreate &sceneRenderer, SkinGeom *skinGeom); - std::array createDynamicVao(IDevice &device, std::array &dynVBOs, - SkinGeom *skinGeom, M2SkinSection *skinSection); + std::array + createDynamicVao(const HMapSceneBufferCreate &sceneRenderer, + std::array &dynVBOs, + SkinGeom *skinGeom, M2SkinSection *skinSection); void loadLowPriority(const HApiContainer& m_api, uint32_t animationId, uint32_t subAnimationId); M2Data * getM2Data(){ if (fsStatus == FileStatus::FSLoaded) {return m_m2Data;} else {return nullptr;}}; @@ -54,6 +56,9 @@ class M2Geom : public PersistentFile { PGD1_chunk * particleGeosetData = nullptr; + EDGF * edgf = nullptr; + int edgf_count = 0; + EXP2 *exp2 = nullptr; std::vector txacMesh = {}; std::vector txacMParticle = {}; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index b540f6f0f..6191e72c8 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -166,6 +166,15 @@ struct uv_map_entry { int16_t t; }; +uint8_t * getLiquidExistsTable(const PointerChecker &mH2OBlob, const SMLiquidInstance &liquidInstance) { + const static uint64_t fullBitmask = 0xFFFFFFFFFFFFFFFF; + + if (liquidInstance.offset_exists_bitmap) { + return (uint8_t *) &mH2OBlob[liquidInstance.offset_exists_bitmap]; + } + + return (uint8_t *) &fullBitmask; +} inline mathfu::vec2 getLiquidVertexCoords(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { int16_t s = 0; int16_t t = 0; @@ -185,7 +194,7 @@ inline mathfu::vec2 getLiquidVertexCoords(int liquidVertexFormat, float *vertexD } //For all other liquidVertexFormat are default zeroes - return mathfu::vec2(s * 3.0 / 256.0, t * 3.0 / 256.0); + return mathfu::vec2(s * 3.0f / 256.0f, t * 3.0f / 256.0f); } inline uint8_t getLiquidDepth(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { @@ -255,13 +264,6 @@ inline LiquidObjectSettings getLiquidSettings(int liquidObjectId, int liquidType HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { - uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water - if (liquidInstance.offset_exists_bitmap > 0 && liquidInstance.height > 0) - { - size_t bitmask_size = static_cast(std::ceil(liquidInstance.height * liquidInstance.width / 8.0f)); - std::memcpy(&infoMask, &m_adtFile->mH2OBlob[liquidInstance.offset_exists_bitmap - m_adtFile->mH2OblobOffset], bitmask_size); - } - //Get Data from DB int basetextureFDID = 0; mathfu::vec3 color = mathfu::vec3(0,0,0); @@ -332,7 +334,7 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat // float *vertexDataPtr = nullptr; if (liquidInstance.offset_vertex_data != 0) { - vertexDataPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data - m_adtFile->mH2OblobOffset])); + vertexDataPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data])); } //Set iteration restrictions for triangles @@ -353,7 +355,6 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat // int baseVertexIndForInst = vertexBuffer.size(); int baseVertexIndForInst = 0; - int bitOffset = 0; int i = this->m_adtFile->mcnkMap[x_chunk][y_chunk]; auto &waterAaBB = waterTileAabb[i]; SMChunk *mcnkChunk = &m_adtFile->mapTile[i]; @@ -384,6 +385,11 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat if (vertexDataPtr!= nullptr) { pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } + +// if (std::isnan(pos.z) || (pos.z > 10000.0f)) { +// pos.z = liquidInstance.min_height_level; +// } + if (generateTexCoordsFromPos) { uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); } else { @@ -406,23 +412,30 @@ HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreat C3Vector(mathfu::vec3(maxX, maxY, maxZ)) ); + uint8_t *existsTable = getLiquidExistsTable(m_adtFile->mH2OBlob, liquidInstance); + for (int y = y_begin; y < y_end; y++) { for (int x = x_begin; x < x_end; x++) { - if (((infoMask >> (bitOffset++)) & 1) == 0) continue; - int16_t vertindexes[4] = { - (int16_t) (baseVertexIndForInst + y * (liquidInstance.width +1 ) + x), - (int16_t) (baseVertexIndForInst + y * (liquidInstance.width + 1) + x + 1), - (int16_t) (baseVertexIndForInst + (y + 1) * (liquidInstance.width + 1) + x), - (int16_t) (baseVertexIndForInst + (y + 1) * (liquidInstance.width + 1) + x + 1), + + int maskIndex = (y - y_begin) * (x_end - x_begin) + (x - x_begin); + bool exists = (existsTable[maskIndex >> 3] >> ((maskIndex & 7))) & 1; + + if (!exists) continue; + + const int16_t vertIndexes[4] = { + (int16_t) (y * (liquidInstance.width + 1 ) + x), + (int16_t) (y * (liquidInstance.width + 1) + x + 1), + (int16_t) ((y + 1) * (liquidInstance.width + 1) + x), + (int16_t) ((y + 1) * (liquidInstance.width + 1) + x + 1), }; - indexBuffer.push_back (vertindexes[0]); - indexBuffer.push_back (vertindexes[1]); - indexBuffer.push_back (vertindexes[2]); + indexBuffer.push_back (vertIndexes[0]); + indexBuffer.push_back (vertIndexes[1]); + indexBuffer.push_back (vertIndexes[2]); - indexBuffer.push_back (vertindexes[1]); - indexBuffer.push_back (vertindexes[3]); - indexBuffer.push_back (vertindexes[2]); + indexBuffer.push_back (vertIndexes[1]); + indexBuffer.push_back (vertIndexes[3]); + indexBuffer.push_back (vertIndexes[2]); } } @@ -515,11 +528,13 @@ void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { for (int y_chunk = 0; y_chunk < 16; y_chunk++) { for (int x_chunk = 0; x_chunk < 16; x_chunk++) { - auto &liquidChunk = m_adtFile->mH2OHeader->chunks[y_chunk*16 + x_chunk]; + M2HOHeader::SMLiquidChunk &liquidChunk = m_adtFile->mH2OHeader->chunks[y_chunk*16 + x_chunk]; if (liquidChunk.layer_count == 0) continue; + auto liquidInstOffset = liquidChunk.offset_instances; + auto *liquidInstPtr = - ((SMLiquidInstance *)(&m_adtFile->mH2OBlob[liquidChunk.offset_instances - m_adtFile->mH2OblobOffset])); + ((SMLiquidInstance *)(&m_adtFile->mH2OBlob[liquidInstOffset])); mathfu::vec3 liquidBasePos = adtBasePos - diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 87ef04159..18d862a73 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -21,14 +21,12 @@ float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int b return finalTransparency; } -void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr &m2Material, int batchIndex, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile){ +void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr &m2Material, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile){ + int batchIndex = m2Material->batchIndex; auto batch = m2SkinProfile->batches[batchIndex]; int renderFlagIndex = batch->materialIndex; auto renderFlag = m2Data->materials[renderFlagIndex]; - mathfu::vec4 meshColor = getCombinedColor(m2SkinProfile, batchIndex, m2Object->subMeshColors); - float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*m2Object, batchIndex, m2SkinProfile); - std::array textureMatrixIndexes = {-1, -1}; getTextureMatrixIndexes(*m2Object, batchIndex, m2Data, m2SkinProfile, textureMatrixIndexes); @@ -55,14 +53,6 @@ void M2MeshBufferUpdater::updateMaterialData(const std::shared_ptr meshblockVSPS.IsAffectedByLight = ((renderFlag->flags & 0x1) > 0) ? 0 : 1; m2Material->m_vertexFragmentData->save(); - - //3. Update individual PS buffer - float uAlphaTest; - if (m2Material->blendMode == EGxBlendEnum::GxBlend_AlphaKey) { - uAlphaTest = 128.0f/255.0f * finalTransparency; //Maybe move this to shader logic? - } else { - uAlphaTest = 1.0f/255.0f; - } } void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, int batchIndex, diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index 013235c3a..8c61070b9 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -17,13 +17,13 @@ class M2MeshBufferUpdater { public: static float calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile); - static void updateMaterialData(const std::shared_ptr &m2Material, int batchIndex, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile); + static void updateMaterialData(const std::shared_ptr &m2Material, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile); static void fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS); static mathfu::mat4 getTextureMatrix(const M2Object &m2Object, int textureMatIndex, M2Data *m2Data); - static inline void getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, + static void getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, const M2SkinProfile *m2SkinProfile, std::array &o_textureMatIndexes); static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index feb78f2d5..047955e2a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -784,13 +784,15 @@ void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) { if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { for (int i = 0; i < this->m_meshArray.size(); i++) { //Update info for sorting - M2MeshBufferUpdater::updateSortData(this->m_meshArray[i], *this, i, m2File, + M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshArray[i]), *this, + std::get<1>(this->m_meshArray[i]), m2File, skinData, modelViewMat); } for (int i = 0; i < this->m_meshForcedTranspArray.size(); i++) { //Update info for sorting - if (this->m_meshForcedTranspArray[i] != nullptr) { - M2MeshBufferUpdater::updateSortData(this->m_meshForcedTranspArray[i], *this, i, m2File, + if (std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { + M2MeshBufferUpdater::updateSortData(std::get<0>(this->m_meshForcedTranspArray[i]), *this, + std::get<1>(this->m_meshForcedTranspArray[i]), m2File, skinData, modelViewMat); } } @@ -985,7 +987,8 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v particleEmitters[i]->Update(deltaTime * 0.001 , transformMat, viewMatInv.TranslationVector3D(), nullptr, viewMat); } - this->sortMaterials(modelViewMat); + + this->sortMaterials(modelViewMat); //Ribbon Emitters mathfu::vec3 nullPos(0,0,0); @@ -1078,12 +1081,12 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_modelFragmentData->save(); } -// for (auto [material, batchIndex] : m_materialArray) { -// M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); -// } + for (auto material: m_materialArray) { + M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); + } //Manually update vertices for dynamics -// updateDynamicMeshes(); + updateDynamicMeshes(); int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); @@ -1261,6 +1264,8 @@ bool M2Object::prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIn materialTemplate.textures[j] = getTexture(m2TextureIndex); } + materialTemplate.batchIndex = batchIndex; + return true; } @@ -1354,11 +1359,7 @@ float wfv_convert(float value, int16_t random) { return (float)((float)(int)(random % invertedVal) / (float)invertedVal) * multiplier; } -HGM2Mesh M2Object::createWaterfallMesh() { - return nullptr; - - HGShaderPermutation shaderPermutation = m_api->hDevice->getShader("waterfallShader", "waterfallShader", nullptr); - +HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRenderer, const HGVertexBufferBindings &finalBufferBindings) { gMeshTemplate meshTemplate(bufferBindings); auto skinData = m_skinGeom->getSkinData(); @@ -1378,32 +1379,33 @@ HGM2Mesh M2Object::createWaterfallMesh() { pipelineTemplate.triCCW = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16)) * 2; meshTemplate.end = skinSection->indexCount; -/* - HGTexture texture[4] = {nullptr,nullptr,nullptr,nullptr}; - meshTemplate.texture.resize(5); - meshTemplate.texture[0] = getTexture(0); //mask - meshTemplate.texture[1] = getTexture(1); //whiteWater - meshTemplate.texture[2] = getTexture(2); //noise - meshTemplate.texture[3] = getTexture(3); //bumpTexture - meshTemplate.texture[4] = getTexture(4); //normalTex - */ + M2WaterfallMaterialTemplate m2WaterfallMaterialTemplate; - std::shared_ptr> waterFallMeshWideBlockVS = nullptr; - waterFallMeshWideBlockVS->setUpdateHandler([this, skinData, m2Data, wfv3Data](auto &data, const HFrameDependantData &frameDepedantData){ - auto &meshblockVS = data; - meshblockVS.bumpScale = mathfu::vec4(wfv3Data->bumpScale, 0, 0, 0); + m2WaterfallMaterialTemplate.textures[0] = getTexture(0); //mask + m2WaterfallMaterialTemplate.textures[1] = getTexture(1); //whiteWater + m2WaterfallMaterialTemplate.textures[2] = getTexture(2); //noise + m2WaterfallMaterialTemplate.textures[3] = getTexture(3); //bumpTexture + m2WaterfallMaterialTemplate.textures[4] = getTexture(4); //normalTex - M2MeshBufferUpdater::fillTextureMatrices(*this, 0, m2Data, skinData, meshblockVS.uTextMat); - }); + auto waterfallMaterial = sceneRenderer->createM2WaterfallMaterial(m_modelWideDataBuff, pipelineTemplate, m2WaterfallMaterialTemplate); + + { + auto &meshblockVS = waterfallMaterial->m_vertexData->getObject(); + meshblockVS.bumpScale = wfv3Data->bumpScale; + std::array textureMatrixIndexes = {-1, -1}; + M2MeshBufferUpdater::getTextureMatrixIndexes(*this, 0, m2Data, skinData, textureMatrixIndexes); + meshblockVS.textureMatIndex1 = textureMatrixIndexes[0]; + meshblockVS.textureMatIndex2 = textureMatrixIndexes[1]; - std::shared_ptr> waterFallMeshWideBlockPS = nullptr; - waterFallMeshWideBlockPS->setUpdateHandler([this, skinData, m2Data, wfv3Data](auto &data, const HFrameDependantData &frameDepedantData){ - auto &meshblockPS = data; + waterfallMaterial->m_vertexData->save(); + } + + { + auto &meshblockPS = waterfallMaterial->m_fragmentData->getObject(); meshblockPS.baseColor = mathfu::vec4( wfv3Data->basecolor.a / 255.0f, wfv3Data->basecolor.r / 255.0f, @@ -1432,13 +1434,15 @@ HGM2Mesh M2Object::createWaterfallMesh() { meshblockPS.values1.z = wfv_convert(meshblockPS.values1.y, (int16_t)((uint64_t)this)); meshblockPS.m_values2.z = wfv_convert(meshblockPS.m_values2.w, (int16_t)((uint64_t)this)); meshblockPS.m_values3.z = wfv_convert(wfv3Data->values3_z, (int16_t)((uint64_t)this)); - }); + + waterfallMaterial->m_fragmentData->save(); + } //Make mesh //TODO: - auto hmesh = m_api->hDevice->createMesh(meshTemplate); + auto hmesh = sceneRenderer->createM2WaterfallMesh(meshTemplate, waterfallMaterial, m2Batch->materialLayer, m2Batch->priorityPlane); - return nullptr; + return hmesh; } @@ -1460,7 +1464,19 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { std::vector batchesRequiringDynamicVao = {}; const auto &batches = m_skinGeom->getSkinData()->batches; + m_materialArray.resize(std::max(batches.size, 0)); + m_forcedTranspMaterialArray.resize(std::max(batches.size, 0)); + if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { + //Create materials + for (int batchIndex = 0; batchIndex < batches.size; batchIndex++) { + auto m2Batch = batches[batchIndex]; + EGxBlendEnum mainBlendMode; + const EGxBlendEnum forcedTranspBlend = EGxBlendEnum::GxBlend_Alpha; + + this->m_materialArray[batchIndex] = createM2Material(sceneRenderer, batchIndex, mainBlendMode, false); + this->m_forcedTranspMaterialArray[batchIndex] = createM2Material(sceneRenderer, batchIndex, forcedTranspBlend, true); + } for (int batchIndex = 0; batchIndex < batches.size; batchIndex++) { auto m2Batch = batches[batchIndex]; auto skinSection = skinProfile->skinSections[m2Batch->skinSectionIndex]; @@ -1469,88 +1485,93 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { continue; } - EGxBlendEnum mainBlendMode; - HGM2Mesh hmesh = createSingleMesh(sceneRenderer, m_m2Data, batchIndex, 0, bufferBindings, m2Batch, skinSection, mainBlendMode, false); + HGM2Mesh hMesh = createSingleMesh(sceneRenderer, 0, bufferBindings, m_materialArray[batchIndex], skinSection, m2Batch); - if (hmesh == nullptr) + if (hMesh == nullptr) continue; - this->m_meshArray.emplace_back(hmesh); + this->m_meshArray.emplace_back(hMesh, batchIndex); - if (mainBlendMode == EGxBlendEnum::GxBlend_Opaque) { + if (getBlendMode(batchIndex) == EGxBlendEnum::GxBlend_Opaque) { EGxBlendEnum blendMode = EGxBlendEnum::GxBlend_Alpha; - HGM2Mesh hmeshTrans = createSingleMesh(sceneRenderer, m_m2Data, batchIndex, 0, bufferBindings, m2Batch, skinSection, blendMode, true); + HGM2Mesh hMeshTrans = createSingleMesh(sceneRenderer, 0, bufferBindings, m_forcedTranspMaterialArray[batchIndex], skinSection, m2Batch); - this->m_meshForcedTranspArray.emplace_back(hmeshTrans); + this->m_meshForcedTranspArray.emplace_back(hMeshTrans, batchIndex); } else { - m_meshForcedTranspArray.emplace_back(nullptr); + m_meshForcedTranspArray.emplace_back(nullptr, batchIndex); } } // Create meshes requiring dynamic - //TODO: - /* + for (int j = 0; j < batchesRequiringDynamicVao.size(); j++) { - int i = batchesRequiringDynamicVao[j]; - auto m2Batch = skinProfile->batches[i]; + int batchIndex = batchesRequiringDynamicVao[j]; + auto m2Batch = skinProfile->batches[batchIndex]; auto skinSection = skinProfile->skinSections[m2Batch->skinSectionIndex]; - std::array dynVBOs; - auto dynVaos = m_m2Geom->createDynamicVao(*m_api->hDevice, dynVBOs, m_skinGeom.get(), skinSection); + std::array dynVBOs; + auto dynVaos = m_m2Geom->createDynamicVao(sceneRenderer, dynVBOs, m_skinGeom.get(), skinSection); - std::array dynamicMeshData; + std::array dynamicMeshData; //Try to create mesh M2MaterialInst testMaterial; EGxBlendEnum blendMode; - auto testMesh = createSingleMesh(m_m2Data, i, 0, dynVaos[0], m2Batch, skinSection, testMaterial, blendMode, - false); + auto testMesh = createSingleMesh(sceneRenderer, 0, dynVaos[0], + m_materialArray[batchIndex], skinSection, m2Batch); if (testMesh == nullptr) continue; - for (int k = 0; k < 4; k++) { - dynamicMeshData[k].batchIndex = i; + for (int k = 0; k < IDevice::MAX_FRAMES_IN_FLIGHT; k++) { + dynamicMeshData[k].batchIndex = batchIndex; dynamicMeshData[k].m_bindings = dynVaos[k]; dynamicMeshData[k].m_bufferVBO = dynVBOs[k]; M2MaterialInst material; int correction = skinSection->indexStart + (skinSection->Level << 16); - dynamicMeshData[k].m_mesh = createSingleMesh(m_m2Data, i, correction, dynVaos[k], m2Batch, skinSection, - material, blendMode, false); - - this->m_materialArray.push_back(material); - M2MeshBufferUpdater::assignUpdateEvents(dynamicMeshData[k].m_mesh, this, - m_materialArray[m_materialArray.size() - 1], m_m2Data, - skinProfile); + dynamicMeshData[k].m_mesh = createSingleMesh(sceneRenderer, correction, dynVaos[k], + m_materialArray[batchIndex], skinSection, m2Batch); } dynamicMeshes.push_back(dynamicMeshData); - }*/ + } } else { - //TODO: -// m_meshArray.push_back({createWaterfallMesh(), 0}); + m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); } { M2Data *m2File = this->m_m2Geom->getM2Data(); M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); - for (auto [material, batchIndex]: m_materialArray) { - M2MeshBufferUpdater::updateMaterialData(material, batchIndex, this, m2File, skinData); + for (auto &material: m_materialArray) { + M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); + } + for (auto &material: m_forcedTranspMaterialArray) { + M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); } } } -HGM2Mesh -M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, - const M2Data *m_m2Data, int batchIndex, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, - const M2Batch *m2Batch, const M2SkinSection *skinSection, - EGxBlendEnum &blendMode, bool overrideBlend) { +EGxBlendEnum M2Object::getBlendMode(int batchIndex) { + const auto &batches = m_skinGeom->getSkinData()->batches; + auto const &m2Data = m_m2Geom->getM2Data(); + + auto m2Batch = batches[batchIndex]; + + int materialIndex = m2Batch->materialIndex; + auto renderFlag = m2Data->materials[materialIndex]; + return M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; +} + +std::shared_ptr M2Object::createM2Material(const HMapSceneBufferCreate &sceneRenderer, int batchIndex, + const EGxBlendEnum blendMode, bool overrideBlend) { M2MaterialTemplate materialTemplate; - if (!prepearMaterial(materialTemplate, batchIndex)) return nullptr; + auto m_m2Data = m_m2Geom->getM2Data(); + const auto &batches = m_skinGeom->getSkinData()->batches; + auto m2Batch = batches[batchIndex]; - gMeshTemplate meshTemplate(finalBufferBindings); + if (!prepearMaterial(materialTemplate, batchIndex)) return nullptr; int materialIndex = m2Batch->materialIndex; auto renderFlag = m_m2Data->materials[materialIndex]; @@ -1565,15 +1586,19 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, pipelineTemplate.blendMode = blendMode; } else { pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; - blendMode = pipelineTemplate.blendMode; } - auto renderFlagIndex = m2Batch->materialIndex; - auto isTransparent = (m_m2Data->materials[renderFlagIndex]->blending_mode >= 2) || - ((m_m2Data->materials[renderFlagIndex]->flags & 0x10) > 0); - auto m2Material = sceneRenderer->createM2Material(m_modelWideDataBuff, pipelineTemplate, materialTemplate); - this->m_materialArray.emplace_back(m2Material, batchIndex); + return m2Material; +} + +HGM2Mesh +M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int indexStartCorrection, + const HGVertexBufferBindings &finalBufferBindings, + const std::shared_ptr m2Material, + const M2SkinSection *skinSection, + const M2Batch *m2Batch) { + gMeshTemplate meshTemplate(finalBufferBindings); meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; @@ -1590,15 +1615,18 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorgetConfig()->m2MaxBatch, (const int &) this->m_meshArray.size()); if (m_api->getConfig()->renderM2) { - for (int i = minBatch; i < maxBatch; i++) { - float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, i, skinData); + for (int i = 0; i < this->m_meshArray.size(); i++) { + int currentM2BatchIndex = std::get<1>(this->m_meshArray[i]); + if (currentM2BatchIndex < minBatch || currentM2BatchIndex > maxBatch ) continue; + + float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); if ((finalTransparency < 0.0001)) continue; - HGM2Mesh mesh = this->m_meshArray[i]; + HGM2Mesh mesh = std::get<0>(this->m_meshArray[i]); if (finalTransparency < 0.999 && i < this->m_meshForcedTranspArray.size() && - this->m_meshForcedTranspArray[i] != nullptr) { - mesh = this->m_meshForcedTranspArray[i]; + std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { + mesh = std::get<0>(this->m_meshForcedTranspArray[i]); } if (mesh->getIsTransparent()) { @@ -1609,9 +1637,18 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorhDevice->getUpdateFrameNumber(); - int frame = 0; - HGParticleMesh mesh = dynMesh[frame].m_mesh; + int frame = m_api->hDevice->getDrawFrameNumber(); + + auto const &dynMeshFrame = dynMesh[frame]; + + int currentM2BatchIndex = dynMeshFrame.batchIndex; + if (currentM2BatchIndex < minBatch || currentM2BatchIndex > maxBatch ) continue; + + float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); + if ((finalTransparency < 0.0001)) + continue; + + const HGM2Mesh &mesh = dynMeshFrame.m_mesh; if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { @@ -1661,7 +1698,8 @@ void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) auto emitter = std::make_unique(m_api, sceneRenderer,m_m2Geom->getM2Data()->particle_emitters.getElement(i), this, m_m2Geom, txacVal); if (m_m2Geom->exp2 != nullptr && emitter->getGenerator() != nullptr) { - emitter->getGenerator()->getAniProp()->zSource = m_m2Geom->exp2->content.getElement(i)->zSource; + auto exp2Rec = m_m2Geom->exp2->content.getElement(i); + emitter->getGenerator()->getAniProp()->zSource = exp2Rec->zSource; } particleEmitters.push_back(std::move(emitter)); @@ -1907,8 +1945,8 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) void M2Object::updateDynamicMeshes() { auto rootMatInverse = bonesMatrices[0].Inverse(); -// auto frameNum = m_api->hDevice->getUpdateFrameNumber(); - int frameNum = 0; + auto frameNum = m_api->hDevice->getDrawFrameNumber(); + for (auto &dynamicMesh: dynamicMeshes) { auto &dynMeshData = dynamicMesh[frameNum]; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 42327675b..141c66199 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -132,14 +132,15 @@ class M2Object { std::unordered_map loadedTextures; - //Tuple of Material and BatchIndex - std::vector, int>> m_materialArray; + std::vector> m_materialArray; + std::vector> m_forcedTranspMaterialArray; - std::vector m_meshForcedTranspArray; - std::vector m_meshArray; + //Tuple of Mesh and batch index + std::vector> m_meshForcedTranspArray; + std::vector> m_meshArray; //TODO: think about if it's viable to do forced transp for dyn meshes - std::vector> dynamicMeshes; + std::vector> dynamicMeshes; AnimationManager *m_animationManager; bool m_interiorAmbientWasSet = false; // For static only @@ -167,6 +168,7 @@ class M2Object { void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer); + EGxBlendEnum getBlendMode(int batchIndex); public: void setAlwaysDraw(bool value) { @@ -296,12 +298,15 @@ class M2Object { return m_m2Geom->m_m2Data->cameras.size; } - HGM2Mesh createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, - const M2Data *m_m2Data, int i, int indexStartCorrection, HGVertexBufferBindings finalBufferBindings, - const M2Batch *m2Batch, const M2SkinSection *skinSection, - EGxBlendEnum &blendMode, bool overrideBlend); + std::shared_ptr createM2Material(const HMapSceneBufferCreate &sceneRenderer, int batchIndex, const EGxBlendEnum blendMode, bool overrideBlend); - HGM2Mesh createWaterfallMesh(); + HGM2Mesh createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int indexStartCorrection, + const HGVertexBufferBindings &finalBufferBindings, + const std::shared_ptr m2Material, + const M2SkinSection *skinSection, + const M2Batch *m2Batch); + + HGM2Mesh createWaterfallMesh(const HMapSceneBufferCreate &sceneRenderer, const HGVertexBufferBindings &finalBufferBindings); void updateDynamicMeshes(); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 02909b7f0..4e748522f 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -23,9 +23,6 @@ #include "../../algorithms/mathHelper_culling.h" #include "../../../gapi/interface/materials/IMaterial.h" - - - std::array skyConusVBO = { { {0, 0, 0.2928932309150696f, 0}, diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index a470f5cf5..c54a93fc5 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -230,14 +230,13 @@ chunkDef AdtFile::adtFileTable = { { [](AdtFile& file, ChunkData& chunkData){ debuglog("Entered MH2O"); - - chunkData.readValue(file.mH2OHeader); - //Read the remaining into blob and parse in ADTObject + //Read everything into blob and parse in ADTObject file.mH2OblobOffset = chunkData.bytesRead; int byteSize = chunkData.chunkLen - chunkData.bytesRead; file.mH2OBlob_len = byteSize; chunkData.readValues(file.mH2OBlob, byteSize); + file.mH2OHeader = (M2HOHeader *)(&file.mH2OBlob[0]); } } }, diff --git a/wowViewerLib/src/engine/persistance/header/M2FileHeader.h b/wowViewerLib/src/engine/persistance/header/M2FileHeader.h index 7179670e5..a6528e596 100644 --- a/wowViewerLib/src/engine/persistance/header/M2FileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/M2FileHeader.h @@ -409,6 +409,12 @@ struct M2_AFID { uint32_t file_id; }; +struct EDGF { +/*0x00*/ float _0x0[2]; +/*0x08*/ float _0x8; +/*0x0C*/ char _0xC[0xC + 8]; +}; + struct TXAC { union { uint16_t value; @@ -419,8 +425,8 @@ struct TXAC { struct Exp2Record { float zSource; - uint32_t unk1; - uint32_t unk2; + float unk1; + float unk2; M2PartTrack unk3; }; diff --git a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h index 1093b8349..a6e26f6ca 100644 --- a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h +++ b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h @@ -11,6 +11,10 @@ #include #include "../header/commonFileStructs.h" +#if _MSC_VER && !__INTEL_COMPILER +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + //#define debuglog(x) std::cout<< x <>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,16}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, - }, + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +658,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,14080}, - {0,1,64}, {0,0,368}, - {0,7,64}, - {0,6,4096}, - {0,4,4096}, - {0,5,256}, }, { { - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,17 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, - {0,1,14144}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {1,1,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1525,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uNormalTex"}, - {1,7, "uNoise"}, - {1,6, "uWhiteWater"}, - {1,5, "uMask"}, }, { { {0,0,0}, - {5,9,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1544,12 +1546,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,144}, - {0,1,14144}, + {0,4,48}, {0,0,368}, }, { @@ -1565,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,8, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {8,8,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1584,21 +1585,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1622,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1945,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1981,29 +2006,23 @@ const std::unordered_map #include "mathfu/glsl_mappings.h" -#define MAX_MATRIX_NUM 220 +#define MAX_MATRIX_NUM 256 #define MAX_M2COLORS_NUM 256 #define MAX_TEXTURE_WEIGHT_NUM 64 #define MAX_TEXTURE_MATRIX_NUM 64 @@ -104,8 +104,10 @@ namespace M2 { namespace WaterfallData { struct meshWideBlockVS { - mathfu::vec4_packed bumpScale; - mathfu::mat4 uTextMat[2]; + float bumpScale; + int textureMatIndex1; + int textureMatIndex2; + int unused; }; struct meshWideBlockPS { mathfu::vec4_packed values0; diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index e1b4ad89d..a0078c211 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -4,59 +4,27 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { ISortableMesh * pA = dynamic_cast(indexA.get()); ISortableMesh * pB = dynamic_cast(indexB.get()); -// HGMesh pA = sortedArrayPtr[indexA]; -// HGMesh pB = sortedArrayPtr[indexB]; if (pA == nullptr) return false; if (pB == nullptr) return true; -// if (pA->getMeshType() > pB->getMeshType()) { -// return false; -// } -// if (pA->getMeshType() < pB->getMeshType()) { -// return true; -// } - -// if (pA->m_renderOrder != pB->m_renderOrder ) { -// if (!pA->getIsTransparent()) { -// return pA->m_renderOrder < pB->m_renderOrder; -// } else { -// return pA->m_renderOrder > pB->m_renderOrder; -// } -// } - - if (pA->getIsTransparent() && pB->getIsTransparent()) { - if (((pA->getMeshType() == MeshType::eM2Mesh || pA->getMeshType() == MeshType::eParticleMesh) && - (pB->getMeshType() == MeshType::eM2Mesh || pB->getMeshType() == MeshType::eParticleMesh))) { - ISortableMesh *pA1 = dynamic_cast(pA); - ISortableMesh *pB1 = dynamic_cast(pB); - - if (pA1->priorityPlane()!= pB1->priorityPlane()) { - return pB1->priorityPlane() < pA1->priorityPlane(); - } + if (pA->priorityPlane() != pB->priorityPlane()) { + return pB->priorityPlane() > pA->priorityPlane(); + } - if (pA1->getSortDistance() > pB1->getSortDistance()) { - return true; - } - if (pA1->getSortDistance() < pB1->getSortDistance()) { - return false; - } + if (pA->getSortDistance() > pB->getSortDistance()) { + return true; + } + if (pA->getSortDistance() < pB->getSortDistance()) { + return false; + } -// if (pA1->getM2Object() == pB1->getM2Object()) { - if (pA1->bindings() == pB1->bindings() && pA->getMeshType() == pB->getMeshType() && pB->getMeshType() == MeshType::eM2Mesh) { - IM2Mesh *pA2 = dynamic_cast(pA); - IM2Mesh *pB2 = dynamic_cast(pB); + if (pA->bindings() == pB->bindings() && pA->getMeshType() == pB->getMeshType() && pB->getMeshType() == MeshType::eM2Mesh) { + IM2Mesh *pA2 = dynamic_cast(pA); + IM2Mesh *pB2 = dynamic_cast(pB); - if (pB2->layer() != pA2->layer()) { - return pB2->layer() > pA2->layer(); - } - } - } else { - if (pA->getSortDistance() > pB->getSortDistance()) { - return true; - } - if (pA->getSortDistance() < pB->getSortDistance()) { - return false; + if (pB2->layer() != pA2->layer()) { + return pB2->layer() > pA2->layer(); } } } else { @@ -79,6 +47,5 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { return pA->end() < pB->end(); } - return pA > pB; } \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index de1d248e1..458e2216c 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -71,6 +71,16 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, )); m_depthTexture = h_depthTexture; + +// VkMemoryRequirements memoryRequirements; +// vkGetImageMemoryRequirements(mdevice.getVkDevice(), std::dynamic_pointer_cast(m_depthTexture)->texture.image, &memoryRequirements); +// std::cout << "Depth Texture wants " +// << memoryRequirements.size +// << " bytes with " +// << memoryRequirements.alignment +// << " alignment. " +// << " Size allocated by VMA " << std::dynamic_pointer_cast(m_depthTexture)->imageAllocationInfo.size +// << std::endl; } std::array attachments = { @@ -163,6 +173,17 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, )); m_depthTexture = h_depthTexture; + +// VkMemoryRequirements memoryRequirements; +// vkGetImageMemoryRequirements(mdevice.getVkDevice(), std::dynamic_pointer_cast(m_depthTexture)->texture.image, &memoryRequirements); +// std::cout << "Depth Texture wants " +// << memoryRequirements.size +// << " bytes with " +// << memoryRequirements.alignment +// << " alignment. " +// << " Size allocated by VMA " << std::dynamic_pointer_cast(m_depthTexture)->imageAllocationInfo.size +// << std::endl; + attachments.push_back(h_depthTexture->texture.view); } diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index cb8e8e7e5..74278aa3e 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -53,8 +53,6 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { BlpCacheRecord blpCacheRecord = { .texture = std::weak_ptr(texture) }; -// blpCacheRecord.wrapX = xWrapTex; -// blpCacheRecord.wrapY = yWrapTex; std::lock_guard lock(m_textureAllocation); auto i = loadedTextureCache.find(blpCacheRecord); diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 1d3770bd0..8b2703d34 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -71,7 +71,7 @@ class TextureManagerVLK : public std::enable_shared_from_this using std::hash; return hash{}(k.texture) ^ (hash{}(k.wrapX) << 8) ^ - (hash{}(k.wrapX) << 8); + (hash{}(k.wrapY) << 16); }; }; std::unordered_map, SampledTextureCacheRecordHasher> sampledTextureCache; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index c20c80666..ec0a56326 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -73,7 +73,7 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, bool minAddressStrategy = sizeInBytes < fakeSize && fakeSize > 0; if (sizeInBytes == 0) { - alloc = {.offset = 0}; + alloc = {.offset = 0, .metadata = OffsetAllocator::Allocation::NO_SPACE}; return VK_SUCCESS; } @@ -164,7 +164,7 @@ void GBufferVLK::resize(int newLength) { for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ auto subBuffer = it->lock(); if (subBuffer != nullptr) { - subBuffer->m_dataPointer = (uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData+subBuffer->m_alloc.offset; + subBuffer->setParentDataPointer(newBuffer.stagingBufferAllocInfo.pMappedData); } } memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData, @@ -225,7 +225,7 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy auto subBuffer = std::make_shared( shared_from_this(), alloc, - alloc.offset, sizeInBytes, fakeSize, + sizeInBytes, fakeSize, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+alloc.offset); std::unique_lock lock(m_mutex, std::defer_lock); @@ -337,7 +337,6 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { subBuffersForUpload.reserve(prevSize); } - return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); } @@ -347,11 +346,9 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, - VkDeviceSize offset, int size, int fakeSize, uint8_t *dataPointer) : m_parentBuffer(parent) { m_alloc = alloc; - m_offset = offset; m_size = size; m_fakeSize = fakeSize > 0 ? fakeSize : m_size; m_dataPointer = dataPointer; @@ -383,6 +380,8 @@ void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length } void *GBufferVLK::GSubBufferVLK::getPointer() { + if (m_size <= 0) return nullptr; + return m_dataPointer; } @@ -390,6 +389,7 @@ void GBufferVLK::GSubBufferVLK::save(int length) { if (length > m_size) { std::cerr << "invalid dataSize" << std::endl; } + if (m_size <= 0) return; m_parentBuffer->addSubBufferForUpload(weak_from_this()); // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index a326641bc..2932234db 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -86,7 +86,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GBufferVLK; public: - explicit GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, VkDeviceSize offset, + explicit GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, int size, int fakeSize, uint8_t * dataPointer); ~GSubBufferVLK() override; @@ -102,13 +102,16 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_thisgetGPUBuffer(); } size_t getOffset() override { - return m_offset; + return m_alloc.offset; }; + private: + void setParentDataPointer(void * ptr) { + m_dataPointer = ((uint8_t *) ptr) + m_alloc.offset; + } private: HGBufferVLK m_parentBuffer; OffsetAllocator::Allocation m_alloc; - VkDeviceSize m_offset; int m_size; int m_fakeSize; uint8_t * m_dataPointer = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index 450437b7a..23f040658 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -15,13 +15,14 @@ class GCommandBuffer { public: friend class CmdBufRecorder; friend class RenderPassHelper; + friend class RenderPassHelper; friend class IDeviceVulkan; public: GCommandBuffer(IDeviceVulkan &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); - VkCommandBuffer getNativeCmdBuffer() { + VkCommandBuffer getNativeCmdBuffer() const { return m_cmdBuffer; } private: diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp new file mode 100644 index 000000000..dc937d95a --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp @@ -0,0 +1,31 @@ +// +// Created by Deamon on 5/16/2023. +// + +#include "CommandBufferDebugLabel.h" +#include "CommandBufferRecorder.h" + +CommandBufferDebugLabel::CommandBufferDebugLabel(CmdBufRecorder &cmdBufRecorder, const std::string &labelStr, + const std::array &colors) : m_cmdBufRecorder(cmdBufRecorder) { + if (vkCmdBeginDebugUtilsLabelEXT != nullptr) { + VkDebugUtilsLabelEXT label; + label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + label.pNext = NULL; + label.pLabelName = labelStr.c_str(); + label.color[0] = colors[0]; + label.color[1] = colors[1]; + label.color[2] = colors[2]; + label.color[3] = colors[3]; + + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + + vkCmdBeginDebugUtilsLabelEXT(gCmdBuffer.getNativeCmdBuffer(), &label); + } +} + +CommandBufferDebugLabel::~CommandBufferDebugLabel() { + if (vkCmdEndDebugUtilsLabelEXT != nullptr) { + auto &gCmdBuffer = m_cmdBufRecorder.m_gCmdBuffer; + vkCmdEndDebugUtilsLabelEXT(gCmdBuffer.getNativeCmdBuffer()); + } +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h new file mode 100644 index 000000000..a86381702 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h @@ -0,0 +1,23 @@ +// +// Created by Deamon on 5/16/2023. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFERDEBUGLABEL_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFERDEBUGLABEL_H + +#include "CommandBufferRecorder.h" + +class CommandBufferDebugLabel { +public: + CommandBufferDebugLabel(CmdBufRecorder &cmdBufRecorder, const std::string &labelStr, const std::array &colors); + + CommandBufferDebugLabel(const CommandBufferDebugLabel&) = delete; + CommandBufferDebugLabel operator=(const CommandBufferDebugLabel&) = delete; + + ~CommandBufferDebugLabel(); +private: + CmdBufRecorder &m_cmdBufRecorder; +}; + + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFERDEBUGLABEL_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 92027a10b..10de28f3d 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -92,6 +92,14 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr m_currentDescriptorSet[bindIndex] = descriptorSet; } +CommandBufferDebugLabel CmdBufRecorder::beginDebugLabel(const std::string &labelName, const std::array &colors) { + return CommandBufferDebugLabel( + *this, + labelName, + colors + ); +} + void CmdBufRecorder::bindIndexBuffer(const std::shared_ptr &buffer) { auto bufferVlk = std::dynamic_pointer_cast(buffer); if (m_currentIndexBuffer!= nullptr && m_currentIndexBuffer->getGPUBuffer() == bufferVlk->getGPUBuffer() && diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 242f0639e..bb8756d3d 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -14,15 +14,17 @@ class CmdBufRecorder; class RenderPassHelper; class GCommandBuffer; +class CommandBufferDebugLabel; #include "../CommandBuffer.h" #include "RenderPassHelper.h" +#include "CommandBufferDebugLabel.h" #include "../../descriptorSets/GDescriptorSet.h" - class CmdBufRecorder { public: enum class ViewportType: int {vp_none = -1, vp_usual = 0, vp_mapArea = 1, vp_skyBox = 2, vp_MAX = 3}; friend RenderPassHelper; + friend CommandBufferDebugLabel; CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr &renderPass); CmdBufRecorder(const CmdBufRecorder&) = delete; @@ -39,6 +41,8 @@ class CmdBufRecorder { const std::array &areaSize, const std::array &colorClearColor, float depthClear); + CommandBufferDebugLabel beginDebugLabel(const std::string &labelName, const std::array &colors); + void bindIndexBuffer(const std::shared_ptr &bufferVlk); void bindVertexBuffers(const std::vector> &bufferVlk); void bindPipeline(const std::shared_ptr &pipeline); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index dd825ab56..be02550e9 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -229,7 +229,8 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te imageCreateInfo.pQueueFamilyIndices = families.data(); VmaAllocationCreateInfo allocImageCreateInfo = {}; - allocImageCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + allocImageCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +// allocImageCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; //this bit forces to create per one texture per memory vmaCreateImage(m_device.getVMAAllocator(), &imageCreateInfo, &allocImageCreateInfo, &texture.image, diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 298ddac5c..42edd1cb7 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -92,6 +92,10 @@ class IMapSceneBufferCreate { const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) = 0; + virtual std::shared_ptr createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) = 0; + virtual std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) = 0; virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; @@ -114,6 +118,7 @@ class IMapSceneBufferCreate { virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; + virtual HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 504f59758..cc581e9c1 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -14,9 +14,15 @@ struct M2MaterialTemplate { int vertexShader = 0; int pixelShader = 0; + int batchIndex; std::array textures = {nullptr, nullptr, nullptr, nullptr}; }; +struct M2WaterfallMaterialTemplate { + std::array textures = {nullptr, nullptr, nullptr, nullptr, nullptr}; +}; + + struct M2ParticleMaterialTemplate { std::array textures = {nullptr, nullptr, nullptr}; }; @@ -55,9 +61,22 @@ class IM2Material : public IMaterial { public: int vertexShader; int pixelShader; + int batchIndex; EGxBlendEnum blendMode; std::shared_ptr> m_vertexFragmentData = nullptr; - }; +}; + +class IM2WaterFallMaterial : public IMaterial { +public: + int vertexShader; + int pixelShader; + EGxBlendEnum blendMode; + + std::shared_ptr> m_vertexData = nullptr; + std::shared_ptr> m_fragmentData = nullptr; +}; + + class IM2ParticleMaterial : public IMaterial { public: std::shared_ptr> m_fragmentData = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 9d92218fc..4a678d4e6 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -244,7 +244,6 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -270,6 +269,7 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & }); material->blendMode = pipelineTemplate.blendMode; + material->batchIndex = m2MaterialTemplate.batchIndex; material->vertexShader = m2MaterialTemplate.vertexShader; material->pixelShader = m2MaterialTemplate.pixelShader; @@ -277,6 +277,40 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & return material; } +std::shared_ptr MapSceneRenderForwardVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexData = std::make_shared>(uboStaticBuffer); + auto fragmentData = std::make_shared>(uboStaticBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) + .ubo(4, vertexData->getSubBuffer()) + .ubo(5, fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(6, m2MaterialTemplate.textures[0]) + .texture(7, m2MaterialTemplate.textures[1]) + .texture(8, m2MaterialTemplate.textures[2]) + .texture(9, m2MaterialTemplate.textures[3]) + .texture(10, m2MaterialTemplate.textures[4]); + }) + .toMaterial([&vertexData, fragmentData](IM2WaterFallMaterial *instance) -> void { + instance->m_vertexData = vertexData; + instance->m_fragmentData = fragmentData; + }); + + return material; +} + std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleMaterial( const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2ParticleMatTemplate) { @@ -558,11 +592,29 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *skyTransparentMeshes) { + std::string debugMess = + "Drawing mesh " + " meshType = " + std::to_string((int)mesh->getMeshType()) + + " priorityPlane = " + std::to_string(mesh->priorityPlane()) + + " sortDistance = " + std::to_string(mesh->getSortDistance()) + + " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); + + auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } if (skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *transparentMeshes) { + std::string debugMess = + "Drawing mesh " + " meshType = " + std::to_string((int)mesh->getMeshType()) + + " priorityPlane = " + std::to_string(mesh->priorityPlane()) + + " sortDistance = " + std::to_string(mesh->getSortDistance()) + + " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); + + auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } } @@ -593,7 +645,12 @@ MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::s auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } - +HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, + const std::shared_ptr &material, + int layer, int priorityPlane) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + return mesh; +} void MapSceneRenderForwardVLK::createFrameBuffers() { { auto const dataFormat = {ITextureFormat::itRGBA}; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 16bc092f1..493d56300 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -61,6 +61,9 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) override; std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) override; @@ -85,6 +88,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; private: HGDeviceVLK m_device; From 64046df582aceac2dfbf7d547487ef8d7cc5c312 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 20 May 2023 16:05:31 +0300 Subject: [PATCH 071/212] restore the sky in Broken Isles --- wowViewerLib/shaders/glsl/common/commonM2Material.glsl | 4 +++- wowViewerLib/src/gapi/interface/sortLambda.h | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index afca5c8c9..8549e14f5 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -25,6 +25,7 @@ out float finalOpacity, out bool discardThisFragment) vec2 uv2 = inUv2; vec2 uv3 = inUv3; +// This was added bcuz of how these three shaders use non-standard UV for querying the textures if (uPixelShader == 26 || uPixelShader == 27 || uPixelShader == 28) { uv2 = uv1; uv3 = uv1; @@ -194,7 +195,8 @@ out float finalOpacity, out bool discardThisFragment) break; } case (28): { //Combiners_Mod_Masked_Dual_Crossfade - vec4 tex4 = texture(texSampler4, uv2).rgba; + //uv2 has inUv1 inside by this point. So we need to use inUv2 directly + vec4 tex4 = texture(texSampler4, inUv2).rgba; matDiffuse = meshColor * mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).rgb; discardAlpha = mix(mix(tex, tex2, vec4(clamp(texSampleAlpha.g, 0.0, 1.0))), tex3, vec4(clamp(texSampleAlpha.b, 0.0, 1.0))).a * tex4.a; canDiscard = true; diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index a0078c211..9d298ee3e 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -12,10 +12,10 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { return pB->priorityPlane() > pA->priorityPlane(); } - if (pA->getSortDistance() > pB->getSortDistance()) { + if (pA->getSortDistance() < pB->getSortDistance()) { return true; } - if (pA->getSortDistance() < pB->getSortDistance()) { + if (pA->getSortDistance() > pB->getSortDistance()) { return false; } @@ -28,10 +28,10 @@ static const bool SortMeshes(const HGMesh &indexA, const HGMesh &indexB) { } } } else { - if (pA->getSortDistance() > pB->getSortDistance()) { + if (pA->getSortDistance() < pB->getSortDistance()) { return true; } - if (pA->getSortDistance() < pB->getSortDistance()) { + if (pA->getSortDistance() > pB->getSortDistance()) { return false; } } From 7106ddbd8ed8602d2fb07ec80243cb2f1ff64cca Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 20 May 2023 19:34:17 +0300 Subject: [PATCH 072/212] Adt liquid put into separate class --- wowViewerLib/CMakeLists.txt | 2 +- wowViewerLib/shaders/CMakeLists.txt | 2 + .../src/engine/objects/adt/adtObject.cpp | 422 +----------------- .../src/engine/objects/adt/adtObject.h | 6 +- .../engine/objects/liquid/LiquidDataGetters.h | 150 +++++++ .../engine/objects/liquid/LiquidInstance.cpp | 316 +++++++++++++ .../engine/objects/liquid/LiquidInstance.h | 49 ++ 7 files changed, 534 insertions(+), 413 deletions(-) create mode 100644 wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h create mode 100644 wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp create mode 100644 wowViewerLib/src/engine/objects/liquid/LiquidInstance.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 0e699eec7..abba29b93 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -335,7 +335,7 @@ set(SOURCE_FILES src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h src/include/custom_container_key.h - src/renderer/mapScene/materials/IMaterialStructs.h src/gapi/interface/textures/ITextureSampler.h src/gapi/interface/textures/ISamplableTexture.h) + src/renderer/mapScene/materials/IMaterialStructs.h src/gapi/interface/textures/ITextureSampler.h src/gapi/interface/textures/ISamplableTexture.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h src/engine/objects/liquid/LiquidDataGetters.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 972f6591f..13f2dffcd 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -65,6 +65,8 @@ else() add_custom_target(spirv_reflection) endif() +set (SPIRV_OPT_APP "") + macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring directory ${destDir}") set(spirvNonOptDir ${CMAKE_BINARY_DIR}/spriv_raw) diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 6191e72c8..7cfa332f7 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -126,397 +126,6 @@ void AdtObject::loadWmos() { } } -struct lfv_4_5_format { - union { - struct { - int16_t s; - int16_t t; - } vert_format_5; - - struct { - char depth; - char filler1; - char filler2; - char filler3; - } vert_format_4; - }; - float height; -}; - -static_assert(sizeof(lfv_4_5_format) == 8); - -inline float getLiquidVertexHeight(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { - constexpr std::bitset<5> lvf_0_1_3 = 0xB; - constexpr std::bitset<5> lvf_4_5 = 0x30; - - if ( liquidVertexFormat > 5 ) - return 0.0; - - if ( liquidVertexFormat == 0 || liquidVertexFormat == 1 || liquidVertexFormat == 3 ) // lvf == 0, 1, 3 - return vertexDataPtr[index]; - - if ( liquidVertexFormat == 4 || liquidVertexFormat == 5 ) - return ((lfv_4_5_format*) vertexDataPtr)[index].height;// lvf == 4,5 - - return 0.0;// lfv == 2 -} - -struct uv_map_entry { - int16_t s; - int16_t t; -}; - -uint8_t * getLiquidExistsTable(const PointerChecker &mH2OBlob, const SMLiquidInstance &liquidInstance) { - const static uint64_t fullBitmask = 0xFFFFFFFFFFFFFFFF; - - if (liquidInstance.offset_exists_bitmap) { - return (uint8_t *) &mH2OBlob[liquidInstance.offset_exists_bitmap]; - } - - return (uint8_t *) &fullBitmask; -} -inline mathfu::vec2 getLiquidVertexCoords(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { - int16_t s = 0; - int16_t t = 0; - - if (liquidVertexFormat == 3 || liquidVertexFormat == 1) { - auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); - auto const &element = uvStart[index]; - - s = element.s; - t = element.t; - } - if (liquidVertexFormat == 5) { - auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; - - s = element.vert_format_5.s; - t = element.vert_format_5.t; - } - //For all other liquidVertexFormat are default zeroes - - return mathfu::vec2(s * 3.0f / 256.0f, t * 3.0f / 256.0f); -} - -inline uint8_t getLiquidDepth(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { - uint8_t depth = 0; - if (liquidVertexFormat == 2) { - depth = 255; - if ( vertexDataPtr ) - depth = ((uint8_t *)vertexDataPtr)[index]; - } else if (liquidVertexFormat == 0) { - auto const depthStart = (uint8_t *) (&vertexDataPtr[totalElemSize]); - depth = depthStart[index]; - } else if (liquidVertexFormat == 3) { - auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); - auto const * depthStart = (uint8_t *) (&uvStart[totalElemSize]); - - depth = depthStart[index]; - } else if (liquidVertexFormat == 4) { - auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; - depth = element.vert_format_4.depth; - } - - return depth; -} - -struct LiquidObjectSettings { - bool generateTexCoordsFromPos; -}; - -const constexpr LiquidObjectSettings useTexCoordLiquidObject = { - .generateTexCoordsFromPos = false -}; -const constexpr LiquidObjectSettings usePlanarMapLiquidObject = { - .generateTexCoordsFromPos = true -}; - -const constexpr LiquidObjectSettings usePlanarMapLiquidObjectNoSky = { - .generateTexCoordsFromPos = true -}; - -const constexpr LiquidObjectSettings oceanLiquidObject = { - .generateTexCoordsFromPos = true -}; - -inline LiquidObjectSettings getLiquidSettings(int liquidObjectId, int liquidType, int materialId, bool db_generateTexCoordsFromPos) { - if (liquidObjectId < 41) { - if (materialId == 2) { - return useTexCoordLiquidObject; - } else if ( materialId == 1) { - if (liquidType == 2 || liquidType == 14) { - return oceanLiquidObject; - } else if (liquidType == 17) { - return usePlanarMapLiquidObjectNoSky; - } else { - return usePlanarMapLiquidObject; - } - } else if ( materialId == 5 && (liquidType == 350 || liquidType == 412) ) { - return usePlanarMapLiquidObjectNoSky; - } else { - return usePlanarMapLiquidObject; - } - } else if (liquidObjectId == 42 || liquidType == 14) { - return oceanLiquidObject; - } else { - return {.generateTexCoordsFromPos = db_generateTexCoordsFromPos}; - } -} - - -HGSortableMesh AdtObject::createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos) { - //Get Data from DB - int basetextureFDID = 0; - mathfu::vec3 color = mathfu::vec3(0,0,0); - mathfu::vec3 minimapStaticCol = {0,0,0}; - - int liquidFlags = 0; - int liquidVertexFormat = 0; - bool generateTexCoordsFromPos = false; - - if (basetextureFDID == 0 && (m_api->databaseHandler != nullptr)) { - if (liquidInstance.liquid_object_or_lvf > 41) { - liquidVertexFormat = 2; - std::vector liqMats; - m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liqMats); - for (auto &liqMat : liqMats) { - if (liqMat.FileDataId != 0) { - basetextureFDID = liqMat.FileDataId; - if (liqMat.color1[0] > 0 || liqMat.color1[1] > 0 || liqMat.color1[2] > 0) { - color = mathfu::vec3(liqMat.color1[2], liqMat.color1[1], liqMat.color1[0]); - } - minimapStaticCol = mathfu::vec3(liqMat.minimapStaticCol[2], liqMat.minimapStaticCol[1], liqMat.minimapStaticCol[0]); - - liquidFlags = liqMat.flags; - liquidVertexFormat = liqMat.LVF; - generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, - liquidInstance.liquid_type, - liqMat.materialId, - liqMat.flowSpeed <=0).generateTexCoordsFromPos; - - break; - } - } - } else { - liquidVertexFormat = liquidInstance.liquid_object_or_lvf; - std::vector liquidTypeData; - m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liquidTypeData); - for (auto ltd: liquidTypeData) { - if (ltd.FileDataId != 0) { - basetextureFDID = ltd.FileDataId; - - if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { - color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); - } - minimapStaticCol = mathfu::vec3(ltd.minimapStaticCol[2], ltd.minimapStaticCol[1], ltd.minimapStaticCol[0]); - liquidFlags = ltd.flags; - liquidVertexFormat = ltd.LVF; - - generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, - liquidInstance.liquid_type, - ltd.materialId, - usePlanarMapLiquidObject.generateTexCoordsFromPos).generateTexCoordsFromPos; - break; - } - } - } - } - - - - if (!liquidInstance.offset_vertex_data && liquidInstance.liquid_type != 2) { - liquidVertexFormat = 2; - } -// -// //Hack -// if (liquidInstance.liquid_type == 2) { -// liquidVertexFormat = 2; -// } -// - float *vertexDataPtr = nullptr; - if (liquidInstance.offset_vertex_data != 0) { - vertexDataPtr = ((float *) (&m_adtFile->mH2OBlob[liquidInstance.offset_vertex_data])); - } - - //Set iteration restrictions for triangles - int y_begin = 0; - int x_begin = 0; - int x_end = 8; - int y_end = 8; - int totalCount = 9 * 9; - if (liquidInstance.liquid_object_or_lvf <= 41) { - x_begin = liquidInstance.x_offset; - y_begin = liquidInstance.y_offset; - x_end = liquidInstance.x_offset + liquidInstance.width; - y_end = liquidInstance.y_offset + liquidInstance.height; - - totalCount = (liquidInstance.width + 1) * (liquidInstance.height + 1) ; - } - -// int baseVertexIndForInst = vertexBuffer.size(); - int baseVertexIndForInst = 0; - - int i = this->m_adtFile->mcnkMap[x_chunk][y_chunk]; - auto &waterAaBB = waterTileAabb[i]; - SMChunk *mcnkChunk = &m_adtFile->mapTile[i]; - - float minX = 999999; float maxX = -999999; - float minY = 999999; float maxY = -999999; - float minZ = 999999; float maxZ = -999999; - - minX = std::min(minX, waterAaBB.min.x); maxX = std::max(maxX, waterAaBB.max.x); - minY = std::min(minY, waterAaBB.min.y); maxY = std::max(maxY, waterAaBB.max.y); - minZ = std::min(minZ, waterAaBB.min.z); maxZ = std::max(maxZ, waterAaBB.max.z); - - //Parse the blob - std::vector vertexBuffer; - std::vector indexBuffer; - - for (int y = 0; y < liquidInstance.height + 1; y++) { - for (int x = 0; x < liquidInstance.width + 1; x++) { - mathfu::vec3 pos = - liquidBasePos - - mathfu::vec3( - MathHelper::UNITSIZE*(y+liquidInstance.y_offset), - MathHelper::UNITSIZE*(x+liquidInstance.x_offset), - -liquidInstance.min_height_level - ); - - mathfu::vec2 uv = mathfu::vec2(0,0); - if (vertexDataPtr!= nullptr) { - pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); - } - -// if (std::isnan(pos.z) || (pos.z > 10000.0f)) { -// pos.z = liquidInstance.min_height_level; -// } - - if (generateTexCoordsFromPos) { - uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); - } else { - uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); - } - - minX = std::min(minX, pos.x); maxX = std::max(maxX, pos.x); - minY = std::min(minY, pos.y); maxY = std::max(maxY, pos.y); - minZ = std::min(minZ, pos.z); maxZ = std::max(maxZ, pos.z); - - LiquidVertexFormat vertex; - vertex.pos_transp = mathfu::vec4(pos, 1.0); - vertex.uv = uv; - - vertexBuffer.push_back(vertex); - } - } - waterAaBB = CAaBox( - C3Vector(mathfu::vec3(minX, minY, minZ)), - C3Vector(mathfu::vec3(maxX, maxY, maxZ)) - ); - - uint8_t *existsTable = getLiquidExistsTable(m_adtFile->mH2OBlob, liquidInstance); - - for (int y = y_begin; y < y_end; y++) { - for (int x = x_begin; x < x_end; x++) { - - int maskIndex = (y - y_begin) * (x_end - x_begin) + (x - x_begin); - bool exists = (existsTable[maskIndex >> 3] >> ((maskIndex & 7))) & 1; - - if (!exists) continue; - - const int16_t vertIndexes[4] = { - (int16_t) (y * (liquidInstance.width + 1 ) + x), - (int16_t) (y * (liquidInstance.width + 1) + x + 1), - (int16_t) ((y + 1) * (liquidInstance.width + 1) + x), - (int16_t) ((y + 1) * (liquidInstance.width + 1) + x + 1), - }; - - indexBuffer.push_back (vertIndexes[0]); - indexBuffer.push_back (vertIndexes[1]); - indexBuffer.push_back (vertIndexes[2]); - - indexBuffer.push_back (vertIndexes[1]); - indexBuffer.push_back (vertIndexes[3]); - indexBuffer.push_back (vertIndexes[2]); - } - } - - //Query river color - mathfu::vec3 closeRiverColor = {0, 0, 0}; - if (m_api->getConfig()->useCloseRiverColorForDB) { - - mathfu::vec3 waterPos = (mathfu::vec3(waterAaBB.max) + mathfu::vec3(waterAaBB.min)) / 2.0f; - bool waterColorFound = true; - if (m_api->getConfig()->colorOverrideHolder != nullptr) { - waterColorFound = false; -// int adt_global_x = worldCoordinateToGlobalAdtChunk(waterPos.y) % 16; -// int adt_global_y = worldCoordinateToGlobalAdtChunk(waterPos.x) % 16; -// -// auto areaId = getAreaId(adt_global_x, adt_global_y); - - for (auto &riverOverride : *m_api->getConfig()->colorOverrideHolder) { - if (riverOverride.liquidObjectId == liquidInstance.liquid_object_or_lvf) { - closeRiverColor = riverOverride.color.xyz(); - waterColorFound = true; - break; - } - } - } - if (!waterColorFound) { - std::vector lightResults = {}; - this->m_mapApi->getLightResultsFromDB(waterPos, m_api->getConfig(), lightResults, nullptr); - for (auto &_light : lightResults) { - closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; - } - closeRiverColor = mathfu::vec3(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0]); - } - } - - - HGDevice device = m_api->hDevice; - - auto waterIBO = sceneRenderer->createWaterIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); - waterIBO->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); - - auto waterVBO = sceneRenderer->createWaterVertexBuffer(vertexBuffer.size() * sizeof(LiquidVertexFormat)); - waterVBO->uploadData( - vertexBuffer.data(), - vertexBuffer.size() * sizeof(LiquidVertexFormat) - ); - - - auto vertexWaterBufferBindings = sceneRenderer->createWaterVAO(waterVBO, waterIBO); - -//Create mesh(es) - gMeshTemplate meshTemplate(vertexWaterBufferBindings); - meshTemplate.meshType = MeshType::eWmoMesh; - - PipelineTemplate pipelineTemplate; - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.depthWrite = false; - pipelineTemplate.depthCulling = true; - pipelineTemplate.backFaceCulling = false; - pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - - WaterMaterialTemplate waterMaterialTemplate; - waterMaterialTemplate.color = color; - waterMaterialTemplate.liquidFlags = liquidFlags; - - if (basetextureFDID != 0) { - auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); - waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); - } else { - waterMaterialTemplate.texture = m_api->hDevice->getBlackTexturePixel(); - } - - meshTemplate.start = 0; - meshTemplate.end = indexBuffer.size(); - - auto waterMaterial = sceneRenderer->createWaterMaterial(m_waterPlacementChunk, pipelineTemplate, waterMaterialTemplate); - m_waterMaterialArray.push_back(waterMaterial); - - auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); - return mesh; -} - void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { if (m_adtFile->mH2OHeader == nullptr) return; @@ -551,7 +160,14 @@ void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { for (int layerInd = 0; layerInd < liquidChunk.layer_count; layerInd++) { SMLiquidInstance &liquidInstance = liquidInstPtr[layerInd]; - waterMeshes[i].push_back(createWaterMeshFromInstance(sceneRenderer, x_chunk,y_chunk,liquidInstance,liquidBasePos)); + auto l_liquidInstance = std::make_shared( + m_api, sceneRenderer, liquidInstance, + m_waterPlacementChunk, liquidBasePos, m_adtFile->mH2OBlob, + waterTileAabb[i] + ); + + m_liquidInstances.push_back(l_liquidInstance); + m_liquidInstancesPerChunk[i].push_back(l_liquidInstance); } } } @@ -871,14 +487,14 @@ void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaq size_t meshCount = adtMeshes.size(); opaqueMeshes.reserve(opaqueMeshes.size() + adtMeshes.size()); - transparentMeshes.reserve(transparentMeshes.size() + waterMeshes.size()); + transparentMeshes.reserve(transparentMeshes.size() + m_liquidInstancesPerChunk.size()); for (int i = 0; i < meshCount; i++) { if (adtRes.drawChunk[i] && (adtMeshes[i] != nullptr)) { opaqueMeshes.push_back(adtMeshes[i]); } if (adtRes.drawWaterChunk[i]) { - for (auto const &waterMesh : waterMeshes[i]) { - transparentMeshes.push_back(waterMesh); + for (auto const &liquidInstance : m_liquidInstancesPerChunk[i]) { + liquidInstance->collectMeshes(transparentMeshes); } } } @@ -1040,20 +656,8 @@ void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependant m_waterPlacementChunk->save(); } - for (auto &waterMaterial : m_waterMaterialArray) { - - auto &waterChunk = waterMaterial->m_materialPS->getObject(); - if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean - waterChunk.color = frameDependantData->closeOceanColor; - } else if (waterMaterial->liquidFlags == 15) { //River/Lake - waterChunk.color = frameDependantData->closeRiverColor; - } else { - waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); - } - - auto time = m_mapApi->getCurrentSceneTime(); - - waterMaterial->m_materialPS->save(); + for(auto &liquidInstance : m_liquidInstances) { + liquidInstance->updateLiquidMaterials(frameDependantData, m_mapApi); } } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index c84dd6a82..e6b6a610a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -21,6 +21,7 @@ class M2Object; #include "../wmo/wmoObject.h" #include "../iMapApi.h" #include "../ViewsObjects.h" +#include "../liquid/LiquidInstance.h" typedef std::function FreeStrategy; @@ -134,7 +135,8 @@ class AdtObject { std::array adtMeshes = {}; std::array, 16*16> adtMaterials = {}; //16x16, then layer - std::array, 16*16> waterMeshes = {}; + std::array>, 16*16> m_liquidInstancesPerChunk = {}; + std::vector> m_liquidInstances = {}; std::vector adtLodMeshes; std::vector tileAabb; @@ -176,8 +178,6 @@ class AdtObject { void loadM2s(); void loadWmos(); void loadWater(const HMapSceneBufferCreate &sceneRenderer); - HGSortableMesh createWaterMeshFromInstance(const HMapSceneBufferCreate &sceneRenderer, int x_chunk, int y_chunk, SMLiquidInstance &liquidInstance, mathfu::vec3 liquidBasePos); - bool checkNonLodChunkCulling(ADTObjRenderRes &adtFrustRes, const mathfu::vec4 &cameraPos, diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h b/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h new file mode 100644 index 000000000..335ff2812 --- /dev/null +++ b/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h @@ -0,0 +1,150 @@ +// +// Created by Deamon on 5/20/2023. +// + +#ifndef AWEBWOWVIEWERCPP_LIQUIDDATAGETTERS_H +#define AWEBWOWVIEWERCPP_LIQUIDDATAGETTERS_H + + +#include +#include +#include "../../persistance/header/adtFileHeader.h" + +struct lfv_4_5_format { + union { + struct { + int16_t s; + int16_t t; + } vert_format_5; + + struct { + char depth; + char filler1; + char filler2; + char filler3; + } vert_format_4; + }; + float height; +}; + +static_assert(sizeof(lfv_4_5_format) == 8); + +inline float getLiquidVertexHeight(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + constexpr std::bitset<5> lvf_0_1_3 = 0xB; + constexpr std::bitset<5> lvf_4_5 = 0x30; + + if ( liquidVertexFormat > 5 ) + return 0.0; + + if ( liquidVertexFormat == 0 || liquidVertexFormat == 1 || liquidVertexFormat == 3 ) // lvf == 0, 1, 3 + return vertexDataPtr[index]; + + if ( liquidVertexFormat == 4 || liquidVertexFormat == 5 ) + return ((lfv_4_5_format*) vertexDataPtr)[index].height;// lvf == 4,5 + + return 0.0;// lfv == 2 +} + +struct uv_map_entry { + int16_t s; + int16_t t; +}; + +uint8_t * getLiquidExistsTable(const PointerChecker &mH2OBlob, const SMLiquidInstance &liquidInstance) { + const static uint64_t fullBitmask = 0xFFFFFFFFFFFFFFFF; + + if (liquidInstance.offset_exists_bitmap) { + return (uint8_t *) &mH2OBlob[liquidInstance.offset_exists_bitmap]; + } + + return (uint8_t *) &fullBitmask; +} +inline mathfu::vec2 getLiquidVertexCoords(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + int16_t s = 0; + int16_t t = 0; + + if (liquidVertexFormat == 3 || liquidVertexFormat == 1) { + auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); + auto const &element = uvStart[index]; + + s = element.s; + t = element.t; + } + if (liquidVertexFormat == 5) { + auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; + + s = element.vert_format_5.s; + t = element.vert_format_5.t; + } + //For all other liquidVertexFormat are default zeroes + + return mathfu::vec2(s * 3.0f / 256.0f, t * 3.0f / 256.0f); +} + +inline uint8_t getLiquidDepth(int liquidVertexFormat, float *vertexDataPtr, int totalElemSize, int index) { + uint8_t depth = 0; + if (liquidVertexFormat == 2) { + depth = 255; + if ( vertexDataPtr ) + depth = ((uint8_t *)vertexDataPtr)[index]; + } else if (liquidVertexFormat == 0) { + auto const depthStart = (uint8_t *) (&vertexDataPtr[totalElemSize]); + depth = depthStart[index]; + } else if (liquidVertexFormat == 3) { + auto const * uvStart = ((uv_map_entry *) &vertexDataPtr[totalElemSize]); + auto const * depthStart = (uint8_t *) (&uvStart[totalElemSize]); + + depth = depthStart[index]; + } else if (liquidVertexFormat == 4) { + auto &element = ((lfv_4_5_format*) vertexDataPtr)[index]; + depth = element.vert_format_4.depth; + } + + return depth; +} + +struct LiquidObjectSettings { + bool generateTexCoordsFromPos; +}; + +const constexpr LiquidObjectSettings useTexCoordLiquidObject = { + .generateTexCoordsFromPos = false +}; +const constexpr LiquidObjectSettings usePlanarMapLiquidObject = { + .generateTexCoordsFromPos = true +}; + +const constexpr LiquidObjectSettings usePlanarMapLiquidObjectNoSky = { + .generateTexCoordsFromPos = true +}; + +const constexpr LiquidObjectSettings oceanLiquidObject = { + .generateTexCoordsFromPos = true +}; + + +inline LiquidObjectSettings getLiquidSettings(int liquidObjectId, int liquidType, int materialId, bool db_generateTexCoordsFromPos) { + if (liquidObjectId < 41) { + if (materialId == 2) { + return useTexCoordLiquidObject; + } else if ( materialId == 1) { + if (liquidType == 2 || liquidType == 14) { + return oceanLiquidObject; + } else if (liquidType == 17) { + return usePlanarMapLiquidObjectNoSky; + } else { + return usePlanarMapLiquidObject; + } + } else if ( materialId == 5 && (liquidType == 350 || liquidType == 412) ) { + return usePlanarMapLiquidObjectNoSky; + } else { + return usePlanarMapLiquidObject; + } + } else if (liquidObjectId == 42 || liquidType == 14) { + return oceanLiquidObject; + } else { + return {.generateTexCoordsFromPos = db_generateTexCoordsFromPos}; + } +} + +#endif //AWEBWOWVIEWERCPP_LIQUIDDATAGETTERS_H diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp new file mode 100644 index 000000000..9d561b185 --- /dev/null +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -0,0 +1,316 @@ +// +// Created by Deamon on 5/20/2023. +// + +#include "LiquidInstance.h" +#include "LiquidDataGetters.h" +#include "../../algorithms/mathHelper.h" + +LiquidInstance::LiquidInstance(const HApiContainer &api, + const HMapSceneBufferCreate &sceneRenderer, + const SMLiquidInstance &liquidInstance, + std::shared_ptr> &waterPlacementChunk, + const mathfu::vec3 &liquidBasePos, + const PointerChecker &mH2OBlob, CAaBox &waterAaBB) : + m_api(api), m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), + m_waterBBox(waterAaBB){ + + //Creating liquid instance from ADT data + liquid_object_or_lvf = liquidInstance.liquid_object_or_lvf; + + //1. Get Data from DB + int basetextureFDID; + mathfu::vec3 color; + int liquidFlags; + int liquidVertexFormat; + bool generateTexCoordsFromPos; + getInfoFromDatabase(liquidInstance, basetextureFDID, color, liquidFlags, + liquidVertexFormat, + generateTexCoordsFromPos); + + //2. Parse Vertex Data from ADT + std::vector vertexBuffer; + std::vector indexBuffer; + + createAdtVertexData(liquidInstance, liquidBasePos, mH2OBlob, m_waterBBox, liquidVertexFormat, + generateTexCoordsFromPos, vertexBuffer, + indexBuffer); + + HGVertexBufferBindings vertexWaterBufferBindings = createLiquidVao(sceneRenderer, vertexBuffer, indexBuffer); + + + //Create material(s) + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = false; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + + WaterMaterialTemplate waterMaterialTemplate; + waterMaterialTemplate.color = color; + waterMaterialTemplate.liquidFlags = liquidFlags; + + if (basetextureFDID != 0) { + auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); + waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); + } else { + waterMaterialTemplate.texture = m_api->hDevice->getBlackTexturePixel(); + } + auto waterMaterial = sceneRenderer->createWaterMaterial(m_waterPlacementChunk, pipelineTemplate, waterMaterialTemplate); + + m_liquidMaterials.push_back(waterMaterial); + + //Create mesh(es) + for (int i = 0; i < m_liquidMaterials.size(); i++) { + gMeshTemplate meshTemplate(vertexWaterBufferBindings); + meshTemplate.meshType = MeshType::eWmoMesh; + + meshTemplate.start = 0; + meshTemplate.end = indexBuffer.size(); + + auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); + m_liquidMeshes.push_back(mesh); + } +} + +void +LiquidInstance::getInfoFromDatabase(const SMLiquidInstance &liquidInstance, int &basetextureFDID, mathfu::vec3 &color, + int &liquidFlags, int &liquidVertexFormat, bool &generateTexCoordsFromPos) { + basetextureFDID= 0; + color= mathfu::vec3(0, 0, 0); + liquidFlags= 0; + liquidVertexFormat= 0; + generateTexCoordsFromPos= false; + mathfu::vec3 minimapStaticCol = {0, 0, 0}; + if (basetextureFDID == 0 && (m_api->databaseHandler != nullptr)) { + if (liquidInstance.liquid_object_or_lvf > 41) { + liquidVertexFormat = 2; + std::vector liqMats; + m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liqMats); + for (auto &liqMat : liqMats) { + if (liqMat.FileDataId != 0) { + basetextureFDID = liqMat.FileDataId; + if (liqMat.color1[0] > 0 || liqMat.color1[1] > 0 || liqMat.color1[2] > 0) { + color = mathfu::vec3(liqMat.color1[2], liqMat.color1[1], liqMat.color1[0]); + } + minimapStaticCol = mathfu::vec3(liqMat.minimapStaticCol[2], liqMat.minimapStaticCol[1], liqMat.minimapStaticCol[0]); + + liquidFlags = liqMat.flags; + liquidVertexFormat = liqMat.LVF; + generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, + liquidInstance.liquid_type, + liqMat.materialId, + liqMat.flowSpeed <=0).generateTexCoordsFromPos; + + break; + } + } + } else { + liquidVertexFormat = liquidInstance.liquid_object_or_lvf; + std::vector liquidTypeData; + m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liquidTypeData); + for (auto ltd: liquidTypeData) { + if (ltd.FileDataId != 0) { + basetextureFDID = ltd.FileDataId; + + if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { + color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); + } + minimapStaticCol = mathfu::vec3(ltd.minimapStaticCol[2], ltd.minimapStaticCol[1], ltd.minimapStaticCol[0]); + liquidFlags = ltd.flags; + liquidVertexFormat = ltd.LVF; + + generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, + liquidInstance.liquid_type, + ltd.materialId, + usePlanarMapLiquidObject.generateTexCoordsFromPos).generateTexCoordsFromPos; + break; + } + } + } + } +} + +HGVertexBufferBindings LiquidInstance::createLiquidVao(const HMapSceneBufferCreate &sceneRenderer, + std::vector &vertexBuffer, + std::vector &indexBuffer) const { + auto waterIBO = sceneRenderer->createWaterIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); + waterIBO->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + auto waterVBO = sceneRenderer->createWaterVertexBuffer(vertexBuffer.size() * sizeof(LiquidVertexFormat)); + waterVBO->uploadData( + vertexBuffer.data(), + vertexBuffer.size() * sizeof(LiquidVertexFormat) + ); + + + auto vertexWaterBufferBindings = sceneRenderer->createWaterVAO(waterVBO, waterIBO); + return vertexWaterBufferBindings; +} + +void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, const mathfu::vec3 &liquidBasePos, + const PointerChecker &mH2OBlob, CAaBox &waterAaBB, + int liquidVertexFormat, bool generateTexCoordsFromPos, + std::vector &vertexBuffer, + std::vector &indexBuffer) const { + if (!liquidInstance.offset_vertex_data && liquidInstance.liquid_type != 2) { + liquidVertexFormat = 2; + } + + float *vertexDataPtr = nullptr; + if (liquidInstance.offset_vertex_data != 0) { + vertexDataPtr = ((float *) (&mH2OBlob[liquidInstance.offset_vertex_data])); + } + + //Set iteration restrictions for triangles + int y_begin = 0; + int x_begin = 0; + int x_end = 8; + int y_end = 8; + int totalCount = 9 * 9; + if (liquidInstance.liquid_object_or_lvf <= 41) { + x_begin = liquidInstance.x_offset; + y_begin = liquidInstance.y_offset; + x_end = liquidInstance.x_offset + liquidInstance.width; + y_end = liquidInstance.y_offset + liquidInstance.height; + + totalCount = (liquidInstance.width + 1) * (liquidInstance.height + 1) ; + } + + float minX = 999999; + float maxX = -999999; + float minY = 999999; + float maxY = -999999; + float minZ = 999999; + float maxZ = -999999; + + minX = std::min(minX, waterAaBB.min.x); + maxX = std::max(maxX, waterAaBB.max.x); + minY = std::min(minY, waterAaBB.min.y); + maxY = std::max(maxY, waterAaBB.max.y); + minZ = std::min(minZ, waterAaBB.min.z); + maxZ = std::max(maxZ, waterAaBB.max.z); + + //Parse the blob + for (int y = 0; y < liquidInstance.height + 1; y++) { + for (int x = 0; x < liquidInstance.width + 1; x++) { + mathfu::vec3 pos = + liquidBasePos - + mathfu::vec3( + MathHelper::UNITSIZE*(y+liquidInstance.y_offset), + MathHelper::UNITSIZE*(x+liquidInstance.x_offset), + -liquidInstance.min_height_level + ); + + mathfu::vec2 uv = mathfu::vec2(0,0); + if (vertexDataPtr!= nullptr) { + pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); + } + +// if (std::isnan(pos.z) || (pos.z > 10000.0f)) { +// pos.z = liquidInstance.min_height_level; +// } + + if (generateTexCoordsFromPos) { + uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); + } else { + uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); + } + + minX = std::min(minX, pos.x); maxX = std::max(maxX, pos.x); + minY = std::min(minY, pos.y); maxY = std::max(maxY, pos.y); + minZ = std::min(minZ, pos.z); maxZ = std::max(maxZ, pos.z); + + LiquidVertexFormat vertex; + vertex.pos_transp = mathfu::vec4(pos, 1.0); + vertex.uv = uv; + + vertexBuffer.push_back(vertex); + } + } + waterAaBB = CAaBox( + C3Vector(mathfu::vec3(minX, minY, minZ)), + C3Vector(mathfu::vec3(maxX, maxY, maxZ)) + ); + + uint8_t *existsTable = getLiquidExistsTable(mH2OBlob, liquidInstance); + + for (int y = y_begin; y < y_end; y++) { + for (int x = x_begin; x < x_end; x++) { + + int maskIndex = (y - y_begin) * (x_end - x_begin) + (x - x_begin); + bool exists = (existsTable[maskIndex >> 3] >> ((maskIndex & 7))) & 1; + + if (!exists) continue; + + const int16_t vertIndexes[4] = { + (int16_t) (y * (liquidInstance.width + 1 ) + x), + (int16_t) (y * (liquidInstance.width + 1) + x + 1), + (int16_t) ((y + 1) * (liquidInstance.width + 1) + x), + (int16_t) ((y + 1) * (liquidInstance.width + 1) + x + 1), + }; + + indexBuffer.push_back (vertIndexes[0]); + indexBuffer.push_back (vertIndexes[1]); + indexBuffer.push_back (vertIndexes[2]); + + indexBuffer.push_back (vertIndexes[1]); + indexBuffer.push_back (vertIndexes[3]); + indexBuffer.push_back (vertIndexes[2]); + } + } +} + +void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDependantData, IMapApi *mapApi) { + for (auto &waterMaterial : m_liquidMaterials) { + auto &waterChunk = waterMaterial->m_materialPS->getObject(); + if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean + waterChunk.color = frameDependantData->closeOceanColor; + } else if (waterMaterial->liquidFlags == 15) { //River/Lake + //Query river color + mathfu::vec3 closeRiverColor = {0, 0, 0}; + if (m_api->getConfig()->useCloseRiverColorForDB) { + + mathfu::vec3 waterPos = (mathfu::vec3(m_waterBBox.max) + mathfu::vec3(m_waterBBox.min)) / 2.0f; + bool waterColorFound = true; + if (m_api->getConfig()->colorOverrideHolder != nullptr) { + waterColorFound = false; +// int adt_global_x = worldCoordinateToGlobalAdtChunk(waterPos.y) % 16; +// int adt_global_y = worldCoordinateToGlobalAdtChunk(waterPos.x) % 16; +// +// auto areaId = getAreaId(adt_global_x, adt_global_y); + + for (auto &riverOverride : *m_api->getConfig()->colorOverrideHolder) { + if (riverOverride.liquidObjectId == liquid_object_or_lvf) { + closeRiverColor = riverOverride.color.xyz(); + waterColorFound = true; + break; + } + } + } + if (!waterColorFound) { + std::vector lightResults = {}; + mapApi->getLightResultsFromDB(waterPos, m_api->getConfig(), lightResults, nullptr); + for (auto &_light : lightResults) { + closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; + } + closeRiverColor = mathfu::vec3(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0]); + } + } + + waterChunk.color = frameDependantData->closeRiverColor; + } else { + waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); + } + + auto time = mapApi->getCurrentSceneTime(); + + waterMaterial->m_materialPS->save(); + } +} + +void LiquidInstance::collectMeshes(std::vector &transparentMeshes) { + //TODO: Get time and right mesh instance for animation + transparentMeshes.push_back(m_liquidMeshes[0]); +} diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h new file mode 100644 index 000000000..2a7536eef --- /dev/null +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -0,0 +1,49 @@ +// +// Created by Deamon on 5/20/2023. +// + +#ifndef AWEBWOWVIEWERCPP_LIQUIDINSTANCE_H +#define AWEBWOWVIEWERCPP_LIQUIDINSTANCE_H + + +#include "../../ApiContainer.h" +#include "../iMapApi.h" + +class LiquidInstance { +public: + LiquidInstance(const HApiContainer &api, + const HMapSceneBufferCreate &sceneRenderer, + const SMLiquidInstance &liquidInstance, + std::shared_ptr> &waterPlacementChunk, + const mathfu::vec3 &liquidBasePos, + const PointerChecker &mH2OBlob, CAaBox &waterBBox); + + void updateLiquidMaterials(const HFrameDependantData &frameDependantData, IMapApi *mapApi); + void collectMeshes(std::vector &transparentMeshes); +private: + const HApiContainer &m_api; + const HMapSceneBufferCreate &m_sceneRenderer; + const std::shared_ptr> m_waterPlacementChunk; + std::vector> m_liquidMaterials; + std::vector m_liquidMeshes; + CAaBox &m_waterBBox; + + uint16_t liquid_object_or_lvf; + + void createAdtVertexData(const SMLiquidInstance &liquidInstance, const mathfu::vec3 &liquidBasePos, + const PointerChecker &mH2OBlob, CAaBox &waterAaBB, int liquidVertexFormat, + bool generateTexCoordsFromPos, std::vector &vertexBuffer, + std::vector &indexBuffer) const; + + HGVertexBufferBindings + createLiquidVao(const HMapSceneBufferCreate &sceneRenderer, std::vector &vertexBuffer, + std::vector &indexBuffer) const; + + void + getInfoFromDatabase(const SMLiquidInstance &liquidInstance, int &basetextureFDID, mathfu::vec3 &color, + int &liquidFlags, + int &liquidVertexFormat, bool &generateTexCoordsFromPos); +}; + + +#endif //AWEBWOWVIEWERCPP_LIQUIDINSTANCE_H From b87dc566ce4a4545ab7ac2177ac714e42160bad9 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 24 May 2023 14:33:57 +0300 Subject: [PATCH 073/212] water data is properly read for ADT from DB and files --- src/database/CEmptySqliteDB.h | 4 +- src/database/CSqliteDB.cpp | 174 ++++++++++-------- src/database/CSqliteDB.h | 38 +++- .../src/engine/camera/firstPersonCamera.cpp | 2 - .../engine/objects/liquid/LiquidDataGetters.h | 2 +- .../engine/objects/liquid/LiquidInstance.cpp | 87 ++++----- .../engine/objects/liquid/LiquidInstance.h | 3 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 32 ++-- wowViewerLib/src/include/config.h | 1 + wowViewerLib/src/include/database/dbStructs.h | 59 +++--- wowViewerLib/src/include/databaseHandler.h | 4 +- 11 files changed, 223 insertions(+), 183 deletions(-) diff --git a/src/database/CEmptySqliteDB.h b/src/database/CEmptySqliteDB.h index 3826e9964..b9f12b6a2 100644 --- a/src/database/CEmptySqliteDB.h +++ b/src/database/CEmptySqliteDB.h @@ -16,8 +16,8 @@ class CEmptySqliteDB : public IClientDatabase { AreaRecord getWmoArea(int wmoId, int nameId, int groupId) override { return {}; }; void getLightById(int lightId, int time, LightResult &lightResult) override {}; void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) override {}; - void getLiquidObjectData(int liquidObjectId, std::vector &loData) override {}; - void getLiquidTypeData(int liquidTypeId, std::vector &liquidTypeData) override {}; + void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; + void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; void getZoneLightsForMap(int mapId, std::vector &zoneLights) override {}; }; diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 6ec58a37a..60d0cf6c4 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -100,31 +100,36 @@ const std::string lightDataSQL = R"===( )==="; const std::string liquidObjectInfoSQL = R"===( - select ltxt.FileDataID, lm.LVF, ltxt.OrderIndex, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lo.FlowSpeed, lt.MaterialID from LiquidObject lo - left join LiquidTypeXTexture ltxt on ltxt.LiquidTypeID = lo.LiquidTypeID - left join LiquidType lt on lt.ID = lo.LiquidTypeID - left join LiquidMaterial lm on lt.MaterialID = lm.ID - where lo.ID = ? - )==="; - -const std::string liquidObjectInfoSQL_classic = R"===( - select lt.Texture_0, lm.LVF, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lo.FlowSpeed, lt.MaterialID from LiquidObject lo - left join LiquidType lt on lt.ID = lo.LiquidTypeID - left join LiquidMaterial lm on lt.MaterialID = lm.ID - where lo.ID = ? + select lo.LiquidTypeID, lo.FlowDirection, lo.FlowSpeed, lo.Reflection from LiquidObject lo + where lo.ID = ?; )==="; const std::string liquidTypeSQL = R"===( - select ltxt.FileDataID, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF, lt.MaterialID from LiquidType lt - left join LiquidTypeXTexture ltxt on ltxt.LiquidTypeID = lt.ID - left join LiquidMaterial lm on lt.MaterialID = lm.ID - where lt.ID = ? order by ltxt.OrderIndex - )==="; -const std::string liquidTypeSQL_classic = R"===( - select lt.Texture_0, lt.Color_0, lt.Color_1, lt.Flags, lt.MinimapStaticCol, lm.LVF, lt.MaterialID from LiquidType lt - left join LiquidMaterial lm on lt.MaterialID = lm.ID - where lt.ID = ? - )==="; + select + lt.Texture_0, lt.Texture_1, lt.Texture_2, lt.Texture_3, lt.Texture_4, lt.Texture_5, + lt.Flags, lt.SpellID, lt.LightID, + lt.MaterialID, + lt.MinimapStaticCol, + lt.FrameCountTexture_0, lt.FrameCountTexture_1, lt.FrameCountTexture_2, lt.FrameCountTexture_3, + lt.FrameCountTexture_4, lt.FrameCountTexture_5, lt.Color_0, lt.Color_1, + lt.Float_0, lt.Float_1, lt.Float_2, lt.Float_3, lt.Float_4, lt.Float_5, lt.Float_6, lt.Float_7, + lt.Float_8, lt.Float_9, lt.Float_10, lt.Float_11, lt.Float_12, lt.Float_13, lt.Float_14, + lt.Float_15, lt.Float_16, lt.Float_17, + lt.Int_0, lt.Int_1, lt.Int_2, lt.Int_3, lt.Int_3, + lt.Coefficient_0, lt.Coefficient_1, lt.Coefficient_2, lt.Coefficient_3, + lm.Flags as MatFlag, + lm.LVF as MatLVF + from LiquidType lt + left join LiquidMaterial lm on lm.ID = lt.MaterialID + where lt.ID = ?; + )==="; + +const std::string liquidTextureFileDataIdsSQL = R"===( + select ltxt.FileDataID, ltxt.Type + from LiquidTypeXTexture ltxt + where ltxt.LiquidTypeID = ? + order by ltxt.OrderIndex; +)==="; CSqliteDB::CSqliteDB(std::string dbFileName) : m_sqliteDatabase(dbFileName, SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE), @@ -136,12 +141,9 @@ CSqliteDB::CSqliteDB(std::string dbFileName) : getLightByIdStatement(m_sqliteDatabase, getLightByIdSQL), getLightData(m_sqliteDatabase, lightDataSQL), - getLiquidObjectInfo(m_sqliteDatabase, - getHasLiquidTypeXTexture(m_sqliteDatabase) ? liquidObjectInfoSQL : liquidObjectInfoSQL_classic - ), - getLiquidTypeInfo(m_sqliteDatabase, - getHasLiquidTypeXTexture(m_sqliteDatabase) ? liquidTypeSQL : liquidTypeSQL_classic - ), + getLiquidObjectInfo(m_sqliteDatabase,liquidObjectInfoSQL), + getLiquidTypeInfo(m_sqliteDatabase, liquidTypeSQL), + getLiquidTextureFileDataIds(m_sqliteDatabase, getHasLiquidTypeXTexture(m_sqliteDatabase) ? liquidTextureFileDataIdsSQL : "select 1 from Map;"), getZoneLightInfo(m_sqliteDatabase, "select ID, Name, LightID, Zmin, Zmax from ZoneLight where MapID = ?" ), @@ -640,71 +642,89 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector } } -void CSqliteDB::getLiquidObjectData(int liquidObjectId, std::vector &loData) { +void CSqliteDB::getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) { getLiquidObjectInfo.setInputs( liquidObjectId ); - bool hasFileDataId = getLiquidObjectInfo.getFieldIndex("FileDataID") >= 0; + if (getLiquidObjectInfo.execute()) { - while (getLiquidObjectInfo.execute()) { - LiquidMat &lm = loData.emplace_back(); + loData.liquidTypeId = getLiquidObjectInfo.getField("LiquidTypeID").getInt(); + loData.flowDirection = getLiquidObjectInfo.getField("FlowDirection").getDouble(); + loData.flowSpeed = getLiquidObjectInfo.getField("FlowSpeed").getDouble(); + loData.reflection = getLiquidObjectInfo.getField("Reflection").getInt() > 0; - if (hasFileDataId) { - lm.FileDataId = getLiquidObjectInfo.getField("FileDataID").getInt(); - lm.OrderIndex = getLiquidObjectInfo.getField("OrderIndex").getInt(); - } else { - lm.texture0Pattern = getLiquidObjectInfo.getField("Texture_0").getInt(); - } + getLiquidTypeData(loData.liquidTypeId, loData, textures); + + return; + } else { + loData.liquidTypeId = fallbackliquidTypeId; + getLiquidTypeData(fallbackliquidTypeId, loData, textures); - lm.LVF = getLiquidObjectInfo.getField("LVF").getInt(); - lm.flowSpeed = getLiquidObjectInfo.getField("FlowSpeed").getDouble(); - lm.materialId = getLiquidObjectInfo.getField("MaterialID").getInt(); - int color1 = getLiquidObjectInfo.getField("Color_0").getInt(); - lm.color1[0] = getFloatFromInt<0>(color1); - lm.color1[1] = getFloatFromInt<1>(color1); - lm.color1[2] = getFloatFromInt<2>(color1); - int color2 = getLiquidObjectInfo.getField("Color_1").getInt(); - lm.color2[0] = getFloatFromInt<0>(color2); - lm.color2[1] = getFloatFromInt<1>(color2); - lm.color2[2] = getFloatFromInt<2>(color2); - lm.flags = getLiquidObjectInfo.getField("Flags").getInt(); - int minimapStaticCol = getLiquidObjectInfo.getField("MinimapStaticCol").getInt(); - lm.minimapStaticCol[0] = getFloatFromInt<0>(minimapStaticCol); - lm.minimapStaticCol[1] = getFloatFromInt<1>(minimapStaticCol); - lm.minimapStaticCol[2] = getFloatFromInt<2>(minimapStaticCol); } -} -void CSqliteDB::getLiquidTypeData(int liquidTypeId, std::vector &liquidTypeData) { - getLiquidTypeInfo.setInputs( liquidTypeId ); +}; +void CSqliteDB::getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) { + getLiquidTypeInfo.setInputs(liquidTypeId); + while (getLiquidTypeInfo.execute()) { - bool hasFileDataId = getLiquidObjectInfo.getFieldIndex("FileDataID") >= 0; + for (int i = 0; i < loData.texture.size(); i++) { + HashedString fieldHash = HashedString(("Texture_" + std::to_string(i)).c_str()); + loData.texture[i] = getLiquidTypeInfo.getField(fieldHash).getString(); + } + loData.flags = getLiquidTypeInfo.getField("Flags").getUInt(); + loData.spellID = getLiquidTypeInfo.getField("SpellID").getUInt(); + loData.lightID = getLiquidTypeInfo.getField("SpellID").getUInt(); + loData.materialID = getLiquidTypeInfo.getField("MaterialID").getUInt(); - while (getLiquidTypeInfo.execute()) { - LiquidTypeData <d = liquidTypeData.emplace_back(); + int minimapStaticCol = getLiquidTypeInfo.getField("MinimapStaticCol").getInt(); + loData.minimapStaticCol[0] = getFloatFromInt<0>(minimapStaticCol); + loData.minimapStaticCol[1] = getFloatFromInt<1>(minimapStaticCol); + loData.minimapStaticCol[2] = getFloatFromInt<2>(minimapStaticCol); - if (hasFileDataId) { - ltd.FileDataId = getLiquidTypeInfo.getField("FileDataID").getInt(); - } else { - ltd.texture0Pattern = getLiquidTypeInfo.getField("Texture_0").getInt(); + for (int i = 0; i < loData.frameCountTexture.size(); i++) { + HashedString fieldHash = HashedString(("FrameCountTexture_" + std::to_string(i)).c_str()); + loData.frameCountTexture[i] = getLiquidTypeInfo.getField(fieldHash).getInt(); } - ltd.materialId = getLiquidTypeInfo.getField("MaterialID").getInt(); int color1 = getLiquidTypeInfo.getField("Color_0").getInt(); - ltd.color1[0] = getFloatFromInt<0>(color1); - ltd.color1[1] = getFloatFromInt<1>(color1); - ltd.color1[2] = getFloatFromInt<2>(color1); + loData.color1[0] = getFloatFromInt<0>(color1); + loData.color1[1] = getFloatFromInt<1>(color1); + loData.color1[2] = getFloatFromInt<2>(color1); int color2 = getLiquidTypeInfo.getField("Color_1").getInt(); - ltd.color2[0] = getFloatFromInt<0>(color2); - ltd.color2[1] = getFloatFromInt<1>(color2); - ltd.color2[2] = getFloatFromInt<2>(color2); - ltd.flags = getLiquidTypeInfo.getField("Flags").getInt(); - int minimapStaticCol = getLiquidTypeInfo.getField("MinimapStaticCol").getInt(); - ltd.minimapStaticCol[0] = getFloatFromInt<0>(minimapStaticCol); - ltd.minimapStaticCol[1] = getFloatFromInt<1>(minimapStaticCol); - ltd.minimapStaticCol[2] = getFloatFromInt<2>(minimapStaticCol); + loData.color2[0] = getFloatFromInt<0>(color2); + loData.color2[1] = getFloatFromInt<1>(color2); + loData.color2[2] = getFloatFromInt<2>(color2); + + for (int i = 0; i < loData.m_floats.size(); i++) { + HashedString fieldHash = HashedString(("Float_" + std::to_string(i)).c_str()); + loData.m_floats[i] = getLiquidTypeInfo.getField(fieldHash).getDouble(); + } + for (int i = 0; i < loData.m_int.size(); i++) { + HashedString fieldHash = HashedString(("Int_" + std::to_string(i)).c_str()); + loData.m_int[i] = getLiquidTypeInfo.getField(fieldHash).getInt(); + } - ltd.LVF = getLiquidTypeInfo.getField("LVF").getInt(); + for (int i = 0; i < loData.coefficient.size(); i++) { + HashedString fieldHash = HashedString(("Coefficient_" + std::to_string(i)).c_str()); + loData.coefficient[i] = getLiquidTypeInfo.getField(fieldHash).getDouble(); + } + + loData.matFlag = getLiquidTypeInfo.getField("MatFlag").getUInt(); + loData.matLVF = getLiquidTypeInfo.getField("MatLVF").getUInt(); + + getLiquidTexture(liquidTypeId, textures); + return; } +}; +void CSqliteDB::getLiquidTexture(int liquidTypeId, std::vector &textures) { + if (!getHasLiquidTypeXTexture(m_sqliteDatabase)) return; + + getLiquidTextureFileDataIds.setInputs(liquidTypeId); + + while (getLiquidTextureFileDataIds.execute()) { + auto <d = textures.emplace_back(); + ltd.fileDataId = getLiquidTextureFileDataIds.getField("FileDataID").getInt(); + ltd.type = getLiquidTextureFileDataIds.getField("Type").getInt(); + } } void CSqliteDB::getZoneLightsForMap(int mapId, std::vector &zoneLights) { diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index 29bc78daf..d540ef88e 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -6,6 +6,7 @@ #define AWEBWOWVIEWERCPP_CSQLITEDB_H #include +#include #include #include #include "../../wowViewerLib/src/include/databaseHandler.h" @@ -22,9 +23,11 @@ class CSqliteDB : public IClientDatabase { void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) override; void getLightById(int lightId, int time, LightResult &lightResult) override; - void getLiquidObjectData(int liquidObjectId, std::vector &loData) override; - void getLiquidTypeData(int liquidTypeId, std::vector &liquidTypeData) override; + void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; + void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; + void getLiquidTexture(int liquidTypeId, std::vector &textures); void getZoneLightsForMap(int mapId, std::vector &zoneLights) override; + private: class StatementFieldHolder { public: @@ -44,10 +47,34 @@ class CSqliteDB : public IClientDatabase { return -1; } } + template + inline void readArray(std::array &data, const std::function &fieldToValue) { + constexpr std::string_view fieldName = std::string(chars) + std::to_string(N); + constexpr const char *c_fieldName = fieldName.data(); + constexpr auto hashedString = HashedString(c_fieldName); + + data[N - 1] = fieldToValue(this->getField(hashedString)); + if constexpr (N > 0) { + this->readArray(data, fieldToValue); + } else { + this->readArrayZero(data, fieldToValue); + } + } private: SQLite::Statement m_query; std::unordered_map fieldToIndex; - }; + + + template + inline void readArrayZero(std::vector &data, const std::function &fieldToValue) { + constexpr std::string_view fieldName = std::string(chars...) + std::to_string(0); + constexpr const char *c_fieldName = fieldName.data(); + constexpr auto hashedString = HashedString(c_fieldName); + + data[0] = fieldToValue(this->getField(hashedString)); + } + + }; SQLite::Database m_sqliteDatabase; @@ -58,6 +85,7 @@ class CSqliteDB : public IClientDatabase { StatementFieldHolder getLightData; StatementFieldHolder getLiquidObjectInfo; StatementFieldHolder getLiquidTypeInfo; + StatementFieldHolder getLiquidTextureFileDataIds; StatementFieldHolder getZoneLightInfo; StatementFieldHolder getZoneLightPointsInfo; @@ -140,9 +168,7 @@ class CSqliteDB : public IClientDatabase { blendTwoAndAdd(LightResult &lightResult, const InnerLightDataRes &lastLdRes, const InnerLightDataRes &currLdRes, float timeAlphaBlend, float innerAlpha) const; -}; - - +}; #endif //AWEBWOWVIEWERCPP_CSQLITEDB_H diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index f7c6498cd..4f5dcda6d 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -92,8 +92,6 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { float depthDiff = (float) (dTime * moveSpeed * (this->MDDepthPlus - this->MDDepthMinus) + this->depthDiff); float verticalDiff = (float) (dTime * moveSpeed * (this->MDVerticalPlus - this->MDVerticalMinus)); - - this->depthDiff = 0; /* Calc look at position */ diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h b/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h index 335ff2812..a2364b2ae 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidDataGetters.h @@ -108,7 +108,7 @@ struct LiquidObjectSettings { }; const constexpr LiquidObjectSettings useTexCoordLiquidObject = { - .generateTexCoordsFromPos = false + .generateTexCoordsFromPos = false, }; const constexpr LiquidObjectSettings usePlanarMapLiquidObject = { .generateTexCoordsFromPos = true diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 9d561b185..b5d366ba6 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -16,7 +16,8 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, m_waterBBox(waterAaBB){ //Creating liquid instance from ADT data - liquid_object_or_lvf = liquidInstance.liquid_object_or_lvf; + liquid_object = liquidInstance.liquid_object_or_lvf >= 42 ? liquidInstance.liquid_object_or_lvf : 0; + liquidType = liquidInstance.liquid_type; //1. Get Data from DB int basetextureFDID; @@ -51,6 +52,8 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, waterMaterialTemplate.color = color; waterMaterialTemplate.liquidFlags = liquidFlags; + assert(liquidFlags >= 0 && liquidFlags <= 2063); + if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); @@ -72,6 +75,8 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); m_liquidMeshes.push_back(mesh); } + + assert(waterMaterial->liquidFlags >= 0 && waterMaterial->liquidFlags <= 2063); } void @@ -79,57 +84,43 @@ LiquidInstance::getInfoFromDatabase(const SMLiquidInstance &liquidInstance, int int &liquidFlags, int &liquidVertexFormat, bool &generateTexCoordsFromPos) { basetextureFDID= 0; color= mathfu::vec3(0, 0, 0); - liquidFlags= 0; - liquidVertexFormat= 0; + liquidFlags = 0; + liquidVertexFormat = 0; generateTexCoordsFromPos= false; mathfu::vec3 minimapStaticCol = {0, 0, 0}; - if (basetextureFDID == 0 && (m_api->databaseHandler != nullptr)) { - if (liquidInstance.liquid_object_or_lvf > 41) { - liquidVertexFormat = 2; - std::vector liqMats; - m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liqMats); - for (auto &liqMat : liqMats) { - if (liqMat.FileDataId != 0) { - basetextureFDID = liqMat.FileDataId; - if (liqMat.color1[0] > 0 || liqMat.color1[1] > 0 || liqMat.color1[2] > 0) { - color = mathfu::vec3(liqMat.color1[2], liqMat.color1[1], liqMat.color1[0]); - } - minimapStaticCol = mathfu::vec3(liqMat.minimapStaticCol[2], liqMat.minimapStaticCol[1], liqMat.minimapStaticCol[0]); + if (m_api->databaseHandler != nullptr) { + LiquidTypeAndMat liqMatAndType; + std::vector liquidTextureData; - liquidFlags = liqMat.flags; - liquidVertexFormat = liqMat.LVF; - generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, - liquidInstance.liquid_type, - liqMat.materialId, - liqMat.flowSpeed <=0).generateTexCoordsFromPos; + if (liquidInstance.liquid_object_or_lvf > 41) { - break; - } + m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liquidInstance.liquid_type, liqMatAndType, liquidTextureData); + //From Liquid::GetVertexFormat + if (liquidInstance.liquid_type == 2) { + liquidVertexFormat = 2; } } else { liquidVertexFormat = liquidInstance.liquid_object_or_lvf; - std::vector liquidTypeData; - m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liquidTypeData); - for (auto ltd: liquidTypeData) { - if (ltd.FileDataId != 0) { - basetextureFDID = ltd.FileDataId; - - if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { - color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); - } - minimapStaticCol = mathfu::vec3(ltd.minimapStaticCol[2], ltd.minimapStaticCol[1], ltd.minimapStaticCol[0]); - liquidFlags = ltd.flags; - liquidVertexFormat = ltd.LVF; - - generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, - liquidInstance.liquid_type, - ltd.materialId, - usePlanarMapLiquidObject.generateTexCoordsFromPos).generateTexCoordsFromPos; - break; - } - } + m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liqMatAndType, liquidTextureData); + + assert(liquidInstance.liquid_object_or_lvf == liqMatAndType.matLVF); + } + basetextureFDID = liquidTextureData.size() > 0 ? liquidTextureData[0].fileDataId : 0; + if (liqMatAndType.color1[0] > 0 || liqMatAndType.color1[1] > 0 || liqMatAndType.color1[2] > 0) { + color = mathfu::vec3(liqMatAndType.color1[2], liqMatAndType.color1[1], liqMatAndType.color1[0]); } + minimapStaticCol = mathfu::vec3(liqMatAndType.minimapStaticCol[2], liqMatAndType.minimapStaticCol[1], liqMatAndType.minimapStaticCol[0]); + + liquidFlags = liqMatAndType.flags; +// assert(liquidVertexFormat == liqMatAndType.matLVF); +// liquidVertexFormat = liqMatAndType.matLVF; + generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, + liquidInstance.liquid_type, + liqMatAndType.materialID, + liqMatAndType.flowSpeed <=0).generateTexCoordsFromPos; } + + assert(liquidFlags >= 0 && liquidFlags <= 2063); } HGVertexBufferBindings LiquidInstance::createLiquidVao(const HMapSceneBufferCreate &sceneRenderer, @@ -208,10 +199,6 @@ void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, pos.z = getLiquidVertexHeight(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } -// if (std::isnan(pos.z) || (pos.z > 10000.0f)) { -// pos.z = liquidInstance.min_height_level; -// } - if (generateTexCoordsFromPos) { uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); } else { @@ -276,13 +263,9 @@ void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDepen bool waterColorFound = true; if (m_api->getConfig()->colorOverrideHolder != nullptr) { waterColorFound = false; -// int adt_global_x = worldCoordinateToGlobalAdtChunk(waterPos.y) % 16; -// int adt_global_y = worldCoordinateToGlobalAdtChunk(waterPos.x) % 16; -// -// auto areaId = getAreaId(adt_global_x, adt_global_y); for (auto &riverOverride : *m_api->getConfig()->colorOverrideHolder) { - if (riverOverride.liquidObjectId == liquid_object_or_lvf) { + if (riverOverride.liquidObjectId == liquid_object || riverOverride.liquidType == liquidType) { closeRiverColor = riverOverride.color.xyz(); waterColorFound = true; break; diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index 2a7536eef..b84440d0e 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -28,7 +28,8 @@ class LiquidInstance { std::vector m_liquidMeshes; CAaBox &m_waterBBox; - uint16_t liquid_object_or_lvf; + uint16_t liquid_object; + uint32_t liquidType; void createAdtVertexData(const SMLiquidInstance &liquidInstance, const mathfu::vec3 &liquidBasePos, const PointerChecker &mH2OBlob, CAaBox &waterAaBB, int liquidVertexFormat, diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 2c09228b8..f3d792482 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -259,29 +259,29 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; - std::vector liquidTypeData; + + int waterMaterialId = 0; + int basetextureFDID = 0; if (m_api->databaseHandler != nullptr) { - m_api->databaseHandler->getLiquidTypeData(static_cast(this->liquid_type), liquidTypeData); +// m_api->databaseHandler->getLiquidTypeData(static_cast(this->liquid_type), liquidTypeData); +// for (auto ltd: liquidTypeData) { +// if (ltd.FileDataId != 0) { +// basetextureFDID = ltd.FileDataId; +// +// if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { +// waterMaterialTemplate.color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); +// } +// waterMaterialTemplate.liquidFlags = ltd.flags; +// waterMaterialId = ltd.materialId; +// break; +// } +// } } waterMaterialTemplate.color = mathfu::vec3(0,0,0); waterMaterialTemplate.liquidFlags = 0; - int waterMaterialId = 0; - for (auto ltd: liquidTypeData) { - if (ltd.FileDataId != 0) { - basetextureFDID = ltd.FileDataId; - - if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { - waterMaterialTemplate.color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); - } - waterMaterialTemplate.liquidFlags = ltd.flags; - waterMaterialId = ltd.materialId; - break; - } - } - if (basetextureFDID != 0) { auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index e614ac1dc..014ba30b6 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -13,6 +13,7 @@ struct RiverColorOverride { int liquidObjectId; + int liquidType; mathfu::vec4 color = {0,0,0,0}; }; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 5d66a7a15..51753ff15 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -59,32 +59,43 @@ struct LightResult { bool isDefault = false; }; -struct LiquidMat { - int FileDataId; - std::string texture0Pattern; - int materialId; - int scrollSpeedX; - int scrollSpeedY; - int LVF; - float flowSpeed; - int OrderIndex; - float color1[3]; - float color2[3]; - int flags; - std::array minimapStaticCol; +struct LiquidTextureData { + int fileDataId; + int type; }; -struct LiquidTypeData { - int FileDataId; - std::string texture0Pattern; - int materialId; - int scrollSpeedX; - int scrollSpeedY; - float color1[3]; - float color2[3]; - int flags; - int LVF; - std::array minimapStaticCol; +struct LiquidTypeAndMat { + int liquidTypeId; + std::string name; + std::array texture; + uint16_t flags; +// uint8_t soundBank; +// uint32_t SoundID; + uint32_t spellID; +// float maxDarkenDepth; +// float fogDarkenIntensity; +// float ambDarkenIntensity; +// float dirDarkenIntensity; + uint16_t lightID; +// float particleScale; +// uint8_t particleMovement; +// uint8_t particleTexSlots; + uint8_t materialID; + std::array minimapStaticCol; + std::array frameCountTexture; + std::array color1; + std::array color2; + std::array m_floats; + std::array m_int; + std::array coefficient; + + uint8_t matFlag; + uint8_t matLVF; + + float flowSpeed = 0.0f; + float flowDirection = 0.0f; + bool fishable = false; + bool reflection = false; }; struct vec2 { diff --git a/wowViewerLib/src/include/databaseHandler.h b/wowViewerLib/src/include/databaseHandler.h index 17ce655be..f66f6b838 100644 --- a/wowViewerLib/src/include/databaseHandler.h +++ b/wowViewerLib/src/include/databaseHandler.h @@ -17,8 +17,8 @@ class IClientDatabase { virtual AreaRecord getWmoArea(int wmoId, int nameId, int groupId) = 0; virtual void getLightById(int lightId, int time, LightResult &lightResult) = 0; virtual void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) = 0; - virtual void getLiquidObjectData(int liquidObjectId, std::vector &loData) = 0; - virtual void getLiquidTypeData(int liquidTypeId, std::vector &liquidTypeData) =0; + virtual void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; + virtual void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; virtual void getZoneLightsForMap(int mapId, std::vector &zoneLights) = 0; }; From fce08f12c3616d28409a7b577d8654a465569cb3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 31 May 2023 11:06:56 +0300 Subject: [PATCH 074/212] liquids from WMO and ADT being served from the same pipeline --- 3rdparty/DBImporter | 2 +- .../glsl/forwardRendering/m2Shader.vert | 14 +- .../glsl/forwardRendering/waterShader.frag | 54 +- .../src/engine/geometry/wmoGroupGeom.cpp | 24 +- .../src/engine/geometry/wmoGroupGeom.h | 2 +- .../src/engine/objects/adt/adtObject.cpp | 2 +- .../engine/objects/liquid/LiquidInstance.cpp | 155 ++- .../engine/objects/liquid/LiquidInstance.h | 28 +- .../src/engine/objects/m2/m2Object.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 85 +- .../src/engine/objects/wmo/wmoGroupObject.h | 8 +- .../src/engine/shader/ShaderDefinitions.h | 1020 +++++++++-------- .../src/gapi/UniformBufferStructures.h | 5 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 1 + .../src/gapi/vulkan/buffers/GBufferVLK.h | 1 + .../CommandBufferRecorder.cpp | 2 +- wowViewerLib/src/include/database/dbStructs.h | 4 +- .../mapScene/materials/IMaterialStructs.h | 3 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 36 +- 20 files changed, 750 insertions(+), 700 deletions(-) diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index 7188c49c3..dfb3aef49 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit 7188c49c3a3ce1c309f71125876b60978b9ce213 +Subproject commit dfb3aef491c3cc0cc2d21d385b71727e5b2d25e2 diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index f60ddf435..a55f02f08 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -72,11 +72,15 @@ void main() { vec4 aPositionVec4 = vec4(aPosition, 1); mat4 boneTransformMat = mat4(0.0); -// - boneTransformMat += (boneWeights.x ) * uBoneMatrixes[bones.x]; - boneTransformMat += (boneWeights.y ) * uBoneMatrixes[bones.y]; - boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; - boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; + if (dot(boneWeights, boneWeights) > 0) { + // + boneTransformMat += (boneWeights.x) * uBoneMatrixes[bones.x]; + boneTransformMat += (boneWeights.y) * uBoneMatrixes[bones.y]; + boneTransformMat += (boneWeights.z) * uBoneMatrixes[bones.z]; + boneTransformMat += (boneWeights.w) * uBoneMatrixes[bones.w]; + } else { + boneTransformMat = mat4(1.0); + } mat4 placementMat; placementMat = uPlacementMat; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index f7b398615..8cbbd31fe 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -23,8 +23,9 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { //Individual meshes layout(std140, binding=4) uniform meshWideBlockPS { - //ivec4 waterTypeV; + ivec4 materialId; vec4 color; + mat4 textureMatrix; }; const InteriorLightParam intLight = { @@ -33,26 +34,45 @@ const InteriorLightParam intLight = { }; void main() { - vec3 matDiffuse = color.rgb+texture(uTexture, vTextCoords).rgb; +// MaterialId: +// 1,3 - Water +// 2,4 - Magma +// 5 - Mercury, +// 10 - Fog +// 12 - LeyLine +// 13 - Fel +// 14 - Swamp +// 18 - Azerithe +// 8 - is probably debug material called Grid + + + vec2 animatedUV = (textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; + + vec3 matDiffuse = color.rgb+texture(uTexture, animatedUV).rgb; vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - vec4 finalColor = vec4( - calcLight( - matDiffuse, - vNormal, - true, - 0, - scene, - intLight, - vec3(0.0) /*accumLight*/, - vec3(0.0), - vec3(0.0), /* specular */ - vec3(0.0) - ), - 1.0 - ); + vec4 finalColor = vec4(matDiffuse, 1.0); + + //Magma is not affected by light + if (materialId.x != 2 && materialId.x != 4) { + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + 0, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vec3(0.0), + vec3(0.0), /* specular */ + vec3(0.0) + ), + 1.0 + ); + } //BlendMode is always GxBlend_Alpha finalColor.rgb = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, 2).rgb; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index e286c1af2..7163ad2df 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -422,10 +422,20 @@ LiquidTypes WmoGroupGeom::getLegacyWaterType(int a) { return static_cast(a); } -HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type) { +HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type, CAaBox &waterAaBB) { if (vertexWaterBufferBindings == nullptr) { + waterAaBB.min = mathfu::vec3(99999,99999,99999); + waterAaBB.max = mathfu::vec3(-99999,-99999,-99999); + if (this->m_mliq == nullptr) return nullptr; + float minX = 999999; + float maxX = -999999; + float minY = 999999; + float maxY = -999999; + float minZ = 999999; + float maxZ = -999999; + //Make Index Buffer std::vector iboBuffer; iboBuffer.reserve(m_mliq->ytiles*m_mliq->xtiles); @@ -471,7 +481,7 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBuffe for (int i = 0; i < m_mliq->xverts; i++) { int p = j*m_mliq->xverts + i; - LiquidVertexFormat lvfVertex; + LiquidVertexFormat &lvfVertex = lVertices.emplace_back(); lvfVertex.pos_transp = mathfu::vec4_packed(mathfu::vec4( pos.x + (MathHelper::UNITSIZE * i), pos.y + (MathHelper::UNITSIZE * j), @@ -488,10 +498,18 @@ HGVertexBufferBindings WmoGroupGeom::getWaterVertexBindings(const HMapSceneBuffe lvfVertex.pos_transp.y / (1600.0 / 3.0 / 16.0)); } - lVertices.push_back(lvfVertex); + minX = std::min(minX, lvfVertex.pos_transp.x); maxX = std::max(maxX, lvfVertex.pos_transp.x); + minY = std::min(minY, lvfVertex.pos_transp.y); maxY = std::max(maxY, lvfVertex.pos_transp.y); + minZ = std::min(minZ, lvfVertex.pos_transp.z); maxZ = std::max(maxZ, lvfVertex.pos_transp.z); } } + waterAaBB = CAaBox( + C3Vector(mathfu::vec3(minX, minY, minZ)), + C3Vector(mathfu::vec3(maxX, maxY, maxZ)) + ); + + waterIBO = sceneRenderer->createWaterIndexBuffer(iboBuffer.size() * sizeof(uint16_t)); waterIBO->uploadData( &iboBuffer[0], diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index e500cace3..64e64850f 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -44,7 +44,7 @@ class WmoGroupGeom : public PersistentFile { HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient); - HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type); + HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type, CAaBox &waterAaBB); int getFileDataId() const {return m_fileDataId;} const std::string &getFileName() const {return m_fileName;} diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 7cfa332f7..39c5d8a68 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -657,7 +657,7 @@ void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependant } for(auto &liquidInstance : m_liquidInstances) { - liquidInstance->updateLiquidMaterials(frameDependantData, m_mapApi); + liquidInstance->updateLiquidMaterials(frameDependantData, m_mapApi->getCurrentSceneTime()); } } diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index b5d366ba6..42fe26479 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -5,42 +5,70 @@ #include "LiquidInstance.h" #include "LiquidDataGetters.h" #include "../../algorithms/mathHelper.h" +#include "../iMapApi.h" LiquidInstance::LiquidInstance(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, const SMLiquidInstance &liquidInstance, - std::shared_ptr> &waterPlacementChunk, + const std::shared_ptr> &waterPlacementChunk, const mathfu::vec3 &liquidBasePos, const PointerChecker &mH2OBlob, CAaBox &waterAaBB) : - m_api(api), m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), - m_waterBBox(waterAaBB){ + m_api(api), m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), + m_waterBBox(waterAaBB){ //Creating liquid instance from ADT data liquid_object = liquidInstance.liquid_object_or_lvf >= 42 ? liquidInstance.liquid_object_or_lvf : 0; liquidType = liquidInstance.liquid_type; //1. Get Data from DB - int basetextureFDID; - mathfu::vec3 color; - int liquidFlags; - int liquidVertexFormat; bool generateTexCoordsFromPos; - getInfoFromDatabase(liquidInstance, basetextureFDID, color, liquidFlags, - liquidVertexFormat, - generateTexCoordsFromPos); + + getInfoFromDatabase(liquidInstance.liquid_object_or_lvf, liquidInstance.liquid_type, generateTexCoordsFromPos); //2. Parse Vertex Data from ADT std::vector vertexBuffer; std::vector indexBuffer; - createAdtVertexData(liquidInstance, liquidBasePos, mH2OBlob, m_waterBBox, liquidVertexFormat, + createAdtVertexData(liquidInstance, liquidBasePos, mH2OBlob, m_waterBBox, m_liqMatAndType.matLVF, generateTexCoordsFromPos, vertexBuffer, indexBuffer); HGVertexBufferBindings vertexWaterBufferBindings = createLiquidVao(sceneRenderer, vertexBuffer, indexBuffer); + createMaterialAndMesh(sceneRenderer, indexBuffer.size(), vertexWaterBufferBindings); +} +LiquidInstance::LiquidInstance(const HApiContainer &api, + const HMapSceneBufferCreate &sceneRenderer, + const HGVertexBufferBindings &binding, + int liquidType, + int indexBufferSize, + const std::shared_ptr> &waterPlacementChunk, + CAaBox &waterAaBB): m_api(api), + m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), m_waterBBox(waterAaBB){ + bool generateTexCoordsFromPos; + getInfoFromDatabase(0, + liquidType, + generateTexCoordsFromPos); + + createMaterialAndMesh(sceneRenderer, indexBufferSize, binding); +} + +void LiquidInstance::createMaterialAndMesh(const HMapSceneBufferCreate &sceneRenderer, + int indexBufferSize, + const HGVertexBufferBindings &vertexWaterBufferBindings) { //Create material(s) + int basetextureFDID = m_liquidTextureData.size() > 0 ? m_liquidTextureData[0].fileDataId : 0; + + mathfu::vec3 color = mathfu::vec3(0,0,0); + if (m_liqMatAndType.color1[0] > 0 || m_liqMatAndType.color1[1] > 0 || m_liqMatAndType.color1[2] > 0) { + color = mathfu::vec3(m_liqMatAndType.color1[2], m_liqMatAndType.color1[1], m_liqMatAndType.color1[0]); + } +// minimapStaticCol = mathfu::vec3(liqMatAndType.minimapStaticCol[2], liqMatAndType.minimapStaticCol[1], liqMatAndType.minimapStaticCol[0]); + + int liquidFlags = m_liqMatAndType.flags; + int liquidMaterialId = m_liqMatAndType.materialID; + PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = false; @@ -51,6 +79,9 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, WaterMaterialTemplate waterMaterialTemplate; waterMaterialTemplate.color = color; waterMaterialTemplate.liquidFlags = liquidFlags; + waterMaterialTemplate.liquidMaterialId = liquidMaterialId; + + assert(liquidFlags >= 0 && liquidFlags <= 2063); @@ -70,7 +101,7 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, meshTemplate.meshType = MeshType::eWmoMesh; meshTemplate.start = 0; - meshTemplate.end = indexBuffer.size(); + meshTemplate.end = indexBufferSize; auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); m_liquidMeshes.push_back(mesh); @@ -80,47 +111,37 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, } void -LiquidInstance::getInfoFromDatabase(const SMLiquidInstance &liquidInstance, int &basetextureFDID, mathfu::vec3 &color, - int &liquidFlags, int &liquidVertexFormat, bool &generateTexCoordsFromPos) { - basetextureFDID= 0; - color= mathfu::vec3(0, 0, 0); - liquidFlags = 0; - liquidVertexFormat = 0; +LiquidInstance::getInfoFromDatabase(int liquid_object_or_lvf, int liquid_type, bool &generateTexCoordsFromPos) { + m_liqMatAndType.color1 = {0, 0, 0}; + m_liqMatAndType.flags = 0; + m_liqMatAndType.matLVF = 0; + generateTexCoordsFromPos= false; mathfu::vec3 minimapStaticCol = {0, 0, 0}; if (m_api->databaseHandler != nullptr) { - LiquidTypeAndMat liqMatAndType; - std::vector liquidTextureData; + if (liquid_object_or_lvf > 41) { - if (liquidInstance.liquid_object_or_lvf > 41) { - - m_api->databaseHandler->getLiquidObjectData(liquidInstance.liquid_object_or_lvf, liquidInstance.liquid_type, liqMatAndType, liquidTextureData); + m_api->databaseHandler->getLiquidObjectData(liquid_object_or_lvf, liquid_type, m_liqMatAndType, m_liquidTextureData); //From Liquid::GetVertexFormat - if (liquidInstance.liquid_type == 2) { - liquidVertexFormat = 2; + if (liquid_type == 2) { + m_liqMatAndType.matLVF = 2; } } else { - liquidVertexFormat = liquidInstance.liquid_object_or_lvf; - m_api->databaseHandler->getLiquidTypeData(liquidInstance.liquid_type, liqMatAndType, liquidTextureData); - assert(liquidInstance.liquid_object_or_lvf == liqMatAndType.matLVF); - } - basetextureFDID = liquidTextureData.size() > 0 ? liquidTextureData[0].fileDataId : 0; - if (liqMatAndType.color1[0] > 0 || liqMatAndType.color1[1] > 0 || liqMatAndType.color1[2] > 0) { - color = mathfu::vec3(liqMatAndType.color1[2], liqMatAndType.color1[1], liqMatAndType.color1[0]); - } - minimapStaticCol = mathfu::vec3(liqMatAndType.minimapStaticCol[2], liqMatAndType.minimapStaticCol[1], liqMatAndType.minimapStaticCol[0]); + m_api->databaseHandler->getLiquidTypeData(liquid_type, m_liqMatAndType, m_liquidTextureData); - liquidFlags = liqMatAndType.flags; + m_liqMatAndType.matLVF = liquid_object_or_lvf; + //assert(liquid_object_or_lvf == liqMatAndType.matLVF); + } // assert(liquidVertexFormat == liqMatAndType.matLVF); // liquidVertexFormat = liqMatAndType.matLVF; - generateTexCoordsFromPos = getLiquidSettings(liquidInstance.liquid_object_or_lvf, - liquidInstance.liquid_type, - liqMatAndType.materialID, - liqMatAndType.flowSpeed <=0).generateTexCoordsFromPos; + generateTexCoordsFromPos = getLiquidSettings(liquid_object_or_lvf, + liquid_type, + m_liqMatAndType.materialID, + m_liqMatAndType.flowSpeed <=0).generateTexCoordsFromPos; } - assert(liquidFlags >= 0 && liquidFlags <= 2063); + assert(m_liqMatAndType.flags >= 0 && m_liqMatAndType.flags <= 2063); } HGVertexBufferBindings LiquidInstance::createLiquidVao(const HMapSceneBufferCreate &sceneRenderer, @@ -200,7 +221,7 @@ void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, } if (generateTexCoordsFromPos) { - uv = mathfu::vec2(pos.x * 0.6f, pos.y * 0.6f); + uv = mathfu::vec2(pos.x * 0.06f, pos.y * 0.06f); } else { uv = getLiquidVertexCoords(liquidVertexFormat, vertexDataPtr, totalCount, y * (liquidInstance.width + 1) + x); } @@ -249,14 +270,16 @@ void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, } } -void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDependantData, IMapApi *mapApi) { +void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime) { for (auto &waterMaterial : m_liquidMaterials) { auto &waterChunk = waterMaterial->m_materialPS->getObject(); + waterChunk.materialId = waterMaterial->materialId; + if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean waterChunk.color = frameDependantData->closeOceanColor; } else if (waterMaterial->liquidFlags == 15) { //River/Lake //Query river color - mathfu::vec3 closeRiverColor = {0, 0, 0}; + mathfu::vec3 closeRiverColor = frameDependantData->closeRiverColor.xyz(); if (m_api->getConfig()->useCloseRiverColorForDB) { mathfu::vec3 waterPos = (mathfu::vec3(m_waterBBox.max) + mathfu::vec3(m_waterBBox.min)) / 2.0f; @@ -272,22 +295,34 @@ void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDepen } } } - if (!waterColorFound) { - std::vector lightResults = {}; - mapApi->getLightResultsFromDB(waterPos, m_api->getConfig(), lightResults, nullptr); - for (auto &_light : lightResults) { - closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; - } - closeRiverColor = mathfu::vec3(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0]); - } } - waterChunk.color = frameDependantData->closeRiverColor; + waterChunk.color = mathfu::vec4(closeRiverColor, 0.7);; } else { waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); } - auto time = mapApi->getCurrentSceneTime(); + if (m_liqMatAndType.materialID == 1 || m_liqMatAndType.materialID == 3) { + waterChunk.textureMatrix = mathfu::mat4::Identity(); + MathHelper::RotationZ(m_liqMatAndType.m_floats[1] * (M_PI / 180.0f)) * + mathfu::mat4::FromScaleVector( + mathfu::vec3(m_liqMatAndType.m_floats[0],m_liqMatAndType.m_floats[0],m_liqMatAndType.m_floats[0]) + ); + } else if (m_liqMatAndType.materialID == 2 || m_liqMatAndType.materialID == 4) { + waterChunk.textureMatrix = +// MathHelper::RotationZ(m_liqMatAndType.m_floats[7] * (M_PI / 180.0f)) * +// mathfu::mat4::FromScaleVector( +// mathfu::vec3(m_liqMatAndType.m_floats[4],m_liqMatAndType.m_floats[4],m_liqMatAndType.m_floats[4]) +// ) * + GetTexScrollMtx(mapCurrentTime, mathfu::vec2( + m_liqMatAndType.m_floats[0], + m_liqMatAndType.m_floats[1] + )) + ; + + } else { + waterChunk.textureMatrix = mathfu::mat4::Identity(); + } waterMaterial->m_materialPS->save(); } @@ -297,3 +332,17 @@ void LiquidInstance::collectMeshes(std::vector &transparentMeshe //TODO: Get time and right mesh instance for animation transparentMeshes.push_back(m_liquidMeshes[0]); } + +mathfu::mat4 LiquidInstance::GetTexScrollMtx(int time, mathfu::vec2 scrollVec) { + float scrollX = 0.0f; + float scrollY = 0.0f; + + if (!feq(scrollVec.x, 0.0)) { + scrollX = (time % (int)(1000.0f / scrollVec.x)) / (float)(int)(1000.0f / scrollVec.x); + } + if (!feq(scrollVec.y, 0.0)) { + scrollY = (time % (int)(1000.0f / scrollVec.y)) / (float) (int)(1000.0f / scrollVec.y); + } + + return mathfu::mat4::FromTranslationVector(mathfu::vec3(scrollX, scrollY, 0.0f)); +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index b84440d0e..40f2699e1 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -5,20 +5,28 @@ #ifndef AWEBWOWVIEWERCPP_LIQUIDINSTANCE_H #define AWEBWOWVIEWERCPP_LIQUIDINSTANCE_H +class IMapApi; #include "../../ApiContainer.h" -#include "../iMapApi.h" class LiquidInstance { public: LiquidInstance(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, const SMLiquidInstance &liquidInstance, - std::shared_ptr> &waterPlacementChunk, + const std::shared_ptr> &waterPlacementChunk, const mathfu::vec3 &liquidBasePos, const PointerChecker &mH2OBlob, CAaBox &waterBBox); - void updateLiquidMaterials(const HFrameDependantData &frameDependantData, IMapApi *mapApi); + LiquidInstance(const HApiContainer &api, + const HMapSceneBufferCreate &sceneRenderer, + const HGVertexBufferBindings &binding, + int liquidType, + int indexBufferSize, + const std::shared_ptr> &waterPlacementChunk, + CAaBox &waterAaBB); + + void updateLiquidMaterials(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime); void collectMeshes(std::vector &transparentMeshes); private: const HApiContainer &m_api; @@ -31,6 +39,9 @@ class LiquidInstance { uint16_t liquid_object; uint32_t liquidType; + LiquidTypeAndMat m_liqMatAndType; + std::vector m_liquidTextureData; + void createAdtVertexData(const SMLiquidInstance &liquidInstance, const mathfu::vec3 &liquidBasePos, const PointerChecker &mH2OBlob, CAaBox &waterAaBB, int liquidVertexFormat, bool generateTexCoordsFromPos, std::vector &vertexBuffer, @@ -41,9 +52,14 @@ class LiquidInstance { std::vector &indexBuffer) const; void - getInfoFromDatabase(const SMLiquidInstance &liquidInstance, int &basetextureFDID, mathfu::vec3 &color, - int &liquidFlags, - int &liquidVertexFormat, bool &generateTexCoordsFromPos); + getInfoFromDatabase(int liquid_object_or_lvf, int liquid_type, bool &generateTexCoordsFromPos); + + void + createMaterialAndMesh(const HMapSceneBufferCreate &sceneRenderer, + int indexBufferSize, + const HGVertexBufferBindings &vertexWaterBufferBindings); + + mathfu::mat4 GetTexScrollMtx(int time, mathfu::vec2 scrollVec); }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 047955e2a..47c846803 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1081,7 +1081,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_modelFragmentData->save(); } - for (auto material: m_materialArray) { + for (const auto &material: m_materialArray) { M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 4e748522f..013c5ad6b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1539,7 +1539,7 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { if (wmoGroupObject == nullptr) continue; - wmoGroupObject->uploadGeneratorBuffers(renderPlan->frameDependentData); + wmoGroupObject->uploadGeneratorBuffers(renderPlan->frameDependentData, getCurrentSceneTime()); } { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index f3d792482..fc8e987c4 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -37,29 +37,9 @@ void WmoGroupObject::update() { } -void WmoGroupObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { - for (auto const &waterMaterial : m_waterMaterialArray) { - auto waterChunk = waterMaterial->m_materialPS->getObject(); -/* - 1,3 - Water - 2,4 - Magma - 5 - Mercury, - 10 - Fog - 12 - LeyLine - 13 - Fel - 14 - Swamp - 18 - Azerithe -*/ - - if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean - waterChunk.color = frameDependantData->closeOceanColor; - } else if (waterMaterial->liquidFlags == 15) { //River/Lake - waterChunk.color = frameDependantData->closeRiverColor; - } else { - waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); - } - - waterMaterial->m_materialPS->save(); +void WmoGroupObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime) { + for(auto &liquidInstance : m_liquidInstances) { + liquidInstance->updateLiquidMaterials(frameDependantData, mapCurrentTime); } } @@ -244,62 +224,13 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere //Get Liquid with new method setLiquidType(); - HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer, liquid_type); + HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer, liquid_type, m_waterAaBB); if (binding == nullptr) return; + auto l_liquidInstance = std::make_shared(m_api, sceneRenderer, binding, (int)liquid_type, m_geom->waterIndexSize, m_wmoApi->getPlacementBuffer(), m_waterAaBB); - WaterMaterialTemplate waterMaterialTemplate; - - - PipelineTemplate pipelineTemplate; - pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; - pipelineTemplate.depthWrite = false; - pipelineTemplate.depthCulling = true; - pipelineTemplate.backFaceCulling = false; - - - int waterMaterialId = 0; - - int basetextureFDID = 0; - if (m_api->databaseHandler != nullptr) { -// m_api->databaseHandler->getLiquidTypeData(static_cast(this->liquid_type), liquidTypeData); -// for (auto ltd: liquidTypeData) { -// if (ltd.FileDataId != 0) { -// basetextureFDID = ltd.FileDataId; -// -// if (ltd.color1[0] > 0 || ltd.color1[1] > 0 || ltd.color1[2] > 0) { -// waterMaterialTemplate.color = mathfu::vec3(ltd.color1[0], ltd.color1[1], ltd.color1[2]); -// } -// waterMaterialTemplate.liquidFlags = ltd.flags; -// waterMaterialId = ltd.materialId; -// break; -// } -// } - } - - waterMaterialTemplate.color = mathfu::vec3(0,0,0); - waterMaterialTemplate.liquidFlags = 0; - - if (basetextureFDID != 0) { - auto htext = m_api->cacheStorage->getTextureCache()->getFileId(basetextureFDID); - waterMaterialTemplate.texture = m_api->hDevice->createBlpTexture(htext, true, true); - } else { - waterMaterialTemplate.texture = m_api->hDevice->getBlackTexturePixel(); - } - - auto waterMaterial = sceneRenderer->createWaterMaterial(m_wmoApi->getPlacementBuffer(),pipelineTemplate, waterMaterialTemplate); - waterMaterial->materialId = waterMaterialId; - - gMeshTemplate meshTemplate(binding); - meshTemplate.meshType = MeshType::eWmoMesh; - meshTemplate.start = 0; - meshTemplate.end = m_geom->waterIndexSize; - - auto hmesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); - m_waterMeshArray.push_back(hmesh); - m_waterMaterialArray.push_back(waterMaterial); + m_liquidInstances.push_back(l_liquidInstance); } void WmoGroupObject::loadDoodads() { @@ -821,8 +752,8 @@ void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vecto } } - for (auto &i : this->m_waterMeshArray) { - transparentMeshes.push_back(i); + for (auto const &liquidInstance : m_liquidInstances) { + liquidInstance->collectMeshes(transparentMeshes); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 27eed94eb..6ffaa28a6 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -11,8 +11,10 @@ class WMOGroupListContainer; #include "../../persistance/header/wmoFileHeader.h" #include "../iWmoApi.h" #include "../m2/m2Object.h" +#include "../liquid/LiquidInstance.h" #include "../../../gapi/interface/meshes/IMesh.h" + class WmoGroupObject { public: WmoGroupObject(mathfu::mat4 &modelMatrix, HApiContainer api, SMOGroupInfo &groupInfo, int groupNumber) : m_api(api){ @@ -49,7 +51,7 @@ class WmoGroupObject { bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); void update(); - void uploadGeneratorBuffers(const HFrameDependantData &frameDependantData); + void uploadGeneratorBuffers(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime); void checkGroupFrustum(bool &drawDoodads, bool &drawGroup, mathfu::vec4 &cameraVec4, const MathHelper::FrustumCullingData &frustumData); @@ -75,13 +77,13 @@ class WmoGroupObject { CAaBox m_worldGroupBorder; CAaBox m_localGroupBorder; CAaBox m_volumeWorldGroupBorder; + CAaBox m_waterAaBB; mathfu::mat4 *m_modelMatrix = nullptr; int m_groupNumber; std::vector m_meshArray = {}; std::vector m_sortableMeshArray = {}; - std::vector m_waterMeshArray = {}; - std::vector> m_waterMaterialArray = {}; + std::vector> m_liquidInstances = {}; SMOGroupInfo *m_main_groupInfo; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b3b778e52..d2f5ac48a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +430,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,19 +499,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,13 +633,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +814,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -877,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,96}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,21 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,13 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {1,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,21 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {0,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,11 +1524,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,16 +1543,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,10 +1585,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1612,21 +1623,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1984,13 +1954,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2006,23 +1990,29 @@ const std::unordered_map m_cpuStagingBuffer; std::mutex dataToBeUploadedMtx; std::vector dataToBeUploaded; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 10de28f3d..03691acf4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -124,7 +124,7 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector(buffers[i]); + auto const &bufferVlk = std::dynamic_pointer_cast(buffers[i]); auto pbufferVlk = bufferVlk.get(); //firstBinding == i <- means we can only skip the start of the list; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 51753ff15..eccdcdc9e 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -85,8 +85,8 @@ struct LiquidTypeAndMat { std::array frameCountTexture; std::array color1; std::array color2; - std::array m_floats; - std::array m_int; + std::array m_floats = {0}; + std::array m_int = {0}; std::array coefficient; uint8_t matFlag; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index cc581e9c1..732045113 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -45,6 +45,7 @@ struct WaterMaterialTemplate { HGSamplableTexture texture = nullptr; mathfu::vec3 color; int liquidFlags; + int liquidMaterialId; }; class IM2ModelData { @@ -104,8 +105,6 @@ class IWaterMaterial : public IMaterial { mathfu::vec3 color; int liquidFlags; int materialId; - float scrollSpeedX; - float scrollSpeedY; std::shared_ptr> m_materialPS = nullptr; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 4a678d4e6..9f26cdfc2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -402,6 +402,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co material->color = waterMaterialTemplate.color; material->liquidFlags = waterMaterialTemplate.liquidFlags; + material->materialId = waterMaterialTemplate.liquidMaterialId; return material; } @@ -592,28 +593,29 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *skyTransparentMeshes) { - std::string debugMess = - "Drawing mesh " - " meshType = " + std::to_string((int)mesh->getMeshType()) + - " priorityPlane = " + std::to_string(mesh->priorityPlane()) + - " sortDistance = " + std::to_string(mesh->getSortDistance()) + - " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); - - auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); +// +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } - if (skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); + if (skyMesh0x4) + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *transparentMeshes) { - std::string debugMess = - "Drawing mesh " - " meshType = " + std::to_string((int)mesh->getMeshType()) + - " priorityPlane = " + std::to_string(mesh->priorityPlane()) + - " sortDistance = " + std::to_string(mesh->getSortDistance()) + - " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); - - auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); +// +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } From 460ae87329cec5438e7ce35324a43e327b8ab496 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 1 Jun 2023 17:43:00 +0300 Subject: [PATCH 075/212] proper normal calculus + buffer optimizations --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- .../glsl/common/commonLightFunctions.glsl | 2 +- .../glsl/forwardRendering/adtShader.vert | 2 +- .../glsl/forwardRendering/m2Shader.vert | 2 +- .../forwardRendering/waterfallShader.vert | 2 +- .../glsl/forwardRendering/wmoShader.vert | 2 +- wowViewerLib/src/engine/CameraMatrices.h | 1 + .../src/engine/algorithms/hashString.h | 5 +- .../src/engine/camera/firstPersonCamera.cpp | 6 +- .../src/engine/camera/firstPersonCamera.h | 1 + .../src/engine/objects/m2/m2Object.cpp | 6 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- .../src/gapi/interface/buffers/IBuffer.h | 1 - .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 64 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 27 +- .../src/gapi/vulkan/buffers/IBufferChunkVLK.h | 8 +- .../CommandBufferRecorder.cpp | 16 +- .../CommandBufferRecorder.h | 4 +- .../renderer/mapScene/MapSceneRenderer.cpp | 2 + .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 2 +- 21 files changed, 600 insertions(+), 573 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index b1197c9b3..fb1da153d 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -122,7 +122,7 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( auto const &descSets = material->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { - swapChainCmd.bindDescriptorSet(i, descSets[i]); + swapChainCmd.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); } } diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 86484c4c6..a2baa067e 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -58,7 +58,7 @@ vec3 calcLight( vec3 normalizedN = normalize(vNormal); if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { - float nDotL = clamp(dot(normalizedN, -(sceneParams.extLight.uExteriorDirectColorDir.xyz)), 0.0, 1.0); + float nDotL = clamp(dot(normalizedN, normalize(-(sceneParams.extLight.uExteriorDirectColorDir.xyz))), 0.0, 1.0); float nDotUp = dot(normalizedN, normalize(sceneParams.uViewUp.xyz)); vec3 adjAmbient = (sceneParams.extLight.uExteriorAmbientColor.rgb + precomputedLight); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 4ce089421..3235df5b3 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -77,7 +77,7 @@ void main() { vColor = aColor; vVertexLighting = aVertexLighting.rgb; mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); - vec3 normal = normalize(viewMatForNormal * vec4(aNormal, 0.0)).xyz; + vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); vNormal = normal; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index a55f02f08..3734acfa0 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -89,7 +89,7 @@ void main() { vec4 vertexPosInView = viewModelMat * aPositionVec4; mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); - vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; + vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); vTexCoord = aTexCoord; vTexCoord2 = aTexCoord2; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index bcf0f1729..c4520d53a 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -82,7 +82,7 @@ void main() { vec4 cameraPoint = viewModelMat * vec4(pos, 1.0); mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); - vec3 normal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; + vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); vNormal = (scene.uLookAtMat * uPlacementMat * vec4(aNormal, 0)).xyz; vPosition = pos; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index ea2515442..275aa130a 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -56,7 +56,7 @@ void main() { gl_Position = scene.uPMatrix * cameraPoint; vPosition = vec4(cameraPoint.xyz, 0); - vNormal = normalize(viewModelMatForNormal * vec4(aNormal, 0.0)).xyz; + vNormal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); vColor = aColor.bgra; vColor2 = aColor2; diff --git a/wowViewerLib/src/engine/CameraMatrices.h b/wowViewerLib/src/engine/CameraMatrices.h index 4f8697a38..f85d9460e 100644 --- a/wowViewerLib/src/engine/CameraMatrices.h +++ b/wowViewerLib/src/engine/CameraMatrices.h @@ -14,6 +14,7 @@ struct CameraMatrices { mathfu::mat4 perspectiveMat; mathfu::mat4 lookAtMat; + mathfu::mat4 invTranspViewMat; mathfu::vec4 cameraPos; mathfu::vec4 viewUp; mathfu::vec4 interiorDirectLightDir; diff --git a/wowViewerLib/src/engine/algorithms/hashString.h b/wowViewerLib/src/engine/algorithms/hashString.h index 177f7afd3..eaabc608c 100644 --- a/wowViewerLib/src/engine/algorithms/hashString.h +++ b/wowViewerLib/src/engine/algorithms/hashString.h @@ -72,7 +72,7 @@ class HashedString // A wrapper so we can generate any number of functions using the pre-processor (const strings) template constexpr HashedString(const char(&str)[N]); - explicit HashedString(ConstCharWrapper str): m_Hash(CalculateFNV(str.str)){ + explicit HashedString(ConstCharWrapper str): m_Hash(CalculateFNV(str.str)), m_originalString(str.str){ }; // Return the original string @@ -92,6 +92,7 @@ class HashedString // The hash object (pre-calculated if we use the full optimization flag) size_t m_Hash; + const char * m_originalString; // The original string //#ifdef _DEBUG @@ -138,7 +139,7 @@ class HashedString #define ME_HASHED_STRING_SPECIALIZATION(n) \ template <> \ constexpr HashedString::HashedString(const char (&str)[n]) \ - : m_Hash(ME_JOIN(ME_HASHED_STRING_, n)) \ + : m_Hash(ME_JOIN(ME_HASHED_STRING_, n)), m_originalString(str) \ {} ME_HASHED_STRING_SPECIALIZATION(1) diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 4f5dcda6d..cef3b3669 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -135,12 +135,13 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { 0,0,0,1.0f //translation ); lookAtMat *= mathfu::mat4::FromTranslationVector(-camera) ; + invTranspViewMat = lookAtMat.Inverse().Transpose(); this->camera = mathfu::vec4(camera, 1.0);//(lookAtMat.Inverse() * mathfu::vec4(0,0,0,1.0)).xyz(); //std::cout<<"camera " << camera[0] <<" "<interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); + this->upVector = (invTranspViewMat * upVector).Normalized().xyz(); updatedAtLeastOnce = true; } void FirstPersonCamera :: setCameraPos (float x, float y, float z) { @@ -192,6 +193,7 @@ HCameraMatrices FirstPersonCamera::getCameraMatrices(float fov, nearPlane, farPlane); cameraMatrices->lookAtMat = lookAtMat; + cameraMatrices->invTranspViewMat = invTranspViewMat; cameraMatrices->cameraPos = camera; cameraMatrices->viewUp = mathfu::vec4(upVector, 0); diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.h b/wowViewerLib/src/engine/camera/firstPersonCamera.h index 428e4a7dd..a18d1673b 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.h @@ -19,6 +19,7 @@ class FirstPersonCamera: public ICamera { mathfu::vec3 lookAt = {0, 0, 0}; mathfu::vec3 upVector = {0, 0, 0}; mathfu::mat4 lookAtMat = {}; + mathfu::mat4 invTranspViewMat = {}; float MDDepthPlus = 0; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 47c846803..53f57f535 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1081,10 +1081,6 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_modelFragmentData->save(); } - for (const auto &material: m_materialArray) { - M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); - } - //Manually update vertices for dynamics updateDynamicMeshes(); @@ -1471,7 +1467,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { //Create materials for (int batchIndex = 0; batchIndex < batches.size; batchIndex++) { auto m2Batch = batches[batchIndex]; - EGxBlendEnum mainBlendMode; + EGxBlendEnum mainBlendMode = EGxBlendEnum::GxBlend_Opaque; const EGxBlendEnum forcedTranspBlend = EGxBlendEnum::GxBlend_Alpha; this->m_materialArray[batchIndex] = createM2Material(sceneRenderer, batchIndex, mainBlendMode, false); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d2f5ac48a..4aac3c3cf 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,96}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +658,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,16384}, - {0,1,64}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,16 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,5,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1524,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, }, { { {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1543,19 +1546,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,48}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {9,9,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,21 +1585,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1623,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1954,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1990,29 +2006,23 @@ const std::unordered_map mutate(int newSize) = 0; virtual size_t getSize() = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 58d90888e..22047ff1a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -39,7 +39,6 @@ void GBufferVLK::createBuffer(BufferInternal &buffer) { &buffer.stagingBufferAlloc, &buffer.stagingBufferAllocInfo)); } - m_cpuStagingBuffer.resize(m_bufferSize); { // No need to flush stagingBuffer memory because CPU_ONLY memory is always HOST_COHERENT. @@ -106,7 +105,7 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, return result; } -void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc) { +void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc) { //Destruction of this virtualBlock happens only in deallocation queue. //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, //the virtualBlock was still not been free'd @@ -114,15 +113,17 @@ void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocat if (alloc.metadata != OffsetAllocator::Allocation::NO_SPACE) { auto l_alloc = alloc; + auto l_uiaAlloc = uiaAlloc; auto l_weak = weak_from_this(); m_device->addDeallocationRecord( - [l_alloc, l_weak]() { + [l_alloc, l_uiaAlloc, l_weak]() { auto shared = l_weak.lock(); if (shared == nullptr) return; std::unique_lock lock(shared->m_mutex, std::defer_lock); lock.lock(); shared->offsetAllocator.free(l_alloc); + shared->uiaAllocator.free(l_uiaAlloc); lock.unlock(); }); } @@ -145,10 +146,6 @@ void GBufferVLK::subUploadData(void *data, int offset, int length) { memcpy((uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset, data, length); } -std::shared_ptr GBufferVLK::mutate(int newSize) { - resize(newSize); - return shared_from_this(); -} void GBufferVLK::resize(int newLength) { std::unique_lock lock(m_mutex, std::defer_lock); lock.lock(); @@ -223,10 +220,23 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy if(res == VK_SUCCESS) { + OffsetAllocator::Allocation uiaAlloc; + { + std::unique_lock lock(m_mutex, std::defer_lock); + uiaAlloc = uiaAllocator.allocate(1); + if (uiaAlloc.offset == OffsetAllocator::Allocation::NO_SPACE) { + this->uiaAllocator.growSize(1000); + uploadIntervalActivatable.resize(uploadIntervalActivatable.size() + 1000); + uiaAlloc = this->uiaAllocator.allocate(1); + } + } + uploadIntervalActivatable[uiaAlloc.offset] = {alloc.offset, static_cast(sizeInBytes), false}; + auto subBuffer = std::make_shared( shared_from_this(), alloc, sizeInBytes, fakeSize, + uiaAlloc, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+alloc.offset); std::unique_lock lock(m_mutex, std::defer_lock); @@ -244,9 +254,12 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy } } -void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, const OffsetAllocator::Allocation &alloc, int subBuffersize) { +void GBufferVLK::deleteSubBuffer(std::list>::const_iterator &it, + const OffsetAllocator::Allocation &alloc, + const OffsetAllocator::Allocation &uiaAlloc, + int subBuffersize) { if (subBuffersize > 0) { - deallocateSubBuffer(currentBuffer, alloc); + deallocateSubBuffer(currentBuffer, alloc, uiaAlloc); } currentSubBuffers.erase(it); @@ -265,24 +278,21 @@ void GBufferVLK::save(int length) { uploadFromStaging(0, 0, length); } -void GBufferVLK::addSubBufferForUpload(const std::weak_ptr &buffer) { - std::lock_guard lock(dataToBeUploadedMtx); - - subBuffersForUpload.emplace_back(buffer); +void GBufferVLK::addIntervalIndexForUpload(int index) { + this->uploadIntervalActivatable[index].requiresUpdate = true; } MutexLockedVector GBufferVLK::getSubmitRecords() { { std::lock_guard lock(dataToBeUploadedMtx); - struct uploadInterval {size_t start; size_t size;}; std::vector intervals; - for (const auto &wsubBuffer : subBuffersForUpload) { - auto subBuffer = wsubBuffer.lock(); - if (subBuffer == nullptr) continue; + for (auto &interval : uploadIntervalActivatable) { + if (!interval.requiresUpdate) continue; + interval.requiresUpdate = false; auto &newInterval = intervals.emplace_back(); - newInterval = {.start = subBuffer->getOffset(), .size = subBuffer->getSize()}; + newInterval = interval; } if (lastSubmittedBufferSize != m_bufferSize) { @@ -333,9 +343,6 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { vbCopyRegion.dstOffset = currInterval.start; vbCopyRegion.size = currInterval.size; } - int prevSize = subBuffersForUpload.size(); - subBuffersForUpload.clear(); - subBuffersForUpload.reserve(prevSize); } return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); @@ -348,15 +355,17 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, int size, int fakeSize, + OffsetAllocator::Allocation uiaAlloc, uint8_t *dataPointer) : m_parentBuffer(parent) { m_alloc = alloc; + m_uiaAlloc = uiaAlloc; m_size = size; m_fakeSize = fakeSize > 0 ? fakeSize : m_size; m_dataPointer = dataPointer; } GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { - m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc, m_size); + m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc, m_uiaAlloc, m_size); } void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { @@ -366,7 +375,7 @@ void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { memcpy(m_dataPointer, data, length); - m_parentBuffer->addSubBufferForUpload(weak_from_this()); + m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } @@ -377,7 +386,7 @@ void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length memcpy(m_dataPointer + offset, data, length); - m_parentBuffer->addSubBufferForUpload(weak_from_this()); + m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); } void *GBufferVLK::GSubBufferVLK::getPointer() { @@ -392,13 +401,10 @@ void GBufferVLK::GSubBufferVLK::save(int length) { } if (m_size <= 0) return; - m_parentBuffer->addSubBufferForUpload(weak_from_this()); + m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } size_t GBufferVLK::GSubBufferVLK::getSize() { return m_fakeSize; -} -std::shared_ptr GBufferVLK::GSubBufferVLK::mutate(int newSize) { - return m_parentBuffer->getSubBuffer(newSize); -}; +} \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 47a741f73..320c58b67 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -6,6 +6,7 @@ #define AWEBWOWVIEWERCPP_GBUFFERVLK_H #include +#include class GDeviceVLK; typedef std::shared_ptr HGDeviceVLK; @@ -31,7 +32,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this &buffer); + void addIntervalIndexForUpload(int index); void *getPointer() override { return currentBuffer.stagingBufferAllocInfo.pMappedData;}; //Submits data edited with Pointer @@ -52,8 +53,12 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords(); - std::shared_ptr mutate(int newSize) override; void resize(int newLength); + + struct uploadInterval {size_t start; size_t size;}; + struct uploadIntervalActivatable : uploadInterval { + bool requiresUpdate = false; + }; private: HGDeviceVLK m_device; @@ -71,7 +76,6 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this m_cpuStagingBuffer; std::mutex dataToBeUploadedMtx; std::vector dataToBeUploaded; @@ -89,6 +93,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this mutate(int newSize) override; - VkBuffer getGPUBuffer() override { return m_parentBuffer->getGPUBuffer(); } @@ -113,6 +116,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> currentSubBuffers; - std::vector> subBuffersForUpload; + std::vector uploadIntervals; + + OffsetAllocator::Allocator uiaAllocator = OffsetAllocator::Allocator(0); + std::vector uploadIntervalActivatable; // uploadCache = {}; public: std::shared_ptr getSubBuffer(int sizeInBytes, int fakeSize = -1); - void deleteSubBuffer(std::list>::const_iterator &it, const OffsetAllocator::Allocation &alloc, int subBuffersize); + void deleteSubBuffer(std::list>::const_iterator &it, + const OffsetAllocator::Allocation &alloc, + const OffsetAllocator::Allocation &uiaAlloc, + int subBuffersize); private: void createBuffer(BufferInternal &buffer); void destroyBuffer(BufferInternal &buffer); VkResult allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, OffsetAllocator::Allocation &alloc); - void deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc); + void deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h index 1d6366519..b11a5344c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h @@ -19,13 +19,15 @@ class CBufferChunkVLK : public IBufferChunk { m_realSize = sizeof(T); subBuffer = mainBuffer->getSubBuffer(m_realSize,sizeof(T)); + pSubBuffer = subBuffer.get(); + } T &getObject() override { - return *(T*)subBuffer->getPointer(); + return *(T*)pSubBuffer->getPointer(); }; void save() override { - subBuffer->save(m_realSize); + pSubBuffer->save(m_realSize); }; const std::shared_ptr getSubBuffer() { @@ -33,7 +35,9 @@ class CBufferChunkVLK : public IBufferChunk { } private: int m_realSize = 0; + void *ptr = nullptr; std::shared_ptr subBuffer = nullptr; + IBufferVLK *pSubBuffer = nullptr; }; namespace BufferChunkHelperVLK { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 03691acf4..580918747 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -75,7 +75,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( ); } -void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet) { +void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet) { //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others //Which leads to three separate states for: // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR @@ -83,13 +83,17 @@ void CmdBufRecorder::bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr // if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; - auto vkDescSet = descriptorSet->getDescSet(); - constexpr uint32_t vkDescCnt = 1; + auto pDescriptorSet = descriptorSet.get(); - vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); + if (m_currentDescriptorSet[bindIndex] != pDescriptorSet) { + auto vkDescSet = pDescriptorSet->getDescSet(); + constexpr uint32_t vkDescCnt = 1; - m_currentDescriptorSet[bindIndex] = descriptorSet; + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, + m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); + + m_currentDescriptorSet[bindIndex] = pDescriptorSet; + } } CommandBufferDebugLabel CmdBufRecorder::beginDebugLabel(const std::string &labelName, const std::array &colors) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index bb8756d3d..eaa33757b 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -46,7 +46,7 @@ class CmdBufRecorder { void bindIndexBuffer(const std::shared_ptr &bufferVlk); void bindVertexBuffers(const std::vector> &bufferVlk); void bindPipeline(const std::shared_ptr &pipeline); - void bindDescriptorSet(uint32_t bindIndex, const std::shared_ptr &descriptorSet); + void bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); void setScissors(const std::array &areaOffset, @@ -70,7 +70,7 @@ class CmdBufRecorder { std::shared_ptr m_currentPipeline = nullptr; std::shared_ptr m_currentIndexBuffer = nullptr; std::array, MAX_VERTEX_BUFFERS_PER_DRAWCALL> m_currentVertexBuffers; - std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> m_currentDescriptorSet = {nullptr}; + std::array m_currentDescriptorSet = {nullptr}; bool m_currentScissorsIsDefault = false; ViewportType m_currentViewport = ViewportType::vp_none; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 92fafb890..7b99a08de 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -118,6 +118,8 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrlookAtMat; if (isVulkan) { blockPSVS.uPMatrix = vulkanMatrixFix*renderingMatrices->perspectiveMat; + } else { + blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; } blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; blockPSVS.uViewUp = renderingMatrices->viewUp; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 9f26cdfc2..46c38b441 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -478,7 +478,7 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM auto const &descSets = material->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { - cmdBuf.bindDescriptorSet(i, descSets[i]); + cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 8b9f7db68..4cd837a8a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -86,7 +86,7 @@ void FFXGlowPassVLK::drawMaterial (CmdBufRecorder& cmdBuf, const std::shared_ptr auto const &descSets = material->getDescriptorSets(); for (int i = 0; i < descSets.size(); i++) { if (descSets[i] != nullptr) { - cmdBuf.bindDescriptorSet(i, descSets[i]); + cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); } } From 85d4b252ef1b12957f8462f92fc5fedf1dce4bda Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 2 Jun 2023 02:25:36 +0300 Subject: [PATCH 076/212] fix of portal culling, fix for one crash --- wowViewerLib/src/engine/algorithms/grahamScan.cpp | 5 +++-- wowViewerLib/src/engine/objects/wmo/wmoObject.cpp | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/wowViewerLib/src/engine/algorithms/grahamScan.cpp b/wowViewerLib/src/engine/algorithms/grahamScan.cpp index 8390a577f..633a26907 100644 --- a/wowViewerLib/src/engine/algorithms/grahamScan.cpp +++ b/wowViewerLib/src/engine/algorithms/grahamScan.cpp @@ -101,10 +101,11 @@ stack grahamScan(std::vector &points) { std::sort(points.begin()+1, points.end(), [&p0](auto const &p1, auto const &p2) -> bool { // Find orientation int o = orientation(p0, p1, p2); - if (o == 0) - return feq(distSq(p0, p2),distSq(p0, p1)) + if (o == 0) { + return feq(distSq(p0, p2), distSq(p0, p1)) ? &p1 > &p2 // this is fallback to stabilize the sorting function : distSq(p0, p2) >= distSq(p0, p1); + } return (o == 2); }); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 857159562..6402d38d3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -4,6 +4,7 @@ #include "wmoObject.h" #include "../../algorithms/mathHelper.h" +#include "../../algorithms/grahamScan.h" #include "../../persistance/header/commonFileStructs.h" #include "./../../../gapi/interface/IDevice.h" #include @@ -998,7 +999,7 @@ void WmoObject::traverseGroupWmo( int numItems = groupObjects[groupId]->getWmoGroupGeom()->mogp->moprCount; if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.showSkyBox) { - if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.INTERIOR > 0) { + if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.INTERIOR > 0 || !m_api->getConfig()->usePortalCulling) { if (skyBox != nullptr) { traverseTempData.ivPerWMOGroup[groupId]->m2List.addToDraw(skyBox); } @@ -1106,10 +1107,12 @@ void WmoObject::traverseGroupWmo( portalVerticesClip[i] /= portalVerticesClip[i].w; } + + for (int i = 0; i < portalVerticesVec.size(); i++) { //Project Portal vertex to near plane in clip space portalVerticesClipNearPlane[i] = portalVerticesClip[i]; - portalVerticesClipNearPlane[i].z = 0; + portalVerticesClipNearPlane[i].z = -1; //Transform back to local space portalVerticesClipNearPlane[i] = traverseTempData.MVPMatInv * portalVerticesClipNearPlane[i]; portalVerticesClipNearPlane[i] /= portalVerticesClipNearPlane[i].w; @@ -1118,7 +1121,7 @@ void WmoObject::traverseGroupWmo( //This condition works, bcuz earlier it's verified we are inside the portal using the //dot product AND `relation->side` bool flip = (relation->side > 0); - + int vertexCnt = portalVerticesVec.size(); for (int i = 0; i < vertexCnt; ++i) { int i2 = (i + 1) % vertexCnt; @@ -1159,7 +1162,7 @@ void WmoObject::traverseGroupWmo( { worldSpaceFrustum.points = MathHelper::getIntersectionPointsFromPlanes(worldSpaceFrustum.planes); - worldSpaceFrustum.hullLines = MathHelper::getHullLines(worldSpaceFrustum.points); + //worldSpaceFrustum.hullLines = MathHelper::getHullLines(worldSpaceFrustum.points); } std::vector worldSpacePortalVertices; From 9429ad38373d7799c1001057b7d4fda9ea920d1d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 3 Jun 2023 00:53:02 +0300 Subject: [PATCH 077/212] Implement proper camera stop --- src/main.cpp | 18 +++++------------ .../src/engine/camera/firstPersonCamera.cpp | 12 ++++++++++- .../src/engine/camera/firstPersonCamera.h | 1 + .../engine/camera/firstPersonOrthoCamera.cpp | 11 +++++++++- .../engine/camera/firstPersonOrthoCamera.h | 1 + .../camera/firstPersonOrthoStaticCamera.cpp | 3 ++- .../camera/firstPersonOrthoStaticCamera.h | 3 +++ .../firstPersonOrthoStaticTopDownCamera.cpp | 3 ++- .../firstPersonOrthoStaticTopDownCamera.h | 2 ++ .../src/engine/camera/m2TiedCamera.cpp | 9 ++++++--- wowViewerLib/src/engine/camera/m2TiedCamera.h | 1 + .../src/engine/camera/planarCamera.cpp | 20 +++++++++++++++---- wowViewerLib/src/engine/camera/planarCamera.h | 1 + 13 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 45bf02ec9..f45bd56ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,7 +107,6 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) static void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (stopKeyboard) return; HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); auto controllable = apiContainer->camera; if (apiContainer->getConfig()->doubleCameraDebug && @@ -117,6 +116,7 @@ static void onKey(GLFWwindow* window, int key, int scancode, int action, int mod } if ( action == GLFW_PRESS) { + if (stopKeyboard) return; switch (key) { case 'W' : controllable->startMovingForward(); @@ -160,18 +160,6 @@ static void onKey(GLFWwindow* window, int key, int scancode, int action, int mod case 'E': controllable->stopMovingDown(); break; - case 'H': -// scene->switchCameras(); -// scene->setScene(0, "trash", 0); -// scene->setAnimationId(159); - break; - case 'J': -// scene->setAnimationId(0); -// testConf->setDoubleCameraDebug(!testConf->getDoubleCameraDebug()); - break; - case 'K': -// testConf->setRenderPortals(!testConf->getRenderPortals()); - break; default: break; } @@ -480,6 +468,10 @@ int main(){ frontendUI->newFrame(); stopMouse = frontendUI->getStopMouse(); stopKeyboard = frontendUI->getStopKeyboard(); +// if (stopMouse || stopKeyboard) { +// apiContainer->camera->stopAllMovement(); +// } + glfwPollEvents(); // Render scene diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index cef3b3669..920f889af 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -57,6 +57,16 @@ void FirstPersonCamera::startMovingDown(){ void FirstPersonCamera::stopMovingDown(){ this->MDVerticalMinus = 0; } +void FirstPersonCamera::stopAllMovement() { + MDDepthPlus = 0; + MDDepthMinus = 0; + MDHorizontalPlus = 0; + MDHorizontalMinus = 0; + + MDVerticalPlus = 0; + MDVerticalMinus = 0; +} + void FirstPersonCamera::setMovementSpeed(float value) { this->m_moveSpeed = value; @@ -150,7 +160,7 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - this->upVector = (invTranspViewMat * upVector).Normalized().xyz(); + this->upVector = ((invTranspViewMat * upVector).xyz()).Normalized(); updatedAtLeastOnce = true; } void FirstPersonCamera :: setCameraPos (float x, float y, float z) { diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.h b/wowViewerLib/src/engine/camera/firstPersonCamera.h index a18d1673b..82f08f040 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.h @@ -58,6 +58,7 @@ class FirstPersonCamera: public ICamera { void stopMovingUp() override; void startMovingDown() override; void stopMovingDown() override; + void stopAllMovement() override; void zoomInFromMouseScroll(float val) override; void zoomInFromTouch(float val) override; diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp index 21b73087d..8f5455740 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.cpp @@ -54,6 +54,15 @@ void FirstPersonOrthoCamera::startMovingDown(){ void FirstPersonOrthoCamera::stopMovingDown(){ this->MDVerticalMinus = 0; } +void FirstPersonOrthoCamera::stopAllMovement() { + MDDepthPlus = 0; + MDDepthMinus = 0; + MDHorizontalPlus = 0; + MDHorizontalMinus = 0; + + MDVerticalPlus = 0; + MDVerticalMinus = 0; +} void FirstPersonOrthoCamera::tick (animTime_t timeDelta) { mathfu::vec3 dir = {1, 0, 0}; @@ -123,7 +132,7 @@ void FirstPersonOrthoCamera::tick (animTime_t timeDelta) { this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); + this->upVector = (invTranspViewMat * upVector).xyz().Normalized(); } void FirstPersonOrthoCamera :: setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.h b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.h index bd7762130..7305fa85e 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoCamera.h @@ -53,6 +53,7 @@ class FirstPersonOrthoCamera: public ICamera { void stopMovingUp() override; void startMovingDown() override; void stopMovingDown() override; + void stopAllMovement() override; void getCameraPosition(float *position) override { position[0] = camera.x; diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp index 9624ebf55..b906ada79 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.cpp @@ -20,6 +20,7 @@ void FirstPersonOrthoStaticCamera::startMovingUp(){} void FirstPersonOrthoStaticCamera::stopMovingUp(){} void FirstPersonOrthoStaticCamera::startMovingDown(){} void FirstPersonOrthoStaticCamera::stopMovingDown(){} +void FirstPersonOrthoStaticCamera::stopAllMovement(){} void FirstPersonOrthoStaticCamera::tick (animTime_t timeDelta) { // cameraRotationMat = cameraRotationMat * MathHelper::RotationX(90*M_PI/180); @@ -39,7 +40,7 @@ void FirstPersonOrthoStaticCamera::tick (animTime_t timeDelta) { mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); + this->upVector = (invTranspViewMat * upVector).xyz().Normalized(); } void FirstPersonOrthoStaticCamera::setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h index 61f110bce..7aff7c9ac 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h @@ -35,6 +35,9 @@ class FirstPersonOrthoStaticCamera: public ICamera { void stopMovingUp() override; void startMovingDown() override; void stopMovingDown() override; + void stopAllMovement() override; + + void zoomInFromMouseScroll(float val) override {}; void zoomInFromTouch(float val) override {}; void addCameraViewOffset(float x, float y) override {}; diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp index 8ccb5d933..2bd51d4ca 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.cpp @@ -21,6 +21,7 @@ void FirstPersonOrthoStaticTopDownCamera::startMovingUp(){} void FirstPersonOrthoStaticTopDownCamera::stopMovingUp(){} void FirstPersonOrthoStaticTopDownCamera::startMovingDown(){} void FirstPersonOrthoStaticTopDownCamera::stopMovingDown(){} +void FirstPersonOrthoStaticTopDownCamera::stopAllMovement(){} void FirstPersonOrthoStaticTopDownCamera::tick (animTime_t timeDelta) { // cameraRotationMat = cameraRotationMat * MathHelper::RotationX(90*M_PI/180); @@ -41,7 +42,7 @@ void FirstPersonOrthoStaticTopDownCamera::tick (animTime_t timeDelta) { this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - this->upVector = (invTranspViewMat * upVector.xyz()).Normalized(); + this->upVector = (invTranspViewMat * upVector).xyz().Normalized(); } void FirstPersonOrthoStaticTopDownCamera::setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h index 3ba9e7ab7..8722cbcb8 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h @@ -38,6 +38,8 @@ class FirstPersonOrthoStaticTopDownCamera: public ICamera { void stopMovingUp() override; void startMovingDown() override; void stopMovingDown() override; + void stopAllMovement() override; + void zoomInFromMouseScroll(float val) override {}; void zoomInFromTouch(float val) override {}; void addCameraViewOffset(float x, float y) override {}; diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp index f3a072388..67a91d1ef 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp @@ -27,8 +27,6 @@ HCameraMatrices m2TiedCamera::getCameraMatrices(float fov, float canvasAspect, f lookAtMat4 = rotateMat * lookAtMat4; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat4); - mathfu::vec3 upVectorTranformed = (lookAtRotation * upVector.xyz()); farPlane = m_lastCameraResult.far_clip; nearPlane = m_lastCameraResult.near_clip; @@ -44,8 +42,13 @@ HCameraMatrices m2TiedCamera::getCameraMatrices(float fov, float canvasAspect, f farPlane); cameraMatrices->lookAtMat = lookAtMat4; - lastCameraPos = lookAtMat4.Inverse() * mathfu::vec4(0,0,0,1); + auto invViewMat = lookAtMat4.Inverse(); + auto invTraspViewMat = invViewMat.Transpose(); + lastCameraPos = invViewMat * mathfu::vec4(0,0,0,1); cameraMatrices->cameraPos = lastCameraPos; + + mathfu::vec3 upVectorTranformed = (invTraspViewMat * upVector).xyz().Normalized(); + cameraMatrices->viewUp = mathfu::vec4(upVectorTranformed, 0); cameraMatrices->interiorDirectLightDir = mathfu::vec4(0,0,0,0); diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.h b/wowViewerLib/src/engine/camera/m2TiedCamera.h index 023f44e4a..bf4fcbe1e 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.h +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.h @@ -35,6 +35,7 @@ class m2TiedCamera : public ICamera { void stopMovingUp() override {}; void startMovingDown() override {}; void stopMovingDown() override {}; + void stopAllMovement() override {}; void addForwardDiff(float val) override {}; diff --git a/wowViewerLib/src/engine/camera/planarCamera.cpp b/wowViewerLib/src/engine/camera/planarCamera.cpp index d784434c7..416ba2e1d 100644 --- a/wowViewerLib/src/engine/camera/planarCamera.cpp +++ b/wowViewerLib/src/engine/camera/planarCamera.cpp @@ -58,6 +58,15 @@ void PlanarCamera::startMovingDown(){ void PlanarCamera::stopMovingDown(){ this->MDVerticalMinus = 0; } +void PlanarCamera::stopAllMovement() { + MDDepthPlus = 0; + MDDepthMinus = 0; + MDHorizontalPlus = 0; + MDHorizontalMinus = 0; + + MDVerticalPlus = 0; + MDVerticalMinus = 0; +} void PlanarCamera::setMovementSpeed(float value) { this->m_moveSpeed = value; @@ -94,18 +103,21 @@ void PlanarCamera::tick (animTime_t timeDelta) { mathfu::mat4::FromTranslationVector(mathfu::vec3(-cameraOffset.x, -cameraOffset.y, -cameraOffset.z)) ; //std::cout<<"camera " << camera[0] <<" "<camera = (lookAtMat.Inverse() * mathfu::vec4(0,0,0,1)).xyz(); + auto invViewMat = lookAtMat.Inverse(); + auto invTranspViewMat = invViewMat.Transpose(); + + this->camera = (invViewMat * mathfu::vec4(0,0,0,1)).xyz(); this->lookAt = (lookAtMat * mathfu::vec4(0,1,0,1)).xyz(); mathfu::vec4 interiorSunDir = mathfu::vec4(-0.30822f, -0.30822f, -0.89999998f, 0); - interiorSunDir = lookAtMat.Transpose().Inverse() * interiorSunDir; + interiorSunDir = invTranspViewMat * interiorSunDir; interiorSunDir = mathfu::vec4(interiorSunDir.xyz() * (1.0f / interiorSunDir.xyz().Length()), 0.0f); this->interiorDirectLightDir = interiorSunDir; mathfu::vec4 upVector ( 0.0, 0.0 , 1.0 , 0.0); - mathfu::mat3 lookAtRotation = mathfu::mat4::ToRotationMatrix(lookAtMat); - this->upVector = (lookAtRotation * upVector.xyz()); + + this->upVector = (invTranspViewMat * upVector).xyz().Normalized(); } void PlanarCamera::setCameraPos (float x, float y, float z) { //Reset camera diff --git a/wowViewerLib/src/engine/camera/planarCamera.h b/wowViewerLib/src/engine/camera/planarCamera.h index a2ade0d35..b0dea49d6 100644 --- a/wowViewerLib/src/engine/camera/planarCamera.h +++ b/wowViewerLib/src/engine/camera/planarCamera.h @@ -62,6 +62,7 @@ class PlanarCamera: public ICamera { void stopMovingUp() override; void startMovingDown() override; void stopMovingDown() override; + void stopAllMovement() override; void addCameraViewOffset(float x, float y) override; From 808bc043e943c13c3929356957a723a5fa1dde92 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 3 Jun 2023 01:38:00 +0300 Subject: [PATCH 078/212] missed file --- wowViewerLib/src/include/controllable.h | 1 + 1 file changed, 1 insertion(+) diff --git a/wowViewerLib/src/include/controllable.h b/wowViewerLib/src/include/controllable.h index ad4ab88e7..aedf7b7a9 100644 --- a/wowViewerLib/src/include/controllable.h +++ b/wowViewerLib/src/include/controllable.h @@ -18,6 +18,7 @@ class IControllable { virtual void stopMovingUp() = 0; virtual void startMovingDown() = 0; virtual void stopMovingDown() = 0; + virtual void stopAllMovement() = 0; virtual void addForwardDiff(float val) = 0; From 457b38c388e717f3c3bff649ec06cd7a5fe395b4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 3 Jun 2023 01:40:06 +0300 Subject: [PATCH 079/212] update ImGUI to stock v1.89.6 --- src/ui/imguiLib/imconfig.h | 78 +- src/ui/imguiLib/imgui.cpp | 15532 ++++++++++------ src/ui/imguiLib/imgui.h | 2305 ++- .../imguiLib/imguiImpl/imgui_impl_android.cpp | 226 +- .../imguiLib/imguiImpl/imgui_impl_android.h | 11 +- src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp | 812 +- src/ui/imguiLib/imguiImpl/imgui_impl_glfw.h | 40 +- .../imguiLib/imguiImpl/imgui_impl_opengl3.cpp | 698 +- .../imguiLib/imguiImpl/imgui_impl_opengl3.h | 64 +- src/ui/imguiLib/imgui_demo.cpp | 5936 ++++-- src/ui/imguiLib/imgui_draw.cpp | 2147 ++- src/ui/imguiLib/imgui_internal.h | 3164 +++- src/ui/imguiLib/imgui_widgets.cpp | 5339 +++--- src/ui/imguiLib/imstb_rectpack.h | 94 +- src/ui/imguiLib/imstb_textedit.h | 202 +- src/ui/imguiLib/imstb_truetype.h | 930 +- 16 files changed, 25344 insertions(+), 12234 deletions(-) diff --git a/src/ui/imguiLib/imconfig.h b/src/ui/imguiLib/imconfig.h index 25cad5f58..876cf32f7 100644 --- a/src/ui/imguiLib/imconfig.h +++ b/src/ui/imguiLib/imconfig.h @@ -3,10 +3,11 @@ // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. //----------------------------------------------------------------------------- -// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) -// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" -// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include -// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. +// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) +// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. +//----------------------------------------------------------------------------- +// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp +// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. //----------------------------------------------------------------------------- @@ -14,31 +15,39 @@ #pragma once //---- Define assertion handler. Defaults to calling assert(). +// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows -// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. //#define IMGUI_API __declspec( dllexport ) //#define IMGUI_API __declspec( dllimport ) -//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. +//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. -//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) -// It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. -//#define IMGUI_DISABLE_DEMO_WINDOWS -//#define IMGUI_DISABLE_METRICS_WINDOW +//---- Disable all of Dear ImGui or don't implement standard windows/tools. +// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. +//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. +//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. +//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). //---- Don't implement some functions to reduce linkage requirements. -//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. -//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) +//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. -//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Include imgui_user.h at the end of imgui.h as a convenience //#define IMGUI_INCLUDE_IMGUI_USER_H @@ -46,44 +55,63 @@ //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) //#define IMGUI_USE_BGRA_PACKED_COLOR +//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) +//#define IMGUI_USE_WCHAR32 + //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version -// By default the embedded implementations are declared static and not available outside of imgui cpp files. +// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) +// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. +//#define IMGUI_USE_STB_SPRINTF + +//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) +// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). +// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. +//#define IMGUI_ENABLE_FREETYPE + +//---- Use stb_truetype to build and rasterize the font atlas (default) +// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. +//#define IMGUI_ENABLE_STB_TRUETYPE + //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. // This will be inlined as part of ImVec2 and ImVec4 class declarations. /* -#define IM_VEC2_CLASS_EXTRA \ - ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ operator MyVec2() const { return MyVec2(x,y); } -#define IM_VEC4_CLASS_EXTRA \ - ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ +#define IM_VEC4_CLASS_EXTRA \ + constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ operator MyVec4() const { return MyVec4(x,y,z,w); } */ +//---- ...Or use Dear ImGui's own very basic math operators. +//#define IMGUI_DEFINE_MATH_OPERATORS //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. -// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). +// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. //#define ImDrawIdx unsigned int -//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) +//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) //struct ImDrawList; //struct ImDrawCmd; //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); //#define ImDrawCallback MyImDrawCallback -//---- Debug Tools -// Use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging. +//---- Debug Tools: Macro to break in Debugger +// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) //#define IM_DEBUG_BREAK IM_ASSERT(0) //#define IM_DEBUG_BREAK __debugbreak() -// Have the Item Picker break in the ItemAdd() function instead of ItemHoverable() - which is earlier in the code, will catch a few extra items, allow picking items other than Hovered one. -// This adds a small runtime cost which is why it is not enabled by default. -//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. /* diff --git a/src/ui/imguiLib/imgui.cpp b/src/ui/imguiLib/imgui.cpp index eea4edbe8..400dcb22b 100644 --- a/src/ui/imguiLib/imgui.cpp +++ b/src/ui/imguiLib/imgui.cpp @@ -1,18 +1,30 @@ -// dear imgui, v1.74 +// dear imgui, v1.89.6 // (main code and documentation) -// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. -// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. -// Get latest version at https://github.com/ocornut/imgui -// Releases change-log at https://github.com/ocornut/imgui/releases -// Technical Support for Getting Started https://github.com/ocornut/imgui/wiki -// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/2847 +// Help: +// - Read FAQ at http://dearimgui.com/faq +// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.com/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues + +// Getting Started? +// - For first-time users having issues compiling/linking/running or issues loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). -// This library is free but I need your support to sustain development and maintenance. -// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README. -// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui. +// This library is free but needs your support to sustain development and maintenance. +// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com". +// Individuals: you can support continued development via donations. See docs/README or web page. // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without @@ -27,35 +39,40 @@ Index of this file: DOCUMENTATION - MISSION STATEMENT -- END-USER GUIDE +- CONTROLS GUIDE - PROGRAMMER GUIDE - READ FIRST - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE - - HOW A SIMPLE APPLICATION MAY LOOK LIKE (2 variations) + - HOW A SIMPLE APPLICATION MAY LOOK LIKE - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE - - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - API BREAKING CHANGES (read me when you update!) - FREQUENTLY ASKED QUESTIONS (FAQ) - - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) + - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer) CODE (search for "[SECTION]" in the code to find them) +// [SECTION] INCLUDES // [SECTION] FORWARD DECLARATIONS // [SECTION] CONTEXT AND MEMORY ALLOCATORS -// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) -// [SECTION] MISC HELPERS/UTILITIES (Geomtry, String, Format, Hash, File functions) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) // [SECTION] MISC HELPERS/UTILITIES (File functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions) // [SECTION] ImGuiStorage // [SECTION] ImGuiTextFilter -// [SECTION] ImGuiTextBuffer +// [SECTION] ImGuiTextBuffer, ImGuiTextIndex // [SECTION] ImGuiListClipper +// [SECTION] STYLING // [SECTION] RENDER HELPERS +// [SECTION] INITIALIZATION, SHUTDOWN // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] INPUTS // [SECTION] ERROR CHECKING +// [SECTION] LAYOUT // [SECTION] SCROLLING // [SECTION] TOOLTIPS // [SECTION] POPUPS @@ -63,8 +80,12 @@ CODE // [SECTION] DRAG AND DROP // [SECTION] LOGGING/CAPTURING // [SECTION] SETTINGS +// [SECTION] LOCALIZATION +// [SECTION] VIEWPORTS, PLATFORM WINDOWS // [SECTION] PLATFORM DEPENDENT HELPERS -// [SECTION] METRICS/DEBUG WINDOW +// [SECTION] METRICS/DEBUGGER WINDOW +// [SECTION] DEBUG LOG WINDOW +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) */ @@ -80,40 +101,85 @@ CODE - Easy to use to create code-driven and data-driven tools. - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. - Easy to hack and improve. - - Minimize screen real-estate usage. - Minimize setup and maintenance. - Minimize state storage on user side. + - Minimize state synchronization. - Portable, minimize dependencies, run on target (consoles, phones, etc.). - - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,. - opening a tree node for the first time, etc. but a typical frame should not allocate anything). + - Efficient runtime and memory consumption. + + Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes: - Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: - Doesn't look fancy, doesn't animate. - Limited layout features, intricate layouts are typically crafted in code. - END-USER GUIDE + CONTROLS GUIDE ============== - - Double-click on title bar to collapse window. - - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). - - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). - - Click and drag on any empty space to move window. - - TAB/SHIFT+TAB to cycle through keyboard editable fields. - - CTRL+Click on a slider or drag box to input value as text. - - Use mouse wheel to scroll. - - Text editor: - - Hold SHIFT or use mouse to select text. - - CTRL+Left/Right to word jump. - - CTRL+Shift+Left/Right to select words. - - CTRL+A our Double-Click to select all. - - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ - - CTRL+Z,CTRL+Y to undo/redo. - - ESCAPE to revert text to its original value. - - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) - - Controls are automatically adjusted for OSX to match standard OSX text editing operations. - - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. - - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW + - MOUSE CONTROLS + - Mouse wheel: Scroll vertically. + - SHIFT+Mouse wheel: Scroll horizontally. + - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click ^, Double-Click title: Collapse window. + - Drag on corner/border: Resize window (double-click to auto fit window to its contents). + - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true). + - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack). + + - TEXT EDITOR + - Hold SHIFT or Drag Mouse: Select text. + - CTRL+Left/Right: Word jump. + - CTRL+Shift+Left/Right: Select words. + - CTRL+A or Double-Click: Select All. + - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard. + - CTRL+Z, CTRL+Y: Undo, Redo. + - ESCAPE: Revert text to its original value. + - On OSX, controls are automatically adjusted to match standard OSX text editing shortcuts and behaviors. + + - KEYBOARD CONTROLS + - Basic: + - Tab, SHIFT+Tab Cycle through text editable fields. + - CTRL+Tab, CTRL+Shift+Tab Cycle through windows. + - CTRL+Click Input text into a Slider or Drag widget. + - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`: + - Tab, SHIFT+Tab: Cycle through every items. + - Arrow keys Move through items using directional navigation. Tweak value. + - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys). + - Enter Activate item (prefer text input when possible). + - Space Activate item (prefer tweaking with arrows when possible). + - Escape Deactivate item, leave child window, close popup. + - Page Up, Page Down Previous page, next page. + - Home, End Scroll to top, scroll to bottom. + - Alt Toggle between scrolling layer and menu layer. + - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving. + - Output when ImGuiConfigFlags_NavEnableKeyboard set, + - io.WantCaptureKeyboard flag is set when keyboard is claimed. + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used). + + - GAMEPAD CONTROLS + - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse! + - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets + - Backend support: backend needs to: + - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. + - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. + Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! + - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, + with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + + - REMOTE INPUTS SHARING & MOUSE EMULATION + - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app) + in order to share your PC mouse/keyboard. + - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) PROGRAMMER GUIDE @@ -121,17 +187,17 @@ CODE READ FIRST ---------- - - Remember to read the FAQ (https://www.dearimgui.org/faq) - - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction - or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. + - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) + - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or + destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). - You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md. + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. - For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, + For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI, where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. - - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). If you get an assert, read the messages and comments around the assert. @@ -141,32 +207,39 @@ CODE However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI ---------------------------------------------- - - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) - - Or maintain your own branch where you have imconfig.h modified. + - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master". + - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file. - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it. Please report any issue to the GitHub page! - - Try to keep your copy of dear imgui reasonably up to date. + - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file. + - Try to keep your copy of Dear ImGui reasonably up to date. + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE --------------------------------------------------------------- - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. - - Add the Dear ImGui source files to your projects or using your preferred build system. - It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL). + - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder. + - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system. + It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL). - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" - phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render(). - - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. + phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render(). + - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code. - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. + HOW A SIMPLE APPLICATION MAY LOOK LIKE -------------------------------------- - EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder). + EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). + The sub-folders in examples/ contain examples applications following this structure. // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -175,7 +248,7 @@ CODE // TODO: Fill optional fields of the io structure later. // TODO: Load TTF/OTF fonts if you don't want to use the default font. - // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32 and imgui_impl_dx11) + // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); @@ -201,7 +274,7 @@ CODE ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); - EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE + EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -213,29 +286,29 @@ CODE // Build and load the texture atlas into a texture // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) int width, height; - unsigned char* pixels = NULL; + unsigned char* pixels = nullptr; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - // At this point you've got the texture data and you need to upload that your your graphic system: + // At this point you've got the texture data and you need to upload that to your graphic system: // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) - io.Fonts->TexID = (void*)texture; + io.Fonts->SetTexID((void*)texture); // Application main loop while (true) { // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. - // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) + // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends) io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) io.DisplaySize.x = 1920.0f; // set the current display width io.DisplaySize.y = 1280.0f; // set the current display height here - io.MousePos = my_mouse_pos; // set the mouse position - io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states - io.MouseDown[1] = my_mouse_buttons[1]; + io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position + io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states + io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states // Call NewFrame(), after this point you can use ImGui::* functions anytime - // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere) + // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere) ImGui::NewFrame(); // Most of your application code here @@ -255,14 +328,23 @@ CODE // Shutdown ImGui::DestroyContext(); + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, + you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + Please read the FAQ and example applications for details about this! + + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE --------------------------------------------- - void void MyImGuiRenderFunction(ImDrawData* draw_data) + The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. + + void MyImGuiRenderFunction(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -277,86 +359,234 @@ CODE } else { - // The texture for the draw call is specified by pcmd->TextureId. - // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. - MyEngineBindTexture((MyTexture*)pcmd->TextureId); + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); + ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; - // We are using scissoring to clip some objects. All low-level graphics API should supports it. + // We are using scissoring to clip some objects. All low-level graphics API should support it. // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches // (some elements visible outside their bounds) but you can fix that once everything else works! - // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) - // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. - // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), - // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Clipping coordinates are provided in imgui coordinates space: + // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size + // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. + // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) - ImVec2 pos = draw_data->DisplayPos; - MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); + MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y); + + // The texture for the draw call is specified by pcmd->GetTexID(). + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); // Render 'pcmd->ElemCount/3' indexed triangles. // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. - MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset); } - idx_buffer += pcmd->ElemCount; } } } - - The examples/ folders contains many actual implementation of the pseudo-codes above. - - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. - They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the - rest of your application. In every cases you need to pass on the inputs to Dear ImGui. - - Refer to the FAQ for more information. Amusingly, it is called a FAQ because people frequently run into the same issues! - - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - ------------------------------------------ - - The gamepad/keyboard navigation is fairly functional and keeps being improved. - - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse! - - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 - - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. - - Gamepad: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. - - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). - Note that io.NavInputs[] is cleared by EndFrame(). - - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: - 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. - - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. - Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). - - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. - - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo - to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. - - Keyboard: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. - NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag - will be set. For more advanced uses, you may want to read from: - - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. - - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). - - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. - Please reach out if you think the game vs navigation input sharing could be improved. - - Mouse: - - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. - - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. - - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. - Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. - When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. - When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. - (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) - (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want - to set a boolean to ignore your other external mouse positions until the external source is moved again.) - API BREAKING CHANGES ==================== Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. - When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. + When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. + - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago: + - ListBoxHeader() -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference) + - ListBoxFooter() -> use EndListBox() + - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin(). + - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices(). + - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago: + - ImGuiSliderFlags_ClampOnInput -> use ImGuiSliderFlags_AlwaysClamp + - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite + - ImDrawList::AddBezierCurve() -> use ImDrawList::AddBezierCubic() + - ImDrawList::PathBezierCurveTo() -> use ImDrawList::PathBezierCubicCurveTo() + - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete). + - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner. + - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h. + Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA, + it has been frequently requested by people to use our own. We had an opt-in define which was + previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164) + - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h" + - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h" + - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3. + - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79. + - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details. + - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete). + - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl + - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift + - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt + - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super + the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends. + the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions. + exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway. + - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. + this will require uses of legacy backend-dependent indices to be casted, e.g. + - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A); + - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A') + - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now! + - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr); + - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020): + - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. + - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. + - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags) + - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries. + this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item. + - previously this would make the window content size ~200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); + - instead, please submit an item: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); + - alternative: + Begin(...) + Dummy(ImVec2(200,200)) + End(); + - content size is now only extended when submitting an item! + - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert. + - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it. + - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete). + - added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter. + - old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1)); + - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values. + - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer. + - new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1)); + - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier. + - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this. + - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes). + - Official backends from 1.87+ -> no issue. + - Official backends from 1.60 to 1.86 -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating! + - Custom backends not writing to io.NavInputs[] -> no issue. + - Custom backends writing to io.NavInputs[] -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing! + - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[]. + - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete). + - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary. + - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO. + - 2022/01/20 (1.87) - inputs: reworded gamepad IO. + - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values. + - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used). + - 2022/01/17 (1.87) - inputs: reworked mouse IO. + - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent() + - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent() + - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent() + - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only] + note: for all calls to IO new functions, the Dear ImGui context should be bound/current. + read https://github.com/ocornut/imgui/issues/4921 for details. + - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. + - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) + - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) + - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes). + - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.* + - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert. + - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper. + - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. + - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'. + - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019) + - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen() + - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x + - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing()); + - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect + - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex + - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings + - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function. + - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful. + - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019): + - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList() + - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder + - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID(). + - if you are using official backends from the source tree: you have nothing to do. + - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID(). + - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags. + - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft + - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight + - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc. + flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API. + breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners": + - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use) + - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use) + - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use) + - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f. + this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok. + the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts. + legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise). + - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018): + - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY() + - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing. + - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future. + - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'. + - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed. + - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). + - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). + - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). + - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): + - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). + - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg + - ImGuiInputTextCallback -> use ImGuiTextEditCallback + - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData + - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete). + - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added! + - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API. + - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures + - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018): + - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend + - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow) + - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT + - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT + - removed redirecting functions names that were marked obsolete in 1.61 (May 2018): + - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision. + - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter. + - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed). + - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). + - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. + - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. + - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. + - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! + - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). + replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). + worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: + - if you omitted the 'power' parameter (likely!), you are not affected. + - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. + - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. + see https://github.com/ocornut/imgui/issues/3361 for all details. + kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used. + for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. + - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. + - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. + - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79] + - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. + - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). + - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. + - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. + - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. + - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): + - ShowTestWindow() -> use ShowDemoWindow() + - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) + - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) + - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) + - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() + - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg + - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding + - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap + - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS + - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API. + - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. - - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): Begin() (5 arguments signature), IsRootWindowOrAnyChildHovered(), AlignFirstTextHeightToWidgets(), SetNextWindowPosCenter(), ImFont::Glyph. See docs/Changelog.txt or grep this log for details and new names, or see how they were implemented until 1.73. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): + - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed + - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) + - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() + - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) + - ImFont::Glyph -> use ImFontGlyph - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). @@ -374,7 +604,7 @@ CODE - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). - - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value! + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value! - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). @@ -395,10 +625,10 @@ CODE - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). - - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). - old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports. - when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. - in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. + - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports. + when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call. + in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. @@ -408,7 +638,7 @@ CODE - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", consistent with other functions. Kept redirection functions (will obsolete). - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. - - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). + - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch). - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. @@ -452,7 +682,7 @@ CODE - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). - - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). @@ -465,24 +695,24 @@ CODE - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. - - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))' + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))' - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. - - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild(). - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. - If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. - This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. - - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337). - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. @@ -499,7 +729,7 @@ CODE you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. this necessary change will break your rendering function! the fix should be very easy. sorry for that :( - - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. + - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. - the signature of the io.RenderDrawListsFn handler has changed! old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). @@ -513,7 +743,7 @@ CODE - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence - - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry! - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. @@ -535,14 +765,13 @@ CODE - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. - (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. - font init: { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; } - became: { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; } - you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. - it is now recommended that you sample the font texture with bilinear interpolation. - (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. - (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) - (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets + - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. + - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier); + you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID() + - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) + - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility @@ -559,221 +788,117 @@ CODE FREQUENTLY ASKED QUESTIONS (FAQ) ================================ - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) + Read all answers online: + https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) + Read all answers locally (with a text editor or ideally a Markdown viewer): + docs/FAQ.md Some answers are copied down here to facilitate searching in code. Q&A: Basics =========== Q: Where is the documentation? - A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++. + A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++. - Run the examples/ and explore them. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. - The demo covers most features of Dear ImGui, so you can read the code and see its output. - See documentation and comments at the top of imgui.cpp + effectively imgui.h. - - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ - folder to explain how to integrate Dear ImGui with your own engine/application. + - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the + examples/ folder to explain how to integrate Dear ImGui with your own engine/application. + - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. + - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. - Your programming IDE is your friend, find the type or function declaration to find comments - associated to it. + associated with it. + Q: What is this library called? Q: Which version should I get? - Q: Why the names "Dear ImGui" vs "ImGui"? - >> See https://www.dearimgui.org/faq - - Q&A: Concerns - ============= - - Q: Who uses Dear ImGui? - Q: Can you create elaborate/serious tools with Dear ImGui? - Q: Can you reskin the look of Dear ImGui? - Q: Why using C++ (as opposed to C)? - >> See https://www.dearimgui.org/faq + >> This library is called "Dear ImGui", please don't call it "ImGui" :) + >> See https://www.dearimgui.com/faq for details. Q&A: Integration ================ - Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application? - A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } ) - - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application. - - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application. - - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS). - Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false. - This is because imgui needs to detect that you clicked in the void to unfocus its own windows. - Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!). - It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs. - Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also - perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to UpdateHoveredWindowAndCaptureFlags(). - Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically - have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs - were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) + Q: How to get started? + A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. + Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application? + A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this. + + Q. How can I enable keyboard controls? Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) - Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. - Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - >> See https://www.dearimgui.org/faq + Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around... + Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries... + >> See https://www.dearimgui.com/faq Q&A: Usage ---------- - Q: Why are multiple widgets reacting when I interact with a single one? - Q: How can I have multiple widgets with the same label or with an empty label? - A: A primer on labels and the ID Stack... - - Dear ImGui internally need to uniquely identify UI elements. - Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. - Interactive widgets (such as calls to Button buttons) need a unique ID. - Unique ID are used internally to track active widgets and occasionally associate state to widgets. - Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. - - - Unique ID are often derived from a string label: - - Button("OK"); // Label = "OK", ID = hash of (..., "OK") - Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel") - - - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having - two buttons labeled "OK" in different windows or different tree locations is fine. - We used "..." above to signify whatever was already pushed to the ID stack previously: - - Begin("MyWindow"); - Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK") - End(); - Begin("MyOtherWindow"); - Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK") - End(); - - - If you have a same ID twice in the same location, you'll have a conflict: - - Button("OK"); - Button("OK"); // ID collision! Interacting with either button will trigger the first one. - - Fear not! this is easy to solve and there are many ways to solve it! - - - Solving ID conflict in a simple/local context: - When passing a label you can optionally specify extra ID information within string itself. - Use "##" to pass a complement to the ID that won't be visible to the end-user. - This helps solving the simple collision cases when you know e.g. at compilation time which items - are going to be created: - - Begin("MyWindow"); - Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play") - Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above - Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above - End(); - - - If you want to completely hide the label, but still need an ID: - - Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox! - - - Occasionally/rarely you might want change a label while preserving a constant ID. This allows - you to animate labels. For example you may want to include varying information in a window title bar, - but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: - - Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID") - Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different - - sprintf(buf, "My game (%f FPS)###MyGame", fps); - Begin(buf); // Variable title, ID = hash of "MyGame" - - - Solving ID conflict in a more general manner: - Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts - within the same window. This is the most convenient way of distinguishing ID when iterating and - creating many UI elements programmatically. - You can push a pointer, a string or an integer value into the ID stack. - Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack. - At each level of the stack we store the seed used for items at this level of the ID stack. - - Begin("Window"); - for (int i = 0; i < 100; i++) - { - PushID(i); // Push i to the id tack - Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click") - PopID(); - } - for (int i = 0; i < 100; i++) - { - MyObject* obj = Objects[i]; - PushID(obj); - Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click") - PopID(); - } - for (int i = 0; i < 100; i++) - { - MyObject* obj = Objects[i]; - PushID(obj->Name); - Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click") - PopID(); - } - End(); - - - You can stack multiple prefixes into the ID stack: - - Button("Click"); // Label = "Click", ID = hash of (..., "Click") - PushID("node"); - Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") - PushID(my_ptr); - Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") - PopID(); - PopID(); - - - Tree nodes implicitly creates a scope for you by calling PushID(). - - Button("Click"); // Label = "Click", ID = hash of (..., "Click") - if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag) - { - Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") - TreePop(); - } - - - When working with trees, ID are used to preserve the open/close state of each tree node. - Depending on your use cases you may want to use strings, indices or pointers as ID. - e.g. when following a single pointer that may change over time, using a static string as ID - will preserve your node open/closed state when the targeted object change. - e.g. when displaying a list of objects, using indices or pointers as ID will preserve the - node open/closed state differently. See what makes more sense in your situation! - - Q: How can I display an image? What is ImTextureID, how does it works? - >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - + Q: About the ID Stack system.. + - Why is my widget not reacting when I click on it? + - How can I have widgets with an empty label? + - How can I have multiple widgets with the same label? + - How can I have multiple windows with the same label? + Q: How can I display an image? What is ImTextureID, how does it work? Q: How can I use my own math types instead of ImVec2/ImVec4? Q: How can I interact with standard C++ types (such as std::string and std::vector)? Q: How can I display custom shapes? (using low-level ImDrawList API) - >> See https://www.dearimgui.org/faq + >> See https://www.dearimgui.com/faq Q&A: Fonts, Text ================ + Q: How should I handle DPI in my application? Q: How can I load a different font than the default? Q: How can I easily use icons in my application? Q: How can I load multiple fonts? Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - >> See https://www.dearimgui.org/faq and docs/FONTS.txt + >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md + + Q&A: Concerns + ============= + + Q: Who uses Dear ImGui? + Q: Can you create elaborate/serious tools with Dear ImGui? + Q: Can you reskin the look of Dear ImGui? + Q: Why using C++ (as opposed to C)? + >> See https://www.dearimgui.com/faq Q&A: Community ============== Q: How can I help? - A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui! + We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. + This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project. + - Individuals: you can support continued development via PayPal donations. See README. + - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt and see how you want to help and can help! - - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui. - - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README. - - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. - You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/2847). Visuals are ideal as they inspire other programmers. - But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. - - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). + - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. + You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately). */ +//------------------------------------------------------------------------- +// [SECTION] INCLUDES +//------------------------------------------------------------------------- + #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif -#include "imgui.h" #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE #include "imgui_internal.h" -#include // toupper +// System includes #include // vsnprintf, sscanf, printf #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t @@ -781,36 +906,69 @@ CODE #include // intptr_t #endif -// Debug options -#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL -#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window -#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file +// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled +#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif + +// [Windows] OS specific includes (optional) +#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_FUNCTIONS +#endif +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef __MINGW32__ +#include // _wfopen, OpenClipboard +#else +#include +#endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif +#endif + +// [Apple] OS specific includes +#if defined(__APPLE__) +#include +#endif // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif // Clang/GCC warnings with -Weverything #if defined(__clang__) -#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great! -#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. -#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. -#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. -#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. -#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 -#endif -#if __has_warning("-Wdouble-promotion") -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! #endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #elif defined(__GNUC__) -// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association. +// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size @@ -822,14 +980,19 @@ CODE #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif +// Debug options +#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL +#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window +#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower) + // When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear -// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) -static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend) +static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow(). static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. -static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certaint time, unless mouse moved. +static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. //------------------------------------------------------------------------- // [SECTION] FORWARD DECLARATIONS @@ -837,54 +1000,71 @@ static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock static void SetCurrentWindow(ImGuiWindow* window); static void FindHoveredWindow(); -static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); -static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); -static ImRect GetViewportRect(); - // Settings +static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); // Platform Dependents default implementation for IO functions -static const char* GetClipboardTextFn_DefaultImpl(void* user_data); -static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data); namespace ImGui { -static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); - // Navigation static void NavUpdate(); static void NavUpdateWindowing(); static void NavUpdateWindowingOverlay(); -static void NavUpdateMoveResult(); +static void NavUpdateCancelRequest(); +static void NavUpdateCreateMoveRequest(); +static void NavUpdateCreateTabbingRequest(); static float NavUpdatePageUpPageDown(); static inline void NavUpdateAnyRequestFlag(); -static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); -static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); +static void NavUpdateCreateWrappingRequest(); +static void NavEndFrame(); +static bool NavScoreItem(ImGuiNavItemData* result); +static void NavApplyItemToResult(ImGuiNavItemData* result); +static void NavProcessItem(); +static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static void NavRestoreLayer(ImGuiNavLayer layer); +static void NavRestoreHighlightAfterMove(); static int FindWindowFocusIndex(ImGuiWindow* window); -// Error Checking -static void ErrorCheckEndFrame(); -static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); +// Error Checking and Debug Tools +static void ErrorCheckNewFrameSanityChecks(); +static void ErrorCheckEndFrameSanityChecks(); +static void UpdateDebugToolItemPicker(); +static void UpdateDebugToolStackQueries(); -// Misc +// Inputs +static void UpdateKeyboardInputs(); static void UpdateMouseInputs(); static void UpdateMouseWheel(); -static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); -static void UpdateDebugToolItemPicker(); +static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); + +// Misc +static void UpdateSettings(); +static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); -static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); +static void RenderDimmedBackgrounds(); + +// Viewports +static void UpdateViewportsNewFrame(); } @@ -892,27 +1072,33 @@ static void RenderWindowTitleBarContents(ImGuiWindow* window, const // [SECTION] CONTEXT AND MEMORY ALLOCATORS //----------------------------------------------------------------------------- +// DLL users: +// - Heaps and globals are not shared across DLL boundaries! +// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from. +// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL). +// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in). + // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. -// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). -// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call -// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. -// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. -// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. -// If you want thread-safety to allow N threads to access N different contexts, you can: -// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: -// struct ImGuiContext; -// extern thread_local ImGuiContext* MyImGuiTLS; -// #define GImGui MyImGuiTLS -// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. -// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 -// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. +// - ImGui::CreateContext() will automatically set this pointer if it is NULL. +// Change to a different context by calling ImGui::SetCurrentContext(). +// - Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts: +// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace. +// - DLL users: read comments above. #ifndef GImGui ImGuiContext* GImGui = NULL; #endif // Memory Allocator functions. Use SetAllocatorFunctions() to change them. -// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. -// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - DLL users: read comments above. #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } @@ -920,20 +1106,20 @@ static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_d static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } #endif - -static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; -static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; -static void* GImAllocatorUserData = NULL; +static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper; +static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; +static void* GImAllocatorUserData = NULL; //----------------------------------------------------------------------------- -// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) //----------------------------------------------------------------------------- ImGuiStyle::ImGuiStyle() { - Alpha = 1.0f; // Global alpha applies to everything in ImGui + Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. + DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. WindowPadding = ImVec2(8,8); // Padding within a window - WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows + WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. WindowMinSize = ImVec2(32,32); // Minimum window size WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text @@ -947,24 +1133,32 @@ ImGuiStyle::ImGuiStyle() FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) + CellPadding = ImVec2(4,2); // Padding within a table cell TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar - GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar + GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. + TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. - SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text when button is larger than text. - DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. + SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText() + SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. - AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. - AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. + AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). + AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. // Default theme ImGui::StyleColorsDark(this); @@ -983,6 +1177,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) FrameRounding = ImFloor(FrameRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); + CellPadding = ImFloor(CellPadding * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); IndentSpacing = ImFloor(IndentSpacing * scale_factor); ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); @@ -990,7 +1185,10 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); TabRounding = ImFloor(TabRounding * scale_factor); + TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -1000,21 +1198,26 @@ ImGuiIO::ImGuiIO() { // Most fields are initialized with zero memset(this, 0, sizeof(*this)); + IM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Settings ConfigFlags = ImGuiConfigFlags_None; BackendFlags = ImGuiBackendFlags_None; DisplaySize = ImVec2(-1.0f, -1.0f); - DeltaTime = 1.0f/60.0f; + DeltaTime = 1.0f / 60.0f; IniSavingRate = 5.0f; - IniFilename = "imgui.ini"; + IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). LogFilename = "imgui_log.txt"; MouseDoubleClickTime = 0.30f; MouseDoubleClickMaxDist = 6.0f; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO for (int i = 0; i < ImGuiKey_COUNT; i++) KeyMap[i] = -1; +#endif KeyRepeatDelay = 0.275f; KeyRepeatRate = 0.050f; + HoverDelayNormal = 0.30f; + HoverDelayShort = 0.10f; UserData = NULL; Fonts = NULL; @@ -1030,62 +1233,401 @@ ImGuiIO::ImGuiIO() #else ConfigMacOSXBehaviors = false; #endif + ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; + ConfigInputTextEnterKeepActive = false; + ConfigDragClickToInputText = false; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; - ConfigWindowsMemoryCompactTimer = 60.0f; + ConfigMemoryCompactTimer = 60.0f; + ConfigDebugBeginReturnValueOnce = false; + ConfigDebugBeginReturnValueLoop = false; // Platform Functions + // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; - GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations - SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; - ClipboardUserData = NULL; - ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; - ImeWindowHandle = NULL; - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - RenderDrawListsFn = NULL; -#endif // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseSource = ImGuiMouseSource_Mouse; MouseDragThreshold = 6.0f; for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; - for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; - for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } + AppAcceptingEvents = true; + BackendUsingLegacyKeyArrays = (ImS8)-1; + BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong } // Pass in translated ASCII characters for text input. // - with glfw you can get those from the callback set in glfwSetCharCallback() // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message +// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API void ImGuiIO::AddInputCharacter(unsigned int c) { - if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) - InputQueueCharacters.push_back((ImWchar)c); + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + if (c == 0 || !AppAcceptingEvents) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Text; + e.Source = ImGuiInputSource_Keyboard; + e.EventId = g.InputEventsNextEventId++; + e.Text.Char = c; + g.InputEventsQueue.push_back(e); +} + +// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so +// we should save the high surrogate. +void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) +{ + if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents) + return; + + if ((c & 0xFC00) == 0xD800) // High surrogate, must save + { + if (InputQueueSurrogate != 0) + AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID); + InputQueueSurrogate = c; + return; + } + + ImWchar cp = c; + if (InputQueueSurrogate != 0) + { + if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate + { + AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID); + } + else + { +#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF + cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar +#else + cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); +#endif + } + + InputQueueSurrogate = 0; + } + AddInputCharacter((unsigned)cp); } void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) { + if (!AppAcceptingEvents) + return; while (*utf8_chars != 0) { unsigned int c = 0; utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); - if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) - InputQueueCharacters.push_back((ImWchar)c); + AddInputCharacter(c); } } +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputCharacters() { InputQueueCharacters.resize(0); } +// FIXME: Perhaps we could clear queued events as well? +void ImGuiIO::ClearInputKeys() +{ +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + memset(KeysDown, 0, sizeof(KeysDown)); +#endif + for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) + { + KeysData[n].Down = false; + KeysData[n].DownDuration = -1.0f; + KeysData[n].DownDurationPrev = -1.0f; + } + KeyCtrl = KeyShift = KeyAlt = KeySuper = false; + KeyMods = ImGuiMod_None; + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++) + { + MouseDown[n] = false; + MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f; + } + MouseWheel = MouseWheelH = 0.0f; +} + +static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1) +{ + ImGuiContext& g = *ctx; + for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--) + { + ImGuiInputEvent* e = &g.InputEventsQueue[n]; + if (e->Type != type) + continue; + if (type == ImGuiInputEventType_Key && e->Key.Key != arg) + continue; + if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg) + continue; + return e; + } + return NULL; +} + +// Queue a new key down/up event. +// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) +// - bool down: Is the key down? use false to signify a key release. +// - float analog_value: 0.0f..1.0f +// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE. +// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT. +void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) +{ + //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } + IM_ASSERT(Ctx != NULL); + if (key == ImGuiKey_None || !AppAcceptingEvents) + return; + ImGuiContext& g = *Ctx; + IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API. + IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. + IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself) + + // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + if (BackendUsingLegacyKeyArrays == -1) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + BackendUsingLegacyKeyArrays = 0; +#endif + if (ImGui::IsGamepadKey(key)) + BackendUsingLegacyNavInputArray = false; + + // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); + const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key); + const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; + const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue; + if (latest_key_down == down && latest_key_analog == analog_value) + return; + + // Add event + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Key; + e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard; + e.EventId = g.InputEventsNextEventId++; + e.Key.Key = key; + e.Key.Down = down; + e.Key.AnalogValue = analog_value; + g.InputEventsQueue.push_back(e); +} + +void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down) +{ + if (!AppAcceptingEvents) + return; + AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f); +} + +// [Optional] Call after AddKeyEvent(). +// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices. +// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this. +void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index) +{ + if (key == ImGuiKey_None) + return; + IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512 + IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511 + IM_UNUSED(native_keycode); // Yet unused + IM_UNUSED(native_scancode); // Yet unused + + // Build native->imgui map so old user code can still call key functions with native 0..511 values. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode; + if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key)) + return; + KeyMap[legacy_key] = key; + KeyMap[key] = legacy_key; +#else + IM_UNUSED(key); + IM_UNUSED(native_legacy_index); +#endif +} + +// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. +void ImGuiIO::SetAppAcceptingEvents(bool accepting_events) +{ + AppAcceptingEvents = accepting_events; +} + +// Queue a mouse move event +void ImGuiIO::AddMousePosEvent(float x, float y) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + if (!AppAcceptingEvents) + return; + + // Apply same flooring as UpdateMouseInputs() + ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y); + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos); + const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos; + if (latest_pos.x == pos.x && latest_pos.y == pos.y) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MousePos; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MousePos.PosX = pos.x; + e.MousePos.PosY = pos.y; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); + if (!AppAcceptingEvents) + return; + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button); + const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button]; + if (latest_button_down == down) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MouseButton; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MouseButton.Button = mouse_button; + e.MouseButton.Down = down; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +// Queue a mouse wheel event (some mouse/API may only have a Y component) +void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + + // Filter duplicate (unlike most events, wheel values are relative and easy to filter) + if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MouseWheel; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MouseWheel.WheelX = wheel_x; + e.MouseWheel.WheelY = wheel_y; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +// This is not a real event, the data is latched in order to be stored in actual Mouse events. +// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes. +void ImGuiIO::AddMouseSourceEvent(ImGuiMouseSource source) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + g.InputEventsNextMouseSource = source; +} + +void ImGuiIO::AddFocusEvent(bool focused) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus); + const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost; + if (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused)) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Focus; + e.EventId = g.InputEventsNextEventId++; + e.AppFocused.Focused = focused; + g.InputEventsQueue.push_back(e); +} + //----------------------------------------------------------------------------- -// [SECTION] MISC HELPERS/UTILITIES (Geometry, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) //----------------------------------------------------------------------------- +ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) +{ + IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau() + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + { + ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + return p_closest; +} + +// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp +static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + ImVec2 p_current(x4, y4); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + else if (level < 10) + { + float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; + float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; + float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; + float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; + float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; + float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol +// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. +ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) +{ + IM_ASSERT(tess_tol > 0.0f); + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + return p_closest; +} + ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) { ImVec2 ap = p - a; @@ -1134,18 +1676,22 @@ ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, return proj_ca; } +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +//----------------------------------------------------------------------------- + // Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. int ImStricmp(const char* str1, const char* str2) { int d; - while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } + while ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } int ImStrnicmp(const char* str1, const char* str2, size_t count) { int d = 0; - while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } + while (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; } return d; } @@ -1212,14 +1758,14 @@ const char* ImStristr(const char* haystack, const char* haystack_end, const char if (!needle_end) needle_end = needle + strlen(needle); - const char un0 = (char)toupper(*needle); + const char un0 = (char)ImToUpper(*needle); while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) { - if (toupper(*haystack) == un0) + if (ImToUpper(*haystack) == un0) { const char* b = needle + 1; for (const char* a = haystack + 1; b < needle_end; a++, b++) - if (toupper(*a) != toupper(*b)) + if (ImToUpper(*a) != ImToUpper(*b)) break; if (b == needle_end) return haystack; @@ -1258,14 +1804,17 @@ const char* ImStrSkipBlank(const char* str) #ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) -// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS -// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are +// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) -//#define IMGUI_USE_STB_SPRINTF #ifdef IMGUI_USE_STB_SPRINTF #define STB_SPRINTF_IMPLEMENTATION +#ifdef IMGUI_STB_SPRINTF_FILENAME +#include IMGUI_STB_SPRINTF_FILENAME +#else #include "stb_sprintf.h" #endif +#endif #if defined(_MSC_VER) && !defined(vsnprintf) #define vsnprintf _vsnprintf @@ -1305,6 +1854,43 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) } #endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + va_list args; + va_start(args, fmt); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + { + const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" + *out_buf = buf; + if (out_buf_end) { *out_buf_end = buf + strlen(buf); } + } + else + { + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } + } + va_end(args); +} + +void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + { + const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" + *out_buf = buf; + if (out_buf_end) { *out_buf_end = buf + strlen(buf); } + } + else + { + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } + } +} + // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. @@ -1331,7 +1917,7 @@ static const ImU32 GCrc32LookupTable[256] = // Known size hash // It is ok to call ImHashData on a string with known length but the ### operator won't be supported. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) +ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) { ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; @@ -1347,7 +1933,7 @@ ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) // - If we reach ### in the string we discard the hash so far and reset to the seed. // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) +ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) { seed = ~seed; ImU32 crc = seed; @@ -1381,17 +1967,19 @@ ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) // Default file functions #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + ImFileHandle ImFileOpen(const char* filename, const char* mode) { #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) - // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. - const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; - const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; - ImVector buf; + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. + // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! + const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + ImVector buf; buf.resize(filename_wsize + mode_wsize); - ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); - ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); - return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); + return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); #else return fopen(filename, mode); #endif @@ -1406,6 +1994,7 @@ ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) // Helper: Load file content into memory // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() +// This can't really be used with "rt" because fseek size won't match read size. void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) { IM_ASSERT(filename && mode); @@ -1449,79 +2038,72 @@ void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_f // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) //----------------------------------------------------------------------------- +IM_MSVC_RUNTIME_CHECKS_OFF + // Convert UTF-8 to 32-bit character, process single character input. -// Based on stb_from_utf8() from github.com/nothings/stb/ +// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). // We handle UTF-8 decoding error by skipping forward. int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) { - unsigned int c = (unsigned int)-1; - const unsigned char* str = (const unsigned char*)in_text; - if (!(*str & 0x80)) - { - c = (unsigned int)(*str++); - *out_char = c; - return 1; - } - if ((*str & 0xe0) == 0xc0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 2) return 1; - if (*str < 0xc2) return 2; - c = (unsigned int)((*str++ & 0x1f) << 6); - if ((*str & 0xc0) != 0x80) return 2; - c += (*str++ & 0x3f); - *out_char = c; - return 2; - } - if ((*str & 0xf0) == 0xe0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 3) return 1; - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; - if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below - c = (unsigned int)((*str++ & 0x0f) << 12); - if ((*str & 0xc0) != 0x80) return 3; - c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 3; - c += (*str++ & 0x3f); - *out_char = c; - return 3; - } - if ((*str & 0xf8) == 0xf0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 4) return 1; - if (*str > 0xf4) return 4; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; - if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below - c = (unsigned int)((*str++ & 0x07) << 18); - if ((*str & 0xc0) != 0x80) return 4; - c += (unsigned int)((*str++ & 0x3f) << 12); - if ((*str & 0xc0) != 0x80) return 4; - c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 4; - c += (*str++ & 0x3f); - // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return 4; - *out_char = c; - return 4; - } - *out_char = 0; - return 0; -} - -int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) -{ - ImWchar* buf_out = buf; - ImWchar* buf_end = buf + buf_size; - while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 }; + static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 }; + static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 }; + static const int shiftc[] = { 0, 18, 12, 6, 0 }; + static const int shifte[] = { 0, 6, 4, 2, 0 }; + int len = lengths[*(const unsigned char*)in_text >> 3]; + int wanted = len + (len ? 0 : 1); + + if (in_text_end == NULL) + in_text_end = in_text + wanted; // Max length, nulls will be taken into account. + + // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here, + // so it is fast even with excessive branching. + unsigned char s[4]; + s[0] = in_text + 0 < in_text_end ? in_text[0] : 0; + s[1] = in_text + 1 < in_text_end ? in_text[1] : 0; + s[2] = in_text + 2 < in_text_end ? in_text[2] : 0; + s[3] = in_text + 3 < in_text_end ? in_text[3] : 0; + + // Assume a four-byte character and load four bytes. Unused bits are shifted out. + *out_char = (uint32_t)(s[0] & masks[len]) << 18; + *out_char |= (uint32_t)(s[1] & 0x3f) << 12; + *out_char |= (uint32_t)(s[2] & 0x3f) << 6; + *out_char |= (uint32_t)(s[3] & 0x3f) << 0; + *out_char >>= shiftc[len]; + + // Accumulate the various error conditions. + int e = 0; + e = (*out_char < mins[len]) << 6; // non-canonical encoding + e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half? + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range? + e |= (s[1] & 0xc0) >> 2; + e |= (s[2] & 0xc0) >> 4; + e |= (s[3] ) >> 6; + e ^= 0x2a; // top two bits of each tail byte correct? + e >>= shifte[len]; + + if (e) + { + // No bytes are consumed when *in_text == 0 || in_text == in_text_end. + // One byte is consumed in case of invalid first byte of in_text. + // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes. + // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s. + wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]); + *out_char = IM_UNICODE_CODEPOINT_INVALID; + } + + return wanted; +} + +int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) +{ + ImWchar* buf_out = buf; + ImWchar* buf_end = buf + buf_size; + while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); - if (c == 0) - break; - if (c <= IM_UNICODE_CODEPOINT_MAX) // FIXME: Losing characters that don't fit in 2 bytes - *buf_out++ = (ImWchar)c; + *buf_out++ = (ImWchar)c; } *buf_out = 0; if (in_text_remaining) @@ -1536,16 +2118,13 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); - if (c == 0) - break; - if (c <= IM_UNICODE_CODEPOINT_MAX) - char_count++; + char_count++; } return char_count; } // Based on stb_to_utf8() from github.com/nothings/stb/ -static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) +static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c) { if (c < 0x80) { @@ -1559,11 +2138,15 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) buf[1] = (char)(0x80 + (c & 0x3f)); return 2; } - if (c >= 0xdc00 && c < 0xe000) + if (c < 0x10000) { - return 0; + if (buf_size < 3) return 0; + buf[0] = (char)(0xe0 + (c >> 12)); + buf[1] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[2] = (char)(0x80 + ((c ) & 0x3f)); + return 3; } - if (c >= 0xd800 && c < 0xdc00) + if (c <= 0x10FFFF) { if (buf_size < 4) return 0; buf[0] = (char)(0xf0 + (c >> 18)); @@ -1572,46 +2155,47 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) buf[3] = (char)(0x80 + ((c ) & 0x3f)); return 4; } - //else if (c < 0x10000) - { - if (buf_size < 3) return 0; - buf[0] = (char)(0xe0 + (c >> 12)); - buf[1] = (char)(0x80 + ((c>> 6) & 0x3f)); - buf[2] = (char)(0x80 + ((c ) & 0x3f)); - return 3; - } + // Invalid code point, the max unicode is 0x10FFFF + return 0; +} + +const char* ImTextCharToUtf8(char out_buf[5], unsigned int c) +{ + int count = ImTextCharToUtf8_inline(out_buf, 5, c); + out_buf[count] = 0; + return out_buf; } // Not optimal but we very rarely use this function. int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) { - unsigned int dummy = 0; - return ImTextCharFromUtf8(&dummy, in_text, in_text_end); + unsigned int unused = 0; + return ImTextCharFromUtf8(&unused, in_text, in_text_end); } static inline int ImTextCountUtf8BytesFromChar(unsigned int c) { if (c < 0x80) return 1; if (c < 0x800) return 2; - if (c >= 0xdc00 && c < 0xe000) return 0; - if (c >= 0xd800 && c < 0xdc00) return 4; + if (c < 0x10000) return 3; + if (c <= 0x10FFFF) return 4; return 3; } -int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end) { - char* buf_out = buf; - const char* buf_end = buf + buf_size; - while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + char* buf_p = out_buf; + const char* buf_end = out_buf + out_buf_size; + while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) { unsigned int c = (unsigned int)(*in_text++); if (c < 0x80) - *buf_out++ = (char)c; + *buf_p++ = (char)c; else - buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c); + buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c); } - *buf_out = 0; - return (int)(buf_out - buf); + *buf_p = 0; + return (int)(buf_p - out_buf); } int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) @@ -1627,15 +2211,25 @@ int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_e } return bytes_count; } +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- -// [SECTION] MISC HELPERS/UTILTIES (Color functions) +// [SECTION] MISC HELPERS/UTILITIES (Color functions) // Note: The Convert functions are early design which are not consistent with other API. //----------------------------------------------------------------------------- +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b) +{ + float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; + int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); + return IM_COL32(r, g, b, 0xFF); +} + ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) { - float s = 1.0f/255.0f; + float s = 1.0f / 255.0f; return ImVec4( ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, @@ -1686,7 +2280,7 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& return; } - h = ImFmod(h, 1.0f) / (60.0f/360.0f); + h = ImFmod(h, 1.0f) / (60.0f / 360.0f); int i = (int)h; float f = h - (float)i; float p = v * (1.0f - s); @@ -1704,38 +2298,6 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& } } -ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) -{ - ImGuiStyle& style = GImGui->Style; - ImVec4 c = style.Colors[idx]; - c.w *= style.Alpha * alpha_mul; - return ColorConvertFloat4ToU32(c); -} - -ImU32 ImGui::GetColorU32(const ImVec4& col) -{ - ImGuiStyle& style = GImGui->Style; - ImVec4 c = col; - c.w *= style.Alpha; - return ColorConvertFloat4ToU32(c); -} - -const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) -{ - ImGuiStyle& style = GImGui->Style; - return style.Colors[idx]; -} - -ImU32 ImGui::GetColorU32(ImU32 col) -{ - float style_alpha = GImGui->Style.Alpha; - if (style_alpha >= 1.0f) - return col; - ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; - a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. - return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); -} - //----------------------------------------------------------------------------- // [SECTION] ImGuiStorage // Helper: Key->value storage @@ -1769,7 +2331,7 @@ void ImGuiStorage::BuildSortByKey() { struct StaticFunc { - static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) + static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) { // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; @@ -1777,8 +2339,7 @@ void ImGuiStorage::BuildSortByKey() return 0; } }; - if (Data.Size > 1) - ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID); } int ImGuiStorage::GetInt(ImGuiID key, int default_val) const @@ -1890,18 +2451,15 @@ void ImGuiStorage::SetAllInt(int v) //----------------------------------------------------------------------------- // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" -ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077 { + InputBuf[0] = 0; + CountGrep = 0; if (default_filter) { ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); Build(); } - else - { - InputBuf[0] = 0; - CountGrep = 0; - } } bool ImGuiTextFilter::Draw(const char* label, float width) @@ -1935,7 +2493,7 @@ void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector= 0 && new_size >= old_size && new_size >= EndOffset); + if (old_size == new_size) + return; + if (EndOffset == 0 || base[EndOffset - 1] == '\n') + LineOffsets.push_back(EndOffset); + const char* base_end = base + new_size; + for (const char* p = base + old_size; (p = (const char*)memchr(p, '\n', base_end - p)) != 0; ) + if (++p < base_end) // Don't push a trailing offset on last \n + LineOffsets.push_back((int)(intptr_t)(p - base)); + EndOffset = ImMax(EndOffset, new_size); +} + //----------------------------------------------------------------------------- // [SECTION] ImGuiListClipper // This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed // the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) //----------------------------------------------------------------------------- -// Helper to calculate coarse clipping of large list of evenly sized items. -// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. -// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX +// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell. +// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous. +static bool GetSkipItemForListClipping() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy helper to calculate coarse clipping of large list of evenly sized items. +// This legacy API is not ideal because it assumes we will return a single contiguous rectangle. +// Prefer using ImGuiListClipper which can returns non-contiguous ranges. void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) { ImGuiContext& g = *GImGui; @@ -2076,25 +2657,30 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items *out_items_display_end = items_count; return; } - if (window->SkipItems) + if (GetSkipItemForListClipping()) { *out_items_display_start = *out_items_display_end = 0; return; } - // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect - ImRect unclipped_rect = window->ClipRect; - if (g.NavMoveRequest) - unclipped_rect.Add(g.NavScoringRectScreen); + // We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect + // We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly. + ImRect rect = window->ClipRect; + if (g.NavMoveScoringItems) + rect.Add(g.NavScoringNoClipRect); + if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) + rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel const ImVec2 pos = window->DC.CursorPos; - int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); - int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); + int start = (int)((rect.Min.y - pos.y) / items_height); + int end = (int)((rect.Max.y - pos.y) / items_height); // When performing a navigation request, ensure we have one item extra in the direction we are moving to - if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) + // FIXME: Verify this works with tabbing + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) start--; - if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) end++; start = ImClamp(start, 0, items_count); @@ -2102,592 +2688,1140 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items *out_items_display_start = start; *out_items_display_end = end; } +#endif + +static void ImGuiListClipper_SortAndFuseRanges(ImVector& ranges, int offset = 0) +{ + if (ranges.Size - offset <= 1) + return; + + // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries) + for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end) + for (int i = offset; i < sort_end + offset; ++i) + if (ranges[i].Min > ranges[i + 1].Min) + ImSwap(ranges[i], ranges[i + 1]); + + // Now fuse ranges together as much as possible. + for (int i = 1 + offset; i < ranges.Size; i++) + { + IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert); + if (ranges[i - 1].Max < ranges[i].Min) + continue; + ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min); + ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max); + ranges.erase(ranges.Data + i); + i--; + } +} -static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) +static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height) { // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. - // The clipper should probably have a 4th step to display the last item in a regular manner. + // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek? ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + float off_y = pos_y - window->DC.CursorPos.y; window->DC.CursorPos.y = pos_y; - window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y); window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. - if (ImGuiColumns* columns = window->DC.CurrentColumns) + if (ImGuiOldColumns* columns = window->DC.CurrentColumns) columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly + if (ImGuiTable* table = g.CurrentTable) + { + if (table->IsInsideRow) + ImGui::TableEndRow(table); + table->RowPosY2 = window->DC.CursorPos.y; + const int row_increase = (int)((off_y / line_height) + 0.5f); + //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow() + table->RowBgColorCounter += row_increase; + } } -// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 -// Use case B: Begin() called from constructor with items_height>0 -// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. -void ImGuiListClipper::Begin(int count, float items_height) +static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - StartPosY = window->DC.CursorPos.y; - ItemsHeight = items_height; - ItemsCount = count; - StepNo = 0; - DisplayEnd = DisplayStart = -1; - if (ItemsHeight > 0.0f) - { - ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display - if (DisplayStart > 0) - SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor - StepNo = 2; - } + // StartPosY starts from ItemsFrozen hence the subtraction + // Perform the add and multiply with double to allow seeking through larger ranges + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; + float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight); + ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight); } -void ImGuiListClipper::End() +ImGuiListClipper::ImGuiListClipper() { - if (ItemsCount < 0) - return; - // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. - if (ItemsCount < INT_MAX) - SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor + memset(this, 0, sizeof(*this)); + Ctx = ImGui::GetCurrentContext(); + IM_ASSERT(Ctx != NULL); ItemsCount = -1; - StepNo = 3; } -bool ImGuiListClipper::Step() +ImGuiListClipper::~ImGuiListClipper() { - ImGuiContext& g = *GImGui; + End(); +} + +void ImGuiListClipper::Begin(int items_count, float items_height) +{ + ImGuiContext& g = *Ctx; ImGuiWindow* window = g.CurrentWindow; + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name); - if (ItemsCount == 0 || window->SkipItems) - { - ItemsCount = -1; - return false; - } - if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. - { - DisplayStart = 0; - DisplayEnd = 1; - StartPosY = window->DC.CursorPos.y; - StepNo = 1; - return true; - } - if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. - { - if (ItemsCount == 1) { ItemsCount = -1; return false; } - float items_height = window->DC.CursorPos.y - StartPosY; - IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically - Begin(ItemsCount - 1, items_height); - DisplayStart++; - DisplayEnd++; - StepNo = 3; - return true; - } - if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. + if (ImGuiTable* table = g.CurrentTable) + if (table->IsInsideRow) + ImGui::TableEndRow(table); + + StartPosY = window->DC.CursorPos.y; + ItemsHeight = items_height; + ItemsCount = items_count; + DisplayStart = -1; + DisplayEnd = 0; + + // Acquire temporary buffer + if (++g.ClipperTempDataStacked > g.ClipperTempData.Size) + g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData()); + ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->Reset(this); + data->LossynessOffset = window->DC.CursorStartPosLossyness.y; + TempData = data; +} + +void ImGuiListClipper::End() +{ + ImGuiContext& g = *Ctx; + if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData) { - IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); - StepNo = 3; - return true; + // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user. + IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name); + if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0) + ImGuiListClipper_SeekCursorForItem(this, ItemsCount); + + // Restore temporary buffer and fix back pointers which may be invalidated when nesting + IM_ASSERT(data->ListClipper == this); + data->StepNo = data->Ranges.Size; + if (--g.ClipperTempDataStacked > 0) + { + data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->ListClipper->TempData = data; + } + TempData = NULL; } - if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. - End(); - return false; + ItemsCount = -1; } -//----------------------------------------------------------------------------- -// [SECTION] RENDER HELPERS -// Those (internal) functions are currently quite a legacy mess - their signature and behavior will change. -// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: state. -//----------------------------------------------------------------------------- - -const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end) { - const char* text_display_end = text; - if (!text_end) - text_end = (const char*)-1; - - while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) - text_display_end++; - return text_display_end; + ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; + IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet. + IM_ASSERT(item_begin <= item_end); + if (item_begin < item_end) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end)); } -// Internal ImGui functions to render text -// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() -void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) +static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) { - ImGuiContext& g = *GImGui; + ImGuiContext& g = *clipper->Ctx; ImGuiWindow* window = g.CurrentWindow; + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; + IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?"); - // Hide anything after a '##' string - const char* text_display_end; - if (hide_text_after_hash) + ImGuiTable* table = g.CurrentTable; + if (table && table->IsInsideRow) + ImGui::TableEndRow(table); + + // No items + if (clipper->ItemsCount == 0 || GetSkipItemForListClipping()) + return false; + + // While we are in frozen row state, keep displaying items one by one, unclipped + // FIXME: Could be stored as a table-agnostic state. + if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows) { - text_display_end = FindRenderedTextEnd(text, text_end); + clipper->DisplayStart = data->ItemsFrozen; + clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount); + if (clipper->DisplayStart < clipper->DisplayEnd) + data->ItemsFrozen++; + return true; } - else + + // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height) + bool calc_clipping = false; + if (data->StepNo == 0) { - if (!text_end) - text_end = text + strlen(text); // FIXME-OPT - text_display_end = text_end; + clipper->StartPosY = window->DC.CursorPos.y; + if (clipper->ItemsHeight <= 0.0f) + { + // Submit the first item (or range) so we can measure its height (generally the first range is 0..1) + data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1)); + clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); + clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount); + data->StepNo = 1; + return true; + } + calc_clipping = true; // If on the first step with known item height, calculate clipping. } - if (text != text_display_end) + // Step 1: Let the clipper infer height from first range + if (clipper->ItemsHeight <= 0.0f) { - window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); - if (g.LogEnabled) - LogRenderedText(&pos, text, text_display_end); - } -} + IM_ASSERT(data->StepNo == 1); + if (table) + IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y); -void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart); + bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); + if (affected_by_floating_point_precision) + clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. - if (!text_end) - text_end = text + strlen(text); // FIXME-OPT + IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); + calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. + } - if (text != text_end) + // Step 0 or 1: Calculate the actual ranges of visible elements. + const int already_submitted = clipper->DisplayEnd; + if (calc_clipping) { - window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); if (g.LogEnabled) - LogRenderedText(&pos, text, text_end); + { + // If logging is active, do not perform any clipping + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount)); + } + else + { + // Add range selected to be included for navigation + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); + if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); + + // Add focused/active item + ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]); + if (g.NavId != 0 && window->NavLastIds[0] == g.NavId) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0)); + + // Add visible range + const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0; + const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0; + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max)); + } + + // Convert position ranges to item index ranges + // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping. + // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list, + // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted. + for (int i = 0; i < data->Ranges.Size; i++) + if (data->Ranges[i].PosToIndexConvert) + { + int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight); + int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f); + data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1); + data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount); + data->Ranges[i].PosToIndexConvert = false; + } + ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo); } -} -// Default clip_rect uses (pos_min,pos_max) -// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) -{ - // Perform CPU side clipping for single clipped element to avoid using scissor state - ImVec2 pos = pos_min; - const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + // Step 0+ (if item height is given in advance) or 1+: Display the next range in line. + if (data->StepNo < data->Ranges.Size) + { + clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); + clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount); + if (clipper->DisplayStart > already_submitted) //-V1051 + ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart); + data->StepNo++; + return true; + } - const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; - const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; - bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); - if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min - need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), + // Advance the cursor to the end of the list and then returns 'false' to end the loop. + if (clipper->ItemsCount < INT_MAX) + ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount); - // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. - if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); - if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); + return false; +} - // Render - if (need_clipping) +bool ImGuiListClipper::Step() +{ + ImGuiContext& g = *Ctx; + bool need_items_height = (ItemsHeight <= 0.0f); + bool ret = ImGuiListClipper_StepInternal(this); + if (ret && (DisplayStart == DisplayEnd)) + ret = false; + if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n"); + if (need_items_height && ItemsHeight > 0.0f) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight); + if (ret) { - ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); - draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd); } else { - draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n"); + End(); } + return ret; } -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +//----------------------------------------------------------------------------- +// [SECTION] STYLING +//----------------------------------------------------------------------------- + +ImGuiStyle& ImGui::GetStyle() { - // Hide anything after a '##' string - const char* text_display_end = FindRenderedTextEnd(text, text_end); - const int text_len = (int)(text_display_end - text); - if (text_len == 0) - return; + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->Style; +} - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); - if (g.LogEnabled) - LogRenderedText(&pos_min, text, text_display_end); +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = style.Colors[idx]; + c.w *= style.Alpha * alpha_mul; + return ColorConvertFloat4ToU32(c); } +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = col; + c.w *= style.Alpha; + return ColorConvertFloat4ToU32(c); +} -// Another overly complex function until we reorganize everything into a nice all-in-one helper. -// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. -// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. -void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) { - ImGuiContext& g = *GImGui; - if (text_end_full == NULL) - text_end_full = FindRenderedTextEnd(text); - const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); - - //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); - //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); - //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); - // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. - if (text_size.x > pos_max.x - pos_min.x) - { - // Hello wo... - // | | | - // min max ellipsis_max - // <-> this is generally some padding value - - const ImFont* font = draw_list->_Data->Font; - const float font_size = draw_list->_Data->FontSize; - const char* text_end_ellipsis = NULL; - - ImWchar ellipsis_char = font->EllipsisChar; - int ellipsis_char_count = 1; - if (ellipsis_char == (ImWchar)-1) - { - ellipsis_char = (ImWchar)'.'; - ellipsis_char_count = 3; - } - const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); + ImGuiStyle& style = GImGui->Style; + return style.Colors[idx]; +} - float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side - float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis +ImU32 ImGui::GetColorU32(ImU32 col) +{ + ImGuiStyle& style = GImGui->Style; + if (style.Alpha >= 1.0f) + return col; + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} - if (ellipsis_char_count > 1) - { - // Full ellipsis size without free spacing after it. - const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); - ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; - ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; - } +// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 +void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); +} - // We can now claim the space between pos_max.x and ellipsis_max.x - const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); - float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; - if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) - { - // Always display at least 1 character if there's no room for character + ellipsis - text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); - text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; - } - while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) - { - // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) - text_end_ellipsis--; - text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte - } +void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = col; +} - // Render text, render ellipsis - RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); - float ellipsis_x = pos_min.x + text_size_clipped_x; - if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) - for (int i = 0; i < ellipsis_char_count; i++) - { - font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); - ellipsis_x += ellipsis_glyph_width; - } +void ImGui::PopStyleColor(int count) +{ + ImGuiContext& g = *GImGui; + if (g.ColorStack.Size < count) + { + IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times: stack underflow."); + count = g.ColorStack.Size; } - else + while (count > 0) { - RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + ImGuiColorMod& backup = g.ColorStack.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorStack.pop_back(); + count--; } +} - if (g.LogEnabled) - LogRenderedText(&pos_min, text, text_end_full); +static const ImGuiDataVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding +}; + +const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; } -// Render a rectangle shaped with optional rounding and borders -void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); - const float border_size = g.Style.FrameBorderSize; - if (border && border_size > 0.0f) + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) { - window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; } + IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); } -void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - const float border_size = g.Style.FrameBorderSize; - if (border_size > 0.0f) + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) { - window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; } + IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); } -// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state -void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) +void ImGui::PopStyleVar(int count) { - const float h = draw_list->_Data->FontSize * 1.00f; - float r = h * 0.40f * scale; - ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); - - ImVec2 a, b, c; - switch (dir) + ImGuiContext& g = *GImGui; + if (g.StyleVarStack.Size < count) { - case ImGuiDir_Up: - case ImGuiDir_Down: - if (dir == ImGuiDir_Up) r = -r; - a = ImVec2(+0.000f,+0.750f) * r; - b = ImVec2(-0.866f,-0.750f) * r; - c = ImVec2(+0.866f,-0.750f) * r; - break; - case ImGuiDir_Left: - case ImGuiDir_Right: - if (dir == ImGuiDir_Left) r = -r; - a = ImVec2(+0.750f,+0.000f) * r; - b = ImVec2(-0.750f,+0.866f) * r; - c = ImVec2(-0.750f,-0.866f) * r; - break; - case ImGuiDir_None: - case ImGuiDir_COUNT: - IM_ASSERT(0); - break; + IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times: stack underflow."); + count = g.StyleVarStack.Size; + } + while (count > 0) + { + // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. + ImGuiStyleMod& backup = g.StyleVarStack.back(); + const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx); + void* data = info->GetVarPtr(&g.Style); + if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + g.StyleVarStack.pop_back(); + count--; } - draw_list->AddTriangleFilled(center + a, center + b, center + c, col); } -void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +const char* ImGui::GetStyleColorName(ImGuiCol idx) { - draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); + // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; + switch (idx) + { + case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; + case ImGuiCol_WindowBg: return "WindowBg"; + case ImGuiCol_ChildBg: return "ChildBg"; + case ImGuiCol_PopupBg: return "PopupBg"; + case ImGuiCol_Border: return "Border"; + case ImGuiCol_BorderShadow: return "BorderShadow"; + case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; + case ImGuiCol_TitleBg: return "TitleBg"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; + case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; + case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; + case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; + case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; + case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; + case ImGuiCol_CheckMark: return "CheckMark"; + case ImGuiCol_SliderGrab: return "SliderGrab"; + case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; + case ImGuiCol_Button: return "Button"; + case ImGuiCol_ButtonHovered: return "ButtonHovered"; + case ImGuiCol_ButtonActive: return "ButtonActive"; + case ImGuiCol_Header: return "Header"; + case ImGuiCol_HeaderHovered: return "HeaderHovered"; + case ImGuiCol_HeaderActive: return "HeaderActive"; + case ImGuiCol_Separator: return "Separator"; + case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; + case ImGuiCol_SeparatorActive: return "SeparatorActive"; + case ImGuiCol_ResizeGrip: return "ResizeGrip"; + case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; + case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; + case ImGuiCol_PlotLines: return "PlotLines"; + case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; + case ImGuiCol_PlotHistogram: return "PlotHistogram"; + case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; + case ImGuiCol_TableHeaderBg: return "TableHeaderBg"; + case ImGuiCol_TableBorderStrong: return "TableBorderStrong"; + case ImGuiCol_TableBorderLight: return "TableBorderLight"; + case ImGuiCol_TableRowBg: return "TableRowBg"; + case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt"; + case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; + case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; + } + IM_ASSERT(0); + return "Unknown"; } -void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - float thickness = ImMax(sz / 5.0f, 1.0f); - sz -= thickness*0.5f; - pos += ImVec2(thickness*0.25f, thickness*0.25f); +//----------------------------------------------------------------------------- +// [SECTION] RENDER HELPERS +// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, +// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. +// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. +//----------------------------------------------------------------------------- + +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +{ + const char* text_display_end = text; + if (!text_end) + text_end = (const char*)-1; - float third = sz / 3.0f; - float bx = pos.x + third; - float by = pos.y + sz - third*0.5f; - window->DrawList->PathLineTo(ImVec2(bx - third, by - third)); - window->DrawList->PathLineTo(ImVec2(bx, by)); - window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2)); - window->DrawList->PathStroke(col, false, thickness); + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + return text_display_end; } -void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +// Internal ImGui functions to render text +// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) { ImGuiContext& g = *GImGui; - if (id != g.NavId) - return; - if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) - return; ImGuiWindow* window = g.CurrentWindow; - if (window->DC.NavHideHighlightOneFrame) - return; - float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; - ImRect display_rect = bb; - display_rect.ClipWith(window->ClipRect); - if (flags & ImGuiNavHighlightFlags_TypeDefault) + // Hide anything after a '##' string + const char* text_display_end; + if (hide_text_after_hash) { - const float THICKNESS = 2.0f; - const float DISTANCE = 3.0f + THICKNESS * 0.5f; - display_rect.Expand(ImVec2(DISTANCE,DISTANCE)); - bool fully_visible = window->ClipRect.Contains(display_rect); - if (!fully_visible) - window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); - window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); - if (!fully_visible) - window->DrawList->PopClipRect(); + text_display_end = FindRenderedTextEnd(text, text_end); } - if (flags & ImGuiNavHighlightFlags_TypeThin) + else { - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + text_display_end = text_end; } -} -//----------------------------------------------------------------------------- -// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) -//----------------------------------------------------------------------------- + if (text != text_display_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_display_end); + } +} -// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods -ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) - : DrawListInst(&context->DrawListSharedData) +void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) { - Name = ImStrdup(name); - ID = ImHashStr(name); - IDStack.push_back(ID); - Flags = ImGuiWindowFlags_None; - Pos = ImVec2(0.0f, 0.0f); - Size = SizeFull = ImVec2(0.0f, 0.0f); - ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f); - WindowPadding = ImVec2(0.0f, 0.0f); - WindowRounding = 0.0f; - WindowBorderSize = 0.0f; - NameBufLen = (int)strlen(name) + 1; - MoveId = GetID("#MOVE"); - ChildId = 0; - Scroll = ImVec2(0.0f, 0.0f); - ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); - ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); - ScrollbarSizes = ImVec2(0.0f, 0.0f); - ScrollbarX = ScrollbarY = false; - Active = WasActive = false; - WriteAccessed = false; - Collapsed = false; - WantCollapseToggle = false; - SkipItems = false; - Appearing = false; - Hidden = false; - HasCloseButton = false; - ResizeBorderHeld = -1; - BeginCount = 0; - BeginOrderWithinParent = -1; - BeginOrderWithinContext = -1; - PopupId = 0; - AutoFitFramesX = AutoFitFramesY = -1; - AutoFitChildAxises = 0x00; - AutoFitOnlyGrows = false; - AutoPosLastDirection = ImGuiDir_None; - HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0; - SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; - SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; - InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used. + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT - LastFrameActive = -1; - LastTimeActive = -1.0f; - ItemWidthDefault = 0.0f; - FontWindowScale = 1.0f; - SettingsOffset = -1; + if (text != text_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_end); + } +} - DrawList = &DrawListInst; - DrawList->_OwnerName = Name; - ParentWindow = NULL; - RootWindow = NULL; - RootWindowForTitleBarHighlight = NULL; - RootWindowForNav = NULL; +// Default clip_rect uses (pos_min,pos_max) +// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) +// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList. +// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take +// better advantage of the render function taking size into account for coarse clipping. +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; + bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - NavLastIds[0] = NavLastIds[1] = 0; - NavRectRel[0] = NavRectRel[1] = ImRect(); - NavLastChildNavWindow = NULL; + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); - MemoryCompacted = false; - MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0; + // Render + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + } } -ImGuiWindow::~ImGuiWindow() +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) { - IM_ASSERT(DrawList == &DrawListInst); - IM_DELETE(Name); - for (int i = 0; i != ColumnsStorage.Size; i++) - ColumnsStorage[i].~ImGuiColumns(); + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); } -ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +// Another overly complex function until we reorganize everything into a nice all-in-one helper. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) { - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); - ImGui::KeepAliveID(id); - return id; + ImGuiContext& g = *GImGui; + if (text_end_full == NULL) + text_end_full = FindRenderedTextEnd(text); + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); + + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); + //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. + if (text_size.x > pos_max.x - pos_min.x) + { + // Hello wo... + // | | | + // min max ellipsis_max + // <-> this is generally some padding value + + const ImFont* font = draw_list->_Data->Font; + const float font_size = draw_list->_Data->FontSize; + const float font_scale = font_size / font->FontSize; + const char* text_end_ellipsis = NULL; + const float ellipsis_width = font->EllipsisWidth * font_scale; + + // We can now claim the space between pos_max.x and ellipsis_max.x + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); + float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; + if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) + { + // Always display at least 1 character if there's no room for character + ellipsis + text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); + text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; + } + while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) + { + // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) + text_end_ellipsis--; + text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte + } + + // Render text, render ellipsis + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); + if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x) + for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) + font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar); + } + else + { + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + } + + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_end_full); } -ImGuiID ImGuiWindow::GetID(const void* ptr) +// Render a rectangle shaped with optional rounding and borders +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) { - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); - ImGui::KeepAliveID(id); - return id; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); + const float border_size = g.Style.FrameBorderSize; + if (border && border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } } -ImGuiID ImGuiWindow::GetID(int n) +void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) { - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashData(&n, sizeof(n), seed); - ImGui::KeepAliveID(id); - return id; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const float border_size = g.Style.FrameBorderSize; + if (border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } } -ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) { - ImGuiID seed = IDStack.back(); - return ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *GImGui; + if (id != g.NavId) + return; + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + return; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.NavHideHighlightOneFrame) + return; + + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + ImRect display_rect = bb; + display_rect.ClipWith(window->ClipRect); + if (flags & ImGuiNavHighlightFlags_TypeDefault) + { + const float THICKNESS = 2.0f; + const float DISTANCE = 3.0f + THICKNESS * 0.5f; + display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); + bool fully_visible = window->ClipRect.Contains(display_rect); + if (!fully_visible) + window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS); + if (!fully_visible) + window->DrawList->PopClipRect(); + } + if (flags & ImGuiNavHighlightFlags_TypeThin) + { + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f); + } } -ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) +void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) { - ImGuiID seed = IDStack.back(); - return ImHashData(&ptr, sizeof(void*), seed); + ImGuiContext& g = *GImGui; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; + for (int n = 0; n < g.Viewports.Size; n++) + { + // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. + ImVec2 offset, size, uv[4]; + if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + continue; + ImGuiViewportP* viewport = g.Viewports[n]; + const ImVec2 pos = base_pos - offset; + const float scale = base_scale; + if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) + continue; + ImDrawList* draw_list = GetForegroundDrawList(viewport); + ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } } -ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) +//----------------------------------------------------------------------------- +// [SECTION] INITIALIZATION, SHUTDOWN +//----------------------------------------------------------------------------- + +// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() { - ImGuiID seed = IDStack.back(); - return ImHashData(&n, sizeof(n), seed); + return GImGui; } -// This is only used in rare/specific situations to manufacture an ID out of nowhere. -ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +void ImGui::SetCurrentContext(ImGuiContext* ctx) { - ImGuiID seed = IDStack.back(); - const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; - ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); - ImGui::KeepAliveID(id); - return id; +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif } -static void SetCurrentWindow(ImGuiWindow* window) +void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) { - ImGuiContext& g = *GImGui; - g.CurrentWindow = window; - if (window) - g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; } -// Free up/compact internal window buffers, we can use this when a window becomes unused. -// This is currently unused by the library, but you may call this yourself for easy GC. -// Not freed: -// - ImGuiWindow, ImGuiWindowSettings, Name -// - StateStorage, ColumnsStorage (may hold useful data) -// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. -void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) +void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) { - window->MemoryCompacted = true; - window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; - window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; - window->IDStack.clear(); - window->DrawList->ClearFreeMemory(); - window->DC.ChildWindows.clear(); - window->DC.ItemFlagsStack.clear(); - window->DC.ItemWidthStack.clear(); - window->DC.TextWrapPosStack.clear(); - window->DC.GroupStack.clear(); + *p_alloc_func = GImAllocatorAllocFunc; + *p_free_func = GImAllocatorFreeFunc; + *p_user_data = GImAllocatorUserData; } -void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) { - // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. - // The other buffers tends to amortize much faster. - window->MemoryCompacted = false; - window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); - window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); - window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; + ImGuiContext* prev_ctx = GetCurrentContext(); + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + SetCurrentContext(ctx); + Initialize(); + if (prev_ctx != NULL) + SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one. + return ctx; } -void ImGui::SetNavID(ImGuiID id, int nav_layer) +void ImGui::DestroyContext(ImGuiContext* ctx) { - ImGuiContext& g = *GImGui; - IM_ASSERT(g.NavWindow); - IM_ASSERT(nav_layer == 0 || nav_layer == 1); - g.NavId = id; - g.NavWindow->NavLastIds[nav_layer] = id; + ImGuiContext* prev_ctx = GetCurrentContext(); + if (ctx == NULL) //-V1051 + ctx = prev_ctx; + SetCurrentContext(ctx); + Shutdown(); + SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL); + IM_DELETE(ctx); } -void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel) +// IMPORTANT: ###xxx suffixes must be same in ALL languages +static const ImGuiLocEntry GLocalizationEntriesEnUS[] = +{ + { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" }, + { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" }, + { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" }, + { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" }, + { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, + { ImGuiLocKey_WindowingPopup, "(Popup)" }, + { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, +}; + +void ImGui::Initialize() { ImGuiContext& g = *GImGui; - SetNavID(id, nav_layer); - g.NavWindow->NavRectRel[nav_layer] = rect_rel; - g.NavMousePosDirty = true; - g.NavDisableHighlight = false; - g.NavDisableMouseHover = true; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow and ImGuiTable types + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + AddSettingsHandler(&ini_handler); + } + TableSettingsAddSettingsHandler(); + + // Setup default localization table + LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); + + // Setup default platform clipboard/IME handlers. + g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) + g.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl; + + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + g.Viewports.push_back(viewport); + g.TempBuffer.resize(1024 * 3 + 1, 0); + +#ifdef IMGUI_HAS_DOCK +#endif + + g.Initialized = true; } -void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +// This function is merely here to free heap allocations. +void ImGui::Shutdown() { + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) ImGuiContext& g = *GImGui; - g.ActiveIdIsJustActivated = (g.ActiveId != id); - if (g.ActiveIdIsJustActivated) + if (g.IO.Fonts && g.FontAtlasOwnedByContext) { - g.ActiveIdTimer = 0.0f; - g.ActiveIdHasBeenPressedBefore = false; - g.ActiveIdHasBeenEditedBefore = false; - if (id != 0) + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + g.DrawListSharedData.TempBuffer.clear(); + + // Cleanup of other data are conditional on actually having initialized Dear ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + + CallContextHooks(&g, ImGuiContextHookType_Shutdown); + + // Clear everything else + g.Windows.clear_delete(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + + g.KeysRoutingTable.Clear(); + + g.ColorStack.clear(); + g.StyleVarStack.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + + g.Viewports.clear_delete(); + + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); + + g.ClipperTempData.clear_destruct(); + + g.Tables.Clear(); + g.TablesTempData.clear_destruct(); + g.DrawChannelsTempMergeBuffer.clear(); + + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.ClearFreeMemory(); + g.InputTextDeactivatedState.ClearFreeMemory(); + + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile) + { +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); + g.LogFile = NULL; + } + g.LogBuffer.clear(); + g.DebugLogBuf.clear(); + g.DebugLogIndex.clear(); + + g.Initialized = false; +} + +// No specific ordering/dependency support, will see as needed +ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); + g.Hooks.push_back(*hook); + g.Hooks.back().HookId = ++g.HookIdNext; + return g.HookIdNext; +} + +// Deferred removal, avoiding issue with changing vector while iterating it +void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook_id != 0); + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].HookId == hook_id) + g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; +} + +// Call context hooks (used by e.g. test engine) +// We assume a small number of hooks so all stored in same array +void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) +{ + ImGuiContext& g = *ctx; + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].Type == hook_type) + g.Hooks[n].Callback(&g, &g.Hooks[n]); +} + + +//----------------------------------------------------------------------------- +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +//----------------------------------------------------------------------------- + +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL) +{ + memset(this, 0, sizeof(*this)); + Ctx = ctx; + Name = ImStrdup(name); + NameBufLen = (int)strlen(name) + 1; + ID = ImHashStr(name); + IDStack.push_back(ID); + MoveId = GetID("#MOVE"); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + AutoFitFramesX = AutoFitFramesY = -1; + AutoPosLastDirection = ImGuiDir_None; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = 0; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + LastFrameActive = -1; + LastTimeActive = -1.0f; + FontWindowScale = 1.0f; + SettingsOffset = -1; + DrawList = &DrawListInst; + DrawList->_Data = &Ctx->DrawListSharedData; + DrawList->_OwnerName = Name; + NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + ColumnsStorage.clear_destruct(); +} + +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); + return id; +} + +ImGuiID ImGuiWindow::GetID(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + return id; +} + +static void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; + if (window) + { + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); + ImGui::NavUpdateCurrentWindowIsScrollPushableX(); + } +} + +void ImGui::GcCompactTransientMiscBuffers() +{ + ImGuiContext& g = *GImGui; + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); + TableGcCompactSettings(); +} + +// Free up/compact internal window buffers, we can use this when a window becomes unused. +// Not freed: +// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) +// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. +void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + window->MemoryCompacted = true; + window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; + window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; + window->IDStack.clear(); + window->DrawList->_ClearFreeMemory(); + window->DC.ChildWindows.clear(); + window->DC.ItemWidthStack.clear(); + window->DC.TextWrapPosStack.clear(); +} + +void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. + // The other buffers tends to amortize much faster. + window->MemoryCompacted = false; + window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); + window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); + window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; +} + +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + // Clear previous active id + if (g.ActiveId != 0) + { + // While most behaved code would make an effort to not steal active id during window move/drag operations, + // we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch + // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that. + if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n"); + g.MovingWindow = NULL; + } + + // This could be written in a more general way (e.g associate a hook to ActiveId), + // but since this is currently quite an exception we'll leave it as is. + // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId() + if (g.InputTextState.ID == g.ActiveId) + InputTextDeactivateHook(g.ActiveId); + } + + // Set active id + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : ""); + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; + g.ActiveIdMouseButton = -1; + if (id != 0) { g.LastActiveId = id; g.LastActiveIdTimer = 0.0f; @@ -2695,47 +3829,28 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) } g.ActiveId = id; g.ActiveIdAllowOverlap = false; + g.ActiveIdNoClearOnFocusLoss = false; g.ActiveIdWindow = window; g.ActiveIdHasBeenEditedThisFrame = false; if (id) { g.ActiveIdIsAlive = id; - g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; + g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; + IM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None); } // Clear declaration of inputs claimed by the widget // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO g.ActiveIdUsingNavInputMask = 0x00; - g.ActiveIdUsingKeyInputMask = 0x00; -} - -// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring. -void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(id != 0); - - // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it. - const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; - if (g.NavWindow != window) - g.NavInitRequest = false; - g.NavId = id; - g.NavWindow = window; - g.NavLayer = nav_layer; - window->NavLastIds[nav_layer] = id; - if (window->DC.LastItemId == id) - window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); - - if (g.ActiveIdSource == ImGuiInputSource_Nav) - g.NavDisableMouseHover = true; - else - g.NavDisableHighlight = true; +#endif } void ImGui::ClearActiveID() { - SetActiveID(0, NULL); + SetActiveID(0, NULL); // g.ActiveId = 0; } void ImGui::SetHoveredID(ImGuiID id) @@ -2753,6 +3868,8 @@ ImGuiID ImGui::GetHoveredID() return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; } +// This is called by ItemAdd(). +// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID(). void ImGui::KeepAliveID(ImGuiID id) { ImGuiContext& g = *GImGui; @@ -2765,17 +3882,23 @@ void ImGui::KeepAliveID(ImGuiID id) void ImGui::MarkItemEdited(ImGuiID id) { // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). - // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. + // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. ImGuiContext& g = *GImGui; - IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); - IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. + if (g.ActiveId == id || g.ActiveId == 0) + { + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; + } + + // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343) + // We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714) + IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id); + //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); - g.ActiveIdHasBeenEditedThisFrame = true; - g.ActiveIdHasBeenEditedBefore = true; - g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; } -static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) { // An active popup disable hovering on other windows (apart from its own children) // FIXME-OPT: This could be cached/stored within the window. @@ -2785,158 +3908,96 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla if (focused_root_window->WasActive && focused_root_window != window->RootWindow) { // For the purpose of those flags we differentiate "standard popup" from "modal popup" - // NB: The order of those two tests is important because Modal windows are also Popups. + // NB: The 'else' is important because Modal windows are also Popups. + bool want_inhibit = false; if (focused_root_window->Flags & ImGuiWindowFlags_Modal) - return false; - if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) - return false; + want_inhibit = true; + else if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + want_inhibit = true; + + // Inhibit hover unless the window is within the stack of our modal/popup + if (want_inhibit) + if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) + return false; } - return true; } -// Advance cursor given item size for layout. -void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) +// This is roughly matching the behavior of internal-facing ItemHoverable() +// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() +// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (window->SkipItems) - return; + if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) + { + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + if (!IsItemFocused()) + return false; + } + else + { + // Test for bounding box overlap, as updated as ItemAdd() + ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; + if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function + + // Done with rectangle culling so we can perform heavier checks now + // Test if we are hovering the right window (our window could be behind another window) + // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable + // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was + // the test that has been running for a long while. + if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) + return false; - // We increase the height in this function to accommodate for baseline offset. - // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, - // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. - const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; - const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); + // Test if another item is active (e.g. being dragged) + if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) + if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; - // Always align ourselves on pixel boundaries - //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] - window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; - window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; - window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line - window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line - window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); - window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); - //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + // Test if interactions on this window are blocked by an active popup or modal. + // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. + if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck)) + return false; - window->DC.PrevLineSize.y = line_height; - window->DC.CurrLineSize.y = 0.0f; - window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); - window->DC.CurrLineTextBaseOffset = 0.0f; + // Test if the item is disabled + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; - // Horizontal layout mode - if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) - SameLine(); -} + // Special handling for calling after Begin() which represent the title bar or tab. + // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) + return false; + } -void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) -{ - ItemSize(bb.GetSize(), text_baseline_y); + // Handle hover delay + // (some ideas: https://www.nngroup.com/articles/timing-exposing-content) + float delay; + if (flags & ImGuiHoveredFlags_DelayNormal) + delay = g.IO.HoverDelayNormal; + else if (flags & ImGuiHoveredFlags_DelayShort) + delay = g.IO.HoverDelayShort; + else + delay = 0.0f; + if (delay > 0.0f) + { + ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect); + if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverDelayIdPreviousFrame != hover_delay_id)) + g.HoverDelayTimer = 0.0f; + g.HoverDelayId = hover_delay_id; + return g.HoverDelayTimer >= delay; + } + + return true; } -// Declare item bounding box for clipping and interaction. -// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface -// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). -bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - if (id != 0) - { - // Navigation processing runs prior to clipping early-out - // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget - // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests - // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of - // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. - // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able - // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). - // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. - // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. - window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; - if (g.NavId == id || g.NavAnyRequest) - if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) - if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) - NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); - - // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd() -#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX - if (id == g.DebugItemPickerBreakID) - { - IM_DEBUG_BREAK(); - g.DebugItemPickerBreakID = 0; - } -#endif - } - - window->DC.LastItemId = id; - window->DC.LastItemRect = bb; - window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; - g.NextItemData.Flags = ImGuiNextItemDataFlags_None; - -#ifdef IMGUI_ENABLE_TEST_ENGINE - if (id != 0) - IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); -#endif - - // Clipping test - const bool is_clipped = IsClippedEx(bb, id, false); - if (is_clipped) - return false; - //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] - - // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) - if (IsMouseHoveringRect(bb.Min, bb.Max)) - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; - return true; -} - -// This is roughly matching the behavior of internal-facing ItemHoverable() -// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() -// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId -bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (g.NavDisableMouseHover && !g.NavDisableHighlight) - return IsItemFocused(); - - // Test for bounding box overlap, as updated as ItemAdd() - if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) - return false; - IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function - - // Test if we are hovering the right window (our window could be behind another window) - // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself. - // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. - //if (g.HoveredWindow != window) - // return false; - if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) - return false; - - // Test if another item is active (e.g. being dragged) - if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) - if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) - return false; - - // Test if interactions on this window are blocked by an active popup or modal. - // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. - if (!IsWindowContentHoverable(window, flags)) - return false; - - // Test if the item is disabled - if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) - return false; - - // Special handling for the dummy item after Begin() which represent the title bar or tab. - // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. - if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) - return false; - return true; -} - -// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). -bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) { ImGuiContext& g = *GImGui; if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) @@ -2949,79 +4010,69 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) return false; - if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + + // Done with rectangle culling so we can perform heavier checks now. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + { + g.HoveredIdDisabled = true; return false; - if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) + } + + // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level + // hover test in widgets code. We could also decide to split this function is two. + if (id != 0) + SetHoveredID(id); + + // When disabled we'll return false but still set HoveredId + if (item_flags & ImGuiItemFlags_Disabled) + { + // Release active id if turning disabled + if (g.ActiveId == id) + ClearActiveID(); + g.HoveredIdDisabled = true; return false; + } - SetHoveredID(id); + if (id != 0) + { + // [DEBUG] Item Picker tool! + // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making + // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered + // items if we performed the test in ItemAdd(), but that would incur a small runtime cost. + if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) + GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); + if (g.DebugItemPickerBreakId == id) + IM_DEBUG_BREAK(); + } - // [DEBUG] Item Picker tool! - // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making - // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered - // items if we perform the test in ItemAdd(), but that would incur a small runtime cost. - // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd(). - if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) - GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); - if (g.DebugItemPickerBreakID == id) - IM_DEBUG_BREAK(); + if (g.NavDisableMouseHover) + return false; return true; } -bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) +// FIXME: This is inlined/duplicated in ItemAdd() +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; if (!bb.Overlaps(window->ClipRect)) - if (id == 0 || id != g.ActiveId) - if (clip_even_when_logged || !g.LogEnabled) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) + if (!g.LogEnabled) return true; return false; } -// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. -bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) +// This is also inlined in ItemAdd() +// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect. +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) { ImGuiContext& g = *GImGui; - - // Increment counters - const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; - window->DC.FocusCounterAll++; - if (is_tab_stop) - window->DC.FocusCounterTab++; - - // Process TAB/Shift-TAB to tab *OUT* of the currently focused item. - // (Note that we can always TAB out of a widget that doesn't allow tabbing in) - if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL) - { - g.FocusRequestNextWindow = window; - g.FocusRequestNextCounterTab = window->DC.FocusCounterTab + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. - } - - // Handle focus requests - if (g.FocusRequestCurrWindow == window) - { - if (window->DC.FocusCounterAll == g.FocusRequestCurrCounterAll) - return true; - if (is_tab_stop && window->DC.FocusCounterTab == g.FocusRequestCurrCounterTab) - { - g.NavJustTabbedId = id; - return true; - } - - // If another item is about to be focused, we clear our own active id - if (g.ActiveId == id) - ClearActiveID(); - } - - return false; -} - -void ImGui::FocusableItemUnregister(ImGuiWindow* window) -{ - window->DC.FocusCounterAll--; - window->DC.FocusCounterTab--; + g.LastItemData.ID = item_id; + g.LastItemData.InFlags = in_flags; + g.LastItemData.StatusFlags = item_flags; + g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; } float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) @@ -3029,11 +4080,21 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) if (wrap_pos_x < 0.0f) return 0.0f; - ImGuiWindow* window = GImGui->CurrentWindow; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; if (wrap_pos_x == 0.0f) + { + // We could decide to setup a default wrapping max point for auto-resizing windows, + // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function? + //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) + // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x); + //else wrap_pos_x = window->WorkRect.Max.x; + } else if (wrap_pos_x > 0.0f) + { wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space + } return ImMax(wrap_pos_x - pos.x, 1.0f); } @@ -3043,7 +4104,7 @@ void* ImGui::MemAlloc(size_t size) { if (ImGuiContext* ctx = GImGui) ctx->IO.MetricsActiveAllocations++; - return GImAllocatorAllocFunc(size, GImAllocatorUserData); + return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData); } // IM_FREE() == ImGui::MemFree() @@ -3052,7 +4113,7 @@ void ImGui::MemFree(void* ptr) if (ptr) if (ImGuiContext* ctx = GImGui) ctx->IO.MetricsActiveAllocations--; - return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); + return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData); } const char* ImGui::GetClipboardText() @@ -3073,103 +4134,74 @@ const char* ImGui::GetVersion() return IMGUI_VERSION; } -// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself -// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module -ImGuiContext* ImGui::GetCurrentContext() -{ - return GImGui; -} - -void ImGui::SetCurrentContext(ImGuiContext* ctx) +ImGuiIO& ImGui::GetIO() { -#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC - IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. -#else - GImGui = ctx; -#endif + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->IO; } -// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. -// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit -// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code -// may see different structures than what imgui.cpp sees, which is problematic. -// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui. -bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) +// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() +ImDrawData* ImGui::GetDrawData() { - bool error = false; - if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatched version string!"); } - if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } - if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } - if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } - if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } - if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } - if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } - return !error; + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL; } -void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) +double ImGui::GetTime() { - GImAllocatorAllocFunc = alloc_func; - GImAllocatorFreeFunc = free_func; - GImAllocatorUserData = user_data; + return GImGui->Time; } -ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +int ImGui::GetFrameCount() { - ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); - if (GImGui == NULL) - SetCurrentContext(ctx); - Initialize(ctx); - return ctx; + return GImGui->FrameCount; } -void ImGui::DestroyContext(ImGuiContext* ctx) +static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) { - if (ctx == NULL) - ctx = GImGui; - Shutdown(ctx); - if (GImGui == ctx) - SetCurrentContext(NULL); - IM_DELETE(ctx); -} + // Create the draw list on demand, because they are not frequently used for all viewports + ImGuiContext& g = *GImGui; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); + ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + if (draw_list == NULL) + { + draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); + draw_list->_OwnerName = drawlist_name; + viewport->DrawLists[drawlist_no] = draw_list; + } -ImGuiIO& ImGui::GetIO() -{ - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); - return GImGui->IO; + // Our ImDrawList system requires that there is always a command + if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) + { + draw_list->_ResetForNewFrame(); + draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; + } + return draw_list; } -ImGuiStyle& ImGui::GetStyle() +ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) { - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); - return GImGui->Style; + return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); } -// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame() -ImDrawData* ImGui::GetDrawData() +ImDrawList* ImGui::GetBackgroundDrawList() { ImGuiContext& g = *GImGui; - return g.DrawData.Valid ? &g.DrawData : NULL; -} - -double ImGui::GetTime() -{ - return GImGui->Time; -} - -int ImGui::GetFrameCount() -{ - return GImGui->FrameCount; + return GetBackgroundDrawList(g.Viewports[0]); } -ImDrawList* ImGui::GetBackgroundDrawList() +ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) { - return &GImGui->BackgroundDrawList; + return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); } ImDrawList* ImGui::GetForegroundDrawList() { - return &GImGui->ForegroundDrawList; + ImGuiContext& g = *GImGui; + return GetForegroundDrawList(g.Viewports[0]); } ImDrawListSharedData* ImGui::GetDrawListSharedData() @@ -3186,7 +4218,9 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) FocusWindow(window); SetActiveID(window->MoveId, window); g.NavDisableHighlight = true; - g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; + g.ActiveIdNoClearOnFocusLoss = true; + SetActiveIdUsingAllKeyboardKeys(); bool can_move_window = true; if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) @@ -3197,6 +4231,9 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) // Handle mouse moving window // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() +// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. +// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, +// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. void ImGui::UpdateMouseMovingWindowNewFrame() { ImGuiContext& g = *GImGui; @@ -3210,17 +4247,13 @@ void ImGui::UpdateMouseMovingWindowNewFrame() if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) { ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; - if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) - { - MarkIniSettingsDirty(moving_window); - SetWindowPos(moving_window, pos, ImGuiCond_Always); - } + SetWindowPos(moving_window, pos, ImGuiCond_Always); FocusWindow(g.MovingWindow); } else { - ClearActiveID(); g.MovingWindow = NULL; + ClearActiveID(); } } else @@ -3235,10 +4268,10 @@ void ImGui::UpdateMouseMovingWindowNewFrame() } } -// Initiate moving window, handle left-click and right-click focus +// Initiate moving window when clicking on empty space or title bar. +// Handle left-click and right-click focus. void ImGui::UpdateMouseMovingWindowEndFrame() { - // Initiate moving window ImGuiContext& g = *GImGui; if (g.ActiveId != 0 || g.HoveredId != 0) return; @@ -3247,20 +4280,32 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (g.NavWindow && g.NavWindow->Appearing) return; - // Click to focus window and start moving (after we're done with all our widgets) + // Click on empty space to focus window and start moving + // (after we're done with all our widgets) if (g.IO.MouseClicked[0]) { - if (g.HoveredRootWindow != NULL) + // Handle the edge case of a popup being closed while clicking in its empty space. + // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more. + ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel); + + if (root_window != NULL && !is_closed_popup) { - StartMouseMovingWindow(g.HoveredWindow); - if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) - if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + StartMouseMovingWindow(g.HoveredWindow); //-V595 + + // Cancel moving if clicked outside of title bar + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; + + // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) + if (g.HoveredIdDisabled) + g.MovingWindow = NULL; } - else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL) + else if (root_window == NULL && g.NavWindow != NULL) { // Clicking on void disable focus - FocusWindow(NULL); + FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal); } } @@ -3272,17 +4317,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // Find the top-most window between HoveredWindow and the top-most Modal Window. // This is where we can trim the popup stack. ImGuiWindow* modal = GetTopMostPopupModal(); - bool hovered_window_above_modal = false; - if (modal == NULL) - hovered_window_above_modal = true; - for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) - { - ImGuiWindow* window = g.Windows[i]; - if (window == modal) - break; - if (window == g.HoveredWindow) - hovered_window_above_modal = true; - } + bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal)); ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); } } @@ -3292,234 +4327,81 @@ static bool IsWindowActiveAndVisible(ImGuiWindow* window) return (window->Active) && (!window->Hidden); } -static void ImGui::UpdateMouseInputs() -{ - ImGuiContext& g = *GImGui; - - // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) - if (IsMousePosValid(&g.IO.MousePos)) - g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); - - // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta - if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) - g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; - else - g.IO.MouseDelta = ImVec2(0.0f, 0.0f); - if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) - g.NavDisableMouseHover = false; - - g.IO.MousePosPrev = g.IO.MousePos; - for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) - { - g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; - g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; - g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; - g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; - g.IO.MouseDoubleClicked[i] = false; - if (g.IO.MouseClicked[i]) - { - if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) - { - ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); - if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) - g.IO.MouseDoubleClicked[i] = true; - g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click - } - else - { - g.IO.MouseClickedTime[i] = g.Time; - } - g.IO.MouseClickedPos[i] = g.IO.MousePos; - g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i]; - g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); - g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; - } - else if (g.IO.MouseDown[i]) - { - // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold - ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); - g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); - g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); - g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); - } - if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i]) - g.IO.MouseDownWasDoubleClick[i] = false; - if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation - g.NavDisableMouseHover = false; - } -} - -static void StartLockWheelingWindow(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (g.WheelingWindow == window) - return; - g.WheelingWindow = window; - g.WheelingWindowRefMousePos = g.IO.MousePos; - g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER; -} - -void ImGui::UpdateMouseWheel() -{ - ImGuiContext& g = *GImGui; - - // Reset the locked window if we move the mouse or after the timer elapses - if (g.WheelingWindow != NULL) - { - g.WheelingWindowTimer -= g.IO.DeltaTime; - if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) - g.WheelingWindowTimer = 0.0f; - if (g.WheelingWindowTimer <= 0.0f) - { - g.WheelingWindow = NULL; - g.WheelingWindowTimer = 0.0f; - } - } - - if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) - return; - - ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; - if (!window || window->Collapsed) - return; - - // Zoom / Scale window - // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. - if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) - { - StartLockWheelingWindow(window); - const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); - const float scale = new_font_scale / window->FontWindowScale; - window->FontWindowScale = new_font_scale; - if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) - { - const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; - SetWindowPos(window, window->Pos + offset, 0); - window->Size = ImFloor(window->Size * scale); - window->SizeFull = ImFloor(window->SizeFull * scale); - } - return; - } - - // Mouse wheel scrolling - // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent - - // Vertical Mouse Wheel scrolling - const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; - if (wheel_y != 0.0f && !g.IO.KeyCtrl) - { - StartLockWheelingWindow(window); - while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) - window = window->ParentWindow; - if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) - { - float max_step = window->InnerRect.GetHeight() * 0.67f; - float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); - SetScrollY(window, window->Scroll.y - wheel_y * scroll_step); - } - } - - // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held - const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; - if (wheel_x != 0.0f && !g.IO.KeyCtrl) - { - StartLockWheelingWindow(window); - while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) - window = window->ParentWindow; - if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) - { - float max_step = window->InnerRect.GetWidth() * 0.67f; - float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); - SetScrollX(window, window->Scroll.x - wheel_x * scroll_step); - } - } -} - // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) void ImGui::UpdateHoveredWindowAndCaptureFlags() { ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); // Find the window hovered by mouse: // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + bool clear_hovered_windows = false; FindHoveredWindow(); - // Modal windows prevents cursor from hovering behind them. + // Modal windows prevents mouse from hovering behind them. ImGuiWindow* modal_window = GetTopMostPopupModal(); - if (modal_window) - if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) - g.HoveredRootWindow = g.HoveredWindow = NULL; + if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) + clear_hovered_windows = true; // Disabled mouse? - if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) - g.HoveredWindow = g.HoveredRootWindow = NULL; - - // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. - int mouse_earliest_button_down = -1; + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + clear_hovered_windows = true; + + // We track click ownership. When clicked outside of a window the click is owned by the application and + // won't report hovering nor request capture even while dragging over our windows afterward. + const bool has_open_popup = (g.OpenPopupStack.Size > 0); + const bool has_open_modal = (modal_window != NULL); + int mouse_earliest_down = -1; bool mouse_any_down = false; - for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) { - if (g.IO.MouseClicked[i]) - g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); - mouse_any_down |= g.IO.MouseDown[i]; - if (g.IO.MouseDown[i]) - if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) - mouse_earliest_button_down = i; + if (io.MouseClicked[i]) + { + io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup; + io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal; + } + mouse_any_down |= io.MouseDown[i]; + if (io.MouseDown[i]) + if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down]) + mouse_earliest_down = i; } - const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; + const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down]; + const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down]; // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; - if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) - g.HoveredWindow = g.HoveredRootWindow = NULL; + if (!mouse_avail && !mouse_dragging_extern_payload) + clear_hovered_windows = true; + + if (clear_hovered_windows) + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; - // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app) + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app) + // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag if (g.WantCaptureMouseNextFrame != -1) - g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); + { + io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0); + } else - g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty()); + { + io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup; + io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal; + } - // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app) + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) if (g.WantCaptureKeyboardNextFrame != -1) - g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); else - g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); - if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) - g.IO.WantCaptureKeyboard = true; + io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + io.WantCaptureKeyboard = true; // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible - g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; -} - -static void NewFrameSanityChecks() -{ - ImGuiContext& g = *GImGui; - - // Check user data - // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) - IM_ASSERT(g.Initialized); - IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); - IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); - IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); - IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); - IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); - IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); - IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!"); - IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); - IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); - for (int n = 0; n < ImGuiKey_COUNT; n++) - IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); - - // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP) - if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) - IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); - - // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. - if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) - g.IO.ConfigWindowsResizeFromEdges = false; + io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } void ImGui::NewFrame() @@ -3527,72 +4409,73 @@ void ImGui::NewFrame() IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); ImGuiContext& g = *GImGui; -#ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PreNewFrame(&g); -#endif + // Remove pending delete hooks before frame start. + // This deferred removal avoid issues of removal while iterating the hook vector + for (int n = g.Hooks.Size - 1; n >= 0; n--) + if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) + g.Hooks.erase(&g.Hooks[n]); - // Check and assert for various common IO and Configuration mistakes - NewFrameSanityChecks(); + CallContextHooks(&g, ImGuiContextHookType_NewFramePre); - // Load settings on first frame (if not explicitly loaded manually before) - if (!g.SettingsLoaded) - { - IM_ASSERT(g.SettingsWindows.empty()); - if (g.IO.IniFilename) - LoadIniSettingsFromDisk(g.IO.IniFilename); - g.SettingsLoaded = true; - } + // Check and assert for various common IO and Configuration mistakes + ErrorCheckNewFrameSanityChecks(); - // Save settings (with a delay after the last modification, so we don't spam disk too much) - if (g.SettingsDirtyTimer > 0.0f) - { - g.SettingsDirtyTimer -= g.IO.DeltaTime; - if (g.SettingsDirtyTimer <= 0.0f) - { - if (g.IO.IniFilename != NULL) - SaveIniSettingsToDisk(g.IO.IniFilename); - else - g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. - g.SettingsDirtyTimer = 0.0f; - } - } + // Load settings on first frame, save settings when modified (after a delay) + UpdateSettings(); g.Time += g.IO.DeltaTime; g.WithinFrameScope = true; g.FrameCount += 1; g.TooltipOverrideCount = 0; g.WindowsActiveCount = 0; + g.MenusIdSubmittedThisFrame.resize(0); + + // Calculate frame-rate for the user, as a purely luxurious feature + g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; + g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; + g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); + g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame)); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX; + + // Process input queue (trickle as many events as possible), turn events into writes to IO structure + g.InputEventsTrail.resize(0); + UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue); + + // Update viewports (after processing input queue, so io.MouseHoveredViewport is set) + UpdateViewportsNewFrame(); // Setup current font and draw list shared data g.IO.Fonts->Locked = true; SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); - g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + virtual_space.Add(g.Viewports[n]->GetMainRect()); + g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; if (g.Style.AntiAliasedLines) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; + if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex; if (g.Style.AntiAliasedFill) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; - g.BackgroundDrawList.Clear(); - g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); - g.BackgroundDrawList.PushClipRectFullScreen(); - - g.ForegroundDrawList.Clear(); - g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); - g.ForegroundDrawList.PushClipRectFullScreen(); - // Mark rendering data as invalid to prevent user who may have a handle on it to use it. - g.DrawData.Clear(); + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataP.Clear(); + } // Drag and drop keep the source ID alive so even if the source disappear our state is consistent if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) KeepAliveID(g.DragDropPayload.SourceId); - // Clear reference to active widget if the widget isn't alive anymore + // Update HoveredId data if (!g.HoveredIdPreviousFrame) g.HoveredIdTimer = 0.0f; if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) @@ -3604,8 +4487,18 @@ void ImGui::NewFrame() g.HoveredIdPreviousFrame = g.HoveredId; g.HoveredId = 0; g.HoveredIdAllowOverlap = false; - if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) + g.HoveredIdDisabled = false; + + // Clear ActiveID if the item is not alive anymore. + // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd(). + // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves. + if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId) + { + IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n"); ClearActiveID(); + } + + // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) if (g.ActiveId) g.ActiveIdTimer += g.IO.DeltaTime; g.LastActiveIdTimer += g.IO.DeltaTime; @@ -3616,37 +4509,74 @@ void ImGui::NewFrame() g.ActiveIdHasBeenEditedThisFrame = false; g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; - if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId) - g.TempInputTextId = 0; + if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) + g.TempInputId = 0; + if (g.ActiveId == 0) + { + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + g.ActiveIdUsingNavInputMask = 0x00; +#endif + } + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO if (g.ActiveId == 0) + g.ActiveIdUsingNavInputMask = 0; + else if (g.ActiveIdUsingNavInputMask != 0) + { + // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); } + // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); } + if (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel)) + SetKeyOwner(ImGuiKey_Escape, g.ActiveId); + if (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel)) + IM_ASSERT(0); // Other values unsupported + } +#endif + + // Update hover delay for IsItemHovered() with delays and tooltips + g.HoverDelayIdPreviousFrame = g.HoverDelayId; + if (g.HoverDelayId != 0) + { + //if (g.IO.MouseDelta.x == 0.0f && g.IO.MouseDelta.y == 0.0f) // Need design/flags + g.HoverDelayTimer += g.IO.DeltaTime; + g.HoverDelayClearTimer = 0.0f; + g.HoverDelayId = 0; + } + else if (g.HoverDelayTimer > 0.0f) { - g.ActiveIdUsingNavDirMask = g.ActiveIdUsingNavInputMask = 0; - g.ActiveIdUsingKeyInputMask = 0; + // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps + g.HoverDelayClearTimer += g.IO.DeltaTime; + if (g.HoverDelayClearTimer >= ImMax(0.20f, g.IO.DeltaTime * 2.0f)) // ~6 frames at 30 Hz + allow for low framerate + g.HoverDelayTimer = g.HoverDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer. } // Drag and drop g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; g.DragDropAcceptIdCurr = 0; g.DragDropAcceptIdCurrRectSurface = FLT_MAX; - g.DragDropWithinSourceOrTarget = false; + g.DragDropWithinSource = false; + g.DragDropWithinTarget = false; + g.DragDropHoldJustPressedId = 0; + + // Close popups on focus lost (currently wip/opt-in) + //if (g.IO.AppFocusLost) + // ClosePopupsExceptModals(); // Update keyboard input state - memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); - for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) - g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + UpdateKeyboardInputs(); + + //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl)); + //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift)); + //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt)); + //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper)); - // Update gamepad/keyboard directional navigation + // Update gamepad/keyboard navigation NavUpdate(); // Update mouse input state UpdateMouseInputs(); - // Calculate frame-rate for the user, as a purely luxurious feature - g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; - g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); - g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; - // Find hovered window // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) UpdateHoveredWindowAndCaptureFlags(); @@ -3662,201 +4592,81 @@ void ImGui::NewFrame() g.MouseCursor = ImGuiMouseCursor_Arrow; g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; - g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + + // Platform IME data: reset for the frame + g.PlatformImeDataPrev = g.PlatformImeData; + g.PlatformImeData.WantVisible = false; // Mouse wheel scrolling, scale UpdateMouseWheel(); - // Pressing TAB activate widget focus - g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); - if (g.ActiveId == 0 && g.FocusTabPressed) - { - // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also - // manipulate the Next fields even, even though they will be turned into Curr fields by the code below. - g.FocusRequestNextWindow = g.NavWindow; - g.FocusRequestNextCounterAll = INT_MAX; - if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) - g.FocusRequestNextCounterTab = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); - else - g.FocusRequestNextCounterTab = g.IO.KeyShift ? -1 : 0; - } - - // Turn queued focus request into current one - g.FocusRequestCurrWindow = NULL; - g.FocusRequestCurrCounterAll = g.FocusRequestCurrCounterTab = INT_MAX; - if (g.FocusRequestNextWindow != NULL) - { - ImGuiWindow* window = g.FocusRequestNextWindow; - g.FocusRequestCurrWindow = window; - if (g.FocusRequestNextCounterAll != INT_MAX && window->DC.FocusCounterAll != -1) - g.FocusRequestCurrCounterAll = ImModPositive(g.FocusRequestNextCounterAll, window->DC.FocusCounterAll + 1); - if (g.FocusRequestNextCounterTab != INT_MAX && window->DC.FocusCounterTab != -1) - g.FocusRequestCurrCounterTab = ImModPositive(g.FocusRequestNextCounterTab, window->DC.FocusCounterTab + 1); - g.FocusRequestNextWindow = NULL; - g.FocusRequestNextCounterAll = g.FocusRequestNextCounterTab = INT_MAX; - } - - g.NavIdTabCounter = INT_MAX; - // Mark all windows as not visible and compact unused memory. - IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); - const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX; + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; for (int i = 0; i != g.Windows.Size; i++) { ImGuiWindow* window = g.Windows[i]; window->WasActive = window->Active; - window->BeginCount = 0; window->Active = false; window->WriteAccessed = false; + window->BeginCountPreviousFrame = window->BeginCount; + window->BeginCount = 0; - // Garbage collect (this is totally functional but we may need decide if the side-effects are desirable) + // Garbage collect transient buffers of recently unused windows if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) GcCompactTransientWindowBuffers(window); } + // Garbage collect transient buffers of recently unused tables + for (int i = 0; i < g.TablesLastTimeActive.Size; i++) + if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) + TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); + for (int i = 0; i < g.TablesTempData.Size; i++) + if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) + TableGcCompactTransientBuffers(&g.TablesTempData[i]); + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); + g.GcCompactAll = false; + // Closing the focused window restore focus to the first active root window in descending z-order if (g.NavWindow && !g.NavWindow->WasActive) - FocusTopMostWindowUnderOne(NULL, NULL); + FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. g.CurrentWindowStack.resize(0); g.BeginPopupStack.resize(0); - ClosePopupsOverWindow(g.NavWindow, false); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_None); + g.GroupStack.resize(0); - // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. + // [DEBUG] Update debug features UpdateDebugToolItemPicker(); + UpdateDebugToolStackQueries(); + if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0) + g.DebugLocateId = 0; + if (g.DebugLogClipperAutoDisableFrames > 0 && --g.DebugLogClipperAutoDisableFrames == 0) + { + DebugLog("(Auto-disabled ImGuiDebugLogFlags_EventClipper to avoid spamming)\n"); + g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper; + } // Create implicit/fallback window - which we will only render it if the user has added something to it. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. - // This fallback is particularly important as it avoid ImGui:: calls from crashing. - SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); - Begin("Debug##Default"); + // This fallback is particularly important as it prevents ImGui:: calls from crashing. g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); -#ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PostNewFrame(&g); -#endif -} - -// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. -void ImGui::UpdateDebugToolItemPicker() -{ - ImGuiContext& g = *GImGui; - g.DebugItemPickerBreakID = 0; - if (g.DebugItemPickerActive) - { - const ImGuiID hovered_id = g.HoveredIdPreviousFrame; - ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); - if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) - g.DebugItemPickerActive = false; - if (ImGui::IsMouseClicked(0) && hovered_id) - { - g.DebugItemPickerBreakID = hovered_id; - g.DebugItemPickerActive = false; - } - ImGui::SetNextWindowBgAlpha(0.60f); - ImGui::BeginTooltip(); - ImGui::Text("HoveredId: 0x%08X", hovered_id); - ImGui::Text("Press ESC to abort picking."); - ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); - ImGui::EndTooltip(); - } -} - -void ImGui::Initialize(ImGuiContext* context) -{ - ImGuiContext& g = *context; - IM_ASSERT(!g.Initialized && !g.SettingsLoaded); - - // Add .ini handle for ImGuiWindow type - { - ImGuiSettingsHandler ini_handler; - ini_handler.TypeName = "Window"; - ini_handler.TypeHash = ImHashStr("Window"); - ini_handler.ReadOpenFn = [](ImGuiContext* g, ImGuiSettingsHandler* gg, const char* name) -> void* { - return WindowSettingsHandler_ReadOpen(g, gg, name); - }; - ini_handler.ReadLineFn = [](ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line) -> void { - WindowSettingsHandler_ReadLine(ctx, handler, entry, line); - }; - ini_handler.WriteAllFn = [](ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) -> void { - WindowSettingsHandler_WriteAll(ctx, handler, buf); - }; - g.SettingsHandlers.push_back(ini_handler); - } - - g.Initialized = true; -} - -// This function is merely here to free heap allocations. -void ImGui::Shutdown(ImGuiContext* context) -{ - // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) - ImGuiContext& g = *context; - if (g.IO.Fonts && g.FontAtlasOwnedByContext) - { - g.IO.Fonts->Locked = false; - IM_DELETE(g.IO.Fonts); - } - g.IO.Fonts = NULL; - - // Cleanup of other data are conditional on actually having initialized Dear ImGui. - if (!g.Initialized) - return; - - // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) - if (g.SettingsLoaded && g.IO.IniFilename != NULL) - { - ImGuiContext* backup_context = GImGui; - SetCurrentContext(context); - SaveIniSettingsToDisk(g.IO.IniFilename); - SetCurrentContext(backup_context); - } - - // Clear everything else - for (int i = 0; i < g.Windows.Size; i++) - IM_DELETE(g.Windows[i]); - g.Windows.clear(); - g.WindowsFocusOrder.clear(); - g.WindowsSortBuffer.clear(); - g.CurrentWindow = NULL; - g.CurrentWindowStack.clear(); - g.WindowsById.Clear(); - g.NavWindow = NULL; - g.HoveredWindow = g.HoveredRootWindow = NULL; - g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; - g.MovingWindow = NULL; - g.ColorModifiers.clear(); - g.StyleModifiers.clear(); - g.FontStack.clear(); - g.OpenPopupStack.clear(); - g.BeginPopupStack.clear(); - g.DrawDataBuilder.ClearFreeMemory(); - g.BackgroundDrawList.ClearFreeMemory(); - g.ForegroundDrawList.ClearFreeMemory(); - - g.TabBars.Clear(); - g.CurrentTabBarStack.clear(); - g.ShrinkWidthBuffer.clear(); - - g.PrivateClipboard.clear(); - g.InputTextState.ClearFreeMemory(); - - g.SettingsWindows.clear(); - g.SettingsHandlers.clear(); - - if (g.LogFile) - { -#ifndef IMGUI_DISABLE_TTY_FUNCTIONS - if (g.LogFile != stdout) -#endif - ImFileClose(g.LogFile); - g.LogFile = NULL; - } - g.LogBuffer.clear(); + // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack, + // allowing to validate correct Begin/End behavior in user code. + if (g.IO.ConfigDebugBeginReturnValueLoop) + g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10); + else + g.DebugBeginReturnValueCullDepth = -1; - g.Initialized = false; + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); } // FIXME: Add a more explicit sort order in the window structure. @@ -3877,8 +4687,7 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im if (window->Active) { int count = window->DC.ChildWindows.Size; - if (count > 1) - ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); for (int i = 0; i < count; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; @@ -3890,17 +4699,10 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) { - if (draw_list->CmdBuffer.empty()) + if (draw_list->CmdBuffer.Size == 0) + return; + if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL) return; - - // Remove trailing command if unused - ImDrawCmd& last_cmd = draw_list->CmdBuffer.back(); - if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL) - { - draw_list->CmdBuffer.pop_back(); - if (draw_list->CmdBuffer.empty()) - return; - } // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. // May trigger for you if you are using PrimXXX functions incorrectly. @@ -3912,13 +4714,13 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) // If this assert triggers because you are drawing lots of stuff manually: // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. - // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents. + // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. // - If you want large meshes with more than 64K vertices, you can either: - // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. - // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't. + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // Most example backends already support this from 1.71. Pre-1.71 backends won't. // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. - // (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. - // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time: + // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); // Your own engine or render API may use different parameters or function calls to specify index sizes. // 2 and 4 bytes indices are generally supported by most graphics API. @@ -3930,27 +4732,29 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d out_list->push_back(draw_list); } -static void AddWindowToDrawData(ImVector* out_render_list, ImGuiWindow* window) +static void AddWindowToDrawData(ImGuiWindow* window, int layer) { ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; g.IO.MetricsRenderWindows++; - AddDrawListToDrawData(out_render_list, window->DrawList); + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList); for (int i = 0; i < window->DC.ChildWindows.Size; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active - AddWindowToDrawData(out_render_list, child); + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, layer); } } +static inline int GetWindowDisplayLayer(ImGuiWindow* window) +{ + return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; +} + // Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) -static void AddRootWindowToDrawData(ImGuiWindow* window) +static inline void AddRootWindowToDrawData(ImGuiWindow* window) { - ImGuiContext& g = *GImGui; - if (window->Flags & ImGuiWindowFlags_Tooltip) - AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window); - else - AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window); + AddWindowToDrawData(window, GetWindowDisplayLayer(window)); } void ImDrawDataBuilder::FlattenIntoSingleLayer() @@ -3971,24 +4775,32 @@ void ImDrawDataBuilder::FlattenIntoSingleLayer() } } -static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_data) +static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector* draw_lists) { ImGuiIO& io = ImGui::GetIO(); + ImDrawData* draw_data = &viewport->DrawDataP; draw_data->Valid = true; draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; draw_data->CmdListsCount = draw_lists->Size; draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; - draw_data->DisplayPos = ImVec2(0.0f, 0.0f); - draw_data->DisplaySize = io.DisplaySize; + draw_data->DisplayPos = viewport->Pos; + draw_data->DisplaySize = viewport->Size; draw_data->FramebufferScale = io.DisplayFramebufferScale; for (int n = 0; n < draw_lists->Size; n++) { - draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; - draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; + ImDrawList* draw_list = draw_lists->Data[n]; + draw_list->_PopUnusedDrawCmd(); + draw_data->TotalVtxCount += draw_list->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_list->IdxBuffer.Size; } } -// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. +// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. +// - When using this function it is sane to ensure that float are perfectly rounded to integer values, +// so that e.g. (int)(max.x-min.x) in user's render produce correct result. +// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): +// some frequently called functions which to modify both channels and clipping simultaneously tend to use the +// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); @@ -4003,33 +4815,131 @@ void ImGui::PopClipRect() window->ClipRect = window->DrawList->_ClipRectStack.back(); } +static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport(); + ImRect viewport_rect = viewport->GetMainRect(); + + // Draw behind window by moving the draw command at the FRONT of the draw list + { + // We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows, + // and draw list have been trimmed already, hence the explicit recreation of a draw command if missing. + // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order. + ImDrawList* draw_list = window->RootWindow->DrawList; + if (draw_list->CmdBuffer.Size == 0) + draw_list->AddDrawCmd(); + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged + draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); + ImDrawCmd cmd = draw_list->CmdBuffer.back(); + IM_ASSERT(cmd.ElemCount == 6); + draw_list->CmdBuffer.pop_back(); + draw_list->CmdBuffer.push_front(cmd); + draw_list->PopClipRect(); + draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command. + } +} + +ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* bottom_most_visible_window = parent_window; + for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + if (!IsWindowWithinBeginStackOf(window, parent_window)) + break; + if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window)) + bottom_most_visible_window = window; + } + return bottom_most_visible_window; +} + +static void ImGui::RenderDimmedBackgrounds() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal(); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + return; + const bool dim_bg_for_modal = (modal_window != NULL); + const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active); + if (!dim_bg_for_modal && !dim_bg_for_window_list) + return; + + if (dim_bg_for_modal) + { + // Draw dimming behind modal or a begin stack child, whichever comes first in draw order. + ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window); + RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio)); + } + else if (dim_bg_for_window_list) + { + // Draw dimming behind CTRL+Tab target window + RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio)); + + // Draw border around CTRL+Tab target window + ImGuiWindow* window = g.NavWindowingTargetAnim; + ImGuiViewport* viewport = GetMainViewport(); + float distance = g.FontSize; + ImRect bb = window->Rect(); + bb.Expand(distance); + if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y) + bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward + if (window->DrawList->CmdBuffer.Size == 0) + window->DrawList->AddDrawCmd(); + window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); + window->DrawList->PopClipRect(); + } +} + // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. void ImGui::EndFrame() { ImGuiContext& g = *GImGui; IM_ASSERT(g.Initialized); - if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. + + // Don't process EndFrame() multiple times. + if (g.FrameCountEnded == g.FrameCount) return; IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); - // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) + CallContextHooks(&g, ImGuiContextHookType_EndFramePre); + + ErrorCheckEndFrameSanityChecks(); + + // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + ImGuiPlatformImeData* ime_data = &g.PlatformImeData; + if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) { - g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); - g.PlatformImeLastPos = g.PlatformImePos; + IMGUI_DEBUG_LOG_IO("[io] Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + ImGuiViewport* viewport = GetMainViewport(); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (viewport->PlatformHandleRaw == NULL && g.IO.ImeWindowHandle != NULL) + { + viewport->PlatformHandleRaw = g.IO.ImeWindowHandle; + g.IO.SetPlatformImeDataFn(viewport, ime_data); + viewport->PlatformHandleRaw = NULL; + } + else +#endif + { + g.IO.SetPlatformImeDataFn(viewport, ime_data); + } } - ErrorCheckEndFrame(); - // Hide implicit/fallback "Debug" window if it hasn't been used g.WithinFrameScopeWithImplicitWindow = false; if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) g.CurrentWindow->Active = false; End(); - // Show CTRL+TAB list window - if (g.NavWindowingTarget != NULL) - NavUpdateWindowingOverlay(); + // Update navigation: CTRL+Tab, wrap-around requests + NavEndFrame(); // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) if (g.DragDropActive) @@ -4041,11 +4951,11 @@ void ImGui::EndFrame() } // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. - if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) { - g.DragDropWithinSourceOrTarget = true; + g.DragDropWithinSource = true; SetTooltip("..."); - g.DragDropWithinSourceOrTarget = false; + g.DragDropWithinSource = false; } // End frame @@ -4056,31 +4966,36 @@ void ImGui::EndFrame() UpdateMouseMovingWindowEndFrame(); // Sort the window list so that all child windows are after their parent - // We cannot do that on FocusWindow() because childs may not exist yet - g.WindowsSortBuffer.resize(0); - g.WindowsSortBuffer.reserve(g.Windows.Size); + // We cannot do that on FocusWindow() because children may not exist yet + g.WindowsTempSortBuffer.resize(0); + g.WindowsTempSortBuffer.reserve(g.Windows.Size); for (int i = 0; i != g.Windows.Size; i++) { ImGuiWindow* window = g.Windows[i]; if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it continue; - AddWindowToSortBuffer(&g.WindowsSortBuffer, window); + AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); } // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. - IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); - g.Windows.swap(g.WindowsSortBuffer); + IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); + g.Windows.swap(g.WindowsTempSortBuffer); g.IO.MetricsActiveWindows = g.WindowsActiveCount; // Unlock font atlas g.IO.Fonts->Locked = false; // Clear Input data for next frame + g.IO.AppFocusLost = false; g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; g.IO.InputQueueCharacters.resize(0); - memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePost); } +// Prepare the data for rendering so you can call GetDrawData() +// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all: +// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend) void ImGui::Render() { ImGuiContext& g = *GImGui; @@ -4088,45 +5003,62 @@ void ImGui::Render() if (g.FrameCountEnded != g.FrameCount) EndFrame(); + const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); g.FrameCountRendered = g.FrameCount; + g.IO.MetricsRenderWindows = 0; + + CallContextHooks(&g, ImGuiContextHookType_RenderPre); + + // Add background ImDrawList (for each active viewport) + for (int n = 0; n != g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.Clear(); + if (viewport->DrawLists[0] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + } - // Gather ImDrawList to render (for each active window) - g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsRenderWindows = 0; - g.DrawDataBuilder.Clear(); - if (!g.BackgroundDrawList.VtxBuffer.empty()) - AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); + // Draw modal/window whitening backgrounds + if (first_render_of_frame) + RenderDimmedBackgrounds(); + // Add ImDrawList to render ImGuiWindow* windows_to_render_top_most[2]; windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; - windows_to_render_top_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL; + windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); for (int n = 0; n != g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) AddRootWindowToDrawData(window); } for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window AddRootWindowToDrawData(windows_to_render_top_most[n]); - g.DrawDataBuilder.FlattenIntoSingleLayer(); - // Draw software mouse cursor if requested - if (g.IO.MouseDrawCursor) - RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + // Draw software mouse cursor if requested by io.MouseDrawCursor flag + if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None) + RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); - if (!g.ForegroundDrawList.VtxBuffer.empty()) - AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList); + // Setup ImDrawData structures for end-user + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.FlattenIntoSingleLayer(); - // Setup ImDrawData structure for end-user - SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); - g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; - g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; + // Add foreground ImDrawList (for each active viewport) + if (viewport->DrawLists[1] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); - // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) - g.IO.RenderDrawListsFn(&g.DrawData); -#endif + SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]); + ImDrawData* draw_data = &viewport->DrawDataP; + g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; + g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; + } + + CallContextHooks(&g, ImGuiContextHookType_RenderPost); } // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. @@ -4148,13 +5080,17 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); // Round - text_size.x = IM_FLOOR(text_size.x + 0.95f); + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); return text_size; } // Find window given position, search front-to-back -// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically // with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is // called, aka before the next Begin(). Moving window isn't affected. static void FindHoveredWindow() @@ -4162,14 +5098,16 @@ static void FindHoveredWindow() ImGuiContext& g = *GImGui; ImGuiWindow* hovered_window = NULL; + ImGuiWindow* hovered_window_ignoring_moving_window = NULL; if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) hovered_window = g.MovingWindow; ImVec2 padding_regular = g.Style.TouchExtraPadding; - ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; for (int i = g.Windows.Size - 1; i >= 0; i--) { ImGuiWindow* window = g.Windows[i]; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. if (!window->Active || window->Hidden) continue; if (window->Flags & ImGuiWindowFlags_NoMouseInputs) @@ -4180,275 +5118,56 @@ static void FindHoveredWindow() if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) bb.Expand(padding_regular); else - bb.Expand(padding_for_resize_from_edges); + bb.Expand(padding_for_resize); if (!bb.Contains(g.IO.MousePos)) continue; - // Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches. + // Support for one rectangular hole in any given window + // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) + if (window->HitTestHoleSize.x != 0) + { + ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y); + ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y); + if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos)) + continue; + } + if (hovered_window == NULL) hovered_window = window; - if (hovered_window) + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) + hovered_window_ignoring_moving_window = window; + if (hovered_window && hovered_window_ignoring_moving_window) break; } g.HoveredWindow = hovered_window; - g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; - + g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; } -// Test if mouse cursor is hovering given rectangle -// NB- Rectangle is clipped by our current clip setting -// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +bool ImGui::IsItemActive() { ImGuiContext& g = *GImGui; - - // Clip - ImRect rect_clipped(r_min, r_max); - if (clip) - rect_clipped.ClipWith(g.CurrentWindow->ClipRect); - - // Expand for touch input - const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); - if (!rect_for_touch.Contains(g.IO.MousePos)) - return false; - return true; -} - -int ImGui::GetKeyIndex(ImGuiKey imgui_key) -{ - IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); - ImGuiContext& g = *GImGui; - return g.IO.KeyMap[imgui_key]; -} - -// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! -bool ImGui::IsKeyDown(int user_key_index) -{ - if (user_key_index < 0) - return false; - ImGuiContext& g = *GImGui; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - return g.IO.KeysDown[user_key_index]; -} - -// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) -// t1 = current time (e.g.: g.Time) -// An event is triggered at: -// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N -int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) -{ - if (t1 == 0.0f) - return 1; - if (t0 >= t1) - return 0; - if (repeat_rate <= 0.0f) - return (t0 < repeat_delay) && (t1 >= repeat_delay); - const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); - const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); - const int count = count_t1 - count_t0; - return count; -} - -int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) -{ - ImGuiContext& g = *GImGui; - if (key_index < 0) - return 0; - IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - const float t = g.IO.KeysDownDuration[key_index]; - return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); -} - -bool ImGui::IsKeyPressed(int user_key_index, bool repeat) -{ - ImGuiContext& g = *GImGui; - if (user_key_index < 0) - return false; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - const float t = g.IO.KeysDownDuration[user_key_index]; - if (t == 0.0f) - return true; - if (repeat && t > g.IO.KeyRepeatDelay) - return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; - return false; -} - -bool ImGui::IsKeyReleased(int user_key_index) -{ - ImGuiContext& g = *GImGui; - if (user_key_index < 0) return false; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; -} - -bool ImGui::IsMouseDown(int button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseDown[button]; -} - -bool ImGui::IsAnyMouseDown() -{ - ImGuiContext& g = *GImGui; - for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) - if (g.IO.MouseDown[n]) - return true; - return false; -} - -bool ImGui::IsMouseClicked(int button, bool repeat) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - const float t = g.IO.MouseDownDuration[button]; - if (t == 0.0f) - return true; - - if (repeat && t > g.IO.KeyRepeatDelay) - { - // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. - int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); - if (amount > 0) - return true; - } - - return false; -} - -bool ImGui::IsMouseReleased(int button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseReleased[button]; -} - -bool ImGui::IsMouseDoubleClicked(int button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseDoubleClicked[button]; -} - -// [Internal] This doesn't test if the button is pressed -bool ImGui::IsMouseDragPastThreshold(int button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; -} - -bool ImGui::IsMouseDragging(int button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (!g.IO.MouseDown[button]) - return false; - return IsMouseDragPastThreshold(button, lock_threshold); -} - -ImVec2 ImGui::GetMousePos() -{ - return GImGui->IO.MousePos; -} - -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! -ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() -{ - ImGuiContext& g = *GImGui; - if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos; - return g.IO.MousePos; -} - -// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. -bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) -{ - // The assert is only to silence a false-positive in XCode Static Analysis. - // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). - IM_ASSERT(GImGui != NULL); - const float MOUSE_INVALID = -256000.0f; - ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; - return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; -} - -// Return the delta from the initial clicking position while the mouse button is clicked or was just released. -// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. -// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. -ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) - if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) - if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) - return g.IO.MousePos - g.IO.MouseClickedPos[button]; - return ImVec2(0.0f, 0.0f); -} - -void ImGui::ResetMouseDragDelta(int button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr - g.IO.MouseClickedPos[button] = g.IO.MousePos; -} - -ImGuiMouseCursor ImGui::GetMouseCursor() -{ - return GImGui->MouseCursor; -} - -void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) -{ - GImGui->MouseCursor = cursor_type; -} - -void ImGui::CaptureKeyboardFromApp(bool capture) -{ - GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; -} - -void ImGui::CaptureMouseFromApp(bool capture) -{ - GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; -} - -bool ImGui::IsItemActive() -{ - ImGuiContext& g = *GImGui; - if (g.ActiveId) - { - ImGuiWindow* window = g.CurrentWindow; - return g.ActiveId == window->DC.LastItemId; - } - return false; -} + if (g.ActiveId) + return g.ActiveId == g.LastItemData.ID; + return false; +} bool ImGui::IsItemActivated() { ImGuiContext& g = *GImGui; if (g.ActiveId) - { - ImGuiWindow* window = g.CurrentWindow; - if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) + if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID) return true; - } return false; } bool ImGui::IsItemDeactivated() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) - return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; - return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; + return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID); } bool ImGui::IsItemDeactivatedAfterEdit() @@ -4457,17 +5176,18 @@ bool ImGui::IsItemDeactivatedAfterEdit() return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); } +// == GetItemID() == GetFocusID() bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) + if (g.NavId != g.LastItemData.ID || g.NavId == 0) return false; return true; } -bool ImGui::IsItemClicked(int mouse_button) +// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()! +// Most widgets have specific reactions based on mouse-up/down state, mouse position etc. +bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) { return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); } @@ -4475,13 +5195,13 @@ bool ImGui::IsItemClicked(int mouse_button) bool ImGui::IsItemToggledOpen() { ImGuiContext& g = *GImGui; - return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; } bool ImGui::IsItemToggledSelection() { ImGuiContext& g = *GImGui; - return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; } bool ImGui::IsAnyItemHovered() @@ -4504,56 +5224,68 @@ bool ImGui::IsAnyItemFocused() bool ImGui::IsItemVisible() { - ImGuiWindow* window = GetCurrentWindowRead(); - return window->ClipRect.Overlaps(window->DC.LastItemRect); + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) != 0; } bool ImGui::IsItemEdited() { - ImGuiWindow* window = GetCurrentWindowRead(); - return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0; } // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework. void ImGui::SetItemAllowOverlap() { ImGuiContext& g = *GImGui; - if (g.HoveredId == g.CurrentWindow->DC.LastItemId) + ImGuiID id = g.LastItemData.ID; + if (g.HoveredId == id) g.HoveredIdAllowOverlap = true; - if (g.ActiveId == g.CurrentWindow->DC.LastItemId) + if (g.ActiveId == id) g.ActiveIdAllowOverlap = true; } -ImVec2 ImGui::GetItemRectMin() +// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function. +void ImGui::SetActiveIdUsingAllKeyboardKeys() { - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.LastItemRect.Min; + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId != 0); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_COUNT) - 1; + g.ActiveIdUsingAllKeyboardKeys = true; + NavMoveRequestCancel(); } -ImVec2 ImGui::GetItemRectMax() +ImGuiID ImGui::GetItemID() { - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.LastItemRect.Max; + ImGuiContext& g = *GImGui; + return g.LastItemData.ID; } -ImVec2 ImGui::GetItemRectSize() +ImVec2 ImGui::GetItemRectMin() { - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.LastItemRect.GetSize(); + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Max; } -static ImRect GetViewportRect() +ImVec2 ImGui::GetItemRectSize() { ImGuiContext& g = *GImGui; - return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + return g.LastItemData.Rect.GetSize(); } -static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) +bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* parent_window = g.CurrentWindow; - flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; + flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag // Size @@ -4561,22 +5293,22 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size ImVec2 size = ImFloor(size_arg); const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); if (size.x <= 0.0f) - size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too many issues) if (size.y <= 0.0f) size.y = ImMax(content_avail.y + size.y, 4.0f); SetNextWindowSize(size); // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. - char title[256]; + const char* temp_window_name; if (name) - ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id); + ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id); else - ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); + ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id); const float backup_border_size = g.Style.ChildBorderSize; if (!border) g.Style.ChildBorderSize = 0.0f; - bool ret = Begin(title, NULL, flags); + bool ret = Begin(temp_window_name, NULL, flags); g.Style.ChildBorderSize = backup_border_size; ImGuiWindow* child_window = g.CurrentWindow; @@ -4589,12 +5321,16 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size parent_window->DC.CursorPos = child_window->Pos; // Process navigation-in immediately so NavInit can run on first frame - if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) + // Can enter a child if (A) it has navigatable items or (B) it can be scrolled. + const ImGuiID temp_id_for_activation = (id + 1); + if (g.ActiveId == temp_id_for_activation) + ClearActiveID(); + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY)) { FocusWindow(child_window); NavInitWindow(child_window, false); - SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item - g.ActiveIdSource = ImGuiInputSource_Nav; + SetActiveID(temp_id_for_activation, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item + g.ActiveIdSource = g.NavInputSource; } return ret; } @@ -4617,7 +5353,7 @@ void ImGui::EndChild() ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(g.WithinEndChild == false); - IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls g.WithinEndChild = true; if (window->BeginCount > 1) @@ -4636,22 +5372,29 @@ void ImGui::EndChild() ImGuiWindow* parent_window = g.CurrentWindow; ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); ItemSize(sz); - if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavWindowHasScrollY) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) { ItemAdd(bb, window->ChildId); RenderNavHighlight(bb, window->ChildId); - // When browsing a window that has no activable items (scroll only) we keep a highlight on the child - if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) - RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) + if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); } else { // Not navigable into ItemAdd(bb, 0); + + // But when flattened we directly reach items, adjust active layer mask accordingly + if (window->Flags & ImGuiWindowFlags_NavFlattened) + parent_window->DC.NavLayersActiveMaskNext |= window->DC.NavLayersActiveMaskNext; } + if (g.HoveredWindow == window) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; } g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } // Helper to create a child window / scrolling region that looks like a normal widget frame. @@ -4693,35 +5436,53 @@ ImGuiWindow* ImGui::FindWindowByName(const char* name) return FindWindowByID(id); } -static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags) +static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y)); + if (settings->Size.x > 0 && settings->Size.y > 0) + window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y)); + window->Collapsed = settings->Collapsed; +} + +static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) { ImGuiContext& g = *GImGui; - //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); - // Create window the first time - ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); - window->Flags = flags; - g.WindowsById.SetVoidPtr(window->ID, window); + const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); + const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; + if ((just_created || child_flag_changed) && !new_is_explicit_child) + { + IM_ASSERT(!g.WindowsFocusOrder.contains(window)); + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + else if (!just_created && child_flag_changed && new_is_explicit_child) + { + IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); + for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) + g.WindowsFocusOrder[n]->FocusOrder--; + g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); + window->FocusOrder = -1; + } + window->IsExplicitChild = new_is_explicit_child; +} - // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. - window->Pos = ImVec2(60, 60); +static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + // Initial window state with e.g. default/arbitrary window position + // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->Pos = main_viewport->Pos + ImVec2(60, 60); + window->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; - // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) - { - // Retrieve settings from .ini file - window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); - SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); - window->Pos = ImVec2(settings->Pos.x, settings->Pos.y); - window->Collapsed = settings->Collapsed; - if (settings->Size.x > 0 && settings->Size.y > 0) - size = ImVec2(settings->Size.x, settings->Size.y); - } - window->Size = window->SizeFull = ImFloor(size); - window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values + if (settings != NULL) + { + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { window->AutoFitFramesX = window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = false; @@ -4734,18 +5495,36 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); } +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + // Create window the first time + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + ImGuiWindowSettings* settings = NULL; + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0) + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + + InitOrLoadWindowSettings(window, settings); - g.WindowsFocusOrder.push_back(window); if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) g.Windows.push_front(window); // Quite slow but rare and only once else g.Windows.push_back(window); + return window; } -static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired) { ImGuiContext& g = *GImGui; + ImVec2 new_size = size_desired; if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) { // Using -1,-1 on either X/Y axis to preserve the current size. @@ -4769,33 +5548,42 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size // Minimum size if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) { + ImGuiWindow* window_for_height = window; new_size = ImMax(new_size, g.Style.WindowMinSize); - new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + const float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f); + new_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows } return new_size; } -static ImVec2 CalcWindowContentSize(ImGuiWindow* window) +static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal) { - if (window->Collapsed) - if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - return window->ContentSize; - if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) - return window->ContentSize; + bool preserve_old_content_sizes = false; + if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + preserve_old_content_sizes = true; + else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) + preserve_old_content_sizes = true; + if (preserve_old_content_sizes) + { + *content_size_current = window->ContentSize; + *content_size_ideal = window->ContentSizeIdeal; + return; + } - ImVec2 sz; - sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); - sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); - return sz; + content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x); + content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); } static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; - ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); + const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x; + const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; ImVec2 size_pad = window->WindowPadding * 2.0f; - ImVec2 size_desired = size_contents + size_pad + size_decorations; + ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars); if (window->Flags & ImGuiWindowFlags_Tooltip) { // Tooltip always resize @@ -4809,13 +5597,15 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont ImVec2 size_min = style.WindowMinSize; if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); - ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); + + ImVec2 avail_size = ImGui::GetMainViewport()->WorkSize; + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f)); // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); - bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); - bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); if (will_have_scrollbar_x) size_auto_fit.y += style.ScrollbarSize; if (will_have_scrollbar_y) @@ -4824,19 +5614,21 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont } } -ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) +ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window) { - ImVec2 size_contents = CalcWindowContentSize(window); - ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents); + ImVec2 size_contents_current; + ImVec2 size_contents_ideal; + CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal); + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal); ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); return size_final; } -static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) +static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) { - if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) return ImGuiCol_PopupBg; - if (flags & ImGuiWindowFlags_ChildWindow) + if (window->Flags & ImGuiWindowFlags_ChildWindow) return ImGuiCol_ChildBg; return ImGuiCol_WindowBg; } @@ -4855,87 +5647,119 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co *out_size = size_constrained; } +// Data for resizing from corner struct ImGuiResizeGripDef { ImVec2 CornerPosN; ImVec2 InnerDir; int AngleMin12, AngleMax12; }; - static const ImGuiResizeGripDef resize_grip_def[4] = { - { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower-right - { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower-left - { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper-left (Unused) - { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper-right (Unused) + { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right + { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left + { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused) + { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused) +}; + +// Data for resizing from borders +struct ImGuiResizeBorderDef +{ + ImVec2 InnerDir; + ImVec2 SegmentN1, SegmentN2; + float OuterAngle; +}; +static const ImGuiResizeBorderDef resize_border_def[4] = +{ + { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left + { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right + { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up + { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down }; static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) { ImRect rect = window->Rect(); - if (thickness == 0.0f) rect.Max -= ImVec2(1,1); - if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top - if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right - if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom - if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left + if (thickness == 0.0f) + rect.Max -= ImVec2(1, 1); + if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } + if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } IM_ASSERT(0); return ImRect(); } // 0..3: corners (Lower-right, Lower-left, Unused, Unused) -// 4..7: borders (Top, Right, Bottom, Left) -ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n) +ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n) { - IM_ASSERT(n >= 0 && n <= 7); + IM_ASSERT(n >= 0 && n < 4); ImGuiID id = window->ID; id = ImHashStr("#RESIZE", 0, id); id = ImHashData(&n, sizeof(int), id); return id; } -// Handle resize for: Resize Grips, Borders, Gamepad -// Return true when using auto-fit (double click on resize grip) -static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) +// Borders (Left, Right, Up, Down) +ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) { - ImGuiContext& g = *GImGui; - ImGuiWindowFlags flags = window->Flags; - - if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) - return false; - if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. + IM_ASSERT(dir >= 0 && dir < 4); + int n = (int)dir + 4; + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Handle resize for: Resize Grips, Borders, Gamepad +// Return true when using auto-fit (double-click on resize grip) +static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return false; + if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window. return false; bool ret_auto_fit = false; const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); - const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; + + ImRect clamp_rect = visibility_rect; + const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar); + if (window_move_from_title_bar) + clamp_rect.Min.y -= window->TitleBarHeight(); ImVec2 pos_target(FLT_MAX, FLT_MAX); ImVec2 size_target(FLT_MAX, FLT_MAX); // Resize grips and borders are on layer 1 window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); // Manual resize grips PushID("#RESIZE"); for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { - const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; - const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN); // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window - ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); + bool hovered, held; + ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size); if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); - bool hovered, held; - ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID() + ItemAdd(resize_rect, resize_grip_id, NULL, ImGuiItemFlags_NoNav); + ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); if (hovered || held) g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; - if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) + if (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0) { // Manual auto-fit when double-clicking size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); @@ -4946,54 +5770,75 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { // Resize from any of the four corners // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip - CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); + ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? clamp_rect.Min.x : -FLT_MAX, (def.CornerPosN.y == 1.0f || (def.CornerPosN.y == 0.0f && window_move_from_title_bar)) ? clamp_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip + corner_target = ImClamp(corner_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target); } + + // Only lower-left grip is visible before hovering/activating if (resize_grip_n == 0 || held || hovered) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); } for (int border_n = 0; border_n < resize_border_count; border_n++) { + const ImGuiResizeBorderDef& def = resize_border_def[border_n]; + const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + bool hovered, held; - ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); - ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() + ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav); + ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { - g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; if (held) *border_held = border_n; } if (held) { + ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX); ImVec2 border_target = window->Pos; - ImVec2 border_posn; - if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top - if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right - if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom - if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left - CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); + border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; + border_target = ImClamp(border_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } } PopID(); + // Restore nav layer + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + // Navigation resize (keyboard/gamepad) + // FIXME: This cannot be moved to NavUpdateWindowing() because CalcWindowSizeAfterConstraint() need to callback into user. + // Not even sure the callback works here. if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) { - ImVec2 nav_resize_delta; - if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) - nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); - if (g.NavInputSource == ImGuiInputSource_NavGamepad) - nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); - if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + ImVec2 nav_resize_dir; + if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift) + nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown); + if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f) { const float NAV_RESIZE_SPEED = 600.0f; - nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y); + g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; + g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size g.NavWindowingToggleLayer = false; g.NavDisableMouseHover = true; resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); - // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. - size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); + ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaSize); + if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) + { + // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. + size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + accum_floored); + g.NavWindowingAccumDeltaSize -= accum_floored; + } } } @@ -5009,19 +5854,17 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au MarkIniSettingsDirty(window); } - // Resize nav layer - window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); - window->Size = window->SizeFull; return ret_auto_fit; } -static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding) +static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect) { ImGuiContext& g = *GImGui; - ImVec2 size_for_clamping = (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size; - window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping); + ImVec2 size_for_clamping = window->Size; + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + size_for_clamping.y = window->TitleBarHeight(); + window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); } static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) @@ -5030,29 +5873,16 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) float rounding = window->WindowRounding; float border_size = window->WindowBorderSize; if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) - window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); int border_held = window->ResizeBorderHeld; if (border_held != -1) { - struct ImGuiResizeBorderDef - { - ImVec2 InnerDir; - ImVec2 CornerPosN1, CornerPosN2; - float OuterAngle; - }; - static const ImGuiResizeBorderDef resize_border_def[4] = - { - { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top - { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right - { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom - { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left - }; const ImGuiResizeBorderDef& def = resize_border_def[border_held]; ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); - window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); - window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); - window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual } if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) { @@ -5061,23 +5891,26 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) } } -void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) +// Draw background and borders +// Draw and handle scrollbars +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; ImGuiWindowFlags flags = window->Flags; // Ensure that ScrollBar doesn't read last frame's SkipItems + IM_ASSERT(window->BeginCount == 0); window->SkipItems = false; // Draw window + handle manual resize - // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame. const float window_rounding = window->WindowRounding; const float window_border_size = window->WindowBorderSize; if (window->Collapsed) { // Title bar only - float backup_border_size = style.FrameBorderSize; + const float backup_border_size = style.FrameBorderSize; g.Style.FrameBorderSize = window->WindowBorderSize; ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); @@ -5088,20 +5921,24 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Window background if (!(flags & ImGuiWindowFlags_NoBackground)) { - ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window)); + bool override_alpha = false; float alpha = 1.0f; if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) + { alpha = g.NextWindowData.BgAlphaVal; - if (alpha != 1.0f) + override_alpha = true; + } + if (override_alpha) bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); - window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom); } // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); - window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop); } // Menu bar @@ -5109,7 +5946,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -5121,21 +5958,25 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar Scrollbar(ImGuiAxis_Y); // Render resize grips (after their input handling so we don't have a frame of latency) - if (!(flags & ImGuiWindowFlags_NoResize)) + if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) { for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { + const ImU32 col = resize_grip_col[resize_grip_n]; + if ((col & IM_COL32_A_MASK) == 0) + continue; const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); - window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); + window->DrawList->PathFillConvex(col); } } // Borders - RenderWindowOuterBorders(window); + if (handle_borders_and_resize_grips) + RenderWindowOuterBorders(window); } } @@ -5150,10 +5991,10 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) - const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref? + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); // Layout buttons // FIXME: Would be nice to generalize the subtleties expressed here into reusable code. @@ -5189,17 +6030,15 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl *p_open = false; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); - window->DC.ItemFlags = item_flags_backup; + g.CurrentItemFlags = item_flags_backup; // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. - const char* UNSAVED_DOCUMENT_MARKER = "*"; - const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f; const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, - // while uncentered title text will still reach edges correct. + // while uncentered title text will still reach edges correctly. if (pad_l > style.FramePadding.x) pad_l += g.Style.ItemInnerSpacing.x; if (pad_r > style.FramePadding.x) @@ -5213,23 +6052,31 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl } ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); - ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y); - //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] - RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); + ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y); if (flags & ImGuiWindowFlags_UnsavedDocument) { - ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); - ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f)); - RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r); + ImVec2 marker_pos; + marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x); + marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f; + if (marker_pos.x > layout_r.Min.x) + { + RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text)); + clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f)); + } } + //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); } void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) { window->ParentWindow = parent_window; - window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + window->RootWindow = window->RootWindowPopupTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) window->RootWindow = parent_window->RootWindow; + if (parent_window && (flags & ImGuiWindowFlags_Popup)) + window->RootWindowPopupTree = parent_window->RootWindowPopupTree; if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) @@ -5239,6 +6086,43 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags } } +// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) +// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. +// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. +// - Window // FindBlockingModal() returns Modal1 +// - Window // .. returns Modal1 +// - Modal1 // .. returns Modal2 +// - Window // .. returns Modal2 +// - Window // .. returns Modal2 +// - Modal2 // .. returns Modal2 +// Notes: +// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. +// Only difference is here we check for ->Active/WasActive but it may be unecessary. +ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= 0) + return NULL; + + // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. + for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--) + { + ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; + if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) + continue; + if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. + continue; + if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. + return popup_window; + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. + break; + for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow) + if (IsWindowWithinBeginStackOf(window, parent)) + return popup_window; // Place window above its begin stack parent. + } + return NULL; +} + // Push a new Dear ImGui window to add widgets to. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. @@ -5258,10 +6142,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImGuiWindow* window = FindWindowByName(name); const bool window_just_created = (window == NULL); if (window_just_created) - { - ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. - window = CreateNewWindow(name, size_on_first_use, flags); - } + window = CreateNewWindow(name, flags); // Automatically disable manual moving/resizing when NoInputs is set if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) @@ -5272,23 +6153,24 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const int current_frame = g.FrameCount; const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow); // Update the Appearing flag bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on - const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed window_just_activated_by_user |= (window != popup_ref.Window); } - window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); + window->Appearing = window_just_activated_by_user; if (window->Appearing) SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); // Update Flags, LastFrameActive, BeginOrderXXX fields if (first_begin_of_the_frame) { + UpdateWindowInFocusOrderList(window, window_just_created, flags); window->Flags = (ImGuiWindowFlags)flags; window->LastFrameActive = current_frame; window->LastTimeActive = (float)g.Time; @@ -5301,7 +6183,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack - ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); + ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window; ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); @@ -5311,21 +6193,39 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Add to stack // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() - g.CurrentWindowStack.push_back(window); + g.CurrentWindow = window; + ImGuiWindowStackData window_stack_data; + window_stack_data.Window = window; + window_stack_data.ParentLastItemDataBackup = g.LastItemData; + window_stack_data.StackSizesOnBegin.SetToContextState(&g); + g.CurrentWindowStack.push_back(window_stack_data); + if (flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount++; + + // Update ->RootWindow and others pointers (before any possible call to FocusWindow) + if (first_begin_of_the_frame) + { + UpdateWindowParentAndRootLinks(window, flags, parent_window); + window->ParentWindowInBeginStack = parent_window_in_stack; + } + + // Add to focus scope stack + PushFocusScope(window->ID); + window->NavRootFocusScopeId = g.CurrentFocusScopeId; g.CurrentWindow = NULL; - ErrorCheckBeginEndCompareStacksSize(window, true); + + // Add to popup stack if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; popup_ref.Window = window; + popup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent; g.BeginPopupStack.push_back(popup_ref); window->PopupId = popup_ref.PopupId; } - if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) - window->NavLastIds[0] = 0; - // Process SetNextWindow***() calls + // (FIXME: Consider splitting the HasXXX flags into X/Y components bool window_pos_set_by_api = false; bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) @@ -5350,6 +6250,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) + { + if (g.NextWindowData.ScrollVal.x >= 0.0f) + { + window->ScrollTarget.x = g.NextWindowData.ScrollVal.x; + window->ScrollTargetCenterRatio.x = 0.0f; + } + if (g.NextWindowData.ScrollVal.y >= 0.0f) + { + window->ScrollTarget.y = g.NextWindowData.ScrollVal.y; + window->ScrollTargetCenterRatio.y = 0.0f; + } + } if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; else if (first_begin_of_the_frame) @@ -5366,12 +6279,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { // Initialize const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) - UpdateWindowParentAndRootLinks(window, flags, parent_window); - + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); window->Active = true; window->HasCloseButton = (p_open != NULL); - window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); + window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); window->IDStack.resize(1); + window->DrawList->_ResetForNewFrame(); + window->DC.CurrentTableIdx = -1; // Restore buffer capacity when woken from a compacted state, to avoid if (window->MemoryCompacted) @@ -5380,7 +6294,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. bool window_title_visible_elsewhere = false; - if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB window_title_visible_elsewhere = true; if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) { @@ -5392,11 +6306,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // Update contents size from last frame for auto-fitting (or use explicit size) - window->ContentSize = CalcWindowContentSize(window); + CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal); if (window->HiddenFramesCanSkipItems > 0) window->HiddenFramesCanSkipItems--; if (window->HiddenFramesCannotSkipItems > 0) window->HiddenFramesCannotSkipItems--; + if (window->HiddenFramesForRenderOnly > 0) + window->HiddenFramesForRenderOnly--; // Hide new windows for one frame until they calculate their size if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) @@ -5413,11 +6329,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Size.x = window->SizeFull.x = 0.f; if (!window_size_y_set_by_api) window->Size.y = window->SizeFull.y = 0.f; - window->ContentSize = ImVec2(0.f, 0.f); + window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f); } } + // SELECT VIEWPORT // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style) + + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + SetWindowViewport(window, viewport); SetCurrentWindow(window); // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) @@ -5429,22 +6349,28 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->WindowPadding = style.WindowPadding; if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + + // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; + // Collapse window by double-clicking on title bar // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) { // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. ImRect title_bar_rect = window->TitleBarRect(); - if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]) + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2) window->WantCollapseToggle = true; if (window->WantCollapseToggle) { window->Collapsed = !window->Collapsed; + if (!window->Collapsed) + use_current_size_for_scrollbar_y = true; MarkIniSettingsDirty(window); - FocusWindow(window); } } else @@ -5455,10 +6381,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // SIZE + // Outer Decoration Sizes + // (we need to clear ScrollbarSize immediatly as CalcWindowAutoFitSize() needs it and can be called from other locations). + const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes; + window->DecoOuterSizeX1 = 0.0f; + window->DecoOuterSizeX2 = 0.0f; + window->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight(); + window->DecoOuterSizeY2 = 0.0f; + window->ScrollbarSizes = ImVec2(0.0f, 0.0f); + // Calculate auto-fit size, handle automatic resize - const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize); - bool use_current_size_for_scrollbar_x = window_just_created; - bool use_current_size_for_scrollbar_y = window_just_created; + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. @@ -5495,16 +6428,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; - // Decoration size - const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); - // POSITION // Popup latch its initial position, will position itself when it appears next frame if (window_just_activated_by_user) { window->AutoPosLastDirection = ImGuiDir_None; - if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) + if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos() window->Pos = g.BeginPopupStack.back().OpenPopupPos; } @@ -5520,7 +6450,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0); if (window_pos_with_pivot) - SetWindowPos(window, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) + SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) window->Pos = FindBestWindowPosForPopup(window); else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) @@ -5528,23 +6458,28 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = FindBestWindowPosForPopup(window); - // Clamp position/size so window stays visible within its viewport or monitor + // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) + // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. + ImRect viewport_rect(viewport->GetMainRect()); + ImRect viewport_work_rect(viewport->GetWorkRect()); + ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding); + // Clamp position/size so window stays visible within its viewport or monitor // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. - ImRect viewport_rect(GetViewportRect()); - if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - { - if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. - { - ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); - ClampWindowRect(window, viewport_rect, clamp_padding); - } - } + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow)) + if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f) + ClampWindowPos(window, visibility_rect); window->Pos = ImFloor(window->Pos); // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + // Large values tend to lead to variety of artifacts and are not recommended. window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. + //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); + // Apply window focus (new and reactivated windows are moved to front) bool want_focus = false; if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) @@ -5555,13 +6490,25 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) want_focus = true; } + // [Test Engine] Register whole window in the item system (before submitting further decorations) +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (g.TestEngineHookItems) + { + IM_ASSERT(window->IDStack.Size == 1); + window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. + IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL); + IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); + window->IDStack.Size = 1; + } +#endif + // Handle manual resize: Resize Grips, Borders, Gamepad int border_held = -1; ImU32 resize_grip_col[4] = {}; const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. - const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (!window->Collapsed) - if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0])) + if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; window->ResizeBorderHeld = (signed char)border_held; @@ -5571,9 +6518,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (!window->Collapsed) { // When reading the current size we need to read it after size constraints have been applied. - // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. - ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); - ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + // Intentionally use previous frame values for InnerRect and ScrollbarSizes. + // And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame; ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; @@ -5583,10 +6531,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (window->ScrollbarX && !window->ScrollbarY) window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + + // Amend the partially filled window->DecorationXXX values. + window->DecoOuterSizeX2 += window->ScrollbarSizes.x; + window->DecoOuterSizeY2 += window->ScrollbarSizes.y; } // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) - // Update various regions. Variables they depends on should be set above in this function. + // Update various regions. Variables they depend on should be set above in this function. // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. // Outer rectangle @@ -5603,13 +6555,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Inner rectangle // Not affected by window border size. Used by: // - InnerClipRect - // - ScrollToBringRectIntoView() + // - ScrollToRectEx() // - NavUpdatePageUpPageDown() // - Scrollbar() - window->InnerRect.Min.x = window->Pos.x; - window->InnerRect.Min.y = window->Pos.y + decoration_up_height; - window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; - window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; + window->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1; + window->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2; // Inner clipping rectangle. // Will extend a little bit outside the normal work region. @@ -5640,66 +6592,43 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); // Apply scrolling - window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + window->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f; // DRAWING // Setup draw list and outer clipping rectangle - window->DrawList->Clear(); + IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); PushClipRect(host_rect.Min, host_rect.Max, false); - // Draw modal window background (darkens what is behind them, all viewports) - const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; - const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); - if (dim_bg_for_modal || dim_bg_for_window_list) - { - const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); - window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); - } - - // Draw navigation selection/windowing rectangle background - if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) - { - ImRect bb = window->Rect(); - bb.Expand(g.FontSize); - if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); - } - - // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call. + // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. - // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child. - // We also disabled this when we have dimming overlay behind this specific one child. - // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected. - bool render_decorations_in_parent = false; - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) - if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0) - render_decorations_in_parent = true; - if (render_decorations_in_parent) - window->DrawList = parent_window->DrawList; - - // Handle title bar, scrollbar, resize grips and resize borders - const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; - const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); - RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); - - if (render_decorations_in_parent) - window->DrawList = &window->DrawListInst; - - // Draw navigation selection/windowing rectangle border - if (g.NavWindowingTargetAnim == window) - { - float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); - ImRect bb = window->Rect(); - bb.Expand(g.FontSize); - if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward + // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493) + { + bool render_decorations_in_parent = false; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) { - bb.Expand(-g.FontSize - 1.0f); - rounding = window->WindowRounding; + // - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here) + // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs + ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL; + bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false; + bool parent_is_empty = (parent_window->DrawList->VtxBuffer.Size == 0); + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && !parent_is_empty && !previous_child_overlapping) + render_decorations_in_parent = true; } - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + if (render_decorations_in_parent) + window->DrawList = parent_window->DrawList; + + // Handle title bar, scrollbar, resize grips and resize borders + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); + const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch. + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); + + if (render_decorations_in_parent) + window->DrawList = &window->DrawListInst; } // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) @@ -5711,68 +6640,64 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - BeginTabBar() for right-most edge const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); - const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? - window->ContentSizeExplicit.x : - ImMax(allow_scrollbar_x ? - window->ContentSize.x : - 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); - const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? - window->ContentSizeExplicit.y : - ImMax(allow_scrollbar_y ? - window->ContentSize.y : - 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; + window->ParentWorkRect = window->WorkRect; // [LEGACY] Content Region // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. // Used by: // - Mouse wheel scrolling + many other things - window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; - window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; - window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); - window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) - window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x; window->DC.GroupOffset.x = 0.0f; window->DC.ColumnsOffset.x = 0.0f; - window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y); + + // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount. + // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64. + double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x; + double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1; + window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y); + window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y)); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorStartPos; + window->DC.IdealMaxPos = window->DC.CursorStartPos; window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.IsSameLine = window->DC.IsSetPos = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; + window->DC.NavLayersActiveMaskNext = 0x00; + window->DC.NavIsScrollPushableX = true; window->DC.NavHideHighlightOneFrame = false; - window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); - window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; - window->DC.NavLayerActiveMaskNext = 0x00; + window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f); + window->DC.MenuBarAppending = false; + window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); + window->DC.TreeDepth = 0; + window->DC.TreeJumpToParentOnPopMask = 0x00; window->DC.ChildWindows.resize(0); + window->DC.StateStorage = &window->StateStorage; + window->DC.CurrentColumns = NULL; window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; - window->DC.FocusCounterAll = window->DC.FocusCounterTab = -1; - window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; + window->DC.ItemWidth = window->ItemWidthDefault; window->DC.TextWrapPos = -1.0f; // disabled - window->DC.ItemFlagsStack.resize(0); window->DC.ItemWidthStack.resize(0); window->DC.TextWrapPosStack.resize(0); - window->DC.CurrentColumns = NULL; - window->DC.TreeDepth = 0; - window->DC.TreeMayJumpToParentOnPopMask = 0x00; - window->DC.StateStorage = &window->StateStorage; - window->DC.GroupStack.resize(0); - window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); - - if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags)) - { - window->DC.ItemFlags = parent_window->DC.ItemFlags; - window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); - } if (window->AutoFitFramesX > 0) window->AutoFitFramesX--; @@ -5780,33 +6705,45 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->AutoFitFramesY--; // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + // We ImGuiFocusRequestFlags_UnlessBelowModal to: + // - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed. + // - Position window behind the modal that is not a begin-parent of this window. if (want_focus) - { - FocusWindow(window); - NavInitWindow(window, false); - } + FocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal); + if (want_focus && window == g.NavWindow) + NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - RenderWindowTitleBarContents(window, title_bar_rect, name, p_open); + RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); + + // Clear hit test shape every frame + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; // Pressing CTRL+C while holding on a window copy its content to the clipboard // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. // Maybe we can support CTRL+C on every element? /* - if (g.ActiveId == move_id) - if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + //if (g.NavWindow == window && g.ActiveId == 0) + if (g.ActiveId == window->MoveId) + if (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C)) LogToClipboard(); */ // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. - window->DC.LastItemId = window->MoveId; - window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; - window->DC.LastItemRect = title_bar_rect; + SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); + + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (g.DebugLocateId != 0 && (window->ID == g.DebugLocateId || window->MoveId == g.DebugLocateId)) + DebugLocateItemResolveWithLastItem(); +#endif + + // [Test Engine] Register title bar / tab with MoveId. #ifdef IMGUI_ENABLE_TEST_ENGINE if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId); + IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData); #endif } else @@ -5818,43 +6755,66 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) - if (first_begin_of_the_frame) - window->WriteAccessed = false; - + window->WriteAccessed = false; window->BeginCount++; g.NextWindowData.ClearFlags(); - if (flags & ImGuiWindowFlags_ChildWindow) + // Update visibility + if (first_begin_of_the_frame) { - // Child window can be out of sight and have "negative" clip windows. - // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). - IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); - if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow?? + { + const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (!g.LogEnabled && !nav_request) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; + } + + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; + } - // Hide along with parent or if parent is collapsed - if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) window->HiddenFramesCanSkipItems = 1; - if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) - window->HiddenFramesCannotSkipItems = 1; - } - // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) - if (style.Alpha <= 0.0f) - window->HiddenFramesCanSkipItems = 1; + // Update the Hidden flag + bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0); + + // Disable inputs for requested number of frames + if (window->DisableInputsFrames > 0) + { + window->DisableInputsFrames--; + window->Flags |= ImGuiWindowFlags_NoInputs; + } - // Update the Hidden flag - window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + // Update the SkipItems flag, used to early out of all items functions (no layout required) + bool skip_items = false; + if (window->Collapsed || !window->Active || hidden_regular) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; + } - // Update the SkipItems flag, used to early out of all items functions (no layout required) - bool skip_items = false; - if (window->Collapsed || !window->Active || window->Hidden) - if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) - skip_items = true; - window->SkipItems = skip_items; + // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. + // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) + if (!window->IsFallbackWindow && ((g.IO.ConfigDebugBeginReturnValueOnce && window_just_created) || (g.IO.ConfigDebugBeginReturnValueLoop && g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size))) + { + if (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; } + if (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; } + return false; + } - return !skip_items; + return !window->SkipItems; } void ImGui::End() @@ -5878,38 +6838,52 @@ void ImGui::End() if (window->DC.CurrentColumns) EndColumns(); PopClipRect(); // Inner window clip rectangle + PopFocusScope(); // Stop logging if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging LogFinish(); + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + // Pop from window stack - g.CurrentWindowStack.pop_back(); + g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount--; if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - ErrorCheckBeginEndCompareStacksSize(window, false); - SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); + g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g); + g.CurrentWindowStack.pop_back(); + SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); } void ImGui::BringWindowToFocusFront(ImGuiWindow* window) { ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); if (g.WindowsFocusOrder.back() == window) return; - for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window - if (g.WindowsFocusOrder[i] == window) - { - memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); - g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; - break; - } + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; } void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) { ImGuiContext& g = *GImGui; ImGuiWindow* current_front_window = g.Windows.back(); - if (current_front_window == window || current_front_window->RootWindow == window) + if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) return; for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window if (g.Windows[i] == window) @@ -5934,210 +6908,218 @@ void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) } } +void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) +{ + IM_ASSERT(window != NULL && behind_window != NULL); + ImGuiContext& g = *GImGui; + window = window->RootWindow; + behind_window = behind_window->RootWindow; + int pos_wnd = FindWindowDisplayIndex(window); + int pos_beh = FindWindowDisplayIndex(behind_window); + if (pos_wnd < pos_beh) + { + size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); + g.Windows[pos_beh - 1] = window; + } + else + { + size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); + g.Windows[pos_beh] = window; + } +} + +int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return g.Windows.index_from_ptr(g.Windows.find(window)); +} + // Moving window to front of display and set focus (which happens to be back of our sorted list) -void ImGui::FocusWindow(ImGuiWindow* window) +void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) { ImGuiContext& g = *GImGui; + // Modal check? + if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. + if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal. + return; + } + + // Find last focused child (if any) and focus it instead. + if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) + window = NavRestoreLastChildNavWindow(window); + + // Apply focus if (g.NavWindow != window) { - g.NavWindow = window; + SetNavWindow(window); if (window && g.NavDisableMouseHover) g.NavMousePosDirty = true; - g.NavInitRequest = false; g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId - g.NavIdIsAlive = false; g.NavLayer = ImGuiNavLayer_Main; - //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); + g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0; + g.NavIdIsAlive = false; + + // Close popups if any + ClosePopupsOverWindow(window, false); } - // Close popups if any - ClosePopupsOverWindow(window, false); + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss) + ClearActiveID(); // Passing NULL allow to disable keyboard focus if (!window) return; - // Move the root window to the top of the pile - if (window->RootWindow) - window = window->RootWindow; - - // Steal focus on active widgets - if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. - if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) - ClearActiveID(); - // Bring to front - BringWindowToFocusFront(window); - if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) - BringWindowToDisplayFront(window); + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); } -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) { ImGuiContext& g = *GImGui; - + IM_UNUSED(filter_viewport); // Unused in master branch. int start_idx = g.WindowsFocusOrder.Size - 1; if (under_this_window != NULL) { - int under_this_window_idx = FindWindowFocusIndex(under_this_window); - if (under_this_window_idx != -1) - start_idx = under_this_window_idx - 1; + // Aim at root window behind us, if we are in a child window that's our own root (see #4640) + int offset = -1; + while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) + { + under_this_window = under_this_window->ParentWindow; + offset = 0; + } + start_idx = FindWindowFocusIndex(under_this_window) + offset; } for (int i = start_idx; i >= 0; i--) { // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. ImGuiWindow* window = g.WindowsFocusOrder[i]; - if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) - if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) - { - ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); - FocusWindow(focus_window); - return; - } + IM_ASSERT(window == window->RootWindow); + if (window == ignore_window || !window->WasActive) + continue; + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + FocusWindow(window, flags); + return; + } } - FocusWindow(NULL); + FocusWindow(NULL, flags); } -void ImGui::SetNextItemWidth(float item_width) +// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. +void ImGui::SetCurrentFont(ImFont* font) { ImGuiContext& g = *GImGui; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; - g.NextItemData.Width = item_width; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.TexUvLines = atlas->TexUvLines; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; } -void ImGui::PushItemWidth(float item_width) +void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); - window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); - g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; + if (!font) + font = GetDefaultFont(); + SetCurrentFont(font); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); } -void ImGui::PushMultiItemsWidths(int components, float w_full) +void ImGui::PopFont() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - const ImGuiStyle& style = g.Style; - const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); - const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); - window->DC.ItemWidthStack.push_back(w_item_last); - for (int i = 0; i < components-1; i++) - window->DC.ItemWidthStack.push_back(w_item_one); - window->DC.ItemWidth = window->DC.ItemWidthStack.back(); - g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; + g.CurrentWindow->DrawList->PopTextureID(); + g.FontStack.pop_back(); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); } -void ImGui::PopItemWidth() +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.ItemWidthStack.pop_back(); - window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); + ImGuiContext& g = *GImGui; + ImGuiItemFlags item_flags = g.CurrentItemFlags; + IM_ASSERT(item_flags == g.ItemFlagsStack.back()); + if (enabled) + item_flags |= option; + else + item_flags &= ~option; + g.CurrentItemFlags = item_flags; + g.ItemFlagsStack.push_back(item_flags); } -// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). -// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() -float ImGui::CalcItemWidth() +void ImGui::PopItemFlag() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - float w; - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) - w = g.NextItemData.Width; - else - w = window->DC.ItemWidth; - if (w < 0.0f) + IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); +} + +// BeginDisabled()/EndDisabled() +// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) +// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently. +// - Feedback welcome at https://github.com/ocornut/imgui/issues/211 +// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. +// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag() +void ImGui::BeginDisabled(bool disabled) +{ + ImGuiContext& g = *GImGui; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (!was_disabled && disabled) { - float region_max_x = GetContentRegionMaxAbs().x; - w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + g.DisabledAlphaBackup = g.Style.Alpha; + g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha); } - w = IM_FLOOR(w); - return w; + if (was_disabled || disabled) + g.CurrentItemFlags |= ImGuiItemFlags_Disabled; + g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.DisabledStackSize++; } -// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). -// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. -// Note that only CalcItemWidth() is publicly exposed. -// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) -ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +void ImGui::EndDisabled() { - ImGuiWindow* window = GImGui->CurrentWindow; - - ImVec2 region_max; - if (size.x < 0.0f || size.y < 0.0f) - region_max = GetContentRegionMaxAbs(); + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DisabledStackSize > 0); + g.DisabledStackSize--; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + //PopItemFlag(); + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); + if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); +} - if (size.x == 0.0f) - size.x = default_w; - else if (size.x < 0.0f) - size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); - - if (size.y == 0.0f) - size.y = default_h; - else if (size.y < 0.0f) - size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); - - return size; -} - -void ImGui::SetCurrentFont(ImFont* font) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? - IM_ASSERT(font->Scale > 0.0f); - g.Font = font; - g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); - g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; - - ImFontAtlas* atlas = g.Font->ContainerAtlas; - g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; - g.DrawListSharedData.Font = g.Font; - g.DrawListSharedData.FontSize = g.FontSize; -} - -void ImGui::PushFont(ImFont* font) -{ - ImGuiContext& g = *GImGui; - if (!font) - font = GetDefaultFont(); - SetCurrentFont(font); - g.FontStack.push_back(font); - g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); -} - -void ImGui::PopFont() -{ - ImGuiContext& g = *GImGui; - g.CurrentWindow->DrawList->PopTextureID(); - g.FontStack.pop_back(); - SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); -} - -void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (enabled) - window->DC.ItemFlags |= option; - else - window->DC.ItemFlags &= ~option; - window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); -} - -void ImGui::PopItemFlag() -{ - ImGuiWindow* window = GetCurrentWindow(); - window->DC.ItemFlagsStack.pop_back(); - window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); -} - -// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. -void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +void ImGui::PushTabStop(bool tab_stop) { - PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); + PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } -void ImGui::PopAllowKeyboardFocus() +void ImGui::PopTabStop() { PopItemFlag(); } @@ -6155,244 +7137,108 @@ void ImGui::PopButtonRepeat() void ImGui::PushTextWrapPos(float wrap_pos_x) { ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos); window->DC.TextWrapPos = wrap_pos_x; - window->DC.TextWrapPosStack.push_back(wrap_pos_x); } void ImGui::PopTextWrapPos() { ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); window->DC.TextWrapPosStack.pop_back(); - window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); -} - -// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 -void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) -{ - ImGuiContext& g = *GImGui; - ImGuiColorMod backup; - backup.Col = idx; - backup.BackupValue = g.Style.Colors[idx]; - g.ColorModifiers.push_back(backup); - g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); -} - -void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) -{ - ImGuiContext& g = *GImGui; - ImGuiColorMod backup; - backup.Col = idx; - backup.BackupValue = g.Style.Colors[idx]; - g.ColorModifiers.push_back(backup); - g.Style.Colors[idx] = col; } -void ImGui::PopStyleColor(int count) +static ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy) { - ImGuiContext& g = *GImGui; - while (count > 0) + ImGuiWindow* last_window = NULL; + while (last_window != window) { - ImGuiColorMod& backup = g.ColorModifiers.back(); - g.Style.Colors[backup.Col] = backup.BackupValue; - g.ColorModifiers.pop_back(); - count--; + last_window = window; + window = window->RootWindow; + if (popup_hierarchy) + window = window->RootWindowPopupTree; } + return window; } -struct ImGuiStyleVarInfo -{ - ImGuiDataType Type; - ImU32 Count; - ImU32 Offset; - void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } -}; - -static const ImGuiStyleVarInfo GStyleVarInfo[] = -{ - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign -}; - -static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) -{ - IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); - IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); - return &GStyleVarInfo[idx]; -} - -void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy) { - const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + ImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy); + if (window_root == potential_parent) + return true; + while (window != NULL) { - ImGuiContext& g = *GImGui; - float* pvar = (float*)var_info->GetVarPtr(&g.Style); - g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; - return; + if (window == potential_parent) + return true; + if (window == window_root) // end of chain + return false; + window = window->ParentWindow; } - IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); + return false; } -void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +bool ImGui::IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent) { - const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) { - ImGuiContext& g = *GImGui; - ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; - return; + if (window == potential_parent) + return true; + window = window->ParentWindowInBeginStack; } - IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); + return false; } -void ImGui::PopStyleVar(int count) +bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below) { ImGuiContext& g = *GImGui; - while (count > 0) - { - // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. - ImGuiStyleMod& backup = g.StyleModifiers.back(); - const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); - void* data = info->GetVarPtr(&g.Style); - if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } - else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } - g.StyleModifiers.pop_back(); - count--; - } -} -const char* ImGui::GetStyleColorName(ImGuiCol idx) -{ - // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; - switch (idx) - { - case ImGuiCol_Text: return "Text"; - case ImGuiCol_TextDisabled: return "TextDisabled"; - case ImGuiCol_WindowBg: return "WindowBg"; - case ImGuiCol_ChildBg: return "ChildBg"; - case ImGuiCol_PopupBg: return "PopupBg"; - case ImGuiCol_Border: return "Border"; - case ImGuiCol_BorderShadow: return "BorderShadow"; - case ImGuiCol_FrameBg: return "FrameBg"; - case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; - case ImGuiCol_FrameBgActive: return "FrameBgActive"; - case ImGuiCol_TitleBg: return "TitleBg"; - case ImGuiCol_TitleBgActive: return "TitleBgActive"; - case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; - case ImGuiCol_MenuBarBg: return "MenuBarBg"; - case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; - case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; - case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; - case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; - case ImGuiCol_CheckMark: return "CheckMark"; - case ImGuiCol_SliderGrab: return "SliderGrab"; - case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; - case ImGuiCol_Button: return "Button"; - case ImGuiCol_ButtonHovered: return "ButtonHovered"; - case ImGuiCol_ButtonActive: return "ButtonActive"; - case ImGuiCol_Header: return "Header"; - case ImGuiCol_HeaderHovered: return "HeaderHovered"; - case ImGuiCol_HeaderActive: return "HeaderActive"; - case ImGuiCol_Separator: return "Separator"; - case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; - case ImGuiCol_SeparatorActive: return "SeparatorActive"; - case ImGuiCol_ResizeGrip: return "ResizeGrip"; - case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; - case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; - case ImGuiCol_Tab: return "Tab"; - case ImGuiCol_TabHovered: return "TabHovered"; - case ImGuiCol_TabActive: return "TabActive"; - case ImGuiCol_TabUnfocused: return "TabUnfocused"; - case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; - case ImGuiCol_PlotLines: return "PlotLines"; - case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; - case ImGuiCol_PlotHistogram: return "PlotHistogram"; - case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; - case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; - case ImGuiCol_DragDropTarget: return "DragDropTarget"; - case ImGuiCol_NavHighlight: return "NavHighlight"; - case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; - case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; - case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; - } - IM_ASSERT(0); - return "Unknown"; -} + // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array + const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below); + if (display_layer_delta != 0) + return display_layer_delta > 0; -bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) -{ - if (window->RootWindow == potential_parent) - return true; - while (window != NULL) + for (int i = g.Windows.Size - 1; i >= 0; i--) { - if (window == potential_parent) + ImGuiWindow* candidate_window = g.Windows[i]; + if (candidate_window == potential_above) return true; - window = window->ParentWindow; + if (candidate_window == potential_below) + return false; } return false; } bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { - IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function + IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled)) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.HoveredWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + if (ref_window == NULL) + return false; - if (flags & ImGuiHoveredFlags_AnyWindow) + if ((flags & ImGuiHoveredFlags_AnyWindow) == 0) { - if (g.HoveredWindow == NULL) + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + bool result; + if (flags & ImGuiHoveredFlags_ChildWindows) + result = IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + result = (ref_window == cur_window); + if (!result) return false; } - else - { - switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) - { - case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: - if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) - return false; - break; - case ImGuiHoveredFlags_RootWindow: - if (g.HoveredWindow != g.CurrentWindow->RootWindow) - return false; - break; - case ImGuiHoveredFlags_ChildWindows: - if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) - return false; - break; - default: - if (g.HoveredWindow != g.CurrentWindow) - return false; - break; - } - } - if (!IsWindowContentHoverable(g.HoveredWindow, flags)) + if (!IsWindowContentHoverable(ref_window, flags)) return false; if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) - if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId) return false; return true; } @@ -6400,30 +7246,31 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) { ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.NavWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + if (ref_window == NULL) + return false; if (flags & ImGuiFocusedFlags_AnyWindow) - return g.NavWindow != NULL; + return true; - IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() - switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) - { - case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: - return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; - case ImGuiFocusedFlags_RootWindow: - return g.NavWindow == g.CurrentWindow->RootWindow; - case ImGuiFocusedFlags_ChildWindows: - return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); - default: - return g.NavWindow == g.CurrentWindow; - } + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + if (flags & ImGuiHoveredFlags_ChildWindows) + return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + return (ref_window == cur_window); } // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) -// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmaticaly. +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. // If you want a window to never be focused, you may use the e.g. NoInputs flag. bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) { - return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); + return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); } float ImGui::GetWindowWidth() @@ -6459,8 +7306,12 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) const ImVec2 old_pos = window->Pos; window->Pos = ImFloor(pos); ImVec2 offset = window->Pos - old_pos; + if (offset.x == 0.0f && offset.y == 0.0f) + return; + MarkIniSettingsDirty(window); window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.IdealMaxPos += offset; window->DC.CursorStartPos += offset; } @@ -6492,26 +7343,19 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); // Set - if (size.x > 0.0f) - { - window->AutoFitFramesX = 0; - window->SizeFull.x = IM_FLOOR(size.x); - } - else - { - window->AutoFitFramesX = 2; + ImVec2 old_size = window->SizeFull; + window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0; + window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0; + if (size.x <= 0.0f) window->AutoFitOnlyGrows = false; - } - if (size.y > 0.0f) - { - window->AutoFitFramesY = 0; - window->SizeFull.y = IM_FLOOR(size.y); - } else - { - window->AutoFitFramesY = 2; + window->SizeFull.x = IM_FLOOR(size.x); + if (size.y <= 0.0f) window->AutoFitOnlyGrows = false; - } + else + window->SizeFull.y = IM_FLOOR(size.y); + if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) + MarkIniSettingsDirty(window); } void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) @@ -6536,6 +7380,19 @@ void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond co window->Collapsed = collapsed; } +void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters + window->HitTestHoleSize = ImVec2ih(size); + window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); +} + +void ImGui::SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window) +{ + window->Hidden = window->SkipItems = true; + window->HiddenFramesCanSkipItems = 1; +} + void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) { SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); @@ -6611,7 +7468,14 @@ void ImGui::SetNextWindowContentSize(const ImVec2& size) { ImGuiContext& g = *GImGui; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; - g.NextWindowData.ContentSizeVal = size; + g.NextWindowData.ContentSizeVal = ImFloor(size); +} + +void ImGui::SetNextWindowScroll(const ImVec2& scroll) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; + g.NextWindowData.ScrollVal = scroll; } void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) @@ -6636,82 +7500,6 @@ void ImGui::SetNextWindowBgAlpha(float alpha) g.NextWindowData.BgAlphaVal = alpha; } -// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions. -ImVec2 ImGui::GetContentRegionMax() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = window->ContentRegionRect.Max - window->Pos; - if (window->DC.CurrentColumns) - mx.x = window->WorkRect.Max.x - window->Pos.x; - return mx; -} - -// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. -ImVec2 ImGui::GetContentRegionMaxAbs() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = window->ContentRegionRect.Max; - if (window->DC.CurrentColumns) - mx.x = window->WorkRect.Max.x; - return mx; -} - -ImVec2 ImGui::GetContentRegionAvail() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return GetContentRegionMaxAbs() - window->DC.CursorPos; -} - -// In window space (not screen space!) -ImVec2 ImGui::GetWindowContentRegionMin() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentRegionRect.Min - window->Pos; -} - -ImVec2 ImGui::GetWindowContentRegionMax() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentRegionRect.Max - window->Pos; -} - -float ImGui::GetWindowContentRegionWidth() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentRegionRect.GetWidth(); -} -float ImGui::GetWindowContentRegionHeight() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentRegionRect.GetHeight(); -} - -float ImGui::GetTextLineHeight() -{ - ImGuiContext& g = *GImGui; - return g.FontSize; -} - -float ImGui::GetTextLineHeightWithSpacing() -{ - ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.ItemSpacing.y; -} - -float ImGui::GetFrameHeight() -{ - ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.FramePadding.y * 2.0f; -} - -float ImGui::GetFrameHeightWithSpacing() -{ - ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; -} - ImDrawList* ImGui::GetWindowDrawList() { ImGuiWindow* window = GetCurrentWindow(); @@ -6735,86 +7523,66 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() void ImGui::SetWindowFontScale(float scale) { + IM_ASSERT(scale > 0.0f); ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); } -// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. -// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. -ImVec2 ImGui::GetCursorPos() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CursorPos - window->Pos + window->Scroll; -} - -float ImGui::GetCursorPosX() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; -} - -float ImGui::GetCursorPosY() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; -} - -void ImGui::SetCursorPos(const ImVec2& local_pos) -{ - ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos = window->Pos - window->Scroll + local_pos; - window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); -} - -void ImGui::SetCursorPosX(float x) -{ - ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; - window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); -} - -void ImGui::SetCursorPosY(float y) -{ - ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; - window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); -} - -ImVec2 ImGui::GetCursorStartPos() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CursorStartPos - window->Pos; -} - -ImVec2 ImGui::GetCursorScreenPos() +void ImGui::ActivateItem(ImGuiID id) { - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CursorPos; + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; + g.NavNextActivateFlags = ImGuiActivateFlags_None; } -void ImGui::SetCursorScreenPos(const ImVec2& pos) +void ImGui::PushFocusScope(ImGuiID id) { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos = pos; - window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); + ImGuiContext& g = *GImGui; + g.FocusScopeStack.push_back(id); + g.CurrentFocusScopeId = id; } -void ImGui::ActivateItem(ImGuiID id) +void ImGui::PopFocusScope() { ImGuiContext& g = *GImGui; - g.NavNextActivateId = id; + IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ? + g.FocusScopeStack.pop_back(); + g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back() : 0; } +// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system! void ImGui::SetKeyboardFocusHere(int offset) { - IM_ASSERT(offset >= -1); // -1 is allowed but not below ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - g.FocusRequestNextWindow = window; - g.FocusRequestNextCounterAll = window->DC.FocusCounterAll + 1 + offset; - g.FocusRequestNextCounterTab = INT_MAX; + IM_ASSERT(offset >= -1); // -1 is allowed but not below + IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name); + + // It makes sense in the vast majority of cases to never interrupt a drag and drop. + // When we refactor this function into ActivateItem() we may want to make this an option. + // MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but + // is also automatically dropped in the event g.ActiveId is stolen. + if (g.DragDropActive || g.MovingWindow != NULL) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere() ignored while DragDropActive!\n"); + return; + } + + SetNavWindow(window); + + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + if (offset == -1) + { + NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); + } + else + { + g.NavTabbingDir = 1; + g.NavTabbingCounter = offset + 1; + } } void ImGui::SetItemDefaultFocus() @@ -6823,15 +7591,16 @@ void ImGui::SetItemDefaultFocus() ImGuiWindow* window = g.CurrentWindow; if (!window->Appearing) return; - if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) - { - g.NavInitRequest = false; - g.NavInitResultId = g.NavWindow->DC.LastItemId; - g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); - NavUpdateAnyRequestFlag(); - if (!IsItemVisible()) - SetScrollHereY(); - } + if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResult.ID == 0) || g.NavLayer != window->DC.NavLayerCurrent) + return; + + g.NavInitRequest = false; + NavApplyItemToResult(&g.NavInitResult); + NavUpdateAnyRequestFlag(); + + // Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll) + if (!window->ClipRect.Contains(g.LastItemData.Rect)) + ScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags_None); } void ImGui::SetStateStorage(ImGuiStorage* tree) @@ -6848,38 +7617,71 @@ ImGuiStorage* ImGui::GetStateStorage() void ImGui::PushID(const char* str_id) { - ImGuiWindow* window = GImGui->CurrentWindow; - window->IDStack.push_back(window->GetIDNoKeepAlive(str_id)); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(str_id); + window->IDStack.push_back(id); } void ImGui::PushID(const char* str_id_begin, const char* str_id_end) { - ImGuiWindow* window = GImGui->CurrentWindow; - window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end)); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(str_id_begin, str_id_end); + window->IDStack.push_back(id); } void ImGui::PushID(const void* ptr_id) { - ImGuiWindow* window = GImGui->CurrentWindow; - window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(ptr_id); + window->IDStack.push_back(id); } void ImGui::PushID(int int_id) { - ImGuiWindow* window = GImGui->CurrentWindow; - window->IDStack.push_back(window->GetIDNoKeepAlive(int_id)); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(int_id); + window->IDStack.push_back(id); } // Push a given id value ignoring the ID stack as a seed. void ImGui::PushOverrideID(ImGuiID id) { - ImGuiWindow* window = GImGui->CurrentWindow; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL); window->IDStack.push_back(id); } +// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call +// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level. +// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more) +ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) +{ + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) +{ + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? window->IDStack.pop_back(); } @@ -6913,3183 +7715,7077 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); } -// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) -void ImGui::BeginGroup() + +//----------------------------------------------------------------------------- +// [SECTION] INPUTS +//----------------------------------------------------------------------------- +// - GetKeyData() [Internal] +// - GetKeyIndex() [Internal] +// - GetKeyName() +// - GetKeyChordName() [Internal] +// - CalcTypematicRepeatAmount() [Internal] +// - GetTypematicRepeatRate() [Internal] +// - GetKeyPressedAmount() [Internal] +// - GetKeyMagnitude2d() [Internal] +//----------------------------------------------------------------------------- +// - UpdateKeyRoutingTable() [Internal] +// - GetRoutingIdFromOwnerId() [Internal] +// - GetShortcutRoutingData() [Internal] +// - CalcRoutingScore() [Internal] +// - SetShortcutRouting() [Internal] +// - TestShortcutRouting() [Internal] +//----------------------------------------------------------------------------- +// - IsKeyDown() +// - IsKeyPressed() +// - IsKeyReleased() +//----------------------------------------------------------------------------- +// - IsMouseDown() +// - IsMouseClicked() +// - IsMouseReleased() +// - IsMouseDoubleClicked() +// - GetMouseClickedCount() +// - IsMouseHoveringRect() [Internal] +// - IsMouseDragPastThreshold() [Internal] +// - IsMouseDragging() +// - GetMousePos() +// - GetMousePosOnOpeningCurrentPopup() +// - IsMousePosValid() +// - IsAnyMouseDown() +// - GetMouseDragDelta() +// - ResetMouseDragDelta() +// - GetMouseCursor() +// - SetMouseCursor() +//----------------------------------------------------------------------------- +// - UpdateAliasKey() +// - GetMergedModsFromKeys() +// - UpdateKeyboardInputs() +// - UpdateMouseInputs() +//----------------------------------------------------------------------------- +// - LockWheelingWindow [Internal] +// - FindBestWheelingWindow [Internal] +// - UpdateMouseWheel() [Internal] +//----------------------------------------------------------------------------- +// - SetNextFrameWantCaptureKeyboard() +// - SetNextFrameWantCaptureMouse() +//----------------------------------------------------------------------------- +// - GetInputSourceName() [Internal] +// - DebugPrintInputEvent() [Internal] +// - UpdateInputEvents() [Internal] +//----------------------------------------------------------------------------- +// - GetKeyOwner() [Internal] +// - TestKeyOwner() [Internal] +// - SetKeyOwner() [Internal] +// - SetItemKeyOwner() [Internal] +// - Shortcut() [Internal] +//----------------------------------------------------------------------------- + +ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext& g = *ctx; - window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); - ImGuiGroupData& group_data = window->DC.GroupStack.back(); - group_data.BackupCursorPos = window->DC.CursorPos; - group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; - group_data.BackupIndent = window->DC.Indent; - group_data.BackupGroupOffset = window->DC.GroupOffset; - group_data.BackupCurrLineSize = window->DC.CurrLineSize; - group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; - group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; - group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; - group_data.EmitItem = true; + // Special storage location for mods + if (key & ImGuiMod_Mask_) + key = ConvertSingleModFlagToKey(ctx, key); - window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; - window->DC.Indent = window->DC.GroupOffset; - window->DC.CursorMaxPos = window->DC.CursorPos; - window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); - if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); + if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1) + key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native +#else + IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); +#endif + return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; } -void ImGui::EndGroup() +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +ImGuiKey ImGui::GetKeyIndex(ImGuiKey key) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls - - ImGuiGroupData& group_data = window->DC.GroupStack.back(); - - ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + IM_ASSERT(IsNamedKey(key)); + const ImGuiKeyData* key_data = GetKeyData(key); + return (ImGuiKey)(key_data - g.IO.KeysData); +} +#endif - window->DC.CursorPos = group_data.BackupCursorPos; - window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); - window->DC.Indent = group_data.BackupIndent; - window->DC.GroupOffset = group_data.BackupGroupOffset; - window->DC.CurrLineSize = group_data.BackupCurrLineSize; - window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; - if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return +// Those names a provided for debugging purpose and are not meant to be saved persistently not compared. +static const char* const GKeyNames[] = +{ + "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown", + "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape", + "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", + "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket", + "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen", + "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", + "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", + "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", + "GamepadStart", "GamepadBack", + "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", + "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", + "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3", + "GamepadLStickLeft", "GamepadLStickRight", "GamepadLStickUp", "GamepadLStickDown", + "GamepadRStickLeft", "GamepadRStickRight", "GamepadRStickUp", "GamepadRStickDown", + "MouseLeft", "MouseRight", "MouseMiddle", "MouseX1", "MouseX2", "MouseWheelX", "MouseWheelY", + "ModCtrl", "ModShift", "ModAlt", "ModSuper", // ReservedForModXXX are showing the ModXXX names. +}; +IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames)); - if (!group_data.EmitItem) +const char* ImGui::GetKeyName(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); +#else + if (IsLegacyKey(key)) { - window->DC.GroupStack.pop_back(); - return; + if (g.IO.KeyMap[key] == -1) + return "N/A"; + IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); + key = (ImGuiKey)g.IO.KeyMap[key]; } +#endif + if (key == ImGuiKey_None) + return "None"; + if (key & ImGuiMod_Mask_) + key = ConvertSingleModFlagToKey(&g, key); + if (!IsNamedKey(key)) + return "Unknown"; - window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. - ItemSize(group_bb.GetSize()); - ItemAdd(group_bb, 0); + return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; +} - // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. - // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. - // Also if you grep for LastItemId you'll notice it is only used in that context. - // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) - const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; - const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive; - if (group_contains_curr_active_id) - window->DC.LastItemId = g.ActiveId; - else if (group_contains_prev_active_id) - window->DC.LastItemId = g.ActiveIdPreviousFrame; - window->DC.LastItemRect = group_bb; - - // Forward Edited flag - if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; - - // Forward Deactivated flag - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; - if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; - - window->DC.GroupStack.pop_back(); - //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +// ImGuiMod_Shortcut is translated to either Ctrl or Super. +void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size) +{ + ImGuiContext& g = *GImGui; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s", + (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", + (key_chord & ImGuiMod_Shift) ? "Shift+" : "", + (key_chord & ImGuiMod_Alt) ? "Alt+" : "", + (key_chord & ImGuiMod_Super) ? (g.IO.ConfigMacOSXBehaviors ? "Cmd+" : "Super+") : "", + GetKeyName((ImGuiKey)(key_chord & ~ImGuiMod_Mask_))); } -// Gets back to previous line and continue with horizontal layout -// offset_from_start_x == 0 : follow right after previous item -// offset_from_start_x != 0 : align to specified x position (relative to window/group left) -// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 -// spacing_w >= 0 : enforce spacing amount -void ImGui::SameLine(float offset_from_start_x, float spacing_w) +// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) +// t1 = current time (e.g.: g.Time) +// An event is triggered at: +// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N +int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) { - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return; + if (t1 == 0.0f) + return 1; + if (t0 >= t1) + return 0; + if (repeat_rate <= 0.0f) + return (t0 < repeat_delay) && (t1 >= repeat_delay); + const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); + const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); + const int count = count_t1 - count_t0; + return count; +} +void ImGui::GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate) +{ ImGuiContext& g = *GImGui; - if (offset_from_start_x != 0.0f) - { - if (spacing_w < 0.0f) spacing_w = 0.0f; - window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; - window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; - } - else + switch (flags & ImGuiInputFlags_RepeatRateMask_) { - if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; - window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; - window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + case ImGuiInputFlags_RepeatRateNavMove: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.80f; return; + case ImGuiInputFlags_RepeatRateNavTweak: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.30f; return; + case ImGuiInputFlags_RepeatRateDefault: default: *repeat_delay = g.IO.KeyRepeatDelay * 1.00f; *repeat_rate = g.IO.KeyRepeatRate * 1.00f; return; } - window->DC.CurrLineSize = window->DC.PrevLineSize; - window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; } -void ImGui::Indent(float indent_w) +// Return value representing the number of presses in the last time period, for the given repeat rate +// (most often returns 0 or 1. The result is generally only >1 when RepeatRate is smaller than DeltaTime, aka large DeltaTime or fast RepeatRate) +int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; - window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return 0; + const float t = key_data->DownDuration; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); } -void ImGui::Unindent(float indent_w) +// Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values). +ImVec2 ImGui::GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; - window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; + return ImVec2( + GetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue, + GetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue); } - -//----------------------------------------------------------------------------- -// [SECTION] ERROR CHECKING -//----------------------------------------------------------------------------- - -static void ImGui::ErrorCheckEndFrame() +// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data. +// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D +// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6 +// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation. +static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) { - // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you - // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). ImGuiContext& g = *GImGui; - if (g.CurrentWindowStack.Size != 1) + rt->EntriesNext.resize(0); + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - if (g.CurrentWindowStack.Size > 1) - { - IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); - while (g.CurrentWindowStack.Size > 1) - End(); - } - else + const int new_routing_start_idx = rt->EntriesNext.Size; + ImGuiKeyRoutingData* routing_entry; + for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex) { - IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + routing_entry = &rt->Entries[old_routing_idx]; + routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry + routing_entry->RoutingNext = ImGuiKeyOwner_None; + routing_entry->RoutingNextScore = 255; + if (routing_entry->RoutingCurr == ImGuiKeyOwner_None) + continue; + rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer + + // Apply routing to owner if there's no owner already (RoutingCurr == None at this point) + if (routing_entry->Mods == g.IO.KeyMods) + { + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + owner_data->OwnerCurr = routing_entry->RoutingCurr; + } } + + // Rewrite linked-list + rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1); + for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++) + rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1); } + rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes +} +// owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope(). +static inline ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + return (owner_id != ImGuiKeyOwner_None && owner_id != ImGuiKeyOwner_Any) ? owner_id : g.CurrentFocusScopeId; } -// Save and compare stack sizes on Begin()/End() to detect usage errors -// Begin() calls this with write=true -// End() calls this with write=false -static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) +ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) { + // Majority of shortcuts will be Key + any number of Mods + // We accept _Single_ mod with ImGuiKey_None. + // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl); // Legal + // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl | ImGuiMod_Shift); // Legal + // - Shortcut(ImGuiMod_Ctrl); // Legal + // - Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift); // Not legal ImGuiContext& g = *GImGui; - short* p = &window->DC.StackSizesBackup[0]; + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + ImGuiKeyRoutingData* routing_data; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); + if (key == ImGuiKey_None) + key = ConvertSingleModFlagToKey(&g, mods); + IM_ASSERT(IsNamedKey(key)); - // Window stacks - // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() - { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + // Get (in the majority of case, the linked list will have one element so this should be 2 reads. + // Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame). + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; idx = routing_data->NextEntryIndex) + { + routing_data = &rt->Entries[idx]; + if (routing_data->Mods == mods) + return routing_data; + } - // Global stacks - // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() - { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() - { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() - { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() - IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); + // Add to linked-list + ImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size; + rt->Entries.push_back(ImGuiKeyRoutingData()); + routing_data = &rt->Entries[routing_data_idx]; + routing_data->Mods = (ImU16)mods; + routing_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list + rt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx; + return routing_data; } - -//----------------------------------------------------------------------------- -// [SECTION] SCROLLING -//----------------------------------------------------------------------------- - -static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) +// Current score encoding (lower is highest priority): +// - 0: ImGuiInputFlags_RouteGlobalHigh +// - 1: ImGuiInputFlags_RouteFocused (if item active) +// - 2: ImGuiInputFlags_RouteGlobal +// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack) +// - 254: ImGuiInputFlags_RouteGlobalLow +// - 255: never route +// 'flags' should include an explicit routing policy +static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputFlags flags) { - ImGuiContext& g = *GImGui; - ImVec2 scroll = window->Scroll; - if (window->ScrollTarget.x < FLT_MAX) - { - float cr_x = window->ScrollTargetCenterRatio.x; - float target_x = window->ScrollTarget.x; - if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x) - target_x = 0.0f; - else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + g.Style.ItemSpacing.x) - target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f; - scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); - } - if (window->ScrollTarget.y < FLT_MAX) - { - // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding. - float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); - float cr_y = window->ScrollTargetCenterRatio.y; - float target_y = window->ScrollTarget.y; - if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) - target_y = 0.0f; - if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y) - target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f; - scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); - } - scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); - if (!window->Collapsed && !window->SkipItems) - { - scroll.x = ImMin(scroll.x, window->ScrollMax.x); - scroll.y = ImMin(scroll.y, window->ScrollMax.y); + if (flags & ImGuiInputFlags_RouteFocused) + { + ImGuiContext& g = *GImGui; + ImGuiWindow* focused = g.NavWindow; + + // ActiveID gets top priority + // (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it) + if (owner_id != 0 && g.ActiveId == owner_id) + return 1; + + // Score based on distance to focused window (lower is better) + // Assuming both windows are submitting a routing request, + // - When Window....... is focused -> Window scores 3 (best), Window/ChildB scores 255 (no match) + // - When Window/ChildB is focused -> Window scores 4, Window/ChildB scores 3 (best) + // Assuming only WindowA is submitting a routing request, + // - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score. + if (focused != NULL && focused->RootWindow == location->RootWindow) + for (int next_score = 3; focused != NULL; next_score++) + { + if (focused == location) + { + IM_ASSERT(next_score < 255); + return next_score; + } + focused = (focused->RootWindow != focused) ? focused->ParentWindow : NULL; // FIXME: This could be later abstracted as a focus path + } + return 255; } - return scroll; + + // ImGuiInputFlags_RouteGlobalHigh is default, so calls without flags are not conditional + if (flags & ImGuiInputFlags_RouteGlobal) + return 2; + if (flags & ImGuiInputFlags_RouteGlobalLow) + return 254; + return 0; } -// Scroll to keep newly navigated item fully into view -ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect) +// Request a desired route for an input chord (key + mods). +// Return true if the route is available this frame. +// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state. +// (Conceptually this does a "Submit for next frame" + "Test for current frame". +// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.) +// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default) +// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut. +bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); - //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] + if ((flags & ImGuiInputFlags_RouteMask_) == 0) + flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut() + else + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used - ImVec2 delta_scroll; - if (!window_rect.Contains(item_rect)) - { - if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) - SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f); - else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) - SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f); - if (item_rect.Min.y < window_rect.Min.y) - SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f); - else if (item_rect.Max.y >= window_rect.Max.y) - SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f); + if (flags & ImGuiInputFlags_RouteUnlessBgFocused) + if (g.NavWindow == NULL) + return false; + if (flags & ImGuiInputFlags_RouteAlways) + return true; - ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false); - delta_scroll = next_scroll - window->Scroll; - } + const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags); + if (score == 255) + return false; - // Also scroll parent window to keep us into view if necessary - if (window->Flags & ImGuiWindowFlags_ChildWindow) - delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll)); + // Submit routing for NEXT frame (assuming score is sufficient) + // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <). + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore); + if (score < routing_data->RoutingNextScore) + { + routing_data->RoutingNext = routing_id; + routing_data->RoutingNextScore = (ImU8)score; + } - return delta_scroll; + // Return routing state for CURRENT frame + return routing_data->RoutingCurr == routing_id; } -float ImGui::GetScrollX() +// Currently unused by core (but used by tests) +// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading. +bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) { - ImGuiWindow* window = GImGui->CurrentWindow; - return window->Scroll.x; + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry. + return routing_data->RoutingCurr == routing_id; } -float ImGui::GetScrollY() +// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes. +// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87) +bool ImGui::IsKeyDown(ImGuiKey key) { - ImGuiWindow* window = GImGui->CurrentWindow; - return window->Scroll.y; + return IsKeyDown(key, ImGuiKeyOwner_Any); } -float ImGui::GetScrollMaxX() +bool ImGui::IsKeyDown(ImGuiKey key, ImGuiID owner_id) { - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ScrollMax.x; + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -float ImGui::GetScrollMaxY() +bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) { - ImGuiWindow* window = GImGui->CurrentWindow; - return window->ScrollMax.y; + return IsKeyPressed(key, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); } -void ImGui::SetScrollX(float scroll_x) +// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. +bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTarget.x = scroll_x; - window->ScrollTargetCenterRatio.x = 0.0f; + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = key_data->DownDuration; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! + + bool pressed = (t == 0.0f); + if (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0)) + { + float repeat_delay, repeat_rate; + GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate); + pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0; + } + if (!pressed) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -void ImGui::SetScrollY(float scroll_y) +bool ImGui::IsKeyReleased(ImGuiKey key) { - ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTarget.y = scroll_y; - window->ScrollTargetCenterRatio.y = 0.0f; + return IsKeyReleased(key, ImGuiKeyOwner_Any); } -void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x) +bool ImGui::IsKeyReleased(ImGuiKey key, ImGuiID owner_id) { - window->ScrollTarget.x = new_scroll_x; - window->ScrollTargetCenterRatio.x = 0.0f; + const ImGuiKeyData* key_data = GetKeyData(key); + if (key_data->DownDurationPrev < 0.0f || key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y) +bool ImGui::IsMouseDown(ImGuiMouseButton button) { - window->ScrollTarget.y = new_scroll_y; - window->ScrollTargetCenterRatio.y = 0.0f; + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array. } - -void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) +bool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id) { - // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size - IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); - window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); - window->ScrollTargetCenterRatio.x = center_x_ratio; + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array. } -void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) { - // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size - IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); - local_y -= decoration_up_height; - window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); - window->ScrollTargetCenterRatio.y = center_y_ratio; + return IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); } -void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +bool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = g.IO.MouseDownDuration[button]; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! + + const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0; + const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0); + if (!pressed) + return false; + + if (!TestKeyOwner(MouseButtonToKey(button), owner_id)) + return false; + + return true; } -void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +bool ImGui::IsMouseReleased(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; - SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any) } -// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. -void ImGui::SetScrollHereX(float center_x_ratio) +bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space - float last_item_width = window->DC.LastItemRect.GetWidth(); - target_x += (last_item_width * center_x_ratio) + (g.Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item. - SetScrollFromPosX(target_x, center_x_ratio); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) } -// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. -void ImGui::SetScrollHereY(float center_y_ratio) +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space - target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (g.Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. - SetScrollFromPosY(target_y, center_y_ratio); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); } -//----------------------------------------------------------------------------- -// [SECTION] TOOLTIPS -//----------------------------------------------------------------------------- - -void ImGui::BeginTooltip() +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; - if (g.DragDropWithinSourceOrTarget) - { - // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) - // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. - // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. - //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; - ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); - SetNextWindowPos(tooltip_pos); - SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); - //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( - BeginTooltipEx(0, true); - } - else - { - BeginTooltipEx(0, false); - } + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button]; } -// Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first. -void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip) +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) { ImGuiContext& g = *GImGui; - char window_name[16]; - ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); - if (override_previous_tooltip) - if (ImGuiWindow* window = FindWindowByName(window_name)) - if (window->Active) - { - // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. - window->Hidden = true; - window->HiddenFramesCanSkipItems = 1; - ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); - } - ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - Begin(window_name, NULL, flags | extra_flags); + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; } -void ImGui::EndTooltip() +// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) { - IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls - End(); + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; } -void ImGui::SetTooltipV(const char* fmt, va_list args) +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) { ImGuiContext& g = *GImGui; - if (g.DragDropWithinSourceOrTarget) - BeginTooltip(); - else - BeginTooltipEx(0, true); - TextV(fmt, args); - EndTooltip(); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); } -void ImGui::SetTooltip(const char* fmt, ...) +ImVec2 ImGui::GetMousePos() { - va_list args; - va_start(args, fmt); - SetTooltipV(fmt, args); - va_end(args); + ImGuiContext& g = *GImGui; + return g.IO.MousePos; } -//----------------------------------------------------------------------------- -// [SECTION] POPUPS -//----------------------------------------------------------------------------- +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} -bool ImGui::IsPopupOpen(ImGuiID id) +// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. +bool ImGui::IsAnyMouseDown() { ImGuiContext& g = *GImGui; - return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; } -bool ImGui::IsPopupOpen(const char* str_id) +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) { ImGuiContext& g = *GImGui; - return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); } -ImGuiWindow* ImGui::GetTopMostPopupModal() +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; - for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) - if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) - if (popup->Flags & ImGuiWindowFlags_Modal) - return popup; - return NULL; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; } -void ImGui::OpenPopup(const char* str_id) +// Get desired mouse cursor shape. +// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(), +// updated during the frame, and locked in EndFrame()/Render(). +// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you +ImGuiMouseCursor ImGui::GetMouseCursor() { ImGuiContext& g = *GImGui; - OpenPopupEx(g.CurrentWindow->GetID(str_id)); + return g.MouseCursor; } -// Mark popup as open (toggle toward open state). -// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. -// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). -// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) -void ImGui::OpenPopupEx(ImGuiID id) +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) { ImGuiContext& g = *GImGui; - ImGuiWindow* parent_window = g.CurrentWindow; - int current_stack_size = g.BeginPopupStack.Size; - ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. - popup_ref.PopupId = id; - popup_ref.Window = NULL; - popup_ref.SourceWindow = g.NavWindow; - popup_ref.OpenFrameCount = g.FrameCount; - popup_ref.OpenParentId = parent_window->IDStack.back(); - popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); - popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + g.MouseCursor = cursor_type; +} - //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id); - if (g.OpenPopupStack.Size < current_stack_size + 1) +static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value) +{ + IM_ASSERT(ImGui::IsAliasKey(key)); + ImGuiKeyData* key_data = ImGui::GetKeyData(key); + key_data->Down = v; + key_data->AnalogValue = analog_value; +} + +// [Internal] Do not use directly +static ImGuiKeyChord GetMergedModsFromKeys() +{ + ImGuiKeyChord mods = 0; + if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; } + if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; } + if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; } + if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; } + return mods; +} + +static void ImGui::UpdateKeyboardInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Import legacy keys or verify they are not used +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (io.BackendUsingLegacyKeyArrays == 0) { - g.OpenPopupStack.push_back(popup_ref); + // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. + for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); } else { - // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui - // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing - // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. - if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) - { - g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; - } - else + if (g.FrameCount == 0) + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); + + // Build reverse KeyMap (Named -> Legacy) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + if (io.KeyMap[n] != -1) + { + IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); + io.KeyMap[io.KeyMap[n]] = n; + } + + // Import legacy keys into new ones + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) + { + const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); + IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); + io.KeysData[key].Down = io.KeysDown[n]; + if (key != n) + io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends + io.BackendUsingLegacyKeyArrays = 1; + } + if (io.BackendUsingLegacyKeyArrays == 1) { - // Close child popups if any, then flag popup for open/reopen - g.OpenPopupStack.resize(current_stack_size + 1); - g.OpenPopupStack[current_stack_size] = popup_ref; + GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; + GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; + GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; + GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; } - - // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). - // This is equivalent to what ClosePopupToLevel() does. - //if (g.OpenPopupStack[current_stack_size].PopupId == id) - // FocusWindow(parent_window); } -} -void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) -{ - ImGuiContext& g = *GImGui; - if (g.OpenPopupStack.empty()) - return; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) + { + #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) + #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); + #undef NAV_MAP_KEY + } +#endif +#endif - // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. - // Don't close our own child popup windows. - int popup_count_to_keep = 0; - if (ref_window) - { - // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) - for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + // Update aliases + for (int n = 0; n < ImGuiMouseButton_COUNT; n++) + UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); + UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH); + UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel); + + // Synchronize io.KeyMods and io.KeyXXX values. + // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing. + io.KeyMods = GetMergedModsFromKeys(); + io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0; + io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0; + io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0; + io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0; + + // Clear gamepad data if disabled + if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) + for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) { - ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; - if (!popup.Window) - continue; - IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); - if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) - continue; - - // Trim the stack when popups are not direct descendant of the reference window (the reference window is often the NavWindow) - bool popup_or_descendent_is_ref_window = false; - for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_is_ref_window; m++) - if (ImGuiWindow* popup_window = g.OpenPopupStack[m].Window) - if (popup_window->RootWindow == ref_window->RootWindow) - popup_or_descendent_is_ref_window = true; - if (!popup_or_descendent_is_ref_window) - break; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; } + + // Update keys + for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) + { + ImGuiKeyData* key_data = &io.KeysData[i]; + key_data->DownDurationPrev = key_data->DownDuration; + key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; } - if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + + // Update keys/input owner (named keys only): one entry per key + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); - ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; + ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; + owner_data->OwnerCurr = owner_data->OwnerNext; + if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. + owner_data->OwnerNext = ImGuiKeyOwner_None; + owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore } + + UpdateKeyRoutingTable(&g.KeysRoutingTable); } -void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +static void ImGui::UpdateMouseInputs() { ImGuiContext& g = *GImGui; - IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); - ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow; - ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; - g.OpenPopupStack.resize(remaining); + ImGuiIO& io = g.IO; - if (restore_focus_to_window_under_popup) + // Mouse Wheel swapping flag + // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead + // - We avoid doing it on OSX as it the OS input layer handles this already. + // - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature. + // - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source. + io.MouseWheelRequestAxisSwap = io.KeyShift && !io.ConfigMacOSXBehaviors; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&io.MousePos)) + io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev)) + io.MouseDelta = io.MousePos - io.MousePosPrev; + else + io.MouseDelta = ImVec2(0.0f, 0.0f); + + // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + io.MousePosPrev = io.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) { - if (focus_window && !focus_window->WasActive && popup_window) + io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; + io.MouseClickedCount[i] = 0; // Will be filled below + io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; + io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; + io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; + if (io.MouseClicked[i]) { - // Fallback - FocusTopMostWindowUnderOne(popup_window, NULL); + bool is_repeated_click = false; + if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist) + is_repeated_click = true; + } + if (is_repeated_click) + io.MouseClickedLastCount[i]++; + else + io.MouseClickedLastCount[i] = 1; + io.MouseClickedTime[i] = g.Time; + io.MouseClickedPos[i] = io.MousePos; + io.MouseClickedCount[i] = io.MouseClickedLastCount[i]; + io.MouseDragMaxDistanceSqr[i] = 0.0f; } - else + else if (io.MouseDown[i]) { - if (g.NavLayer == 0 && focus_window) - focus_window = NavRestoreLastChildNavWindow(focus_window); - FocusWindow(focus_window); + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f; + io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos); } + + // We provide io.MouseDoubleClicked[] as a legacy service + io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); + + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + if (io.MouseClicked[i]) + g.NavDisableMouseHover = false; } } -// Close the popup we have begin-ed into. -void ImGui::CloseCurrentPopup() +static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount) { ImGuiContext& g = *GImGui; - int popup_idx = g.BeginPopupStack.Size - 1; - if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + if (window) + g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER); + else + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindow == window) return; - - // Closing a menu closes its top-most parent popup (unless a modal) - while (popup_idx > 0) + IMGUI_DEBUG_LOG_IO("[io] LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL"); + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; + if (window == NULL) { - ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; - ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; - bool close_parent = false; - if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) - if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) - close_parent = true; - if (!close_parent) - break; - popup_idx--; + g.WheelingWindowStartFrame = -1; + g.WheelingAxisAvg = ImVec2(0.0f, 0.0f); } - //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); - ClosePopupToLevel(popup_idx, true); - - // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. - // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. - // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. - if (ImGuiWindow* window = g.NavWindow) - window->DC.NavHideHighlightOneFrame = true; } -bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) +static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel) { + // For each axis, find window in the hierarchy that may want to use scrolling ImGuiContext& g = *GImGui; - if (!IsPopupOpen(id)) - { - g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values - return false; - } - - char name[20]; - if (extra_flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth - else - ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame - - bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup); - if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) - EndPopup(); + ImGuiWindow* windows[2] = { NULL, NULL }; + for (int axis = 0; axis < 2; axis++) + if (wheel[axis] != 0.0f) + for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow) + { + // Bubble up into parent window if: + // - a child window doesn't allow any scrolling. + // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. + //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP) + const bool has_scrolling = (window->ScrollMax[axis] != 0.0f); + const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs); + //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]); + if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits) + break; // select this window + } + if (windows[0] == NULL && windows[1] == NULL) + return NULL; - return is_open; -} + // If there's only one window or only one axis then there's no ambiguity + if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL) + return windows[1] ? windows[1] : windows[0]; -bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) -{ - ImGuiContext& g = *GImGui; - if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + // If candidate are different windows we need to decide which one to prioritize + // - First frame: only find a winner if one axis is zero. + // - Subsequent frames: only find a winner when one is more than the other. + if (g.WheelingWindowStartFrame == -1) + g.WheelingWindowStartFrame = g.FrameCount; + if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y)) { - g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values - return false; + g.WheelingWindowWheelRemainder = wheel; + return NULL; } - flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; - return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); + return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1]; } -// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. -// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. -bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +// Called by NewFrame() +void ImGui::UpdateMouseWheel() { + // Reset the locked window if we move the mouse or after the timer elapses. + // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795) ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - const ImGuiID id = window->GetID(name); - if (!IsPopupOpen(id)) + if (g.WheelingWindow != NULL) { - g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values - return false; + g.WheelingWindowReleaseTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindowReleaseTimer <= 0.0f) + LockWheelingWindow(NULL, 0.0f); } - // Center modal windows by default - // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) - SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + ImVec2 wheel; + wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f; + wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f; - flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; - const bool is_open = Begin(name, p_open, flags); - if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y); + ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!mouse_window || mouse_window->Collapsed) + return; + + // Zoom / Scale window + // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. + if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) { - EndPopup(); - if (is_open) - ClosePopupToLevel(g.BeginPopupStack.Size, true); - return false; + LockWheelingWindow(mouse_window, wheel.y); + ImGuiWindow* window = mouse_window; + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + if (window == window->RootWindow) + { + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + SetWindowPos(window, window->Pos + offset, 0); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + } + return; } - return is_open; + if (g.IO.KeyCtrl) + return; + + // Mouse wheel scrolling + // Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs() + if (g.IO.MouseWheelRequestAxisSwap) + wheel = ImVec2(wheel.y, 0.0f); + + // Maintain a rough average of moving magnitude on both axises + // FIXME: should by based on wall clock time rather than frame-counter + g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30); + g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30); + + // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now. + wheel += g.WheelingWindowWheelRemainder; + g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f); + if (wheel.x == 0.0f && wheel.y == 0.0f) + return; + + // Mouse wheel scrolling: find target and apply + // - don't renew lock if axis doesn't apply on the window. + // - select a main axis when both axises are being moved. + if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel))) + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f }; + if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y]) + do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false; + if (do_scroll[ImGuiAxis_X]) + { + LockWheelingWindow(window, wheel.x); + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + } + if (do_scroll[ImGuiAxis_Y]) + { + LockWheelingWindow(window, wheel.y); + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); + } + } } -void ImGui::EndPopup() +void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls - IM_ASSERT(g.BeginPopupStack.Size > 0); - - // Make all menus and popups wrap around for now, may need to expose that policy. - NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); - - // Child-popups don't need to be layed out - IM_ASSERT(g.WithinEndChild == false); - if (window->Flags & ImGuiWindowFlags_ChildWindow) - g.WithinEndChild = true; - End(); - g.WithinEndChild = false; + g.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0; } -bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) +void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse) { - ImGuiWindow* window = GImGui->CurrentWindow; - if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) - { - ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! - IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) - OpenPopupEx(id); - return true; - } - return false; + ImGuiContext& g = *GImGui; + g.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0; } -// This is a helper to handle the simplest case of associating one named popup to one given widget. -// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). -// You can pass a NULL str_id to use the identifier of the last item. -bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +static const char* GetInputSourceName(ImGuiInputSource source) { - ImGuiWindow* window = GImGui->CurrentWindow; - if (window->SkipItems) - return false; - ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! - IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) - if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) - OpenPopupEx(id); - return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Clipboard" }; + IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); + return input_source_names[source]; } - -bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) +static const char* GetMouseSourceName(ImGuiMouseSource source) { - if (!str_id) - str_id = "window_context"; - ImGuiID id = GImGui->CurrentWindow->GetID(str_id); - if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) - if (also_over_items || !IsAnyItemHovered()) - OpenPopupEx(id); - return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + const char* mouse_source_names[] = { "Mouse", "TouchScreen", "Pen" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT); + return mouse_source_names[source]; } - -bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) +static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) { - if (!str_id) - str_id = "void_context"; - ImGuiID id = GImGui->CurrentWindow->GetID(str_id); - if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) - OpenPopupEx(id); - return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + ImGuiContext& g = *GImGui; + if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } + if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } + if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } } +#endif -// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) -// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. -ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +// Process input queue +// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'. +// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost) +// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87) +void ImGui::UpdateInputEvents(bool trickle_fast_inputs) { - ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); - //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); - //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; - // Combo Box policy (we want a connecting edge) - if (policy == ImGuiPopupPositionPolicy_ComboBox) + // Only trickle chars<>key when working with InputText() + // FIXME: InputText() could parse event trail? + // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters) + const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); + + bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false; + int mouse_button_changed = 0x00; + ImBitArray key_changed_mask; + + int event_n = 0; + for (; event_n < g.InputEventsQueue.Size; event_n++) { - const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; - for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + ImGuiInputEvent* e = &g.InputEventsQueue[event_n]; + if (e->Type == ImGuiInputEventType_MousePos) { - const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; - if (n != -1 && dir == *last_dir) // Already tried this direction? - continue; - ImVec2 pos; - if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) - if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right - if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left - if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left - if (!r_outer.Contains(ImRect(pos, pos + size))) - continue; - *last_dir = dir; - return pos; + // Trickling Rule: Stop processing queued events if we already handled a mouse button change + ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); + if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) + break; + io.MousePos = event_pos; + io.MouseSource = e->MousePos.MouseSource; + mouse_moved = true; + } + else if (e->Type == ImGuiInputEventType_MouseButton) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button + const ImGuiMouseButton button = e->MouseButton.Button; + IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); + if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled)) + break; + if (trickle_fast_inputs && e->MouseButton.MouseSource == ImGuiMouseSource_TouchScreen && mouse_moved) // #2702: TouchScreen have no initial hover. + break; + io.MouseDown[button] = e->MouseButton.Down; + io.MouseSource = e->MouseButton.MouseSource; + mouse_button_changed |= (1 << button); + } + else if (e->Type == ImGuiInputEventType_MouseWheel) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the event + if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0)) + break; + io.MouseWheelH += e->MouseWheel.WheelX; + io.MouseWheel += e->MouseWheel.WheelY; + io.MouseSource = e->MouseWheel.MouseSource; + mouse_wheeled = true; + } + else if (e->Type == ImGuiInputEventType_Key) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button + ImGuiKey key = e->Key.Key; + IM_ASSERT(key != ImGuiKey_None); + ImGuiKeyData* key_data = GetKeyData(key); + const int key_data_index = (int)(key_data - g.IO.KeysData); + if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0)) + break; + key_data->Down = e->Key.Down; + key_data->AnalogValue = e->Key.AnalogValue; + key_changed = true; + key_changed_mask.SetBit(key_data_index); + + // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + io.KeysDown[key_data_index] = key_data->Down; + if (io.KeyMap[key_data_index] != -1) + io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; +#endif + } + else if (e->Type == ImGuiInputEventType_Text) + { + // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with + if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) + break; + unsigned int c = e->Text.Char; + io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); + if (trickle_interleaved_keys_and_text) + text_inputted = true; + } + else if (e->Type == ImGuiInputEventType_Focus) + { + // We intentionally overwrite this and process in NewFrame(), in order to give a chance + // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame. + const bool focus_lost = !e->AppFocused.Focused; + io.AppFocusLost = focus_lost; + } + else + { + IM_ASSERT(0 && "Unknown event!"); } } - // Default popup policy - const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; - for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) - { - const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; - if (n != -1 && dir == *last_dir) // Already tried this direction? - continue; - float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); - float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); - if (avail_w < size.x || avail_h < size.y) - continue; - ImVec2 pos; - pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; - pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; - *last_dir = dir; - return pos; - } + // Record trail (for domain-specific applications wanting to access a precise trail) + //if (event_n != 0) IMGUI_DEBUG_LOG_IO("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n); + for (int n = 0; n < event_n; n++) + g.InputEventsTrail.push_back(g.InputEventsQueue[n]); - // Fallback, try to keep within display - *last_dir = ImGuiDir_None; - ImVec2 pos = ref_pos; - pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); - pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); - return pos; + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO)) + for (int n = 0; n < g.InputEventsQueue.Size; n++) + DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]); +#endif + + // Remaining events will be processed on the next frame + if (event_n == g.InputEventsQueue.Size) + g.InputEventsQueue.resize(0); + else + g.InputEventsQueue.erase(g.InputEventsQueue.Data, g.InputEventsQueue.Data + event_n); + + // Clear buttons state when focus is lost + // - this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle. + // - we clear in EndFrame() and not now in order allow application/user code polling this flag + // (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event). + if (g.IO.AppFocusLost) + g.IO.ClearInputKeys(); } -ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) +ImGuiID ImGui::GetKeyOwner(ImGuiKey key) { - IM_UNUSED(window); - ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; - ImRect r_screen = GetViewportRect(); - r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); - return r_screen; + if (!IsNamedKeyOrModKey(key)) + return ImGuiKeyOwner_None; + + ImGuiContext& g = *GImGui; + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + ImGuiID owner_id = owner_data->OwnerCurr; + + if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) + if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) + return ImGuiKeyOwner_None; + + return owner_id; } -ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +// TestKeyOwner(..., ID) : (owner == None || owner == ID) +// TestKeyOwner(..., None) : (owner == None) +// TestKeyOwner(..., Any) : no owner test +// All paths are also testing for key not being locked, for the rare cases that key have been locked with using ImGuiInputFlags_LockXXX flags. +bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id) { + if (!IsNamedKeyOrModKey(key)) + return true; + ImGuiContext& g = *GImGui; + if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) + if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) + return false; - ImRect r_outer = GetWindowAllowedExtentRect(window); - if (window->Flags & ImGuiWindowFlags_ChildMenu) - { - // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. - // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. - IM_ASSERT(g.CurrentWindow == window); - ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; - float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). - ImRect r_avoid; - if (parent_window->DC.MenuBarAppending) - r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); - else - r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); - return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); - } - if (window->Flags & ImGuiWindowFlags_Popup) + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_id == ImGuiKeyOwner_Any) + return (owner_data->LockThisFrame == false); + + // Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId + // are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things. + // Setting OwnerCurr in SetKeyOwner() is more consistent than testing OwnerNext here: would be inconsistent with getter and other functions. + if (owner_data->OwnerCurr != owner_id) { - ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); - return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + if (owner_data->LockThisFrame) + return false; + if (owner_data->OwnerCurr != ImGuiKeyOwner_None) + return false; } - if (window->Flags & ImGuiWindowFlags_Tooltip) + + return true; +} + +// _LockXXX flags are useful to lock keys away from code which is not input-owner aware. +// When using _LockXXX flags, you can use ImGuiKeyOwner_Any to lock keys from everyone. +// - SetKeyOwner(..., None) : clears owner +// - SetKeyOwner(..., Any, !Lock) : illegal (assert) +// - SetKeyOwner(..., Any or None, Lock) : set lock +void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) +{ + IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it) + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function! + + ImGuiContext& g = *GImGui; + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + owner_data->OwnerCurr = owner_data->OwnerNext = owner_id; + + // We cannot lock by default as it would likely break lots of legacy code. + // In the case of using LockUntilRelease while key is not down we still lock during the frame (no key_data->Down test) + owner_data->LockUntilRelease = (flags & ImGuiInputFlags_LockUntilRelease) != 0; + owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease); +} + +// Rarely used helper +void ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) +{ + if (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); } + if (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); } + if (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); } + if (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); } + if (key_chord & ImGuiMod_Shortcut) { SetKeyOwner(ImGuiMod_Shortcut, owner_id, flags); } + if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); } +} + +// This is more or less equivalent to: +// if (IsItemHovered() || IsItemActive()) +// SetKeyOwner(key, GetItemID()); +// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times. +// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition. +// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority. +void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.LastItemData.ID; + if (id == 0 || (g.HoveredId != id && g.ActiveId != id)) + return; + if ((flags & ImGuiInputFlags_CondMask_) == 0) + flags |= ImGuiInputFlags_CondDefault_; + if ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive))) { - // Position tooltip (always follows mouse) - float sc = g.Style.MouseCursorScale; - ImVec2 ref_pos = NavCalcPreferredRefPos(); - ImRect r_avoid; - if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) - r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); - else - r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. - ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); - if (window->AutoPosLastDirection == ImGuiDir_None) - pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. - return pos; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function! + SetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_); } - IM_ASSERT(0); - return window->Pos; +} + +bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + + // When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any. + if ((flags & ImGuiInputFlags_RouteMask_) == 0) + flags |= ImGuiInputFlags_RouteFocused; + if (!SetShortcutRouting(key_chord, owner_id, flags)) + return false; + + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); + if (g.IO.KeyMods != mods) + return false; + + // Special storage location for mods + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + if (key == ImGuiKey_None) + key = ConvertSingleModFlagToKey(&g, mods); + + if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_)))) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function! + + return true; } //----------------------------------------------------------------------------- -// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +// [SECTION] ERROR CHECKING //----------------------------------------------------------------------------- -ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. +// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit +// If this triggers you have an issue: +// - Most commonly: mismatched headers and compiled code version. +// - Or: mismatched configuration #define, compilation settings, packing pragma etc. +// The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui, +// which is way it is required you put them in your imconfig file (and not just before including imgui.h). +// Otherwise it is possible that different compilation units would see different structure layout +bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) { - if (ImFabs(dx) > ImFabs(dy)) - return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; - return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; + bool error = false; + if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } + return !error; } -static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) +// Until 1.89 (IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos() to extend the boundary of a parent (e.g. window or table cell) +// This is causing issues and ambiguity and we need to retire that. +// See https://github.com/ocornut/imgui/issues/5548 for more details. +// [Scenario 1] +// Previously this would make the window content size ~200x200: +// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK +// Instead, please submit an item: +// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK +// Alternative: +// Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK +// [Scenario 2] +// For reference this is one of the issue what we aim to fix with this change: +// BeginGroup() + SomeItem("foobar") + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup() +// The previous logic made SetCursorScreenPos(GetCursorScreenPos()) have a side-effect! It would erroneously incorporate ItemSpacing.y after the item into content size, making the group taller! +// While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. Using vertical alignment patterns could trigger this issue. +void ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries() { - if (a1 < b0) - return a1 - b0; - if (b1 < a0) - return a0 - b1; - return 0.0f; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->DC.IsSetPos); + window->DC.IsSetPos = false; +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y) + return; + if (window->SkipItems) + return; + IM_ASSERT(0 && "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. Please submit an item e.g. Dummy() to validate extent."); +#else + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +#endif } -static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +static void ImGui::ErrorCheckNewFrameSanityChecks() { - if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) - { - r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); - r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); - } - else - { - r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); - r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); - } + ImGuiContext& g = *GImGui; + + // Check user IM_ASSERT macro + // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined! + // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. + // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) + // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong! + // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct! + if (true) IM_ASSERT(1); else IM_ASSERT(0); + + // Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644) + // Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it. +#ifdef __EMSCRIPTEN__ + if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0) + g.IO.DeltaTime = 0.00001f; +#endif + + // Check user data + // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) + IM_ASSERT(g.Initialized); + IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); + IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); + IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); + IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); + IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)"); + + // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); +#endif + + // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; } -// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 -static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) +static void ImGui::ErrorCheckEndFrameSanityChecks() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (g.NavLayer != window->DC.NavLayerCurrent) - return false; - const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) - g.NavScoringCount++; + // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() + // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). + // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will + // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. + // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // while still correctly asserting on mid-frame key press events. + const ImGuiKeyChord key_mods = GetMergedModsFromKeys(); + IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mods); - // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring - if (window->ParentWindow == g.NavWindow) + // [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame(). + //ErrorCheckEndFrameRecover(); + + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) { - IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); - if (!window->ClipRect.Overlaps(cand)) - return false; - cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + if (g.CurrentWindowStack.Size > 1) + { + ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended! + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + IM_UNUSED(window); + while (g.CurrentWindowStack.Size > 1) + End(); + } + else + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } } - // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) - // For example, this ensure that items in one column are not reached when moving vertically from items in another column. - NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); +} - // Compute distance between boxes - // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. - float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); - float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items - if (dby != 0.0f && dbx != 0.0f) - dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); - float dist_box = ImFabs(dbx) + ImFabs(dby); +// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls. +// Must be called during or before EndFrame(). +// This is generally flawed as we are not necessarily End/Popping things in the right order. +// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. +// FIXME: Can't recover from interleaved BeginTabBar/Begin +void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations" + ImGuiContext& g = *GImGui; + while (g.CurrentWindowStack.Size > 0) //-V1044 + { + ErrorCheckEndWindowRecover(log_callback, user_data); + ImGuiWindow* window = g.CurrentWindow; + if (g.CurrentWindowStack.Size == 1) + { + IM_ASSERT(window->IsFallbackWindow); + break; + } + if (window->Flags & ImGuiWindowFlags_ChildWindow) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name); + EndChild(); + } + else + { + if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name); + End(); + } + } +} - // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) - float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); - float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); - float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) +// Must be called before End()/EndChild() +void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + ImGuiContext& g = *GImGui; + while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow)) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name); + EndTable(); + } - // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance - ImGuiDir quadrant; - float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; - if (dbx != 0.0f || dby != 0.0f) + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin; + IM_ASSERT(window != NULL); + while (g.CurrentTabBar != NULL) //-V1044 { - // For non-overlapping boxes, use distance between boxes - dax = dbx; - day = dby; - dist_axial = dist_box; - quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name); + EndTabBar(); } - else if (dcx != 0.0f || dcy != 0.0f) + while (window->DC.TreeDepth > 0) { - // For overlapping boxes with different centers, use distance between centers - dax = dcx; - day = dcy; - dist_axial = dist_center; - quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name); + TreePop(); } - else + while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044 { - // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) - quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name); + EndGroup(); } - -#if IMGUI_DEBUG_NAV_SCORING - char buf[128]; - if (IsMouseHoveringRect(cand.Min, cand.Max)) + while (window->IDStack.Size > 1) { - ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); - ImDrawList* draw_list = GetForegroundDrawList(window); - draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); - draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); - draw_list->AddRectFilled(cand.Max - ImVec2(4,4), cand.Max + CalcTextSize(buf) + ImVec2(4,4), IM_COL32(40,0,0,150)); - draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); + if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name); + PopID(); } - else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. + while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044 { - if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } - if (quadrant == g.NavMoveDir) - { - ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); - ImDrawList* draw_list = GetForegroundDrawList(window); - draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); - draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); - } + if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); + EndDisabled(); } - #endif - - // Is it in the quadrant we're interesting in moving to? - bool new_best = false; - if (quadrant == g.NavMoveDir) + while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) { - // Does it beat the current best candidate? - if (dist_box < result->DistBox) - { - result->DistBox = dist_box; - result->DistCenter = dist_center; - return true; - } - if (dist_box == result->DistBox) - { - // Try using distance between center points to break ties - if (dist_center < result->DistCenter) - { - result->DistCenter = dist_center; - new_best = true; - } - else if (dist_center == result->DistCenter) - { - // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items - // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), - // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. - if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance - new_best = true; - } - } + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col)); + PopStyleColor(); + } + while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name); + PopItemFlag(); + } + while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); + PopStyleVar(); + } + while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name); + PopFont(); + } + while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); + PopFocusScope(); } +} - // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches - // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) - // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. - // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. - // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? - if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match - if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) - if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) - { - result->DistAxial = dist_axial; - new_best = true; - } +// Save current stack sizes for later compare +void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiWindow* window = g.CurrentWindow; + SizeOfIDStack = (short)window->IDStack.Size; + SizeOfColorStack = (short)g.ColorStack.Size; + SizeOfStyleVarStack = (short)g.StyleVarStack.Size; + SizeOfFontStack = (short)g.FontStack.Size; + SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; + SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; + SizeOfDisabledStack = (short)g.DisabledStackSize; +} - return new_best; +// Compare to detect usage errors +void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiWindow* window = g.CurrentWindow; + IM_UNUSED(window); + + // Window stacks + // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!"); + IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!"); + IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); + IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); + IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); + IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!"); } -// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) -static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) + +//----------------------------------------------------------------------------- +// [SECTION] LAYOUT +//----------------------------------------------------------------------------- +// - ItemSize() +// - ItemAdd() +// - SameLine() +// - GetCursorScreenPos() +// - SetCursorScreenPos() +// - GetCursorPos(), GetCursorPosX(), GetCursorPosY() +// - SetCursorPos(), SetCursorPosX(), SetCursorPosY() +// - GetCursorStartPos() +// - Indent() +// - Unindent() +// - SetNextItemWidth() +// - PushItemWidth() +// - PushMultiItemsWidths() +// - PopItemWidth() +// - CalcItemWidth() +// - CalcItemSize() +// - GetTextLineHeight() +// - GetTextLineHeightWithSpacing() +// - GetFrameHeight() +// - GetFrameHeightWithSpacing() +// - GetContentRegionMax() +// - GetContentRegionMaxAbs() [Internal] +// - GetContentRegionAvail(), +// - GetWindowContentRegionMin(), GetWindowContentRegionMax() +// - BeginGroup() +// - EndGroup() +// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns. +//----------------------------------------------------------------------------- + +// Advance cursor given item size for layout. +// Register minimum needed size so it can extend the bounding box used for auto-fit calculation. +// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. +void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) { ImGuiContext& g = *GImGui; - //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. - // return; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; - const ImGuiItemFlags item_flags = window->DC.ItemFlags; - const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); + // We increase the height in this function to accommodate for baseline offset. + // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, + // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. + const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; - // Process Init Request - if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) - { - // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback - if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) - { - g.NavInitResultId = id; - g.NavInitResultRectRel = nav_bb_rel; - } - if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) - { - g.NavInitRequest = false; // Found a match, clear request - NavUpdateAnyRequestFlag(); - } - } + const float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y; + const float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y); - // Process Move Request (scoring for navigation) - // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) - if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled|ImGuiItemFlags_NoNav))) + // Always align ourselves on pixel boundaries + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = line_y1; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line + window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.y = line_height; + window->DC.CurrLineSize.y = 0.0f; + window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); + window->DC.CurrLineTextBaseOffset = 0.0f; + window->DC.IsSameLine = window->DC.IsSetPos = false; + + // Horizontal layout mode + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Set item data + // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set) + g.LastItemData.ID = id; + g.LastItemData.Rect = bb; + g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; + g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags; + g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; + + // Directional navigation processing + if (id != 0) { - ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; -#if IMGUI_DEBUG_NAV_SCORING - // [DEBUG] Score all items in NavWindow at all times - if (!g.NavMoveRequest) - g.NavMoveDir = g.NavMoveDirLast; - bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; -#else - bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); -#endif - if (new_best) + KeepAliveID(id); + + // Runs prior to clipping early-out + // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget + // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests + // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of + // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. + // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able + // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). + // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. + // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. + if (!(g.LastItemData.InFlags & ImGuiItemFlags_NoNav)) { - result->ID = id; - result->SelectScopeId = g.MultiSelectScopeId; - result->Window = window; - result->RectRel = nav_bb_rel; + window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); + if (g.NavId == id || g.NavAnyRequest) + if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) + if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) + NavProcessItem(); } - const float VISIBLE_RATIO = 0.70f; - if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) - if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) - if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) - { - result = &g.NavMoveResultLocalVisibleSet; - result->ID = id; - result->SelectScopeId = g.MultiSelectScopeId; - result->Window = window; - result->RectRel = nav_bb_rel; - } + // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something". + // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something". + // READ THE FAQ: https://dearimgui.com/faq + IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); } + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; - // Update window-relative bounding box of navigated item - if (g.NavId == id) - { - g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. - g.NavLayer = window->DC.NavLayerCurrent; - g.NavIdIsAlive = true; - g.NavIdTabCounter = window->DC.FocusCounterTab; - window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) - } -} +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + IMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData); +#endif -bool ImGui::NavMoveRequestButNoResultYet() -{ - ImGuiContext& g = *GImGui; - return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; -} + // Clipping test + // (FIXME: This is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value) + //const bool is_clipped = IsClippedEx(bb, id); + //if (is_clipped) + // return false; + const bool is_rect_visible = bb.Overlaps(window->ClipRect); + if (!is_rect_visible) + if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId)) + if (!g.LogEnabled) + return false; -void ImGui::NavMoveRequestCancel() -{ - ImGuiContext& g = *GImGui; - g.NavMoveRequest = false; - NavUpdateAnyRequestFlag(); -} + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (id != 0 && id == g.DebugLocateId) + DebugLocateItemResolveWithLastItem(); +#endif + //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + //if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0) + // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] -void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); - NavMoveRequestCancel(); - g.NavMoveDir = move_dir; - g.NavMoveClipDir = clip_dir; - g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; - g.NavMoveRequestFlags = move_flags; - g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) + if (is_rect_visible) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Visible; + if (IsMouseHoveringRect(bb.Min, bb.Max)) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; } -void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) +// Gets back to previous line and continue with horizontal layout +// offset_from_start_x == 0 : follow right after previous item +// offset_from_start_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float offset_from_start_x, float spacing_w) { ImGuiContext& g = *GImGui; - if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != 0) + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) return; - IM_ASSERT(move_flags != 0); // No points calling this with no wrapping - ImRect bb_rel = window->NavRectRel[0]; - ImGuiDir clip_dir = g.NavMoveDir; - if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) - { - bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; - if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } - NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); - } - if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) - { - bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; - if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; } - NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); - } - if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + if (offset_from_start_x != 0.0f) { - bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; - if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } - NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + if (spacing_w < 0.0f) + spacing_w = 0.0f; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } - if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + else { - bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; - if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; } - NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + if (spacing_w < 0.0f) + spacing_w = g.Style.ItemSpacing.x; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } + window->DC.CurrLineSize = window->DC.PrevLineSize; + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + window->DC.IsSameLine = true; } -// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). -// This way we could find the last focused window among our children. It would be much less confusing this way? -static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +ImVec2 ImGui::GetCursorScreenPos() { - ImGuiWindow* parent_window = nav_window; - while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) - parent_window = parent_window->ParentWindow; - if (parent_window && parent_window != nav_window) - parent_window->NavLastChildNavWindow = nav_window; + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; } -// Restore the last focused child. -// Call when we are expected to land on the Main Layer (0) after FocusWindow() -static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc. +// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50) +// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos... +void ImGui::SetCursorScreenPos(const ImVec2& pos) { - return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); + window->DC.IsSetPos = true; } -static void NavRestoreLayer(ImGuiNavLayer layer) +// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. +// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. +ImVec2 ImGui::GetCursorPos() { - ImGuiContext& g = *GImGui; - g.NavLayer = layer; - if (layer == 0) - g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); - if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) - ImGui::SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); - else - ImGui::NavInitWindow(g.NavWindow, true); + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos - window->Pos + window->Scroll; } -static inline void ImGui::NavUpdateAnyRequestFlag() +float ImGui::GetCursorPosX() { - ImGuiContext& g = *GImGui; - g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); - if (g.NavAnyRequest) - IM_ASSERT(g.NavWindow != NULL); + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; } -// This needs to be called before we submit any widget (aka in or before Begin) -void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +float ImGui::GetCursorPosY() { - ImGuiContext& g = *GImGui; - IM_ASSERT(window == g.NavWindow); - bool init_for_nav = false; - if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) - if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) - init_for_nav = true; - //IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); - if (init_for_nav) - { - SetNavID(0, g.NavLayer); - g.NavInitRequest = true; - g.NavInitRequestFromMove = false; - g.NavInitResultId = 0; - g.NavInitResultRectRel = ImRect(); - NavUpdateAnyRequestFlag(); - } - else - { - g.NavId = window->NavLastIds[0]; - } + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; } -static ImVec2 ImGui::NavCalcPreferredRefPos() +void ImGui::SetCursorPos(const ImVec2& local_pos) { - ImGuiContext& g = *GImGui; - if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) - { - // Mouse (we need a fallback in case the mouse becomes invalid after being used) - if (IsMousePosValid(&g.IO.MousePos)) - return g.IO.MousePos; - return g.LastValidMousePos; - } - else - { - // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. - const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; - ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); - ImRect visible_rect = GetViewportRect(); - return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. - } + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = window->Pos - window->Scroll + local_pos; + //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); + window->DC.IsSetPos = true; } -float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) +void ImGui::SetCursorPosX(float x) { - ImGuiContext& g = *GImGui; - if (mode == ImGuiInputReadMode_Down) - return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; + //window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); + window->DC.IsSetPos = true; +} - const float t = g.IO.NavInputsDownDuration[n]; - if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. - return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); - if (t < 0.0f) - return 0.0f; - if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. - return (t == 0.0f) ? 1.0f : 0.0f; - if (mode == ImGuiInputReadMode_Repeat) - return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f); - if (mode == ImGuiInputReadMode_RepeatSlow) - return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); - if (mode == ImGuiInputReadMode_RepeatFast) - return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); - return 0.0f; +void ImGui::SetCursorPosY(float y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; + //window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); + window->DC.IsSetPos = true; } -ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) +ImVec2 ImGui::GetCursorStartPos() { - ImVec2 delta(0.0f, 0.0f); - if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) - delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); - if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) - delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); - if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) - delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); - if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) - delta *= slow_factor; - if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) - delta *= fast_factor; - return delta; + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorStartPos - window->Pos; } -static void ImGui::NavUpdate() +void ImGui::Indent(float indent_w) { ImGuiContext& g = *GImGui; - g.IO.WantSetMousePos = false; -#if 0 - if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); -#endif + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +void ImGui::Unindent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +// Affect large frame+labels widgets only. +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; +} + +// FIXME: Remove the == 0.0f behavior? +void ImGui::PushItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PushMultiItemsWidths(int components, float w_full) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiStyle& style = g.Style; + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidthStack.push_back(w_item_last); + for (int i = 0; i < components - 2; i++) + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PopItemWidth() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + window->DC.ItemWidthStack.pop_back(); +} + +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). +// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() +float ImGui::CalcItemWidth() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float w; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + w = g.NextItemData.Width; + else + w = window->DC.ItemWidth; + if (w < 0.0f) + { + float region_max_x = GetContentRegionMaxAbs().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + } + w = IM_FLOOR(w); + return w; +} + +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). +// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. +// Note that only CalcItemWidth() is publicly exposed. +// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 region_max; + if (size.x < 0.0f || size.y < 0.0f) + region_max = GetContentRegionMaxAbs(); + + if (size.x == 0.0f) + size.x = default_w; + else if (size.x < 0.0f) + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); + + if (size.y == 0.0f) + size.y = default_h; + else if (size.y < 0.0f) + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); + + return size; +} + +float ImGui::GetTextLineHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize; +} + +float ImGui::GetTextLineHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.ItemSpacing.y; +} + +float ImGui::GetFrameHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f; +} + +float ImGui::GetFrameHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! + +// FIXME: This is in window space (not screen space!). +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x - window->Pos.x; + return mx; +} + +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxAbs() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +// In window space (not screen space!) +ImVec2 ImGui::GetWindowContentRegionMin() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Min - window->Pos; +} + +ImVec2 ImGui::GetWindowContentRegionMax() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Max - window->Pos; +} + +// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) +// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. +// FIXME-OPT: Could we safely early out on ->SkipItems? +void ImGui::BeginGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + g.GroupStack.resize(g.GroupStack.Size + 1); + ImGuiGroupData& group_data = g.GroupStack.back(); + group_data.WindowID = window->ID; + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupIndent = window->DC.Indent; + group_data.BackupGroupOffset = window->DC.GroupOffset; + group_data.BackupCurrLineSize = window->DC.CurrLineSize; + group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.EmitItem = true; + + window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; + window->DC.Indent = window->DC.GroupOffset; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls + + ImGuiGroupData& group_data = g.GroupStack.back(); + IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window? + + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.Indent = group_data.BackupIndent; + window->DC.GroupOffset = group_data.BackupGroupOffset; + window->DC.CurrLineSize = group_data.BackupCurrLineSize; + window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return + + if (!group_data.EmitItem) + { + g.GroupStack.pop_back(); + return; + } + + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize()); + ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); + + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. + // Also if you grep for LastItemId you'll notice it is only used in that context. + // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) + const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; + const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); + if (group_contains_curr_active_id) + g.LastItemData.ID = g.ActiveId; + else if (group_contains_prev_active_id) + g.LastItemData.ID = g.ActiveIdPreviousFrame; + g.LastItemData.Rect = group_bb; + + // Forward Hovered flag + const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0; + if (group_contains_curr_hovered_id) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + + // Forward Edited flag + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; + + // Forward Deactivated flag + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated; + + g.GroupStack.pop_back(); + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +} + + +//----------------------------------------------------------------------------- +// [SECTION] SCROLLING +//----------------------------------------------------------------------------- + +// Helper to snap on edges when aiming at an item very close to the edge, +// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. +// When we refactor the scrolling API this may be configurable with a flag? +// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. +static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) +{ + if (target <= snap_min + snap_threshold) + return ImLerp(snap_min, target, center_ratio); + if (target >= snap_max - snap_threshold) + return ImLerp(target, snap_max, center_ratio); + return target; +} + +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) +{ + ImVec2 scroll = window->Scroll; + ImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2); + for (int axis = 0; axis < 2; axis++) + { + if (window->ScrollTarget[axis] < FLT_MAX) + { + float center_ratio = window->ScrollTargetCenterRatio[axis]; + float scroll_target = window->ScrollTarget[axis]; + if (window->ScrollTargetEdgeSnapDist[axis] > 0.0f) + { + float snap_min = 0.0f; + float snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis]; + scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio); + } + scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); + } + scroll[axis] = IM_FLOOR(ImMax(scroll[axis], 0.0f)); + if (!window->Collapsed && !window->SkipItems) + scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); + } + return scroll; +} + +void ImGui::ScrollToItem(ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ScrollToRectEx(window, g.LastItemData.NavRect, flags); +} + +void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ScrollToRectEx(window, item_rect, flags); +} + +// Scroll to keep newly navigated item fully into view +ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x); + scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y); + //GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG] + //GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG] + + // Check that only one behavior is selected per axis + IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_)); + IM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_)); + + // Defaults + ImGuiScrollFlags in_flags = flags; + if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX) + flags |= ImGuiScrollFlags_KeepVisibleEdgeX; + if ((flags & ImGuiScrollFlags_MaskY_) == 0) + flags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY; + + const bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x; + const bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y; + const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; + const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x) + { + if (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x) + SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f); + else if (item_rect.Max.x >= scroll_rect.Max.x) + SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX)) + { + if (can_be_fully_visible_x) + SetScrollFromPosX(window, ImFloor((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f); + else + SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f); + } + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y) + { + if (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y) + SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f); + else if (item_rect.Max.y >= scroll_rect.Max.y) + SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY)) + { + if (can_be_fully_visible_y) + SetScrollFromPosY(window, ImFloor((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f); + else + SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f); + } + + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + ImVec2 delta_scroll = next_scroll - window->Scroll; + + // Also scroll parent window to keep us into view if necessary + if (!(flags & ImGuiScrollFlags_NoScrollParent) && (window->Flags & ImGuiWindowFlags_ChildWindow)) + { + // FIXME-SCROLL: May be an option? + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterX | ImGuiScrollFlags_KeepVisibleCenterX)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX; + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterY | ImGuiScrollFlags_KeepVisibleCenterY)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskY_) | ImGuiScrollFlags_KeepVisibleEdgeY; + delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags); + } + + return delta_scroll; +} + +float ImGui::GetScrollX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.x; +} + +float ImGui::GetScrollY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.x; +} + +float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.y; +} + +void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x) +{ + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y) +{ + window->ScrollTarget.y = scroll_y; + window->ScrollTargetCenterRatio.y = 0.0f; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollX(float scroll_x) +{ + ImGuiContext& g = *GImGui; + SetScrollX(g.CurrentWindow, scroll_x); +} + +void ImGui::SetScrollY(float scroll_y) +{ + ImGuiContext& g = *GImGui; + SetScrollY(g.CurrentWindow, scroll_y); +} + +// Note that a local position will vary depending on initial scroll value, +// This is a little bit confusing so bear with us: +// - local_pos = (absolution_pos - window->Pos) +// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window, +// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area. +// - They mostly exist because of legacy API. +// Following the rules above, when trying to work with scrolling code, consider that: +// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect! +// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense +// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size +void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) +{ + IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); + window->ScrollTarget.x = IM_FLOOR(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.x = center_x_ratio; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) +{ + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + window->ScrollTarget.y = IM_FLOOR(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.y = center_y_ratio; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); +} + +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); +} + +// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x); + float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio); + SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); +} + +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y); + float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); + SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); +} + +//----------------------------------------------------------------------------- +// [SECTION] TOOLTIPS +//----------------------------------------------------------------------------- + +bool ImGui::BeginTooltip() +{ + return BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); +} + +bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) +{ + ImGuiContext& g = *GImGui; + + if (g.DragDropWithinSource || g.DragDropWithinTarget) + { + // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) + // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. + // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. + //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( + tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; + } + + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + SetWindowHiddendAndSkipItemsForCurrentFrame(window); + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; + Begin(window_name, NULL, flags | extra_window_flags); + // 2023-03-09: Added bool return value to the API, but currently always returning true. + // If this ever returns false we need to update BeginDragDropSource() accordingly. + //if (!ret) + // End(); + //return ret; + return true; +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls + End(); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None)) + return; + TextV(fmt, args); + EndTooltip(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// [SECTION] POPUPS +//----------------------------------------------------------------------------- + +// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel +bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + if (popup_flags & ImGuiPopupFlags_AnyPopupId) + { + // Return true if any popup is open at the current BeginPopup() level of the popup stack + // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level. + IM_ASSERT(id == 0); + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + return g.OpenPopupStack.Size > 0; + else + return g.OpenPopupStack.Size > g.BeginPopupStack.Size; + } + else + { + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + { + // Return true if the popup is open anywhere in the popup stack + for (int n = 0; n < g.OpenPopupStack.Size; n++) + if (g.OpenPopupStack[n].PopupId == id) + return true; + return false; + } + else + { + // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query) + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; + } + } +} + +bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id); + if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0) + IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally + return IsPopupOpen(id, popup_flags); +} + +// Also see FindBlockingModal(NULL) +ImGuiWindow* ImGui::GetTopMostPopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if (popup->Flags & ImGuiWindowFlags_Modal) + return popup; + return NULL; +} + +// See Demo->Stacked Modal to confirm what this is for. +ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup)) + return popup; + return NULL; +} + +void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.CurrentWindow->GetID(str_id); + IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)\n", str_id, id); + OpenPopupEx(id, popup_flags); +} + +void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + OpenPopupEx(id, popup_flags); +} + +// Mark popup as open (toggle toward open state). +// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. +// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) +void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + const int current_stack_size = g.BeginPopupStack.Size; + + if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) + if (IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId)) + return; + + ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.BackupNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type). + popup_ref.OpenFrameCount = g.FrameCount; + popup_ref.OpenParentId = parent_window->IDStack.back(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + + IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui + // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing + // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. + if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) + { + g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; + } + else + { + // Close child popups if any, then flag popup for open/reopen + ClosePopupToLevel(current_stack_size, false); + g.OpenPopupStack.push_back(popup_ref); + } + + // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). + // This is equivalent to what ClosePopupToLevel() does. + //if (g.OpenPopupStack[current_stack_size].PopupId == id) + // FocusWindow(parent_window); + } +} + +// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. +// This function closes any popups that are over 'ref_window'. +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size == 0) + return; + + // Don't close our own child popup windows. + int popup_count_to_keep = 0; + if (ref_window) + { + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + { + ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + + // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow) + // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3: + // Window -> Popup1 -> Popup2 -> Popup3 + // - Each popups may contain child windows, which is why we compare ->RootWindow! + // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child + bool ref_window_is_descendent_of_popup = false; + for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) + if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) + if (IsWindowWithinBeginStackOf(ref_window, popup_window)) + { + ref_window_is_descendent_of_popup = true; + break; + } + if (!ref_window_is_descendent_of_popup) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")\n", ref_window ? ref_window->Name : ""); + ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + } +} + +void ImGui::ClosePopupsExceptModals() +{ + ImGuiContext& g = *GImGui; + + int popup_count_to_keep; + for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--) + { + ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window; + if (!window || (window->Flags & ImGuiWindowFlags_Modal)) + break; + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + ClosePopupToLevel(popup_count_to_keep, true); +} + +void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup); + IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); + + // Trim open popup stack + ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; + ImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow; + g.OpenPopupStack.resize(remaining); + + if (restore_focus_to_window_under_popup) + { + ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window; + if (focus_window && !focus_window->WasActive && popup_window) + FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback + else + FocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None); + } +} + +// Close the popup we have begin-ed into. +void ImGui::CloseCurrentPopup() +{ + ImGuiContext& g = *GImGui; + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + return; + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +// Attention! BeginPopup() adds default flags which BeginPopupEx()! +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + char name[20]; + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + + flags |= ImGuiWindowFlags_Popup; + bool is_open = Begin(name, NULL, flags); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + ImGuiID id = g.CurrentWindow->GetID(str_id); + return BeginPopupEx(id, flags); +} + +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + // Center modal windows by default for increased visibility + // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) + // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + { + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + } + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse; + const bool is_open = Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + { + EndPopup(); + if (is_open) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + return false; + } + return is_open; +} + +void ImGui::EndPopup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.BeginPopupStack.Size > 0); + + // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) + if (g.NavWindow == window) + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + + // Child-popups don't need to be laid out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +// Helper to open a popup if mouse button is released over the item +// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() +void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + OpenPopupEx(id, popup_flags); + } +} + +// This is a helper to handle the simplest case of associating one named popup to one given widget. +// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. +// - To create a popup with a specific identifier, pass it in str_id. +// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. +// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// This is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight); +// return BeginPopup(id); +// Which is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) +// OpenPopup(id); +// return BeginPopup(id); +// The main difference being that this is tweaked to avoid computing the ID twice. +bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "window_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "void_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + if (GetTopMostPopupModal() == NULL) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) +// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor +// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. +// this allows us to have tooltips/popups displayed out of the parent viewport.) +ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +{ + ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + + // Combo Box policy (we want a connecting edge) + if (policy == ImGuiPopupPositionPolicy_ComboBox) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + // Tooltip and Default popup policy + // (Always first try the direction we used on the last frame, if any) + if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + + const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + + // If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) + if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) + continue; + if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) + continue; + + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; + + // Clamp top-left corner of popup + pos.x = ImMax(pos.x, r_outer.Min.x); + pos.y = ImMax(pos.y, r_outer.Min.y); + + *last_dir = dir; + return pos; + } + } + + // Fallback when not enough room: + *last_dir = ImGuiDir_None; + + // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + if (policy == ImGuiPopupPositionPolicy_Tooltip) + return ref_pos + ImVec2(2, 2); + + // Otherwise try to keep within display + ImVec2 pos = ref_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; +} + +// Note that this is used for popups, which can overlap the non work-area of individual viewports. +ImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(window); + ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect(); + ImVec2 padding = g.Style.DisplaySafeAreaPadding; + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + return r_screen; +} + +ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + ImRect r_outer = GetPopupAllowedExtentRect(window); + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. + // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. + IM_ASSERT(g.CurrentWindow == window); + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window; + float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). + ImRect r_avoid; + if (parent_window->DC.MenuBarAppending) + r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field + else + r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); + } + if (window->Flags & ImGuiWindowFlags_Popup) + { + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Position tooltip (always follows mouse) + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); + ImRect r_avoid; + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); + else + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); + } + IM_ASSERT(0); + return window->Pos; +} + +//----------------------------------------------------------------------------- +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +//----------------------------------------------------------------------------- + +// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked. +// In our terminology those should be interchangeable, yet right now this is super confusing. +// Those two functions are merely a legacy artifact, so at minimum naming should be clarified. + +void ImGui::SetNavWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.NavWindow != window) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : ""); + g.NavWindow = window; + } + g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX; +} + +void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu); + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = focus_scope_id; + g.NavWindow->NavLastIds[nav_layer] = id; + g.NavWindow->NavRectRel[nav_layer] = rect_rel; + + // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); +} + +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + if (g.NavWindow != window) + SetNavWindow(window); + + // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid. + // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text) + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = g.CurrentFocusScopeId; + window->NavLastIds[nav_layer] = id; + if (g.LastItemData.ID == id) + window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); + + if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; + + // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); +} + +static ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +{ + if (ImFabs(dx) > ImFabs(dy)) + return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; + return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; +} + +static float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max) +{ + if (cand_max < curr_min) + return cand_max - curr_min; + if (curr_max < cand_min) + return cand_min - curr_max; + return 0.0f; +} + +// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 +static bool ImGui::NavScoreItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + // FIXME: Those are not good variables names + ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle + const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) + g.NavScoringDebugCount++; + + // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring + if (window->ParentWindow == g.NavWindow) + { + IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); + if (!window->ClipRect.Overlaps(cand)) + return false; + cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + } + + // Compute distance between boxes + // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. + float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); + float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items + if (dby != 0.0f && dbx != 0.0f) + dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); + float dist_box = ImFabs(dbx) + ImFabs(dby); + + // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) + float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); + float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); + float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) + + // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + // For non-overlapping boxes, use distance between boxes + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + // For overlapping boxes with different centers, use distance between centers + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) + quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + + const ImGuiDir move_dir = g.NavMoveDir; +#if IMGUI_DEBUG_NAV_SCORING + char buf[200]; + if (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate. + { + if (quadrant == move_dir) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 80)); + draw_list->AddRectFilled(cand.Min, cand.Min + CalcTextSize(buf), IM_COL32(255, 0, 0, 200)); + draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } + const bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max); + const bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space)); + if (debug_hovering || debug_tty) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), + "d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c", + dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "-WENS"[move_dir+1], "-WENS"[quadrant+1]); + if (debug_hovering) + { + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200)); + draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200)); + draw_list->AddText(cand.Max, ~0U, buf); + } + if (debug_tty) { IMGUI_DEBUG_LOG_NAV("id 0x%08X\n%s\n", g.LastItemData.ID, buf); } + } +#endif + + // Is it in the quadrant we're interested in moving to? + bool new_best = false; + if (quadrant == move_dir) + { + // Does it beat the current best candidate? + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + // Try using distance between center points to break ties + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items + // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), + // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. + if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance + new_best = true; + } + } + } + + // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches + // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) + // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. + // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. + // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match + if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + result->Window = window; + result->ID = g.LastItemData.ID; + result->FocusScopeId = g.CurrentFocusScopeId; + result->InFlags = g.LastItemData.InFlags; + result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); +} + +// True when current work location may be scrolled horizontally when moving left / right. +// This is generally always true UNLESS within a column. We don't have a vertical equivalent. +void ImGui::NavUpdateCurrentWindowIsScrollPushableX() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL); +} + +// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) +// This is called after LastItemData is set. +static void ImGui::NavProcessItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = g.LastItemData.ID; + const ImGuiItemFlags item_flags = g.LastItemData.InFlags; + + // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) + if (window->DC.NavIsScrollPushableX == false) + { + g.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + g.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + } + const ImRect nav_bb = g.LastItemData.NavRect; + + // Process Init Request + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0) + { + // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback + const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0; + if (candidate_for_nav_default_focus || g.NavInitResult.ID == 0) + { + NavApplyItemToResult(&g.NavInitResult); + } + if (candidate_for_nav_default_focus) + { + g.NavInitRequest = false; // Found a match, clear request + NavUpdateAnyRequestFlag(); + } + } + + // Process Move Request (scoring for navigation) + // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy) + if (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0) + { + const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) != 0; + if (is_tabbing) + { + NavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags); + } + else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) + { + ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + if (NavScoreItem(result)) + NavApplyItemToResult(result); + + // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisible)) + NavApplyItemToResult(&g.NavMoveResultLocalVisible); + } + } + + // Update information for currently focused/navigated item + if (g.NavId == id) + { + if (g.NavWindow != window) + SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window. + g.NavLayer = window->DC.NavLayerCurrent; + g.NavFocusScopeId = g.CurrentFocusScopeId; + g.NavIdIsAlive = true; + window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) + } +} + +// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest(). +// Note that SetKeyboardFocusHere() API calls are considered tabbing requests! +// - Case 1: no nav/active id: set result to first eligible item, stop storing. +// - Case 2: tab forward: on ref id set counter, on counter elapse store result +// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request +// - Case 4: tab backward: store all results, on ref id pick prev, stop storing +// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested +void ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + + if ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0) + if (g.NavLayer != g.CurrentWindow->DC.NavLayerCurrent) + return; + + // - Can always land on an item when using API call. + // - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item. + // - Tabbing without _NavEnableKeyboard: goes through inputable items only. + bool can_stop; + if (move_flags & ImGuiNavMoveFlags_FocusApi) + can_stop = true; + else + can_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable)); + + // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows) + ImGuiNavItemData* result = &g.NavMoveResultLocal; + if (g.NavTabbingDir == +1) + { + // Tab Forward or SetKeyboardFocusHere() with >= 0 + if (can_stop && g.NavTabbingResultFirst.ID == 0) + NavApplyItemToResult(&g.NavTabbingResultFirst); + if (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0) + NavMoveRequestResolveWithLastItem(result); + else if (g.NavId == id) + g.NavTabbingCounter = 1; + } + else if (g.NavTabbingDir == -1) + { + // Tab Backward + if (g.NavId == id) + { + if (result->ID) + { + g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); + } + } + else if (can_stop) + { + // Keep applying until reaching NavId + NavApplyItemToResult(result); + } + } + else if (g.NavTabbingDir == 0) + { + if (can_stop && g.NavId == id) + NavMoveRequestResolveWithLastItem(result); + if (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init + NavApplyItemToResult(&g.NavTabbingResultFirst); + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +// FIXME: ScoringRect is not set +void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + + if (move_flags & ImGuiNavMoveFlags_Tabbing) + move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; + + g.NavMoveSubmitted = g.NavMoveScoringItems = true; + g.NavMoveDir = move_dir; + g.NavMoveDirForDebug = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags; + g.NavMoveScrollFlags = scroll_flags; + g.NavMoveForwardToNextFrame = false; + g.NavMoveKeyMods = g.IO.KeyMods; + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisible.Clear(); + g.NavMoveResultOther.Clear(); + g.NavTabbingCounter = 0; + g.NavTabbingResultFirst.Clear(); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + g.NavMoveScoringItems = false; // Ensure request doesn't need more processing + NavApplyItemToResult(result); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); +} + +// Forward will reuse the move request again on the next frame (generally with modifications done to it) +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveForwardToNextFrame == false); + NavMoveRequestCancel(); + g.NavMoveForwardToNextFrame = true; + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded; + g.NavMoveScrollFlags = scroll_flags; +} + +// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire +// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT((wrap_flags & ImGuiNavMoveFlags_WrapMask_ ) != 0 && (wrap_flags & ~ImGuiNavMoveFlags_WrapMask_) == 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY + + // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it: + // as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest(). + if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) + g.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags; +} + +// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). +// This way we could find the last focused window among our children. It would be much less confusing this way? +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent = nav_window; + while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent = parent->ParentWindow; + if (parent && parent != nav_window) + parent->NavLastChildNavWindow = nav_window; +} + +// Restore the last focused child. +// Call when we are expected to land on the Main Layer (0) after FocusWindow() +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + return window; +} + +void ImGui::NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + if (layer == ImGuiNavLayer_Main) + { + ImGuiWindow* prev_nav_window = g.NavWindow; + g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests? + if (prev_nav_window) + IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name); + } + ImGuiWindow* window = g.NavWindow; + if (window->NavLastIds[layer] != 0) + { + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + } + else + { + g.NavLayer = layer; + NavInitWindow(window, true); + } +} + +void ImGui::NavRestoreHighlightAfterMove() +{ + ImGuiContext& g = *GImGui; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +// This needs to be called before we submit any widget (aka in or before Begin) +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + + if (window->Flags & ImGuiWindowFlags_NoNavInputs) + { + g.NavId = 0; + g.NavFocusScopeId = window->NavRootFocusScopeId; + return; + } + + bool init_for_nav = false; + if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + if (init_for_nav) + { + SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect()); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResult.ID = 0; + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + g.NavFocusScopeId = window->NavRootFocusScopeId; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window) + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard. + // In theory we could move that +1.0f offset in OpenPopupEx() + ImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLastValidPos; + return ImVec2(p.x + 1.0f, p.y); + } + else + { + // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item + // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?) + ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]); + if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX)) + { + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + rect_rel.Translate(window->Scroll - next_scroll); + } + ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImGuiViewport* viewport = GetMainViewport(); + return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. + } +} + +float ImGui::GetNavTweakPressedAmount(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + float repeat_delay, repeat_rate; + GetTypematicRepeatRate(ImGuiInputFlags_RepeatRateNavTweak, &repeat_delay, &repeat_rate); + + ImGuiKey key_less, key_more; + if (g.NavInputSource == ImGuiInputSource_Gamepad) + { + key_less = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadLeft : ImGuiKey_GamepadDpadUp; + key_more = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadRight : ImGuiKey_GamepadDpadDown; + } + else + { + key_less = (axis == ImGuiAxis_X) ? ImGuiKey_LeftArrow : ImGuiKey_UpArrow; + key_more = (axis == ImGuiAxis_X) ? ImGuiKey_RightArrow : ImGuiKey_DownArrow; + } + float amount = (float)GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - (float)GetKeyPressedAmount(key_less, repeat_delay, repeat_rate); + if (amount != 0.0f && IsKeyDown(key_less) && IsKeyDown(key_more)) // Cancel when opposite directions are held, regardless of repeat phase + amount = 0.0f; + return amount; +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + io.WantSetMousePos = false; + //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV("[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); + + // Set input source based on which keys are last pressed (as some features differs when used with Gamepad vs Keyboard) + // FIXME-NAV: Now that keys are separated maybe we can get rid of NavInputSource? + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const ImGuiKey nav_gamepad_keys_to_change_source[] = { ImGuiKey_GamepadFaceRight, ImGuiKey_GamepadFaceLeft, ImGuiKey_GamepadFaceUp, ImGuiKey_GamepadFaceDown, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown }; + if (nav_gamepad_active) + for (ImGuiKey key : nav_gamepad_keys_to_change_source) + if (IsKeyDown(key)) + g.NavInputSource = ImGuiInputSource_Gamepad; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + const ImGuiKey nav_keyboard_keys_to_change_source[] = { ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, ImGuiKey_RightArrow, ImGuiKey_LeftArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow }; + if (nav_keyboard_active) + for (ImGuiKey key : nav_keyboard_keys_to_change_source) + if (IsKeyDown(key)) + g.NavInputSource = ImGuiInputSource_Keyboard; + + // Process navigation init request (select first/default focus) + g.NavJustMovedToId = 0; + if (g.NavInitResult.ID != 0) + NavInitRequestApplyResult(); + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResult.ID = 0; + + // Process navigation move request + if (g.NavMoveSubmitted) + NavMoveRequestApplyResult(); + g.NavTabbingCounter = 0; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + + // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) + bool set_mouse_pos = false; + if (g.NavMousePosDirty && g.NavIdIsAlive) + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + set_mouse_pos = true; + g.NavMousePosDirty = false; + IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); + + // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow) + NavSaveLastChildNavWindowIntoParent(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) + g.NavWindow->NavLastChildNavWindow = NULL; + + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) + NavUpdateWindowing(); + + // Set output flags for user application + io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); + io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + + // Process NavCancel input (to close a popup, get back to parent, clear focus) + NavUpdateCancelRequest(); + + // Process manual activation request + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0; + g.NavActivateFlags = ImGuiActivateFlags_None; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate)); + const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false))); + const bool input_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Enter)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput)); + const bool input_pressed = input_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Enter, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, false))); + if (g.ActiveId == 0 && activate_pressed) + { + g.NavActivateId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferTweak; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed) + { + g.NavActivateId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down)) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed)) + g.NavActivatePressedId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + + // Process programmatic activation request + // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others) + if (g.NavNextActivateId != 0) + { + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; + g.NavActivateFlags = g.NavNextActivateFlags; + } + g.NavNextActivateId = 0; + + // Process move requests + NavUpdateCreateMoveRequest(); + if (g.NavMoveDir == ImGuiDir_None) + NavUpdateCreateTabbingRequest(); + NavUpdateAnyRequestFlag(); + g.NavIdIsAlive = false; + + // Scrolling + if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + // *Fallback* manual-scroll with Nav directional keys when window has no navigable item + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const ImGuiDir move_dir = g.NavMoveDir; + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) + { + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) + SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + // *Normal* Manual scroll with LStick + // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. + if (nav_gamepad_active) + { + const ImVec2 scroll_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + const float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f; + if (scroll_dir.x != 0.0f && window->ScrollbarX) + SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor)); + if (scroll_dir.y != 0.0f) + SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed * tweak_factor)); + } + } + + // Always prioritize mouse highlight if navigation is disabled + if (!nav_keyboard_active && !nav_gamepad_active) + { + g.NavDisableHighlight = true; + g.NavDisableMouseHover = set_mouse_pos = false; + } + + // Update mouse position if requested + // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied) + if (set_mouse_pos && (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); + io.WantSetMousePos = true; + //IMGUI_DEBUG_LOG_IO("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); + } + + // [DEBUG] + g.NavScoringDebugCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (ImGuiWindow* debug_window = g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(debug_window); + int layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); } + //if (1) { ImU32 col = (!debug_window->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + } +#endif +} + +void ImGui::NavInitRequestApplyResult() +{ + // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) + ImGuiContext& g = *GImGui; + if (!g.NavWindow) + return; + + ImGuiNavItemData* result = &g.NavInitResult; + if (g.NavId != result->ID) + { + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = 0; + } + + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result + if (g.NavInitRequestFromMove) + NavRestoreHighlightAfterMove(); +} + +// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position +static void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags) +{ + // Bias initial rect + ImGuiContext& g = *GImGui; + const ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos; + + // Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias. + // - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column. + // - But each successful move sets new bias on one axis, only cleared when using mouse. + if ((move_flags & ImGuiNavMoveFlags_Forwarded) == 0) + { + if (preferred_pos_rel.x == FLT_MAX) + preferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x; + if (preferred_pos_rel.y == FLT_MAX) + preferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y; + } + + // Apply general bias on the other axis + if ((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) && preferred_pos_rel.x != FLT_MAX) + r.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x; + else if ((move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) && preferred_pos_rel.y != FLT_MAX) + r.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y; +} + +void ImGui::NavUpdateCreateMoveRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiWindow* window = g.NavWindow; + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + + if (g.NavMoveForwardToNextFrame && window != NULL) + { + // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) + // (preserve most state, which were already set by the NavMoveRequestForward() function) + IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); + IM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); + } + else + { + // Initiate directional inputs request + g.NavMoveDir = ImGuiDir_None; + g.NavMoveFlags = ImGuiNavMoveFlags_None; + g.NavMoveScrollFlags = ImGuiScrollFlags_None; + if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const ImGuiInputFlags repeat_mode = ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateNavMove; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadDown, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_DownArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Down; } + } + g.NavMoveClipDir = g.NavMoveDir; + g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + } + + // Update PageUp/PageDown/Home/End scroll + // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? + float scoring_rect_offset_y = 0.0f; + if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active) + scoring_rect_offset_y = NavUpdatePageUpPageDown(); + if (scoring_rect_offset_y != 0.0f) + { + g.NavScoringNoClipRect = window->InnerRect; + g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y); + } + + // [DEBUG] Always send a request when holding CTRL. Hold CTRL + Arrow change the direction. +#if IMGUI_DEBUG_NAV_SCORING + //if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C)) + // g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); + if (io.KeyCtrl) + { + if (g.NavMoveDir == ImGuiDir_None) + g.NavMoveDir = g.NavMoveDirForDebug; + g.NavMoveClipDir = g.NavMoveDir; + g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; + } +#endif + + // Submit + g.NavMoveForwardToNextFrame = false; + if (g.NavMoveDir != ImGuiDir_None) + NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); + + // Moving with no reference triggers an init request (will be used as a fallback if the direction fails to find a match) + if (g.NavMoveSubmitted && g.NavId == 0) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); + g.NavInitRequest = g.NavInitRequestFromMove = true; + g.NavInitResult.ID = 0; + g.NavDisableHighlight = false; + } + + // When using gamepad, we project the reference nav bounding box into window visible area. + // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, + // since with gamepad all movements are relative (can't focus a visible object like we can with the mouse). + if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded)) + { + bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0; + bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0; + ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1))); + + // Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171) + // Otherwise 'inner_rect_rel' would be off on the move result frame. + inner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll); + + if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); + float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f); + float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item + inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX; + inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX; + inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX; + inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX; + window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel); + g.NavId = 0; + } + } + + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) + ImRect scoring_rect; + if (window != NULL) + { + ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); + scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); + scoring_rect.TranslateY(scoring_rect_offset_y); + if (g.NavMoveSubmitted) + NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags); + IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem(). + //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] + //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] + } + g.NavScoringRect = scoring_rect; + g.NavScoringNoClipRect.Add(scoring_rect); +} + +void ImGui::NavUpdateCreateTabbingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + IM_ASSERT(g.NavMoveDir == ImGuiDir_None); + if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs)) + return; + + const bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat) && !g.IO.KeyCtrl && !g.IO.KeyAlt; + if (!tab_pressed) + return; + + // Initiate tabbing request + // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!) + // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests. + // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. + const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + if (nav_keyboard_active) + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1; + else + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down; + NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + g.NavTabbingCounter = -1; +} + +// Apply result from previous frame navigation directional move request. Always called from NavUpdate() +void ImGui::NavMoveRequestApplyResult() +{ + ImGuiContext& g = *GImGui; +#if IMGUI_DEBUG_NAV_SCORING + if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times + return; +#endif + + // Select which result to use + ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL; + + // Tabbing forward wrap + if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && result == NULL) + if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID) + result = &g.NavTabbingResultFirst; + + // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) + const ImGuiAxis axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + if (result == NULL) + { + if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); + NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis. + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); + return; + } + + // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. + if (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId) + result = &g.NavMoveResultLocalVisible; + + // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. + if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) + if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) + result = &g.NavMoveResultOther; + IM_ASSERT(g.NavWindow && result->Window); + + // Scroll to keep newly navigated item fully into view. + if (g.NavLayer == ImGuiNavLayer_Main) + { + ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel); + ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags); + + if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY) + { + // FIXME: Should remove this? Or make more precise: use ScrollToRectEx() with edge? + float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; + SetScrollY(result->Window, scroll_target); + } + } + + if (g.NavWindow != result->Window) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name); + g.NavWindow = result->Window; + } + if (g.ActiveId != result->ID) + ClearActiveID(); + if (g.NavId != result->ID) + { + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = g.NavMoveKeyMods; + } + + // Apply new NavID/Focus + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer]; + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + + // Restore last preferred position for current axis + // (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..) + if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) == 0) + { + preferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis]; + g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel; + } + + // Tabbing: Activates Inputable or Focus non-Inputable + if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && (result->InFlags & ImGuiItemFlags_Inputable)) + { + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState; + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; + } + + // Activate + if (g.NavMoveFlags & ImGuiNavMoveFlags_Activate) + { + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_None; + } + + // Enable nav highlight + if ((g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); +} + +// Process NavCancel input (to close a popup, get back to parent, clear focus) +// FIXME: In order to support e.g. Escape to clear a selection we'll need: +// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it. +// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept +static void ImGui::NavUpdateCancelRequest() +{ + ImGuiContext& g = *GImGui; + const bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + if (!(nav_keyboard_active && IsKeyPressed(ImGuiKey_Escape, ImGuiKeyOwner_None)) && !(nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, ImGuiKeyOwner_None))) + return; + + IMGUI_DEBUG_LOG_NAV("[nav] NavUpdateCancelRequest()\n"); + if (g.ActiveId != 0) + { + ClearActiveID(); + } + else if (g.NavLayer != ImGuiNavLayer_Main) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + NavRestoreHighlightAfterMove(); + } + else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + { + // Exit child window + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + ImRect child_rect = child_window->Rect(); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect)); + NavRestoreHighlightAfterMove(); + } + else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + { + // Close open popup/menu + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else + { + // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = 0; + } +} + +// Handle PageUp/PageDown/Home/End keys +// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request +// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference +// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid? +static float ImGui::NavUpdatePageUpPageDown() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL) + return 0.0f; + + const bool page_up_held = IsKeyDown(ImGuiKey_PageUp, ImGuiKeyOwner_None); + const bool page_down_held = IsKeyDown(ImGuiKey_PageDown, ImGuiKeyOwner_None); + const bool home_pressed = IsKeyPressed(ImGuiKey_Home, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat); + const bool end_pressed = IsKeyPressed(ImGuiKey_End, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat); + if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out + return 0.0f; + + if (g.NavLayer != ImGuiNavLayer_Main) + NavRestoreLayer(ImGuiNavLayer_Main); + + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY) + { + // Fallback manual-scroll when window has no navigable item + if (IsKeyPressed(ImGuiKey_PageUp, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) + SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); + else if (IsKeyPressed(ImGuiKey_PageDown, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) + SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); + else if (home_pressed) + SetScrollY(window, 0.0f); + else if (end_pressed) + SetScrollY(window, window->ScrollMax.y); + } + else + { + ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + float nav_scoring_rect_offset_y = 0.0f; + if (IsKeyPressed(ImGuiKey_PageUp, true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (IsKeyPressed(ImGuiKey_PageDown, true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (home_pressed) + { + // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y + // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result. + // Preserve current horizontal position if we have any. + nav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + else if (end_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + return nav_scoring_rect_offset_y; + } + return 0.0f; +} + +static void ImGui::NavEndFrame() +{ + ImGuiContext& g = *GImGui; + + // Show CTRL+TAB list window + if (g.NavWindowingTarget != NULL) + NavUpdateWindowingOverlay(); + + // Perform wrap-around in menus + // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly. + // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame. + if (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & ImGuiNavMoveFlags_WrapMask_) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + NavUpdateCreateWrappingRequest(); +} + +static void ImGui::NavUpdateCreateWrappingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + + bool do_forward = false; + ImRect bb_rel = window->NavRectRel[g.NavLayer]; + ImGuiDir clip_dir = g.NavMoveDir; + + const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; + //const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row + clip_dir = ImGuiDir_Up; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(+bb_rel.GetHeight()); // Next row + clip_dir = ImGuiDir_Down; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column + clip_dir = ImGuiDir_Left; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column + clip_dir = ImGuiDir_Right; + } + do_forward = true; + } + if (!do_forward) + return; + window->NavRectRel[g.NavLayer] = bb_rel; + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); + NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) + if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) + return g.WindowsFocusOrder[i]; + return NULL; +} + +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget); + if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) + return; + + const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); + ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); + if (!window_target) + window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); + if (window_target) // Don't reset windowing target if there's a single window in the list + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); + } + g.NavWindowingToggleLayer = false; +} + +// Windowing management mode +// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) +// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + bool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows that are inside the Begin-stack of that modal. + if (!allow_windowing) + g.NavWindowingTarget = NULL; + + // Fade out + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + // Start CTRL+Tab or Square+L/R window selection + const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing"); + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None); + const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! + if (start_windowing_with_gamepad || start_windowing_with_keyboard) + if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; + g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; + g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); + g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; + + // Register ownership of our mods. Using ImGuiInputFlags_RouteGlobalHigh in the Shortcut() calls instead would probably be correct but may have more side-effects. + if (keyboard_next_window || keyboard_prev_window) + SetKeyOwnersForKeyChord((g.ConfigNavWindowingKeyNext | g.ConfigNavWindowingKeyPrev) & ImGuiMod_Mask_, owner_id); + } + + // Gamepad update + g.NavWindowingTimer += io.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) + { + // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } - // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard) - bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; - bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; - if (nav_gamepad_active) - if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f) - g.NavInputSource = ImGuiInputSource_NavGamepad; + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) + if (!IsKeyDown(ImGuiKey_NavGamepadMenu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } - // Update Keyboard->Nav inputs mapping - if (nav_keyboard_active) + // Keyboard: Focus + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) { - #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0) - NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); - NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); - NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); - NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); - NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); - NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); - NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); - if (g.IO.KeyCtrl) - g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; - if (g.IO.KeyShift) - g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; - if (g.IO.KeyAlt && !g.IO.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu. - g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; - #undef NAV_MAP_KEY + // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise + ImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_; + IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows. + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f + if (keyboard_next_window || keyboard_prev_window) + NavUpdateWindowingHighlightWindow(keyboard_next_window ? -1 : +1); + else if ((io.KeyMods & shared_mods) != shared_mods) + apply_focus_window = g.NavWindowingTarget; } - memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); - for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) - g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; - // Process navigation init request (select first/default focus) - // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) - if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow) + // Keyboard: Press and Release ALT to toggle menu layer + // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer. + // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway. + if (nav_keyboard_active && IsKeyPressed(ImGuiMod_Alt, ImGuiKeyOwner_None)) { - // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) - //IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); - if (g.NavInitRequestFromMove) - SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel); - else - SetNavID(g.NavInitResultId, g.NavLayer); - g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; + g.NavWindowingToggleLayer = true; + g.NavInputSource = ImGuiInputSource_Keyboard; } - g.NavInitRequest = false; - g.NavInitRequestFromMove = false; - g.NavInitResultId = 0; - g.NavJustMovedToId = 0; - - // Process navigation move request - if (g.NavMoveRequest) - NavUpdateMoveResult(); - - // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame - if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) + if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) { - IM_ASSERT(g.NavMoveRequest); - if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) - g.NavDisableHighlight = false; - g.NavMoveRequestForward = ImGuiNavForward_None; + // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) + // We cancel toggling nav layer when other modifiers are pressed. (See #4439) + // We cancel toggling nav layer if an owner has claimed the key. + if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_None) == false) + g.NavWindowingToggleLayer = false; + + // Apply layer toggle on release + // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss. + if (IsKeyReleased(ImGuiMod_Alt) && g.NavWindowingToggleLayer) + if (g.ActiveId == 0 || g.ActiveIdAllowOverlap) + if (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev)) + apply_toggle_layer = true; + if (!IsKeyDown(ImGuiMod_Alt)) + g.NavWindowingToggleLayer = false; } - // Apply application mouse position movement, after we had a chance to process move request result. - if (g.NavMousePosDirty && g.NavIdIsAlive) + // Move window + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) { - // Set mouse position given our knowledge of the navigated item position from last frame - if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + ImVec2 nav_move_dir; + if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift) + nav_move_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + nav_move_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f) { - if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + const float NAV_MOVE_SPEED = 800.0f; + const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + g.NavWindowingAccumDeltaPos += nav_move_dir * move_step; + g.NavDisableMouseHover = true; + ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaPos); + if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) { - g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos(); - g.IO.WantSetMousePos = true; + ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow; + SetWindowPos(moving_window, moving_window->Pos + accum_floored, ImGuiCond_Always); + g.NavWindowingAccumDeltaPos -= accum_floored; } } - g.NavMousePosDirty = false; } - g.NavIdIsAlive = false; - g.NavJustTabbedId = 0; - IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); - - // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 - if (g.NavWindow) - NavSaveLastChildNavWindowIntoParent(g.NavWindow); - if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) - g.NavWindow->NavLastChildNavWindow = NULL; - // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) - NavUpdateWindowing(); + // Apply final focus + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) + { + ClearActiveID(); + NavRestoreHighlightAfterMove(); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); + apply_focus_window = g.NavWindow; + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); - // Set output flags for user application - g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); - g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + // If the window has ONLY a menu layer (no main layer), select it directly + // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, + // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since + // the target window as already been previewed once. + // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, + // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* + // won't be valid. + if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; - // Process NavCancel input (to close a popup, get back to parent, clear focus) - if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + // Apply menu/layer toggle + if (apply_toggle_layer && g.NavWindow) { - if (g.ActiveId != 0) - { - if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) - ClearActiveID(); - } - else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) - { - // Exit child window - ImGuiWindow* child_window = g.NavWindow; - ImGuiWindow* parent_window = g.NavWindow->ParentWindow; - IM_ASSERT(child_window->ChildId != 0); - FocusWindow(parent_window); - SetNavID(child_window->ChildId, 0); - g.NavIdIsAlive = false; - if (g.NavDisableMouseHover) - g.NavMousePosDirty = true; - } - else if (g.OpenPopupStack.Size > 0) - { - // Close open popup/menu - if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) - ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); - } - else if (g.NavLayer != 0) + ClearActiveID(); + + // Move to parent menu if necessary + ImGuiWindow* new_nav_window = g.NavWindow; + while (new_nav_window->ParentWindow + && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + new_nav_window = new_nav_window->ParentWindow; + if (new_nav_window != g.NavWindow) { - // Leave the "menu" layer - NavRestoreLayer(ImGuiNavLayer_Main); + ImGuiWindow* old_nav_window = g.NavWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; } - else + + // Toggle layer + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + if (new_nav_layer != g.NavLayer) { - // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were - if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) - g.NavWindow->NavLastIds[0] = 0; - g.NavId = 0; + // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?) + if (new_nav_layer == ImGuiNavLayer_Menu) + g.NavWindow->NavLastIds[new_nav_layer] = 0; + NavRestoreLayer(new_nav_layer); + NavRestoreHighlightAfterMove(); } } +} - // Process manual activation request - g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; - if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingPopup); + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingMainMenuBar); + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingUntitled); +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingOverlay() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget != NULL); + + if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) + return; + + if (g.NavWindowingListWindow == NULL) + g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) { - bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); - bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); - if (g.ActiveId == 0 && activate_pressed) - g.NavActivateId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) - g.NavActivateDownId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) - g.NavActivatePressedId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) - g.NavInputId = g.NavId; + ImGuiWindow* window = g.WindowsFocusOrder[n]; + IM_ASSERT(window != NULL); // Fix static analyzers + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); } - if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) - g.NavDisableHighlight = true; - if (g.NavActivateId != 0) - IM_ASSERT(g.NavActivateDownId == g.NavActivateId); - g.NavMoveRequest = false; + End(); + PopStyleVar(); +} - // Process programmatic activation request - if (g.NavNextActivateId != 0) - g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; - g.NavNextActivateId = 0; - // Initiate directional inputs request - if (g.NavMoveRequestForward == ImGuiNavForward_None) +//----------------------------------------------------------------------------- +// [SECTION] DRAG AND DROP +//----------------------------------------------------------------------------- + +bool ImGui::IsDragDropActive() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive; +} + +void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropAcceptFrameCount = -1; + + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); +} + +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +// If the item has an identifier: +// - This assume/require the item to be activated (typically via ButtonBehavior). +// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button. +// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag. +// If the item has no identifier: +// - Currently always assume left mouse button. +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button, + // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic). + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) { - g.NavMoveDir = ImGuiDir_None; - g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; - if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + source_id = g.LastItemData.ID; + if (source_id != 0) { - const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; - if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } + // Common path: items with ID + if (g.ActiveId != source_id) + return false; + if (g.ActiveIdMouseButton != -1) + mouse_button = g.ActiveIdMouseButton; + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + g.ActiveIdAllowOverlap = false; } - g.NavMoveClipDir = g.NavMoveDir; + else + { + // Uncommon path: items without ID + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + // Rely on keeping other window->LastItemXXX fields intact. + source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); + KeepAliveID(source_id); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + + // Disable navigation and key inputs while dragging + cancel existing request if any + SetActiveIdUsingAllKeyboardKeys(); } else { - // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) - // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) - IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); - IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); - g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; + window = NULL; + source_id = ImHashStr("#SourceExtern"); + source_drag_active = true; } - // Update PageUp/PageDown/Home/End scroll - // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? - float nav_scoring_rect_offset_y = 0.0f; - if (nav_keyboard_active) - nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(); - - // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match - if (g.NavMoveDir != ImGuiDir_None) - { - g.NavMoveRequest = true; - g.NavMoveDirLast = g.NavMoveDir; - } - if (g.NavMoveRequest && g.NavId == 0) + if (source_drag_active) { - //IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); - g.NavInitRequest = g.NavInitRequestFromMove = true; - g.NavInitResultId = 0; - g.NavDisableHighlight = false; + if (!g.DragDropActive) + { + IM_ASSERT(source_id != 0); + ClearDragDrop(); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + if (payload.SourceId == g.ActiveId) + g.ActiveIdNoClearOnFocusLoss = true; + } + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSource = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + bool ret = BeginTooltip(); + IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame(). + IM_UNUSED(ret); + + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + SetWindowHiddendAndSkipItemsForCurrentFrame(g.CurrentWindow); + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; } - NavUpdateAnyRequestFlag(); + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?"); + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + EndTooltip(); + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSource = false; +} + +// Use 'cond' to choose to submit payload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() - // Scrolling - if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) { - // *Fallback* manual-scroll with Nav directional keys when window has no navigable item - ImGuiWindow* window = g.NavWindow; - const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * g.IO.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. - if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) - { - if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) - SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); - if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) - SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); - } - - // *Normal* Manual scroll with NavScrollXXX keys - // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. - ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f); - if (scroll_dir.x != 0.0f && window->ScrollbarX) + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) { - SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); - g.NavMoveFromClampedRefRect = true; + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); } - if (scroll_dir.y != 0.0f) + else if (data_size > 0) { - SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); - g.NavMoveFromClampedRefRect = true; + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy(payload.Data, data, data_size); } - } - - // Reset search results - g.NavMoveResultLocal.Clear(); - g.NavMoveResultLocalVisibleSet.Clear(); - g.NavMoveResultOther.Clear(); - - // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items - if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) - { - ImGuiWindow* window = g.NavWindow; - ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1)); - if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + else { - float pad = window->CalcFontSize() * 0.5f; - window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item - window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel); - g.NavId = 0; + payload.Data = NULL; } - g.NavMoveFromClampedRefRect = false; + payload.DataSize = (int)data_size; } + payload.DataFrameCount = g.FrameCount; - // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) - ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0); - g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); - g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y); - g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x); - g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x; - IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). - //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] - g.NavScoringCount = 0; -#if IMGUI_DEBUG_NAV_RECTS - if (g.NavWindow) - { - ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); - if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG] - if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } - } -#endif + // Return whether the payload has been accepted + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); } -// Apply result from previous frame navigation directional move request -static void ImGui::NavUpdateMoveResult() +bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) { ImGuiContext& g = *GImGui; - if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) - { - // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) - if (g.NavId != 0) - { - g.NavDisableHighlight = false; - g.NavDisableMouseHover = true; - } - return; - } - - // Select which result to use - ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + if (!g.DragDropActive) + return false; - // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. - if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) - if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) - result = &g.NavMoveResultLocalVisibleSet; + ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) + return false; + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) + return false; + if (window->SkipItems) + return false; - // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. - if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) - if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) - result = &g.NavMoveResultOther; - IM_ASSERT(g.NavWindow && result->Window); + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = bb; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} - // Scroll to keep newly navigated item fully into view. - if (g.NavLayer == 0) - { - ImVec2 delta_scroll; - if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge) - { - float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; - delta_scroll.y = result->Window->Scroll.y - scroll_target; - SetScrollY(result->Window, scroll_target); - } - else - { - ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); - delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs); - } +// We don't use BeginDragDropTargetCustom() and duplicate its code because: +// 1) we use LastItemRectHoveredRect which handles items that push a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. +// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. +// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; - // Offset our result position so mouse position can be applied immediately after in NavUpdate() - result->RectRel.TranslateX(-delta_scroll.x); - result->RectRel.TranslateY(-delta_scroll.y); - } + ImGuiWindow* window = g.CurrentWindow; + if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow || window->SkipItems) + return false; - ClearActiveID(); - g.NavWindow = result->Window; - if (g.NavId != result->ID) + const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect; + ImGuiID id = g.LastItemData.ID; + if (id == 0) { - // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) - g.NavJustMovedToId = result->ID; - g.NavJustMovedToMultiSelectScopeId = result->SelectScopeId; + id = window->GetIDFromRectangle(display_rect); + KeepAliveID(id); } - SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel); - g.NavMoveFromClampedRefRect = false; + if (g.DragDropPayload.SourceId == id) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = display_rect; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; } -// Handle PageUp/PageDown/Home/End keys -static float ImGui::NavUpdatePageUpPageDown() +bool ImGui::IsDragDropPayloadBeingAccepted() { ImGuiContext& g = *GImGui; - if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL) - return 0.0f; - if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != 0) - return 0.0f; - - ImGuiWindow* window = g.NavWindow; - const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); - const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); - const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); - const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); - if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed - { - if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) - { - // Fallback manual-scroll when window has no navigable item - if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) - SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); - else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) - SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); - else if (home_pressed) - SetScrollY(window, 0.0f); - else if (end_pressed) - SetScrollY(window, window->ScrollMax.y); - } - else - { - ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; - const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); - float nav_scoring_rect_offset_y = 0.0f; - if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) - { - nav_scoring_rect_offset_y = -page_offset_y; - g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) - g.NavMoveClipDir = ImGuiDir_Up; - g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; - } - else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) - { - nav_scoring_rect_offset_y = +page_offset_y; - g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) - g.NavMoveClipDir = ImGuiDir_Down; - g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; - } - else if (home_pressed) - { - // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y - // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result. - // Preserve current horizontal position if we have any. - nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y; - if (nav_rect_rel.IsInverted()) - nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; - g.NavMoveDir = ImGuiDir_Down; - g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; - } - else if (end_pressed) - { - nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y; - if (nav_rect_rel.IsInverted()) - nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; - g.NavMoveDir = ImGuiDir_Up; - g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; - } - return nav_scoring_rect_offset_y; - } - } - return 0.0f; + return g.DragDropActive && g.DragDropAcceptIdPrev != 0; } -static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) { ImGuiContext& g = *GImGui; - for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--) - if (g.WindowsFocusOrder[i] == window) - return i; - return -1; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. + // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); + ImRect r = g.DragDropTargetRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface > g.DragDropAcceptIdCurrRectSurface) + return NULL; + + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: accept\n", g.DragDropTargetId); + + // Render default drop visuals + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame) + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId); + return &payload; } -static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +// FIXME-DRAGDROP: Settle on a proper default visuals for drop target. +void ImGui::RenderDragDropTargetRect(const ImRect& bb) { - ImGuiContext& g = *GImGui; - for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) - if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) - return g.WindowsFocusOrder[i]; - return NULL; + GetWindowDrawList()->AddRect(bb.Min - ImVec2(3.5f, 3.5f), bb.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); } -static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +const ImGuiPayload* ImGui::GetDragDropPayload() { ImGuiContext& g = *GImGui; - IM_ASSERT(g.NavWindowingTarget); - if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) - return; - - const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); - ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); - if (!window_target) - window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); - if (window_target) // Don't reset windowing target if there's a single window in the list - g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; - g.NavWindowingToggleLayer = false; + return (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL; } -// Windowing management mode -// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) -// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) -static void ImGui::NavUpdateWindowing() +void ImGui::EndDragDropTarget() { ImGuiContext& g = *GImGui; - ImGuiWindow* apply_focus_window = NULL; - bool apply_toggle_layer = false; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinTarget); + g.DragDropWithinTarget = false; - ImGuiWindow* modal_window = GetTopMostPopupModal(); - if (modal_window != NULL) + // Clear drag and drop state payload right after delivery + if (g.DragDropPayload.Delivery) + ClearDragDrop(); +} + +//----------------------------------------------------------------------------- +// [SECTION] LOGGING/CAPTURING +//----------------------------------------------------------------------------- +// All text output from the interface can be captured into tty/file/clipboard. +// By default, tree nodes are automatically opened during logging. +//----------------------------------------------------------------------------- + +// Pass text data straight to log (without being displayed) +static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args) +{ + if (g.LogFile) { - g.NavWindowingTarget = NULL; - return; + g.LogBuffer.Buf.resize(0); + g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); } - - // Fade out - if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + else { - g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); - if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) - g.NavWindowingTargetAnim = NULL; + g.LogBuffer.appendfv(fmt, args); } +} - // Start CTRL-TAB or Square+L/R window selection - bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); - bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); - if (start_windowing_with_gamepad || start_windowing_with_keyboard) - if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) - { - g.NavWindowingTarget = g.NavWindowingTargetAnim = window; - g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; - g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; - g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; - } +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; - // Gamepad update - g.NavWindowingTimer += g.IO.DeltaTime; - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) - { - // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise - g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + va_list args; + va_start(args, fmt); + LogTextV(g, fmt, args); + va_end(args); +} - // Select window to focus - const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); - if (focus_change_dir != 0) - { - NavUpdateWindowingHighlightWindow(focus_change_dir); - g.NavWindowingHighlightAlpha = 1.0f; - } +void ImGui::LogTextV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; - // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) - if (!IsNavInputDown(ImGuiNavInput_Menu)) - { - g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. - if (g.NavWindowingToggleLayer && g.NavWindow) - apply_toggle_layer = true; - else if (!g.NavWindowingToggleLayer) - apply_focus_window = g.NavWindowingTarget; - g.NavWindowingTarget = NULL; - } - } + LogTextV(g, fmt, args); +} - // Keyboard: Focus - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) - { - // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise - g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f - if (IsKeyPressedMap(ImGuiKey_Tab, true)) - NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); - if (!g.IO.KeyCtrl) - apply_focus_window = g.NavWindowingTarget; - } +// Internal version that takes a position to decide on newline placement and pad items according to their depth. +// We split text into individual lines to add current tree level padding +// FIXME: This code is a little complicated perhaps, considering simplifying the whole system. +void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; - // Keyboard: Press and Release ALT to toggle menu layer - // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB - if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) - g.NavWindowingToggleLayer = true; - if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) - if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) - apply_toggle_layer = true; + const char* prefix = g.LogNextPrefix; + const char* suffix = g.LogNextSuffix; + g.LogNextPrefix = g.LogNextSuffix = NULL; - // Move window - if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + if (!text_end) + text_end = FindRenderedTextEnd(text, text_end); + + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); + if (ref_pos) + g.LogLinePosY = ref_pos->y; + if (log_new_line) { - ImVec2 move_delta; - if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) - move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); - if (g.NavInputSource == ImGuiInputSource_NavGamepad) - move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); - if (move_delta.x != 0.0f || move_delta.y != 0.0f) - { - const float NAV_MOVE_SPEED = 800.0f; - const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well - SetWindowPos(g.NavWindowingTarget->RootWindow, g.NavWindowingTarget->RootWindow->Pos + move_delta * move_speed, ImGuiCond_Always); - g.NavDisableMouseHover = true; - MarkIniSettingsDirty(g.NavWindowingTarget); - } + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; } - // Apply final focus - if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) - { - ClearActiveID(); - g.NavDisableHighlight = false; - g.NavDisableMouseHover = true; - apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); - ClosePopupsOverWindow(apply_focus_window, false); - FocusWindow(apply_focus_window); - if (apply_focus_window->NavLastIds[0] == 0) - NavInitWindow(apply_focus_window, false); + if (prefix) + LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. - // If the window only has a menu layer, select it directly - if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) - g.NavLayer = ImGuiNavLayer_Menu; - } - if (apply_focus_window) - g.NavWindowingTarget = NULL; + // Re-adjust padding if we have popped out of our starting depth + if (g.LogDepthRef > window->DC.TreeDepth) + g.LogDepthRef = window->DC.TreeDepth; + const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); - // Apply menu/layer toggle - if (apply_toggle_layer && g.NavWindow) + const char* text_remaining = text; + for (;;) { - // Move to parent menu if necessary - ImGuiWindow* new_nav_window = g.NavWindow; - while (new_nav_window->ParentWindow - && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 - && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 - && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) - new_nav_window = new_nav_window->ParentWindow; - if (new_nav_window != g.NavWindow) + // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry. + // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured. + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_last_line = (line_end == text_end); + if (line_start != line_end || !is_last_line) { - ImGuiWindow* old_nav_window = g.NavWindow; - FocusWindow(new_nav_window); - new_nav_window->NavLastChildNavWindow = old_nav_window; + const int line_length = (int)(line_end - line_start); + const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1; + LogText("%*s%.*s", indentation, "", line_length, line_start); + g.LogLineFirstItem = false; + if (*line_end == '\n') + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } } - g.NavDisableHighlight = false; - g.NavDisableMouseHover = true; - - // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID. - const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; - NavRestoreLayer(new_nav_layer); + if (is_last_line) + break; + text_remaining = line_end + 1; } + + if (suffix) + LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); } -// Window has already passed the IsWindowNavFocusable() -static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +// Start logging/capturing text output +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) { - if (window->Flags & ImGuiWindowFlags_Popup) - return "(Popup)"; - if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) - return "(Main menu bar)"; - return "(Untitled)"; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.LogEnabled == false); + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); + g.LogEnabled = true; + g.LogType = type; + g.LogNextPrefix = g.LogNextSuffix = NULL; + g.LogDepthRef = window->DC.TreeDepth; + g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); + g.LogLinePosY = FLT_MAX; + g.LogLineFirstItem = true; } -// Overlay displayed when using CTRL+TAB. Called by EndFrame(). -void ImGui::NavUpdateWindowingOverlay() +// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText) +void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix) { ImGuiContext& g = *GImGui; - IM_ASSERT(g.NavWindowingTarget != NULL); + g.LogNextPrefix = prefix; + g.LogNextSuffix = suffix; +} - if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) +void ImGui::LogToTTY(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + LogBegin(ImGuiLogType_TTY, auto_open_depth); + g.LogFile = stdout; +#endif +} - if (g.NavWindowingList == NULL) - g.NavWindowingList = FindWindowByName("###NavWindowingList"); - SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); - SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); - PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); - Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); - for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) +// Start logging/capturing text output to given file +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still + // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. + // By opening the file in binary mode "ab" we have consistent output everywhere. + if (!filename) + filename = g.IO.LogFilename; + if (!filename || !filename[0]) + return; + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) { - ImGuiWindow* window = g.WindowsFocusOrder[n]; - if (!IsWindowNavFocusable(window)) - continue; - const char* label = window->Name; - if (label == FindRenderedTextEnd(label)) - label = GetFallbackWindowNameForWindowingList(window); - Selectable(label, g.NavWindowingTarget == window); + IM_ASSERT(0); + return; } - End(); - PopStyleVar(); + + LogBegin(ImGuiLogType_File, auto_open_depth); + g.LogFile = f; } +// Start logging/capturing text output to clipboard +void ImGui::LogToClipboard(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); +} -//----------------------------------------------------------------------------- -// [SECTION] DRAG AND DROP -//----------------------------------------------------------------------------- +void ImGui::LogToBuffer(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Buffer, auto_open_depth); +} -void ImGui::ClearDragDrop() +void ImGui::LogFinish() { ImGuiContext& g = *GImGui; - g.DragDropActive = false; - g.DragDropPayload.Clear(); - g.DragDropAcceptFlags = ImGuiDragDropFlags_None; - g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; - g.DragDropAcceptIdCurrRectSurface = FLT_MAX; - g.DragDropAcceptFrameCount = -1; + if (!g.LogEnabled) + return; - g.DragDropPayloadBufHeap.clear(); - memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + LogText(IM_NEWLINE); + switch (g.LogType) + { + case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + fflush(g.LogFile); +#endif + break; + case ImGuiLogType_File: + ImFileClose(g.LogFile); + break; + case ImGuiLogType_Buffer: + break; + case ImGuiLogType_Clipboard: + if (!g.LogBuffer.empty()) + SetClipboardText(g.LogBuffer.begin()); + break; + case ImGuiLogType_None: + IM_ASSERT(0); + break; + } + + g.LogEnabled = false; + g.LogType = ImGuiLogType_None; + g.LogFile = NULL; + g.LogBuffer.clear(); } -// Call when current ID is active. -// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() -bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +// Helper to display logging buttons +// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) +void ImGui::LogButtons() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - bool source_drag_active = false; - ImGuiID source_id = 0; - ImGuiID source_parent_id = 0; - int mouse_button = 0; - if (!(flags & ImGuiDragDropFlags_SourceExtern)) - { - source_id = window->DC.LastItemId; - if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case - return false; - if (g.IO.MouseDown[mouse_button] == false) - return false; + PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushTabStop(false); + SetNextItemWidth(80.0f); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopTabStop(); + PopID(); - if (source_id == 0) - { - // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: - // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. - if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) - { - IM_ASSERT(0); - return false; - } + // Start logging at the end of the function so that the buttons don't appear in the log + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} - // Early out - if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) - return false; - // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() - // We build a throwaway ID based on current ID stack + relative AABB of items in window. - // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. - // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. - source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); - bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id); - if (is_hovered && g.IO.MouseClicked[mouse_button]) - { - SetActiveID(source_id, window); - FocusWindow(window); - } - if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. - g.ActiveIdAllowOverlap = is_hovered; - } - else - { - g.ActiveIdAllowOverlap = false; - } - if (g.ActiveId != source_id) - return false; - source_parent_id = window->IDStack.back(); - source_drag_active = IsMouseDragging(mouse_button); - } - else +//----------------------------------------------------------------------------- +// [SECTION] SETTINGS +//----------------------------------------------------------------------------- +// - UpdateSettings() [Internal] +// - MarkIniSettingsDirty() [Internal] +// - FindSettingsHandler() [Internal] +// - ClearIniSettings() [Internal] +// - LoadIniSettingsFromDisk() +// - LoadIniSettingsFromMemory() +// - SaveIniSettingsToDisk() +// - SaveIniSettingsToMemory() +//----------------------------------------------------------------------------- +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettingsByID() [Internal] +// - FindWindowSettingsByWindow() [Internal] +// - ClearWindowSettings() [Internal] +// - WindowSettingsHandler_***() [Internal] +//----------------------------------------------------------------------------- + +// Called by NewFrame() +void ImGui::UpdateSettings() +{ + // Load settings on first frame (if not explicitly loaded manually before) + ImGuiContext& g = *GImGui; + if (!g.SettingsLoaded) { - window = NULL; - source_id = ImHashStr("#SourceExtern"); - source_drag_active = true; + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; } - if (source_drag_active) + // Save settings (with a delay after the last modification, so we don't spam disk too much) + if (g.SettingsDirtyTimer > 0.0f) { - if (!g.DragDropActive) + g.SettingsDirtyTimer -= g.IO.DeltaTime; + if (g.SettingsDirtyTimer <= 0.0f) { - IM_ASSERT(source_id != 0); - ClearDragDrop(); - ImGuiPayload& payload = g.DragDropPayload; - payload.SourceId = source_id; - payload.SourceParentId = source_parent_id; - g.DragDropActive = true; - g.DragDropSourceFlags = flags; - g.DragDropMouseButton = mouse_button; + if (g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + else + g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. + g.SettingsDirtyTimer = 0.0f; } - g.DragDropSourceFrameCount = g.FrameCount; - g.DragDropWithinSourceOrTarget = true; + } +} - if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) - { - // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) - // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. - BeginTooltip(); - if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) - { - ImGuiWindow* tooltip_window = g.CurrentWindow; - tooltip_window->SkipItems = true; - tooltip_window->HiddenFramesCanSkipItems = 1; - } - } +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} - if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) - window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; +void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} - return true; - } - return false; +void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL); + g.SettingsHandlers.push_back(*handler); } -void ImGui::EndDragDropSource() +void ImGui::RemoveSettingsHandler(const char* type_name) { ImGuiContext& g = *GImGui; - IM_ASSERT(g.DragDropActive); - IM_ASSERT(g.DragDropWithinSourceOrTarget && "Not after a BeginDragDropSource()?"); + if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name)) + g.SettingsHandlers.erase(handler); +} - if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) - EndTooltip(); +ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + const ImGuiID type_hash = ImHashStr(type_name); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + return &g.SettingsHandlers[handler_n]; + return NULL; +} - // Discard the drag if have not called SetDragDropPayload() - if (g.DragDropPayload.DataFrameCount == -1) - ClearDragDrop(); - g.DragDropWithinSourceOrTarget = false; +// Clear all settings (windows, tables, docking etc.) +void ImGui::ClearIniSettings() +{ + ImGuiContext& g = *GImGui; + g.SettingsIniData.clear(); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ClearAllFn) + g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); } -// Use 'cond' to choose to submit payload on drag start or every frame -bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +{ + size_t file_data_size = 0; + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); + if (!file_data) + return; + if (file_data_size > 0) + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + IM_FREE(file_data); +} + +// Zero-tolerance, no error reporting, cheap .ini parsing +// Set ini_size==0 to let us use strlen(ini_data). Do not call this function with a 0 if your buffer is actually empty! +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) { ImGuiContext& g = *GImGui; - ImGuiPayload& payload = g.DragDropPayload; - if (cond == 0) - cond = ImGuiCond_Always; + IM_ASSERT(g.Initialized); + //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()"); + //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); - IM_ASSERT(type != NULL); - IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); - IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); - IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); - IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). + // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. + if (ini_size == 0) + ini_size = strlen(ini_data); + g.SettingsIniData.Buf.resize((int)ini_size + 1); + char* const buf = g.SettingsIniData.Buf.Data; + char* const buf_end = buf + ini_size; + memcpy(buf, ini_data, ini_size); + buf_end[0] = 0; - if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + // Call pre-read handlers + // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ReadInitFn) + g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); + + void* entry_data = NULL; + ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) { - // Copy payload - ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); - g.DragDropPayloadBufHeap.resize(0); - if (data_size > sizeof(g.DragDropPayloadBufLocal)) - { - // Store in heap - g.DragDropPayloadBufHeap.resize((int)data_size); - payload.Data = g.DragDropPayloadBufHeap.Data; - memcpy(payload.Data, data, data_size); - } - else if (data_size > 0) + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; + while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') + line_end++; + line_end[0] = 0; + if (line[0] == ';') + continue; + if (line[0] == '[' && line_end > line && line_end[-1] == ']') { - // Store locally - memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); - payload.Data = g.DragDropPayloadBufLocal; - memcpy(payload.Data, data, data_size); + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; + char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (!type_end || !name_start) + continue; + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + entry_handler = FindSettingsHandler(type_start); + entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; } - else + else if (entry_handler != NULL && entry_data != NULL) { - payload.Data = NULL; + // Let type handler parse the line + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); } - payload.DataSize = (int)data_size; } - payload.DataFrameCount = g.FrameCount; + g.SettingsLoaded = true; - return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); + // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary) + memcpy(buf, ini_data, ini_size); + + // Call post-read handlers + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ApplyAllFn) + g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); } -bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) +void ImGui::SaveIniSettingsToDisk(const char* ini_filename) { ImGuiContext& g = *GImGui; - if (!g.DragDropActive) - return false; + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) + return; - ImGuiWindow* window = g.CurrentWindow; - if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) - return false; - IM_ASSERT(id != 0); - if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) - return false; - if (window->SkipItems) - return false; + size_t ini_data_size = 0; + const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); +} - IM_ASSERT(g.DragDropWithinSourceOrTarget == false); - g.DragDropTargetRect = bb; - g.DragDropTargetId = id; - g.DragDropWithinSourceOrTarget = true; - return true; +// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer +const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + g.SettingsIniData.Buf.resize(0); + g.SettingsIniData.Buf.push_back(0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + { + ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; + handler->WriteAllFn(&g, handler, &g.SettingsIniData); + } + if (out_size) + *out_size = (size_t)g.SettingsIniData.size(); + return g.SettingsIniData.c_str(); } -// We don't use BeginDragDropTargetCustom() and duplicate its code because: -// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. -// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. -// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) -bool ImGui::BeginDragDropTarget() +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) { ImGuiContext& g = *GImGui; - if (!g.DragDropActive) - return false; - ImGuiWindow* window = g.CurrentWindow; - if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) - return false; - if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) - return false; +#if !IMGUI_DEBUG_INI_SETTINGS + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); - const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; - ImGuiID id = window->DC.LastItemId; - if (id == 0) - id = window->GetIDFromRectangle(display_rect); - if (g.DragDropPayload.SourceId == id) - return false; + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator - IM_ASSERT(g.DragDropWithinSourceOrTarget == false); - g.DragDropTargetRect = display_rect; - g.DragDropTargetId = id; - g.DragDropWithinSourceOrTarget = true; - return true; + return settings; +} + +// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names. +// This is called once per window .ini entry + once per newly instantiated window. +ImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id && !settings->WantDelete) + return settings; + return NULL; +} + +// This is faster if you are holding on a Window already as we don't need to perform a search. +ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (window->SettingsOffset != -1) + return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); + return FindWindowSettingsByID(window->ID); +} + +// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more. +void ImGui::ClearWindowSettings(const char* name) +{ + //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name); + ImGuiWindow* window = FindWindowByName(name); + if (window != NULL) + { + window->Flags |= ImGuiWindowFlags_NoSavedSettings; + InitOrLoadWindowSettings(window, NULL); + } + if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name))) + settings->WantDelete = true; +} + +static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + g.Windows[i]->SettingsOffset = -1; + g.SettingsWindows.clear(); +} + +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiID id = ImHashStr(name); + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id); + if (settings) + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + else + settings = ImGui::CreateNewWindowSettings(name); + settings->ID = id; + settings->WantApply = true; + return (void*)settings; +} + +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; + int x, y; + int i; + if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } } -bool ImGui::IsDragDropPayloadBeingAccepted() +// Apply to existing windows (if any) +static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) { - ImGuiContext& g = *GImGui; - return g.DragDropActive && g.DragDropAcceptIdPrev != 0; + ImGuiContext& g = *ctx; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->WantApply) + { + if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID)) + ApplyWindowSettings(window, settings); + settings->WantApply = false; + } } -const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiPayload& payload = g.DragDropPayload; - IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? - IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? - if (type != NULL && !payload.IsDataType(type)) - return NULL; - - // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. - // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! - const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); - ImRect r = g.DragDropTargetRect; - float r_surface = r.GetWidth() * r.GetHeight(); - if (r_surface < g.DragDropAcceptIdCurrRectSurface) + // Gather data from windows that were active during this session + // (if a window wasn't opened in this session we preserve its settings) + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) { - g.DragDropAcceptFlags = flags; - g.DragDropAcceptIdCurr = g.DragDropTargetId; - g.DragDropAcceptIdCurrRectSurface = r_surface; + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = ImVec2ih(window->Pos); + settings->Size = ImVec2ih(window->SizeFull); + + settings->Collapsed = window->Collapsed; + settings->WantDelete = false; } - // Render default drop visuals - payload.Preview = was_accepted_previously; - flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) - if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + // Write to text buffer + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) { - // FIXME-DRAG: Settle on a proper default visuals for drop target. - r.Expand(3.5f); - bool push_clip_rect = !window->ClipRect.Contains(r); - if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1)); - window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); - if (push_clip_rect) window->DrawList->PopClipRect(); + if (settings->WantDelete) + continue; + const char* settings_name = settings->GetName(); + buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); + buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + buf->append("\n"); } - - g.DragDropAcceptFrameCount = g.FrameCount; - payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() - if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) - return NULL; - - return &payload; } -const ImGuiPayload* ImGui::GetDragDropPayload() -{ - ImGuiContext& g = *GImGui; - return g.DragDropActive ? &g.DragDropPayload : NULL; -} -// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. -void ImGui::EndDragDropTarget() +//----------------------------------------------------------------------------- +// [SECTION] LOCALIZATION +//----------------------------------------------------------------------------- + +void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) { ImGuiContext& g = *GImGui; - IM_ASSERT(g.DragDropActive); - IM_ASSERT(g.DragDropWithinSourceOrTarget); - g.DragDropWithinSourceOrTarget = false; + for (int n = 0; n < count; n++) + g.LocalizationTable[entries[n].Key] = entries[n].Text; } //----------------------------------------------------------------------------- -// [SECTION] LOGGING/CAPTURING +// [SECTION] VIEWPORTS, PLATFORM WINDOWS //----------------------------------------------------------------------------- -// All text output from the interface can be captured into tty/file/clipboard. -// By default, tree nodes are automatically opened during logging. +// - GetMainViewport() +// - SetWindowViewport() [Internal] +// - UpdateViewportsNewFrame() [Internal] +// (this section is more complete in the 'docking' branch) //----------------------------------------------------------------------------- -// Pass text data straight to log (without being displayed) -void ImGui::LogText(const char* fmt, ...) +ImGuiViewport* ImGui::GetMainViewport() { ImGuiContext& g = *GImGui; - if (!g.LogEnabled) - return; + return g.Viewports[0]; +} - va_list args; - va_start(args, fmt); - if (g.LogFile) - { - g.LogBuffer.Buf.resize(0); - g.LogBuffer.appendfv(fmt, args); - ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); - } - else - { - g.LogBuffer.appendfv(fmt, args); - } - va_end(args); +void ImGui::SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport) +{ + window->Viewport = viewport; } -// Internal version that takes a position to decide on newline placement and pad items according to their depth. -// We split text into individual lines to add current tree level padding -void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +// Update viewports and monitor infos +static void ImGui::UpdateViewportsNewFrame() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - if (!text_end) - text_end = FindRenderedTextEnd(text, text_end); + IM_ASSERT(g.Viewports.Size == 1); - const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); - if (ref_pos) - g.LogLinePosY = ref_pos->y; - if (log_new_line) - g.LogLineFirstItem = true; + // Update main viewport with current platform position. + // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent. + ImGuiViewportP* main_viewport = g.Viewports[0]; + main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp; + main_viewport->Pos = ImVec2(0.0f, 0.0f); + main_viewport->Size = g.IO.DisplaySize; - const char* text_remaining = text; - if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth - g.LogDepthRef = window->DC.TreeDepth; - const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); - for (;;) + for (int n = 0; n < g.Viewports.Size; n++) { - // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. - // We don't add a trailing \n to allow a subsequent item on the same line to be captured. - const char* line_start = text_remaining; - const char* line_end = ImStreolRange(line_start, text_end); - const bool is_first_line = (line_start == text); - const bool is_last_line = (line_end == text_end); - if (!is_last_line || (line_start != line_end)) - { - const int char_count = (int)(line_end - line_start); - if (log_new_line || !is_first_line) - LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); - else if (g.LogLineFirstItem) - LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); - else - LogText(" %.*s", char_count, line_start); - g.LogLineFirstItem = false; - } - else if (log_new_line) - { - // An empty "" string at a different Y position should output a carriage return. - LogText(IM_NEWLINE); - break; - } + ImGuiViewportP* viewport = g.Viewports[n]; - if (is_last_line) - break; - text_remaining = line_end + 1; + // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; + viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; + viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); + viewport->UpdateWorkRect(); } } -// Start logging/capturing text output -void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(g.LogEnabled == false); - IM_ASSERT(g.LogFile == NULL); - IM_ASSERT(g.LogBuffer.empty()); - g.LogEnabled = true; - g.LogType = type; - g.LogDepthRef = window->DC.TreeDepth; - g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); - g.LogLinePosY = FLT_MAX; - g.LogLineFirstItem = true; -} +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- -void ImGui::LogToTTY(int auto_open_depth) -{ - ImGuiContext& g = *GImGui; - if (g.LogEnabled) - return; - IM_UNUSED(auto_open_depth); -#ifndef IMGUI_DISABLE_TTY_FUNCTIONS - LogBegin(ImGuiLogType_TTY, auto_open_depth); - g.LogFile = stdout; +// (this section is filled in the 'docking' branch) + + +//----------------------------------------------------------------------------- +// [SECTION] PLATFORM DEPENDENT HELPERS +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) + +#ifdef _MSC_VER +#pragma comment(lib, "user32") +#pragma comment(lib, "kernel32") #endif -} -// Start logging/capturing text output to given file -void ImGui::LogToFile(int auto_open_depth, const char* filename) +// Win32 clipboard implementation +// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *GImGui; - if (g.LogEnabled) - return; + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + g.ClipboardHandlerData.clear(); + if (!::OpenClipboard(NULL)) + return NULL; + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return NULL; + } + if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) + { + int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); + g.ClipboardHandlerData.resize(buf_len); + ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); + } + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); + return g.ClipboardHandlerData.Data; +} - // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still - // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. - // By opening the file in binary mode "ab" we have consistent output everywhere. - if (!filename) - filename = g.IO.LogFilename; - if (!filename || !filename[0]) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!::OpenClipboard(NULL)) return; - ImFileHandle f = ImFileOpen(filename, "ab"); - if (!f) + const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); + if (wbuf_handle == NULL) { - IM_ASSERT(0); + ::CloseClipboard(); return; } + WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); + ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); +} - LogBegin(ImGuiLogType_File, auto_open_depth); - g.LogFile = f; +#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) + +#include // Use old API to avoid need for separate .mm file +static PasteboardRef main_clipboard = 0; + +// OSX clipboard implementation +// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardClear(main_clipboard); + CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); + if (cf_data) + { + PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); + CFRelease(cf_data); + } } -// Start logging/capturing text output to clipboard -void ImGui::LogToClipboard(int auto_open_depth) +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *GImGui; - if (g.LogEnabled) - return; - LogBegin(ImGuiLogType_Clipboard, auto_open_depth); + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardSynchronize(main_clipboard); + + ItemCount item_count = 0; + PasteboardGetItemCount(main_clipboard, &item_count); + for (ItemCount i = 0; i < item_count; i++) + { + PasteboardItemID item_id = 0; + PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); + CFArrayRef flavor_type_array = 0; + PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); + for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) + { + CFDataRef cf_data; + if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) + { + g.ClipboardHandlerData.clear(); + int length = (int)CFDataGetLength(cf_data); + g.ClipboardHandlerData.resize(length + 1); + CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data); + g.ClipboardHandlerData[length] = 0; + CFRelease(cf_data); + return g.ClipboardHandlerData.Data; + } + } + } + return NULL; } -void ImGui::LogToBuffer(int auto_open_depth) +#else + +// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *GImGui; - if (g.LogEnabled) - return; - LogBegin(ImGuiLogType_Buffer, auto_open_depth); + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); +} + +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text) +{ + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + g.ClipboardHandlerData.clear(); + const char* text_end = text + strlen(text); + g.ClipboardHandlerData.resize((int)(text_end - text) + 1); + memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); + g.ClipboardHandlerData[(int)(text_end - text)] = 0; } -void ImGui::LogFinish() +#endif + +// Win32 API IME support (for Asian languages, etc.) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif + +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data) { - ImGuiContext& g = *GImGui; - if (!g.LogEnabled) + // Notify OS Input Method Editor of text input position + HWND hwnd = (HWND)viewport->PlatformHandleRaw; + if (hwnd == 0) return; - LogText(IM_NEWLINE); - switch (g.LogType) + //::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); + if (HIMC himc = ::ImmGetContext(hwnd)) { - case ImGuiLogType_TTY: -#ifndef IMGUI_DISABLE_TTY_FUNCTIONS - fflush(g.LogFile); -#endif - break; - case ImGuiLogType_File: - ImFileClose(g.LogFile); - break; - case ImGuiLogType_Buffer: - break; - case ImGuiLogType_Clipboard: - if (!g.LogBuffer.empty()) - SetClipboardText(g.LogBuffer.begin()); - break; - case ImGuiLogType_None: - IM_ASSERT(0); - break; + COMPOSITIONFORM composition_form = {}; + composition_form.ptCurrentPos.x = (LONG)data->InputPos.x; + composition_form.ptCurrentPos.y = (LONG)data->InputPos.y; + composition_form.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &composition_form); + CANDIDATEFORM candidate_form = {}; + candidate_form.dwStyle = CFS_CANDIDATEPOS; + candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x; + candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y; + ::ImmSetCandidateWindow(himc, &candidate_form); + ::ImmReleaseContext(hwnd, himc); } - - g.LogEnabled = false; - g.LogType = ImGuiLogType_None; - g.LogFile = NULL; - g.LogBuffer.clear(); } -// Helper to display logging buttons -// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) -void ImGui::LogButtons() -{ - ImGuiContext& g = *GImGui; - - PushID("LogButtons"); -#ifndef IMGUI_DISABLE_TTY_FUNCTIONS - const bool log_to_tty = Button("Log To TTY"); SameLine(); #else - const bool log_to_tty = false; -#endif - const bool log_to_file = Button("Log To File"); SameLine(); - const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); - PushAllowKeyboardFocus(false); - SetNextItemWidth(80.0f); - SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); - PopAllowKeyboardFocus(); - PopID(); - // Start logging at the end of the function so that the buttons don't appear in the log - if (log_to_tty) - LogToTTY(); - if (log_to_file) - LogToFile(); - if (log_to_clipboard) - LogToClipboard(); -} +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {} + +#endif //----------------------------------------------------------------------------- -// [SECTION] SETTINGS +// [SECTION] METRICS/DEBUGGER WINDOW +//----------------------------------------------------------------------------- +// - RenderViewportThumbnail() [Internal] +// - RenderViewportsThumbnails() [Internal] +// - DebugTextEncoding() +// - MetricsHelpMarker() [Internal] +// - ShowFontAtlas() [Internal] +// - ShowMetricsWindow() +// - DebugNodeColumns() [Internal] +// - DebugNodeDrawList() [Internal] +// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal] +// - DebugNodeFont() [Internal] +// - DebugNodeFontGlyph() [Internal] +// - DebugNodeStorage() [Internal] +// - DebugNodeTabBar() [Internal] +// - DebugNodeViewport() [Internal] +// - DebugNodeWindow() [Internal] +// - DebugNodeWindowSettings() [Internal] +// - DebugNodeWindowsList() [Internal] +// - DebugNodeWindowsListByBeginStackParent() [Internal] //----------------------------------------------------------------------------- -void ImGui::MarkIniSettingsDirty() +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + +void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb) { ImGuiContext& g = *GImGui; - if (g.SettingsDirtyTimer <= 0.0f) - g.SettingsDirtyTimer = g.IO.IniSavingRate; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 scale = bb.GetSize() / viewport->Size; + ImVec2 off = bb.Min - viewport->Pos * scale; + float alpha_mul = 1.0f; + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* thumb_window = g.Windows[i]; + if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) + continue; + + ImRect thumb_r = thumb_window->Rect(); + ImRect title_r = thumb_window->TitleBarRect(); + thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale)); + title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height + thumb_r.ClipWithFull(bb); + title_r.ClipWithFull(bb); + const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul)); + window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul)); + window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); + window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name)); + } + draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); } -void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +static void RenderViewportsThumbnails() { ImGuiContext& g = *GImGui; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) - if (g.SettingsDirtyTimer <= 0.0f) - g.SettingsDirtyTimer = g.IO.IniSavingRate; + ImGuiWindow* window = g.CurrentWindow; + + // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. + float SCALE = 1.0f / 8.0f; + ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + bb_full.Add(g.Viewports[n]->GetMainRect()); + ImVec2 p = window->DC.CursorPos; + ImVec2 off = p - bb_full.Min * SCALE; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); + ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); + } + ImGui::Dummy(bb_full.GetSize() * SCALE); } -ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +// Draw an arbitrary US keyboard layout to visualize translated keys +void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list) { - ImGuiContext& g = *GImGui; + const ImVec2 key_size = ImVec2(35.0f, 35.0f); + const float key_rounding = 3.0f; + const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); + const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); + const float key_face_rounding = 2.0f; + const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); + const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); + const float key_row_offset = 9.0f; -#if !IMGUI_DEBUG_INI_SETTINGS - // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() - // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. - if (const char* p = strstr(name, "###")) - name = p; -#endif - const size_t name_len = strlen(name); + ImVec2 board_min = GetCursorScreenPos(); + ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); + ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); - // Allocate chunk - const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; - ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); - IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); - settings->ID = ImHashStr(name, name_len); - memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; + const KeyLayoutData keys_to_display[] = + { + { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, + { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, + { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } + }; - return settings; + // Elements rendered manually via ImDrawList API are not clipped automatically. + // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. + Dummy(board_max - board_min); + if (!IsItemVisible()) + return; + draw_list->PushClipRect(board_min, board_max, true); + for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) + { + const KeyLayoutData* key_data = &keys_to_display[n]; + ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); + ImVec2 key_max = key_min + key_size; + draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); + draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); + ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); + ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); + draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); + draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); + ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); + draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); + if (IsKeyDown(key_data->Key)) + draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); + } + draw_list->PopClipRect(); +} + +// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct. +void ImGui::DebugTextEncoding(const char* str) +{ + Text("Text: \"%s\"", str); + if (!BeginTable("##DebugTextEncoding", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable)) + return; + TableSetupColumn("Offset"); + TableSetupColumn("UTF-8"); + TableSetupColumn("Glyph"); + TableSetupColumn("Codepoint"); + TableHeadersRow(); + for (const char* p = str; *p != 0; ) + { + unsigned int c; + const int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL); + TableNextColumn(); + Text("%d", (int)(p - str)); + TableNextColumn(); + for (int byte_index = 0; byte_index < c_utf8_len; byte_index++) + { + if (byte_index > 0) + SameLine(); + Text("0x%02X", (int)(unsigned char)p[byte_index]); + } + TableNextColumn(); + if (GetFont()->FindGlyphNoFallback((ImWchar)c)) + TextUnformatted(p, p + c_utf8_len); + else + TextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? "[invalid]" : "[missing]"); + TableNextColumn(); + Text("U+%04X", (int)c); + p += c_utf8_len; + } + EndTable(); } -ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) { - ImGuiContext& g = *GImGui; - for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) - if (settings->ID == id) - return settings; - return NULL; + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort) && ImGui::BeginTooltip()) + { + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } -ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +// [DEBUG] List fonts in a font atlas and display its texture +void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { - if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) - return settings; - return CreateNewWindowSettings(name); + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + PushID(font); + DebugNodeFont(font); + PopID(); + } + if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImGuiContext& g = *GImGui; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons + ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border); + Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); + TreePop(); + } } -void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +void ImGui::ShowMetricsWindow(bool* p_open) { - size_t file_data_size = 0; - char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); - if (!file_data) + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + if (cfg->ShowDebugLog) + ShowDebugLogWindow(&cfg->ShowDebugLog); + if (cfg->ShowStackTool) + ShowStackToolWindow(&cfg->ShowStackTool); + + if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); return; - LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); - IM_FREE(file_data); -} + } + + // Basic info + Text("Dear ImGui %s", GetVersion()); + Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations); + //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } + + Separator(); + + // Debugging enums + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" }; + enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type + const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" }; + if (cfg->ShowWindowsRectsType < 0) + cfg->ShowWindowsRectsType = WRT_WorkRect; + if (cfg->ShowTablesRectsType < 0) + cfg->ShowTablesRectsType = TRT_WorkRect; + + struct Funcs + { + static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n) + { + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance + if (rect_type == TRT_OuterRect) { return table->OuterRect; } + else if (rect_type == TRT_InnerRect) { return table->InnerRect; } + else if (rect_type == TRT_WorkRect) { return table->WorkRect; } + else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; } + else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; } + else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; } + else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); } + else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); } + else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; } + else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate + else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); } + else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); } + IM_ASSERT(0); + return ImRect(); + } + + static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) + { + if (rect_type == WRT_OuterRect) { return window->Rect(); } + else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } + else if (rect_type == WRT_InnerRect) { return window->InnerRect; } + else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == WRT_WorkRect) { return window->WorkRect; } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); } + else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } + IM_ASSERT(0); + return ImRect(); + } + }; + + // Tools + if (TreeNode("Tools")) + { + bool show_encoding_viewer = TreeNode("UTF-8 Encoding viewer"); + SameLine(); + MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct."); + if (show_encoding_viewer) + { + static char buf[100] = ""; + SetNextItemWidth(-FLT_MIN); + InputText("##Text", buf, IM_ARRAYSIZE(buf)); + if (buf[0] != 0) + DebugTextEncoding(buf); + TreePop(); + } + + // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. + if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive) + DebugStartItemPicker(); + SameLine(); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); + + // Stack Tool is your best friend! + Checkbox("Show Debug Log", &cfg->ShowDebugLog); + SameLine(); + MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code."); + + // Stack Tool is your best friend! + Checkbox("Show Stack Tool", &cfg->ShowStackTool); + SameLine(); + MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code."); + + Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); + Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count); + if (cfg->ShowWindowsRects && g.NavWindow != NULL) + { + BulletText("'%s':", g.NavWindow->Name); + Indent(); + for (int rect_n = 0; rect_n < WRT_Count; rect_n++) + { + ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); + Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); + } + Unindent(); + } + + Checkbox("Show tables rectangles", &cfg->ShowTablesRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count); + if (cfg->ShowTablesRects && g.NavWindow != NULL) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) + { + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow)) + continue; + + BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + Indent(); + char buf[128]; + for (int rect_n = 0; rect_n < TRT_Count; rect_n++) + { + if (rect_n >= TRT_ColumnsRect) + { + if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect) + continue; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, rect_n, column_n); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, rect_n, -1); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + Unindent(); + } + } + + Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop); + SameLine(); + MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + + TreePop(); + } + + // Windows + if (TreeNode("Windows", "Windows (%d)", g.Windows.Size)) + { + //SetNextItemOpen(true, ImGuiCond_Once); + DebugNodeWindowsList(&g.Windows, "By display order"); + DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)"); + if (TreeNode("By submission order (begin stack)")) + { + // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship! + ImVector& temp_buffer = g.WindowsTempSortBuffer; + temp_buffer.resize(0); + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount) + temp_buffer.push_back(g.Windows[i]); + struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } }; + ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder); + DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL); + TreePop(); + } + + TreePop(); + } + + // DrawLists + int drawlist_count = 0; + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount(); + if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) + { + Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); + Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes); + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + { + ImGuiViewportP* viewport = g.Viewports[viewport_i]; + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + } + TreePop(); + } + + // Viewports + if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size)) + { + Indent(GetTreeNodeToLabelSpacing()); + RenderViewportsThumbnails(); + Unindent(GetTreeNodeToLabelSpacing()); + for (int i = 0; i < g.Viewports.Size; i++) + DebugNodeViewport(g.Viewports[i]); + TreePop(); + } + + // Details for Popups + if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + // As it's difficult to interact with tree nodes while popups are open, we display everything inline. + const ImGuiPopupData* popup_data = &g.OpenPopupStack[i]; + ImGuiWindow* window = popup_data->Window; + BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'", + popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "", + popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL"); + } + TreePop(); + } + + // Details for TabBars + if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount())) + { + for (int n = 0; n < g.TabBars.GetMapSize(); n++) + if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n)) + { + PushID(tab_bar); + DebugNodeTabBar(tab_bar, "TabBar"); + PopID(); + } + TreePop(); + } + + // Details for Tables + if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount())) + { + for (int n = 0; n < g.Tables.GetMapSize(); n++) + if (ImGuiTable* table = g.Tables.TryGetMapData(n)) + DebugNodeTable(table); + TreePop(); + } + + // Details for Fonts + ImFontAtlas* atlas = g.IO.Fonts; + if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } + + // Details for InputText + if (TreeNode("InputText")) + { + DebugNodeInputTextState(&g.InputTextState); + TreePop(); + } + + // Details for Docking +#ifdef IMGUI_HAS_DOCK + if (TreeNode("Docking")) + { + TreePop(); + } +#endif // #ifdef IMGUI_HAS_DOCK + + // Settings + if (TreeNode("Settings")) + { + if (SmallButton("Clear")) + ClearIniSettings(); + SameLine(); + if (SmallButton("Save to memory")) + SaveIniSettingsToMemory(); + SameLine(); + if (SmallButton("Save to disk")) + SaveIniSettingsToDisk(g.IO.IniFilename); + SameLine(); + if (g.IO.IniFilename) + Text("\"%s\"", g.IO.IniFilename); + else + TextUnformatted(""); + Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); + if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) + { + for (int n = 0; n < g.SettingsHandlers.Size; n++) + BulletText("%s", g.SettingsHandlers[n].TypeName); + TreePop(); + } + if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) + { + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + DebugNodeWindowSettings(settings); + TreePop(); + } + + if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) + { + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + DebugNodeTableSettings(settings); + TreePop(); + } -ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) -{ - ImGuiContext& g = *GImGui; - const ImGuiID type_hash = ImHashStr(type_name); - for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) - if (g.SettingsHandlers[handler_n].TypeHash == type_hash) - return &g.SettingsHandlers[handler_n]; - return NULL; -} +#ifdef IMGUI_HAS_DOCK +#endif // #ifdef IMGUI_HAS_DOCK -// Zero-tolerance, no error reporting, cheap .ini parsing -void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(g.Initialized); - IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); + if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size())) + { + InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly); + TreePop(); + } + TreePop(); + } - // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). - // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. - if (ini_size == 0) - ini_size = strlen(ini_data); - char* buf = (char*)IM_ALLOC(ini_size + 1); - char* buf_end = buf + ini_size; - memcpy(buf, ini_data, ini_size); - buf[ini_size] = 0; + if (TreeNode("Inputs")) + { + Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); + { + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. + // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. + Indent(); +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } +#endif + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + DebugRenderKeyboardPreview(GetWindowDrawList()); + Unindent(); + } - void* entry_data = NULL; - ImGuiSettingsHandler* entry_handler = NULL; + Text("MOUSE STATE"); + { + Indent(); + if (IsMousePosValid()) + Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + Text("Mouse pos: "); + Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + int count = IM_ARRAYSIZE(io.MouseDown); + Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); } + Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); } + Text("Mouse wheel: %.1f", io.MouseWheel); + Text("Mouse source: %s", GetMouseSourceName(io.MouseSource)); + Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused + Unindent(); + } - char* line_end = NULL; - for (char* line = buf; line < buf_end; line = line_end + 1) + Text("MOUSE WHEELING"); + { + Indent(); + Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); + Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); + Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); + Unindent(); + } + + Text("KEY OWNERS"); + { + Indent(); + if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + { + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + continue; + Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, + owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); + DebugLocateItemOnHover(owner_data->OwnerCurr); + } + EndListBox(); + } + Unindent(); + } + Text("SHORTCUT ROUTING"); + { + Indent(); + if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + { + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) + { + char key_chord_name[64]; + ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; + GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); + Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); + DebugLocateItemOnHover(routing_data->RoutingCurr); + idx = routing_data->NextEntryIndex; + } + } + EndListBox(); + } + Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); + Unindent(); + } + TreePop(); + } + + if (TreeNode("Internal state")) + { + Text("WINDOWING"); + Indent(); + Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL"); + Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); + Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); + Unindent(); + + Text("ITEMS"); + Indent(); + Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource)); + DebugLocateItemOnHover(g.ActiveId); + Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + Text("ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); + Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame + Text("HoverDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverDelayId, g.HoverDelayTimer, g.HoverDelayClearTimer); + Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + DebugLocateItemOnHover(g.DragDropPayload.SourceId); + Unindent(); + + Text("NAV,FOCUS"); + Indent(); + Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + DebugLocateItemOnHover(g.NavId); + Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource)); + Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); + Text("NavActivateFlags: %04X", g.NavActivateFlags); + Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); + Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); + Unindent(); + + TreePop(); + } + + // Overlay: Display windows Rectangles and Begin Order + if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder) { - // Skip new lines markers, then find end of the line - while (*line == '\n' || *line == '\r') - line++; - line_end = line; - while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') - line_end++; - line_end[0] = 0; - if (line[0] == ';') - continue; - if (line[0] == '[' && line_end > line && line_end[-1] == ']') + for (int n = 0; n < g.Windows.Size; n++) { - // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. - line_end[-1] = 0; - const char* name_end = line_end - 1; - const char* type_start = line + 1; - char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); - const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; - if (!type_end || !name_start) + ImGuiWindow* window = g.Windows[n]; + if (!window->WasActive) continue; - *type_end = 0; // Overwrite first ']' - name_start++; // Skip second '[' - entry_handler = FindSettingsHandler(type_start); - entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; + ImDrawList* draw_list = GetForegroundDrawList(window); + if (cfg->ShowWindowsRects) + { + ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + if (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + { + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = GetFontSize(); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); + } } - else if (entry_handler != NULL && entry_data != NULL) + } + + // Overlay: Display Tables Rectangles + if (cfg->ShowTablesRects) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) { - // Let type handler parse the line - entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1) + continue; + ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow); + if (cfg->ShowTablesRectsType >= TRT_ColumnsRect) + { + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n); + ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255); + float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f; + draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } } } - IM_FREE(buf); - g.SettingsLoaded = true; + +#ifdef IMGUI_HAS_DOCK + // Overlay: Display Docking info + if (show_docking_nodes && g.IO.KeyCtrl) + { + } +#endif // #ifdef IMGUI_HAS_DOCK + + End(); } -void ImGui::SaveIniSettingsToDisk(const char* ini_filename) +// [DEBUG] Display contents of Columns +void ImGui::DebugNodeColumns(ImGuiOldColumns* columns) { - ImGuiContext& g = *GImGui; - g.SettingsDirtyTimer = 0.0f; - if (!ini_filename) - return; - - size_t ini_data_size = 0; - const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); - ImFileHandle f = ImFileOpen(ini_filename, "wt"); - if (!f) + if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImFileWrite(ini_data, sizeof(char), ini_data_size, f); - ImFileClose(f); + BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); + TreePop(); } -// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer -const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +// [DEBUG] Display contents of ImDrawList +void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label) { ImGuiContext& g = *GImGui; - g.SettingsDirtyTimer = 0.0f; - g.SettingsIniData.Buf.resize(0); - g.SettingsIniData.Buf.push_back(0); - for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + int cmd_count = draw_list->CmdBuffer.Size; + if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL) + cmd_count--; + bool node_open = TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count); + if (draw_list == GetWindowDrawList()) { - ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; - handler->WriteAllFn(&g, handler, &g.SettingsIniData); + SameLine(); + TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_open) + TreePop(); + return; } - if (out_size) - *out_size = (size_t)g.SettingsIniData.size(); - return g.SettingsIniData.c_str(); -} -static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) -{ - ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name)); - if (!settings) - settings = ImGui::CreateNewWindowSettings(name); - return (void*)settings; -} + ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list + if (window && IsItemHovered() && fg_draw_list) + fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!node_open) + return; -static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) -{ - ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; - int x, y; - int i; - if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) settings->Pos = ImVec2ih((short)x, (short)y); - else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) settings->Size = ImVec2ih((short)x, (short)y); - else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); -} + if (window && !window->WasActive) + TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); -static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) -{ - // Gather data from windows that were active during this session - // (if a window wasn't opened in this session we preserve its settings) - ImGuiContext& g = *ctx; - for (int i = 0; i != g.Windows.Size; i++) + for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++) { - ImGuiWindow* window = g.Windows[i]; - if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + if (pcmd->UserCallback) + { + BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; + } - ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); - if (!settings) + char buf[300]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); + if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); + if (!pcmd_node_open) + continue; + + // Calculate approximate coverage area (touched pixel count) + // This will be in pixels squared as long there's no post-scaling happening to the renderer output. + const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset; + float total_area = 0.0f; + for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; ) { - settings = ImGui::CreateNewWindowSettings(window->Name); - window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos; + total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); } - IM_ASSERT(settings->ID == window->ID); - settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y); - settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y); - settings->Collapsed = window->Collapsed; - } - // Write to text buffer - buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve - for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) - { - const char* settings_name = settings->GetName(); - buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); - buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); - buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); - buf->appendf("Collapsed=%d\n", settings->Collapsed); - buf->append("\n"); + // Display vertex information summary. Hover to get all triangles drawn in wire-frame + ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); + Selectable(buf); + if (IsItemHovered() && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false); + + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. + ImGuiListClipper clipper; + clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++) + { + char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf); + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_i++) + { + const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; + triangle[n] = v.pos; + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + + Selectable(buf, false); + if (fg_draw_list && IsItemHovered()) + { + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + TreePop(); } + TreePop(); } - -//----------------------------------------------------------------------------- -// [SECTION] VIEWPORTS, PLATFORM WINDOWS -//----------------------------------------------------------------------------- - -// (this section is filled in the 'docking' branch) - - -//----------------------------------------------------------------------------- -// [SECTION] DOCKING -//----------------------------------------------------------------------------- - -// (this section is filled in the 'docking' branch) - - -//----------------------------------------------------------------------------- -// [SECTION] PLATFORM DEPENDENT HELPERS -//----------------------------------------------------------------------------- - -#if defined(_WIN32) && !defined(_WINDOWS_) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef __MINGW32__ -#include -#else -#include -#endif -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions -#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS -#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS -#endif -#elif defined(__APPLE__) -#include -#endif - -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) - -#ifdef _MSC_VER -#pragma comment(lib, "user32") -#endif - -// Win32 clipboard implementation -static const char* GetClipboardTextFn_DefaultImpl(void*) +// [DEBUG] Display mesh/aabb of a ImDrawCmd +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) { - static ImVector buf_local; - buf_local.clear(); - if (!::OpenClipboard(NULL)) - return NULL; - HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); - if (wbuf_handle == NULL) + IM_ASSERT(show_mesh || show_aabb); + + // Draw wire-frame version of all triangles + ImRect clip_rect = draw_cmd->ClipRect; + ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + ImDrawListFlags backup_flags = out_draw_list->Flags; + out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; ) { - ::CloseClipboard(); - return NULL; + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list + ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset; + + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos)); + if (show_mesh) + out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles } - if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle)) + // Draw bounding boxes + if (show_aabb) { - int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; - buf_local.resize(buf_len); - ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL); + out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU + out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles } - ::GlobalUnlock(wbuf_handle); - ::CloseClipboard(); - return buf_local.Data; + out_draw_list->Flags = backup_flags; } -static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +// [DEBUG] Display details for a single font, called by ShowStyleEditor(). +void ImGui::DebugNodeFont(ImFont* font) { - if (!::OpenClipboard(NULL)) - return; - const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; - HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); - if (wbuf_handle == NULL) - { - ::CloseClipboard(); + bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", + font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + SameLine(); + if (SmallButton("Set as default")) + GetIO().FontDefault = font; + if (!opened) return; + + // Display preview text + PushFont(font); + Text("The quick brown fox jumps over the lazy dog"); + PopFont(); + + // Display details + SetNextItemWidth(GetFontSize() * 8); + DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); + SameLine(); MetricsHelpMarker( + "Note than the default embedded font is NOT meant to be scaled.\n\n" + "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " + "You may oversample them to get some flexibility with scaling. " + "You can also render at multiple sizes and select which one to use at runtime.\n\n" + "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); + Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + char c_str[5]; + Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); + Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); + const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface); + Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (font->ConfigData) + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + + // Display all glyphs of the fonts in separate pages of 256 characters + if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = font->FontSize * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + { + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) + { + base += 4096 - 256; + continue; + } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (!glyph) + continue; + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + { + DebugNodeFontGlyph(font, glyph); + EndTooltip(); + } + } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + TreePop(); + } + TreePop(); } - ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle); - ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); - ::GlobalUnlock(wbuf_handle); - ::EmptyClipboard(); - if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) - ::GlobalFree(wbuf_handle); - ::CloseClipboard(); + TreePop(); } -#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) - -#include // Use old API to avoid need for separate .mm file -static PasteboardRef main_clipboard = 0; +void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) +{ + Text("Codepoint: U+%04X", glyph->Codepoint); + Separator(); + Text("Visible: %d", glyph->Visible); + Text("AdvanceX: %.1f", glyph->AdvanceX); + Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); +} -// OSX clipboard implementation -// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! -static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +// [DEBUG] Display contents of ImGuiStorage +void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label) { - if (!main_clipboard) - PasteboardCreate(kPasteboardClipboard, &main_clipboard); - PasteboardClear(main_clipboard); - CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); - if (cf_data) + if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) + return; + for (int n = 0; n < storage->Data.Size; n++) { - PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); - CFRelease(cf_data); + const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; + BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. } + TreePop(); } -static const char* GetClipboardTextFn_DefaultImpl(void*) +// [DEBUG] Display contents of ImGuiTabBar +void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) { - if (!main_clipboard) - PasteboardCreate(kPasteboardClipboard, &main_clipboard); - PasteboardSynchronize(main_clipboard); - - ItemCount item_count = 0; - PasteboardGetItemCount(main_clipboard, &item_count); - for (ItemCount i = 0; i < item_count; i++) + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2); + p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s {", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); + for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) { - PasteboardItemID item_id = 0; - PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); - CFArrayRef flavor_type_array = 0; - PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); - for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab)); + } + p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(label, "%s", buf); + if (!is_active) { PopStyleColor(); } + if (is_active && IsItemHovered()) + { + ImDrawList* draw_list = GetForegroundDrawList(); + draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + } + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { - CFDataRef cf_data; - if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) - { - static ImVector clipboard_text; - int length = (int)CFDataGetLength(cf_data); - clipboard_text.resize(length + 1); - CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)clipboard_text.Data); - clipboard_text[length] = 0; - CFRelease(cf_data); - return clipboard_text.Data; - } + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + PushID(tab); + if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2); + if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine(); + Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f", + tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth); + PopID(); } + TreePop(); } - return NULL; } -#else - -// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. -static const char* GetClipboardTextFn_DefaultImpl(void*) +void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) { - ImGuiContext& g = *GImGui; - return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin(); + SetNextItemOpen(true, ImGuiCond_Once); + if (TreeNode("viewport0", "Viewport #%d", 0)) + { + ImGuiWindowFlags flags = viewport->Flags; + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", + viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); + BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, + (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", + (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", + (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + TreePop(); + } } -static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) { - ImGuiContext& g = *GImGui; - g.PrivateClipboard.clear(); - const char* text_end = text + strlen(text); - g.PrivateClipboard.resize((int)(text_end - text) + 1); - memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text)); - g.PrivateClipboard[(int)(text_end - text)] = 0; -} + if (window == NULL) + { + BulletText("%s: NULL", label); + return; + } -#endif + ImGuiContext& g = *GImGui; + const bool is_active = window->WasActive; + ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None; + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered() && is_active) + GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) + return; -// Win32 API IME support (for Asian languages, etc.) -#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + if (window->MemoryCompacted) + TextDisabled("Note: some memory buffers have been compacted/freed."); -#include -#ifdef _MSC_VER -#pragma comment(lib, "imm32") -#endif + ImGuiWindowFlags flags = window->Flags; + DebugNodeDrawList(window, window->DrawList, "DrawList"); + BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y); + BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, + (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", + (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", + (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); + BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); + BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + { + ImRect r = window->NavRectRel[layer]; + if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y) + BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]); + else + BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); + DebugLocateItemOnHover(window->NavLastIds[layer]); + } + const ImVec2* pr = window->NavPreferredScoringPosRel; + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater. + BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } + if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } + if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); } + if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) + { + for (int n = 0; n < window->ColumnsStorage.Size; n++) + DebugNodeColumns(&window->ColumnsStorage[n]); + TreePop(); + } + DebugNodeStorage(&window->StateStorage, "Storage"); + TreePop(); +} -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) { - // Notify OS Input Method Editor of text input position - ImGuiIO& io = ImGui::GetIO(); - if (HWND hwnd = (HWND)io.ImeWindowHandle) - if (HIMC himc = ::ImmGetContext(hwnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ::ImmSetCompositionWindow(himc, &cf); - ::ImmReleaseContext(hwnd, himc); - } + if (settings->WantDelete) + BeginDisabled(); + Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", + settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); + if (settings->WantDelete) + EndDisabled(); } -#else - -static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} +void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) +{ + if (!TreeNode(label, "%s (%d)", label, windows->Size)) + return; + for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back + { + PushID((*windows)[i]); + DebugNodeWindow((*windows)[i], "Window"); + PopID(); + } + TreePop(); +} -#endif +// FIXME-OPT: This is technically suboptimal, but it is simpler this way. +void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack) +{ + for (int i = 0; i < windows_size; i++) + { + ImGuiWindow* window = windows[i]; + if (window->ParentWindowInBeginStack != parent_in_begin_stack) + continue; + char buf[20]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); + //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); + DebugNodeWindow(window, buf); + Indent(); + DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); + Unindent(); + } +} //----------------------------------------------------------------------------- -// [SECTION] METRICS/DEBUG WINDOW +// [SECTION] DEBUG LOG WINDOW //----------------------------------------------------------------------------- -#ifndef IMGUI_DISABLE_METRICS_WINDOW -// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. -static void MetricsHelpMarker(const char* desc) +void ImGui::DebugLog(const char* fmt, ...) { - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(desc); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } + va_list args; + va_start(args, fmt); + DebugLogV(fmt, args); + va_end(args); } -void ImGui::ShowMetricsWindow(bool* p_open) +void ImGui::DebugLogV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + const int old_size = g.DebugLogBuf.size(); + g.DebugLogBuf.appendf("[%05d] ", g.FrameCount); + g.DebugLogBuf.appendfv(fmt, args); + if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY) + IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size); + g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size()); +} + +void ImGui::ShowDebugLogWindow(bool* p_open) { - if (!ImGui::Begin("Dear ImGui Metrics", p_open)) + ImGuiContext& g = *GImGui; + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); + if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) { - ImGui::End(); + End(); return; } - // State - enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type - const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" }; - static bool show_windows_rects = false; - static int show_windows_rect_type = WRT_WorkRect; - static bool show_windows_begin_order = false; - static bool show_drawcmd_details = true; + CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_); + SameLine(); CheckboxFlags("ActiveId", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId); + SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus); + SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup); + SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav); + SameLine(); if (CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip("Clipper log auto-disabled after 2 frames"); + //SameLine(); CheckboxFlags("Selection", &g.DebugLogFlags, ImGuiDebugLogFlags_EventSelection); + SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO); - // Basic info - ImGuiContext& g = *GImGui; - ImGuiIO& io = ImGui::GetIO(); - ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); - ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); - ImGui::Text("%d active allocations", io.MetricsActiveAllocations); - ImGui::Separator(); - - // Helper functions to display common structures: - // - NodeDrawList - // - NodeColumns - // - NodeWindow - // - NodeWindows - // - NodeTabBar - struct Funcs + if (SmallButton("Clear")) { - static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) - { - if (rect_type == WRT_OuterRect) { return window->Rect(); } - else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } - else if (rect_type == WRT_InnerRect) { return window->InnerRect; } - else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } - else if (rect_type == WRT_WorkRect) { return window->WorkRect; } - else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } - else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } - IM_ASSERT(0); - return ImRect(); - } + g.DebugLogBuf.clear(); + g.DebugLogIndex.clear(); + } + SameLine(); + if (SmallButton("Copy")) + SetClipboardText(g.DebugLogBuf.c_str()); + BeginChild("##log", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); - static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label) + ImGuiListClipper clipper; + clipper.Begin(g.DebugLogIndex.size()); + while (clipper.Step()) + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) { - bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); - if (draw_list == ImGui::GetWindowDrawList()) - { - ImGui::SameLine(); - ImGui::TextColored(ImVec4(1.0f,0.4f,0.4f,1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) - if (node_open) ImGui::TreePop(); - return; - } - - ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list - if (window && IsItemHovered()) - fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); - if (!node_open) - return; - - if (window && !window->WasActive) - ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); - - unsigned int elem_offset = 0; - for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) - { - if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) - continue; - if (pcmd->UserCallback) + const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no); + const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no); + TextUnformatted(line_begin, line_end); + ImRect text_rect = g.LastItemData.Rect; + if (IsItemHovered()) + for (const char* p = line_begin; p <= line_end - 10; p++) { - ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); - continue; + ImGuiID id = 0; + if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) + continue; + ImVec2 p0 = CalcTextSize(line_begin, p); + ImVec2 p1 = CalcTextSize(p, p + 10); + g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y)); + if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true)) + DebugLocateItemOnHover(id); + p += 10; } + } + if (GetScrollY() >= GetScrollMaxY()) + SetScrollHereY(1.0f); + EndChild(); - ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; - char buf[300]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd: %4d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", - pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId.get(), - pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); - bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); - if (show_drawcmd_details && fg_draw_list && ImGui::IsItemHovered()) - { - ImRect clip_rect = pcmd->ClipRect; - ImRect vtxs_rect; - for (unsigned int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) - vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); - fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255,0,255,255)); - fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(255,255,0,255)); - } - if (!pcmd_node_open) - continue; + End(); +} - // Calculate approximate coverage area (touched pixel count) - // This will be in pixels squared as long there's no post-scaling happening to the renderer output. - float total_area = 0.0f; - for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) - { - ImVec2 triangle[3]; - for (int n = 0; n < 3; n++) - triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; - total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); - } +//----------------------------------------------------------------------------- +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) +//----------------------------------------------------------------------------- - // Display vertex information summary. Hover to get all triangles drawn in wire-frame - ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); - ImGui::Selectable(buf); - if (fg_draw_list && ImGui::IsItemHovered() && show_drawcmd_details) - { - // Draw wire-frame version of everything - ImDrawListFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. - ImRect clip_rect = pcmd->ClipRect; - fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); - for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) - { - ImVec2 triangle[3]; - for (int n = 0; n < 3; n++) - triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; - fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); - } - fg_draw_list->Flags = backup_flags; - } +static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green - // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. - ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. - while (clipper.Step()) - for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) - { - char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); - ImVec2 triangle[3]; - for (int n = 0; n < 3; n++, idx_i++) - { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; - triangle[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", - (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); - } +void ImGui::DebugLocateItem(ImGuiID target_id) +{ + ImGuiContext& g = *GImGui; + g.DebugLocateId = target_id; + g.DebugLocateFrames = 2; +} - ImGui::Selectable(buf, false); - if (fg_draw_list && ImGui::IsItemHovered()) - { - ImDrawListFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. - fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f); - fg_draw_list->Flags = backup_flags; - } - } - ImGui::TreePop(); - } - ImGui::TreePop(); - } +void ImGui::DebugLocateItemOnHover(ImGuiID target_id) +{ + if (target_id == 0 || !IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return; + ImGuiContext& g = *GImGui; + DebugLocateItem(target_id); + GetForegroundDrawList(g.CurrentWindow)->AddRect(g.LastItemData.Rect.Min - ImVec2(3.0f, 3.0f), g.LastItemData.Rect.Max + ImVec2(3.0f, 3.0f), DEBUG_LOCATE_ITEM_COLOR); +} - static void NodeColumns(const ImGuiColumns* columns) - { - if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) - return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); - for (int column_n = 0; column_n < columns->Columns.Size; column_n++) - ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); - ImGui::TreePop(); - } +void ImGui::DebugLocateItemResolveWithLastItem() +{ + ImGuiContext& g = *GImGui; + ImGuiLastItemData item_data = g.LastItemData; + g.DebugLocateId = 0; + ImDrawList* draw_list = GetForegroundDrawList(g.CurrentWindow); + ImRect r = item_data.Rect; + r.Expand(3.0f); + ImVec2 p1 = g.IO.MousePos; + ImVec2 p2 = ImVec2((p1.x < r.Min.x) ? r.Min.x : (p1.x > r.Max.x) ? r.Max.x : p1.x, (p1.y < r.Min.y) ? r.Min.y : (p1.y > r.Max.y) ? r.Max.y : p1.y); + draw_list->AddRect(r.Min, r.Max, DEBUG_LOCATE_ITEM_COLOR); + draw_list->AddLine(p1, p2, DEBUG_LOCATE_ITEM_COLOR); +} - static void NodeWindows(ImVector& windows, const char* label) - { - if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) - return; - for (int i = 0; i < windows.Size; i++) - Funcs::NodeWindow(windows[i], "Window"); - ImGui::TreePop(); - } +// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. +void ImGui::UpdateDebugToolItemPicker() +{ + ImGuiContext& g = *GImGui; + g.DebugItemPickerBreakId = 0; + if (!g.DebugItemPickerActive) + return; - static void NodeWindow(ImGuiWindow* window, const char* label) - { - if (window == NULL) - { - ImGui::BulletText("%s: NULL", label); - return; - } - bool open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window); - if (ImGui::IsItemHovered() && window->WasActive) - ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); - if (!open) - return; - ImGuiWindowFlags flags = window->Flags; - NodeDrawList(window, window->DrawList, "DrawList"); - ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y); - ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, - (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", - (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", - (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); - ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); - ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); - ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); - ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); - ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); - if (!window->NavRectRel[0].IsInverted()) - ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); - else - ImGui::BulletText("NavRectRel[0]: "); - if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); - if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow"); - if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); - if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) - { - for (int n = 0; n < window->ColumnsStorage.Size; n++) - NodeColumns(&window->ColumnsStorage[n]); - ImGui::TreePop(); - } - NodeStorage(&window->StateStorage, "Storage"); - ImGui::TreePop(); - } + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + SetMouseCursor(ImGuiMouseCursor_Hand); + if (IsKeyPressed(ImGuiKey_Escape)) + g.DebugItemPickerActive = false; + const bool change_mapping = g.IO.KeyMods == (ImGuiMod_Ctrl | ImGuiMod_Shift); + if (!change_mapping && IsMouseClicked(g.DebugItemPickerMouseButton) && hovered_id) + { + g.DebugItemPickerBreakId = hovered_id; + g.DebugItemPickerActive = false; + } + for (int mouse_button = 0; mouse_button < 3; mouse_button++) + if (change_mapping && IsMouseClicked(mouse_button)) + g.DebugItemPickerMouseButton = (ImU8)mouse_button; + SetNextWindowBgAlpha(0.70f); + if (!BeginTooltip()) + return; + Text("HoveredId: 0x%08X", hovered_id); + Text("Press ESC to abort picking."); + const char* mouse_button_names[] = { "Left", "Right", "Middle" }; + if (change_mapping) + Text("Remap w/ Ctrl+Shift: click anywhere to select new mouse button."); + else + TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click %s Button to break in debugger! (remap w/ Ctrl+Shift)", mouse_button_names[g.DebugItemPickerMouseButton]); + EndTooltip(); +} - static void NodeTabBar(ImGuiTabBar* tab_bar) - { - // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. - char buf[256]; - char* p = buf; - const char* buf_end = buf + IM_ARRAYSIZE(buf); - ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); - if (ImGui::TreeNode(tab_bar, "%s", buf)) - { - for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) - { - const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - ImGui::PushID(tab); - if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); - if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); - ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : ""); - ImGui::PopID(); - } - ImGui::TreePop(); - } - } +// [DEBUG] Stack Tool: update queries. Called by NewFrame() +void ImGui::UpdateDebugToolStackQueries() +{ + ImGuiContext& g = *GImGui; + ImGuiStackTool* tool = &g.DebugStackTool; - static void NodeStorage(ImGuiStorage* storage, const char* label) - { - if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) - return; - for (int n = 0; n < storage->Data.Size; n++) - { - const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; - ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. - } - ImGui::TreePop(); - } - }; + // Clear hook when stack tool is not visible + g.DebugHookIdInfo = 0; + if (g.FrameCount != tool->LastActiveFrame + 1) + return; - Funcs::NodeWindows(g.Windows, "Windows"); - if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + // Update queries. The steps are: -1: query Stack, >= 0: query each stack item + // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time + const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId; + if (tool->QueryId != query_id) { - for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) - Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); - ImGui::TreePop(); + tool->QueryId = query_id; + tool->StackLevel = -1; + tool->Results.resize(0); } + if (query_id == 0) + return; - if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) - { - for (int i = 0; i < g.OpenPopupStack.Size; i++) - { - ImGuiWindow* window = g.OpenPopupStack[i].Window; - ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); - } - ImGui::TreePop(); - } + // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result) + int stack_level = tool->StackLevel; + if (stack_level >= 0 && stack_level < tool->Results.Size) + if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2) + tool->StackLevel++; - if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize())) + // Update hook + stack_level = tool->StackLevel; + if (stack_level == -1) + g.DebugHookIdInfo = query_id; + if (stack_level >= 0 && stack_level < tool->Results.Size) { - for (int n = 0; n < g.TabBars.GetSize(); n++) - Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); - ImGui::TreePop(); + g.DebugHookIdInfo = tool->Results[stack_level].ID; + tool->Results[stack_level].QueryFrameCount++; } +} + +// [DEBUG] Stack tool: hooks called by GetID() family functions +void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackTool* tool = &g.DebugStackTool; -#if 0 - if (ImGui::TreeNode("Docking")) + // Step 0: stack query + // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget. + if (tool->StackLevel == -1) { - ImGui::TreePop(); + tool->StackLevel++; + tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo()); + for (int n = 0; n < window->IDStack.Size + 1; n++) + tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id; + return; } -#endif -#if 0 - if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) + // Step 1+: query for individual level + IM_ASSERT(tool->StackLevel >= 0); + if (tool->StackLevel != window->IDStack.Size) + return; + ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel]; + IM_ASSERT(info->ID == id && info->QueryFrameCount > 0); + + switch (data_type) { - ImGui::TreePop(); + case ImGuiDataType_S32: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id); + break; + case ImGuiDataType_String: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id); + break; + case ImGuiDataType_Pointer: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id); + break; + case ImGuiDataType_ID: + if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one. + return; + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id); + break; + default: + IM_ASSERT(0); } + info->QuerySuccess = true; + info->DataType = data_type; +} + +static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size) +{ + ImGuiStackLevelInfo* info = &tool->Results[n]; + ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL; + if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked) + return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name); + if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id) + return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc); + if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers. + return (*buf = 0); +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo() + return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label); #endif + return ImFormatString(buf, buf_size, "???"); +} - if (ImGui::TreeNode("Internal state")) +// Stack Tool: Display UI +void ImGui::ShowStackToolWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); + if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { - const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); - ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); - ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); - ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not - ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); - ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); - ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); - ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); - ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); - ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); - ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); - ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); - ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); - ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); - ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); - ImGui::TreePop(); + End(); + return; } - if (ImGui::TreeNode("Tools")) - { - // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. - if (ImGui::Button("Item Picker..")) - ImGui::DebugStartItemPicker(); - ImGui::SameLine(); - MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); - - ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); - ImGui::Checkbox("Show windows rectangles", &show_windows_rects); - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); - show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count); - if (show_windows_rects && g.NavWindow) + // Display hovered/active status + ImGuiStackTool* tool = &g.DebugStackTool; + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + const ImGuiID active_id = g.ActiveId; +#ifdef IMGUI_ENABLE_TEST_ENGINE + Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : ""); +#else + Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id); +#endif + SameLine(); + MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details."); + + // CTRL+C to copy path + const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime; + Checkbox("Ctrl+C: copy path to clipboard", &tool->CopyToClipboardOnCtrlC); + SameLine(); + TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*"); + if (tool->CopyToClipboardOnCtrlC && IsKeyDown(ImGuiMod_Ctrl) && IsKeyPressed(ImGuiKey_C)) + { + tool->CopyToClipboardLastTime = (float)g.Time; + char* p = g.TempBuffer.Data; + char* p_end = p + g.TempBuffer.Size; + for (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++) { - ImGui::BulletText("'%s':", g.NavWindow->Name); - ImGui::Indent(); - for (int rect_n = 0; rect_n < WRT_Count; rect_n++) + *p++ = '/'; + char level_desc[256]; + StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc)); + for (int n = 0; level_desc[n] && p + 2 < p_end; n++) { - ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); - ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); + if (level_desc[n] == '/') + *p++ = '\\'; + *p++ = level_desc[n]; } - ImGui::Unindent(); } - ImGui::Checkbox("Show details when hovering ImDrawCmd node", &show_drawcmd_details); - ImGui::TreePop(); + *p = '\0'; + SetClipboardText(g.TempBuffer.Data); } - // Tool: Display windows Rectangles and Begin Order - if (show_windows_rects || show_windows_begin_order) + // Display decorated stack + tool->LastActiveFrame = g.FrameCount; + if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders)) { - for (int n = 0; n < g.Windows.Size; n++) + const float id_width = CalcTextSize("0xDDDDDDDD").x; + TableSetupColumn("Seed", ImGuiTableColumnFlags_WidthFixed, id_width); + TableSetupColumn("PushID", ImGuiTableColumnFlags_WidthStretch); + TableSetupColumn("Result", ImGuiTableColumnFlags_WidthFixed, id_width); + TableHeadersRow(); + for (int n = 0; n < tool->Results.Size; n++) { - ImGuiWindow* window = g.Windows[n]; - if (!window->WasActive) - continue; - ImDrawList* draw_list = GetForegroundDrawList(window); - if (show_windows_rects) - { - ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type); - draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); - } - if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow)) - { - char buf[32]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); - float font_size = ImGui::GetFontSize(); - draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); - draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); - } + ImGuiStackLevelInfo* info = &tool->Results[n]; + TableNextColumn(); + Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0); + TableNextColumn(); + StackToolFormatLevelInfo(tool, n, true, g.TempBuffer.Data, g.TempBuffer.Size); + TextUnformatted(g.TempBuffer.Data); + TableNextColumn(); + Text("0x%08X", info->ID); + if (n == tool->Results.Size - 1) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header)); } + EndTable(); } - ImGui::End(); + End(); } #else -void ImGui::ShowMetricsWindow(bool*) { } - -#endif +void ImGui::ShowMetricsWindow(bool*) {} +void ImGui::ShowFontAtlas(ImFontAtlas*) {} +void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} +void ImGui::DebugNodeFont(ImFont*) {} +void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} +void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} +void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {} +void ImGui::DebugNodeWindowsList(ImVector*, const char*) {} +void ImGui::DebugNodeViewport(ImGuiViewportP*) {} + +void ImGui::DebugLog(const char*, ...) {} +void ImGui::DebugLogV(const char*, va_list) {} +void ImGui::ShowDebugLogWindow(bool*) {} +void ImGui::ShowStackToolWindow(bool*) {} +void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {} +void ImGui::UpdateDebugToolItemPicker() {} +void ImGui::UpdateDebugToolStackQueries() {} + +#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS //----------------------------------------------------------------------------- @@ -10100,3 +14796,5 @@ void ImGui::ShowMetricsWindow(bool*) { } #endif //----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/src/ui/imguiLib/imgui.h b/src/ui/imguiLib/imgui.h index 09762fd48..8da4ea1b3 100644 --- a/src/ui/imguiLib/imgui.h +++ b/src/ui/imguiLib/imgui.h @@ -1,42 +1,64 @@ -// dear imgui, v1.74 +// dear imgui, v1.89.6 // (headers) -// See imgui.cpp file for documentation. -// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. -// Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. -// Get latest version at https://github.com/ocornut/imgui +// Help: +// - Read FAQ at http://dearimgui.com/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.com/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues + +// Getting Started? +// - For first-time users having issues compiling/linking/running or issues loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. + +// Library Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') +#define IMGUI_VERSION "1.89.6" +#define IMGUI_VERSION_NUM 18960 +#define IMGUI_HAS_TABLE /* Index of this file: -// Header mess -// Forward declarations and basic types -// ImGui API (Dear ImGui end-user API) -// Flags & Enumerations -// Memory allocations macros -// ImVector<> -// ImGuiStyle -// ImGuiIO -// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) -// Obsolete functions -// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) -// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) -// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Header mess +// [SECTION] Forward declarations and basic types +// [SECTION] Dear ImGui end-user API functions +// [SECTION] Flags & Enumerations +// [SECTION] Helpers: Memory allocations macros, ImVector<> +// [SECTION] ImGuiStyle +// [SECTION] ImGuiIO +// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) +// [SECTION] Platform Dependent Interfaces (ImGuiPlatformImeData) +// [SECTION] Obsolete functions and types */ #pragma once -// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename) +// Configuration file with compile-time options +// (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system') #ifdef IMGUI_USER_CONFIG #include IMGUI_USER_CONFIG #endif -#if !defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H) #include "imconfig.h" -#endif + +#ifndef IMGUI_DISABLE //----------------------------------------------------------------------------- -// Header mess +// [SECTION] Header mess //----------------------------------------------------------------------------- // Includes @@ -45,15 +67,9 @@ Index of this file: #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -// Version -// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) -#define IMGUI_VERSION "1.74" -#define IMGUI_VERSION_NUM 17400 -#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) - // Define attributes of all API symbols declarations (e.g. for DLL under Windows) -// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h) -// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) +// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) #ifndef IMGUI_API #define IMGUI_API #endif @@ -66,24 +82,37 @@ Index of this file: #include #define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h #endif -#if defined(__clang__) || defined(__GNUC__) -#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions. +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) + +// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) #define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) #else #define IM_FMTARGS(FMT) #define IM_FMTLIST(FMT) #endif -#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! -#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. -#if (__cplusplus >= 201100) -#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 + +// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID) +#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) +#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) #else -#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. +#define IM_MSVC_RUNTIME_CHECKS_OFF +#define IM_MSVC_RUNTIME_CHECKS_RESTORE #endif -#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Last Unicode code point supported by this build. -#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Standard invalid Unicode code point. // Warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#endif #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" @@ -92,14 +121,15 @@ Index of this file: #endif #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //----------------------------------------------------------------------------- -// Forward declarations and basic types +// [SECTION] Forward declarations and basic types //----------------------------------------------------------------------------- +// Forward declarations struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. @@ -109,6 +139,7 @@ struct ImDrawListSplitter; // Helper to split a draw list into differen struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) struct ImFont; // Runtime data for a single font within a parent ImFontAtlas struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontBuilderIO; // Opaque interface to a font builder (stb_truetype or FreeType). struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data @@ -116,34 +147,46 @@ struct ImColor; // Helper functions to create a color that c struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. struct ImGuiListClipper; // Helper to manually clip large list of items -struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformImeData; // Platform IME data for io.SetPlatformImeDataFn() function. struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) struct ImGuiStorage; // Helper for key->value storage struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) -struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]") - -// Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) -// Use your programming IDE "Go to definition" facility on the names in the central column below to find the actual flags/enum lists. -#ifndef ImTextureID -typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) -#endif -typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) -typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings. +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor + +// Enumerations +// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) +enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen) typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction -typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) -typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation -typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier +typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape +typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending) typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling -typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect(), AddRectFilled() etc. -typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList -typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas +typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() + +// Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() @@ -151,101 +194,134 @@ typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: f typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() +typedef int ImGuiKeyChord; // -> ImGuiKey | ImGuiMod_XXX // Flags: for storage only for now: an ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values. +typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: For BeginTable() +typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() +typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() -typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data); -typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); + +// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] +// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. +#ifndef ImTextureID +typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +#endif + +// ImDrawIdx: vertex index. [Compile-time configurable type] +// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). +// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) +#endif // Scalar data types +typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) typedef signed char ImS8; // 8-bit signed integer typedef unsigned char ImU8; // 8-bit unsigned integer typedef signed short ImS16; // 16-bit signed integer typedef unsigned short ImU16; // 16-bit unsigned integer typedef signed int ImS32; // 32-bit signed integer == int typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) -#if defined(_MSC_VER) && !defined(__clang__) -typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) -typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) -#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) -#include -typedef int64_t ImS64; // 64-bit signed integer (pre C++11) -typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer + +// Character types +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) +typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. +typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. +#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] +typedef ImWchar32 ImWchar; #else -typedef signed long long ImS64; // 64-bit signed integer (post C++11) -typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) +typedef ImWchar16 ImWchar; #endif -// 2D vector (often used to store positions, sizes, etc.) +// Callback and functions types +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText() +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() + +// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] +// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. +IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { - float x, y; - ImVec2() { x = y = 0.0f; } - ImVec2(float _x, float _y) { x = _x; y = _y; } - float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. - float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. + float x, y; + constexpr ImVec2() : x(0.0f), y(0.0f) { } + constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif }; -// 4D vector (often used to store floating-point colors) +// ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] struct ImVec4 { - float x, y, z, w; - ImVec4() { x = y = z = w = 0.0f; } - ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } + float x, y, z, w; + constexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { } + constexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } #ifdef IM_VEC4_CLASS_EXTRA IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. #endif }; +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- -// ImGui: Dear ImGui end-user API -// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui source files!) +// [SECTION] Dear ImGui end-user API functions +// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) //----------------------------------------------------------------------------- namespace ImGui { // Context creation and access - // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. - // None of those functions is reliant on the current context. + // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for details. IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context IMGUI_API ImGuiContext* GetCurrentContext(); IMGUI_API void SetCurrentContext(ImGuiContext* ctx); - IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // Main IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) - IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame. + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame! IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). - IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(), you likely don't need to call that yourself directly. If you don't need to render data (skipping rendering) you may call EndFrame() but you'll have wasted CPU already! If you don't need to render, better to not create any imgui windows and not call NewFrame() at all! - IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can get call GetDrawData() to obtain it and run your rendering function. (Obsolete: this used to call io.RenderDrawListsFn(). Nowadays, we allow and prefer calling your render function yourself.) + IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. // Demo, Debug, Information - IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. + IMGUI_API void ShowDebugLogWindow(bool* p_open = NULL); // create Debug Log window. display a simplified log of important dear imgui events. + IMGUI_API void ShowStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. - IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debug window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. - IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). - IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION) + IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as an end-user (mouse/keyboard controls). + IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp) // Styles IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) - IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style // Windows // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. - // - You may append multiple times to the same window during the same frame. // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, // which clicking will set the boolean to false when clicked. + // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. + // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, @@ -259,9 +335,12 @@ namespace ImGui // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. - // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().] - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value. + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); IMGUI_API void EndChild(); // Windows Utilities @@ -276,40 +355,43 @@ namespace ImGui IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) - // Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). - IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. + // Window manipulation + // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() - IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. + IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // set next window scrolling value (use < 0.0f to not affect a given axis). + IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. - IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). - IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). + IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. // Content region - // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion) - IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful. + // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() - IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates - IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates - IMGUI_API float GetWindowContentRegionWidth(); // - IMGUI_API float GetWindowContentRegionHeight(); // + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates // Windows Scrolling - IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] - IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] - IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X - IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y - IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] - IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] + // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). + // - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). + IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. @@ -318,43 +400,49 @@ namespace ImGui // Parameters stacks (shared) IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font IMGUI_API void PopFont(); - IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). IMGUI_API void PopStyleVar(int count = 1); - IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. - IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied - IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API - IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier - IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied - IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied + IMGUI_API void PushTabStop(bool tab_stop); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopTabStop(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); // Parameters stacks (current window) - IMGUI_API void PushItemWidth(float item_width); // set width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width, + IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). IMGUI_API void PopItemWidth(); - IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) + IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side) IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. - IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); - IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets - IMGUI_API void PopAllowKeyboardFocus(); - IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. - IMGUI_API void PopButtonRepeat(); + + // Style read access + // - Use the ShowStyleEditor() function to interactively see/edit the colors. + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. // Cursor / Layout // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. - // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceeding widget. + // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. + // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: + // Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() + // Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. - IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in a horizontal-layout context. IMGUI_API void Spacing(); // add vertical spacing. IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. - IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 - IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0 IMGUI_API void BeginGroup(); // lock horizontal starting position IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) @@ -364,8 +452,8 @@ namespace ImGui IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) IMGUI_API void SetCursorPosY(float local_y); // IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (useful to work with ImDrawList API). generally top-left == GetMainViewport()->Pos == (0,0) in single viewport mode, and bottom-right == GetMainViewport()->Pos+Size == io.DisplaySize in single-viewport mode. + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) IMGUI_API float GetTextLineHeight(); // ~ FontSize IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) @@ -373,11 +461,15 @@ namespace ImGui IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) // ID stack/scopes - // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most - // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. - // - The resulting ID are hashes of the entire stack. + // Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. + // - Those questions are answered and impacted by understanding of the ID stack system: + // - "Q: Why is my widget not reacting when I click on it?" + // - "Q: How can I have widgets with an empty label?" + // - "Q: How can I have multiple widgets with the same label?" + // - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely + // want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. - // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, // whereas "str_id" denote a string that is only used as an ID and not normally displayed. IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). @@ -402,82 +494,88 @@ namespace ImGui IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line // Widgets: Main // - Most widgets return true when the value has been changed or when pressed/selected // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. - IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text - IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape - IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); - IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, int* flags, int flags_value); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer - template - IMGUI_API bool RadioButton(const char* label, T* v, T v_button) { - const bool pressed = RadioButton(label, *v == v_button); - if (pressed) - *v = v_button; - return pressed; - } // shortcut to handle the above pattern when value is an integer - IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1,0), const char* overlay = NULL); - IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses - - // Widgets: Combo Box + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); + IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + + // Widgets: Images + // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + + // Widgets: Combo Box (Dropdown) // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. - // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); - // Widgets: Drags - // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds. - // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // Widgets: Drag Sliders + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function argument is the same as 'float* v', + // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). - // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits. - // - Use v_min > v_max to lock edits. - IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound - IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f); - IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); // If v_min >= v_max we have no bound - IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); - IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); - IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); - IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL); - IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f); - IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f); - - // Widgets: Sliders - // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. + // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. + // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. + // - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + + // Widgets: Regular Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders - IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg"); - IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d"); - IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d"); - IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d"); - IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d"); - IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d"); - IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). + // - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); // Widgets: Input with Keyboard - // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h + // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); @@ -491,14 +589,14 @@ namespace ImGui IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); - // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) + // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); - IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0)); // display a colored square/button, hover for details, return true when pressed. + IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. // Widgets: Trees @@ -514,28 +612,32 @@ namespace ImGui IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. - IMGUI_API void TreePush(const void* ptr_id = NULL); // " + IMGUI_API void TreePush(const void* ptr_id); // " IMGUI_API void TreePop(); // ~ Unindent()+PopId() IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). - IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header + IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. // Widgets: Selectables // - A selectable highlights when hovered, and can display another color when selected. // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. - IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height - IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. // Widgets: List Boxes - // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. + // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. + // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth + // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region + IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); - IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. - IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " - IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! // Widgets: Data Plotting + // - Consider using ImPlot (https://github.com/epezent/implot) which is much better! IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); @@ -550,46 +652,128 @@ namespace ImGui // Widgets: Menus // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. - // - Use BeginMainMenuBar() to create a menu bar at the top of the screen. + // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. + // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. + // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! - IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Tooltips - // - Tooltip are windows following the mouse which do not take focus away. - IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). - IMGUI_API void EndTooltip(); + // - Tooltip are windows following the mouse. They do not take focus away. + IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). + IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip() returns true! IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); // Popups, Modals - // The properties of popups windows are: - // - They block normal mouse hovering detection outside them. (*) - // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. - // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. - // User can manipulate the visibility state by calling OpenPopup(). - // (*) You can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. - // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. - IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). - IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! - IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! - IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window. - IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (where there are no imgui windows). - IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) - IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! - IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened. - IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack. - IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. - - // Columns + // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. + // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. + // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). + // - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. + // This is sometimes leading to confusing mistakes. May rework this in the future. + + // Popups: begin/end functions + // - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window. + // - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, has a title bar. + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. + IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! + + // Popups: open/close functions + // - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. + // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). + // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). + // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. + // - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter + IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). + IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) + IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. + + // Popups: open+begin combined functions helpers + // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. + // - They are convenient to easily create context menus, hence the name. + // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. + // - IMPORTANT: Notice that we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). + + // Popups: query functions + // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. + IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. + + // Tables + // - Full-featured replacement for old Columns API. + // - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary. + // - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. + // The typical call flow is: + // - 1. Call BeginTable(), early out if returning false. + // - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. + // - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. + // - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. + // - 5. Populate contents: + // - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. + // - If you are using tables as a sort of grid, where every column is holding the same type of contents, + // you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). + // TableNextColumn() will automatically wrap-around into the next row if needed. + // - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! + // - Summary of possible call flow: + // -------------------------------------------------------------------------------------------------------- + // TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK + // TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK + // TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! + // TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! + // -------------------------------------------------------------------------------------------------------- + // - 5. Call EndTable() + IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); + IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! + IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. + IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. + IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. + + // Tables: Headers & Columns declaration + // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. + // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. + // Headers are required to perform: reordering, sorting, and opening the context menu. + // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. + // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in + // some advanced use cases (e.g. adding custom widgets in header row). + // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); + IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu + IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) + + // Tables: Sorting & Miscellaneous functions + // - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. + // When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have + // changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, + // else you may wastefully sort your data every frame! + // - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable(). + IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) + IMGUI_API int TableGetColumnIndex(); // return current column index. + IMGUI_API int TableGetRowIndex(); // return current row index. + IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. + IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column. + IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) + IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. + + // Legacy Columns API (prefer using Tables!) // - You can also use SameLine(pos_x) to mimic simplified columns. - // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) - // - By end of the 2019 we will expose a new 'Table' api which will replace columns. IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index @@ -600,10 +784,12 @@ namespace ImGui IMGUI_API int GetColumnsCount(); // Tab Bars, Tabs + // - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself. IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! - IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. // Logging/Capture @@ -614,18 +800,30 @@ namespace ImGui IMGUI_API void LogFinish(); // stop logging (close file, etc.) IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + IMGUI_API void LogTextV(const char* fmt, va_list args) IM_FMTLIST(1); // Drag and Drop - // [BETA API] API may evolve! - IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() - IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + // - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource(). + // - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget(). + // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) + // - An item can be both drag source and drop target. + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. Return true when payload has been accepted. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. + // Disabling [BETA API] + // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) + // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) + // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. + IMGUI_API void BeginDisabled(bool disabled = true); + IMGUI_API void EndDisabled(); + // Clipping + // - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only. IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); IMGUI_API void PopClipRect(); @@ -634,98 +832,127 @@ namespace ImGui IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. - // Item/Widgets Utilities - // - Most of the functions are referring to the last/previous item we submitted. + // Item/Widgets Utilities and Query Functions + // - Most of the functions are referring to the previous Item that has been submitted. // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? - IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this is NOT equivalent to the behavior of e.g. Button(). Read comments in function definition. IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). - IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. - IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that require continuous editing. + IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that require continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). IMGUI_API bool IsAnyItemHovered(); // is any item hovered? IMGUI_API bool IsAnyItemActive(); // is any item active? IMGUI_API bool IsAnyItemFocused(); // is any item focused? + IMGUI_API ImGuiID GetItemID(); // get ID of last item (~~ often same ImGui::GetID(label) beforehand) IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectSize(); // get size of last item IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. + // Viewports + // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. + // - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. + // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. + IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL. + + // Background/Foreground Draw Lists + IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + // Miscellaneous Utilities IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. - IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. - IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) IMGUI_API ImGuiStorage* GetStateStorage(); - IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); - IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) + // Text Utilities + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + // Color Utilities IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); - // Inputs Utilities - IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] - IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! - IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down). if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate - IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down).. - IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate - IMGUI_API bool IsMouseDown(int button); // is mouse button held (0=left, 1=right, 2=middle) - IMGUI_API bool IsAnyMouseDown(); // is any mouse button held - IMGUI_API bool IsMouseClicked(int button, bool repeat = false); // did mouse button clicked (went from !Down to Down) (0=left, 1=right, 2=middle) - IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. - IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) - IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold - IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. - IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse + // Inputs Utilities: Keyboard/Mouse/Gamepad + // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). + // - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values: + // - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey. + // - with IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined). + IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. + IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? + IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. + IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. + + // Inputs Utilities: Mouse specific + // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. + // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. + // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') + IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) + IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available + IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls - IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into - IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once. If lock_threshold < -1.0f uses io.MouseDraggingThreshold. - IMGUI_API void ResetMouseDragDelta(int button = 0); // - IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you - IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type - IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. - IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. - - // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) + IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you + IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape + IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instucts your app to ignore inputs). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. + + // Clipboard Utilities + // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. IMGUI_API const char* GetClipboardText(); IMGUI_API void SetClipboardText(const char* text); // Settings/.Ini Utilities // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + // - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables). IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. + // Debug Utilities + IMGUI_API void DebugTextEncoding(const char* text); + IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. + // Memory Allocators - // - All those functions are not reliant on the current context. - // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those. - IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); + // - Those functions are not reliant on the current context. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. + IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data = NULL); + IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data); IMGUI_API void* MemAlloc(size_t size); IMGUI_API void MemFree(void* ptr); } // namespace ImGui //----------------------------------------------------------------------------- -// Flags & Enumerations +// [SECTION] Flags & Enumerations //----------------------------------------------------------------------------- // Flags for ImGui::Begin() +// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and io.ConfigWindowsMoveFromTitleBarOnly) enum ImGuiWindowFlags_ { ImGuiWindowFlags_None = 0, @@ -734,7 +961,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. - ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node). ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file @@ -748,25 +975,22 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) - ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, // [Internal] - ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() - ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() - - // [Obsolete] - //ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items - //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) + ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() }; // Flags for ImGui::InputText() +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive) enum ImGuiInputTextFlags_ { ImGuiInputTextFlags_None = 0, @@ -783,15 +1007,17 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally - ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) - // [Internal] - ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline() - ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) + + // Obsolete names + //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior }; // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() @@ -799,7 +1025,7 @@ enum ImGuiTreeNodeFlags_ { ImGuiTreeNodeFlags_None = 0, ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected - ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) @@ -813,23 +1039,41 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible - ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, +}; - // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap // [renamed in 1.53] -#endif +// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. +// - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat +// small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. +// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. +// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. +// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter +// and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly. +// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). +enum ImGuiPopupFlags_ +{ + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) + ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) + ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space + ImGuiPopupFlags_AnyPopupId = 1 << 7, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel, }; // Flags for ImGui::Selectable() enum ImGuiSelectableFlags_ { ImGuiSelectableFlags_None = 0, - ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window + ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this doesn't close parent popup window ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text - ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 // (WIP) Hit testing to allow subsequent widgets to overlap this one + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one }; // Flags for ImGui::BeginCombo() @@ -843,7 +1087,7 @@ enum ImGuiComboFlags_ ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button - ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest, }; // Flags for ImGui::BeginTabBar() @@ -859,31 +1103,170 @@ enum ImGuiTabBarFlags_ ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, - ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown, }; // Flags for ImGui::BeginTabItem() enum ImGuiTabItemFlags_ { ImGuiTabItemFlags_None = 0, - ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() + ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() + ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab + ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab + ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) + ImGuiTabItemFlags_Trailing = 1 << 7, // Enforce the tab position to the right of the tab bar (before the scrolling buttons) +}; + +// Flags for ImGui::BeginTable() +// - Important! Sizing policies have complex and subtle side effects, much more so than you would expect. +// Read comments/demos carefully + experiment with live demos to get acquainted with them. +// - The DEFAULT sizing policies are: +// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off. +// - When ScrollX is off: +// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. +// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. +// - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all). +// - Stretch Columns will share the remaining width according to their respective weight. +// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// - When ScrollX is on: +// - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed +// - Columns sizing policy allowed: Fixed/Auto mostly. +// - Fixed Columns can be enlarged as needed. Table will show a horizontal scrollbar if needed. +// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. +// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. +// - Read on documentation at the top of imgui_tables.cpp for details. +enum ImGuiTableFlags_ +{ + // Features + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns. + ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) + ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. + ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. + ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. + ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + // Decorations + ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) + ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. + ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. + ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. + ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. + ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appear in Headers). -> May move to style + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers). -> May move to style + // Sizing Policy (read above for defaults) + ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. + ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. + ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). + // Sizing Extra Options + ImGuiTableFlags_NoHostExtendX = 1 << 16, // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. + ImGuiTableFlags_NoHostExtendY = 1 << 17, // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. + ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + // Clipping + ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + // Padding + ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outermost padding. Generally desirable if you have headers. + ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outermost padding. + ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + // Scrolling + ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this creates a child window, ScrollY is currently generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + // Sorting + ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). + ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + + // [Internal] Combinations and masks + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame, +}; + +// Flags for ImGui::TableSetupColumn() +enum ImGuiTableColumnFlags_ +{ + // Input configuration flags + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_Disabled = 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state) + ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column. + ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column. + ImGuiTableColumnFlags_WidthStretch = 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp). + ImGuiTableColumnFlags_WidthFixed = 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable). + ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. + ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. + ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. + ImGuiTableColumnFlags_NoClip = 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command). + ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). + ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. + ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu. + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. + ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). + ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. + ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0). + ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored. + + // Output status flags, read-only via TableGetColumnFlags() + ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags. + ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling. + ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs + ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse + + // [Internal] Combinations and masks + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30, // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) +}; + +// Flags for ImGui::TableNextRow() +enum ImGuiTableRowFlags_ +{ + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0, // Identify header row (set default background color + width of its contents accounted differently for auto column width) +}; + +// Enum for ImGui::TableSetBgColor() +// Background colors are rendering in 3 layers: +// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set. +// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set. +// - Layer 2: draw with CellBg color if set. +// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend with the existing color. +// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows. +// If you set the color of RowBg0 target, your color will override the existing RowBg0 color. +// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. +enum ImGuiTableBgTarget_ +{ + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) + ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) + ImGuiTableBgTarget_CellBg = 3, // Set cell background color (top-most color) }; // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { ImGuiFocusedFlags_None = 0, - ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused - ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) - ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use ImGui::GetIO().WantCaptureMouse instead. - ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows + ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! + ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows, }; // Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() -// Note: if you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that. Please read the FAQ! +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! // Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. enum ImGuiHoveredFlags_ { @@ -891,13 +1274,21 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered - ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window - //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. - ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. - ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is obstructed or overlapped by another window - ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, // Return true even if the item is disabled + ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_NoNavOverride = 1 << 10, // Disable using gamepad/keyboard navigation state when active, always query mouse. ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, - ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, + + // Hovering delays (for tooltips) + ImGuiHoveredFlags_DelayNormal = 1 << 11, // Return true after io.HoverDelayNormal elapsed (~0.30 sec) + ImGuiHoveredFlags_DelayShort = 1 << 12, // Return true after io.HoverDelayShort elapsed (~0.10 sec) + ImGuiHoveredFlags_NoSharedDelay = 1 << 13, // Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) }; // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() @@ -905,8 +1296,8 @@ enum ImGuiDragDropFlags_ { ImGuiDragDropFlags_None = 0, // BeginDragDropSource() flags - ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. - ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disables this behavior so you can still call IsItemHovered() on the source item. ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. @@ -915,7 +1306,7 @@ enum ImGuiDragDropFlags_ ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. - ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery. }; // Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. @@ -949,10 +1340,24 @@ enum ImGuiDir_ ImGuiDir_COUNT }; -// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array -enum ImGuiKey_ +// A sorting direction +enum ImGuiSortDirection_ { - ImGuiKey_Tab, + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. + ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. +}; + +// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. +// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87). +// Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey. +// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921 +// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). +enum ImGuiKey : int +{ + // Keyboard + ImGuiKey_None = 0, + ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, @@ -967,75 +1372,148 @@ enum ImGuiKey_ ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, - ImGuiKey_KeyPadEnter, - ImGuiKey_A, // for text edit CTRL+A: select all - ImGuiKey_C, // for text edit CTRL+C: copy - ImGuiKey_V, // for text edit CTRL+V: paste - ImGuiKey_X, // for text edit CTRL+X: cut - ImGuiKey_Y, // for text edit CTRL+Y: redo - ImGuiKey_Z, // for text edit CTRL+Z: undo - ImGuiKey_COUNT -}; - -// Gamepad/Keyboard directional navigation -// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. -// Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). -// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW. -enum ImGuiNavInput_ -{ - // Gamepad Mapping - ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) - ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) - ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) - ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) - ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) - ImGuiNavInput_DpadRight, // - ImGuiNavInput_DpadUp, // - ImGuiNavInput_DpadDown, // - ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down - ImGuiNavInput_LStickRight, // - ImGuiNavInput_LStickUp, // - ImGuiNavInput_LStickDown, // - ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) - ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) - ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) - ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) - - // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. - // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. - ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt - ImGuiNavInput_KeyLeft_, // move left // = Arrow keys - ImGuiNavInput_KeyRight_, // move right - ImGuiNavInput_KeyUp_, // move up - ImGuiNavInput_KeyDown_, // move down + ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, + ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, + ImGuiKey_Menu, + ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, + ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J, + ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T, + ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, + ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6, + ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12, + ImGuiKey_Apostrophe, // ' + ImGuiKey_Comma, // , + ImGuiKey_Minus, // - + ImGuiKey_Period, // . + ImGuiKey_Slash, // / + ImGuiKey_Semicolon, // ; + ImGuiKey_Equal, // = + ImGuiKey_LeftBracket, // [ + ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) + ImGuiKey_RightBracket, // ] + ImGuiKey_GraveAccent, // ` + ImGuiKey_CapsLock, + ImGuiKey_ScrollLock, + ImGuiKey_NumLock, + ImGuiKey_PrintScreen, + ImGuiKey_Pause, + ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4, + ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9, + ImGuiKey_KeypadDecimal, + ImGuiKey_KeypadDivide, + ImGuiKey_KeypadMultiply, + ImGuiKey_KeypadSubtract, + ImGuiKey_KeypadAdd, + ImGuiKey_KeypadEnter, + ImGuiKey_KeypadEqual, + + // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION + // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) + ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) + ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) + ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) + ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit + ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard + ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak + ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in Windowing mode) + ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing mode) + ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] + ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] + ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) + ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) + ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadRStickLeft, // [Analog] + ImGuiKey_GamepadRStickRight, // [Analog] + ImGuiKey_GamepadRStickUp, // [Analog] + ImGuiKey_GamepadRStickDown, // [Analog] + + // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. + ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, + + // [Internal] Reserved for mod storage + ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, + ImGuiKey_COUNT, + + // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) + // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing + // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those + // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl). + // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. + // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and + // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... + ImGuiMod_None = 0, + ImGuiMod_Ctrl = 1 << 12, // Ctrl + ImGuiMod_Shift = 1 << 13, // Shift + ImGuiMod_Alt = 1 << 14, // Option/Menu + ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows + ImGuiMod_Shortcut = 1 << 11, // Alias for Ctrl (non-macOS) _or_ Super (macOS). + ImGuiMod_Mask_ = 0xF800, // 5-bits + + // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. + // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) + // If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + ImGuiKey_NamedKey_BEGIN = 512, + ImGuiKey_NamedKey_END = ImGuiKey_COUNT, + ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#else + ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys + ImGuiKey_KeysData_OFFSET = 0, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#endif + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 + ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 +#endif +}; + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +// OBSOLETED in 1.88 (from July 2022): ImGuiNavInput and io.NavInputs[]. +// Official backends between 1.60 and 1.86: will keep working and feed gamepad inputs as long as IMGUI_DISABLE_OBSOLETE_KEYIO is not set. +// Custom backends: feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +enum ImGuiNavInput +{ + ImGuiNavInput_Activate, ImGuiNavInput_Cancel, ImGuiNavInput_Input, ImGuiNavInput_Menu, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_DpadDown, + ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp, ImGuiNavInput_LStickDown, ImGuiNavInput_FocusPrev, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakSlow, ImGuiNavInput_TweakFast, ImGuiNavInput_COUNT, - ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ }; +#endif // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { ImGuiConfigFlags_None = 0, - ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. - ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. - ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate. + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. - ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end. - ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. - // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui) + // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. - ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. + ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. }; -// Back-end capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom back-end. +// Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. enum ImGuiBackendFlags_ { ImGuiBackendFlags_None = 0, - ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected. - ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape. - ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). - ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. + ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. }; // Enumeration for PushStyleColor() / PopStyleColor() @@ -1071,10 +1549,10 @@ enum ImGuiCol_ ImGuiCol_Separator, ImGuiCol_SeparatorHovered, ImGuiCol_SeparatorActive, - ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows. ImGuiCol_ResizeGripHovered, ImGuiCol_ResizeGripActive, - ImGuiCol_Tab, + ImGuiCol_Tab, // TabItem in a TabBar ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, @@ -1083,30 +1561,32 @@ enum ImGuiCol_ ImGuiCol_PlotLinesHovered, ImGuiCol_PlotHistogram, ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, // Table header background + ImGuiCol_TableBorderStrong, // Table outer and header borders (prefer using Alpha=1.0 here) + ImGuiCol_TableBorderLight, // Table inner borders (prefer using Alpha=1.0 here) + ImGuiCol_TableRowBg, // Table row background (even rows) + ImGuiCol_TableRowBgAlt, // Table row background (odd rows) ImGuiCol_TextSelectedBg, - ImGuiCol_DragDropTarget, + ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active ImGuiCol_COUNT - - // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63] - , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg // [renamed in 1.53] - //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors. - //ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate. -#endif }; // Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. -// NB: the enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. During initialization, feel free to just poke into ImGuiStyle directly. -// NB: if changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. +// During initialization or between frames, feel free to just poke into ImGuiStyle directly. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. enum ImGuiStyleVar_ { // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding ImGuiStyleVar_WindowRounding, // float WindowRounding ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize @@ -1122,6 +1602,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_CellPadding, // ImVec2 CellPadding ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding ImGuiStyleVar_GrabMinSize, // float GrabMinSize @@ -1129,13 +1610,23 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize + ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign + ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding ImGuiStyleVar_COUNT +}; - // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT // [renamed in 1.60] - , ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding // [renamed in 1.53] -#endif +// Flags for InvisibleButton() [extended in imgui_internal.h] +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) + ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button + + // [Internal] + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft, }; // Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() @@ -1143,14 +1634,15 @@ enum ImGuiColorEditFlags_ { ImGuiColorEditFlags_None = 0, ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). - ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on color square. ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. - ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) - ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable color square preview next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview color square). ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). - ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. + ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) // User Options (right-click on widget to change some of them). ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. @@ -1169,70 +1661,106 @@ enum ImGuiColorEditFlags_ // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. - ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks - ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_DisplayHSV|ImGuiColorEditFlags_DisplayHex, - ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_Float, - ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel|ImGuiColorEditFlags_PickerHueBar, - ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_InputHSV + ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, - // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] -#endif + // Obsolete names + //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] +}; + +// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigDragClickToInputText) +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. + ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) + ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget + ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + + // Obsolete names + //ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79] +}; + +// Identify a mouse button. +// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. +enum ImGuiMouseButton_ +{ + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 }; // Enumeration for GetMouseCursor() -// User code may request binding to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here enum ImGuiMouseCursor_ { ImGuiMouseCursor_None = -1, ImGuiMouseCursor_Arrow = 0, ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) - ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border + ImGuiMouseCursor_ResizeNS, // When hovering over a horizontal border ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. ImGuiMouseCursor_COUNT +}; - // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT // [renamed in 1.60] -#endif +// Enumeration for AddMouseSourceEvent() actual source of Mouse Input data. +// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent() +// But that "Mouse" data can come from different source which occasionally may be useful for application to know about. +// You can submit a change of pointer type using io.AddMouseSourceEvent(). +enum ImGuiMouseSource : int +{ + ImGuiMouseSource_Mouse = 0, // Input is coming from an actual mouse. + ImGuiMouseSource_TouchScreen, // Input is coming from a touch screen (no hovering prior to initial press, less precise initial press aiming, dual-axis wheeling possible). + ImGuiMouseSource_Pen, // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling rates). + ImGuiMouseSource_COUNT }; -// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions +// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions // Represent a condition. // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. enum ImGuiCond_ { - ImGuiCond_Always = 1 << 0, // Set the variable - ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call with succeed) + ImGuiCond_None = 0, // No condition (always set the variable), same as _Always + ImGuiCond_Always = 1 << 0, // No condition (always set the variable), same as _None + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) - ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) + ImGuiCond_Appearing = 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) }; //----------------------------------------------------------------------------- -// Helpers: Memory allocations macros +// [SECTION] Helpers: Memory allocations macros, ImVector<> +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- // IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. -// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. //----------------------------------------------------------------------------- -struct ImNewDummy {}; -inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } -inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new() +struct ImNewWrapper {}; +inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() #define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) #define IM_FREE(_PTR) ImGui::MemFree(_PTR) -#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) -#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) +#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } //----------------------------------------------------------------------------- -// Helper: ImVector<> +// ImVector<> // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). //----------------------------------------------------------------------------- // - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. @@ -1242,6 +1770,7 @@ template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p // Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. //----------------------------------------------------------------------------- +IM_MSVC_RUNTIME_CHECKS_OFF template struct ImVector { @@ -1257,17 +1786,21 @@ struct ImVector // Constructors, destructor inline ImVector() { Size = Capacity = 0; Data = NULL; } inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } - inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } - inline ~ImVector() { if (Data) IM_FREE(Data); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything + + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything + inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit. + inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit. inline bool empty() const { return Size == 0; } inline int size() const { return Size; } inline int size_in_bytes() const { return Size * (int)sizeof(T); } + inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } inline int capacity() const { return Capacity; } - inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } - inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } - inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } inline T* begin() { return Data; } inline const T* begin() const { return Data; } inline T* end() { return Data + Size; } @@ -1278,20 +1811,21 @@ struct ImVector inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } + inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } + inline void reserve_discard(int new_capacity) { if (new_capacity <= Capacity) return; if (Data) IM_FREE(Data); Data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); Capacity = new_capacity; } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } inline void pop_back() { IM_ASSERT(Size > 0); Size--; } inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } - inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } - inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } - inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } - inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last >= it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } @@ -1299,9 +1833,11 @@ struct ImVector inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } }; +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- -// ImGuiStyle +// [SECTION] ImGuiStyle +//----------------------------------------------------------------------------- // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). // During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, // and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. @@ -1310,10 +1846,11 @@ struct ImVector struct ImGuiStyle { float Alpha; // Global alpha applies to everything in Dear ImGui. + float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. ImVec2 WindowPadding; // Padding within a window. - float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). - ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints(). ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. @@ -1325,6 +1862,7 @@ struct ImGuiStyle float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + ImVec2 CellPadding; // Padding within a table cell ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). @@ -1332,17 +1870,24 @@ struct ImGuiStyle float ScrollbarRounding; // Radius of grab corners for scrollbar. float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. + float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). - ImVec2 SelectableTextAlign; // Alignment of selectable text when selectable is larger than text. Defaults to (0.0f, 0.0f) (top-left aligned). - ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. + ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + float SeparatorTextBorderSize; // Thickkness of border in SeparatorText() + ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. + ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. - bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. - bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); @@ -1350,31 +1895,43 @@ struct ImGuiStyle }; //----------------------------------------------------------------------------- -// ImGuiIO +// [SECTION] ImGuiIO +//----------------------------------------------------------------------------- // Communicate most settings and inputs/outputs to Dear ImGui using this structure. // Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. //----------------------------------------------------------------------------- +// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. +// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. +struct ImGuiKeyData +{ + bool Down; // True for if key is down + float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) + float DownDurationPrev; // Last frame duration the key has been down + float AnalogValue; // 0.0f..1.0f for gamepad values +}; + struct ImGuiIO { //------------------------------------------------------------------ - // Configuration (fill once) // Default value + // Configuration // Default value //------------------------------------------------------------------ ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. - ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. - ImVec2 DisplaySize; // // Main display size, in pixels. - float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. + ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame. + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. - const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. + const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. - float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. - void* UserData; // = NULL // Store your own data for retrieval by callbacks. + float HoverDelayNormal; // = 0.30 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayNormal) returns true. + float HoverDelayShort; // = 0.10 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayShort) returns true. + void* UserData; // = NULL // Store your own data. ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. float FontGlobalScale; // = 1.0f // Global scale all fonts @@ -1383,24 +1940,39 @@ struct ImGuiIO ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. // Miscellaneous options - bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) - bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. + bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). + bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) - bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. - float ConfigWindowsMemoryCompactTimer;// = 60.0f // [BETA] Compact window memory usage when unused. Set to -1.0f to disable. + bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + + // Debug options + // - tools to test correct Begin/End and BeginChild/EndChild behaviors. + // - presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() + // this is inconsistent with other BeginXXX functions and create confusion for many users. + // - we expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code behavior. + bool ConfigDebugBeginReturnValueOnce;// = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. + bool ConfigDebugBeginReturnValueLoop;// = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. + // - option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data. + // - backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them. + // - consider using e.g. Win32's IsDebuggerPresent() as an additional filter (or see ImOsIsDebuggerPresent() in imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). + bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing. //------------------------------------------------------------------ // Platform Functions - // (the imgui_impl_xxxx back-end files are setting those up for you) + // (the imgui_impl_xxxx backend files are setting those up for you) //------------------------------------------------------------------ - // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. + // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. const char* BackendPlatformName; // = NULL const char* BackendRendererName; // = NULL - void* BackendPlatformUserData; // = NULL - void* BackendRendererUserData; // = NULL - void* BackendLanguageUserData; // = NULL + void* BackendPlatformUserData; // = NULL // User data for platform backend + void* BackendRendererUserData; // = NULL // User data for renderer backend + void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend // Optional: Access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) @@ -1410,97 +1982,128 @@ struct ImGuiIO // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) - void (*ImeSetInputScreenPosFn)(int x, int y); - void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. - + void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! - // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this. - void (*RenderDrawListsFn)(ImDrawData* data); + void* ImeWindowHandle; // = NULL // [Obsolete] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. #else - // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. - void* RenderDrawListsFnUnused; + void* _UnusedPadding; // Unused field to keep data structure the same size. #endif //------------------------------------------------------------------ - // Input - Fill before calling NewFrame() + // Input - Call before calling NewFrame() //------------------------------------------------------------------ - ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX,-FLT_MAX) if mouse is unavailable (on another screen, etc.) - bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. - float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. - float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. - bool KeyCtrl; // Keyboard modifier pressed: Control - bool KeyShift; // Keyboard modifier pressed: Shift - bool KeyAlt; // Keyboard modifier pressed: Alt - bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows - bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). - float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). - float uiScale = 1.0f; - - // Functions - IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input - IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string - IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually + // Input Functions + IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) + IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. + IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) + IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change + IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. + IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) + IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) + IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue a new characters input from a UTF-8 string + + IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. + IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. + IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually + IMGUI_API void ClearInputKeys(); // [Internal] Release all keys //------------------------------------------------------------------ - // Output - Retrieve after calling NewFrame() + // Output - Updated by NewFrame() or EndFrame()/Render() + // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is + // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) //------------------------------------------------------------------ - bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). - bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). - bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). - bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. - bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself. - bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. - bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events). - float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames - int MetricsRenderVertices; // Vertices output during last call to Render() - int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 - int MetricsRenderWindows; // Number of visible windows - int MetricsActiveWindows; // Number of active windows - int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. - ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. + // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). + // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. + bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. + float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +#endif //------------------------------------------------------------------ - // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed! + // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) - ImVec2 MouseClickedPos[5]; // Position at time of clicking - double MouseClickedTime[5]; // Time of last click (used to figure out double-click) - bool MouseClicked[5]; // Mouse button went from !Down to Down - bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? - bool MouseReleased[5]; // Mouse button went from Down to !Down - bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds. - bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click - float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) - float MouseDownDurationPrev[5]; // Previous time the mouse button has been down - ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point - float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point - float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) - float KeysDownDurationPrev[512]; // Previous duration the key has been down - float NavInputsDownDuration[ImGuiNavInput_COUNT]; - float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; - ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. + ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). + + // Main Input State + // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) + // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll. + float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. + ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). + bool KeyCtrl; // Keyboard modifier down: Control + bool KeyShift; // Keyboard modifier down: Shift + bool KeyAlt; // Keyboard modifier down: Alt + bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows + + // Other state maintained from data above + IO function calls + ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame() + ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. + bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down + ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. + bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) + float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. + bool AppFocusLost; // Only modify via AddFocusEvent() + bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() + ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] + bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. IMGUI_API ImGuiIO(); }; //----------------------------------------------------------------------------- -// Misc data structures +// [SECTION] Misc data structures //----------------------------------------------------------------------------- // Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. // The callback function should return 0 by default. // Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows -// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. // - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. struct ImGuiInputTextCallbackData { + ImGuiContext* Ctx; // Parent UI context ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only void* UserData; // What user passed to InputText() // Read-only @@ -1523,14 +2126,16 @@ struct ImGuiInputTextCallbackData IMGUI_API ImGuiInputTextCallbackData(); IMGUI_API void DeleteChars(int pos, int bytes_count); IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); - bool HasSelection() const { return SelectionStart != SelectionEnd; } + void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } + void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } + bool HasSelection() const { return SelectionStart != SelectionEnd; } }; // Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). // NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. struct ImGuiSizeCallbackData { - void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>). ImVec2 Pos; // Read-only. Window position, for reference. ImVec2 CurrentSize; // Read-only. Current window size. ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. @@ -1547,7 +2152,7 @@ struct ImGuiPayload ImGuiID SourceId; // Source item id ImGuiID SourceParentId; // Source parent id (if available) int DataFrameCount; // Data timestamp - char DataType[32+1]; // Data type tag (short user-supplied string, 32 characters max) + char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. @@ -1558,51 +2163,43 @@ struct ImGuiPayload bool IsDelivery() const { return Delivery; } }; -//----------------------------------------------------------------------------- -// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) -// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. -//----------------------------------------------------------------------------- +// Sorting specification for one column of a table (sizeof == 12 bytes) +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) + ImS16 ColumnIndex; // Index of the column + ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) + ImGuiSortDirection SortDirection : 8; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending (you can use this or SortSign, whichever is more convenient for your sort function) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -namespace ImGui + ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +// Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +// Obtained by calling TableGetSortSpecs(). +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. +// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! +struct ImGuiTableSortSpecs { - // OBSOLETED in 1.72 (from July 2019) - static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } - // OBSOLETED in 1.71 (from June 2019) - static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } - // OBSOLETED in 1.70 (from May 2019) - static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } - // OBSOLETED in 1.69 (from Mar 2019) - static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } - // OBSOLETED in 1.66 (from Sep 2018) - static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } - // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018) - static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } - // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018) - IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! - IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); - // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) - static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } - static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } - static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; } - // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - static inline void ShowTestWindow() { return ShowDemoWindow(); } - static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } - static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } - static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } - static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } -} -typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent -typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; -#endif + const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. + int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. + bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. + + ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } +}; //----------------------------------------------------------------------------- -// Helpers +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) //----------------------------------------------------------------------------- -// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. +// Helper: Unicode defines +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#endif + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame. // Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); struct ImGuiOnceUponAFrame { @@ -1710,36 +2307,82 @@ struct ImGuiStorage }; // Helper: Manually clip large list of items. -// If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all. +// If you have lots evenly spaced items and you have random access to the list, you can perform coarse +// clipping based on visibility to only submit items that are in view. // The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. -// ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null. +// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally +// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily +// scale using lists with tens of thousands of items without a problem) // Usage: -// ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. -// while (clipper.Step()) -// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) -// ImGui::Text("line number %d", i); -// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor). -// - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. -// - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.) -// - Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. +// ImGuiListClipper clipper; +// clipper.Begin(1000); // We have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// Generally what happens is: +// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. +// - User code submit that one element. +// - Clipper can measure the height of the first element +// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. +// - User code submit visible elements. +// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. struct ImGuiListClipper { - float StartPosY; - float ItemsHeight; - int ItemsCount, StepNo, DisplayStart, DisplayEnd; - - // items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step). + ImGuiContext* Ctx; // Parent UI context + int DisplayStart; // First item to display, updated by each call to Step() + int DisplayEnd; // End of items to display (exclusive) + int ItemsCount; // [Internal] Number of items + float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it + float StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + void* TempData; // [Internal] Internal data + + // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step) // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). - // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step(). - ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want). - ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // Assert if user forgot to call End() or Step() until false. + IMGUI_API ImGuiListClipper(); + IMGUI_API ~ImGuiListClipper(); + IMGUI_API void Begin(int items_count, float items_height = -1.0f); + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. - IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. - IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. - IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. + // Call IncludeRangeByIndices() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility. + // (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range). + IMGUI_API void IncludeRangeByIndices(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeRangeByIndices(item_begin, item_end); } // [renamed in 1.89.6] + //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] +#endif }; +// Helpers: ImVec2/ImVec4 operators +// - It is important that we are keeping those disabled by default so they don't leak in user space. +// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) +// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED +IM_MSVC_RUNTIME_CHECKS_OFF +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + // Helpers macros to generate 32-bit encoded colors +// User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. +#ifndef IM_COL32_R_SHIFT #ifdef IMGUI_USE_BGRA_PACKED_COLOR #define IM_COL32_R_SHIFT 16 #define IM_COL32_G_SHIFT 8 @@ -1753,6 +2396,7 @@ struct ImGuiListClipper #define IM_COL32_A_SHIFT 24 #define IM_COL32_A_MASK 0xFF000000 #endif +#endif #define IM_COL32(R,G,B,A) (((ImU32)(A)<>IM_COL32_R_SHIFT)&0xFF) * sc; Value.y = (float)((rgba>>IM_COL32_G_SHIFT)&0xFF) * sc; Value.z = (float)((rgba>>IM_COL32_B_SHIFT)&0xFF) * sc; Value.w = (float)((rgba>>IM_COL32_A_SHIFT)&0xFF) * sc; } - ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } - ImColor(const ImVec4& col) { Value = col; } + constexpr ImColor() { } + constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { } + constexpr ImColor(const ImVec4& col) : Value(col) {} + ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } + ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } inline operator ImVec4() const { return Value; } // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } - static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r,g,b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r,g,b,a); } + static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } }; //----------------------------------------------------------------------------- -// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) // Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. //----------------------------------------------------------------------------- -// Draw callbacks for advanced uses. +// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. +#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) +#endif + +// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] // NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, // you can poke into the draw list for that! Draw callback may be useful for example to: // A) Change your GPU render state, // B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' -// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering back-end accordingly. +// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly. #ifndef ImDrawCallback typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); #endif -// Special Draw callback value to request renderer back-end to reset the graphics/render state. -// The renderer back-end needs to handle this special value, otherwise it will crash trying to call a function at this address. +// Special Draw callback value to request renderer backend to reset the graphics/render state. +// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. // This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. // It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). #define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) // Typically, 1 command = 1 GPU draw call (unless command is a callback) -// Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' -// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Backends made for <1.71. will typically ignore the VtxOffset fields. +// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). struct ImDrawCmd { - unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. - ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates - ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. - unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices. - unsigned int IdxOffset; // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. - ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. - void* UserCallbackData; // The draw callback code can access this. - - ImDrawCmd() { ElemCount = 0; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; } + ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. + unsigned int IdxOffset; // 4 // Start offset in index buffer. + unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + void* UserCallbackData; // 4-8 // The draw callback code can access this. + + ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + + // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) + inline ImTextureID GetTexID() const { return TextureId; } }; -// Vertex index -// (to allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end) -// (to use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h) -#ifndef ImDrawIdx -typedef unsigned short ImDrawIdx; -#endif - // Vertex layout #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert @@ -1835,27 +2482,36 @@ struct ImDrawVert #else // You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h // The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. -// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up. +// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared at the time you'd want to set your type up. // NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; #endif -// For use by ImDrawListSplitter. +// [Internal] For use by ImDrawList +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; + +// [Internal] For use by ImDrawListSplitter struct ImDrawChannel { ImVector _CmdBuffer; ImVector _IdxBuffer; }; + // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. -// This is used by the Columns api, so items of each column can be batched together in a same draw call. +// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. struct ImDrawListSplitter { int _Current; // Current channel number (0) int _Count; // Number of active channels (1+) ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) - inline ImDrawListSplitter() { Clear(); } + inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } inline ~ImDrawListSplitter() { ClearFreeMemory(); } inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame IMGUI_API void ClearFreeMemory(); @@ -1864,26 +2520,35 @@ struct ImDrawListSplitter IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); }; -enum ImDrawCornerFlags_ +// Flags for ImDrawList functions +// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused) +enum ImDrawFlags_ { - ImDrawCornerFlags_None = 0, - ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 - ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 - ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 - ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 - ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 - ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC - ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 - ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA - ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason) + ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. + ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. + ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. + ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified. + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, }; +// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. +// It is however possible to temporarily alter flags between calls to ImDrawList:: functions. enum ImDrawListFlags_ { - ImDrawListFlags_None = 0, - ImDrawListFlags_AntiAliasedLines = 1 << 0, // Lines are anti-aliased (*2 the number of triangles for 1.0f wide line, otherwise *3 the number of triangles) - ImDrawListFlags_AntiAliasedFill = 1 << 1, // Filled shapes have anti-aliased edges (*2 the number of vertices) - ImDrawListFlags_AllowVtxOffset = 1 << 2 // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). + ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). + ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. }; // Draw command list @@ -1892,7 +2557,8 @@ enum ImDrawListFlags_ // Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to // access the current window draw list and draw custom primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. -// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well) +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). +// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) // Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. struct ImDrawList { @@ -1903,21 +2569,23 @@ struct ImDrawList ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. // [Internal, used while building lists] - const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. + ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) const char* _OwnerName; // Pointer to owner window's name for debugging - unsigned int _VtxCurrentOffset; // [Internal] Always 0 unless 'Flags & ImDrawListFlags_AllowVtxOffset'. - unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImVector _ClipRectStack; // [Internal] ImVector _TextureIdStack; // [Internal] ImVector _Path; // [Internal] current path building - ImDrawListSplitter _Splitter; // [Internal] for channels api + ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). + ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) + float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) - ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); } - ~ImDrawList() { ClearFreeMemory(); } - IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } + + ~ImDrawList() { _ClearFreeMemory(); } + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); IMGUI_API void PushTextureID(ImTextureID texture_id); @@ -1926,22 +2594,30 @@ struct ImDrawList inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } // Primitives + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. + // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). + // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. + // In future versions we will use textures to provide cheaper and higher-quality circles. + // Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides. IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round - IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size) IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); - IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); - IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 12); + IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); + IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); - IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness); - IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. - IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness); + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); + IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) // Image primitives // - Read FAQ to understand what ImTextureID is. @@ -1949,18 +2625,20 @@ struct ImDrawList // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); - IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); // Stateful path API, add points then finish with PathFillConvex() or PathStroke() + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. inline void PathClear() { _Path.Size = 0; } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } - inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } - inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. - inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } - IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); - IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle - IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); - IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } + inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0); + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); // Advanced IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. @@ -1968,25 +2646,42 @@ struct ImDrawList IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. // Advanced: Channels - // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives) - // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end) + // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) + // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! + // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. + // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } inline void ChannelsMerge() { _Splitter.Merge(this); } inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } - // Internal helpers - // NB: all primitives needs to be reserved via PrimReserve() beforehand! - IMGUI_API void Clear(); - IMGUI_API void ClearFreeMemory(); + // Advanced: Primitives allocations + // - We render triangles (three vertices) + // - All primitives needs to be reserved via PrimReserve() beforehand. IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); - inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col){ _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } - inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } - inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } - IMGUI_API void UpdateClipRect(); - IMGUI_API void UpdateTextureID(); + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index + + // Obsolete names + //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + + // [Internal helpers] + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _TryMergeDrawCmds(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; + IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); + IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); }; // All draw data to render a Dear ImGui frame @@ -1995,24 +2690,23 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. int CmdListsCount; // Number of ImDrawList* to render int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size - ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) - ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. // Functions - ImDrawData() { Valid = false; Clear(); } - ~ImDrawData() { Clear(); } - void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! + ImDrawData() { Clear(); } + void Clear() { memset(this, 0, sizeof(*this)); } // The ImDrawList are owned by ImGuiContext! IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. }; //----------------------------------------------------------------------------- -// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) //----------------------------------------------------------------------------- struct ImFontConfig @@ -2022,16 +2716,16 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). int FontNo; // 0 // Index of font within TTF/OTF file float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. - const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. + const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. - unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. + unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. @@ -2042,9 +2736,13 @@ struct ImFontConfig IMGUI_API ImFontConfig(); }; +// Hold rendering data for one glyph. +// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) struct ImFontGlyph { - ImWchar Codepoint; // 0x0000..0xFFFF + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int Codepoint : 30; // 0x0000..0x10FFFF float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates @@ -2056,11 +2754,11 @@ struct ImFontGlyphRangesBuilder { ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - ImFontGlyphRangesBuilder() { Clear(); } - inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX+1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } - inline bool GetBit(int n) const { int off = (n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array - inline void SetBit(int n) { int off = (n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array - inline void AddChar(ImWchar c) { SetBit(c); } // Add character + ImFontGlyphRangesBuilder() { Clear(); } + inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } + inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array + inline void AddChar(ImWchar c) { SetBit(c); } // Add character IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges @@ -2069,21 +2767,23 @@ struct ImFontGlyphRangesBuilder // See ImFontAtlas::AddCustomRectXXX functions. struct ImFontAtlasCustomRect { - unsigned int ID; // Input // User ID. Use < 0x110000 to map into a font glyph, >= 0x110000 for other/internal/custom texture data. unsigned short Width, Height; // Input // Desired rectangle dimension unsigned short X, Y; // Output // Packed position in Atlas - float GlyphAdvanceX; // Input // For custom font glyphs only (ID < 0x110000): glyph xadvance - ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID < 0x110000): glyph display offset - ImFont* Font; // Input // For custom font glyphs only (ID < 0x110000): target font - ImFontAtlasCustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; } + unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) + float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset + ImFont* Font; // Input // For custom font glyphs only: target font + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; +// Flags for ImFontAtlas build enum ImFontAtlasFlags_ { ImFontAtlasFlags_None = 0, ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two - ImFontAtlasFlags_NoMouseCursors = 1 << 1 // Don't build software mouse cursors into the atlas + ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) + ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory, allow support for point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). }; // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: @@ -2102,7 +2802,7 @@ enum ImFontAtlasFlags_ // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, // - Even though many functions are suffixed with "TTF", OTF data is supported just as well. -// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! +// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the future! struct ImFontAtlas { IMGUI_API ImFontAtlas(); @@ -2126,7 +2826,7 @@ struct ImFontAtlas IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... void SetTexID(ImTextureID id) { TexID = id; } //------------------------------------------- @@ -2134,11 +2834,13 @@ struct ImFontAtlas //------------------------------------------- // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) - // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. + // NB: Make sure that your string are UTF-8 and NOT in your local code page. + // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesGreek(); // Default + Greek and Coptic IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters - IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters @@ -2150,13 +2852,15 @@ struct ImFontAtlas //------------------------------------------- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. - // After calling Build(), you can query the rectangle position and render your pixels. - // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), - // so you can render e.g. custom colorful icons and use them as regular glyphs. - // Read docs/FONTS.txt for more details about using colorful icons. - IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x110000. Id >= 0x80000000 are reserved for ImGui and ImDrawList - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x110000 to register a rectangle to map into a specific font. - const ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } + // - After calling Build(), you can query the rectangle position and render your pixels. + // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of prefered texture format. + // - You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // - Read docs/FONTS.md for more details about using colorful icons. + // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. + IMGUI_API int AddCustomRectRegular(int width, int height); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } // [Internal] IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; @@ -2166,14 +2870,17 @@ struct ImFontAtlas // Members //------------------------------------------- - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool TexReady; // Set when texture was built matching current font input + bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 int TexWidth; // Texture width calculated during Build(). @@ -2182,13 +2889,20 @@ struct ImFontAtlas ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. - ImVector ConfigData; // Internal data - int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList + ImVector ConfigData; // Configuration data + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ - typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ -#endif + // [Internal] Font builder + const ImFontBuilderIO* FontBuilderIO; // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). + unsigned int FontBuilderFlags; // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig. + + // [Internal] Packing data + int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors + int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines + + // [Obsolete] + //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; // Font runtime data and rendering @@ -2200,22 +2914,25 @@ struct ImFont float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) - // Members: Hot ~36/48 bytes (for CalcTextSize + render loop) + // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // // All glyphs. const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) - ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels // Members: Cold ~32/40 bytes ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. - ImWchar FallbackChar; // 2 // in // = '?' // Replacement character if a glyph isn't found. Only set via SetFallbackChar() - ImWchar EllipsisChar; // 2 // out // = -1 // Character used for ellipsis rendering. + ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. + ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. + short EllipsisCharCount; // 1 // out // 1 or 3 + float EllipsisWidth; // 4 // out // Width + float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + bool DirtyLookupTables; // 1 // out // float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) - bool DirtyLookupTables; // 1 // out // + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. // Methods IMGUI_API ImFont(); @@ -2230,25 +2947,201 @@ struct ImFont // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; - IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; - IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; // [Internal] Don't use! IMGUI_API void BuildLookupTable(); IMGUI_API void ClearOutputData(); IMGUI_API void GrowIndex(int new_size); - IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); + IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. - IMGUI_API void SetFallbackChar(ImWchar c); + IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Viewports +//----------------------------------------------------------------------------- + +// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends. +enum ImGuiViewportFlags_ +{ + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) + ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: is created/managed by the application (rather than a dear imgui backend) +}; + +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +// - About Main Area vs Work Area: +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Windows are generally trying to stay within the Work Area of their host viewport. +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + ImVec2 Pos; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) + ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) + ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + + // Platform/Backend Dependent Data + void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms) + + ImGuiViewport() { memset(this, 0, sizeof(*this)); } + + // Helpers + ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Platform Dependent Interfaces +//----------------------------------------------------------------------------- + +// (Optional) Support for IME (Input Method Editor) via the io.SetPlatformImeDataFn() function. +struct ImGuiPlatformImeData +{ + bool WantVisible; // A widget wants the IME to be visible + ImVec2 InputPos; // Position of the input cursor + float InputLineHeight; // Line height + + ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Obsolete functions and types +// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +namespace ImGui +{ +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // map ImGuiKey_* values into legacy native key index. == io.KeyMap[key] +#else + static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END && "ImGuiKey and native_index was merged together and native_index is disabled by IMGUI_DISABLE_OBSOLETE_KEYIO. Please switch to ImGuiKey."); return key; } +#endif +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.89.4 (from March 2023) + static inline void PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); } + static inline void PopAllowKeyboardFocus() { PopTabStop(); } + // OBSOLETED in 1.89 (from August 2022) + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding) + // OBSOLETED in 1.88 (from May 2022) + static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. + static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. + // OBSOLETED in 1.86 (from November 2021) + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Calculate coarse clipping for large list of evenly sized items. Prefer using ImGuiListClipper. + // OBSOLETED in 1.85 (from August 2021) + static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } + + // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + //-- OBSOLETED in 1.81 (from February 2021) + //static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + //static inline bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } // Helper to calculate size from items_count and height_in_items + //static inline void ListBoxFooter() { EndListBox(); } + //-- OBSOLETED in 1.79 (from August 2020) + //static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! + //-- OBSOLETED in 1.78 (from June 2020): Old drag/sliders functions that took a 'float power > 1.0f' argument instead of ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details. + //IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f) // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //-- OBSOLETED in 1.77 and before + //static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } // OBSOLETED in 1.77 (from June 2020) + //static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } // OBSOLETED in 1.72 (from July 2019) + //static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } // OBSOLETED in 1.71 (from June 2019) + //static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.70 (from May 2019) + //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) + //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) + //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) + //-- OBSOLETED in 1.60 and before + //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) + //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //IMGUI_API bool Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha(). + //static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline void SetNextWindowPosCenter(ImGuiCond c=0) { SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the io.WantCaptureMouse flag instead. + //static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //-- OBSOLETED in 1.50 and before + //static inline bool CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49 + //static inline ImFont*GetWindowFont() { return GetFont(); } // OBSOLETED in 1.48 + //static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETED in 1.48 + //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 +} + +// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() +typedef ImDrawFlags ImDrawCornerFlags; +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit + ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). + ImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight, // Was == 0x02 (1 << 1) prior to 1.82. + ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. + ImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. + ImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll, // Was == 0x0F prior to 1.82 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, }; +// RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022) +// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of obscolescence schedule to reduce confusion and because they were not meant to be used in the first place. +typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with any number of ImGuiMod_XXX value", but you may store only mods in there. +enum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super }; +//typedef ImGuiKeyChord ImGuiKeyModFlags; // == int +//enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super }; + +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +// RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) +#define IMGUI_DISABLE_DEBUG_TOOLS +#endif +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) +#error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. +#endif + +//----------------------------------------------------------------------------- + #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif +#ifdef _MSC_VER +#pragma warning (pop) +#endif + // Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) #ifdef IMGUI_INCLUDE_IMGUI_USER_H #include "imgui_user.h" #endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_android.cpp b/src/ui/imguiLib/imguiImpl/imgui_impl_android.cpp index 4127210d1..48828ec20 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_android.cpp +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_android.cpp @@ -2,28 +2,33 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: +// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2021-03-04: Initial version. #include "imgui.h" #include "imgui_impl_android.h" #include -#include -#include #include #include #include @@ -33,7 +38,119 @@ static double g_Time = 0.0; static ANativeWindow* g_Window; static char g_LogTag[] = "ImGuiExample"; -static std::map> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue. + +static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code) +{ + switch (key_code) + { + case AKEYCODE_TAB: return ImGuiKey_Tab; + case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow; + case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow; + case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow; + case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow; + case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp; + case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown; + case AKEYCODE_MOVE_HOME: return ImGuiKey_Home; + case AKEYCODE_MOVE_END: return ImGuiKey_End; + case AKEYCODE_INSERT: return ImGuiKey_Insert; + case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete; + case AKEYCODE_DEL: return ImGuiKey_Backspace; + case AKEYCODE_SPACE: return ImGuiKey_Space; + case AKEYCODE_ENTER: return ImGuiKey_Enter; + case AKEYCODE_ESCAPE: return ImGuiKey_Escape; + case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; + case AKEYCODE_COMMA: return ImGuiKey_Comma; + case AKEYCODE_MINUS: return ImGuiKey_Minus; + case AKEYCODE_PERIOD: return ImGuiKey_Period; + case AKEYCODE_SLASH: return ImGuiKey_Slash; + case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon; + case AKEYCODE_EQUALS: return ImGuiKey_Equal; + case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash; + case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent; + case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; + case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock; + case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen; + case AKEYCODE_BREAK: return ImGuiKey_Pause; + case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0; + case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1; + case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2; + case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3; + case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4; + case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5; + case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6; + case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7; + case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8; + case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9; + case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal; + case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide; + case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply; + case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract; + case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd; + case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter; + case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual; + case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl; + case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift; + case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt; + case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper; + case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl; + case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift; + case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt; + case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper; + case AKEYCODE_MENU: return ImGuiKey_Menu; + case AKEYCODE_0: return ImGuiKey_0; + case AKEYCODE_1: return ImGuiKey_1; + case AKEYCODE_2: return ImGuiKey_2; + case AKEYCODE_3: return ImGuiKey_3; + case AKEYCODE_4: return ImGuiKey_4; + case AKEYCODE_5: return ImGuiKey_5; + case AKEYCODE_6: return ImGuiKey_6; + case AKEYCODE_7: return ImGuiKey_7; + case AKEYCODE_8: return ImGuiKey_8; + case AKEYCODE_9: return ImGuiKey_9; + case AKEYCODE_A: return ImGuiKey_A; + case AKEYCODE_B: return ImGuiKey_B; + case AKEYCODE_C: return ImGuiKey_C; + case AKEYCODE_D: return ImGuiKey_D; + case AKEYCODE_E: return ImGuiKey_E; + case AKEYCODE_F: return ImGuiKey_F; + case AKEYCODE_G: return ImGuiKey_G; + case AKEYCODE_H: return ImGuiKey_H; + case AKEYCODE_I: return ImGuiKey_I; + case AKEYCODE_J: return ImGuiKey_J; + case AKEYCODE_K: return ImGuiKey_K; + case AKEYCODE_L: return ImGuiKey_L; + case AKEYCODE_M: return ImGuiKey_M; + case AKEYCODE_N: return ImGuiKey_N; + case AKEYCODE_O: return ImGuiKey_O; + case AKEYCODE_P: return ImGuiKey_P; + case AKEYCODE_Q: return ImGuiKey_Q; + case AKEYCODE_R: return ImGuiKey_R; + case AKEYCODE_S: return ImGuiKey_S; + case AKEYCODE_T: return ImGuiKey_T; + case AKEYCODE_U: return ImGuiKey_U; + case AKEYCODE_V: return ImGuiKey_V; + case AKEYCODE_W: return ImGuiKey_W; + case AKEYCODE_X: return ImGuiKey_X; + case AKEYCODE_Y: return ImGuiKey_Y; + case AKEYCODE_Z: return ImGuiKey_Z; + case AKEYCODE_F1: return ImGuiKey_F1; + case AKEYCODE_F2: return ImGuiKey_F2; + case AKEYCODE_F3: return ImGuiKey_F3; + case AKEYCODE_F4: return ImGuiKey_F4; + case AKEYCODE_F5: return ImGuiKey_F5; + case AKEYCODE_F6: return ImGuiKey_F6; + case AKEYCODE_F7: return ImGuiKey_F7; + case AKEYCODE_F8: return ImGuiKey_F8; + case AKEYCODE_F9: return ImGuiKey_F9; + case AKEYCODE_F10: return ImGuiKey_F10; + case AKEYCODE_F11: return ImGuiKey_F11; + case AKEYCODE_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) { @@ -44,12 +161,14 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) case AINPUT_EVENT_TYPE_KEY: { int32_t event_key_code = AKeyEvent_getKeyCode(input_event); + int32_t event_scan_code = AKeyEvent_getScanCode(input_event); int32_t event_action = AKeyEvent_getAction(input_event); int32_t event_meta_state = AKeyEvent_getMetaState(input_event); - io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0); - io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0); - io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0); + io.AddKeyEvent(ImGuiMod_Ctrl, (event_meta_state & AMETA_CTRL_ON) != 0); + io.AddKeyEvent(ImGuiMod_Shift, (event_meta_state & AMETA_SHIFT_ON) != 0); + io.AddKeyEvent(ImGuiMod_Alt, (event_meta_state & AMETA_ALT_ON) != 0); + io.AddKeyEvent(ImGuiMod_Super, (event_meta_state & AMETA_META_ON) != 0); switch (event_action) { @@ -58,8 +177,16 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_UP: - g_KeyEventQueues[event_key_code].push(event_action); + { + ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code); + if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP)) + { + io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN); + io.SetKeyEventNativeData(key, event_key_code, event_scan_code); + } + break; + } default: break; } @@ -70,6 +197,22 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) int32_t event_action = AMotionEvent_getAction(input_event); int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; event_action &= AMOTION_EVENT_ACTION_MASK; + + switch (AMotionEvent_getToolType(input_event, event_pointer_index)) + { + case AMOTION_EVENT_TOOL_TYPE_MOUSE: + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + break; + case AMOTION_EVENT_TOOL_TYPE_STYLUS: + case AMOTION_EVENT_TOOL_TYPE_ERASER: + io.AddMouseSourceEvent(ImGuiMouseSource_Pen); + break; + case AMOTION_EVENT_TOOL_TYPE_FINGER: + default: + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + break; + } + switch (event_action) { case AMOTION_EVENT_ACTION_DOWN: @@ -80,35 +223,25 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) { - io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false; - io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); - auto uiScale = ImGui::GetIO().uiScale; - io.MousePos = ImVec2((float)io.MousePos.x / uiScale, (float)io.MousePos.y / uiScale); - + io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); + io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN); } break; case AMOTION_EVENT_ACTION_BUTTON_PRESS: case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { int32_t button_state = AMotionEvent_getButtonState(input_event); - io.MouseDown[0] = (button_state & AMOTION_EVENT_BUTTON_PRIMARY) ? true : false; - io.MouseDown[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false; - io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false; + io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0); + io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0); + io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0); } break; case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse) case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN - { - io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), - AMotionEvent_getY(input_event, event_pointer_index)); - - auto uiScale = ImGui::GetIO().uiScale; - io.MousePos = ImVec2((float) io.MousePos.x / uiScale, (float) io.MousePos.y / uiScale); - } + io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); break; case AMOTION_EVENT_ACTION_SCROLL: - io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); - io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); + io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index)); break; default: break; @@ -131,51 +264,18 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window) ImGuiIO& io = ImGui::GetIO(); io.BackendPlatformName = "imgui_impl_android"; - // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. - io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP; - io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN; - io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME; - io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END; - io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT; - io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL; - io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL; - io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE; - io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER; - io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE; - io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER; - io.KeyMap[ImGuiKey_A] = AKEYCODE_A; - io.KeyMap[ImGuiKey_C] = AKEYCODE_C; - io.KeyMap[ImGuiKey_V] = AKEYCODE_V; - io.KeyMap[ImGuiKey_X] = AKEYCODE_X; - io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y; - io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z; - return true; } void ImGui_ImplAndroid_Shutdown() { + ImGuiIO& io = ImGui::GetIO(); + io.BackendPlatformName = nullptr; } void ImGui_ImplAndroid_NewFrame() { ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); - - // Process queued key events - // FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue. - for (auto& key_queue : g_KeyEventQueues) - { - if (key_queue.second.empty()) - continue; - io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN); - key_queue.second.pop(); - } // Setup display size (every frame to accommodate for window resizing) int32_t window_width = ANativeWindow_getWidth(g_Window); diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_android.h b/src/ui/imguiLib/imguiImpl/imgui_impl_android.h index e2f175736..eb97c4c89 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_android.h +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_android.h @@ -2,18 +2,21 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: +// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs #pragma once diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp index f93f03e43..31b22681b 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp @@ -1,20 +1,47 @@ -// dear imgui: Platform Binding for GLFW -// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// dear imgui: Platform Backend for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// (Requires: GLFW 3.1+) +// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ or GLFW 3.4+ for full feature support.) // Implemented features: // [X] Platform: Clipboard support. +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. -// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen on Windows ONLY, using a custom WndProc hook. (#2702) +// 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034) +// 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240) +// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096) +// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty. +// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908) +// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785) +// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. +// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). +// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position. +// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX. +// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11. +// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend. +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates. +// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. +// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. +// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback(). +// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback(). +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. +// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). @@ -38,39 +65,90 @@ #include "imgui.h" #include "imgui_impl_glfw.h" +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + // GLFW #include + #ifdef _WIN32 #undef APIENTRY #define GLFW_EXPOSE_NATIVE_WIN32 -#include // for glfwGetWin32Window +#include // for glfwGetWin32Window() +#endif +#ifdef __APPLE__ +#define GLFW_EXPOSE_NATIVE_COCOA +#include // for glfwGetCocoaWindow() +#endif + +#ifdef __EMSCRIPTEN__ +#include +#include +#endif + +// We gather version tests as define in order to easily see which features are version-dependent. +#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) +#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? +#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR +#else +#define GLFW_HAS_NEW_CURSORS (0) #endif -#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING -#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED -#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity -#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale -#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface +#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api +#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() +#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() -// Data +// GLFW data enum GlfwClientApi { GlfwClientApi_Unknown, GlfwClientApi_OpenGL, GlfwClientApi_Vulkan }; -static GLFWwindow* g_Window = NULL; // Main window -static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; -static double g_Time = 0.0; -static bool g_MouseJustPressed[5] = { false, false, false, false, false }; -static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; -static bool g_InstalledCallbacks = false; - -// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. -static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; -static GLFWscrollfun g_PrevUserCallbackScroll = NULL; -static GLFWkeyfun g_PrevUserCallbackKey = NULL; -static GLFWcharfun g_PrevUserCallbackChar = NULL; +struct ImGui_ImplGlfw_Data +{ + GLFWwindow* Window; + GlfwClientApi ClientApi; + double Time; + GLFWwindow* MouseWindow; + GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; + ImVec2 LastValidMousePos; + bool InstalledCallbacks; + bool CallbacksChainForAllWindows; + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + GLFWwindowfocusfun PrevUserCallbackWindowFocus; + GLFWcursorposfun PrevUserCallbackCursorPos; + GLFWcursorenterfun PrevUserCallbackCursorEnter; + GLFWmousebuttonfun PrevUserCallbackMousebutton; + GLFWscrollfun PrevUserCallbackScroll; + GLFWkeyfun PrevUserCallbackKey; + GLFWcharfun PrevUserCallbackChar; + GLFWmonitorfun PrevUserCallbackMonitor; +#ifdef _WIN32 + WNDPROC GlfwWndProc; +#endif + + ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks +// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks. +// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; +} + +// Functions static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) { return glfwGetClipboardString((GLFWwindow*)user_data); @@ -81,118 +159,451 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) glfwSetClipboardString((GLFWwindow*)user_data, text); } +static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) +{ + switch (key) + { + case GLFW_KEY_TAB: return ImGuiKey_Tab; + case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; + case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow; + case GLFW_KEY_UP: return ImGuiKey_UpArrow; + case GLFW_KEY_DOWN: return ImGuiKey_DownArrow; + case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp; + case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown; + case GLFW_KEY_HOME: return ImGuiKey_Home; + case GLFW_KEY_END: return ImGuiKey_End; + case GLFW_KEY_INSERT: return ImGuiKey_Insert; + case GLFW_KEY_DELETE: return ImGuiKey_Delete; + case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace; + case GLFW_KEY_SPACE: return ImGuiKey_Space; + case GLFW_KEY_ENTER: return ImGuiKey_Enter; + case GLFW_KEY_ESCAPE: return ImGuiKey_Escape; + case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe; + case GLFW_KEY_COMMA: return ImGuiKey_Comma; + case GLFW_KEY_MINUS: return ImGuiKey_Minus; + case GLFW_KEY_PERIOD: return ImGuiKey_Period; + case GLFW_KEY_SLASH: return ImGuiKey_Slash; + case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon; + case GLFW_KEY_EQUAL: return ImGuiKey_Equal; + case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash; + case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent; + case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock; + case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock; + case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen; + case GLFW_KEY_PAUSE: return ImGuiKey_Pause; + case GLFW_KEY_KP_0: return ImGuiKey_Keypad0; + case GLFW_KEY_KP_1: return ImGuiKey_Keypad1; + case GLFW_KEY_KP_2: return ImGuiKey_Keypad2; + case GLFW_KEY_KP_3: return ImGuiKey_Keypad3; + case GLFW_KEY_KP_4: return ImGuiKey_Keypad4; + case GLFW_KEY_KP_5: return ImGuiKey_Keypad5; + case GLFW_KEY_KP_6: return ImGuiKey_Keypad6; + case GLFW_KEY_KP_7: return ImGuiKey_Keypad7; + case GLFW_KEY_KP_8: return ImGuiKey_Keypad8; + case GLFW_KEY_KP_9: return ImGuiKey_Keypad9; + case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal; + case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide; + case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; + case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; + case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd; + case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter; + case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual; + case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift; + case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl; + case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt; + case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper; + case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift; + case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl; + case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt; + case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper; + case GLFW_KEY_MENU: return ImGuiKey_Menu; + case GLFW_KEY_0: return ImGuiKey_0; + case GLFW_KEY_1: return ImGuiKey_1; + case GLFW_KEY_2: return ImGuiKey_2; + case GLFW_KEY_3: return ImGuiKey_3; + case GLFW_KEY_4: return ImGuiKey_4; + case GLFW_KEY_5: return ImGuiKey_5; + case GLFW_KEY_6: return ImGuiKey_6; + case GLFW_KEY_7: return ImGuiKey_7; + case GLFW_KEY_8: return ImGuiKey_8; + case GLFW_KEY_9: return ImGuiKey_9; + case GLFW_KEY_A: return ImGuiKey_A; + case GLFW_KEY_B: return ImGuiKey_B; + case GLFW_KEY_C: return ImGuiKey_C; + case GLFW_KEY_D: return ImGuiKey_D; + case GLFW_KEY_E: return ImGuiKey_E; + case GLFW_KEY_F: return ImGuiKey_F; + case GLFW_KEY_G: return ImGuiKey_G; + case GLFW_KEY_H: return ImGuiKey_H; + case GLFW_KEY_I: return ImGuiKey_I; + case GLFW_KEY_J: return ImGuiKey_J; + case GLFW_KEY_K: return ImGuiKey_K; + case GLFW_KEY_L: return ImGuiKey_L; + case GLFW_KEY_M: return ImGuiKey_M; + case GLFW_KEY_N: return ImGuiKey_N; + case GLFW_KEY_O: return ImGuiKey_O; + case GLFW_KEY_P: return ImGuiKey_P; + case GLFW_KEY_Q: return ImGuiKey_Q; + case GLFW_KEY_R: return ImGuiKey_R; + case GLFW_KEY_S: return ImGuiKey_S; + case GLFW_KEY_T: return ImGuiKey_T; + case GLFW_KEY_U: return ImGuiKey_U; + case GLFW_KEY_V: return ImGuiKey_V; + case GLFW_KEY_W: return ImGuiKey_W; + case GLFW_KEY_X: return ImGuiKey_X; + case GLFW_KEY_Y: return ImGuiKey_Y; + case GLFW_KEY_Z: return ImGuiKey_Z; + case GLFW_KEY_F1: return ImGuiKey_F1; + case GLFW_KEY_F2: return ImGuiKey_F2; + case GLFW_KEY_F3: return ImGuiKey_F3; + case GLFW_KEY_F4: return ImGuiKey_F4; + case GLFW_KEY_F5: return ImGuiKey_F5; + case GLFW_KEY_F6: return ImGuiKey_F6; + case GLFW_KEY_F7: return ImGuiKey_F7; + case GLFW_KEY_F8: return ImGuiKey_F8; + case GLFW_KEY_F9: return ImGuiKey_F9; + case GLFW_KEY_F10: return ImGuiKey_F10; + case GLFW_KEY_F11: return ImGuiKey_F11; + case GLFW_KEY_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} + +// X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW +// See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630 +static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window) +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); +} + +static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + return bd->CallbacksChainForAllWindows ? true : (window == bd->Window); +} + void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { - if (g_PrevUserCallbackMousebutton != NULL) - g_PrevUserCallbackMousebutton(window, button, action, mods); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackMousebutton(window, button, action, mods); + + ImGui_ImplGlfw_UpdateKeyModifiers(window); - if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) - g_MouseJustPressed[button] = true; + ImGuiIO& io = ImGui::GetIO(); + if (button >= 0 && button < ImGuiMouseButton_COUNT) + io.AddMouseButtonEvent(button, action == GLFW_PRESS); } void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - if (g_PrevUserCallbackScroll != NULL) - g_PrevUserCallbackScroll(window, xoffset, yoffset); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackScroll(window, xoffset, yoffset); + +#ifdef __EMSCRIPTEN__ + // Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback(). + return; +#endif + + ImGuiIO& io = ImGui::GetIO(); + io.AddMouseWheelEvent((float)xoffset, (float)yoffset); +} + +static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) +{ +#if GLFW_HAS_GETKEYNAME && !defined(__EMSCRIPTEN__) + // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult. + // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently) + // See https://github.com/glfw/glfw/issues/1502 for details. + // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process). + // This won't cover edge cases but this is at least going to cover common cases. + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL) + return key; + GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr); + const char* key_name = glfwGetKeyName(key, scancode); + glfwSetErrorCallback(prev_error_callback); +#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908) + (void)glfwGetError(nullptr); +#endif + if (key_name && key_name[0] != 0 && key_name[1] == 0) + { + const char char_names[] = "`-=[]\\,;\'./"; + const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 }; + IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys)); + if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); } + else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); } + else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); } + else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; } + } + // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name); +#else + IM_UNUSED(scancode); +#endif + return key; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); + + if (action != GLFW_PRESS && action != GLFW_RELEASE) + return; + + ImGui_ImplGlfw_UpdateKeyModifiers(window); + + keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); + + ImGuiIO& io = ImGui::GetIO(); + ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode); + io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); + io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) +} + +void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackWindowFocus(window, focused); ImGuiIO& io = ImGui::GetIO(); - io.MouseWheelH += (float)xoffset; - io.MouseWheel += (float)yoffset; + io.AddFocusEvent(focused != 0); } -void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) { - if (g_PrevUserCallbackKey != NULL) - g_PrevUserCallbackKey(window, key, scancode, action, mods); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackCursorPos(window, x, y); + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; ImGuiIO& io = ImGui::GetIO(); - if (action == GLFW_PRESS) - io.KeysDown[key] = true; - if (action == GLFW_RELEASE) - io.KeysDown[key] = false; - - // Modifiers are not reliable across systems - io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; - io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; - io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; - io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; + io.AddMousePosEvent((float)x, (float)y); + bd->LastValidMousePos = ImVec2((float)x, (float)y); +} + +// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position, +// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984) +void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackCursorEnter(window, entered); + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiIO& io = ImGui::GetIO(); + if (entered) + { + bd->MouseWindow = window; + io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y); + } + else if (!entered && bd->MouseWindow == window) + { + bd->LastValidMousePos = io.MousePos; + bd->MouseWindow = nullptr; + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + } } void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) { - if (g_PrevUserCallbackChar != NULL) - g_PrevUserCallbackChar(window, c); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + bd->PrevUserCallbackChar(window, c); ImGuiIO& io = ImGui::GetIO(); io.AddInputCharacter(c); } -static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) { - g_Window = window; - g_Time = 0.0; + // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. +} - // Setup back-end capabilities flags +#ifdef __EMSCRIPTEN__ +static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*) +{ + // Mimic Emscripten_HandleWheel() in SDL. + // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096 + float multiplier = 0.0f; + if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step. + else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step. + else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps. + float wheel_x = ev->deltaX * -multiplier; + float wheel_y = ev->deltaY * -multiplier; ImGuiIO& io = ImGui::GetIO(); + io.AddMouseWheelEvent(wheel_x, wheel_y); + //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y); + return EM_TRUE; +} +#endif + +#ifdef _WIN32 +// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. +// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. +static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() +{ + LPARAM extra_info = ::GetMessageExtraInfo(); + if ((extra_info & 0xFFFFFF80) == 0xFF515700) + return ImGuiMouseSource_Pen; + if ((extra_info & 0xFFFFFF80) == 0xFF515780) + return ImGuiMouseSource_TouchScreen; + return ImGuiMouseSource_Mouse; +} +static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + switch (msg) + { + case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: + ImGui::GetIO().AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); + break; + } + return ::CallWindowProc(bd->GlfwWndProc, hWnd, msg, wParam, lParam); +} +#endif + +void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!"); + IM_ASSERT(bd->Window == window); + + bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); + bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); + bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback); + bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); + bd->InstalledCallbacks = true; +} + +void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!"); + IM_ASSERT(bd->Window == window); + + glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus); + glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter); + glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos); + glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton); + glfwSetScrollCallback(window, bd->PrevUserCallbackScroll); + glfwSetKeyCallback(window, bd->PrevUserCallbackKey); + glfwSetCharCallback(window, bd->PrevUserCallbackChar); + glfwSetMonitorCallback(bd->PrevUserCallbackMonitor); + bd->InstalledCallbacks = false; + bd->PrevUserCallbackWindowFocus = nullptr; + bd->PrevUserCallbackCursorEnter = nullptr; + bd->PrevUserCallbackCursorPos = nullptr; + bd->PrevUserCallbackMousebutton = nullptr; + bd->PrevUserCallbackScroll = nullptr; + bd->PrevUserCallbackKey = nullptr; + bd->PrevUserCallbackChar = nullptr; + bd->PrevUserCallbackMonitor = nullptr; +} + +// Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user. +// This is 'false' by default meaning we only chain callbacks for the main viewport. +// We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback. +// If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter. +void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + bd->CallbacksChainForAllWindows = chain_for_all_windows; +} + +static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); + //printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED); + + // Setup backend capabilities flags + ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)(); + io.BackendPlatformUserData = (void*)bd; + io.BackendPlatformName = "imgui_impl_glfw"; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) - io.BackendPlatformName = "imgui_impl_glfw"; - // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. - io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; - io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; - io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; - io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; - io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; - io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; - io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; - io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; - io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; - io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; - io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; - io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; - io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; - io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; - io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; - io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; - io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; - io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; - io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + bd->Window = window; + bd->Time = 0.0; io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; - io.ClipboardUserData = g_Window; -#if defined(_WIN32) - io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); + io.ClipboardUserData = bd->Window; + + // Create mouse cursors + // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, + // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. + // Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.) + GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr); + bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); +#if GLFW_HAS_NEW_CURSORS + bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); +#else + bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); +#endif + glfwSetErrorCallback(prev_error_callback); +#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908) + (void)glfwGetError(nullptr); #endif - - g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); - g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); - g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. - g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); - g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); - g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. - g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. - g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. - g_PrevUserCallbackMousebutton = NULL; - g_PrevUserCallbackScroll = NULL; - g_PrevUserCallbackKey = NULL; - g_PrevUserCallbackChar = NULL; if (install_callbacks) - { - g_InstalledCallbacks = true; - g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); - g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); - g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); - g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); - } + ImGui_ImplGlfw_InstallCallbacks(window); + // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096) + // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves. + // FIXME: May break chaining in case user registered their own Emscripten callback? +#ifdef __EMSCRIPTEN__ + emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, ImGui_ImplEmscripten_WheelCallback); +#endif - g_ClientApi = client_api; + // Set platform dependent data in viewport + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); +#ifdef _WIN32 + main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); +#elif defined(__APPLE__) + main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); +#else + IM_UNUSED(main_viewport); +#endif + + // Windows: register a WndProc hook so we can intercept some messages. +#ifdef _WIN32 + bd->GlfwWndProc = (WNDPROC)::GetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC); + IM_ASSERT(bd->GlfwWndProc != nullptr); + ::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); +#endif + + bd->ClientApi = client_api; return true; } @@ -206,57 +617,70 @@ bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); } +bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown); +} + void ImGui_ImplGlfw_Shutdown() { - if (g_InstalledCallbacks) - { - glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton); - glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll); - glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey); - glfwSetCharCallback(g_Window, g_PrevUserCallbackChar); - g_InstalledCallbacks = false; - } + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + if (bd->InstalledCallbacks) + ImGui_ImplGlfw_RestoreCallbacks(bd->Window); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) - { - glfwDestroyCursor(g_MouseCursors[cursor_n]); - g_MouseCursors[cursor_n] = NULL; - } - g_ClientApi = GlfwClientApi_Unknown; + glfwDestroyCursor(bd->MouseCursors[cursor_n]); + + // Windows: register a WndProc hook so we can intercept some messages. +#ifdef _WIN32 + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->GlfwWndProc); + bd->GlfwWndProc = nullptr; +#endif + + io.BackendPlatformName = nullptr; + io.BackendPlatformUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + IM_DELETE(bd); } -static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +static void ImGui_ImplGlfw_UpdateMouseData() { - // Update buttons + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + + if (glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { - // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; - g_MouseJustPressed[i] = false; + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + return; } - // Update mouse position - const ImVec2 mouse_pos_backup = io.MousePos; - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) + { + GLFWwindow* window = bd->Window; + #ifdef __EMSCRIPTEN__ - const bool focused = true; // Emscripten + const bool is_window_focused = true; #else - const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; + const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0; #endif - if (focused) - { - if (io.WantSetMousePos) + if (is_window_focused) { - glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); - } - else - { - double mouse_x, mouse_y; - glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); - auto uiScale = ImGui::GetIO().uiScale; - - io.MousePos = ImVec2((float)mouse_x / uiScale, (float)mouse_y / uiScale); + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y); + + // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) + if (bd->MouseWindow == nullptr) + { + double mouse_x, mouse_y; + glfwGetCursorPos(window, &mouse_x, &mouse_y); + bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); + io.AddMousePosEvent((float)mouse_x, (float)mouse_y); + } } } } @@ -264,83 +688,109 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons() static void ImGui_ImplGlfw_UpdateMouseCursor() { ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) return; ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) { - // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - } - else - { - // Show OS mouse cursor - // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. - glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + GLFWwindow* window = bd->Window; + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + // Show OS mouse cursor + // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. + glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } } } +// Update gamepad inputs +static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } static void ImGui_ImplGlfw_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - memset(io.NavInputs, 0, sizeof(io.NavInputs)); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. return; - // Update gamepad inputs - #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } - #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +#if GLFW_HAS_GAMEPAD_API && !defined(__EMSCRIPTEN__) + GLFWgamepadstate gamepad; + if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad)) + return; + #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0) + #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#else int axes_count = 0, buttons_count = 0; const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); - MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A - MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B - MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X - MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y - MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left - MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right - MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up - MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down - MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB - MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB - MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB - MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB - MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); - MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); - MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); - MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); + if (axes_count == 0 || buttons_count == 0) + return; + #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0) + #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#endif + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7); + MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6); + MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square + MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle + MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle + MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross + MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13); + MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11); + MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10); + MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12); + MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4); + MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5); + MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f); + MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8); + MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9); + MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f); #undef MAP_BUTTON #undef MAP_ANALOG - if (axes_count > 0 && buttons_count > 0) - io.BackendFlags |= ImGuiBackendFlags_HasGamepad; - else - io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; } void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplGlfw_InitForXXX()?"); // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - glfwGetWindowSize(g_Window, &w, &h); - glfwGetFramebufferSize(g_Window, &display_w, &display_h); + glfwGetWindowSize(bd->Window, &w, &h); + glfwGetFramebufferSize(bd->Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h); // Setup time step double current_time = glfwGetTime(); - io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); - g_Time = current_time; + io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); + bd->Time = current_time; - ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseData(); ImGui_ImplGlfw_UpdateMouseCursor(); // Update game controllers (if enabled and available) ImGui_ImplGlfw_UpdateGamepads(); } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.h b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.h index ccbe840d4..698b0d4b8 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.h +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.h @@ -1,33 +1,47 @@ -// dear imgui: Platform Binding for GLFW -// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// dear imgui: Platform Backend for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) // Implemented features: // [X] Platform: Clipboard support. +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. -// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui - -// About GLSL version: -// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. -// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs #pragma once +#include "imgui.h" // IMGUI_IMPL_API struct GLFWwindow; +struct GLFWmonitor; IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); -// InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any. -// InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks. +// GLFW callbacks install +// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any. +// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks. +IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); +IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); + +// GFLW callbacks options: +// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user) +IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows); + +// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks) +IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87 IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); +IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event); diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.cpp b/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.cpp index 0d95e395c..338ed9e27 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.cpp +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.cpp @@ -1,25 +1,61 @@ -// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline // - Desktop GL: 2.x 3.x 4.x // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) -// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) +// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. +// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui +// About WebGL/ES: +// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. +// - This is done automatically on iOS, Android and Emscripten targets. +// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375) +// 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333) +// 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224) +// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530) +// 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224) +// 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes). +// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. +// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'. +// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127). +// 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states. +// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers. +// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions. +// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader. +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state. +// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader. +// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version. +// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) +// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater. +// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer. +// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state. +// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state. +// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x) +// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader. +// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader. +// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX. +// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix. +// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset. +// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader. +// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader. // 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders. // 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility. // 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call. // 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. -// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. +// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. // 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). // 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. // 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. @@ -33,7 +69,7 @@ // 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. // 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. // 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. -// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. +// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer. // 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". // 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. @@ -75,161 +111,323 @@ #include // intptr_t #endif #if defined(__APPLE__) -#include "TargetConditionals.h" +#include #endif -// Auto-enable GLES on matching platforms -#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) -#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) -#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" -#undef IMGUI_IMPL_OPENGL_LOADER_GL3W -#undef IMGUI_IMPL_OPENGL_LOADER_GLEW -#undef IMGUI_IMPL_OPENGL_LOADER_GLAD -#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM -#elif defined(__EMSCRIPTEN__) -#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" -#undef IMGUI_IMPL_OPENGL_LOADER_GL3W -#undef IMGUI_IMPL_OPENGL_LOADER_GLEW -#undef IMGUI_IMPL_OPENGL_LOADER_GLAD -#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used +#pragma clang diagnostic ignored "-Wnonportable-system-include-path" +#pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) #endif +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) #endif // GL includes #if defined(IMGUI_IMPL_OPENGL_ES2) -#include +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include // Use GL ES 2 +#else +#include // Use GL ES 2 +#endif +#if defined(__EMSCRIPTEN__) +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES +#endif +#include +#endif #elif defined(IMGUI_IMPL_OPENGL_ES3) #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) #include // Use GL ES 3 #else #include // Use GL ES 3 #endif -#else -// About Desktop OpenGL function loaders: -// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). -// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. -#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) -#include // Needs to be initialized with gl3wInit() in user's code -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) -#include // Needs to be initialized with glewInit() in user's code -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) -#include // Needs to be initialized with gladLoadGL() in user's code -#else -#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) +// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w. +// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.). +// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp): +// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped +// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases +// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version. +#define IMGL3W_IMPL +#include "imgui_impl_opengl3_loader.h" #endif + +// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension +#ifndef IMGUI_IMPL_OPENGL_ES2 +#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY +#elif defined(__EMSCRIPTEN__) +#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY +#define glBindVertexArray glBindVertexArrayOES +#define glGenVertexArrays glGenVertexArraysOES +#define glDeleteVertexArrays glDeleteVertexArraysOES +#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES +#endif + +// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have. +#ifdef GL_POLYGON_MODE +#define IMGUI_IMPL_HAS_POLYGON_MODE #endif // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. -#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2) -#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0 +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET +#endif + +// Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler() +#if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3)) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER +#endif + +// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART +#endif + +// Desktop GL use extension detection +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS +#endif + +// [Debugging] +//#define IMGUI_IMPL_OPENGL_DEBUG +#ifdef IMGUI_IMPL_OPENGL_DEBUG +#include +#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check #else -#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1 +#define GL_CALL(_CALL) _CALL // Call without error check #endif // OpenGL Data -static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries. -static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. -static GLuint g_FontTexture = 0; -static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; -static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location -static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location -static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; +struct ImGui_ImplOpenGL3_Data +{ + GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) + char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings. + bool GlProfileIsES2; + bool GlProfileIsES3; + bool GlProfileIsCompat; + GLint GlProfileMask; + GLuint FontTexture; + GLuint ShaderHandle; + GLint AttribLocationTex; // Uniforms location + GLint AttribLocationProjMtx; + GLuint AttribLocationVtxPos; // Vertex attributes location + GLuint AttribLocationVtxUV; + GLuint AttribLocationVtxColor; + unsigned int VboHandle, ElementsHandle; + GLsizeiptr VertexBufferSize; + GLsizeiptr IndexBufferSize; + bool HasClipOrigin; + bool UseBufferSubData; + + ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only) +#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY +struct ImGui_ImplOpenGL3_VtxAttribState +{ + GLint Enabled, Size, Type, Normalized, Stride; + GLvoid* Ptr; + + void GetState(GLint index) + { + glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled); + glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size); + glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type); + glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized); + glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride); + glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr); + } + void SetState(GLint index) + { + glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr); + if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index); + } +}; +#endif // Functions bool ImGui_ImplOpenGL3_Init(const char* glsl_version) { - // Query for GL version + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Initialize our loader +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) + if (imgl3wInit() != 0) + { + fprintf(stderr, "Failed to initialize OpenGL loader!\n"); + return false; + } +#endif + + // Setup backend capabilities flags + ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_opengl3"; + + // Query for GL version (e.g. 320 for GL 3.2) #if !defined(IMGUI_IMPL_OPENGL_ES2) - GLint major, minor; + GLint major = 0; + GLint minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); - g_GlVersion = major * 1000 + minor; -#else - g_GlVersion = 2000; // GLES 2 + if (major == 0 && minor == 0) + { + // Query GL_VERSION in desktop GL 2.x, the string will start with "." + const char* gl_version = (const char*)glGetString(GL_VERSION); + sscanf(gl_version, "%d.%d", &major, &minor); + } + bd->GlVersion = (GLuint)(major * 100 + minor * 10); +#if defined(GL_CONTEXT_PROFILE_MASK) + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask); + bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0; #endif - // Setup back-end capabilities flags - ImGuiIO& io = ImGui::GetIO(); - io.BackendRendererName = "imgui_impl_opengl3"; -#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET - if (g_GlVersion >= 3200) + bd->UseBufferSubData = false; + /* + // Query vendor to enable glBufferSubData kludge +#ifdef _WIN32 + if (const char* vendor = (const char*)glGetString(GL_VENDOR)) + if (strncmp(vendor, "Intel", 5) == 0) + bd->UseBufferSubData = true; +#endif + */ +#elif defined(IMGUI_IMPL_OPENGL_ES2) + bd->GlVersion = 200; // GLES 2 + bd->GlProfileIsES2 = true; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + bd->GlVersion = 200; // Don't raise version as it is intended as a desktop version check for now. + bd->GlProfileIsES3 = true; +#endif + +#ifdef IMGUI_IMPL_OPENGL_DEBUG + printf("GL_MAJOR_VERSION = %d\nGL_MINOR_VERSION = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", major, minor, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] +#endif + +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (bd->GlVersion >= 320) io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. #endif - // Store GLSL version string so we can refer to it later in case we recreate shaders. - // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. + // Store GLSL version string so we can refer to it later in case we recreate shaders. + // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure. + if (glsl_version == nullptr) + { #if defined(IMGUI_IMPL_OPENGL_ES2) - if (glsl_version == NULL) glsl_version = "#version 100"; #elif defined(IMGUI_IMPL_OPENGL_ES3) - if (glsl_version == NULL) - glsl_version = "#version 310 es"; + glsl_version = "#version 300 es"; +#elif defined(__APPLE__) + glsl_version = "#version 150"; #else - if (glsl_version == NULL) glsl_version = "#version 130"; #endif - IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); - strcpy(g_GlslVersionString, glsl_version); - strcat(g_GlslVersionString, "\n"); - - // Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. - // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! - // If auto-detection fails or doesn't select the same GL loader file as used by your application, - // you are likely to get a crash below. - // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. - const char* gl_loader = "Unknown"; - IM_UNUSED(gl_loader); -#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) - gl_loader = "GL3W"; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) - gl_loader = "GLEW"; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) - gl_loader = "GLAD"; -#else // IMGUI_IMPL_OPENGL_LOADER_CUSTOM - gl_loader = "Custom"; -#endif - - // Make a dummy GL call (we don't actually need the result) - // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. - // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. + } + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString)); + strcpy(bd->GlslVersionString, glsl_version); + strcat(bd->GlslVersionString, "\n"); + + // Make an arbitrary GL call (we don't actually need the result) + // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know! GLint current_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); + // Detect extensions we support + bd->HasClipOrigin = (bd->GlVersion >= 450); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS + GLint num_extensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + for (GLint i = 0; i < num_extensions; i++) + { + const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i); + if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0) + bd->HasClipOrigin = true; + } +#endif + return true; } void ImGui_ImplOpenGL3_Shutdown() { + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplOpenGL3_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + IM_DELETE(bd); } void ImGui_ImplOpenGL3_NewFrame() { - if (!g_ShaderHandle) + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?"); + + if (!bd->ShaderHandle) ImGui_ImplOpenGL3_CreateDeviceObjects(); } static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) { + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); -#ifdef GL_POLYGON_MODE +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART + if (bd->GlVersion >= 310) + glDisable(GL_PRIMITIVE_RESTART); +#endif +#ifdef IMGUI_IMPL_HAS_POLYGON_MODE glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif + // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) +#if defined(GL_CLIP_ORIGIN) + bool clip_origin_lower_left = true; + if (bd->HasClipOrigin) + { + GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); + if (current_clip_origin == GL_UPPER_LEFT) + clip_origin_lower_left = false; + } +#endif + // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); + GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); float L = draw_data->DisplayPos.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; +#if defined(GL_CLIP_ORIGIN) + if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left +#endif const float ortho_projection[4][4] = { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, @@ -237,32 +435,34 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid { 0.0f, 0.0f, -1.0f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, }; - glUseProgram(g_ShaderHandle); - glUniform1i(g_AttribLocationTex, 0); - glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); -#ifdef GL_SAMPLER_BINDING - glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. + glUseProgram(bd->ShaderHandle); + glUniform1i(bd->AttribLocationTex, 0); + glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); + +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + if (bd->GlVersion >= 330 || bd->GlProfileIsES3) + glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. #endif (void)vertex_array_object; -#ifndef IMGUI_IMPL_OPENGL_ES2 +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY glBindVertexArray(vertex_array_object); #endif // Bind vertex/index buffers and setup attributes for ImDrawVert - glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); - glEnableVertexAttribArray(g_AttribLocationVtxPos); - glEnableVertexAttribArray(g_AttribLocationVtxUV); - glEnableVertexAttribArray(g_AttribLocationVtxColor); - glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); - glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); - glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); + GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle)); + GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle)); + GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos)); + GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV)); + GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor)); + GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos))); + GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv))); + GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col))); } // OpenGL3 Render function. -// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) -// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. +// This is in order to be able to run within an OpenGL engine that doesn't do so. void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -271,19 +471,28 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (fb_width <= 0 || fb_height <= 0) return; + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + // Backup GL state GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); glActiveTexture(GL_TEXTURE0); - GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); - GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); -#ifdef GL_SAMPLER_BINDING - GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); + GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program); + GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; } #endif - GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 - GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); + GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY + // This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+. + GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); + ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos); + ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV); + ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor); #endif -#ifdef GL_POLYGON_MODE +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY + GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object); +#endif +#ifdef IMGUI_IMPL_HAS_POLYGON_MODE GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); #endif GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); @@ -297,20 +506,18 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); + GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - bool clip_origin_lower_left = true; -#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) - GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) - if (last_clip_origin == GL_UPPER_LEFT) - clip_origin_lower_left = false; +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART + GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE; #endif // Setup desired GL state // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. GLuint vertex_array_object = 0; -#ifndef IMGUI_IMPL_OPENGL_ES2 - glGenVertexArrays(1, &vertex_array_object); +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY + GL_CALL(glGenVertexArrays(1, &vertex_array_object)); #endif ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); @@ -324,13 +531,40 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) const ImDrawList* cmd_list = draw_data->CmdLists[n]; // Upload vertex/index buffers - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); + // - OpenGL drivers are in a very sorry state nowadays.... + // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports + // of leaks on Intel GPU when using multi-viewports on Windows. + // - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel. + // - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code. + // We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path. + // - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues. + const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); + const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); + if (bd->UseBufferSubData) + { + if (bd->VertexBufferSize < vtx_buffer_size) + { + bd->VertexBufferSize = vtx_buffer_size; + GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW)); + } + if (bd->IndexBufferSize < idx_buffer_size) + { + bd->IndexBufferSize = idx_buffer_size; + GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW)); + } + GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data)); + GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data)); + } + else + { + GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW)); + GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW)); + } for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != NULL) + if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) @@ -342,115 +576,137 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) else { // Project scissor/clipping rectangles into framebuffer space - ImVec4 clip_rect; - clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { - // Apply scissor/clipping rectangle - if (clip_origin_lower_left) - glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); - else - glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) - - // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); -#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET - if (g_GlVersion >= 3200) - glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); - else -#endif - glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))); - } + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply scissor/clipping rectangle (Y is inverted in OpenGL) + GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y))); + + // Bind texture, Draw + GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID())); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (bd->GlVersion >= 320) + GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset)); + else +#endif + GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)))); } } } // Destroy the temporary VAO -#ifndef IMGUI_IMPL_OPENGL_ES2 - glDeleteVertexArrays(1, &vertex_array_object); +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY + GL_CALL(glDeleteVertexArrays(1, &vertex_array_object)); #endif // Restore modified GL state - glUseProgram(last_program); + // This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220. + if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program); glBindTexture(GL_TEXTURE_2D, last_texture); -#ifdef GL_SAMPLER_BINDING - glBindSampler(0, last_sampler); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + if (bd->GlVersion >= 330 || bd->GlProfileIsES3) + glBindSampler(0, last_sampler); #endif glActiveTexture(last_active_texture); -#ifndef IMGUI_IMPL_OPENGL_ES2 +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY glBindVertexArray(last_vertex_array_object); #endif glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); + last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos); + last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV); + last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor); +#endif glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); -#ifdef GL_POLYGON_MODE - glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART + if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); } #endif + +#ifdef IMGUI_IMPL_HAS_POLYGON_MODE + // Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons + if (bd->GlVersion <= 310 || bd->GlProfileIsCompat) + { + glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); + glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); + } + else + { + glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); + } +#endif // IMGUI_IMPL_HAS_POLYGON_MODE + glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); + (void)bd; // Not all compilation paths use this } bool ImGui_ImplOpenGL3_CreateFontsTexture() { - // Build texture atlas ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + + // Build texture atlas unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. // Upload texture to graphics system + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) GLint last_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGenTextures(1, &g_FontTexture); - glBindTexture(GL_TEXTURE_2D, g_FontTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#ifdef GL_UNPACK_ROW_LENGTH - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + GL_CALL(glGenTextures(1, &bd->FontTexture)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); +#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); #endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); // Restore state - glBindTexture(GL_TEXTURE_2D, last_texture); + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); return true; } void ImGui_ImplOpenGL3_DestroyFontsTexture() { - if (g_FontTexture) + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + if (bd->FontTexture) { - ImGuiIO& io = ImGui::GetIO(); - glDeleteTextures(1, &g_FontTexture); - io.Fonts->TexID = 0; - g_FontTexture = 0; + glDeleteTextures(1, &bd->FontTexture); + io.Fonts->SetTexID(0); + bd->FontTexture = 0; } } // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. static bool CheckShader(GLuint handle, const char* desc) { + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); GLint status = 0, log_length = 0; glGetShaderiv(handle, GL_COMPILE_STATUS, &status); glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); if ((GLboolean)status == GL_FALSE) - fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString); if (log_length > 1) { ImVector buf; buf.resize((int)(log_length + 1)); - glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + glGetShaderInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin()); fprintf(stderr, "%s\n", buf.begin()); } return (GLboolean)status == GL_TRUE; @@ -459,16 +715,17 @@ static bool CheckShader(GLuint handle, const char* desc) // If you get an error please report on GitHub. You may try different GL context version or GLSL version. static bool CheckProgram(GLuint handle, const char* desc) { + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); GLint status = 0, log_length = 0; glGetProgramiv(handle, GL_LINK_STATUS, &status); glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); if ((GLboolean)status == GL_FALSE) - fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString); if (log_length > 1) { ImVector buf; buf.resize((int)(log_length + 1)); - glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin()); fprintf(stderr, "%s\n", buf.begin()); } return (GLboolean)status == GL_TRUE; @@ -476,18 +733,20 @@ static bool CheckProgram(GLuint handle, const char* desc) bool ImGui_ImplOpenGL3_CreateDeviceObjects() { + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + // Backup GL state GLint last_texture, last_array_buffer; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); #endif // Parse GLSL version string int glsl_version = 130; - sscanf(g_GlslVersionString, "#version %d", &glsl_version); + sscanf(bd->GlslVersionString, "#version %d", &glsl_version); const GLchar* vertex_shader_glsl_120 = "uniform mat4 ProjMtx;\n" @@ -518,7 +777,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() "}\n"; const GLchar* vertex_shader_glsl_300_es = - "precision mediump float;\n" + "precision highp float;\n" "layout (location = 0) in vec2 Position;\n" "layout (location = 1) in vec2 UV;\n" "layout (location = 2) in vec4 Color;\n" @@ -590,8 +849,8 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() "}\n"; // Select shaders matching our GLSL versions - const GLchar* vertex_shader = NULL; - const GLchar* fragment_shader = NULL; + const GLchar* vertex_shader = nullptr; + const GLchar* fragment_shader = nullptr; if (glsl_version < 130) { vertex_shader = vertex_shader_glsl_120; @@ -614,40 +873,46 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() } // Create shaders - const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; - g_VertHandle = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); - glCompileShader(g_VertHandle); - CheckShader(g_VertHandle, "vertex shader"); - - const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; - g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); - glCompileShader(g_FragHandle); - CheckShader(g_FragHandle, "fragment shader"); - - g_ShaderHandle = glCreateProgram(); - glAttachShader(g_ShaderHandle, g_VertHandle); - glAttachShader(g_ShaderHandle, g_FragHandle); - glLinkProgram(g_ShaderHandle); - CheckProgram(g_ShaderHandle, "shader program"); - - g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); - g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); - g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); - g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); - g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); + const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader }; + GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr); + glCompileShader(vert_handle); + CheckShader(vert_handle, "vertex shader"); + + const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader }; + GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr); + glCompileShader(frag_handle); + CheckShader(frag_handle, "fragment shader"); + + // Link + bd->ShaderHandle = glCreateProgram(); + glAttachShader(bd->ShaderHandle, vert_handle); + glAttachShader(bd->ShaderHandle, frag_handle); + glLinkProgram(bd->ShaderHandle); + CheckProgram(bd->ShaderHandle, "shader program"); + + glDetachShader(bd->ShaderHandle, vert_handle); + glDetachShader(bd->ShaderHandle, frag_handle); + glDeleteShader(vert_handle); + glDeleteShader(frag_handle); + + bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture"); + bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx"); + bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position"); + bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV"); + bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color"); // Create buffers - glGenBuffers(1, &g_VboHandle); - glGenBuffers(1, &g_ElementsHandle); + glGenBuffers(1, &bd->VboHandle); + glGenBuffers(1, &bd->ElementsHandle); ImGui_ImplOpenGL3_CreateFontsTexture(); // Restore modified GL state glBindTexture(GL_TEXTURE_2D, last_texture); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 +#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY glBindVertexArray(last_vertex_array); #endif @@ -656,13 +921,16 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() void ImGui_ImplOpenGL3_DestroyDeviceObjects() { - if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } - if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } - if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } - if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } - if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } - if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } - if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } - + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; } + if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; } + if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; } ImGui_ImplOpenGL3_DestroyFontsTexture(); } + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.h b/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.h index 4c72ec479..77d11801d 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.h +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_opengl3.h @@ -1,30 +1,32 @@ -// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline // - Desktop GL: 2.x 3.x 4.x // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) -// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) +// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. +// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui +// About WebGL/ES: +// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. +// - This is done automatically on iOS, Android and Emscripten targets. +// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h. -// About Desktop OpenGL function loaders: -// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). -// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs // About GLSL version: -// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. +// The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string. // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. #pragma once +#include "imgui.h" // IMGUI_IMPL_API // Backend API -IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); @@ -35,30 +37,24 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); -// Specific OpenGL versions +// Specific OpenGL ES versions //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android -// Desktop OpenGL: attempt to detect default GL loader based on available header files. -// If auto-detection fails or doesn't select the same GL loader file as used by your application, -// you are likely to get a crash in ImGui_ImplOpenGL3_Init(). -// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. -#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) - #if defined(__has_include) - #if __has_include() - #define IMGUI_IMPL_OPENGL_LOADER_GLEW - #elif __has_include() - #define IMGUI_IMPL_OPENGL_LOADER_GLAD - #elif __has_include() - #define IMGUI_IMPL_OPENGL_LOADER_GL3W - #else - #error "Cannot detect OpenGL loader!" - #endif - #else - #define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W - #endif +// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. +#if !defined(IMGUI_IMPL_OPENGL_ES2) \ + && !defined(IMGUI_IMPL_OPENGL_ES3) + +// Try to detect GLES on matching platforms +#if defined(__APPLE__) +#include +#endif +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) +#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" +#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__) +#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" +#else +// Otherwise imgui_impl_opengl3_loader.h will be used. #endif +#endif diff --git a/src/ui/imguiLib/imgui_demo.cpp b/src/ui/imguiLib/imgui_demo.cpp index 7e4759925..fd0adc9eb 100644 --- a/src/ui/imguiLib/imgui_demo.cpp +++ b/src/ui/imguiLib/imgui_demo.cpp @@ -1,43 +1,67 @@ -// dear imgui, v1.74 +// dear imgui, v1.89.6 // (demo code) -// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: -// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders -// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of -// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, +// Help: +// - Read FAQ at http://dearimgui.com/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for more details, documentation and comments. +// Get the latest version at https://github.com/ocornut/imgui + +// ------------------------------------------------- +// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT! +// ------------------------------------------------- +// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase: +// Think again! It is the most useful reference code that you and other coders will want to refer to and call. +// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app! +// Also include Metrics! ItemPicker! DebugLog! and other debug features. +// Removing this file from your project is hindering access to documentation for everyone in your team, // likely leading you to poorer usage of the library. // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). -// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked, -// you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. -// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. +// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. // Thank you, -// -Your beloved friend, imgui_demo.cpp (that you won't delete) +// -Your beloved friend, imgui_demo.cpp (which you won't delete) // Message to beginner C/C++ programmers about the meaning of the 'static' keyword: -// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is -// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data -// in the same place, to make the demo source code faster to read, faster to write, and smaller in size. -// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be -// reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data -// you would be editing is likely going to be stored outside your functions. - -// The Demo code is this file is designed to be easy to copy-and-paste in into your application! +// In this demo code, we frequently use 'static' variables inside functions. A static variable persists across calls, +// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to +// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller +// in size. It also happens to be a convenient way of storing simple UI related information as long as your function +// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, +// but most of the real data you would be editing is likely going to be stored outside your functions. + +// The Demo code in this file is designed to be easy to copy-and-paste into your application! // Because of this: -// - We never omit the ImGui:: namespace when calling functions, even though most of our code is already in the same namespace. +// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. // - We try to declare static variables in the local scope, as close as possible to the code using them. -// - We never use any of the helpers/facilities used internally by dear imgui, unless it has been exposed in the public API (imgui.h). -// - We never use maths operators on ImVec2/ImVec4. For other imgui sources files, they are provided by imgui_internal.h w/ IMGUI_DEFINE_MATH_OPERATORS, -// for your own sources file they are optional and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. -// Because we don't want to assume anything about your support of maths operators, we don't use them in imgui_demo.cpp. +// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. /* Index of this file: -// [SECTION] Forward Declarations, Helpers +// [SECTION] Forward Declarations +// [SECTION] Helpers // [SECTION] Demo Window / ShowDemoWindow() +// - ShowDemoWindow() +// - sub section: ShowDemoWindowWidgets() +// - sub section: ShowDemoWindowLayout() +// - sub section: ShowDemoWindowPopups() +// - sub section: ShowDemoWindowTables() +// - sub section: ShowDemoWindowInputs() // [SECTION] About Window / ShowAboutWindow() // [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] User Guide / ShowUserGuide() // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() // [SECTION] Example App: Debug Console / ShowExampleAppConsole() // [SECTION] Example App: Debug Log / ShowExampleAppLog() @@ -46,8 +70,9 @@ Index of this file: // [SECTION] Example App: Long Text / ShowExampleAppLongText() // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() -// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() @@ -58,6 +83,9 @@ Index of this file: #endif #include "imgui.h" +#ifndef IMGUI_DISABLE + +// System includes #include // toupper #include // INT_MIN, INT_MAX #include // sqrtf, powf, cosf, sinf, floorf, ceilf @@ -69,41 +97,46 @@ Index of this file: #include // intptr_t #endif +// Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). #endif + +// Clang/GCC warnings with -Weverything #if defined(__clang__) -#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) -#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' -#pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal -#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. -#pragma clang diagnostic ignored "-Wunused-macros" // warning : warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 -#endif -#if __has_warning("-Wdouble-promotion") -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. -#endif -#if __has_warning("-Wreserved-id-macro") -#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! #endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type +#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. #endif -// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. +// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) #ifdef _WIN32 #define IM_NEWLINE "\r\n" #else #define IM_NEWLINE "\n" #endif +// Helpers #if defined(_MSC_VER) && !defined(snprintf) #define snprintf _snprintf #endif @@ -111,14 +144,37 @@ Index of this file: #define vsnprintf _vsnprintf #endif +// Format specifiers, printing 64-bit hasn't been decently standardized... +// In a real application you should be using PRId64 and PRIu64 from (non-windows) and on Windows define them yourself. +#ifdef _MSC_VER +#define IM_PRId64 "I64d" +#define IM_PRIu64 "I64u" +#else +#define IM_PRId64 "lld" +#define IM_PRIu64 "llu" +#endif + +// Helpers macros +// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +// but making an exception here as those are largely simplifying code... +// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) +#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) +#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifndef IMGUI_CDECL +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif +#endif + //----------------------------------------------------------------------------- // [SECTION] Forward Declarations, Helpers //----------------------------------------------------------------------------- -#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO -#define IMGUI_DISABLE_DEMO_WINDOWS -#endif - #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Forward Declarations @@ -132,18 +188,31 @@ static void ShowExampleAppLongText(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open); static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppFullscreen(bool* p_open); static void ShowExampleAppWindowTitles(bool* p_open); static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleMenuFile(); +// We split the contents of the big ShowDemoWindow() function into smaller functions +// (because the link time of very large functions grow non-linearly) +static void ShowDemoWindowWidgets(); +static void ShowDemoWindowLayout(); +static void ShowDemoWindowPopups(); +static void ShowDemoWindowTables(); +static void ShowDemoWindowColumns(); +static void ShowDemoWindowInputs(); + +//----------------------------------------------------------------------------- +// [SECTION] Helpers +//----------------------------------------------------------------------------- + // Helper to display a little (?) mark which shows a tooltip when hovered. -// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt) +// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) static void HelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort) && ImGui::BeginTooltip()) { - ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); ImGui::TextUnformatted(desc); ImGui::PopTextWrapPos(); @@ -151,62 +220,38 @@ static void HelpMarker(const char* desc) } } -// Helper to display basic user controls. -void ImGui::ShowUserGuide() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui::BulletText("Double-click on title bar to collapse window."); - ImGui::BulletText("Click and drag on lower corner to resize window\n(double-click to auto fit window to its contents)."); - ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); - ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); - if (io.FontAllowUserScaling) - ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); - ImGui::BulletText("While inputing text:\n"); - ImGui::Indent(); - ImGui::BulletText("CTRL+Left/Right to word jump."); - ImGui::BulletText("CTRL+A or double-click to select all."); - ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); - ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); - ImGui::BulletText("ESCAPE to revert."); - ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); - ImGui::Unindent(); - ImGui::BulletText("With keyboard navigation enabled:"); - ImGui::Indent(); - ImGui::BulletText("Arrow keys to navigate."); - ImGui::BulletText("Space to activate a widget."); - ImGui::BulletText("Return to input text into a widget."); - ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); - ImGui::BulletText("Alt to jump to the menu layer of a window."); - ImGui::BulletText("CTRL+Tab to select a window."); - ImGui::Unindent(); -} +// Helper to wire demo markers located in code to an interactive browser +typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data); +extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback; +extern void* GImGuiDemoMarkerCallbackUserData; +ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL; +void* GImGuiDemoMarkerCallbackUserData = NULL; +#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) //----------------------------------------------------------------------------- // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- +// - ShowDemoWindow() // - ShowDemoWindowWidgets() // - ShowDemoWindowLayout() // - ShowDemoWindowPopups() +// - ShowDemoWindowTables() // - ShowDemoWindowColumns() -// - ShowDemoWindowMisc() +// - ShowDemoWindowInputs() //----------------------------------------------------------------------------- -// We split the contents of the big ShowDemoWindow() function into smaller functions (because the link time of very large functions grow non-linearly) -static void ShowDemoWindowWidgets(); -static void ShowDemoWindowLayout(); -static void ShowDemoWindowPopups(); -static void ShowDemoWindowColumns(); -static void ShowDemoWindowMisc(); - // Demonstrate most Dear ImGui features (this is big function!) -// You may execute this function to experiment with the UI and understand what it does. You may then search for keywords in the code when you are interested by a specific feature. +// You may execute this function to experiment with the UI and understand what it does. +// You may then search for keywords in the code when you are interested by a specific feature. void ImGui::ShowDemoWindow(bool* p_open) { - IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); // Exceptionally add an extra assert here for people confused with initial dear imgui setup + // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + // Most functions would normally just crash if the context is missing. + IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); // Examples Apps (accessible from the "Examples" menu) - static bool show_app_documents = false; static bool show_app_main_menu_bar = false; + static bool show_app_documents = false; static bool show_app_console = false; static bool show_app_log = false; static bool show_app_layout = false; @@ -215,11 +260,12 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool show_app_auto_resize = false; static bool show_app_constrained_resize = false; static bool show_app_simple_overlay = false; + static bool show_app_fullscreen = false; static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; - if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); + if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); if (show_app_console) ShowExampleAppConsole(&show_app_console); if (show_app_log) ShowExampleAppLog(&show_app_log); if (show_app_layout) ShowExampleAppLayout(&show_app_layout); @@ -228,17 +274,31 @@ void ImGui::ShowDemoWindow(bool* p_open) if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); - // Dear ImGui Apps (accessible from the "Tools" menu) + // Dear ImGui Tools/Apps (accessible from the "Tools" menu) static bool show_app_metrics = false; - static bool show_app_style_editor = false; + static bool show_app_debug_log = false; + static bool show_app_stack_tool = false; static bool show_app_about = false; + static bool show_app_style_editor = false; - if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } - if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } - if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } + if (show_app_metrics) + ImGui::ShowMetricsWindow(&show_app_metrics); + if (show_app_debug_log) + ImGui::ShowDebugLogWindow(&show_app_debug_log); + if (show_app_stack_tool) + ImGui::ShowStackToolWindow(&show_app_stack_tool); + if (show_app_about) + ImGui::ShowAboutWindow(&show_app_about); + if (show_app_style_editor) + { + ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); + ImGui::ShowStyleEditor(); + ImGui::End(); + } // Demonstrate the various window flags. Typically you would just use the default! static bool no_titlebar = false; @@ -251,6 +311,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool no_nav = false; static bool no_background = false; static bool no_bring_to_front = false; + static bool unsaved_document = false; ImGuiWindowFlags window_flags = 0; if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; @@ -262,10 +323,13 @@ void ImGui::ShowDemoWindow(bool* p_open) if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument; if (no_close) p_open = NULL; // Don't pass our bool* to Begin - // We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming. - ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); + // We specify a default position/size in case there's no data in the .ini file. + // We only do it to make the demo applications a little more welcoming, but typically this isn't required. + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); // Main body of the Demo window starts here. @@ -276,20 +340,24 @@ void ImGui::ShowDemoWindow(bool* p_open) return; } - // Most "big" widgets share a common width settings by default. - //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // Use 2/3 of the space for widgets and 1/3 for labels (default) - ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // Use fixed width for labels (by passing a negative value), the rest goes to widgets. We choose a width proportional to our font size. + // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. + // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) + //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); + // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. + ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // Menu Bar if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) { + IMGUI_DEMO_MARKER("Menu/File"); ShowExampleMenuFile(); ImGui::EndMenu(); } if (ImGui::BeginMenu("Examples")) { + IMGUI_DEMO_MARKER("Menu/Examples"); ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); ImGui::MenuItem("Console", NULL, &show_app_console); ImGui::MenuItem("Log", NULL, &show_app_log); @@ -299,14 +367,24 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); ImGui::MenuItem("Documents", NULL, &show_app_documents); ImGui::EndMenu(); } + //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! if (ImGui::BeginMenu("Tools")) { - ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + IMGUI_DEMO_MARKER("Menu/Tools"); +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + const bool has_debug_tools = true; +#else + const bool has_debug_tools = false; +#endif + ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics, has_debug_tools); + ImGui::MenuItem("Debug Log", NULL, &show_app_debug_log, has_debug_tools); + ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool, has_debug_tools); ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); ImGui::EndMenu(); @@ -314,92 +392,127 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::EndMenuBar(); } - ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); + ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); + IMGUI_DEMO_MARKER("Help"); if (ImGui::CollapsingHeader("Help")) { - ImGui::Text("ABOUT THIS DEMO:"); + ImGui::SeparatorText("ABOUT THIS DEMO:"); ImGui::BulletText("Sections below are demonstrating many aspects of the library."); ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" - "and Metrics (general purpose Dear ImGui debugging tool)."); - ImGui::Separator(); + "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); - ImGui::Text("PROGRAMMER GUIDE:"); + ImGui::SeparatorText("PROGRAMMER GUIDE:"); ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); ImGui::BulletText("See comments in imgui.cpp."); ImGui::BulletText("See example applications in the examples/ folder."); - ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); + ImGui::BulletText("Read the FAQ at http://www.dearimgui.com/faq/"); ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); - ImGui::Separator(); - ImGui::Text("USER GUIDE:"); + ImGui::SeparatorText("USER GUIDE:"); ImGui::ShowUserGuide(); } + IMGUI_DEMO_MARKER("Configuration"); if (ImGui::CollapsingHeader("Configuration")) { ImGuiIO& io = ImGui::GetIO(); if (ImGui::TreeNode("Configuration##2")) { - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::SeparatorText("General"); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::SameLine(); HelpMarker("Enable keyboard controls."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); - ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) // Create a way to restore this flag otherwise we could be stuck completely! + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) { + // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) { ImGui::SameLine(); ImGui::Text("<>"); } - if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + if (ImGui::IsKeyPressed(ImGuiKey_Space)) io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; } - ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); - ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); + ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); + ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); + ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + + ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); - ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); + ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); + ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); + ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); + ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); - ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); - ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor for you. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); + ImGui::Text("Also see Style->Rendering for rendering options."); + + ImGui::SeparatorText("Debug"); + ImGui::BeginDisabled(); + ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . + ImGui::EndDisabled(); + ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover"); + ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); + ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss); + ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data."); + ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } + IMGUI_DEMO_MARKER("Configuration/Backend Flags"); if (ImGui::TreeNode("Backend Flags")) { - HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\nHere we expose then as read-only fields to avoid breaking interactions with your back-end."); - ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying actual back-end flags. - ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); - ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos); - ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int *)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); + HelpMarker( + "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" + "Here we expose them as read-only fields to avoid breaking interactions with your backend."); + + // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? + ImGui::BeginDisabled(); + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::EndDisabled(); ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } + IMGUI_DEMO_MARKER("Configuration/Style"); if (ImGui::TreeNode("Style")) { HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::ShowStyleEditor(); ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } + IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); if (ImGui::TreeNode("Capture/Logging")) { - ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded."); - HelpMarker("Try opening any of the contents below in this window and then click one of the \"Log To\" button."); + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " + "a window or a block. Tree nodes can be automatically expanded.\n" + "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); ImGui::LogButtons(); - ImGui::TextWrapped("You can also call ImGui::LogText() to output directly to the log without a visual output."); + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) { ImGui::LogToClipboard(); @@ -410,38 +523,54 @@ void ImGui::ShowDemoWindow(bool* p_open) } } + IMGUI_DEMO_MARKER("Window options"); if (ImGui::CollapsingHeader("Window options")) { - ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); - ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); - ImGui::Checkbox("No menu", &no_menu); - ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); - ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); - ImGui::Checkbox("No collapse", &no_collapse); - ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); - ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); - ImGui::Checkbox("No background", &no_background); - ImGui::Checkbox("No bring to front", &no_bring_to_front); + if (ImGui::BeginTable("split", 3)) + { + ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar); + ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar); + ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu); + ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move); + ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize); + ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse); + ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close); + ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); + ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); + ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); + ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); + ImGui::EndTable(); + } } // All demo contents ShowDemoWindowWidgets(); ShowDemoWindowLayout(); ShowDemoWindowPopups(); - ShowDemoWindowColumns(); - ShowDemoWindowMisc(); + ShowDemoWindowTables(); + ShowDemoWindowInputs(); // End of ShowDemoWindow() + ImGui::PopItemWidth(); ImGui::End(); } static void ShowDemoWindowWidgets() { + IMGUI_DEMO_MARKER("Widgets"); if (!ImGui::CollapsingHeader("Widgets")) return; + static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom + if (disable_all) + ImGui::BeginDisabled(); + + IMGUI_DEMO_MARKER("Widgets/Basic"); if (ImGui::TreeNode("Basic")) { + ImGui::SeparatorText("General"); + + IMGUI_DEMO_MARKER("Widgets/Basic/Button"); static int clicked = 0; if (ImGui::Button("Button")) clicked++; @@ -451,34 +580,40 @@ static void ShowDemoWindowWidgets() ImGui::Text("Thanks for clicking me!"); } + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox"); static bool check = true; ImGui::Checkbox("checkbox", &check); + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); static int e = 0; ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); ImGui::RadioButton("radio c", &e, 2); // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)"); for (int i = 0; i < 7; i++) { if (i > 0) ImGui::SameLine(); ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); ImGui::Button("Click"); ImGui::PopStyleColor(3); ImGui::PopID(); } - // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + // See 'Demo->Layout->Text Baseline Alignment' for details. ImGui::AlignTextToFramePadding(); ImGui::Text("Hold to repeat:"); ImGui::SameLine(); // Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)"); static int counter = 0; float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::PushButtonRepeat(true); @@ -489,45 +624,67 @@ static void ShowDemoWindowWidgets() ImGui::SameLine(); ImGui::Text("%d", counter); - ImGui::Text("Hover over me"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("I am a tooltip"); - - ImGui::SameLine(); - ImGui::Text("- or me"); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("I am a fancy tooltip"); - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); - ImGui::EndTooltip(); - } + // Tooltips + IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips"); + //ImGui::AlignTextToFramePadding(); + ImGui::Text("Tooltips:"); - ImGui::Separator(); + ImGui::SameLine(); + ImGui::SmallButton("Basic"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip"); - ImGui::LabelText("label", "Value"); + ImGui::SameLine(); + ImGui::SmallButton("Fancy"); + if (ImGui::IsItemHovered() && ImGui::BeginTooltip()) + { + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); + ImGui::EndTooltip(); + } - { - // Using the _simplified_ one-liner Combo() api here - // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_current = 0; - ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); - ImGui::SameLine(); HelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); + ImGui::SameLine(); + ImGui::SmallButton("Delayed"); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // With a delay + ImGui::SetTooltip("I am a tooltip with a delay."); + + ImGui::SameLine(); + HelpMarker( + "Tooltip are created by using the IsItemHovered() function over any kind of item."); } + ImGui::LabelText("label", "Value"); + + ImGui::SeparatorText("Inputs"); + { + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); static char str0[128] = "Hello, world!"; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); - ImGui::SameLine(); HelpMarker("USER:\nHold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp)."); + ImGui::SameLine(); HelpMarker( + "USER:\n" + "Hold SHIFT or use mouse to select text.\n" + "CTRL+Left/Right to word jump.\n" + "CTRL+A or Double-Click to select all.\n" + "CTRL+X,CTRL+C,CTRL+V clipboard.\n" + "CTRL+Z,CTRL+Y undo/redo.\n" + "ESCAPE to revert.\n\n" + "PROGRAMMER:\n" + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " + "in imgui_demo.cpp)."); static char str1[128] = ""; ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); static int i0 = 123; ImGui::InputInt("input int", &i0); - ImGui::SameLine(); HelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); static float f0 = 0.001f; ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); @@ -537,65 +694,96 @@ static void ShowDemoWindowWidgets() static float f1 = 1.e10f; ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); - ImGui::SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n"); + ImGui::SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" + " e.g. \"1e+8\" becomes \"100000000\"."); static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; ImGui::InputFloat3("input float3", vec4a); } + ImGui::SeparatorText("Drags"); + { + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); static int i1 = 50, i2 = 42; ImGui::DragInt("drag int", &i1, 1); - ImGui::SameLine(); HelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); + ImGui::SameLine(); HelpMarker( + "Click and drag to edit value.\n" + "Hold SHIFT/ALT for faster/slower edit.\n" + "Double-click or CTRL+click to input value."); - ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); - static float f1=1.00f, f2=0.0067f; + static float f1 = 1.00f, f2 = 0.0067f; ImGui::DragFloat("drag float", &f1, 0.005f); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); } + ImGui::SeparatorText("Sliders"); + { - static int i1=0; + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); + static int i1 = 0; ImGui::SliderInt("slider int", &i1, -1, 3); ImGui::SameLine(); HelpMarker("CTRL+click to input value."); - static float f1=0.123f, f2=0.0f; + static float f1 = 0.123f, f2 = 0.0f; ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); - ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); + ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle"); static float angle = 0.0f; ImGui::SliderAngle("slider angle", &angle); // Using the format string to display a name instead of an integer. // Here we completely omit '%d' from the format string, so it'll only display a name. // This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)"); enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; - const char* element_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; - static int current_element = Element_Fire; - const char* current_element_name = (current_element >= 0 && current_element < Element_COUNT) ? element_names[current_element] : "Unknown"; - ImGui::SliderInt("slider enum", ¤t_element, 0, Element_COUNT - 1, current_element_name); + static int elem = Element_Fire; + const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; + const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); } + ImGui::SeparatorText("Selectors/Pickers"); + { - static float col1[3] = { 1.0f,0.0f,0.2f }; - static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; ImGui::ColorEdit3("color 1", col1); - ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nClick and hold to use drag and drop.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n"); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "Click and hold to use drag and drop.\n" + "Right-click on the color square to show options.\n" + "CTRL+click on individual component to input value.\n"); ImGui::ColorEdit4("color 2", col2); } { - // List box - const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; - static int listbox_item_current = 1; - ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); + } - //static int listbox_item_current2 = 2; - //ImGui::SetNextItemWidth(-1); - //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + { + // Using the _simplified_ one-liner ListBox() api here + // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); + const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static int item_current = 1; + ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); } ImGui::TreePop(); @@ -607,14 +795,16 @@ static void ShowDemoWindowWidgets() // if (once) // ImGui::Text("This will be displayed only once."); + IMGUI_DEMO_MARKER("Widgets/Trees"); if (ImGui::TreeNode("Trees")) { + IMGUI_DEMO_MARKER("Widgets/Trees/Basic trees"); if (ImGui::TreeNode("Basic trees")) { for (int i = 0; i < 5; i++) { - // Use SetNextItemOpen() so set the default state of a node to be open. - // We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + // Use SetNextItemOpen() so set the default state of a node to be open. We could + // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! if (i == 0) ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -622,32 +812,42 @@ static void ShowDemoWindowWidgets() { ImGui::Text("blah blah"); ImGui::SameLine(); - if (ImGui::SmallButton("button")) {}; + if (ImGui::SmallButton("button")) {} ImGui::TreePop(); } } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Trees/Advanced, with Selectable nodes"); if (ImGui::TreeNode("Advanced, with Selectable nodes")) { - HelpMarker("This is a more typical looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); + HelpMarker( + "This is a more typical looking tree with selectable nodes.\n" + "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; static bool align_label_with_current_x_position = false; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position); + static bool test_drag_and_drop = false; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); + ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); ImGui::Text("Hello!"); if (align_label_with_current_x_position) ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); - static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. - int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. + // 'selection_mask' is dumb representation of what may be user-side selection state. + // You may retain selection state inside or outside your objects in whatever format you see fit. + // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end + /// of the loop. May be a pointer to your own node type, etc. + static int selection_mask = (1 << 2); + int node_clicked = -1; for (int i = 0; i < 6; i++) { - // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. + // Disable the default "open on single-click behavior" + set Selected flag according to our selection. + // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. ImGuiTreeNodeFlags node_flags = base_flags; const bool is_selected = (selection_mask & (1 << i)) != 0; if (is_selected) @@ -656,8 +856,14 @@ static void ShowDemoWindowWidgets() { // Items 0..2 are Tree Node bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); - if (ImGui::IsItemClicked()) + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } if (node_open) { ImGui::BulletText("Blah blah\nBlah Blah"); @@ -667,20 +873,27 @@ static void ShowDemoWindowWidgets() else { // Items 3..5 are Tree Leaves - // The only reason we use TreeNode at all is to allow selection of the leaf. - // Otherwise we can use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); - if (ImGui::IsItemClicked()) + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } } } if (node_clicked != -1) { - // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. + // Update selection state + // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) if (ImGui::GetIO().KeyCtrl) selection_mask ^= (1 << node_clicked); // CTRL+click to toggle - else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection selection_mask = (1 << node_clicked); // Click to single-select } if (align_label_with_current_x_position) @@ -690,6 +903,7 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); if (ImGui::TreeNode("Collapsing Headers")) { static bool closable_group = true; @@ -713,6 +927,7 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Bullets"); if (ImGui::TreeNode("Bullets")) { ImGui::BulletText("Bullet point 1"); @@ -727,57 +942,71 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text"); if (ImGui::TreeNode("Text")) { - if (ImGui::TreeNode("Colored Text")) + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text"); + if (ImGui::TreeNode("Colorful Text")) { // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); - ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); ImGui::TextDisabled("Disabled"); ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); if (ImGui::TreeNode("Word Wrapping")) { // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); + ImGui::TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " + "for text wrapping follows simple rules suitable for English and possibly other languages."); ImGui::Spacing(); static float wrap_width = 200.0f; ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); - ImGui::Text("Test paragraph 1:"); - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); - ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); - ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); - ImGui::PopTextWrapPos(); - - ImGui::Text("Test paragraph 2:"); - pos = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); - ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); - ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); - ImGui::PopTextWrapPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 2; n++) + { + ImGui::Text("Test paragraph %d:", n); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); + ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + if (n == 0) + ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + else + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + + // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); + ImGui::PopTextWrapPos(); + } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text"); if (ImGui::TreeNode("UTF-8 Text")) { // UTF-8 test with Japanese characters - // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read docs/FONTS.txt for details.) + // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 - // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') - // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. - // Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application! - // Please use u8"text in any language" in your application! - // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. - ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.txt for details."); + // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + // can save your source files as 'UTF-8 without signature'). + // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + // Don't do this in your application! Please use u8"text in any language" in your application! + // Note that characters values are preserved even by InputText() if the font cannot be displayed, + // so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped( + "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " + "Read docs/FONTS.md for details."); ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; @@ -788,47 +1017,82 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Images"); if (ImGui::TreeNode("Images")) { ImGuiIO& io = ImGui::GetIO(); - ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); - - // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. - // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure. - // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID. - // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier etc.) - // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. - // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. - // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + ImGui::TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " + "Hover the texture for a zoomed view!"); + + // Below we are displaying the font texture because it is the only texture we have access to inside the demo! + // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that + // will be passed to the rendering backend via the ImDrawCmd structure. + // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + // of their respective source file to specify what they expect to be stored in ImTextureID, for example: + // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer + // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + // More: + // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + // to ImGui::Image(), and gather width/height through your own functions, etc. + // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + // it will help you debug issues if you are confused about it. + // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples ImTextureID my_tex_id = io.Fonts->TexID; float my_tex_w = (float)io.Fonts->TexWidth; float my_tex_h = (float)io.Fonts->TexHeight; - - ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0,0), ImVec2(1,1), ImVec4(1.0f,1.0f,1.0f,1.0f), ImVec4(1.0f,1.0f,1.0f,0.5f)); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - float region_sz = 32.0f; - float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz; - float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz; - float zoom = 4.0f; - ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); - ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); - ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); - ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); - ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(1.0f, 1.0f, 1.0f, 1.0f), ImVec4(1.0f, 1.0f, 1.0f, 0.5f)); - ImGui::EndTooltip(); + { + static bool use_text_color_for_tint = false; + ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint); + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left + ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right + ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border); + ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); + if (ImGui::IsItemHovered() && ImGui::BeginTooltip()) + { + float region_sz = 32.0f; + float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; + float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; + float zoom = 4.0f; + if (region_x < 0.0f) { region_x = 0.0f; } + else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } + if (region_y < 0.0f) { region_y = 0.0f; } + else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } + ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); + ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); + ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); + ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); + ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); + ImGui::EndTooltip(); + } } + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); ImGui::TextWrapped("And now some textured buttons.."); static int pressed_count = 0; for (int i = 0; i < 8; i++) { + // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures. + // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. + // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples ImGui::PushID(i); - int frame_padding = -1 + i; // -1 = uses default padding - if (ImGui::ImageButton(my_tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/my_tex_w,32/my_tex_h), frame_padding, ImVec4(0.0f,0.0f,0.0f,1.0f))) + if (i > 0) + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f)); + ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible + ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left + ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture + ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col)) pressed_count += 1; + if (i > 0) + ImGui::PopStyleVar(); ImGui::PopID(); ImGui::SameLine(); } @@ -837,68 +1101,124 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Combo"); if (ImGui::TreeNode("Combo")) { + // Combo Boxes are also called "Dropdown" in other systems // Expose flags as checkbox for the demo static ImGuiComboFlags flags = 0; - ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both - // General BeginCombo() API, you have full control over your selection data and display type. - // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.) + // Using the generic BeginCombo() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object. - if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo. + static int item_current_idx = 0; // Here we store our selection data as an index. + const char* combo_preview_value = items[item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything) + if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - bool is_selected = (item_current == items[n]); + const bool is_selected = (item_current_idx == n); if (ImGui::Selectable(items[n], is_selected)) - item_current = items[n]; + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) - ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) + ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } // Simplified one-liner Combo() API, using values packed in a single constant string + // This is a convenience for when the selection set is small and known at compile-time. static int item_current_2 = 0; ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); // Simplified one-liner Combo() using an array of const char* + // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); // Simplified one-liner Combo() using an accessor function - struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; + struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } }; static int item_current_4 = 0; - ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); + ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items)); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/List Boxes"); + if (ImGui::TreeNode("List boxes")) + { + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current_idx = 0; // Here we store our selection data as an index. + if (ImGui::BeginListBox("listbox 1")) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + // Custom size: use all width, 5 items tall + ImGui::Text("Full-width:"); + if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables"); if (ImGui::TreeNode("Selectables")) { // Selectable() has 2 overloads: - // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly. + // - The one taking "bool selected" as a read-only selection information. + // When Selectable() has been clicked it returns true and you can alter selection state accordingly. // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) - // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc). + // The earlier is more flexible, as in real application your selection may be stored in many different ways + // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); if (ImGui::TreeNode("Basic")) { static bool selection[5] = { false, true, false, false, false }; ImGui::Selectable("1. I am selectable", &selection[0]); ImGui::Selectable("2. I am selectable", &selection[1]); - ImGui::Text("3. I am not selectable"); + ImGui::Text("(I am not selectable)"); ImGui::Selectable("4. I am selectable", &selection[3]); if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) if (ImGui::IsMouseDoubleClicked(0)) selection[4] = !selection[4]; ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection"); if (ImGui::TreeNode("Selection State: Single Selection")) { static int selected = -1; @@ -911,6 +1231,7 @@ static void ShowDemoWindowWidgets() } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection"); if (ImGui::TreeNode("Selection State: Multiple Selection")) { HelpMarker("Hold CTRL and click to select multiple items."); @@ -928,53 +1249,93 @@ static void ShowDemoWindowWidgets() } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more text into the same line"); if (ImGui::TreeNode("Rendering more text into the same line")) { - // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically. + // Using the Selectable() override that takes "bool* p_selected" parameter, + // this function toggle your bool value automatically. static bool selected[3] = { false, false, false }; ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/In columns"); if (ImGui::TreeNode("In columns")) { - ImGui::Columns(3, NULL, false); - static bool selected[16] = {}; - for (int i = 0; i < 16; i++) + static bool selected[10] = {}; + + if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) { - char label[32]; sprintf(label, "Item %d", i); - if (ImGui::Selectable(label, &selected[i])) {} - ImGui::NextColumn(); + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap + } + ImGui::EndTable(); + } + ImGui::Spacing(); + if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); + ImGui::TableNextColumn(); + ImGui::Text("Some other contents"); + ImGui::TableNextColumn(); + ImGui::Text("123456"); + } + ImGui::EndTable(); } - ImGui::Columns(1); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); if (ImGui::TreeNode("Grid")) { - static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; - for (int i = 0; i < 4*4; i++) - { - ImGui::PushID(i); - if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) + static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; + + // Add in a bit of silly fun... + const float time = (float)ImGui::GetTime(); + const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... + if (winning_state) + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); + + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) { - // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary. - int x = i % 4; - int y = i / 4; - if (x > 0) { selected[i - 1] ^= 1; } - if (x < 3 && i < 15) { selected[i + 1] ^= 1; } - if (y > 0 && i > 3) { selected[i - 4] ^= 1; } - if (y < 3 && i < 12) { selected[i + 4] ^= 1; } + if (x > 0) + ImGui::SameLine(); + ImGui::PushID(y * 4 + x); + if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) + { + // Toggle clicked cell + toggle neighbors + selected[y][x] ^= 1; + if (x > 0) { selected[y][x - 1] ^= 1; } + if (x < 3) { selected[y][x + 1] ^= 1; } + if (y > 0) { selected[y - 1][x] ^= 1; } + if (y < 3) { selected[y + 1][x] ^= 1; } + } + ImGui::PopID(); } - if ((i % 4) < 3) ImGui::SameLine(); - ImGui::PopID(); - } + + if (winning_state) + ImGui::PopStyleVar(); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); if (ImGui::TreeNode("Alignment")) { - HelpMarker("Alignment applies when a selectable is larger than its text content.\nBy default, Selectables uses style.SelectableTextAlign but it can be overriden on a per-item basis using PushStyleVar()."); - static bool selected[3*3] = { true, false, true, false, true, false, true, false, true }; + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " + "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) @@ -984,7 +1345,7 @@ static void ShowDemoWindowWidgets() sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); if (x > 0) ImGui::SameLine(); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); - ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80)); + ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); ImGui::PopStyleVar(); } } @@ -993,8 +1354,12 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Text Input"); if (ImGui::TreeNode("Text Input")) { + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input"); if (ImGui::TreeNode("Multi-line Text Input")) { // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize @@ -1012,38 +1377,122 @@ static void ShowDemoWindowWidgets() "\tlock cmpxchg8b eax\n"; static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp)"); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); - ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input"); if (ImGui::TreeNode("Filtered Text Input")) { - static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); - static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); - static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); - static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); - static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); - struct TextFilters { static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; - static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); - - ImGui::Text("Password input"); - static char bufpass[64] = "password123"; - ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); + struct TextFilters + { + // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) + static int FilterCasingSwap(ImGuiInputTextCallbackData* data) + { + if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar = data->EventChar - 'A' - 'a'; } // Lowercase becomes uppercase + else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar = data->EventChar + 'a' - 'A'; } // Uppercase becomes lowercase + return 0; + } + + // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) + { + if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) + return 0; + return 1; + } + }; + + static char buf1[32] = ""; ImGui::InputText("default", buf1, 32); + static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal); + static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase); + static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank); + static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. + static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input"); + if (ImGui::TreeNode("Password Input")) + { + static char password[64] = "password123"; + ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); - ImGui::InputTextWithHint("password (w/ hint)", "", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); - ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); + ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Completion, History, Edit Callbacks")) + { + struct Funcs + { + static int MyCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) + { + data->InsertChars(data->CursorPos, ".."); + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) + { + if (data->EventKey == ImGuiKey_UpArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Up!"); + data->SelectAll(); + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Down!"); + data->SelectAll(); + } + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) + { + // Toggle casing of first character + char c = data->Buf[0]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; + data->BufDirty = true; + + // Increment a counter + int* p_int = (int*)data->UserData; + *p_int = *p_int + 1; + } + return 0; + } + }; + static char buf1[64]; + ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf2[64]; + ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf3[64]; + static int edit_count = 0; + ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); + ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edit + count edits."); + ImGui::SameLine(); ImGui::Text("(%d)", edit_count); + ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback"); if (ImGui::TreeNode("Resize Callback")) { - // If you have a custom string type you would typically create a ImGui::InputText() wrapper than takes your type as input. - // See misc/cpp/imgui_stdlib.h and .cpp for an implementation of this using std::string. - HelpMarker("Demonstrate using ImGuiInputTextFlags_CallbackResize to wire your resizable string type to InputText().\n\nSee misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + // To wire InputText() with std::string or any other custom string type, + // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); struct Funcs { static int MyResizeCallback(ImGuiInputTextCallbackData* data) @@ -1052,14 +1501,14 @@ static void ShowDemoWindowWidgets() { ImVector* my_str = (ImVector*)data->UserData; IM_ASSERT(my_str->begin() == data->Buf); - my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 data->Buf = my_str->begin(); } return 0; } - // Tip: Because ImGui:: is a namespace you would typicall add your own function into the namespace in your own source files. - // For example, you may add a function called ImGui::InputText(const char* label, MyString* my_str). + // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); @@ -1068,7 +1517,8 @@ static void ShowDemoWindowWidgets() }; // For this demo we are using ImVector as a string container. - // Note that because we need to store a terminating zero character, our size/capacity are 1 more than usually reported by a typical string class. + // Note that because we need to store a terminating zero character, our size/capacity are 1 more + // than usually reported by a typical string class. static ImVector my_str; if (my_str.empty()) my_str.push_back(0); @@ -1080,64 +1530,214 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } - // Plot/Graph widgets are currently fairly limited. - // Consider writing your own plotting widget, or using a third-party one (see "Wiki->Useful Widgets", or github.com/ocornut/imgui/issues/2747) - if (ImGui::TreeNode("Plots Widgets")) + // Tabs + IMGUI_DEMO_MARKER("Widgets/Tabs"); + if (ImGui::TreeNode("Tabs")) { - static bool animate = true; - ImGui::Checkbox("Animate", &animate); - - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); - - // Create a dummy array of contiguous float values to plot - // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. - static float values[90] = {}; - static int values_offset = 0; - static double refresh_time = 0.0; - if (!animate || refresh_time == 0.0) - refresh_time = ImGui::GetTime(); - while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic"); + if (ImGui::TreeNode("Basic")) { - static float phase = 0.0f; - values[values_offset] = cosf(phase); - values_offset = (values_offset+1) % IM_ARRAYSIZE(values); - phase += 0.10f*values_offset; - refresh_time += 1.0f/60.0f; + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); } - // Plots can display overlay texts - // (in this example, we will display an average value) + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button"); + if (ImGui::TreeNode("Advanced & Close Button")) { - float average = 0.0f; - for (int n = 0; n < IM_ARRAYSIZE(values); n++) + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + if (n > 0) { ImGui::SameLine(); } + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + // the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags"); + if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) + { + static ImVector active_tabs; + static int next_tab_id = 0; + if (next_tab_id == 0) // Initialize with some default tabs + for (int i = 0; i < 3; i++) + active_tabs.push_back(next_tab_id++); + + // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + // but they tend to make more sense together) + static bool show_leading_button = true; + static bool show_trailing_button = true; + ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); + ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); + + // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + // Demo a Leading TabItemButton(): click the "?" button to open a menu + if (show_leading_button) + if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) + ImGui::OpenPopup("MyHelpMenu"); + if (ImGui::BeginPopup("MyHelpMenu")) + { + ImGui::Selectable("Hello!"); + ImGui::EndPopup(); + } + + // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+") + // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if (show_trailing_button) + if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) + active_tabs.push_back(next_tab_id++); // Add new tab + + // Submit our regular tabs + for (int n = 0; n < active_tabs.Size; ) + { + bool open = true; + char name[16]; + snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); + if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", name); + ImGui::EndTabItem(); + } + + if (!open) + active_tabs.erase(active_tabs.Data + n); + else + n++; + } + + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // Plot/Graph widgets are not very good. + // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + IMGUI_DEMO_MARKER("Widgets/Plotting"); + if (ImGui::TreeNode("Plotting")) + { + static bool animate = true; + ImGui::Checkbox("Animate", &animate); + + // Plot as lines and plot as histogram + IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + + // Fill an array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + // and the sizeof() of your structure in the "stride" parameter. + static float values[90] = {}; + static int values_offset = 0; + static double refresh_time = 0.0; + if (!animate || refresh_time == 0.0) + refresh_time = ImGui::GetTime(); + while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo + { + static float phase = 0.0f; + values[values_offset] = cosf(phase); + values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); + phase += 0.10f * values_offset; + refresh_time += 1.0f / 60.0f; + } + + // Plots can display overlay texts + // (in this example, we will display an average value) + { + float average = 0.0f; + for (int n = 0; n < IM_ARRAYSIZE(values); n++) average += values[n]; average /= (float)IM_ARRAYSIZE(values); char overlay[32]; sprintf(overlay, "avg %f", average); - ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); } - ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); // Use functions to generate output - // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count. + // FIXME: This is actually VERY awkward because current plot API only pass in indices. + // We probably want an API passing floats and user provide sample rate/count. struct Funcs { static float Sin(void*, int i) { return sinf(i * 0.1f); } static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } }; static int func_type = 0, display_count = 70; - ImGui::Separator(); - ImGui::SetNextItemWidth(100); + ImGui::SeparatorText("Functions"); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; - ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); - ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::Separator(); // Animate a simple progress bar + IMGUI_DEMO_MARKER("Widgets/Plotting/ProgressBar"); static float progress = 0.0f, progress_dir = 1.0f; if (animate) { @@ -1148,26 +1748,28 @@ static void ShowDemoWindowWidgets() // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. - ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f)); + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::Text("Progress Bar"); - float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; + float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); char buf[32]; - sprintf(buf, "%d/%d", (int)(progress_saturated*1753), 1753); - ImGui::ProgressBar(progress, ImVec2(0.f,0.f), buf); + sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Color"); if (ImGui::TreeNode("Color/Picker Widgets")) { - static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f); + static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); static bool alpha_preview = true; static bool alpha_half_preview = false; static bool drag_and_drop = true; static bool options_menu = true; static bool hdr = false; + ImGui::SeparatorText("Options"); ImGui::Checkbox("With Alpha Preview", &alpha_preview); ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); ImGui::Checkbox("With Drag and Drop", &drag_and_drop); @@ -1175,30 +1777,42 @@ static void ShowDemoWindowWidgets() ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); + ImGui::SeparatorText("Inline color editor"); ImGui::Text("Color widget:"); - ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n"); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "CTRL+click on individual component to input value.\n"); ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); ImGui::Text("Color widget HSV with Alpha:"); ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); ImGui::Text("Color widget with Float Display:"); ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); ImGui::Text("Color button with Picker:"); - ImGui::SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup."); + ImGui::SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " + "be used for the tooltip and picker popup."); ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); ImGui::Text("Color button with Custom Picker Popup:"); - // Generate a dummy default palette. The palette will persist and can be edited. + // Generate a default palette. The palette will persist and can be edited. static bool saved_palette_init = true; static ImVec4 saved_palette[32] = {}; if (saved_palette_init) { for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { - ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, + saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); saved_palette[n].w = 1.0f; // Alpha } saved_palette_init = false; @@ -1222,9 +1836,9 @@ static void ShowDemoWindowWidgets() ImGui::BeginGroup(); // Lock X position ImGui::Text("Current"); - ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); ImGui::Text("Previous"); - if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40))) + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) color = backup_color; ImGui::Separator(); ImGui::Text("Palette"); @@ -1233,11 +1847,13 @@ static void ShowDemoWindowWidgets() ImGui::PushID(n); if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); - if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! - // Allow user to drop colors into each palette entry - // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop) + // Allow user to drop colors into each palette entry. Note that ColorButton() is already a + // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) @@ -1253,15 +1869,19 @@ static void ShowDemoWindowWidgets() ImGui::EndPopup(); } + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)"); ImGui::Text("Color button only:"); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80,80)); + static bool no_border = false; + ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); - ImGui::Text("Color picker:"); + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); + ImGui::SeparatorText("Color picker"); static bool alpha = true; static bool alpha_bar = true; static bool side_preview = true; static bool ref_color = false; - static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f); + static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); static int display_mode = 0; static int picker_mode = 0; ImGui::Checkbox("With Alpha", &alpha); @@ -1278,9 +1898,11 @@ static void ShowDemoWindowWidgets() } } ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); - ImGui::SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); - ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); - ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); + ImGui::SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " + "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode."); ImGuiColorEditFlags flags = misc_flags; if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; @@ -1293,51 +1915,107 @@ static void ShowDemoWindowWidgets() if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); - ImGui::Text("Programmatically set defaults:"); - ImGui::SameLine(); HelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible."); + ImGui::Text("Set defaults in code:"); + ImGui::SameLine(); HelpMarker( + "SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" + "encouraging you to persistently save values that aren't forward-compatible."); if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); if (ImGui::Button("Default: Float + HDR + Hue Wheel")) ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + // Always both a small version of both types of pickers (to make it more visible in the demo to people who are skimming quickly through it) + ImGui::Text("Both types:"); + float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f; + ImGui::SetNextItemWidth(w); + ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::SameLine(); + ImGui::SetNextItemWidth(w); + ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) - static ImVec4 color_stored_as_hsv(0.23f, 1.0f, 1.0f, 1.0f); + static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! ImGui::Spacing(); ImGui::Text("HSV encoded colors"); - ImGui::SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); + ImGui::SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); ImGui::Text("Color widget with InputHSV:"); - ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::DragFloat4("Raw HSV values", (float*)&color_stored_as_hsv, 0.01f, 0.0f, 1.0f); + ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); + if (ImGui::TreeNode("Drag/Slider Flags")) + { + // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + static ImGuiSliderFlags flags = ImGuiSliderFlags_None; + ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); + ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); + ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); + ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); + ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); + ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + + // Drags + static float drag_f = 0.5f; + static int drag_i = 50; + ImGui::Text("Underlying float value: %f", drag_f); + ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); + ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); + + // Sliders + static float slider_f = 0.5f; + static int slider_i = 50; + ImGui::Text("Underlying float value: %f", slider_f); + ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); + ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Range Widgets"); if (ImGui::TreeNode("Range Widgets")) { static float begin = 10, end = 90; static int begin_i = 100, end_i = 1000; - ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Data Types"); if (ImGui::TreeNode("Data Types")) { - // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double - // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, - // and passing all arguments by address. - // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. - // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it - // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address - // to the generic function. For example: + // DragScalar/InputScalar/SliderScalar functions allow various data types + // - signed/unsigned + // - 8/16/32/64-bits + // - integer/float/double + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + // to pass the type, and passing all arguments by pointer. + // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. + // In practice, if you frequently use a given type that is not covered by the normal API entry points, + // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + // and then pass their address to the generic function. For example: // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") // { // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); // } - // Limits (as helper variables that we can take the address of) - // Note that the SliderScalar function has a maximum usable range of half the natural type maximum, hence the /2 below. + // Setup limits (as helper variables so we can take their address, as explained above) + // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. #ifndef LLONG_MIN ImS64 LLONG_MIN = -9223372036854775807LL - 1; ImS64 LLONG_MAX = 9223372036854775807LL; @@ -1368,56 +2046,72 @@ static void ShowDemoWindowWidgets() const float drag_speed = 0.2f; static bool drag_clamp = false; - ImGui::Text("Drags:"); - ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value."); + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); + ImGui::SeparatorText("Drags"); + ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); + ImGui::SameLine(); HelpMarker( + "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" + "You can override the clamping limits by using CTRL+Click to input a value."); ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X"); ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); - ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f); - ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); HelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range."); - ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f); - ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f); - - ImGui::Text("Sliders"); - ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); - ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); - ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); - ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); - ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); - ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); - ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); - ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); - ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); - ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); - ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); - ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); - ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); - ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); - ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); - ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); - ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); - ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f); - ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); - ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f); - ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f); - ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f); - + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); + ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); + ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); + ImGui::SeparatorText("Sliders"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X"); + ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); + ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); + ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); + ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); + ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); + + ImGui::SeparatorText("Sliders (reverse)"); + ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); + ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); + ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); + ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); + ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; - ImGui::Text("Inputs"); + ImGui::SeparatorText("Inputs"); ImGui::Checkbox("Show step buttons", &inputs_step); ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); - ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X"); ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); - ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X"); ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); @@ -1426,27 +2120,29 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); if (ImGui::TreeNode("Multi-component Widgets")) { static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static int vec4i[4] = { 1, 5, 100, 255 }; + ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::InputInt2("input int2", vec4i); ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::SliderInt2("slider int2", vec4i, 0, 255); - ImGui::Spacing(); + ImGui::SeparatorText("3-wide"); ImGui::InputFloat3("input float3", vec4f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::InputInt3("input int3", vec4i); ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::SliderInt3("slider int3", vec4i, 0, 255); - ImGui::Spacing(); + ImGui::SeparatorText("4-wide"); ImGui::InputFloat4("input float4", vec4f); ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); @@ -1457,13 +2153,14 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); if (ImGui::TreeNode("Vertical Sliders")) { const float spacing = 4; ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); static int int_value = 0; - ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5); + ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); ImGui::SameLine(); static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; @@ -1472,11 +2169,11 @@ static void ShowDemoWindowWidgets() { if (i > 0) ImGui::SameLine(); ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i/7.0f, 0.5f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i/7.0f, 0.9f, 0.9f)); - ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, ""); + ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); if (ImGui::IsItemActive() || ImGui::IsItemHovered()) ImGui::SetTooltip("%.3f", values[i]); ImGui::PopStyleColor(4); @@ -1495,7 +2192,7 @@ static void ShowDemoWindowWidgets() ImGui::BeginGroup(); for (int ny = 0; ny < rows; ny++) { - ImGui::PushID(nx*rows+ny); + ImGui::PushID(nx * rows + ny); ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); if (ImGui::IsItemActive() || ImGui::IsItemHovered()) ImGui::SetTooltip("%.3f", values2[nx]); @@ -1512,7 +2209,7 @@ static void ShowDemoWindowWidgets() if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); - ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); ImGui::PopStyleVar(); ImGui::PopID(); } @@ -1521,14 +2218,17 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Drag and drop"); if (ImGui::TreeNode("Drag and Drop")) { + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets"); if (ImGui::TreeNode("Drag and drop in standard widgets")) { // ColorEdit widgets automatically act as drag source and drag target. - // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets - // to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo. - HelpMarker("You can drag from the colored squares."); + // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + // to allow your own widgets to use colors in their drag and drop interaction. + // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares."); static float col1[3] = { 1.0f, 0.0f, 0.2f }; static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; ImGui::ColorEdit3("color 1", col1); @@ -1536,6 +2236,7 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items"); if (ImGui::TreeNode("Drag and drop to copy/swap items")) { enum Mode @@ -1548,19 +2249,28 @@ static void ShowDemoWindowWidgets() if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } - static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; + static const char* names[9] = + { + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }; for (int n = 0; n < IM_ARRAYSIZE(names); n++) { ImGui::PushID(n); if ((n % 3) != 0) ImGui::SameLine(); - ImGui::Button(names[n], ImVec2(60,60)); + ImGui::Button(names[n], ImVec2(60, 60)); // Our buttons are both drag sources and drag targets here! if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { - ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything) - if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.) + // Set payload to carry the index of our item (could be anything) + ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); + + // Display preview (could be anything, e.g. when dragging an image we could decide to display + // the filename and a small preview of the image, etc.) + if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } ImGui::EndDragDropSource(); @@ -1594,10 +2304,13 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); if (ImGui::TreeNode("Drag to reorder items (simple)")) { // Simple reordering - HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly."); + HelpMarker( + "We don't use the drag and drop api at all here! " + "Instead we query when the item is held but not hovered, and order items accordingly."); static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) { @@ -1621,35 +2334,54 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } - if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); + if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) { - // Submit an item (various types available) so we can query their status in the following block. - static int item_type = 1; - ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode\0TreeNode (w/ double-click)\0ListBox\0", 20); + // Select an item type + const char* item_names[] = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + }; + static int item_type = 4; + static bool item_disabled = false; + ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); ImGui::SameLine(); - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); + ImGui::Checkbox("Item Disabled", &item_disabled); + + // Submit selected items so we can query their status in the code following it. bool ret = false; static bool b = false; static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; static char str[16] = {}; + if (item_disabled) + ImGui::BeginDisabled(true); if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) - if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input - if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node - if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } - - // Display the value of IsItemHovered() and other common item state functions. + if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) + if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input + if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item + if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } + if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + + bool hovered_delay_none = ImGui::IsItemHovered(); + bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort); + bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal); + + // Display the values of IsItemHovered() and other common item state functions. // Note that the ImGuiHoveredFlags_XXX flags can be combined. // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, - // we query every state in a single call to avoid storing them and to simplify the code + // we query every state in a single call to avoid storing them and to simplify the code. ImGui::BulletText( "Return value = %d\n" "IsItemFocused() = %d\n" @@ -1657,6 +2389,7 @@ static void ShowDemoWindowWidgets() "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_AllowWhenDisabled) = %d\n" "IsItemHovered(_RectOnly) = %d\n" "IsItemActive() = %d\n" "IsItemEdited() = %d\n" @@ -1675,6 +2408,7 @@ static void ShowDemoWindowWidgets() ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), ImGui::IsItemActive(), ImGui::IsItemEdited(), @@ -1688,44 +2422,70 @@ static void ShowDemoWindowWidgets() ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y ); + ImGui::BulletText( + "w/ Hovering Delay: None = %d, Fast %d, Normal = %d", hovered_delay_none, hovered_delay_short, hovered_delay_normal); + + if (item_disabled) + ImGui::EndDisabled(); + + char buf[1] = ""; + ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); + ImGui::SameLine(); + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)"); + if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) + { static bool embed_all_inside_a_child_window = false; - ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); + ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true); + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); // Testing IsWindowFocused() function with its various flags. - // Note that the ImGuiFocusedFlags_XXX flags can be combined. ImGui::BulletText( "IsWindowFocused() = %d\n" "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" "IsWindowFocused(_AnyWindow) = %d\n", ImGui::IsWindowFocused(), ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); // Testing IsWindowHovered() function with its various flags. - // Note that the ImGuiHoveredFlags_XXX flags can be combined. ImGui::BulletText( "IsWindowHovered() = %d\n" "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" - "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" "IsWindowHovered(_AnyWindow) = %d\n", ImGui::IsWindowHovered(), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); ImGui::BeginChild("child", ImVec2(0, 50), true); @@ -1734,11 +2494,8 @@ static void ShowDemoWindowWidgets() if (embed_all_inside_a_child_window) ImGui::EndChild(); - static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above."; - ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly); - // Calling IsItemHovered() after begin returns the hovered status of the title bar. - // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. + // This is useful in particular if you want to create a context menu associated to the title bar of a window. static bool test_window = false; ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); if (test_window) @@ -1758,39 +2515,66 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + + // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd: + // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space) + if (disable_all) + ImGui::EndDisabled(); + + IMGUI_DEMO_MARKER("Widgets/Disable Block"); + if (ImGui::TreeNode("Disable block")) + { + ImGui::Checkbox("Disable entire section above", &disable_all); + ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section."); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Filter"); + if (ImGui::TreeNode("Text Filter")) + { + // Helper class to easy setup a text filter. + // You may want to implement a more feature-full filtering scheme in your own application. + HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings."); + static ImGuiTextFilter filter; + ImGui::Text("Filter usage:\n" + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); + filter.Draw(); + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (int i = 0; i < IM_ARRAYSIZE(lines); i++) + if (filter.PassFilter(lines[i])) + ImGui::BulletText("%s", lines[i]); + ImGui::TreePop(); + } } static void ShowDemoWindowLayout() { - if (!ImGui::CollapsingHeader("Layout")) + IMGUI_DEMO_MARKER("Layout"); + if (!ImGui::CollapsingHeader("Layout & Scrolling")) return; + IMGUI_DEMO_MARKER("Layout/Child windows"); if (ImGui::TreeNode("Child windows")) { + ImGui::SeparatorText("Child windows"); + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); ImGui::Checkbox("Disable Menu", &disable_menu); - static int line = 50; - bool goto_line = ImGui::Button("Goto"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(100); - goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); - // Child 1: no border, enable horizontal scrollbar { - ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0); - ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), false, window_flags); for (int i = 0; i < 100; i++) - { ImGui::Text("%04d: scrollable region", i); - if (goto_line && line == i) - ImGui::SetScrollHereY(); - } - if (goto_line && line >= 100) - ImGui::SetScrollHereY(); ImGui::EndChild(); } @@ -1798,9 +2582,13 @@ static void ShowDemoWindowLayout() // Child 2: rounded border { - ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + if (!disable_menu) + window_flags |= ImGuiWindowFlags_MenuBar; ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("Child2", ImVec2(0, 260), true, window_flags); + ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); if (!disable_menu && ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) @@ -1810,84 +2598,136 @@ static void ShowDemoWindowLayout() } ImGui::EndMenuBar(); } - ImGui::Columns(2); - for (int i = 0; i < 100; i++) + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) { - char buf[32]; - sprintf(buf, "%03d", i); - ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); - ImGui::NextColumn(); + for (int i = 0; i < 100; i++) + { + char buf[32]; + sprintf(buf, "%03d", i); + ImGui::TableNextColumn(); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + ImGui::EndTable(); } ImGui::EndChild(); ImGui::PopStyleVar(); } - ImGui::Separator(); + ImGui::SeparatorText("Misc/Advanced"); // Demonstrate a few extra things // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) - // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window) - // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position. - // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window) - // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this. + // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + // You can also call SetNextWindowPos() to position the child window. The parent window will effectively + // layout from this position. + // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from + // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. { - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10); + static int offset_x = 0; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); - ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None); + ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); for (int n = 0; n < 50; n++) ImGui::Text("Some test %d", n); ImGui::EndChild(); + bool child_is_hovered = ImGui::IsItemHovered(); ImVec2 child_rect_min = ImGui::GetItemRectMin(); ImVec2 child_rect_max = ImGui::GetItemRectMax(); ImGui::PopStyleColor(); + ImGui::Text("Hovered: %d", child_is_hovered); ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Layout/Widgets Width"); if (ImGui::TreeNode("Widgets Width")) { + static float f = 0.0f; + static bool show_indented_items = true; + ImGui::Checkbox("Show indented items", &show_indented_items); + // Use SetNextItemWidth() to set the width of a single upcoming item. // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. - static float f = 0.0f; + // In real code use you'll probably want to choose width values that are proportional to your font size + // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); ImGui::SameLine(); HelpMarker("Fixed width."); - ImGui::SetNextItemWidth(100); - ImGui::DragFloat("float##1", &f); + ImGui::PushItemWidth(100); + ImGui::DragFloat("float##1b", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##1b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); - ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); - ImGui::SameLine(); HelpMarker("Half of window width."); - ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); - ImGui::DragFloat("float##2", &f); + ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); + ImGui::PushItemWidth(-100); + ImGui::DragFloat("float##2a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##2b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); - ImGui::DragFloat("float##3", &f); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::DragFloat("float##3a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##3b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); - ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); - ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); - ImGui::SetNextItemWidth(-100); - ImGui::DragFloat("float##4", &f); + ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus half"); + ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::DragFloat("float##4a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##4b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); - // Demonstrate using PushItemWidth to surround three items. Calling SetNextItemWidth() before each of them would have the same effect. - ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); + // Demonstrate using PushItemWidth to surround three items. + // Calling SetNextItemWidth() before each of them would have the same effect. + ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); ImGui::SameLine(); HelpMarker("Align to right edge"); - ImGui::PushItemWidth(-1); + ImGui::PushItemWidth(-FLT_MIN); ImGui::DragFloat("##float5a", &f); - ImGui::DragFloat("##float5b", &f); - ImGui::DragFloat("##float5c", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##5b", &f); + ImGui::Unindent(); + } ImGui::PopItemWidth(); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout"); if (ImGui::TreeNode("Basic Horizontal Layout")) { ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); // Text + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine"); ImGui::Text("Two items: Hello"); ImGui::SameLine(); ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); @@ -1908,6 +2748,7 @@ static void ShowDemoWindowLayout() ImGui::Text("can fit within a text block."); // Aligned to arbitrary position. Easy/cheap column. + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)"); ImGui::Text("Aligned"); ImGui::SameLine(150); ImGui::Text("x=150"); ImGui::SameLine(300); ImGui::Text("x=300"); @@ -1916,6 +2757,7 @@ static void ShowDemoWindowLayout() ImGui::SameLine(300); ImGui::SmallButton("x=300"); // Checkbox + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)"); static bool c1 = false, c2 = false, c3 = false, c4 = false; ImGui::Checkbox("My", &c1); ImGui::SameLine(); ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); @@ -1947,13 +2789,16 @@ static void ShowDemoWindowLayout() ImGui::PopItemWidth(); // Dummy + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy"); ImVec2 button_sz(40, 40); ImGui::Button("A", button_sz); ImGui::SameLine(); ImGui::Dummy(button_sz); ImGui::SameLine(); ImGui::Button("B", button_sz); - // Manually wrapping (we should eventually provide this as an automatic layout feature, but for now you can do it manually) - ImGui::Text("Manually wrapping:"); + // Manually wrapping + // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping"); + ImGui::Text("Manual wrapping:"); ImGuiStyle& style = ImGui::GetStyle(); int buttons_count = 20; float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; @@ -1971,80 +2816,13 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Tabs")) - { - if (ImGui::TreeNode("Basic")) - { - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; - if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) - { - if (ImGui::BeginTabItem("Avocado")) - { - ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Broccoli")) - { - ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Cucumber")) - { - ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - } - ImGui::Separator(); - ImGui::TreePop(); - } - - if (ImGui::TreeNode("Advanced & Close Button")) - { - // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). - static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; - ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); - ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); - if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) - tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); - - // Tab Bar - const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; - static bool opened[4] = { true, true, true, true }; // Persistent user state - for (int n = 0; n < IM_ARRAYSIZE(opened); n++) - { - if (n > 0) { ImGui::SameLine(); } - ImGui::Checkbox(names[n], &opened[n]); - } - - // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed. - if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) - { - for (int n = 0; n < IM_ARRAYSIZE(opened); n++) - if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n])) - { - ImGui::Text("This is the %s tab!", names[n]); - if (n & 1) - ImGui::Text("I am an odd tab."); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - } - ImGui::Separator(); - ImGui::TreePop(); - } - ImGui::TreePop(); - } - + IMGUI_DEMO_MARKER("Layout/Groups"); if (ImGui::TreeNode("Groups")) { - HelpMarker("BeginGroup() basically locks the horizontal position for new line. EndGroup() bundles the whole group so that you can use \"item\" functions such as IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); ImGui::BeginGroup(); { ImGui::BeginGroup(); @@ -2067,31 +2845,33 @@ static void ShowDemoWindowLayout() const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); - ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); ImGui::SameLine(); - ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); ImGui::EndGroup(); ImGui::SameLine(); ImGui::Button("LEVERAGE\nBUZZWORD", size); ImGui::SameLine(); - if (ImGui::ListBoxHeader("List", size)) + if (ImGui::BeginListBox("List", size)) { ImGui::Selectable("Selected", true); ImGui::Selectable("Not Selected", false); - ImGui::ListBoxFooter(); + ImGui::EndListBox(); } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment"); if (ImGui::TreeNode("Text Baseline Alignment")) { { ImGui::BulletText("Text baseline:"); - ImGui::SameLine(); - HelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets."); + ImGui::SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); ImGui::Indent(); ImGui::Text("KO Blahblah"); ImGui::SameLine(); @@ -2099,7 +2879,8 @@ static void ShowDemoWindowLayout() HelpMarker("Baseline of button will look misaligned with text.."); // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - // Because we don't know what's coming after the Text() statement, we need to move the text baseline down by FramePadding.y + // (because we don't know what's coming after the Text() statement, we need to move the text baseline + // down by FramePadding.y ahead of time) ImGui::AlignTextToFramePadding(); ImGui::Text("OK Blahblah"); ImGui::SameLine(); ImGui::Button("Some framed item"); ImGui::SameLine(); @@ -2151,7 +2932,7 @@ static void ShowDemoWindowLayout() ImGui::BulletText("Misc items:"); ImGui::Indent(); - // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button + // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. ImGui::Button("80x80", ImVec2(80, 80)); ImGui::SameLine(); ImGui::Button("50x50", ImVec2(50, 50)); @@ -2164,12 +2945,29 @@ static void ShowDemoWindowLayout() const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::Button("Button##1"); ImGui::SameLine(0.0f, spacing); - if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + if (ImGui::TreeNode("Node##1")) + { + // Placeholder tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } - ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). - bool node_open = ImGui::TreeNode("Node##2");// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. + // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + // Otherwise you can use SmallButton() (smaller fit). + ImGui::AlignTextToFramePadding(); + + // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + // other contents below the node. + bool node_open = ImGui::TreeNode("Node##2"); ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); - if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + if (node_open) + { + // Placeholder tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } // Bullet ImGui::Button("Button##3"); @@ -2185,9 +2983,11 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Layout/Scrolling"); if (ImGui::TreeNode("Scrolling")) { // Vertical scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical"); HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); static int track_item = 50; @@ -2197,18 +2997,16 @@ static void ShowDemoWindowLayout() static float scroll_to_pos_px = 200.0f; ImGui::Checkbox("Decoration", &enable_extra_decorations); - ImGui::SameLine(); - HelpMarker("We expose this for testing because scrolling sometimes had issues with window decoration such as menu-bars."); ImGui::Checkbox("Track", &enable_track); ImGui::PushItemWidth(100); ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); bool scroll_to_off = ImGui::Button("Scroll Offset"); - ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, 9999, "+%.0f px"); + ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); bool scroll_to_pos = ImGui::Button("Scroll To Pos"); - ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, 9999, "X/Y = %.0f px"); + ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); ImGui::PopItemWidth(); if (scroll_to_off || scroll_to_pos) @@ -2226,8 +3024,9 @@ static void ShowDemoWindowLayout() const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; ImGui::TextUnformatted(names[i]); - ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; - bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); + const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; + const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -2237,7 +3036,7 @@ static void ShowDemoWindowLayout() ImGui::SetScrollY(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); - if (window_visible) // Avoid calling SetScrollHereY when running with culled items + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items { for (int item = 0; item < 100; item++) { @@ -2261,22 +3060,30 @@ static void ShowDemoWindowLayout() ImGui::PopID(); // Horizontal scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal"); ImGui::Spacing(); - HelpMarker("Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\nUsing the \"Scroll To Pos\" button above will make the discontinuity at edges visible: scrolling to the top/bottom/left/right-most item will add an additional WindowPadding to reflect on reaching the edge of the list.\n\nBecause the clipping rectangle of most window hides half worth of WindowPadding on the left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the equivalent SetScrollFromPosY(+1) wouldn't."); + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " + "equivalent SetScrollFromPosY(+1) wouldn't."); ImGui::PushID("##HorizontalScrolling"); for (int i = 0; i < 5; i++) { float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); - bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); + ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); - if (window_visible) // Avoid calling SetScrollHereY when running with culled items + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items { for (int item = 0; item < 100; item++) { + if (item > 0) + ImGui::SameLine(); if (enable_track && item == track_item) { ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); @@ -2286,7 +3093,6 @@ static void ShowDemoWindowLayout() { ImGui::Text("Item %d", item); } - ImGui::SameLine(); } } float scroll_x = ImGui::GetScrollX(); @@ -2300,16 +3106,22 @@ static void ShowDemoWindowLayout() ImGui::PopID(); // Miscellaneous Horizontal Scrolling Demo - HelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)"); + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); static int lines = 7; ImGui::SliderInt("Lines", &lines, 1, 15); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); - ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); + ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); + ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { - // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off - // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) + // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + // If you want to create your own time line for a real application you may be better off manipulating + // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + // yourself. You may also want to use the lower-level ImDrawList API. int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); for (int n = 0; n < num_buttons; n++) { @@ -2317,8 +3129,8 @@ static void ShowDemoWindowLayout() ImGui::PushID(n + line * 1000); char num_buf[16]; sprintf(num_buf, "%d", n); - const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf; - float hue = n*0.05f; + const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; + float hue = n * 0.05f; ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); @@ -2332,13 +3144,21 @@ static void ShowDemoWindowLayout() ImGui::EndChild(); ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; - ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); + ImGui::SmallButton("<<"); + if (ImGui::IsItemActive()) + scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); - ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); + ImGui::SmallButton(">>"); + if (ImGui::IsItemActive()) + scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); if (scroll_x_delta != 0.0f) { - ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) + // Demonstrate a trick: you can use Begin to set yourself in the context of another window + // (here we are already out of your child window) + ImGui::BeginChild("scrolling"); ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); ImGui::EndChild(); } @@ -2361,6 +3181,7 @@ static void ShowDemoWindowLayout() if (explicit_content_size) ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window"); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); @@ -2409,8 +3230,19 @@ static void ShowDemoWindowLayout() } if (show_columns) { - ImGui::Columns(4); - for (int n = 0; n < 4; n++) + ImGui::Text("Tables:"); + if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) + { + for (int n = 0; n < 4; n++) + { + ImGui::TableNextColumn(); + ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); + } + ImGui::EndTable(); + } + ImGui::Text("Columns:"); + ImGui::Columns(4); + for (int n = 0; n < 4; n++) { ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::NextColumn(); @@ -2427,7 +3259,7 @@ static void ShowDemoWindowLayout() } if (show_child) { - ImGui::BeginChild("child", ImVec2(0,0), true); + ImGui::BeginChild("child", ImVec2(0, 0), true); ImGui::EndChild(); } ImGui::End(); @@ -2436,34 +3268,87 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Layout/Clipping"); if (ImGui::TreeNode("Clipping")) { - static ImVec2 size(100, 100), offset(50, 20); - ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); + static ImVec2 size(100.0f, 100.0f); + static ImVec2 offset(30.0f, 30.0f); ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); - ImGui::TextWrapped("(Click and drag)"); - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); - ImGui::InvisibleButton("##dummy", size); - if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } - ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); - ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); + ImGui::TextWrapped("(Click and drag to scroll)"); + + HelpMarker( + "(Left) Using ImGui::PushClipRect():\n" + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" + "(use this if you want your clipping rectangle to affect interactions)\n\n" + "(Center) Using ImDrawList::PushClipRect():\n" + "Will alter ImDrawList rendering only.\n" + "(use this as a shortcut if you are only using ImDrawList calls)\n\n" + "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" + "Will alter only this specific ImDrawList::AddText() rendering.\n" + "This is often used internally to avoid altering the clipping rectangle and minimize draw calls."); + + for (int n = 0; n < 3; n++) + { + if (n > 0) + ImGui::SameLine(); + + ImGui::PushID(n); + ImGui::InvisibleButton("##canvas", size); + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + { + offset.x += ImGui::GetIO().MouseDelta.x; + offset.y += ImGui::GetIO().MouseDelta.y; + } + ImGui::PopID(); + if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped. + continue; + + const ImVec2 p0 = ImGui::GetItemRectMin(); + const ImVec2 p1 = ImGui::GetItemRectMax(); + const char* text_str = "Line 1 hello\nLine 2 clip me!"; + const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + switch (n) + { + case 0: + ImGui::PushClipRect(p0, p1, true); + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); + ImGui::PopClipRect(); + break; + case 1: + draw_list->PushClipRect(p0, p1, true); + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); + draw_list->PopClipRect(); + break; + case 2: + ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); + break; + } + } + ImGui::TreePop(); } } static void ShowDemoWindowPopups() { + IMGUI_DEMO_MARKER("Popups"); if (!ImGui::CollapsingHeader("Popups & Modal windows")) return; // The properties of popups windows are: // - They block normal mouse hovering detection outside them. (*) // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. - // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as we are used to with regular Begin() calls. - // User can manipulate the visibility state by calling OpenPopup(). - // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. - // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. + // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as + // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even + // when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close + // popups at any time. // Typical use for regular windows: // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); @@ -2473,24 +3358,26 @@ static void ShowDemoWindowPopups() // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. + IMGUI_DEMO_MARKER("Popups/Popups"); if (ImGui::TreeNode("Popups")) { - ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); + ImGui::TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " + "Clicking outside the popup closes it."); static int selected_fish = -1; const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; static bool toggles[] = { true, false, false, false, false }; - // Simple selection popup - // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + // Simple selection popup (if you want to show the current selection inside the Button itself, + // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) if (ImGui::Button("Select..")) ImGui::OpenPopup("my_select_popup"); ImGui::SameLine(); ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); if (ImGui::BeginPopup("my_select_popup")) { - ImGui::Text("Aquarium"); - ImGui::Separator(); + ImGui::SeparatorText("Aquarium"); for (int i = 0; i < IM_ARRAYSIZE(names); i++) if (ImGui::Selectable(names[i])) selected_fish = i; @@ -2539,164 +3426,2109 @@ static void ShowDemoWindowPopups() } // Call the more complete ShowExampleMenuFile which we use in various places of this demo - if (ImGui::Button("File Menu..")) + if (ImGui::Button("With a menu..")) ImGui::OpenPopup("my_file_popup"); - if (ImGui::BeginPopup("my_file_popup")) + if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar)) { - ShowExampleMenuFile(); + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + ImGui::MenuItem("Dummy"); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from popup!"); + ImGui::Button("This is a dummy button.."); ImGui::EndPopup(); } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Popups/Context menus"); if (ImGui::TreeNode("Context menus")) { + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: - // if (IsItemHovered() && IsMouseReleased(0)) - // OpenPopup(id); - // return BeginPopup(id); - // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. - static float value = 0.5f; - ImGui::Text("Value = %.3f (<-- right-click here)", value); - if (ImGui::BeginPopupContextItem("item context menu")) - { - if (ImGui::Selectable("Set to zero")) value = 0.0f; - if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::SetNextItemWidth(-1); - ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); - ImGui::EndPopup(); + // if (id == 0) + // id = GetItemID(); // Use last item id + // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + // OpenPopup(id); + // return BeginPopup(id); + // For advanced uses you may want to replicate and customize this code. + // See more details in BeginPopupContextItem(). + + // Example 1 + // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + // and BeginPopupContextItem() will use the last item ID as the popup ID. + { + const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" }; + static int selected = -1; + for (int n = 0; n < 5; n++) + { + if (ImGui::Selectable(names[n], selected == n)) + selected = n; + if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id + { + selected = n; + ImGui::Text("This a popup for \"%s\"!", names[n]); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Right-click to open popup"); + } + } + + // Example 2 + // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + // Using an explicit identifier is also convenient if you want to activate the popups from different locations. + { + HelpMarker("Text() elements don't have stable identifiers so we need to provide one."); + static float value = 0.5f; + ImGui::Text("Value = %.3f <-- (1) right-click this text", value); + if (ImGui::BeginPopupContextItem("my popup")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = 3.1415f; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::EndPopup(); + } + + // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + // Here we make it that right-clicking this other text element opens the same popup as above. + // The popup itself will be submitted by the code above. + ImGui::Text("(2) Or right-click this text"); + ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight); + + // Back to square one: manually open the same popup. + if (ImGui::Button("(3) Or click this button")) + ImGui::OpenPopup("my popup"); + } + + // Example 3 + // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID), + // we need to make sure your item identifier is stable. + // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + { + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator."); + static char name[32] = "Label1"; + char buf[64]; + sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label + ImGui::Button(buf); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("Edit name:"); + ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); } - // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the Begin call. - // So here we will make it that clicking on the text field with the right mouse button (1) will toggle the visibility of the popup above. - ImGui::Text("(You can also right-click me to open the same popup as above.)"); - ImGui::OpenPopupOnItemClick("item context menu", 1); + ImGui::TreePop(); + } - // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). - // BeginPopupContextItem() will use the last item ID as the popup ID. - // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details) - static char name[32] = "Label1"; - char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label - ImGui::Button(buf); - if (ImGui::BeginPopupContextItem()) + IMGUI_DEMO_MARKER("Popups/Modals"); + if (ImGui::TreeNode("Modals")) + { + ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); + + if (ImGui::Button("Delete..")) + ImGui::OpenPopup("Delete?"); + + // Always center this window when appearing + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!"); + ImGui::Separator(); + + //static int unused_i = 0; + //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); + + static bool dont_ask_me_next_time = false; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); + ImGui::PopStyleVar(); + + if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (ImGui::Button("Stacked modals..")) + ImGui::OpenPopup("Stacked 1"); + if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) { - ImGui::Text("Edit name:"); - ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Some menu item")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + + // Testing behavior of widgets stacking their own regular popups over the modal. + static int item = 1; + static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::ColorEdit4("color", color); + + if (ImGui::Button("Add another modal..")) + ImGui::OpenPopup("Stacked 2"); + + // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + // of the bool actually doesn't matter here. + bool unused_open = true; + if (ImGui::BeginPopupModal("Stacked 2", &unused_open)) + { + ImGui::Text("Hello from Stacked The Second!"); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + if (ImGui::Button("Close")) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } - ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); - ImGui::TreePop(); - } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Popups/Menus inside a regular window"); + if (ImGui::TreeNode("Menus inside a regular window")) + { + ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::Separator(); + + ImGui::MenuItem("Menu item", "CTRL+M"); + if (ImGui::BeginMenu("Menu inside a regular window")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::Separator(); + ImGui::TreePop(); + } +} + +// Dummy data structure that we use for the Table demo. +// (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo function) +namespace +{ +// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. +// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. +// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) +// If you don't use sorting, you will generally never care about giving column an ID! +enum MyItemColumnID +{ + MyItemColumnID_ID, + MyItemColumnID_Name, + MyItemColumnID_Action, + MyItemColumnID_Quantity, + MyItemColumnID_Description +}; + +struct MyItem +{ + int ID; + const char* Name; + int Quantity; + + // We have a problem which is affecting _only this demo_ and should not affect your code: + // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), + // however qsort doesn't allow passing user data to comparing function. + // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. + // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. + // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called + // very often by the sorting algorithm it would be a little wasteful. + static const ImGuiTableSortSpecs* s_current_sort_specs; + + // Compare function to be used by qsort() + static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) + { + const MyItem* a = (const MyItem*)lhs; + const MyItem* b = (const MyItem*)rhs; + for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) + { + // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() + // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler! + const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n]; + int delta = 0; + switch (sort_spec->ColumnUserID) + { + case MyItemColumnID_ID: delta = (a->ID - b->ID); break; + case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break; + case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break; + case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break; + default: IM_ASSERT(0); break; + } + if (delta > 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1; + if (delta < 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1; + } + + // qsort() is instable so always return a way to differenciate items. + // Your own compare function may want to avoid fallback on implicit sort specs e.g. a Name compare if it wasn't already part of the sort specs. + return (a->ID - b->ID); + } +}; +const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; +} + +// Make the UI compact because there are so many fields +static void PushStyleCompact() +{ + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); +} + +static void PopStyleCompact() +{ + ImGui::PopStyleVar(2); +} + +// Show a combo box with a choice of sizing policies +static void EditTableSizingFlags(ImGuiTableFlags* p_flags) +{ + struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; + static const EnumDesc policies[] = + { + { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, + { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, + { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, + { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." }, + { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." } + }; + int idx; + for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++) + if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_)) + break; + const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : ""; + if (ImGui::BeginCombo("Sizing Policy", preview_text)) + { + for (int n = 0; n < IM_ARRAYSIZE(policies); n++) + if (ImGui::Selectable(policies[n].Name, idx == n)) + *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value; + ImGui::EndCombo(); + } + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered() && ImGui::BeginTooltip()) + { + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f); + for (int m = 0; m < IM_ARRAYSIZE(policies); m++) + { + ImGui::Separator(); + ImGui::Text("%s:", policies[m].Name); + ImGui::Separator(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f); + ImGui::TextUnformatted(policies[m].Tooltip); + } + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) +{ + ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)"); + ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide); + ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort); + if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch)) + *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch); + if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed)) + *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed); + ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize); + ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder); + ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide); + ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip); + ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort); + ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending); + ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending); + ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel); + ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth); + ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending); + ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending); + ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0"); + ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0"); +} + +static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) +{ + ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled); + ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible); + ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted); + ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered); +} + +static void ShowDemoWindowTables() +{ + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + IMGUI_DEMO_MARKER("Tables"); + if (!ImGui::CollapsingHeader("Tables & Columns")) + return; + + // Using those as a base value to create width/height that are factor of the size of our font + const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; + const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); + + ImGui::PushID("Tables"); + + int open_action = -1; + if (ImGui::Button("Open all")) + open_action = 1; + ImGui::SameLine(); + if (ImGui::Button("Close all")) + open_action = 0; + ImGui::SameLine(); + + // Options + static bool disable_indent = false; + ImGui::Checkbox("Disable tree indentation", &disable_indent); + ImGui::SameLine(); + HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width."); + ImGui::Separator(); + if (disable_indent) + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); + + // About Styling of tables + // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. + // There are however a few settings that a shared and part of the ImGuiStyle structure: + // style.CellPadding // Padding within each cell + // style.Colors[ImGuiCol_TableHeaderBg] // Table header background + // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders + // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders + // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows) + // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) + + // Demos + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Basic"); + if (ImGui::TreeNode("Basic")) + { + // Here we will showcase three different ways to output a table. + // They are very simple variations of a same thing! + + // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. + // In many situations, this is the most flexible and easy to use pattern. + HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop."); + if (ImGui::BeginTable("table1", 3)) + { + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Row %d Column %d", row, column); + } + } + ImGui::EndTable(); + } + + // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). + // This is generally more convenient when you have code manually submitting the contents of each column. + HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually."); + if (ImGui::BeginTable("table2", 3)) + { + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Row %d", row); + ImGui::TableNextColumn(); + ImGui::Text("Some contents"); + ImGui::TableNextColumn(); + ImGui::Text("123.456"); + } + ImGui::EndTable(); + } + + // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), + // as TableNextColumn() will automatically wrap around and create new rows as needed. + // This is generally more convenient when your cells all contains the same type of data. + HelpMarker( + "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains the same type of contents.\n" + "This is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition."); + if (ImGui::BeginTable("table3", 3)) + { + for (int item = 0; item < 14; item++) + { + ImGui::TableNextColumn(); + ImGui::Text("Item %d", item); + } + ImGui::EndTable(); + } + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Borders, background"); + if (ImGui::TreeNode("Borders, background")) + { + // Expose a few Borders related flags interactively + enum ContentsType { CT_Text, CT_FillButton }; + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; + static bool display_headers = false; + static int contents_type = CT_Text; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); + ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH"); + ImGui::Indent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); + ImGui::Unindent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); + ImGui::Unindent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner); + ImGui::Unindent(); + + ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); + ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); + ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); + ImGui::Checkbox("Display headers", &display_headers); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + // Display headers so we can inspect their interaction with borders. + // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them too much. See other sections for details) + if (display_headers) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + char buf[32]; + sprintf(buf, "Hello %d,%d", column, row); + if (contents_type == CT_Text) + ImGui::TextUnformatted(buf); + else if (contents_type == CT_FillButton) + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, stretch"); + if (ImGui::TreeNode("Resizable, stretch")) + { + // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" + // All columns maintain a sizing weight, and they will occupy all available width. + static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this."); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, fixed"); + if (ImGui::TreeNode("Resizable, fixed")) + { + // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) + // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) + // If there is not enough available width to fit all columns, they will however be resized down. + // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings + HelpMarker( + "Using _Resizable + _SizingFixedFit flags.\n" + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" + "Double-click a column border to auto-fit the column to its contents."); + PushStyleCompact(); + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, mixed"); + if (ImGui::TreeNode("Resizable, mixed")) + { + HelpMarker( + "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch."); + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + + if (ImGui::BeginTable("table1", 3, flags)) + { + ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableHeadersRow(); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row); + } + } + ImGui::EndTable(); + } + if (ImGui::BeginTable("table2", 6, flags)) + { + ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide); + ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide); + ImGui::TableHeadersRow(); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 6; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers"); + if (ImGui::TreeNode("Reorderable, hideable, with headers")) + { + HelpMarker( + "Click and drag column headers to reorder columns.\n\n" + "Right-click on a header to open a context menu."); + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)"); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. + // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column) + if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f))) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Fixed %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Padding"); + if (ImGui::TreeNode("Padding")) + { + // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. + // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" + "e.g.:\n" + "- BorderOuterV\n" + "- any form of row selection\n" + "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n" + "Actual padding values are using style.CellPadding.\n\n" + "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding."); + + static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX); + ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX); + ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX); + ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)"); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV); + static bool show_headers = false; + ImGui::Checkbox("show_headers", &show_headers); + PopStyleCompact(); + + if (ImGui::BeginTable("table_padding", 3, flags1)) + { + if (show_headers) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + { + ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); + } + else + { + char buf[32]; + sprintf(buf, "Hello %d,%d", column, row); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) + // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); + } + } + ImGui::EndTable(); + } + + // Second example: set style.CellPadding to (0.0) or a custom value. + // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... + HelpMarker("Setting style.CellPadding to (0,0) or a custom value."); + static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; + static ImVec2 cell_padding(0.0f, 0.0f); + static bool show_widget_frame_bg = true; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable); + ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg); + ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f"); + PopStyleCompact(); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding); + if (ImGui::BeginTable("table_padding_2", 3, flags2)) + { + static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells + static bool init = true; + if (!show_widget_frame_bg) + ImGui::PushStyleColor(ImGuiCol_FrameBg, 0); + for (int cell = 0; cell < 3 * 5; cell++) + { + ImGui::TableNextColumn(); + if (init) + strcpy(text_bufs[cell], "edit me"); + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::PushID(cell); + ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell])); + ImGui::PopID(); + } + if (!show_widget_frame_bg) + ImGui::PopStyleColor(); + init = false; + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Explicit widths"); + if (ImGui::TreeNode("Sizing policies")) + { + static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX); + PopStyleCompact(); + + static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame }; + for (int table_n = 0; table_n < 4; table_n++) + { + ImGui::PushID(table_n); + ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30); + EditTableSizingFlags(&sizing_policy_flags[table_n]); + + // To make it easier to understand the different sizing policy, + // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width. + if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1)) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + } + ImGui::EndTable(); + } + if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1)) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::Text("AAAA"); + ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB"); + ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC"); + } + ImGui::EndTable(); + } + ImGui::PopID(); + } + + ImGui::Spacing(); + ImGui::TextUnformatted("Advanced"); + ImGui::SameLine(); + HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns."); + + enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText }; + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable; + static int contents_type = CT_ShowWidth; + static int column_count = 3; + + PushStyleCompact(); + ImGui::PushID("Advanced"); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); + EditTableSizingFlags(&flags); + ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0"); + if (contents_type == CT_FillButton) + { + ImGui::SameLine(); + HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width."); + } + ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); + ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); + ImGui::PopItemWidth(); + ImGui::PopID(); + PopStyleCompact(); + + if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7))) + { + for (int cell = 0; cell < 10 * column_count; cell++) + { + ImGui::TableNextColumn(); + int column = ImGui::TableGetColumnIndex(); + int row = ImGui::TableGetRowIndex(); + + ImGui::PushID(cell); + char label[32]; + static char text_buf[32] = ""; + sprintf(label, "Hello %d,%d", column, row); + switch (contents_type) + { + case CT_ShortText: ImGui::TextUnformatted(label); break; + case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break; + case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break; + case CT_Button: ImGui::Button(label); break; + case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break; + case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping"); + if (ImGui::TreeNode("Vertical scrolling, with clipping")) + { + HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + PopStyleCompact(); + + // When using ScrollX or ScrollY we need to specify a size for our table container! + // Otherwise by default the table will fit all available space, like a BeginChild() call. + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); + if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size)) + { + ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible + ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None); + ImGui::TableHeadersRow(); + + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(1000); + while (clipper.Step()) + { + for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Horizontal scrolling"); + if (ImGui::TreeNode("Horizontal scrolling")) + { + HelpMarker( + "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" + "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX," + "because the container window won't automatically extend vertically to fix contents (this may be improved in future versions)."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + static int freeze_cols = 1; + static int freeze_rows = 1; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + PopStyleCompact(); + + // When using ScrollX or ScrollY we need to specify a size for our table container! + // Otherwise by default the table will fit all available space, like a BeginChild() call. + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); + if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size)) + { + ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); + ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableSetupColumn("Four"); + ImGui::TableSetupColumn("Five"); + ImGui::TableSetupColumn("Six"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 20; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 7; column++) + { + // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. + // Because here we know that: + // - A) all our columns are contributing the same to row height + // - B) column 0 is always visible, + // We only always submit this one column and can skip others. + // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + if (!ImGui::TableSetColumnIndex(column) && column > 0) + continue; + if (column == 0) + ImGui::Text("Line %d", row); + else + ImGui::Text("Hello world %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + ImGui::Spacing(); + ImGui::TextUnformatted("Stretch + ScrollX"); + ImGui::SameLine(); + HelpMarker( + "Showcase using Stretch columns + ScrollX together: " + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense."); + static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + static float inner_width = 1000.0f; + PushStyleCompact(); + ImGui::PushID("flags3"); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX); + ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f"); + ImGui::PopItemWidth(); + ImGui::PopID(); + PopStyleCompact(); + if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width)) + { + for (int cell = 0; cell < 20 * 7; cell++) + { + ImGui::TableNextColumn(); + ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex()); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Columns flags"); + if (ImGui::TreeNode("Columns flags")) + { + // Create a first table just to show all the options/flags we want to make visible in our example! + const int column_count = 3; + const char* column_names[column_count] = { "One", "Two", "Three" }; + static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide }; + static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags() + + if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None)) + { + PushStyleCompact(); + for (int column = 0; column < column_count; column++) + { + ImGui::TableNextColumn(); + ImGui::PushID(column); + ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns + ImGui::Text("'%s'", column_names[column]); + ImGui::Spacing(); + ImGui::Text("Input flags:"); + EditTableColumnsFlags(&column_flags[column]); + ImGui::Spacing(); + ImGui::Text("Output flags:"); + ImGui::BeginDisabled(); + ShowTableColumnsStatusFlags(column_flags_out[column]); + ImGui::EndDisabled(); + ImGui::PopID(); + } + PopStyleCompact(); + ImGui::EndTable(); + } + + // Create the real table we care about for the example! + // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in + // a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down) + const ImGuiTableFlags flags + = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY + | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV + | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9); + if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size)) + { + for (int column = 0; column < column_count; column++) + ImGui::TableSetupColumn(column_names[column], column_flags[column]); + ImGui::TableHeadersRow(); + for (int column = 0; column < column_count; column++) + column_flags_out[column] = ImGui::TableGetColumnFlags(column); + float indent_step = (float)((int)TEXT_BASE_WIDTH / 2); + for (int row = 0; row < 8; row++) + { + ImGui::Indent(indent_step); // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. + ImGui::TableNextRow(); + for (int column = 0; column < column_count; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column)); + } + } + ImGui::Unindent(indent_step * 8.0f); + + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Columns widths"); + if (ImGui::TreeNode("Columns widths")) + { + HelpMarker("Using TableSetupColumn() to setup default width."); + + static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize); + PopStyleCompact(); + if (ImGui::BeginTable("table1", 3, flags1)) + { + // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f + ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f + ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto + ImGui::TableHeadersRow(); + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); + else + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + HelpMarker("Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, fixed columns with set width may still be shrunk down if there's not enough space in the host."); + + static ImGuiTableFlags flags2 = ImGuiTableFlags_None; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV); + PopStyleCompact(); + if (ImGui::BeginTable("table2", 4, flags2)) + { + // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 4; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); + else + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Nested tables"); + if (ImGui::TreeNode("Nested tables")) + { + HelpMarker("This demonstrates embedding a table into another table cell."); + + if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("A0"); + ImGui::TableSetupColumn("A1"); + ImGui::TableHeadersRow(); + + ImGui::TableNextColumn(); + ImGui::Text("A0 Row 0"); + { + float rows_height = TEXT_BASE_HEIGHT * 2; + if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("B0"); + ImGui::TableSetupColumn("B1"); + ImGui::TableHeadersRow(); + + ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); + ImGui::TableNextColumn(); + ImGui::Text("B0 Row 0"); + ImGui::TableNextColumn(); + ImGui::Text("B1 Row 0"); + ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); + ImGui::TableNextColumn(); + ImGui::Text("B0 Row 1"); + ImGui::TableNextColumn(); + ImGui::Text("B1 Row 1"); + + ImGui::EndTable(); + } + } + ImGui::TableNextColumn(); ImGui::Text("A1 Row 0"); + ImGui::TableNextColumn(); ImGui::Text("A0 Row 1"); + ImGui::TableNextColumn(); ImGui::Text("A1 Row 1"); + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Row height"); + if (ImGui::TreeNode("Row height")) + { + HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row."); + if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV)) + { + for (int row = 0; row < 10; row++) + { + float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row); + ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height); + ImGui::TableNextColumn(); + ImGui::Text("min_row_height = %.2f", min_row_height); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Outer size"); + if (ImGui::TreeNode("Outer size")) + { + // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY + // Important to that note how the two flags have slightly different behaviors! + ImGui::Text("Using NoHostExtendX and NoHostExtendY:"); + PushStyleCompact(); + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); + ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); + PopStyleCompact(); + + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f); + if (ImGui::BeginTable("table1", 3, flags, outer_size)) + { + for (int row = 0; row < 10; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::SameLine(); + ImGui::Text("Hello!"); + + ImGui::Spacing(); + + ImGui::Text("Using explicit size:"); + if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::SameLine(); + if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Background color"); + if (ImGui::TreeNode("Background color")) + { + static ImGuiTableFlags flags = ImGuiTableFlags_RowBg; + static int row_bg_type = 1; + static int row_bg_target = 1; + static int cell_bg_type = 1; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); + ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0"); + ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); + ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here."); + IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2); + IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1); + IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 5, flags)) + { + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + + // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)' + // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + if (row_bg_type != 0) + { + ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient? + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color); + } + + // Fill cells + for (int column = 0; column < 5; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%c%c", 'A' + row, '0' + column); + + // Change background of Cells B1->C2 + // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)' + // (the CellBg color will be blended over the RowBg and ColumnBg colors) + // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1) + { + ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color); + } + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Tree view"); + if (ImGui::TreeNode("Tree view")) + { + static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + + if (ImGui::BeginTable("3ways", 3, flags)) + { + // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); + ImGui::TableHeadersRow(); + + // Simple storage to output a dummy file-system. + struct MyTreeNode + { + const char* Name; + const char* Type; + int Size; + int ChildIdx; + int ChildCount; + static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + const bool is_folder = (node->ChildCount > 0); + if (is_folder) + { + bool open = ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::TextDisabled("--"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + if (open) + { + for (int child_n = 0; child_n < node->ChildCount; child_n++) + DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes); + ImGui::TreePop(); + } + } + else + { + ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::Text("%d", node->Size); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + } + } + }; + static const MyTreeNode nodes[] = + { + { "Root", "Folder", -1, 1, 3 }, // 0 + { "Music", "Folder", -1, 4, 2 }, // 1 + { "Textures", "Folder", -1, 6, 3 }, // 2 + { "desktop.ini", "System file", 1024, -1,-1 }, // 3 + { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4 + { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5 + { "Image001.png", "Image file", 203128, -1,-1 }, // 6 + { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7 + { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8 + }; + + MyTreeNode::DisplayNode(&nodes[0], nodes); + + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Item width"); + if (ImGui::TreeNode("Item width")) + { + HelpMarker( + "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" + "Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense."); + if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders)) + { + ImGui::TableSetupColumn("small"); + ImGui::TableSetupColumn("half"); + ImGui::TableSetupColumn("right-align"); + ImGui::TableHeadersRow(); + + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + if (row == 0) + { + // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + ImGui::TableSetColumnIndex(0); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small + ImGui::TableSetColumnIndex(1); + ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::TableSetColumnIndex(2); + ImGui::PushItemWidth(-FLT_MIN); // Right-aligned + } + + // Draw our contents + static float dummy_f = 0.0f; + ImGui::PushID(row); + ImGui::TableSetColumnIndex(0); + ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f); + ImGui::TableSetColumnIndex(1); + ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f); + ImGui::TableSetColumnIndex(2); + ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // Demonstrate using TableHeader() calls instead of TableHeadersRow() + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Custom headers"); + if (ImGui::TreeNode("Custom headers")) + { + const int COLUMNS_COUNT = 3; + if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("Apricot"); + ImGui::TableSetupColumn("Banana"); + ImGui::TableSetupColumn("Cherry"); + + // Dummy entire-column selection storage + // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. + static bool column_selected[3] = {}; + + // Instead of calling TableHeadersRow() we'll submit custom headers ourselves + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + ImGui::TableSetColumnIndex(column); + const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn() + ImGui::PushID(column); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("##checkall", &column_selected[column]); + ImGui::PopStyleVar(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TableHeader(column_name); + ImGui::PopID(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + char buf[32]; + sprintf(buf, "Cell %d,%d", column, row); + ImGui::TableSetColumnIndex(column); + ImGui::Selectable(buf, column_selected[column]); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // Demonstrate creating custom context menus inside columns, while playing it nice with context menus provided by TableHeadersRow()/TableHeader() + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Context menus"); + if (ImGui::TreeNode("Context menus")) + { + HelpMarker("By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\nUsing ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body."); + static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody); + PopStyleCompact(); + + // Context Menus: first example + // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. + // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + const int COLUMNS_COUNT = 3; + if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1)) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + + // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui::TableHeadersRow(); + + // Submit dummy contents + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + // Context Menus: second example + // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + // [2.2] Right-click on the ".." to open a custom popup + // [2.3] Right-click in columns to open another custom popup + HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body)."); + ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; + if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2)) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + + // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui::TableHeadersRow(); + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + // Submit dummy contents + ImGui::TableSetColumnIndex(column); + ImGui::Text("Cell %d,%d", column, row); + ImGui::SameLine(); + + // [2.2] Right-click on the ".." to open a custom popup + ImGui::PushID(row * COLUMNS_COUNT + column); + ImGui::SmallButton(".."); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::PopID(); + } + } + + // [2.3] Right-click anywhere in columns to open another custom popup + // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup + // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + int hovered_column = -1; + for (int column = 0; column < COLUMNS_COUNT + 1; column++) + { + ImGui::PushID(column); + if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered) + hovered_column = column; + if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1)) + ImGui::OpenPopup("MyPopup"); + if (ImGui::BeginPopup("MyPopup")) + { + if (column == COLUMNS_COUNT) + ImGui::Text("This is a custom popup for unused space after the last column."); + else + ImGui::Text("This is a custom popup for Column %d", column); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + ImGui::Text("Hovered column: %d", hovered_column); + } + ImGui::TreePop(); + } + + // Demonstrate creating multiple tables with the same ID + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Synced instances"); + if (ImGui::TreeNode("Synced instances")) + { + HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); + + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings; + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit); + for (int n = 0; n < 3; n++) + { + char buf[32]; + sprintf(buf, "Synced Table %d", n); + bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); + if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5))) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions. + for (int cell = 0; cell < cell_count; cell++) + { + ImGui::TableNextColumn(); + ImGui::Text("this cell %d", cell); + } + ImGui::EndTable(); + } + } + ImGui::TreePop(); + } + + // Demonstrate using Sorting facilities + // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. + // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) + static const char* template_items_names[] = + { + "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", + "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" + }; + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Sorting"); + if (ImGui::TreeNode("Sorting")) + { + // Create item list + static ImVector items; + if (items.Size == 0) + { + items.resize(50, MyItem()); + for (int n = 0; n < items.Size; n++) + { + const int template_n = n % IM_ARRAYSIZE(template_items_names); + MyItem& item = items[n]; + item.ID = n; + item.Name = template_items_names[template_n]; + item.Quantity = (n * n - n) % 20; // Assign default quantities + } + } + + // Options + static ImGuiTableFlags flags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti + | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody + | ImGuiTableFlags_ScrollY; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + PopStyleCompact(); + + if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f)) + { + // Declare columns + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + // Demonstrate using a mixture of flags among available sort-related flags: + // - ImGuiTableColumnFlags_DefaultSort + // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible + ImGui::TableHeadersRow(); + + // Sort our data if sort specs have been changed! + if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) + if (sorts_specs->SpecsDirty) + { + MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. + if (items.Size > 1) + qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); + MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; + } + + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(items.Size); + while (clipper.Step()) + for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) + { + // Display a data item + MyItem* item = &items[row_n]; + ImGui::PushID(item->ID); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%04d", item->ID); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(item->Name); + ImGui::TableNextColumn(); + ImGui::SmallButton("None"); + ImGui::TableNextColumn(); + ImGui::Text("%d", item->Quantity); + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // In this example we'll expose most table flags and settings. + // For specific flags and settings refer to the corresponding section for more detailed explanation. + // This section is mostly useful to experiment with combining certain flags or settings with each others. + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Advanced"); + if (ImGui::TreeNode("Advanced")) + { + static ImGuiTableFlags flags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable + | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti + | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody + | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY + | ImGuiTableFlags_SizingFixedFit; + + enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; + static int contents_type = CT_SelectableSpanRow; + const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" }; + static int freeze_cols = 1; + static int freeze_rows = 1; + static int items_count = IM_ARRAYSIZE(template_items_names) * 2; + static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12); + static float row_min_height = 0.0f; // Auto + static float inner_width_with_scroll = 0.0f; // Auto-extend + static bool outer_size_enabled = true; + static bool show_headers = true; + static bool show_wrapped_text = false; + //static ImGuiTextFilter filter; + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing + if (ImGui::TreeNode("Options")) + { + // Make the UI compact because there are so many fields + PushStyleCompact(); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f); + + if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); + ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings); + ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)"); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen)) + { + EditTableSizingFlags(&flags); + ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); + ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled."); + ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); + ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); + ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options."); + ImGui::TreePop(); + } - if (ImGui::TreeNode("Modals")) - { - ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window."); + if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX); + ImGui::TreePop(); + } - if (ImGui::Button("Delete..")) - ImGui::OpenPopup("Delete?"); + if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::TreePop(); + } - if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); - ImGui::Separator(); + if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + ImGui::TreePop(); + } - //static int dummy_i = 0; - //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0"); + if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Checkbox("show_headers", &show_headers); + ImGui::Checkbox("show_wrapped_text", &show_wrapped_text); - static bool dont_ask_me_next_time = false; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); - ImGui::PopStyleVar(); + ImGui::DragFloat2("##OuterSize", &outer_size_value.x); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Checkbox("outer_size", &outer_size_enabled); + ImGui::SameLine(); + HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" + "- The table is output directly in the parent window.\n" + "- OuterSize.x < 0.0f will right-align the table.\n" + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set)."); + + // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. + // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX); + + ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX); + ImGui::SameLine(); HelpMarker("Specify height of the Selectable item."); + + ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999); + ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names)); + //filter.Draw("filter"); + ImGui::TreePop(); + } - if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } - ImGui::SetItemDefaultFocus(); - ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } - ImGui::EndPopup(); + ImGui::PopItemWidth(); + PopStyleCompact(); + ImGui::Spacing(); + ImGui::TreePop(); } - if (ImGui::Button("Stacked modals..")) - ImGui::OpenPopup("Stacked 1"); - if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) + // Update item list if we changed the number of items + static ImVector items; + static ImVector selection; + static bool items_need_sort = false; + if (items.Size != items_count) { - if (ImGui::BeginMenuBar()) + items.resize(items_count, MyItem()); + for (int n = 0; n < items_count; n++) { - if (ImGui::BeginMenu("File")) - { - if (ImGui::MenuItem("Dummy menu item")) {} - ImGui::EndMenu(); - } - ImGui::EndMenuBar(); + const int template_n = n % IM_ARRAYSIZE(template_items_names); + MyItem& item = items[n]; + item.ID = n; + item.Name = template_items_names[template_n]; + item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities } - ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + } - // Testing behavior of widgets stacking their own regular popups over the modal. - static int item = 1; - static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; - ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); - ImGui::ColorEdit4("color", color); + const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList(); + const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size; + ImVec2 table_scroll_cur, table_scroll_max; // For debug display + const ImDrawList* table_draw_list = NULL; // " + + // Submit table + const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f; + if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use)) + { + // Declare columns + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupColumn("Description", (flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Description); + ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); + ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); + + // Sort our data if sort specs have been changed! + ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty) + items_need_sort = true; + if (sorts_specs && items_need_sort && items.Size > 1) + { + MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. + qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); + MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; + } + items_need_sort = false; - if (ImGui::Button("Add another modal..")) - ImGui::OpenPopup("Stacked 2"); + // Take note of whether we are currently sorting based on the Quantity field, + // we will use this to trigger sorting when we know the data of this column has been modified. + const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0; - // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup. - // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here. - bool dummy_open = true; - if (ImGui::BeginPopupModal("Stacked 2", &dummy_open)) + // Show headers + if (show_headers) + ImGui::TableHeadersRow(); + + // Show data + // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? + ImGui::PushButtonRepeat(true); +#if 1 + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(items.Size); + while (clipper.Step()) { - ImGui::Text("Hello from Stacked The Second!"); - if (ImGui::Button("Close")) - ImGui::CloseCurrentPopup(); - ImGui::EndPopup(); - } + for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) +#else + // Without clipper + { + for (int row_n = 0; row_n < items.Size; row_n++) +#endif + { + MyItem* item = &items[row_n]; + //if (!filter.PassFilter(item->Name)) + // continue; + + const bool item_is_selected = selection.contains(item->ID); + ImGui::PushID(item->ID); + ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height); + + // For the demo purpose we can select among different type of items submitted in the first column + ImGui::TableSetColumnIndex(0); + char label[32]; + sprintf(label, "%04d", item->ID); + if (contents_type == CT_Text) + ImGui::TextUnformatted(label); + else if (contents_type == CT_Button) + ImGui::Button(label); + else if (contents_type == CT_SmallButton) + ImGui::SmallButton(label); + else if (contents_type == CT_FillButton) + ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); + else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) + { + ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None; + if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) + { + if (ImGui::GetIO().KeyCtrl) + { + if (item_is_selected) + selection.find_erase_unsorted(item->ID); + else + selection.push_back(item->ID); + } + else + { + selection.clear(); + selection.push_back(item->ID); + } + } + } - if (ImGui::Button("Close")) - ImGui::CloseCurrentPopup(); - ImGui::EndPopup(); - } + if (ImGui::TableSetColumnIndex(1)) + ImGui::TextUnformatted(item->Name); - ImGui::TreePop(); - } + // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, + // and we are currently sorting on the column showing the Quantity. + // To avoid triggering a sort while holding the button, we only trigger it when the button has been released. + // You will probably need a more advanced system in your code if you want to automatically sort when a specific entry changes. + if (ImGui::TableSetColumnIndex(2)) + { + if (ImGui::SmallButton("Chop")) { item->Quantity += 1; } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + ImGui::SameLine(); + if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + } - if (ImGui::TreeNode("Menus inside a regular window")) - { - ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); - ImGui::Separator(); - // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. - // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here - // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. - ImGui::PushID("foo"); - ImGui::MenuItem("Menu item", "CTRL+M"); - if (ImGui::BeginMenu("Menu inside a regular window")) - { - ShowExampleMenuFile(); - ImGui::EndMenu(); + if (ImGui::TableSetColumnIndex(3)) + ImGui::Text("%d", item->Quantity); + + ImGui::TableSetColumnIndex(4); + if (show_wrapped_text) + ImGui::TextWrapped("Lorem ipsum dolor sit amet"); + else + ImGui::Text("Lorem ipsum dolor sit amet"); + + if (ImGui::TableSetColumnIndex(5)) + ImGui::Text("1234"); + + ImGui::PopID(); + } + } + ImGui::PopButtonRepeat(); + + // Store some info to display debug details below + table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY()); + table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY()); + table_draw_list = ImGui::GetWindowDrawList(); + ImGui::EndTable(); + } + static bool show_debug_details = false; + ImGui::Checkbox("Debug details", &show_debug_details); + if (show_debug_details && table_draw_list) + { + ImGui::SameLine(0.0f, 0.0f); + const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size; + if (table_draw_list == parent_draw_list) + ImGui::Text(": DrawCmd: +%d (in same window)", + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); + else + ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y); } - ImGui::PopID(); - ImGui::Separator(); ImGui::TreePop(); } + + ImGui::PopID(); + + ShowDemoWindowColumns(); + + if (disable_indent) + ImGui::PopStyleVar(); } +// Demonstrate old/legacy Columns API! +// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] static void ShowDemoWindowColumns() { - if (!ImGui::CollapsingHeader("Columns")) - return; - - ImGui::PushID("Columns"); - - static bool disable_indent = false; - ImGui::Checkbox("Disable tree indentation", &disable_indent); + IMGUI_DEMO_MARKER("Columns (legacy API)"); + bool open = ImGui::TreeNode("Legacy Columns API"); ImGui::SameLine(); - HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); - if (disable_indent) - ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); + HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!"); + if (!open) + return; // Basic columns + IMGUI_DEMO_MARKER("Columns (legacy API)/Basic"); if (ImGui::TreeNode("Basic")) { ImGui::Text("Without border:"); @@ -2741,6 +5573,7 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Columns (legacy API)/Borders"); if (ImGui::TreeNode("Borders")) { // NB: Future columns API should allow automatic horizontal borders. @@ -2776,6 +5609,7 @@ static void ShowDemoWindowColumns() } // Create multiple items in a same cell before switching to next column + IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items"); if (ImGui::TreeNode("Mixed items")) { ImGui::Columns(3, "mixed"); @@ -2807,6 +5641,7 @@ static void ShowDemoWindowColumns() } // Word wrapping + IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping"); if (ImGui::TreeNode("Word-wrapping")) { ImGui::Columns(2, "word-wrapping"); @@ -2821,39 +5656,18 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } - // Scrolling columns - /* - if (ImGui::TreeNode("Vertical Scrolling")) - { - ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); - ImGui::Columns(3); - ImGui::Text("ID"); ImGui::NextColumn(); - ImGui::Text("Name"); ImGui::NextColumn(); - ImGui::Text("Path"); ImGui::NextColumn(); - ImGui::Columns(1); - ImGui::Separator(); - ImGui::EndChild(); - ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); - ImGui::Columns(3); - for (int i = 0; i < 10; i++) - { - ImGui::Text("%04d", i); ImGui::NextColumn(); - ImGui::Text("Foobar"); ImGui::NextColumn(); - ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); - } - ImGui::Columns(1); - ImGui::EndChild(); - ImGui::TreePop(); - } - */ - + IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling"); if (ImGui::TreeNode("Horizontal Scrolling")) { ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); - ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar); + ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); + ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); ImGui::Columns(10); + + // Also demonstrate using clipper for large vertical lists int ITEMS_COUNT = 2000; - ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list + ImGuiListClipper clipper; + clipper.Begin(ITEMS_COUNT); while (clipper.Step()) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) @@ -2868,6 +5682,7 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Columns (legacy API)/Tree"); if (ImGui::TreeNode("Tree")) { ImGui::Columns(2, "tree", true); @@ -2904,91 +5719,140 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } - if (disable_indent) - ImGui::PopStyleVar(); - ImGui::PopID(); + ImGui::TreePop(); } -static void ShowDemoWindowMisc() +static void ShowDemoWindowInputs() { - if (ImGui::CollapsingHeader("Filtering")) - { - // Helper class to easy setup a text filter. - // You may want to implement a more feature-full filtering scheme in your own application. - static ImGuiTextFilter filter; - ImGui::Text("Filter usage:\n" - " \"\" display all lines\n" - " \"xxx\" display lines containing \"xxx\"\n" - " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); - filter.Draw(); - const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; - for (int i = 0; i < IM_ARRAYSIZE(lines); i++) - if (filter.PassFilter(lines[i])) - ImGui::BulletText("%s", lines[i]); - } - - if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) + IMGUI_DEMO_MARKER("Inputs & Focus"); + if (ImGui::CollapsingHeader("Inputs & Focus")) { ImGuiIO& io = ImGui::GetIO(); - // Display ImGuiIO output flags - ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); - ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); - ImGui::Text("WantTextInput: %d", io.WantTextInput); - ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); - ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); - - // Display Keyboard/Mouse state - if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) + // Display inputs submitted to ImGuiIO + IMGUI_DEMO_MARKER("Inputs & Focus/Inputs"); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode("Inputs")) { + HelpMarker( + "This is a simplified view. See more detailed input state:\n" + "- in 'Tools->Metrics/Debugger->Inputs'.\n" + "- in 'Tools->Debug Log->IO'."); if (ImGui::IsMousePosValid()) ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse pos: "); ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse down:"); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); - ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } - ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } - ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. + // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; + ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + ImGuiKey start_key = (ImGuiKey)0; +#endif + ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } - ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } - ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } + ImGui::TreePop(); + } - ImGui::Button("Hovering me sets the\nkeyboard capture flag"); - if (ImGui::IsItemHovered()) - ImGui::CaptureKeyboardFromApp(true); - ImGui::SameLine(); - ImGui::Button("Holding me clears the\nthe keyboard capture flag"); - if (ImGui::IsItemActive()) - ImGui::CaptureKeyboardFromApp(false); + // Display ImGuiIO output flags + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs"); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode("Outputs")) + { + HelpMarker( + "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " + "to instruct your application of how to route inputs. Typically, when a value is true, it means " + "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" + "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " + "and underlying application should ignore mouse inputs (in practice there are many and more subtle " + "rules leading to how those flags are set)."); + ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); + ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + ImGui::Text("io.WantTextInput: %d", io.WantTextInput); + ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos); + ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible); + + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override"); + if (ImGui::TreeNode("WantCapture override")) + { + HelpMarker( + "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering and true when clicking."); + static int capture_override_mouse = -1; + static int capture_override_keyboard = -1; + const char* capture_override_desc[] = { "None", "Set to false", "Set to true" }; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); + ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); + ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); + + ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item + if (ImGui::IsItemHovered() && capture_override_mouse != -1) + ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1); + if (ImGui::IsItemHovered() && capture_override_keyboard != -1) + ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1); + + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // Display mouse cursors + IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); + if (ImGui::TreeNode("Mouse Cursors")) + { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); + ImGuiMouseCursor current = ImGui::GetMouseCursor(); + ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); + ImGui::BeginDisabled(true); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); + ImGui::EndDisabled(); + + ImGui::Text("Hover to see mouse cursors:"); + ImGui::SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " + "otherwise your backend needs to handle it."); + for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered()) + ImGui::SetMouseCursor(i); + } ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing"); if (ImGui::TreeNode("Tabbing")) { ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); - static char buf[32] = "dummy"; + static char buf[32] = "hello"; ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); - ImGui::PushAllowKeyboardFocus(false); + ImGui::PushTabStop(false); ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); - //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); - ImGui::PopAllowKeyboardFocus(); + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); + ImGui::PopTabStop(); ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code"); if (ImGui::TreeNode("Focus from code")) { bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); @@ -3005,11 +5869,12 @@ static void ShowDemoWindowMisc() ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 2; - ImGui::PushAllowKeyboardFocus(false); + ImGui::PushTabStop(false); if (focus_3) ImGui::SetKeyboardFocusHere(); ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 3; - ImGui::PopAllowKeyboardFocus(); + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); + ImGui::PopTabStop(); if (has_focus) ImGui::Text("Item with focus: %d", has_focus); @@ -3029,42 +5894,32 @@ static void ShowDemoWindowMisc() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Inputs & Focus/Dragging"); if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); for (int button = 0; button < 3; button++) - ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d", - button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f)); + { + ImGui::Text("IsMouseDragging(%d):", button); + ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); + ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); + ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); + } ImGui::Button("Drag Me"); if (ImGui::IsItemActive()) ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor - // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold) - // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta() + // Drag operations gets "unlocked" when the mouse has moved past a certain threshold + // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); ImVec2 mouse_delta = io.MouseDelta; - ImGui::Text("GetMouseDragDelta(0):\n w/ default threshold: (%.1f, %.1f),\n w/ zero threshold: (%.1f, %.1f)\nMouseDelta: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y, value_raw.x, value_raw.y, mouse_delta.x, mouse_delta.y); - ImGui::TreePop(); - } - - if (ImGui::TreeNode("Mouse cursors")) - { - const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand" }; - IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); - - ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); - ImGui::Text("Hover to see mouse cursors:"); - ImGui::SameLine(); HelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); - for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) - { - char label[32]; - sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); - ImGui::Bullet(); ImGui::Selectable(label, false); - if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) - ImGui::SetMouseCursor(i); - } + ImGui::Text("GetMouseDragDelta(0):"); + ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); + ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); + ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); ImGui::TreePop(); } } @@ -3082,6 +5937,7 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::End(); return; } + IMGUI_DEMO_MARKER("Tools/About Dear ImGui"); ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); ImGui::Separator(); ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); @@ -3095,11 +5951,12 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGuiStyle& style = ImGui::GetStyle(); bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); - ImGui::BeginChildFrame(ImGui::GetID("cfginfos"), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18), ImGuiWindowFlags_NoMove); + ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); + ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); if (copy_to_clipboard) { ImGui::LogToClipboard(); - ImGui::LogText("```\n"); // Back quotes will make the text appears without formatting when pasting to GitHub + ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub } ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); @@ -3109,6 +5966,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); #endif +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO"); +#endif #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); #endif @@ -3151,6 +6011,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef _MSC_VER ImGui::Text("define: _MSC_VER=%d", _MSC_VER); #endif +#ifdef _MSVC_LANG + ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG); +#endif #ifdef __MINGW32__ ImGui::Text("define: __MINGW32__"); #endif @@ -3162,6 +6025,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #endif #ifdef __clang_version__ ImGui::Text("define: __clang_version__=%s", __clang_version__); +#endif +#ifdef __EMSCRIPTEN__ + ImGui::Text("define: __EMSCRIPTEN__"); #endif ImGui::Separator(); ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); @@ -3178,7 +6044,7 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); - if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); + if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); @@ -3210,31 +6076,16 @@ void ImGui::ShowAboutWindow(bool* p_open) //----------------------------------------------------------------------------- // [SECTION] Style Editor / ShowStyleEditor() //----------------------------------------------------------------------------- -// - ShowStyleSelector() // - ShowFontSelector() +// - ShowStyleSelector() // - ShowStyleEditor() //----------------------------------------------------------------------------- -// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. -// Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally. -bool ImGui::ShowStyleSelector(const char* label) -{ - static int style_idx = -1; - if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) - { - switch (style_idx) - { - case 0: ImGui::StyleColorsClassic(); break; - case 1: ImGui::StyleColorsDark(); break; - case 2: ImGui::StyleColorsLight(); break; - } - return true; - } - return false; -} +// Forward declare ShowFontAtlas() which isn't worth putting in public API yet +namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } // Demo helper function to select among loaded fonts. -// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. void ImGui::ShowFontSelector(const char* label) { ImGuiIO& io = ImGui::GetIO(); @@ -3255,13 +6106,34 @@ void ImGui::ShowFontSelector(const char* label) HelpMarker( "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" - "- Read FAQ and docs/FONTS.txt for more details.\n" + "- Read FAQ and docs/FONTS.md for more details.\n" "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); } +// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +// Here we use the simplified Combo() api that packs items into a single literal string. +// Useful for quick combo boxes where the choices are known locally. +bool ImGui::ShowStyleSelector(const char* label) +{ + static int style_idx = -1; + if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0")) + { + switch (style_idx) + { + case 0: ImGui::StyleColorsDark(); break; + case 1: ImGui::StyleColorsLight(); break; + case 2: ImGui::StyleColorsClassic(); break; + } + return true; + } + return false; +} + void ImGui::ShowStyleEditor(ImGuiStyle* ref) { - // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference) + IMGUI_DEMO_MARKER("Tools/Style Editor"); + // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + // (without a reference style pointer, we will use one compared locally as a reference) ImGuiStyle& style = ImGui::GetStyle(); static ImGuiStyle ref_saved_style; @@ -3279,14 +6151,14 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ref_saved_style = style; ImGui::ShowFontSelector("Fonts##Selector"); - // Simplified Settings + // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding - { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; } + { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } ImGui::SameLine(); - { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; } + { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } ImGui::SameLine(); - { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; } + { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } // Save/Revert button if (ImGui::Button("Save Ref")) @@ -3295,7 +6167,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::Button("Revert Ref")) style = *ref; ImGui::SameLine(); - HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere."); + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " + "Use \"Export\" below to save them somewhere."); ImGui::Separator(); @@ -3303,22 +6177,25 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { if (ImGui::BeginTabItem("Sizes")) { - ImGui::Text("Main"); + ImGui::SeparatorText("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); - ImGui::Text("Borders"); + + ImGui::SeparatorText("Borders"); ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::Text("Rounding"); + + ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); @@ -3326,16 +6203,24 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); - ImGui::Text("Alignment"); + + ImGui::SeparatorText("Widgets"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) style.WindowMenuButtonPosition = window_menu_button_position - 1; ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); - ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); - ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); - ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); - ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%0.f"); + ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + + ImGui::SeparatorText("Misc"); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); ImGui::EndTabItem(); } @@ -3355,7 +6240,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) const ImVec4& col = style.Colors[i]; const char* name = ImGui::GetStyleColorName(i); if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) - ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, + name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); } ImGui::LogFinish(); } @@ -3366,10 +6252,13 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) filter.Draw("Filter colors", ImGui::GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); - ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); - ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::SameLine(); - HelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu."); + if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); + if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); + if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + HelpMarker( + "In the color list:\n" + "Left-click on color square to open color picker,\n" + "Right-click to open edit options menu."); ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); ImGui::PushItemWidth(-160); @@ -3382,105 +6271,43 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) { - // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. - // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient! - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; + // Tips: in a real user application, you may want to merge and use an icon font into the main font, + // so instead of "Save"/"Revert" you'd use icons! + // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } } ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); - ImGui::TextUnformatted(name); - ImGui::PopID(); - } - ImGui::PopItemWidth(); - ImGui::EndChild(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Fonts")) - { - ImGuiIO& io = ImGui::GetIO(); - ImFontAtlas* atlas = io.Fonts; - HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading."); - ImGui::PushItemWidth(120); - for (int i = 0; i < atlas->Fonts.Size; i++) - { - ImFont* font = atlas->Fonts[i]; - ImGui::PushID(font); - bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } - if (font_details_opened) - { - ImGui::PushFont(font); - ImGui::Text("The quick brown fox jumps over the lazy dog"); - ImGui::PopFont(); - ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font - ImGui::SameLine(); HelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); - ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); - ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); - ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); - ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); - const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface); - ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt); - for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) - if (const ImFontConfig* cfg = &font->ConfigData[config_i]) - ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); - if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) - { - // Display all glyphs of the fonts in separate pages of 256 characters - for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) - { - int count = 0; - for (unsigned int n = 0; n < 256; n++) - count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; - if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) - { - float cell_size = font->FontSize * 1; - float cell_spacing = style.ItemSpacing.y; - ImVec2 base_pos = ImGui::GetCursorScreenPos(); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - for (unsigned int n = 0; n < 256; n++) - { - ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); - ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); - draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); - if (glyph) - font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. - if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) - { - ImGui::BeginTooltip(); - ImGui::Text("Codepoint: U+%04X", base + n); - ImGui::Separator(); - ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); - ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); - ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); - ImGui::EndTooltip(); - } - } - ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); - ImGui::TreePop(); - } - } - ImGui::TreePop(); - } - ImGui::TreePop(); - } - ImGui::PopID(); - } - if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) - { - ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); - ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); - ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); - ImGui::TreePop(); + ImGui::TextUnformatted(name); + ImGui::PopID(); } + ImGui::PopItemWidth(); + ImGui::EndChild(); - HelpMarker("Those are old settings provided for convenience.\nHowever, the _correct_ way of scaling your UI is currently to reload your font at the designed size, rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure."); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Fonts")) + { + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); + ImGui::ShowFontAtlas(atlas); + + // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); static float window_scale = 1.0f; - if (ImGui::DragFloat("window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); + if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); @@ -3488,12 +6315,64 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::BeginTabItem("Rendering")) { - ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); + ImGui::SameLine(); + HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + + ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); + ImGui::SameLine(); + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); + ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); - ImGui::PushItemWidth(100); - ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f); + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + + // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. + ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); + const bool show_samples = ImGui::IsItemActive(); + if (show_samples) + ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); + if (show_samples && ImGui::BeginTooltip()) + { + ImGui::TextUnformatted("(R = radius, N = number of segments)"); + ImGui::Spacing(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x; + for (int n = 0; n < 8; n++) + { + const float RAD_MIN = 5.0f; + const float RAD_MAX = 70.0f; + const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f); + + ImGui::BeginGroup(); + + ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); + + const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f); + const float offset_x = floorf(canvas_width * 0.5f); + const float offset_y = floorf(RAD_MAX); + + const ImVec2 p1 = ImGui::GetCursorScreenPos(); + draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + + /* + const ImVec2 p2 = ImGui::GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + */ + + ImGui::EndGroup(); + ImGui::SameLine(); + } + ImGui::EndTooltip(); + } + ImGui::SameLine(); + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); + ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); ImGui::PopItemWidth(); ImGui::EndTabItem(); @@ -3505,6 +6384,40 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::PopItemWidth(); } +//----------------------------------------------------------------------------- +// [SECTION] User Guide / ShowUserGuide() +//----------------------------------------------------------------------------- + +void ImGui::ShowUserGuide() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui::BulletText("Double-click on title bar to collapse window."); + ImGui::BulletText( + "Click and drag on lower corner to resize window\n" + "(double-click to auto fit window to its contents)."); + ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + ImGui::BulletText("CTRL+Tab to select a window."); + if (io.FontAllowUserScaling) + ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); + ImGui::BulletText("While inputing text:\n"); + ImGui::Indent(); + ImGui::BulletText("CTRL+Left/Right to word jump."); + ImGui::BulletText("CTRL+A or double-click to select all."); + ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); + ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("ESCAPE to revert."); + ImGui::Unindent(); + ImGui::BulletText("With keyboard navigation enabled:"); + ImGui::Indent(); + ImGui::BulletText("Arrow keys to navigate."); + ImGui::BulletText("Space to activate a widget."); + ImGui::BulletText("Return to input text into a widget."); + ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); + ImGui::BulletText("Alt to jump to the menu layer of a window."); + ImGui::Unindent(); +} + //----------------------------------------------------------------------------- // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() //----------------------------------------------------------------------------- @@ -3514,7 +6427,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // Demonstrate creating a "main" fullscreen menu bar and populating it. // Note the difference between BeginMainMenuBar() and BeginMenuBar(): -// - BeginMenuBar() = menu-bar inside current window we Begin()-ed into (the window needs the ImGuiWindowFlags_MenuBar flag) +// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. static void ShowExampleAppMainMenuBar() { @@ -3539,10 +6452,12 @@ static void ShowExampleAppMainMenuBar() } } -// Note that shortcuts are currently provided for display only (future version will add flags to BeginMenu to process shortcuts) +// Note that shortcuts are currently provided for display only +// (future version will add explicit flags to BeginMenu() to request processing shortcuts) static void ShowExampleMenuFile() { - ImGui::MenuItem("(dummy menu)", NULL, false, false); + IMGUI_DEMO_MARKER("Examples/Menu"); + ImGui::MenuItem("(demo menu)", NULL, false, false); if (ImGui::MenuItem("New")) {} if (ImGui::MenuItem("Open", "Ctrl+O")) {} if (ImGui::BeginMenu("Open Recent")) @@ -3565,7 +6480,9 @@ static void ShowExampleMenuFile() } if (ImGui::MenuItem("Save", "Ctrl+S")) {} if (ImGui::MenuItem("Save As..")) {} + ImGui::Separator(); + IMGUI_DEMO_MARKER("Examples/Menu/Options"); if (ImGui::BeginMenu("Options")) { static bool enabled = true; @@ -3576,13 +6493,13 @@ static void ShowExampleMenuFile() ImGui::EndChild(); static float f = 0.5f; static int n = 0; - static bool b = true; ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); ImGui::InputFloat("Input", &f, 0.1f); ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); - ImGui::Checkbox("Check", &b); ImGui::EndMenu(); } + + IMGUI_DEMO_MARKER("Examples/Menu/Colors"); if (ImGui::BeginMenu("Colors")) { float sz = ImGui::GetTextLineHeight(); @@ -3590,18 +6507,31 @@ static void ShowExampleMenuFile() { const char* name = ImGui::GetStyleColorName((ImGuiCol)i); ImVec2 p = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x+sz, p.y+sz), ImGui::GetColorU32((ImGuiCol)i)); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); ImGui::Dummy(ImVec2(sz, sz)); ImGui::SameLine(); ImGui::MenuItem(name); } ImGui::EndMenu(); } + + // Here we demonstrate appending again to the "Options" menu (which we already created above) + // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + // In a real code-base using it would make senses to use this feature from very different code locations. + if (ImGui::BeginMenu("Options")) // <-- Append! + { + IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu"); + static bool b = true; + ImGui::Checkbox("SomeOption", &b); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Disabled", false)) // Disabled { IM_ASSERT(0); } if (ImGui::MenuItem("Checked", NULL, true)) {} + ImGui::Separator(); if (ImGui::MenuItem("Quit", "Alt+F4")) {} } @@ -3610,7 +6540,7 @@ static void ShowExampleMenuFile() //----------------------------------------------------------------------------- // Demonstrate creating a simple console window, with scrolling, filtering, completion and history. -// For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. +// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. struct ExampleAppConsole { char InputBuf[256]; @@ -3624,13 +6554,16 @@ struct ExampleAppConsole ExampleAppConsole() { + IMGUI_DEMO_MARKER("Examples/Console"); ClearLog(); memset(InputBuf, 0, sizeof(InputBuf)); HistoryPos = -1; + + // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. Commands.push_back("HELP"); Commands.push_back("HISTORY"); Commands.push_back("CLEAR"); - Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches. + Commands.push_back("CLASSIFY"); AutoScroll = true; ScrollToBottom = false; AddLog("Welcome to Dear ImGui!"); @@ -3643,10 +6576,10 @@ struct ExampleAppConsole } // Portable helpers - static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } - static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } - static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); } - static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } + static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } + static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } + static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } + static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } void ClearLog() { @@ -3669,14 +6602,15 @@ struct ExampleAppConsole void Draw(const char* title, bool* p_open) { - ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open)) { ImGui::End(); return; } - // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + // So e.g. IsItemHovered() will return true when hovering the title bar. // Here we create a context menu only available from the title bar. if (ImGui::BeginPopupContextItem()) { @@ -3685,14 +6619,19 @@ struct ExampleAppConsole ImGui::EndPopup(); } - ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); - ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); + ImGui::TextWrapped( + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " + "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); + ImGui::TextWrapped("Enter 'HELP' for help."); // TODO: display items starting from the bottom - if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); - if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); - if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); + if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Clear")) { ClearLog(); } + ImGui::SameLine(); bool copy_to_clipboard = ImGui::SmallButton("Copy"); //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } @@ -3712,56 +6651,79 @@ struct ExampleAppConsole Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); ImGui::Separator(); - const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText - if (ImGui::BeginPopupContextWindow()) + // Reserve enough left-over height for 1 separator + 1 input text + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar)) { - if (ImGui::Selectable("Clear")) ClearLog(); - ImGui::EndPopup(); - } + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } - // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); - // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. - // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. - // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: - // ImGuiListClipper clipper(Items.Size); - // while (clipper.Step()) - // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - // However, note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. - // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, - // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! - // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing - if (copy_to_clipboard) - ImGui::LogToClipboard(); - for (int i = 0; i < Items.Size; i++) - { - const char* item = Items[i]; - if (!Filter.PassFilter(item)) - continue; + // Display every line as a separate entry so we can change their color or add custom widgets. + // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + // to only process visible items. The clipper will automatically measure the height of your first item and then + // "seek" to display only items in the visible area. + // To use the clipper we can replace your standard loop: + // for (int i = 0; i < Items.Size; i++) + // With: + // ImGuiListClipper clipper; + // clipper.Begin(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // - That your items are evenly spaced (same height) + // - That you have cheap random access to your elements (you can access them given their index, + // without processing all the ones before) + // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + // We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage + // to improve this example code! + // If your items are of variable height: + // - Split them into same height items would be simpler and facilitate random-seeking into your list. + // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing + if (copy_to_clipboard) + ImGui::LogToClipboard(); + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; - // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.) - bool pop_color = false; - if (strstr(item, "[error]")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); pop_color = true; } - else if (strncmp(item, "# ", 2) == 0) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f)); pop_color = true; } - ImGui::TextUnformatted(item); - if (pop_color) - ImGui::PopStyleColor(); - } - if (copy_to_clipboard) - ImGui::LogFinish(); + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(item); + if (has_color) + ImGui::PopStyleColor(); + } + if (copy_to_clipboard) + ImGui::LogFinish(); - if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) - ImGui::SetScrollHereY(1.0f); - ScrollToBottom = false; + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + // Using a scrollbar or mouse-wheel will take away from the bottom edge. + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; - ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + } ImGui::EndChild(); ImGui::Separator(); // Command-line bool reclaim_focus = false; - if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) { char* s = InputBuf; Strtrim(s); @@ -3783,9 +6745,10 @@ struct ExampleAppConsole { AddLog("# %s\n", command_line); - // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal. + // Insert into history. First find match and delete it so it can be pushed to the back. + // This isn't trying to be smart or optimal. HistoryPos = -1; - for (int i = History.Size-1; i >= 0; i--) + for (int i = History.Size - 1; i >= 0; i--) if (Stricmp(History[i], command_line) == 0) { free(History[i]); @@ -3816,11 +6779,12 @@ struct ExampleAppConsole AddLog("Unknown command: '%s'\n", command_line); } - // On commad input, we scroll to bottom even if AutoScroll==false + // On command input, we scroll to bottom even if AutoScroll==false ScrollToBottom = true; } - static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks + // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) { ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; return console->TextEditCallback(data); @@ -3849,24 +6813,25 @@ struct ExampleAppConsole // Build a list of candidates ImVector candidates; for (int i = 0; i < Commands.Size; i++) - if (Strnicmp(Commands[i], word_start, (int)(word_end-word_start)) == 0) + if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) candidates.push_back(Commands[i]); if (candidates.Size == 0) { // No match - AddLog("No match for \"%.*s\"!\n", (int)(word_end-word_start), word_start); + AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); } else if (candidates.Size == 1) { - // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing - data->DeleteChars((int)(word_start-data->Buf), (int)(word_end-word_start)); + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); data->InsertChars(data->CursorPos, candidates[0]); data->InsertChars(data->CursorPos, " "); } else { - // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY" + // Multiple matches. Complete as much as we can.. + // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. int match_len = (int)(word_end - word_start); for (;;) { @@ -3884,7 +6849,7 @@ struct ExampleAppConsole if (match_len > 0) { - data->DeleteChars((int)(word_start - data->Buf), (int)(word_end-word_start)); + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); } @@ -3945,8 +6910,8 @@ struct ExampleAppLog { ImGuiTextBuffer Buf; ImGuiTextFilter Filter; - ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines - bool AutoScroll; // Keep scrolling if already at the bottom + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool AutoScroll; // Keep scrolling if already at the bottom. ExampleAppLog() { @@ -3999,59 +6964,66 @@ struct ExampleAppLog Filter.Draw("Filter", -100.0f); ImGui::Separator(); - ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); - - if (clear) - Clear(); - if (copy) - ImGui::LogToClipboard(); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - const char* buf = Buf.begin(); - const char* buf_end = Buf.end(); - if (Filter.IsActive()) - { - // In this example we don't use the clipper when Filter is enabled. - // This is because we don't have a random access on the result on our filter. - // A real application processing logs with ten of thousands of entries may want to store the result of search/filter. - // especially if the filtering function is not trivial (e.g. reg-exp). - for (int line_no = 0; line_no < LineOffsets.Size; line_no++) - { - const char* line_start = buf + LineOffsets[line_no]; - const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; - if (Filter.PassFilter(line_start, line_end)) - ImGui::TextUnformatted(line_start, line_end); - } - } - else + if (ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { - // The simplest and easy way to display the entire buffer: - // ImGui::TextUnformatted(buf_begin, buf_end); - // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. - // Here we instead demonstrate using the clipper to only process lines that are within the visible area. - // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. - // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, - // both of which we can handle since we an array pointing to the beginning of each line of text. - // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. - // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) - ImGuiListClipper clipper; - clipper.Begin(LineOffsets.Size); - while (clipper.Step()) + if (clear) + Clear(); + if (copy) + ImGui::LogToClipboard(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + if (Filter.IsActive()) { - for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + // In this example we don't use the clipper when Filter is enabled. + // This is because we don't have random access to the result of our filter. + // A real application processing logs with ten of thousands of entries may want to store the result of + // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) { const char* line_start = buf + LineOffsets[line_no]; const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; - ImGui::TextUnformatted(line_start, line_end); + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); } } - clipper.End(); - } - ImGui::PopStyleVar(); - - if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) - ImGui::SetScrollHereY(1.0f); + else + { + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + // within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + // on your side is recommended. Using ImGuiListClipper requires + // - A) random access into your data + // - B) items all being the same height, + // both of which we can handle since we have an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display + // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + // it possible (and would be recommended if you want to search through tens of thousands of entries). + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + } + ImGui::PopStyleVar(); + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + // Using a scrollbar or mouse-wheel will take away from the bottom edge. + if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + ImGui::SetScrollHereY(1.0f); + } ImGui::EndChild(); ImGui::End(); } @@ -4067,15 +7039,18 @@ static void ShowExampleAppLog(bool* p_open) // Most of the contents of the window will be added by the log.Draw() call. ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); ImGui::Begin("Example: Log", p_open); + IMGUI_DEMO_MARKER("Examples/Log"); if (ImGui::SmallButton("[Debug] Add 5 entries")) { static int counter = 0; + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; for (int n = 0; n < 5; n++) { - const char* categories[3] = { "info", "warn", "error" }; - const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + const char* category = categories[counter % IM_ARRAYSIZE(categories)]; + const char* word = words[counter % IM_ARRAYSIZE(words)]; log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", - ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); + ImGui::GetFrameCount(), category, ImGui::GetTime(), word); counter++; } } @@ -4095,53 +7070,59 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) { + IMGUI_DEMO_MARKER("Examples/Simple layout"); if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Close")) *p_open = false; + if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; } ImGui::EndMenu(); } ImGui::EndMenuBar(); } - // left + // Left static int selected = 0; - ImGui::BeginChild("left pane", ImVec2(150, 0), true); - for (int i = 0; i < 100; i++) { - char label[128]; - sprintf(label, "MyObject %d", i); - if (ImGui::Selectable(label, selected == i)) - selected = i; + ImGui::BeginChild("left pane", ImVec2(150, 0), true); + for (int i = 0; i < 100; i++) + { + // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav + char label[128]; + sprintf(label, "MyObject %d", i); + if (ImGui::Selectable(label, selected == i)) + selected = i; + } + ImGui::EndChild(); } - ImGui::EndChild(); ImGui::SameLine(); - // right - ImGui::BeginGroup(); + // Right + { + ImGui::BeginGroup(); ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us - ImGui::Text("MyObject: %d", selected); - ImGui::Separator(); - if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + ImGui::Text("MyObject: %d", selected); + ImGui::Separator(); + if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Description")) { - if (ImGui::BeginTabItem("Description")) - { - ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Details")) - { - ImGui::Text("ID: 0123456789"); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("Details")) + { + ImGui::Text("ID: 0123456789"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } ImGui::EndChild(); if (ImGui::Button("Revert")) {} ImGui::SameLine(); if (ImGui::Button("Save")) {} - ImGui::EndGroup(); + ImGui::EndGroup(); + } } ImGui::End(); } @@ -4150,70 +7131,81 @@ static void ShowExampleAppLayout(bool* p_open) // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() //----------------------------------------------------------------------------- +static void ShowPlaceholderObject(const char* prefix, int uid) +{ + // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::PushID(uid); + + // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high. + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + ImGui::TableSetColumnIndex(1); + ImGui::Text("my sailor is rich"); + + if (node_open) + { + static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f }; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); // Use field index as identifier. + if (i < 2) + { + ShowPlaceholderObject("Child", 424242); + } + else + { + // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; + ImGui::TreeNodeEx("Field", flags, "Field_%d", i); + + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-FLT_MIN); + if (i >= 5) + ImGui::InputFloat("##value", &placeholder_members[i], 1.0f); + else + ImGui::DragFloat("##value", &placeholder_members[i], 0.01f); + ImGui::NextColumn(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + ImGui::PopID(); +} + // Demonstrate create a simple property editor. static void ShowExampleAppPropertyEditor(bool* p_open) { - ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Property editor", p_open)) { ImGui::End(); return; } + IMGUI_DEMO_MARKER("Examples/Property Editor"); - HelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API."); - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2,2)); - ImGui::Columns(2); - ImGui::Separator(); + HelpMarker( + "This example shows how you may implement a property editor using two columns.\n" + "All objects/fields data are dummies here.\n" + "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" + "your cursor horizontally instead of using the Columns() API."); - struct funcs + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable)) { - static void ShowDummyObject(const char* prefix, int uid) + // Iterate placeholder objects (all the same data) + for (int obj_i = 0; obj_i < 4; obj_i++) { - ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. - ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. - bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); - ImGui::NextColumn(); - ImGui::AlignTextToFramePadding(); - ImGui::Text("my sailor is rich"); - ImGui::NextColumn(); - if (node_open) - { - static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; - for (int i = 0; i < 8; i++) - { - ImGui::PushID(i); // Use field index as identifier. - if (i < 2) - { - ShowDummyObject("Child", 424242); - } - else - { - // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) - ImGui::AlignTextToFramePadding(); - ImGui::TreeNodeEx("Field", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet, "Field_%d", i); - ImGui::NextColumn(); - ImGui::SetNextItemWidth(-1); - if (i >= 5) - ImGui::InputFloat("##value", &dummy_members[i], 1.0f); - else - ImGui::DragFloat("##value", &dummy_members[i], 0.01f); - ImGui::NextColumn(); - } - ImGui::PopID(); - } - ImGui::TreePop(); - } - ImGui::PopID(); + ShowPlaceholderObject("Object", obj_i); + //ImGui::Separator(); } - }; - - // Iterate dummy objects with dummy members (all the same data) - for (int obj_i = 0; obj_i < 3; obj_i++) - funcs::ShowDummyObject("Object", obj_i); - - ImGui::Columns(1); - ImGui::Separator(); + ImGui::EndTable(); + } ImGui::PopStyleVar(); ImGui::End(); } @@ -4225,25 +7217,29 @@ static void ShowExampleAppPropertyEditor(bool* p_open) // Demonstrate/test rendering huge amount of text, and the incidence of clipping. static void ShowExampleAppLongText(bool* p_open) { - ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Long text display", p_open)) { ImGui::End(); return; } + IMGUI_DEMO_MARKER("Examples/Long text display"); static int test_type = 0; static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Combo("Test type", &test_type, + "Single call to TextUnformatted()\0" + "Multiple calls to Text(), clipped\0" + "Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); if (ImGui::Button("Add 1000 lines")) { for (int i = 0; i < 1000; i++) - log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i); + log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); lines += 1000; } ImGui::BeginChild("Log"); @@ -4256,8 +7252,9 @@ static void ShowExampleAppLongText(bool* p_open) case 1: { // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); - ImGuiListClipper clipper(lines); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGuiListClipper clipper; + clipper.Begin(lines); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); @@ -4266,7 +7263,7 @@ static void ShowExampleAppLongText(bool* p_open) } case 2: // Multiple calls to Text(), not clipped (slow) - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); for (int i = 0; i < lines; i++) ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); ImGui::PopStyleVar(); @@ -4288,9 +7285,13 @@ static void ShowExampleAppAutoResize(bool* p_open) ImGui::End(); return; } + IMGUI_DEMO_MARKER("Examples/Auto-resizing window"); static int lines = 10; - ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); + ImGui::TextUnformatted( + "Window will resize every-frame to the size of its content.\n" + "Note that you probably don't want to query the window size to\n" + "output your content because that would create a feedback loop."); ImGui::SliderInt("Number of lines", &lines, 1, 20); for (int i = 0; i < lines; i++) ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally @@ -4302,72 +7303,122 @@ static void ShowExampleAppAutoResize(bool* p_open) //----------------------------------------------------------------------------- // Demonstrate creating a window with custom resize constraints. +// Note that size constraints currently don't work on a docked window (when in 'docking' branch) static void ShowExampleAppConstrainedResize(bool* p_open) { - struct CustomConstraints // Helper functions to demonstrate programmatic constraints + struct CustomConstraints { - static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = (data->DesiredSize.x > data->DesiredSize.y ? data->DesiredSize.x : data->DesiredSize.y); } - static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + // Helper functions to demonstrate programmatic constraints + // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. + static void AspectRatio(ImGuiSizeCallbackData* data) { float aspect_ratio = *(float*)data->UserData; data->DesiredSize.x = IM_MAX(data->CurrentSize.x, data->CurrentSize.y); data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio); } + static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->CurrentSize.x, data->CurrentSize.y); } + static void Step(ImGuiSizeCallbackData* data) { float step = *(float*)data->UserData; data->DesiredSize = ImVec2((int)(data->CurrentSize.x / step + 0.5f) * step, (int)(data->CurrentSize.y / step + 0.5f) * step); } }; + const char* test_desc[] = + { + "Between 100x100 and 500x500", + "At least 100x100", + "Resize vertical only", + "Resize horizontal only", + "Width Between 400 and 500", + "Custom: Aspect Ratio 16:9", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + }; + + // Options static bool auto_resize = false; - static int type = 0; + static bool window_padding = true; + static int type = 5; // Aspect Ratio static int display_lines = 10; - if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only - if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only - if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 - if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 - if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 - if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square - if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step - - ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; - if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) - { - const char* desc[] = - { - "Resize vertical only", - "Resize horizontal only", - "Width > 100, Height > 100", - "Width 400-500", - "Height 400-500", - "Custom: Always Square", - "Custom: Fixed Steps (100)", - }; - if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); - if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); - if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } - ImGui::SetNextItemWidth(200); - ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); - ImGui::SetNextItemWidth(200); - ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); - ImGui::Checkbox("Auto-resize", &auto_resize); - for (int i = 0; i < display_lines; i++) - ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); + + // Submit constraint + float aspect_ratio = 16.0f / 9.0f; + float fixed_step = 100.0f; + if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500 + if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500 + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step + + // Submit window + if (!window_padding) + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; + const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags); + if (!window_padding) + ImGui::PopStyleVar(); + if (window_open) + { + IMGUI_DEMO_MARKER("Examples/Constrained Resizing window"); + if (ImGui::GetIO().KeyShift) + { + // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture. + ImVec2 avail_size = ImGui::GetContentRegionAvail(); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size); + ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10)); + ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y); + } + else + { + ImGui::Text("(Hold SHIFT to display a dummy viewport)"); + if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); + if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); + if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); + ImGui::Checkbox("Auto-resize", &auto_resize); + ImGui::Checkbox("Window padding", &window_padding); + for (int i = 0; i < display_lines; i++) + ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); + } } ImGui::End(); } //----------------------------------------------------------------------------- -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() //----------------------------------------------------------------------------- -// Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. +// Demonstrate creating a simple static window with no decoration +// + a context-menu to choose which corner of the screen to use. static void ShowExampleAppSimpleOverlay(bool* p_open) { - const float DISTANCE = 10.0f; - static int corner = 0; + static int location = 0; ImGuiIO& io = ImGui::GetIO(); - if (corner != -1) + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; + if (location >= 0) { - ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); - ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); + const float PAD = 10.0f; + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! + ImVec2 work_size = viewport->WorkSize; + ImVec2 window_pos, window_pos_pivot; + window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD); + window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD); + window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f; + window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f; ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + window_flags |= ImGuiWindowFlags_NoMove; + } + else if (location == -2) + { + // Center window + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + window_flags |= ImGuiWindowFlags_NoMove; } ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background - if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) + if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) { - ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + IMGUI_DEMO_MARKER("Examples/Simple Overlay"); + ImGui::Text("Simple overlay\n" "(right-click to change position)"); ImGui::Separator(); if (ImGui::IsMousePosValid()) ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); @@ -4375,11 +7426,12 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::Text("Mouse Position: "); if (ImGui::BeginPopupContextWindow()) { - if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; - if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; - if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; - if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; - if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1; + if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2; + if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0; + if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1; + if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2; + if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3; if (p_open && ImGui::MenuItem("Close")) *p_open = false; ImGui::EndPopup(); } @@ -4387,24 +7439,65 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::End(); } +//----------------------------------------------------------------------------- +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window covering the entire screen/viewport +static void ShowExampleAppFullscreen(bool* p_open) +{ + static bool use_work_area = true; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; + + // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) + // Based on your use case you may want one or the other. + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); + ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); + + if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) + { + ImGui::Checkbox("Use work area instead of main area", &use_work_area); + ImGui::SameLine(); + HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); + + ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); + ImGui::Unindent(); + + if (p_open && ImGui::Button("Close this window")) + *p_open = false; + } + ImGui::End(); +} + //----------------------------------------------------------------------------- // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() //----------------------------------------------------------------------------- -// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. -// This apply to all regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details. +// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation. +// This applies to all regular items as well. +// Read FAQ section "How can I have multiple widgets with the same label?" for details. static void ShowExampleAppWindowTitles(bool*) { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImVec2 base_pos = viewport->Pos; + // By default, Windows are uniquely identified by their title. // You can use the "##" and "###" markers to manipulate the display/ID. // Using "##" to display same title but have unique identifier. - ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##1"); + IMGUI_DEMO_MARKER("Examples/Manipulating window titles"); ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); ImGui::End(); - ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##2"); ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); ImGui::End(); @@ -4412,7 +7505,7 @@ static void ShowExampleAppWindowTitles(bool*) // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" char buf[128]; sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); - ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); ImGui::Begin(buf); ImGui::Text("This window has a changing title."); ImGui::End(); @@ -4430,112 +7523,209 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::End(); return; } + IMGUI_DEMO_MARKER("Examples/Custom Rendering"); - // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc. - // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4. - // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types) - // In this example we are not using the maths operators! - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! if (ImGui::BeginTabBar("##TabBar")) { - // Primitives if (ImGui::BeginTabItem("Primitives")) { + ImGui::PushItemWidth(-ImGui::GetFontSize() * 15); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + // Draw gradients + // (note that those are currently exacerbating our sRGB/Linear issues) + // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + ImGui::Text("Gradients"); + ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); + ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient1", gradient_size); + } + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); + ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient2", gradient_size); + } + + // Draw a bunch of primitives + ImGui::Text("All primitives"); static float sz = 36.0f; static float thickness = 3.0f; + static int ngon_sides = 6; + static bool circle_segments_override = false; + static int circle_segments_override_v = 12; + static bool curve_segments_override = false; + static int curve_segments_override_v = 8; static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); - ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); + ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); + ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); + ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40); ImGui::ColorEdit4("Color", &colf.x); + const ImVec2 p = ImGui::GetCursorScreenPos(); const ImU32 col = ImColor(colf); - float x = p.x + 4.0f, y = p.y + 4.0f; - float spacing = 10.0f; - ImDrawCornerFlags corners_none = 0; - ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; - ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; + const float spacing = 10.0f; + const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight; + const float rounding = sz / 5.0f; + const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; + const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; + float x = p.x + 4.0f; + float y = p.y + 4.0f; for (int n = 0; n < 2; n++) { // First line uses a thickness of 1.0f, second line uses the configurable thickness float th = (n == 0) ? 1.0f : thickness; - draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 6, th); x += sz + spacing; // Hexagon - draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 20, th); x += sz + spacing; // Circle - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners - draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th); x += sz + spacing; // Triangle - draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th); x += sz*0.4f + spacing; // Thin triangle - draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line - draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th); + draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon + draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle + //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line + + // Quadratic Bezier Curve (3 control points) + ImVec2 cp3[3] = { ImVec2(x, y + sz * 0.6f), ImVec2(x + sz * 0.5f, y - sz * 0.4f), ImVec2(x + sz, y + sz) }; + draw_list->AddBezierQuadratic(cp3[0], cp3[1], cp3[2], col, th, curve_segments); x += sz + spacing; + + // Cubic Bezier Curve (4 control points) + ImVec2 cp4[4] = { ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz) }; + draw_list->AddBezierCubic(cp4[0], cp4[1], cp4[2], cp4[3], col, th, curve_segments); + x = p.x + 4; y += sz + spacing; } - draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 6); x += sz + spacing; // Hexagon - draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 32); x += sz + spacing; // Circle - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners - draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle - draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing*2.0f; // Vertical line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) + draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon + draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle + //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); - ImGui::Dummy(ImVec2((sz + spacing) * 9.8f, (sz + spacing) * 3)); + + ImGui::Dummy(ImVec2((sz + spacing) * 10.2f, (sz + spacing) * 3.0f)); + ImGui::PopItemWidth(); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Canvas")) { static ImVector points; + static ImVec2 scrolling(0.0f, 0.0f); + static bool opt_enable_grid = true; + static bool opt_enable_context_menu = true; static bool adding_line = false; - if (ImGui::Button("Clear")) points.clear(); - if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } - ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); - - // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered() - // But you can also draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). - // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max). - ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! - ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available - if (canvas_size.x < 50.0f) canvas_size.x = 50.0f; - if (canvas_size.y < 50.0f) canvas_size.y = 50.0f; - draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); - draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); - - bool adding_preview = false; - ImGui::InvisibleButton("canvas", canvas_size); - ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); - if (adding_line) + + ImGui::Checkbox("Enable grid", &opt_enable_grid); + ImGui::Checkbox("Enable context menu", &opt_enable_context_menu); + ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); + + // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + // To use a child window instead we could use, e.g: + // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding + // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color + // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); + // ImGui::PopStyleColor(); + // ImGui::PopStyleVar(); + // [...] + // ImGui::EndChild(); + + // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available + if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; + if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; + ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); + + // Draw border and background color + ImGuiIO& io = ImGui::GetIO(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); + draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); + + // This will catch our interactions + ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); + const bool is_hovered = ImGui::IsItemHovered(); // Hovered + const bool is_active = ImGui::IsItemActive(); // Held + const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin + const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); + + // Add first and second point + if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - adding_preview = true; points.push_back(mouse_pos_in_canvas); - if (!ImGui::IsMouseDown(0)) - adding_line = adding_preview = false; + points.push_back(mouse_pos_in_canvas); + adding_line = true; } - if (ImGui::IsItemHovered()) + if (adding_line) { - if (!adding_line && ImGui::IsMouseClicked(0)) - { - points.push_back(mouse_pos_in_canvas); - adding_line = true; - } - if (ImGui::IsMouseClicked(1) && !points.empty()) - { - adding_line = adding_preview = false; - points.pop_back(); - points.pop_back(); - } + points.back() = mouse_pos_in_canvas; + if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) + adding_line = false; + } + + // Pan (we use a zero mouse threshold when there's no context menu) + // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; + if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) + { + scrolling.x += io.MouseDelta.x; + scrolling.y += io.MouseDelta.y; + } + + // Context menu (under default mouse threshold) + ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); + if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f) + ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + if (ImGui::BeginPopup("context")) + { + if (adding_line) + points.resize(points.size() - 2); + adding_line = false; + if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } + if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } + ImGui::EndPopup(); } - draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) - for (int i = 0; i < points.Size - 1; i += 2) - draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); + + // Draw grid + all lines in the canvas + draw_list->PushClipRect(canvas_p0, canvas_p1, true); + if (opt_enable_grid) + { + const float GRID_STEP = 64.0f; + for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) + draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); + for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) + draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); + } + for (int n = 0; n < points.Size; n += 2) + draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); draw_list->PopClipRect(); - if (adding_preview) - points.pop_back(); + ImGui::EndTabItem(); } @@ -4551,9 +7741,9 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImVec2 window_size = ImGui::GetWindowSize(); ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); if (draw_bg) - ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 48, 10+4); + ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); if (draw_fg) - ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 48, 10); + ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); ImGui::EndTabItem(); } @@ -4570,14 +7760,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) // Simplified structure to mimic a Document model struct MyDocument { - const char* Name; // Document title - bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) - bool OpenPrev; // Copy of Open from last update. - bool Dirty; // Set when the document has been modified - bool WantClose; // Set when the document - ImVec4 Color; // An arbitrary variable associated to the document - - MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) + const char* Name; // Document title + bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + bool WantClose; // Set when the document + ImVec4 Color; // An arbitrary variable associated to the document + + MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) { Name = name; Open = OpenPrev = open; @@ -4590,7 +7780,7 @@ struct MyDocument void DoForceClose() { Open = false; Dirty = false; } void DoSave() { Dirty = false; } - // Display dummy contents for the Document + // Display placeholder contents for the Document static void DisplayContents(MyDocument* doc) { ImGui::PushID(doc); @@ -4639,10 +7829,11 @@ struct ExampleAppDocuments }; // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. -// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed -// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. -// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar -// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. +// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +// the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +// give the impression of a flicker for one frame. // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) @@ -4664,7 +7855,8 @@ void ShowExampleAppDocuments(bool* p_open) static bool opt_reorderable = true; static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; - if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar)) + bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); + if (!window_contents_visible) { ImGui::End(); return; @@ -4693,7 +7885,8 @@ void ShowExampleAppDocuments(bool* p_open) if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) app.Documents[doc_n].DoQueueClose(); - if (ImGui::MenuItem("Exit", "Alt+F4")) {} + if (ImGui::MenuItem("Exit", "Ctrl+F4") && p_open) + *p_open = false; ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -4714,6 +7907,16 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::Separator(); + // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags. + // They have multiple effects: + // - Display a dot next to the title. + // - Tab is selected when clicking the X close button. + // - Closure is not assumed (will wait for user to stop submitting the tab). + // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty + // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. + // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. + // Submit Tab Bar and Tabs { ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); @@ -4790,19 +7993,20 @@ void ShowExampleAppDocuments(bool* p_open) { if (!ImGui::IsPopupOpen("Save?")) ImGui::OpenPopup("Save?"); - if (ImGui::BeginPopupModal("Save?")) + if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Save change to the following items?"); - ImGui::SetNextItemWidth(-1.0f); - if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) + float item_height = ImGui::GetTextLineHeightWithSpacing(); + if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) { for (int n = 0; n < close_queue.Size; n++) if (close_queue[n]->Dirty) ImGui::Text("%s", close_queue[n]->Name); - ImGui::ListBoxFooter(); + ImGui::EndChildFrame(); } - if (ImGui::Button("Yes", ImVec2(80, 0))) + ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); + if (ImGui::Button("Yes", button_size)) { for (int n = 0; n < close_queue.Size; n++) { @@ -4814,7 +8018,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("No", ImVec2(80, 0))) + if (ImGui::Button("No", button_size)) { for (int n = 0; n < close_queue.Size; n++) close_queue[n]->DoForceClose(); @@ -4822,7 +8026,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(80, 0))) + if (ImGui::Button("Cancel", button_size)) { close_queue.clear(); ImGui::CloseCurrentPopup(); @@ -4844,3 +8048,5 @@ void ImGui::ShowUserGuide() {} void ImGui::ShowStyleEditor(ImGuiStyle*) {} #endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/src/ui/imguiLib/imgui_draw.cpp b/src/ui/imguiLib/imgui_draw.cpp index 8089bbef2..0280c6e7c 100644 --- a/src/ui/imguiLib/imgui_draw.cpp +++ b/src/ui/imguiLib/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.74 +// dear imgui, v1.89.6 // (drawing and font code) /* @@ -16,7 +16,7 @@ Index of this file: // [SECTION] ImFontAtlas glyph ranges helpers // [SECTION] ImFontGlyphRangesBuilder // [SECTION] ImFont -// [SECTION] Internal Render Helpers +// [SECTION] ImGui Internal Render Helpers // [SECTION] Decompression code // [SECTION] Default font data (ProggyClean.ttf) @@ -26,51 +26,43 @@ Index of this file: #define _CRT_SECURE_NO_WARNINGS #endif -#include "imgui.h" #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE #include "imgui_internal.h" +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif #include // vsnprintf, sscanf, printf -#if !defined(alloca) -#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__) || defined(__SWITCH__) -#include // alloca (glibc uses . Note that Cygwin may have _WIN32 defined, so the order matters here) -#elif defined(_WIN32) -#include // alloca -#if !defined(alloca) -#define alloca _alloca // for clang with MS Codegen -#endif -#else -#include // alloca -#endif -#endif // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) #endif // Clang/GCC warnings with -Weverything #if defined(__clang__) -#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. -#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 -#endif -#if __has_warning("-Wcomma") -#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // -#endif -#if __has_warning("-Wreserved-id-macro") -#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // -#endif -#if __has_warning("-Wdouble-promotion") -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! #endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used @@ -81,7 +73,7 @@ Index of this file: #endif //------------------------------------------------------------------------- -// [SECTION] STB libraries implementation +// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack) //------------------------------------------------------------------------- // Compile time options: @@ -99,6 +91,9 @@ namespace IMGUI_STB_NAMESPACE #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. +#pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. +#pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. #endif #if defined(__clang__) @@ -106,7 +101,7 @@ namespace IMGUI_STB_NAMESPACE #pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" -#pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier // +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier #endif #if defined(__GNUC__) @@ -116,9 +111,9 @@ namespace IMGUI_STB_NAMESPACE #endif #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit #define STBRP_STATIC -#define STBRP_ASSERT(x) IM_ASSERT(x) +#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) #define STBRP_SORT ImQsort #define STB_RECT_PACK_IMPLEMENTATION #endif @@ -129,16 +124,17 @@ namespace IMGUI_STB_NAMESPACE #endif #endif +#ifdef IMGUI_ENABLE_STB_TRUETYPE #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit #define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) #define STBTT_free(x,u) ((void)(u), IM_FREE(x)) -#define STBTT_assert(x) IM_ASSERT(x) +#define STBTT_assert(x) do { IM_ASSERT(x); } while(0) #define STBTT_fmod(x,y) ImFmod(x,y) #define STBTT_sqrt(x) ImSqrt(x) #define STBTT_pow(x,y) ImPow(x,y) #define STBTT_fabs(x) ImFabs(x) -#define STBTT_ifloor(x) ((int)ImFloorStd(x)) +#define STBTT_ifloor(x) ((int)ImFloorSigned(x)) #define STBTT_iceil(x) ((int)ImCeil(x)) #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION @@ -151,6 +147,7 @@ namespace IMGUI_STB_NAMESPACE #include "imstb_truetype.h" #endif #endif +#endif // IMGUI_ENABLE_STB_TRUETYPE #if defined(__GNUC__) #pragma GCC diagnostic pop @@ -208,7 +205,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); @@ -220,6 +217,11 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); @@ -235,7 +237,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f); colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); @@ -263,7 +265,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); @@ -275,6 +277,11 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; @@ -319,7 +326,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); @@ -331,6 +338,11 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; @@ -340,32 +352,50 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) } //----------------------------------------------------------------------------- -// ImDrawList +// [SECTION] ImDrawList //----------------------------------------------------------------------------- ImDrawListSharedData::ImDrawListSharedData() { - Font = NULL; - FontSize = 0.0f; - CurveTessellationTol = 0.0f; - ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); - InitialFlags = ImDrawListFlags_None; + memset(this, 0, sizeof(*this)); + for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); + ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); + } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); +} - // Const data - for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++) +void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) +{ + if (CircleSegmentMaxError == max_error) + return; + + IM_ASSERT(max_error > 0.0f); + CircleSegmentMaxError = max_error; + for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) { - const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12); - CircleVtx12[i] = ImVec2(ImCos(a), ImSin(a)); + const float radius = (float)i; + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } -void ImDrawList::Clear() +// Initialize before use in a new frame. We always have a command ready in the buffer. +void ImDrawList::_ResetForNewFrame() { + // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + if (_Splitter._Count > 1) + _Splitter.Merge(this); + CmdBuffer.resize(0); IdxBuffer.resize(0); VtxBuffer.resize(0); - Flags = _Data ? _Data->InitialFlags : ImDrawListFlags_None; - _VtxCurrentOffset = 0; + Flags = _Data->InitialFlags; + memset(&_CmdHeader, 0, sizeof(_CmdHeader)); _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; @@ -373,13 +403,16 @@ void ImDrawList::Clear() _TextureIdStack.resize(0); _Path.resize(0); _Splitter.Clear(); + CmdBuffer.push_back(ImDrawCmd()); + _FringeScale = 1.0f; } -void ImDrawList::ClearFreeMemory() +void ImDrawList::_ClearFreeMemory() { CmdBuffer.clear(); IdxBuffer.clear(); VtxBuffer.clear(); + Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; @@ -399,86 +432,147 @@ ImDrawList* ImDrawList::CloneOutput() const return dst; } -// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds -#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) -#define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : (ImTextureID)NULL) - void ImDrawList::AddDrawCmd() { ImDrawCmd draw_cmd; - draw_cmd.ClipRect = GetCurrentClipRect(); - draw_cmd.TextureId = GetCurrentTextureId(); - draw_cmd.VtxOffset = _VtxCurrentOffset; + draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() + draw_cmd.TextureId = _CmdHeader.TextureId; + draw_cmd.VtxOffset = _CmdHeader.VtxOffset; draw_cmd.IdxOffset = IdxBuffer.Size; IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); CmdBuffer.push_back(draw_cmd); } +// Pop trailing draw command (used before merging or presenting to user) +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +void ImDrawList::_PopUnusedDrawCmd() +{ + while (CmdBuffer.Size > 0) + { + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) + return;// break; + CmdBuffer.pop_back(); + } +} + void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { - ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; - if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL) + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + IM_ASSERT(curr_cmd->UserCallback == NULL); + if (curr_cmd->ElemCount != 0) { AddDrawCmd(); - current_cmd = &CmdBuffer.back(); + curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; } - current_cmd->UserCallback = callback; - current_cmd->UserCallbackData = callback_data; + curr_cmd->UserCallback = callback; + curr_cmd->UserCallbackData = callback_data; AddDrawCmd(); // Force a new command after us (see comment below) } +// Compare ClipRect, TextureId and VtxOffset with a single memcmp() +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) + +// Try to merge two last draw commands +void ImDrawList::_TryMergeDrawCmds() +{ + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + { + prev_cmd->ElemCount += curr_cmd->ElemCount; + CmdBuffer.pop_back(); + } +} + // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. -void ImDrawList::UpdateClipRect() +void ImDrawList::_OnChangedClipRect() { // If current command is used with different settings we need to add a new command - const ImVec4 curr_clip_rect = GetCurrentClipRect(); - ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL; - if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command - ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; - if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + { CmdBuffer.pop_back(); - else - curr_cmd->ClipRect = curr_clip_rect; + return; + } + + curr_cmd->ClipRect = _CmdHeader.ClipRect; } -void ImDrawList::UpdateTextureID() +void ImDrawList::_OnChangedTextureID() { // If current command is used with different settings we need to add a new command - const ImTextureID curr_texture_id = GetCurrentTextureId(); - ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; - if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command - ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; - if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL) + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + { CmdBuffer.pop_back(); - else - curr_cmd->TextureId = curr_texture_id; + return; + } + + curr_cmd->TextureId = _CmdHeader.TextureId; } -#undef GetCurrentClipRect -#undef GetCurrentTextureId +void ImDrawList::_OnChangedVtxOffset() +{ + // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. + _VtxCurrentIdx = 0; + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + curr_cmd->VtxOffset = _CmdHeader.VtxOffset; +} + +int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const +{ + // Automatic segment count + const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + return _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); +} // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) -void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) +void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect) { ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); - if (intersect_with_current_clip_rect && _ClipRectStack.Size) + if (intersect_with_current_clip_rect) { - ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1]; + ImVec4 current = _CmdHeader.ClipRect; if (cr.x < current.x) cr.x = current.x; if (cr.y < current.y) cr.y = current.y; if (cr.z > current.z) cr.z = current.z; @@ -488,7 +582,8 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ cr.w = ImMax(cr.y, cr.w); _ClipRectStack.push_back(cr); - UpdateClipRect(); + _CmdHeader.ClipRect = cr; + _OnChangedClipRect(); } void ImDrawList::PushClipRectFullScreen() @@ -498,37 +593,43 @@ void ImDrawList::PushClipRectFullScreen() void ImDrawList::PopClipRect() { - IM_ASSERT(_ClipRectStack.Size > 0); _ClipRectStack.pop_back(); - UpdateClipRect(); + _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; + _OnChangedClipRect(); } void ImDrawList::PushTextureID(ImTextureID texture_id) { _TextureIdStack.push_back(texture_id); - UpdateTextureID(); + _CmdHeader.TextureId = texture_id; + _OnChangedTextureID(); } void ImDrawList::PopTextureID() { - IM_ASSERT(_TextureIdStack.Size > 0); _TextureIdStack.pop_back(); - UpdateTextureID(); + _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; + _OnChangedTextureID(); } -// NB: this can be called with negative count for removing primitives (as long as the result does not underflow) +// Reserve space for a number of vertices and indices. +// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or +// submit the intermediate results. PrimUnreserve() can be used to release unused allocations. void ImDrawList::PrimReserve(int idx_count, int vtx_count) { // Large mesh support (when enabled) + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) { - _VtxCurrentOffset = VtxBuffer.Size; - _VtxCurrentIdx = 0; - AddDrawCmd(); + // FIXME: In theory we should be testing that vtx_count <64k here. + // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us + // to not make that check until we rework the text functions to handle clipping and large horizontal lines better. + _CmdHeader.VtxOffset = VtxBuffer.Size; + _OnChangedVtxOffset(); } - ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1]; - draw_cmd.ElemCount += idx_count; + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount += idx_count; int vtx_buffer_old_size = VtxBuffer.Size; VtxBuffer.resize(vtx_buffer_old_size + vtx_count); @@ -539,6 +640,17 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; } +// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve(). +void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) +{ + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount -= idx_count; + VtxBuffer.shrink(VtxBuffer.Size - vtx_count); + IdxBuffer.shrink(IdxBuffer.Size - idx_count); +} + // Fully unrolled with inline call to keep our debug builds decently fast. void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) { @@ -584,42 +696,58 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c _IdxWritePtr += 6; } -// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds. -// Those macros expects l-values. -#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } -#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. +// - Those macros expects l-values and need to be used as their own statement. +// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0 +#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) +#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0 // TODO: Thickness anti-aliased lines cap are missing their AA fringe. // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. -void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness) { - if (points_count < 2) + if (points_count < 2 || (col & IM_COL32_A_MASK) == 0) return; - const ImVec2 uv = _Data->TexUvWhitePixel; - - int count = points_count; - if (!closed) - count = points_count-1; + const bool closed = (flags & ImDrawFlags_Closed) != 0; + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw + const bool thick_line = (thickness > _FringeScale); - const bool thick_line = thickness > 1.0f; if (Flags & ImDrawListFlags_AntiAliasedLines) { // Anti-aliased stroke - const float AA_SIZE = 1.0f; + const float AA_SIZE = _FringeScale; const ImU32 col_trans = col & ~IM_COL32_A_MASK; - const int idx_count = thick_line ? count*18 : count*12; - const int vtx_count = thick_line ? points_count*4 : points_count*3; + // Thicknesses <1.0 should behave like thickness 1.0 + thickness = ImMax(thickness, 1.0f); + const int integer_thickness = (int)thickness; + const float fractional_thickness = thickness - integer_thickness; + + // Do we want to draw this line using a texture? + // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. + // - If AA_SIZE is not 1.0f we cannot use the texture path. + const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + + // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off + IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); + + const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); + const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3); PrimReserve(idx_count, vtx_count); // Temporary buffer - ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630 + // The first items are normals at each line point, then after that there are either 2 or 4 temp points for each line point + _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5)); + ImVec2* temp_normals = _Data->TempBuffer.Data; ImVec2* temp_points = temp_normals + points_count; + // Calculate normals (tangents) for each line segment for (int i1 = 0; i1 < count; i1++) { - const int i2 = (i1+1) == points_count ? 0 : i1+1; + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; float dx = points[i2].x - points[i1].x; float dy = points[i2].y - points[i1].y; IM_NORMALIZE2F_OVER_ZERO(dx, dy); @@ -627,79 +755,134 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 temp_normals[i1].y = -dx; } if (!closed) - temp_normals[points_count-1] = temp_normals[points_count-2]; + temp_normals[points_count - 1] = temp_normals[points_count - 2]; - if (!thick_line) + // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point + if (use_texture || !thick_line) { + // [PATH 1] Texture-based lines (thick or non-thick) + // [PATH 2] Non texture-based lines (non-thick) + + // The width of the geometry we need to draw - this is essentially pixels for the line itself, plus "one pixel" for AA. + // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture + // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. + // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to + // allow scaling geometry while preserving one-screen-pixel AA fringe). + const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend if (!closed) { - temp_points[0] = points[0] + temp_normals[0] * AA_SIZE; - temp_points[1] = points[0] - temp_normals[0] * AA_SIZE; - temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE; - temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE; + temp_points[0] = points[0] + temp_normals[0] * half_draw_size; + temp_points[1] = points[0] - temp_normals[0] * half_draw_size; + temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; + temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; } + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. - unsigned int idx1 = _VtxCurrentIdx; - for (int i1 = 0; i1 < count; i1++) + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment { - const int i2 = (i1+1) == points_count ? 0 : i1+1; - unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment + const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment // Average normals float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; - IM_FIXNORMAL2F(dm_x, dm_y) - dm_x *= AA_SIZE; - dm_y *= AA_SIZE; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area + dm_y *= half_draw_size; - // Add temporary vertexes - ImVec2* out_vtx = &temp_points[i2*2]; + // Add temporary vertexes for the outer edges + ImVec2* out_vtx = &temp_points[i2 * 2]; out_vtx[0].x = points[i2].x + dm_x; out_vtx[0].y = points[i2].y + dm_y; out_vtx[1].x = points[i2].x - dm_x; out_vtx[1].y = points[i2].y - dm_y; - // Add indexes - _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); - _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0); - _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); - _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1); - _IdxWritePtr += 12; + if (use_texture) + { + // Add indices for two triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri + _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri + _IdxWritePtr += 6; + } + else + { + // Add indexes for four triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 + _IdxWritePtr += 12; + } idx1 = idx2; } - // Add vertexes - for (int i = 0; i < points_count; i++) + // Add vertexes for each point on the line + if (use_texture) + { + // If we're using textures we only need to emit the left/right edge vertices + ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness]; + /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false! + { + const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1]; + tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp() + tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness; + tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness; + tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness; + }*/ + ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y); + ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge + _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge + _VtxWritePtr += 2; + } + } + else { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; - _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans; - _VtxWritePtr += 3; + // If we're not using a texture, we need the center vertex as well + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line + _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge + _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge + _VtxWritePtr += 3; + } } } else { + // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend if (!closed) { + const int points_last = points_count - 1; temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); - temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); - temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness); - temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness); - temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); } + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. - unsigned int idx1 = _VtxCurrentIdx; - for (int i1 = 0; i1 < count; i1++) + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment { - const int i2 = (i1+1) == points_count ? 0 : i1+1; - unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; + const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment + const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment // Average normals float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; @@ -710,8 +893,8 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 float dm_in_x = dm_x * half_inner_thickness; float dm_in_y = dm_y * half_inner_thickness; - // Add temporary vertexes - ImVec2* out_vtx = &temp_points[i2*4]; + // Add temporary vertices + ImVec2* out_vtx = &temp_points[i2 * 4]; out_vtx[0].x = points[i2].x + dm_out_x; out_vtx[0].y = points[i2].y + dm_out_y; out_vtx[1].x = points[i2].x + dm_in_x; @@ -722,24 +905,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 out_vtx[3].y = points[i2].y - dm_out_y; // Add indexes - _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); - _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1); - _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); - _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1); - _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3); - _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2); + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr += 18; idx1 = idx2; } - // Add vertexes + // Add vertices for (int i = 0; i < points_count; i++) { - _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans; - _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; _VtxWritePtr += 4; } } @@ -747,14 +930,14 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 } else { - // Non Anti-aliased Stroke - const int idx_count = count*6; - const int vtx_count = count*4; // FIXME-OPT: Not sharing edges + // [PATH 4] Non texture-based, Non anti-aliased lines + const int idx_count = count * 6; + const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges PrimReserve(idx_count, vtx_count); for (int i1 = 0; i1 < count; i1++) { - const int i2 = (i1+1) == points_count ? 0 : i1+1; + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; const ImVec2& p1 = points[i1]; const ImVec2& p2 = points[i2]; @@ -764,24 +947,25 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 dx *= (thickness * 0.5f); dy *= (thickness * 0.5f); - _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; _VtxWritePtr += 4; - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2); - _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3); + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); _IdxWritePtr += 6; _VtxCurrentIdx += 4; } } } -// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) { - if (points_count < 3) + if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) return; const ImVec2 uv = _Data->TexUvWhitePixel; @@ -789,24 +973,25 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun if (Flags & ImDrawListFlags_AntiAliasedFill) { // Anti-aliased Fill - const float AA_SIZE = 1.0f; + const float AA_SIZE = _FringeScale; const ImU32 col_trans = col & ~IM_COL32_A_MASK; - const int idx_count = (points_count-2)*3 + points_count*6; - const int vtx_count = (points_count*2); + const int idx_count = (points_count - 2)*3 + points_count * 6; + const int vtx_count = (points_count * 2); PrimReserve(idx_count, vtx_count); // Add indexes for fill unsigned int vtx_inner_idx = _VtxCurrentIdx; - unsigned int vtx_outer_idx = _VtxCurrentIdx+1; + unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; for (int i = 2; i < points_count; i++) { - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); _IdxWritePtr += 3; } // Compute normals - ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 - for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + _Data->TempBuffer.reserve_discard(points_count); + ImVec2* temp_normals = _Data->TempBuffer.Data; + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { const ImVec2& p0 = points[i0]; const ImVec2& p1 = points[i1]; @@ -817,7 +1002,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun temp_normals[i0].y = -dx; } - for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { // Average normals const ImVec2& n0 = temp_normals[i0]; @@ -834,8 +1019,8 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun _VtxWritePtr += 2; // Add indexes for fringes - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); - _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr += 6; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; @@ -843,7 +1028,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun else { // Non Anti-aliased Fill - const int idx_count = (points_count-2)*3; + const int idx_count = (points_count - 2)*3; const int vtx_count = points_count; PrimReserve(idx_count, vtx_count); for (int i = 0; i < vtx_count; i++) @@ -853,31 +1038,108 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun } for (int i = 2; i < points_count; i++) { - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i); + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); _IdxWritePtr += 3; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; } } -void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) { - if (radius == 0.0f || a_min_of_12 > a_max_of_12) + if (radius < 0.5f) { _Path.push_back(center); return; } - _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); - for (int a = a_min_of_12; a <= a_max_of_12; a++) + + // Calculate arc auto segment step size + if (a_step <= 0) + a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius); + + // Make sure we never do steps larger than one quarter of the circle + a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + + const int sample_range = ImAbs(a_max_sample - a_min_sample); + const int a_next_step = a_step; + + int samples = sample_range + 1; + bool extra_max_sample = false; + if (a_step > 1) { - const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)]; - _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius)); + samples = sample_range / a_step + 1; + const int overstep = sample_range % a_step; + + if (overstep > 0) + { + extra_max_sample = true; + samples++; + + // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end, + // distribute first step range evenly between them by reducing first step size. + if (sample_range > 0) + a_step -= (a_step - overstep) / 2; + } + } + + _Path.resize(_Path.Size + samples); + ImVec2* out_ptr = _Path.Data + (_Path.Size - samples); + + int sample_index = a_min_sample; + if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + { + sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + } + + if (a_max_sample >= a_min_sample) + { + for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + else + { + for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } } + + if (extra_max_sample) + { + int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (normalized_max_sample < 0) + normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + + IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr); } -void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) { - if (radius == 0.0f) + if (radius < 0.5f) { _Path.push_back(center); return; @@ -893,62 +1155,204 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa } } -static void PathBezierToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +// 0: East, 3: South, 6: West, 9: North, 12: East +void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0); +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + + if (num_segments > 0) + { + _PathArcToN(center, radius, a_min, a_max, num_segments); + return; + } + + // Automatic segment count + if (radius <= _Data->ArcFastRadiusCutoff) + { + const bool a_is_reverse = a_max < a_min; + + // We are going to use precomputed values for mid samples. + // Determine first and last sample in lookup table that belong to the arc. + const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f); + const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f); + + const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f); + const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f); + const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0); + + const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f; + const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f; + + _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0))); + if (a_emit_start) + _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)); + if (a_mid_samples > 0) + _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0); + if (a_emit_end) + _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)); + } + else + { + const float arc_length = ImAbs(a_max - a_min); + const int circle_segment_count = _CalcCircleAutoSegmentCount(radius); + const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length)); + _PathArcToN(center, radius, a_min, a_max, arc_segment_count); + } +} + +ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) +{ + float u = 1.0f - t; + float w1 = u * u * u; + float w2 = 3 * u * u * t; + float w3 = 3 * u * t * t; + float w4 = t * t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y); +} + +ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t) +{ + float u = 1.0f - t; + float w1 = u * u; + float w2 = 2 * u * t; + float w3 = t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y); +} + +// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp +static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) { float dx = x4 - x1; float dy = y4 - y1; - float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); - float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + float d2 = (x2 - x4) * dy - (y2 - y4) * dx; + float d3 = (x3 - x4) * dy - (y3 - y4) * dx; d2 = (d2 >= 0) ? d2 : -d2; d3 = (d3 >= 0) ? d3 : -d3; - if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) { path->push_back(ImVec2(x4, y4)); } else if (level < 10) { - float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f; - float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f; - float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f; - float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f; - float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f; - float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f; + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f; + float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f; + PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} - PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1); - PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1); +static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level) +{ + float dx = x3 - x1, dy = y3 - y1; + float det = (x2 - x3) * dy - (y2 - y3) * dx; + if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy)) + { + path->push_back(ImVec2(x3, y3)); + } + else if (level < 10) + { + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1); + PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1); } } -void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) { ImVec2 p1 = _Path.back(); if (num_segments == 0) { - // Auto-tessellated - PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); + IM_ASSERT(_Data->CurveTessellationTol > 0.0f); + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated } else { float t_step = 1.0f / (float)num_segments; for (int i_step = 1; i_step <= num_segments; i_step++) - { - float t = t_step * i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t*t*t; - _Path.push_back(ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y)); - } + _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step)); } } -void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners) +void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments) { - rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); - rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + IM_ASSERT(_Data->CurveTessellationTol > 0.0f); + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step)); + } +} + +IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4)); +static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) +{ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Obsoleted in 1.82 (from February 2021) + // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All) + // ~0 --> ImDrawFlags_RoundCornersAll or 0 + if (flags == ~0) + return ImDrawFlags_RoundCornersAll; + + // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations) + // 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!) + // 0x02 --> ImDrawFlags_RoundCornersTopRight + // 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight + // 0x04 --> ImDrawFlags_RoundCornersBotLeft + // 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft + // ... + // 0x0F --> ImDrawFlags_RoundCornersAll or 0 + // (See all values in ImDrawCornerFlags_) + if (flags >= 0x01 && flags <= 0x0F) + return (flags << 4); + + // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f' +#endif + + // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values. + // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc... + IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); + + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags |= ImDrawFlags_RoundCornersAll; - if (rounding <= 0.0f || rounding_corners == 0) + return flags; +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) +{ + flags = FixRectCornerFlags(flags); + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { PathLineTo(a); PathLineTo(ImVec2(b.x, a.y)); @@ -957,10 +1361,10 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } else { - const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; - const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; - const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; - const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; + const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f; PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); @@ -974,35 +1378,35 @@ void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float th return; PathLineTo(p1 + ImVec2(0.5f, 0.5f)); PathLineTo(p2 + ImVec2(0.5f, 0.5f)); - PathStroke(col, false, thickness); + PathStroke(col, 0, thickness); } // p_min = upper-left, p_max = lower-right // Note we don't render 1 pixels sized rectangles properly. -void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness) +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; if (Flags & ImDrawListFlags_AntiAliasedLines) - PathRect(p_min + ImVec2(0.50f,0.50f), p_max - ImVec2(0.50f,0.50f), rounding, rounding_corners); + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags); else - PathRect(p_min + ImVec2(0.50f,0.50f), p_max - ImVec2(0.49f,0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes. - PathStroke(col, true, thickness); + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding > 0.0f) + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { - PathRect(p_min, p_max, rounding, rounding_corners); - PathFillConvex(col); + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); } else { - PrimReserve(6, 4); - PrimRect(p_min, p_max, col); + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); } } @@ -1014,8 +1418,8 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_ma const ImVec2 uv = _Data->TexUvWhitePixel; PrimReserve(6, 4); - PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); - PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); PrimWriteVtx(p_min, uv, col_upr_left); PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); PrimWriteVtx(p_max, uv, col_bot_right); @@ -1031,7 +1435,7 @@ void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, c PathLineTo(p2); PathLineTo(p3); PathLineTo(p4); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) @@ -1054,7 +1458,7 @@ void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p PathLineTo(p1); PathLineTo(p2); PathLineTo(p3); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) @@ -1069,6 +1473,55 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV } void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + } + + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + } + + PathFillConvex(col); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) { if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; @@ -1076,10 +1529,11 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) { if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; @@ -1090,14 +1544,26 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, PathFillConvex(col); } -void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) +// Cubic Bezier takes 4 controls points +void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) { if ((col & IM_COL32_A_MASK) == 0) return; - PathLineTo(pos0); - PathBezierCurveTo(cp0, cp1, pos1, num_segments); - PathStroke(col, false, thickness); + PathLineTo(p1); + PathBezierCubicCurveTo(p2, p3, p4, num_segments); + PathStroke(col, 0, thickness); +} + +// Quadratic Bezier takes 3 controls points +void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierQuadraticCurveTo(p2, p3, num_segments); + PathStroke(col, 0, thickness); } void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) @@ -1116,9 +1582,9 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, if (font_size == 0.0f) font_size = _Data->FontSize; - IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - ImVec4 clip_rect = _ClipRectStack.back(); + ImVec4 clip_rect = _CmdHeader.ClipRect; if (cpu_fine_clip_rect) { clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); @@ -1139,7 +1605,7 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, cons if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); @@ -1155,7 +1621,7 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, con if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); @@ -1166,23 +1632,24 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, con PopTextureID(); } -void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) + flags = FixRectCornerFlags(flags); + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); return; } - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); int vert_start_idx = VtxBuffer.Size; - PathRect(p_min, p_max, rounding, rounding_corners); + PathRect(p_min, p_max, rounding, flags); PathFillConvex(col); int vert_end_idx = VtxBuffer.Size; ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); @@ -1193,7 +1660,7 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi //----------------------------------------------------------------------------- -// ImDrawListSplitter +// [SECTION] ImDrawListSplitter //----------------------------------------------------------------------------- // FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. //----------------------------------------------------------------------------- @@ -1214,10 +1681,14 @@ void ImDrawListSplitter::ClearFreeMemory() void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) { - IM_ASSERT(_Current == 0 && _Count <= 1); + IM_UNUSED(draw_list); + IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); int old_channels_count = _Channels.Size; if (old_channels_count < channels_count) + { + _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable _Channels.resize(channels_count); + } _Count = channels_count; // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer @@ -1235,30 +1706,17 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) _Channels[i]._CmdBuffer.resize(0); _Channels[i]._IdxBuffer.resize(0); } - if (_Channels[i]._CmdBuffer.Size == 0) - { - ImDrawCmd draw_cmd; - draw_cmd.ClipRect = draw_list->_ClipRectStack.back(); - draw_cmd.TextureId = draw_list->_TextureIdStack.back(); - _Channels[i]._CmdBuffer.push_back(draw_cmd); - } } } -static inline bool CanMergeDrawCommands(ImDrawCmd* a, ImDrawCmd* b) -{ - return memcmp(&a->ClipRect, &b->ClipRect, sizeof(a->ClipRect)) == 0 && a->TextureId == b->TextureId && a->VtxOffset == b->VtxOffset && !a->UserCallback && !b->UserCallback; -} - void ImDrawListSplitter::Merge(ImDrawList* draw_list) { - // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. if (_Count <= 1) return; SetCurrentChannel(draw_list, 0); - if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0) - draw_list->CmdBuffer.pop_back(); + draw_list->_PopUnusedDrawCmd(); // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. int new_cmd_buffer_count = 0; @@ -1268,14 +1726,21 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) for (int i = 1; i < _Count; i++) { ImDrawChannel& ch = _Channels[i]; - if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() ch._CmdBuffer.pop_back(); - if (ch._CmdBuffer.Size > 0 && last_cmd != NULL && CanMergeDrawCommands(last_cmd, &ch._CmdBuffer[0])) + + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { - // Merge previous channel last draw command with current channel first draw command if matching. - last_cmd->ElemCount += ch._CmdBuffer[0].ElemCount; - idx_offset += ch._CmdBuffer[0].ElemCount; - ch._CmdBuffer.erase(ch._CmdBuffer.Data); + // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. + // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. + ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + { + // Merge previous channel last draw command with current channel first draw command if matching. + last_cmd->ElemCount += next_cmd->ElemCount; + idx_offset += next_cmd->ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + } } if (ch._CmdBuffer.Size > 0) last_cmd = &ch._CmdBuffer.back(); @@ -1300,8 +1765,18 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } } draw_list->_IdxWritePtr = idx_write; - draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. - draw_list->UpdateTextureID(); + + // Ensure there's always a non-callback draw command trailing the command-buffer + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); + _Count = 1; } @@ -1310,6 +1785,7 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) return; + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); @@ -1317,6 +1793,15 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd == NULL) + draw_list->AddDrawCmd(); + else if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); } //----------------------------------------------------------------------------- @@ -1369,13 +1854,19 @@ void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int ve float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF; + const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF; + const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF; + const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r; + const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g; + const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b; for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) { float d = ImDot(vert->pos - gradient_p0, gradient_extent); float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); - int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t); - int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t); - int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t); + int r = (int)(col0_r + col_delta_r * t); + int g = (int)(col0_g + col_delta_g * t); + int b = (int)(col0_b + col_delta_b * t); vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); } } @@ -1411,25 +1902,13 @@ void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int ve ImFontConfig::ImFontConfig() { - FontData = NULL; - FontDataSize = 0; + memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - FontNo = 0; - SizePixels = 0.0f; OversampleH = 3; // FIXME: 2 may be a better default? OversampleV = 1; - PixelSnapH = false; - GlyphExtraSpacing = ImVec2(0.0f, 0.0f); - GlyphOffset = ImVec2(0.0f, 0.0f); - GlyphRanges = NULL; - GlyphMinAdvanceX = 0.0f; GlyphMaxAdvanceX = FLT_MAX; - MergeMode = false; - RasterizerFlags = 0x00; RasterizerMultiply = 1.0f; EllipsisChar = (ImWchar)-1; - memset(Name, 0, sizeof(Name)); - DstFont = NULL; } //----------------------------------------------------------------------------- @@ -1437,39 +1916,39 @@ ImFontConfig::ImFontConfig() //----------------------------------------------------------------------------- // A work of art lies ahead! (. = white layer, X = black layer, others are blank) -// The white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. -const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 108; -const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; -const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000; -static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = -{ - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX " - "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " - "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " - "X - X.X - X.....X - X.....X -X...X - X...X- X..X " - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X " - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX " - "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX " - "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X" - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X" - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X" - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X" - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X" - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X" - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X" - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X " - "X.X X..X - -X.......X- X.......X - XX XX - - X..........X " - "XX X..X - - X.....X - X.....X - X.X X.X - - X........X " - " X..X - X...X - X...X - X..X X..X - - X........X " - " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX " - "------------ - X - X -X.....................X- ------------------" - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " +// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. +// (This is used when io.MouseDrawCursor = true) +const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing. +const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" + "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " + " X..X - - X...X - X...X - X..X X..X - - X........X - " + " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " + "------------- - X - X -X.....................X- ------------------- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " }; static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = @@ -1483,23 +1962,14 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand + { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; ImFontAtlas::ImFontAtlas() { - Locked = false; - Flags = ImFontAtlasFlags_None; - TexID = (ImTextureID)NULL; - TexDesiredWidth = 0; + memset(this, 0, sizeof(*this)); TexGlyphPadding = 1; - - TexPixelsAlpha8 = NULL; - TexPixelsRGBA32 = NULL; - TexWidth = TexHeight = 0; - TexUvScale = ImVec2(0.0f, 0.0f); - TexUvWhitePixel = ImVec2(0.0f, 0.0f); - for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) - CustomRectIds[n] = -1; + PackIdMouseCursors = PackIdLines = -1; } ImFontAtlas::~ImFontAtlas() @@ -1527,8 +1997,8 @@ void ImFontAtlas::ClearInputData() } ConfigData.clear(); CustomRects.clear(); - for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) - CustomRectIds[n] = -1; + PackIdMouseCursors = PackIdLines = -1; + // Important: we leave TexReady untouched } void ImFontAtlas::ClearTexData() @@ -1540,14 +2010,15 @@ void ImFontAtlas::ClearTexData() IM_FREE(TexPixelsRGBA32); TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; + TexPixelsUseColors = false; + // Important: we leave TexReady untouched } void ImFontAtlas::ClearFonts() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - for (int i = 0; i < Fonts.Size; i++) - IM_DELETE(Fonts[i]); - Fonts.clear(); + Fonts.clear_delete(); + TexReady = false; } void ImFontAtlas::Clear() @@ -1561,11 +2032,7 @@ void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_wid { // Build atlas on demand if (TexPixelsAlpha8 == NULL) - { - if (ConfigData.empty()) - AddFontDefault(); Build(); - } *out_pixels = TexPixelsAlpha8; if (out_width) *out_width = TexWidth; @@ -1624,20 +2091,21 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; // Invalidate texture + TexReady = false; ClearTexData(); return new_font_cfg.DstFont; } // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) -static unsigned int stb_decompress_length(const unsigned char *input); -static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length); +static unsigned int stb_decompress_length(const unsigned char* input); +static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); static const char* GetDefaultCompressedFontDataTTFBase85(); static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } static void Decode85(const unsigned char* src, unsigned char* dst) { while (*src) { - unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4])))); + unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. src += 5; dst += 4; @@ -1658,11 +2126,11 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); font_cfg.EllipsisChar = (ImWchar)0x0085; + font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); - font->DisplayOffset.y = 1.0f; return font; } @@ -1673,7 +2141,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); if (!data) { - IM_ASSERT(0); // Could not load file. + IM_ASSERT_USER_ERROR(0, "Could not load font file!"); return NULL; } ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); @@ -1695,7 +2163,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si IM_ASSERT(font_cfg.FontData == NULL); font_cfg.FontData = ttf_data; font_cfg.FontDataSize = ttf_size; - font_cfg.SizePixels = size_pixels; + font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels; if (glyph_ranges) font_cfg.GlyphRanges = glyph_ranges; return AddFont(&font_cfg); @@ -1704,7 +2172,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); - unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size); + unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size); stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); @@ -1723,14 +2191,11 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed return font; } -int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) +int ImFontAtlas::AddCustomRectRegular(int width, int height) { - // Breaking change on 2019/11/21 (1.74): ImFontAtlas::AddCustomRectRegular() now requires an ID >= 0x110000 (instead of >= 0x10000) - IM_ASSERT(id >= 0x110000); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); ImFontAtlasCustomRect r; - r.ID = id; r.Width = (unsigned short)width; r.Height = (unsigned short)height; CustomRects.push_back(r); @@ -1739,13 +2204,16 @@ int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) { +#ifdef IMGUI_USE_WCHAR32 + IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); +#endif IM_ASSERT(font != NULL); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); ImFontAtlasCustomRect r; - r.ID = id; r.Width = (unsigned short)width; r.Height = (unsigned short)height; + r.GlyphID = id; r.GlyphAdvanceX = advance_x; r.GlyphOffset = offset; r.Font = font; @@ -1768,16 +2236,15 @@ bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* ou if (Flags & ImFontAtlasFlags_NoMouseCursors) return false; - IM_ASSERT(CustomRectIds[0] != -1); - ImFontAtlasCustomRect& r = CustomRects[CustomRectIds[0]]; - IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); - ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y); + IM_ASSERT(PackIdMouseCursors != -1); + ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; *out_size = size; *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; out_uv_border[0] = (pos) * TexUvScale; out_uv_border[1] = (pos + size) * TexUvScale; - pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; out_uv_fill[0] = (pos) * TexUvScale; out_uv_fill[1] = (pos + size) * TexUvScale; return true; @@ -1786,7 +2253,30 @@ bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* ou bool ImFontAtlas::Build() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - return ImFontAtlasBuildWithStbTruetype(this); + + // Default font is none are specified + if (ConfigData.Size == 0) + AddFontDefault(); + + // Select builder + // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which + // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere + // and point to it instead of pointing directly to return value of the GetBuilderXXX functions. + const ImFontBuilderIO* builder_io = FontBuilderIO; + if (builder_io == NULL) + { +#ifdef IMGUI_ENABLE_FREETYPE + builder_io = ImGuiFreeType::GetBuilderForFreeType(); +#elif defined(IMGUI_ENABLE_STB_TRUETYPE) + builder_io = ImFontAtlasGetBuilderForStbTruetype(); +#else + IM_ASSERT(0); // Invalid Build function +#endif + } + + // Build + return builder_io->FontBuilder_Build(this); } void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) @@ -1800,12 +2290,14 @@ void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], fl void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) { + IM_ASSERT_PARANOID(w <= stride); unsigned char* data = pixels + x + y * stride; - for (int j = h; j > 0; j--, data += stride) - for (int i = 0; i < w; i++) - data[i] = table[data[i]]; + for (int j = h; j > 0; j--, data += stride - w) + for (int i = w; i > 0; i--, data++) + *data = table[*data]; } +#ifdef IMGUI_ENABLE_STB_TRUETYPE // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) struct ImFontBuildSrcData @@ -1818,8 +2310,8 @@ struct ImFontBuildSrcData int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] int GlyphsHighest; // Highest requested codepoint int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) - ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) - ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) + ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsSet) }; // Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) @@ -1828,26 +2320,26 @@ struct ImFontBuildDstData int SrcCount; // Number of source fonts targeting this destination font. int GlyphsHighest; int GlyphsCount; - ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. + ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. }; -static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector* out) +static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out) { IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); - const int* it_begin = in->Storage.begin(); - const int* it_end = in->Storage.end(); - for (const int* it = it_begin; it < it_end; it++) - if (int entries_32 = *it) - for (int bit_n = 0; bit_n < 32; bit_n++) - if (entries_32 & (1u << bit_n)) - out->push_back((int)((it - it_begin) << 5) + bit_n); + const ImU32* it_begin = in->Storage.begin(); + const ImU32* it_end = in->Storage.end(); + for (const ImU32* it = it_begin; it < it_end; it++) + if (ImU32 entries_32 = *it) + for (ImU32 bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & ((ImU32)1 << bit_n)) + out->push_back((int)(((it - it_begin) << 5) + bit_n)); } -bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { IM_ASSERT(atlas->ConfigData.Size > 0); - ImFontAtlasBuildRegisterDefaultCustomRects(atlas); + ImFontAtlasBuildInit(atlas); // Clear atlas atlas->TexID = (ImTextureID)NULL; @@ -1876,10 +2368,11 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) if (cfg.DstFont == atlas->Fonts[output_i]) src_tmp.DstIndex = output_i; - IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? if (src_tmp.DstIndex == -1) + { + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? return false; - + } // Initialize helper structure for font loading and verify that the TTF/OTF data is correct const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); @@ -1890,7 +2383,12 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + { + // Check for valid range. This may also help detect *some* dangling pointers, because a common + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. + IM_ASSERT(src_range[0] <= src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + } dst_tmp.SrcCount++; dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); } @@ -1901,14 +2399,14 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); + src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); if (dst_tmp.GlyphsSet.Storage.empty()) - dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); + dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) { - if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) + if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) continue; if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? continue; @@ -1916,8 +2414,8 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Add to avail set/counters src_tmp.GlyphsCount++; dst_tmp.GlyphsCount++; - src_tmp.GlyphsSet.SetBit(codepoint, true); - dst_tmp.GlyphsSet.SetBit(codepoint, true); + src_tmp.GlyphsSet.SetBit(codepoint); + dst_tmp.GlyphsSet.SetBit(codepoint); total_glyphs_count++; } } @@ -1927,7 +2425,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); - UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); src_tmp.GlyphsSet.Clear(); IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); } @@ -1992,7 +2490,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) if (atlas->TexDesiredWidth > 0) atlas->TexWidth = atlas->TexDesiredWidth; else - atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; + atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; // 5. Start packing // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). @@ -2055,12 +2553,12 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // 9. Setup ImFont and glyphs for runtime for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { + // When merging fonts with MergeMode=true: + // - We can have multiple input fonts writing into a same destination font. + // - dst_font->ConfigData is != from cfg which is our source configuration. ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - ImFontConfig& cfg = atlas->ConfigData[src_i]; - ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) + ImFont* dst_font = cfg.DstFont; const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); int unscaled_ascent, unscaled_descent, unscaled_line_gap; @@ -2074,41 +2572,32 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) { + // Register glyph const int codepoint = src_tmp.GlyphsList[glyph_i]; const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; - - const float char_advance_x_org = pc.xadvance; - const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); - float char_off_x = font_off_x; - if (char_advance_x_org != char_advance_x_mod) - char_off_x += cfg.PixelSnapH ? ImFloor((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; - - // Register glyph stbtt_aligned_quad q; - float dummy_x = 0.0f, dummy_y = 0.0f; - stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0); - dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod); + float unused_x = 0.0f, unused_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0); + dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); } } - // Cleanup temporary (ImVector doesn't honor destructor) - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - src_tmp_array[src_i].~ImFontBuildSrcData(); + // Cleanup + src_tmp_array.clear_destruct(); ImFontAtlasBuildFinish(atlas); return true; } -void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas) +const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() { - if (atlas->CustomRectIds[0] >= 0) - return; - if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) - atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H); - else - atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, 2, 2); + static ImFontBuilderIO io; + io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; + return &io; } +#endif // IMGUI_ENABLE_STB_TRUETYPE + void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) { if (!font_config->MergeMode) @@ -2116,6 +2605,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f font->ClearOutputData(); font->FontSize = font_config->SizePixels; font->ConfigData = font_config; + font->ConfigDataCount = 0; font->ContainerAtlas = atlas; font->Ascent = ascent; font->Descent = descent; @@ -2130,6 +2620,9 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa ImVector& user_rects = atlas->CustomRects; IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. +#ifdef __GNUC__ + if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) +#endif ImVector pack_rects; pack_rects.resize(user_rects.Size); @@ -2143,60 +2636,165 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa for (int i = 0; i < pack_rects.Size; i++) if (pack_rects[i].was_packed) { - user_rects[i].X = pack_rects[i].x; - user_rects[i].Y = pack_rects[i].y; + user_rects[i].X = (unsigned short)pack_rects[i].x; + user_rects[i].Y = (unsigned short)pack_rects[i].y; IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); } } +void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; +} + +void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; +} + static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) { - IM_ASSERT(atlas->CustomRectIds[0] >= 0); - IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); - ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]]; - IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); - IM_ASSERT(r.IsPacked()); + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); + IM_ASSERT(r->IsPacked()); const int w = atlas->TexWidth; if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) { // Render/copy pixels - IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); - for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++) - for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++) - { - const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w; - const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; - atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00; - atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00; - } + IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + const int x_for_white = r->X; + const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + if (atlas->TexPixelsAlpha8 != NULL) + { + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + } + else + { + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + } } else { - IM_ASSERT(r.Width == 2 && r.Height == 2); - const int offset = (int)(r.X) + (int)(r.Y) * w; - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + // Render 4 white pixels + IM_ASSERT(r->Width == 2 && r->Height == 2); + const int offset = (int)r->X + (int)r->Y * w; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } + } + atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); +} + +static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) +{ + if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) + return; + + // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); + IM_ASSERT(r->IsPacked()); + for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row + { + // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle + unsigned int y = n; + unsigned int line_width = n; + unsigned int pad_left = (r->Width - line_width) / 2; + unsigned int pad_right = r->Width - (pad_left + line_width); + + // Write each slice + IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else + { + unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); + } + + // Calculate UVs for this line + ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale; + float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); + } +} + +// Note: this is called / shared by both the stb_truetype and the FreeType builder +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + // Register texture region for mouse cursors or standard white pixels + if (atlas->PackIdMouseCursors < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + else + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2); + } + + // Register texture region for thick lines + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row + if (atlas->PackIdLines < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines)) + atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); } - atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y); } +// This is called/shared by both the stb_truetype and the FreeType builder. void ImFontAtlasBuildFinish(ImFontAtlas* atlas) { - // Render into our custom data block + // Render into our custom data blocks + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); ImFontAtlasBuildRenderDefaultTexData(atlas); + ImFontAtlasBuildRenderLinesTexData(atlas); // Register custom rectangle glyphs for (int i = 0; i < atlas->CustomRects.Size; i++) { - const ImFontAtlasCustomRect& r = atlas->CustomRects[i]; - if (r.Font == NULL || r.ID >= 0x110000) + const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; + if (r->Font == NULL || r->GlyphID == 0) continue; - IM_ASSERT(r.Font->ContainerAtlas == atlas); + // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH + IM_ASSERT(r->Font->ContainerAtlas == atlas); ImVec2 uv0, uv1; - atlas->CalcCustomRectUV(&r, &uv0, &uv1); - r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX); + atlas->CalcCustomRectUV(r, &uv0, &uv1); + r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); } // Build all fonts lookup tables @@ -2204,22 +2802,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) if (atlas->Fonts[i]->DirtyLookupTables) atlas->Fonts[i]->BuildLookupTable(); - // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). - // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. - // FIXME: Also note that 0x2026 is currently seldomly included in our font ranges. Because of this we are more likely to use three individual dots. - for (int i = 0; i < atlas->Fonts.size(); i++) - { - ImFont* font = atlas->Fonts[i]; - if (font->EllipsisChar != (ImWchar)-1) - continue; - const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; - for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++) - if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists - { - font->EllipsisChar = ellipsis_variants[j]; - break; - } - } + atlas->TexReady = true; } // Retrieve list of range (2 int per range, values are inclusive) @@ -2233,13 +2816,25 @@ const ImWchar* ImFontAtlas::GetGlyphRangesDefault() return &ranges[0]; } +const ImWchar* ImFontAtlas::GetGlyphRangesGreek() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0370, 0x03FF, // Greek and Coptic + 0, + }; + return &ranges[0]; +} + const ImWchar* ImFontAtlas::GetGlyphRangesKorean() { static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x3131, 0x3163, // Korean alphabets - 0xAC00, 0xD79D, // Korean characters + 0xAC00, 0xD7A3, // Korean characters + 0xFFFD, 0xFFFD, // Invalid 0, }; return &ranges[0]; @@ -2254,6 +2849,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD, // Invalid 0x4e00, 0x9FAF, // CJK Ideograms 0, }; @@ -2330,7 +2926,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF // Half-width characters + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; if (!full_ranges[0]) @@ -2343,52 +2940,84 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() { - // 1946 common ideograms code points for Japanese - // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering - // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this. + // 2999 ideograms code points for Japanese + // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points + // - 863 Jinmeiyo (meaning "for personal name") Kanji code points + // - Sourced from official information provided by the government agencies of Japan: + // - List of Joyo Kanji by the Agency for Cultural Affairs + // - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/ + // - List of Jinmeiyo Kanji by the Ministry of Justice + // - http://www.moj.go.jp/MINJI/minji86.html + // - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0). + // - https://creativecommons.org/licenses/by/4.0/legalcode + // - You can generate this code by the script at: + // - https://github.com/vaiorabbit/everyday_use_kanji + // - References: + // - List of Joyo Kanji + // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji + // - List of Jinmeiyo Kanji + // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji + // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) static const short accumulative_offsets_from_0x4E00[] = { - 0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18, - 5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15, - 2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1, - 2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12, - 20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9, - 4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3, - 3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23, - 8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2, - 3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14, - 15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5, - 1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12, - 12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16, - 22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2, - 5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2, - 1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7, - 1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14, - 11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25, - 15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18, - 5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5, - 3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15, - 18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1, - 27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4, - 1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41, - 1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2, - 10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159, - 179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6, - 3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1, - 3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2, - 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, - 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, - 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, - 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, + 0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1, + 1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3, + 2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8, + 2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5, + 2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1, + 1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30, + 2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3, + 13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4, + 5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14, + 2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1, + 1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1, + 7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1, + 1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1, + 6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2, + 10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7, + 2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5, + 3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1, + 6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7, + 4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2, + 4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5, + 1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6, + 12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2, + 1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16, + 22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11, + 2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18, + 18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9, + 14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3, + 1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6, + 40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1, + 12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8, + 2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1, + 1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10, + 1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5, + 3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2, + 14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5, + 12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1, + 2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5, + 1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4, + 3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7, + 2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5, + 13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13, + 18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21, + 37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1, + 5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38, + 32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4, + 1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4, + 4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1, + 3,2,1,1,1,1,2,1,1, }; static ImWchar base_ranges[] = // not zero-terminated { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF // Half-width characters + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; if (!full_ranges[0]) @@ -2454,16 +3083,15 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) text += c_len; if (c_len == 0) break; - if (c <= IM_UNICODE_CODEPOINT_MAX) - AddChar((ImWchar)c); + AddChar((ImWchar)c); } } void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) { for (; ranges[0]; ranges += 2) - for (ImWchar c = ranges[0]; c <= ranges[1]; c++) - AddChar(c); + for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 + AddChar((ImWchar)c); } void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) @@ -2488,9 +3116,10 @@ ImFont::ImFont() { FontSize = 0.0f; FallbackAdvanceX = 0.0f; - FallbackChar = (ImWchar)'?'; + FallbackChar = (ImWchar)-1; EllipsisChar = (ImWchar)-1; - DisplayOffset = ImVec2(0.0f, 0.0f); + EllipsisWidth = EllipsisCharStep = 0.0f; + EllipsisCharCount = 0; FallbackGlyph = NULL; ContainerAtlas = NULL; ConfigData = NULL; @@ -2499,6 +3128,7 @@ ImFont::ImFont() Scale = 1.0f; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); } ImFont::~ImFont() @@ -2520,49 +3150,114 @@ void ImFont::ClearOutputData() MetricsTotalSurface = 0; } +static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) +{ + for (int n = 0; n < candidate_chars_count; n++) + if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) + return candidate_chars[n]; + return (ImWchar)-1; +} + void ImFont::BuildLookupTable() { int max_codepoint = 0; for (int i = 0; i != Glyphs.Size; i++) max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + // Build lookup table IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved IndexAdvanceX.clear(); IndexLookup.clear(); DirtyLookupTables = false; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); GrowIndex(max_codepoint + 1); for (int i = 0; i < Glyphs.Size; i++) { int codepoint = (int)Glyphs[i].Codepoint; IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; IndexLookup[codepoint] = (ImWchar)i; + + // Mark 4K page as used + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); } // Create a glyph to handle TAB // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) if (FindGlyph((ImWchar)' ')) { - if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times + if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) Glyphs.resize(Glyphs.Size + 1); ImFontGlyph& tab_glyph = Glyphs.back(); tab_glyph = *FindGlyph((ImWchar)' '); tab_glyph.Codepoint = '\t'; tab_glyph.AdvanceX *= IM_TABSIZE; IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; - IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size-1); + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); } + // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) + SetGlyphVisible((ImWchar)' ', false); + SetGlyphVisible((ImWchar)'\t', false); + + // Setup Fallback character + const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; FallbackGlyph = FindGlyphNoFallback(FallbackChar); - FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; + if (FallbackGlyph == NULL) + { + FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars)); + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + if (FallbackGlyph == NULL) + { + FallbackGlyph = &Glyphs.back(); + FallbackChar = (ImWchar)FallbackGlyph->Codepoint; + } + } + FallbackAdvanceX = FallbackGlyph->AdvanceX; for (int i = 0; i < max_codepoint + 1; i++) if (IndexAdvanceX[i] < 0.0f) IndexAdvanceX[i] = FallbackAdvanceX; + + // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. + const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + if (EllipsisChar == (ImWchar)-1) + EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); + const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + if (EllipsisChar != (ImWchar)-1) + { + EllipsisCharCount = 1; + EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; + } + else if (dot_char != (ImWchar)-1) + { + const ImFontGlyph* glyph = FindGlyph(dot_char); + EllipsisChar = dot_char; + EllipsisCharCount = 3; + EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; + EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; + } } -void ImFont::SetFallbackChar(ImWchar c) +// API is designed this way to avoid exposing the 4K page size +// e.g. use with IsGlyphRangeUnused(0, 255) +bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) { - FallbackChar = c; - BuildLookupTable(); + unsigned int page_begin = (c_begin / 4096); + unsigned int page_last = (c_last / 4096); + for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) + if ((page_n >> 3) < sizeof(Used4kPagesMap)) + if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + return false; + return true; +} + +void ImFont::SetGlyphVisible(ImWchar c, bool visible) +{ + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) + glyph->Visible = visible ? 1 : 0; } void ImFont::GrowIndex(int new_size) @@ -2576,11 +3271,34 @@ void ImFont::GrowIndex(int new_size) // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). -void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. +void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) { + if (cfg != NULL) + { + // Clamp & recenter if needed + const float advance_x_original = advance_x; + advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX); + if (advance_x != advance_x_original) + { + float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; + x0 += char_off_x; + x1 += char_off_x; + } + + // Snap to pixel + if (cfg->PixelSnapH) + advance_x = IM_ROUND(advance_x); + + // Bake spacing + advance_x += cfg->GlyphExtraSpacing.x; + } + Glyphs.resize(Glyphs.Size + 1); ImFontGlyph& glyph = Glyphs.back(); - glyph.Codepoint = (ImWchar)codepoint; + glyph.Codepoint = (unsigned int)codepoint; + glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.Colored = false; glyph.X0 = x0; glyph.Y0 = y0; glyph.X1 = x1; @@ -2589,14 +3307,13 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, glyph.V0 = v0; glyph.U1 = u1; glyph.V1 = v1; - glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX - - if (ConfigData->PixelSnapH) - glyph.AdvanceX = IM_ROUND(glyph.AdvanceX); + glyph.AdvanceX = advance_x; // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. + float pad = ContainerAtlas->TexGlyphPadding + 0.99f; DirtyLookupTables = true; - MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); } void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) @@ -2616,7 +3333,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const { - if (c >= IndexLookup.Size) + if (c >= (size_t)IndexLookup.Size) return FallbackGlyph; const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) @@ -2626,7 +3343,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const { - if (c >= IndexLookup.Size) + if (c >= (size_t)IndexLookup.Size) return NULL; const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) @@ -2634,11 +3351,21 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const return &Glyphs.Data[i]; } -const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +// Wrapping skips upcoming blanks +static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) { - // Simple word-wrapping for English, not full-featured. Please submit failing cases! - // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) + while (text < text_end && ImCharIsBlankA(*text)) + text++; + if (*text == '\n') + text++; + return text; +} +// Simple word-wrapping for English, not full-featured. Please submit failing cases! +// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. +// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ // For references, possible wrap point marked with ^ // "aaa bbb, ccc,ddd. eee fff. ggg!" // ^ ^ ^ ^ ^__ ^ ^ @@ -2650,7 +3377,6 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c // Cut words that cannot possibly fit within one line. // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" - float line_width = 0.0f; float word_width = 0.0f; float blank_width = 0.0f; @@ -2661,6 +3387,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c bool inside_word = true; const char* s = text; + IM_ASSERT(text_end != NULL); while (s < text_end) { unsigned int c = (unsigned int)*s; @@ -2669,8 +3396,6 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c next_s = s + 1; else next_s = s + ImTextCharFromUtf8(&c, s, text_end); - if (c == 0) - break; if (c < 32) { @@ -2715,7 +3440,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } // Allow wrapping after punctuation. - inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"'); + inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); } // We ignore blank width at the end of the line (they can be skipped) @@ -2730,6 +3455,10 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c s = next_s; } + // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + // +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol). + if (s == text && text < text_end) + return s + 1; return s; } @@ -2741,7 +3470,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons const float line_height = size; const float scale = size / FontSize; - ImVec2 text_size = ImVec2(0,0); + ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; const bool word_wrap_enabled = (wrap_width > 0.0f); @@ -2754,11 +3483,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - { word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); - if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. - word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below - } if (s >= word_wrap_eol) { @@ -2767,13 +3492,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons text_size.y += line_height; line_width = 0.0f; word_wrap_eol = NULL; - - // Wrapping skips upcoming blanks - while (s < text_end) - { - const char c = *s; - if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } - } + s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks continue; } } @@ -2782,15 +3501,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons const char* prev_s = s; unsigned int c = (unsigned int)*s; if (c < 0x80) - { s += 1; - } else - { s += ImTextCharFromUtf8(&c, s, text_end); - if (c == 0) // Malformed UTF-8? - break; - } if (c < 32) { @@ -2827,45 +3540,56 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons return text_size; } -void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const { - if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. + const ImFontGlyph* glyph = FindGlyph(c); + if (!glyph || !glyph->Visible) return; - if (const ImFontGlyph* glyph = FindGlyph(c)) - { - float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; - pos.x = IM_FLOOR(pos.x + DisplayOffset.x); - pos.y = IM_FLOOR(pos.y + DisplayOffset.y); - draw_list->PrimReserve(6, 4); - draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); - } + if (glyph->Colored) + col |= ~IM_COL32_A_MASK; + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + float x = IM_FLOOR(pos.x); + float y = IM_FLOOR(pos.y); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); } -void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const { if (!text_end) text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. // Align to be pixel perfect - pos.x = IM_FLOOR(pos.x + DisplayOffset.x); - pos.y = IM_FLOOR(pos.y + DisplayOffset.y); - float x = pos.x; - float y = pos.y; + float x = IM_FLOOR(pos.x); + float y = IM_FLOOR(pos.y); if (y > clip_rect.w) return; + const float start_x = x; const float scale = size / FontSize; const float line_height = FontSize * scale; const bool word_wrap_enabled = (wrap_width > 0.0f); - const char* word_wrap_eol = NULL; // Fast-forward to first visible line const char* s = text_begin; - if (y + line_height < clip_rect.y && !word_wrap_enabled) + if (y + line_height < clip_rect.y) while (y + line_height < clip_rect.y && s < text_end) { - s = (const char*)memchr(s, '\n', text_end - s); - s = s ? s + 1 : text_end; + const char* line_end = (const char*)memchr(s, '\n', text_end - s); + if (word_wrap_enabled) + { + // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). + // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. + // However it is still better than nothing performing the fast-forward! + s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width); + s = CalcWordWrapNextLineStartA(s, text_end); + } + else + { + s = line_end ? line_end + 1 : text_end; + } y += line_height; } @@ -2891,10 +3615,12 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col const int idx_count_max = (int)(text_end - s) * 6; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; draw_list->PrimReserve(idx_count_max, vtx_count_max); + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_index = draw_list->_VtxCurrentIdx; - ImDrawVert* vtx_write = draw_list->_VtxWritePtr; - ImDrawIdx* idx_write = draw_list->_IdxWritePtr; - unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + const char* word_wrap_eol = NULL; while (s < text_end) { @@ -2902,24 +3628,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - { - word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); - if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. - word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below - } + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x)); if (s >= word_wrap_eol) { - x = pos.x; + x = start_x; y += line_height; word_wrap_eol = NULL; - - // Wrapping skips upcoming blanks - while (s < text_end) - { - const char c = *s; - if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } - } + s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks continue; } } @@ -2927,21 +3643,15 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col // Decode and advance source unsigned int c = (unsigned int)*s; if (c < 0x80) - { s += 1; - } else - { s += ImTextCharFromUtf8(&c, s, text_end); - if (c == 0) // Malformed UTF-8? - break; - } if (c < 32) { if (c == '\n') { - x = pos.x; + x = start_x; y += line_height; if (y > clip_rect.w) break; // break out of main loop @@ -2951,113 +3661,151 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col continue; } - float char_width = 0.0f; - if (const ImFontGlyph* glyph = FindGlyph((ImWchar)c)) - { - char_width = glyph->AdvanceX * scale; + const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + if (glyph == NULL) + continue; - // Arbitrarily assume that both space and tabs are empty glyphs as an optimization - if (c != ' ' && c != '\t') + float char_width = glyph->AdvanceX * scale; + if (glyph->Visible) + { + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + if (x1 <= clip_rect.z && x2 >= clip_rect.x) { - // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w - float x1 = x + glyph->X0 * scale; - float x2 = x + glyph->X1 * scale; - float y1 = y + glyph->Y0 * scale; - float y2 = y + glyph->Y1 * scale; - if (x1 <= clip_rect.z && x2 >= clip_rect.x) + // Render a character + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip) { - // Render a character - float u1 = glyph->U0; - float v1 = glyph->V0; - float u2 = glyph->U1; - float v2 = glyph->V1; - - // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. - if (cpu_fine_clip) + if (x1 < clip_rect.x) { - if (x1 < clip_rect.x) - { - u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); - x1 = clip_rect.x; - } - if (y1 < clip_rect.y) - { - v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); - y1 = clip_rect.y; - } - if (x2 > clip_rect.z) - { - u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); - x2 = clip_rect.z; - } - if (y2 > clip_rect.w) - { - v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); - y2 = clip_rect.w; - } - if (y1 >= y2) - { - x += char_width; - continue; - } + u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); + x1 = clip_rect.x; } - - // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + if (y1 < clip_rect.y) { - idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); - idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); - vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; - vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; - vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; - vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; - vtx_write += 4; - vtx_current_idx += 4; - idx_write += 6; + v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); + y1 = clip_rect.y; + } + if (x2 > clip_rect.z) + { + u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); + x2 = clip_rect.z; + } + if (y2 > clip_rect.w) + { + v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); + y2 = clip_rect.w; + } + if (y1 >= y2) + { + x += char_width; + continue; } } + + // Support for untinted glyphs + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + { + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2); + idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3); + vtx_write += 4; + vtx_index += 4; + idx_write += 6; + } } } - x += char_width; } // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); - draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); draw_list->_VtxWritePtr = vtx_write; draw_list->_IdxWritePtr = idx_write; - draw_list->_VtxCurrentIdx = vtx_current_idx; + draw_list->_VtxCurrentIdx = vtx_index; } //----------------------------------------------------------------------------- -// [SECTION] Internal Render Helpers -// (progressively moved from imgui.cpp to here when they are redesigned to stop accessing ImGui global state) +// [SECTION] ImGui Internal Render Helpers //----------------------------------------------------------------------------- -// - RenderMouseCursor() +// Vaguely redesigned to stop accessing ImGui global state: +// - RenderArrow() +// - RenderBullet() +// - RenderCheckMark() // - RenderArrowPointingAt() // - RenderRectFilledRangeH() +// - RenderRectFilledWithHole() +//----------------------------------------------------------------------------- +// Function in need of a redesign (legacy mess) +// - RenderColorRectWithAlphaCheckerboard() //----------------------------------------------------------------------------- -void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) { - if (mouse_cursor == ImGuiMouseCursor_None) - return; - IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + const float h = draw_list->_Data->FontSize * 1.00f; + float r = h * 0.40f * scale; + ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); - ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; - ImVec2 offset, size, uv[4]; - if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + ImVec2 a, b, c; + switch (dir) { - pos -= offset; - const ImTextureID tex_id = font_atlas->TexID; - draw_list->PushTextureID(tex_id); - draw_list->AddImage(tex_id, pos + ImVec2(1,0)*scale, pos + ImVec2(1,0)*scale + size*scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos + ImVec2(2,0)*scale, pos + ImVec2(2,0)*scale + size*scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos, pos + size*scale, uv[2], uv[3], col_border); - draw_list->AddImage(tex_id, pos, pos + size*scale, uv[0], uv[1], col_fill); - draw_list->PopTextureID(); + case ImGuiDir_Up: + case ImGuiDir_Down: + if (dir == ImGuiDir_Up) r = -r; + a = ImVec2(+0.000f, +0.750f) * r; + b = ImVec2(-0.866f, -0.750f) * r; + c = ImVec2(+0.866f, -0.750f) * r; + break; + case ImGuiDir_Left: + case ImGuiDir_Right: + if (dir == ImGuiDir_Left) r = -r; + a = ImVec2(+0.750f, +0.000f) * r; + b = ImVec2(-0.750f, +0.866f) * r; + c = ImVec2(-0.750f, -0.866f) * r; + break; + case ImGuiDir_None: + case ImGuiDir_COUNT: + IM_ASSERT(0); + break; } + draw_list->AddTriangleFilled(center + a, center + b, center + c, col); +} + +void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +{ + // FIXME-OPT: This should be baked in font. + draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); +} + +void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) +{ + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + float third = sz / 3.0f; + float bx = pos.x + third; + float by = pos.y + sz - third * 0.5f; + draw_list->PathLineTo(ImVec2(bx - third, by - third)); + draw_list->PathLineTo(ImVec2(bx, by)); + draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); + draw_list->PathStroke(col, 0, thickness); } // Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. @@ -3142,6 +3890,63 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathFillConvex(col); } +void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding) +{ + const bool fill_L = (inner.Min.x > outer.Min.x); + const bool fill_R = (inner.Max.x < outer.Max.x); + const bool fill_U = (inner.Min.y > outer.Min.y); + const bool fill_D = (inner.Max.y < outer.Max.y); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); +} + +// Helper for ColorPicker4() +// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. +// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. +// FIXME: uses ImGui::GetColorU32 +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) +{ + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags = ImDrawFlags_RoundCornersDefault_; + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); + + int yi = 0; + for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) + { + float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + if (y2 <= y1) + continue; + for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + { + float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + if (x2 <= x1) + continue; + ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; + if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } + + // Combine flags + cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags); + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags); + } + } + } + else + { + draw_list->AddRectFilled(p_min, p_max, col, rounding, flags); + } +} + //----------------------------------------------------------------------------- // [SECTION] Decompression code //----------------------------------------------------------------------------- @@ -3273,7 +4078,7 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. //----------------------------------------------------------------------------- -static const char proggy_clean_ttf_compressed_data_base85[11980+1] = +static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a // FILE*, sscanf @@ -36,85 +57,140 @@ Index of this file: #include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf #include // INT_MIN, INT_MAX +// Enable SSE intrinsics if available +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) +#define IMGUI_ENABLE_SSE +#include +#endif + // Visual Studio warnings #ifdef _MSC_VER #pragma warning (push) -#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 26812) // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif #endif // Clang/GCC warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h -#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned() +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h #pragma clang diagnostic ignored "-Wold-style-cast" -#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif -#if __has_warning("-Wdouble-promotion") #pragma clang diagnostic ignored "-Wdouble-promotion" -#endif +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h +// As they are frequently requested, we do not want to encourage to many people using imgui_internal.h +#if defined(IMGUI_DEFINE_MATH_OPERATORS) && !defined(IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED) +#error Please '#define IMGUI_DEFINE_MATH_OPERATORS' _BEFORE_ including imgui.h! #endif // Legacy defines -#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 #error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS #endif -#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 #error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS #endif +// Enable stb_truetype by default unless FreeType is enabled. +// You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together. +#ifndef IMGUI_ENABLE_FREETYPE +#define IMGUI_ENABLE_STB_TRUETYPE +#endif + //----------------------------------------------------------------------------- -// Forward declarations +// [SECTION] Forward declarations //----------------------------------------------------------------------------- -struct ImBoolVector; // Store 1-bit per value +struct ImBitVector; // Store 1-bit per value struct ImRect; // An axis-aligned rectangle (2 points) struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it -struct ImGuiColumnData; // Storage data for a single column -struct ImGuiColumns; // Storage data for a columns set struct ImGuiContext; // Main Dear ImGui context +struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine +struct ImGuiDataVarInfo; // Variable information (e.g. to avoid style variables from an enum) struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box -struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data +struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id +struct ImGuiLastItemData; // Status storage for last submitted items +struct ImGuiLocEntry; // A localization entry. struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only -struct ImGuiNavMoveResult; // Result of a directional navigation move query result +struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions +struct ImGuiOldColumnData; // Storage data for a single column for legacy Columns() api +struct ImGuiOldColumns; // Storage data for a columns set for legacy Columns() api struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) +struct ImGuiTable; // Storage for a table +struct ImGuiTableColumn; // Storage for one column of a table +struct ImGuiTableInstanceData; // Storage for one instance of a same table +struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables. +struct ImGuiTableSettings; // Storage for a table .ini settings +struct ImGuiTableColumnsSettings; // Storage for a column .ini settings struct ImGuiWindow; // Storage for one window -struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) +struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) +// Enumerations // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +enum ImGuiLocKey : int; // -> enum ImGuiLocKey // Enum: a localization entry for translation. typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical -typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() -typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: BeginColumns() -typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() -typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() -typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags + +// Flags +typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) +typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags +typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow(); +typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for IsKeyPressed(), IsMouseClicked(), SetKeyOwner(), SetItemKeyOwner() etc. +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags +typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() -typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions +typedef int ImGuiScrollFlags; // -> enum ImGuiScrollFlags_ // Flags: for ScrollToItem() and navigation requests typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() -typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() +typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() + +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); + +//----------------------------------------------------------------------------- +// [SECTION] Context pointer +// See implementation of this variable in imgui.cpp for comments and details. +//----------------------------------------------------------------------------- + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer +#endif //------------------------------------------------------------------------- -// STB libraries includes +// [SECTION] STB libraries includes //------------------------------------------------------------------------- namespace ImStb @@ -124,7 +200,7 @@ namespace ImStb #undef STB_TEXTEDIT_CHARTYPE #define STB_TEXTEDIT_STRING ImGuiInputTextState #define STB_TEXTEDIT_CHARTYPE ImWchar -#define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f +#define STB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) #define STB_TEXTEDIT_UNDOSTATECOUNT 99 #define STB_TEXTEDIT_UNDOCHARCOUNT 999 #include "imstb_textedit.h" @@ -132,41 +208,49 @@ namespace ImStb } // namespace ImStb //----------------------------------------------------------------------------- -// Context pointer +// [SECTION] Macros //----------------------------------------------------------------------------- -#ifndef GImGui -extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer +// Debug Printing Into TTY +// (since IMGUI_VERSION_NUM >= 18729: IMGUI_DEBUG_LOG was reworked into IMGUI_DEBUG_PRINTF (and removed framecount from it). If you were using a #define IMGUI_DEBUG_LOG please rename) +#ifndef IMGUI_DEBUG_PRINTF +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#define IMGUI_DEBUG_PRINTF(_FMT,...) printf(_FMT, __VA_ARGS__) +#else +#define IMGUI_DEBUG_PRINTF(_FMT,...) ((void)0) +#endif #endif -//----------------------------------------------------------------------------- -// Macros -//----------------------------------------------------------------------------- - -// Debug Logging -#ifndef IMGUI_DEBUG_LOG -#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) +// Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#else +#define IMGUI_DEBUG_LOG(...) ((void)0) #endif +#define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Static Asserts -#if (__cplusplus >= 201100) #define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") -#else -#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] -#endif // "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. -#define IMGUI_DEBUG_PARANOID 0 -#if IMGUI_DEBUG_PARANOID +// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. +//#define IMGUI_DEBUG_PARANOID +#ifdef IMGUI_DEBUG_PARANOID #define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) #else -#define IM_ASSERT_PARANOID(_EXPR) +#define IM_ASSERT_PARANOID(_EXPR) #endif // Error handling // Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. #ifndef IM_ASSERT_USER_ERROR -#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && (_MSG)) // Recoverable User Error +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error #endif // Misc Macros @@ -176,7 +260,10 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #else #define IM_NEWLINE "\n" #endif +#ifndef IM_TABSIZE // Until we move this to runtime and/or add proper tab support, at least allow users to compile-time override #define IM_TABSIZE (4) +#endif +#define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds @@ -189,34 +276,75 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_CDECL #endif +// Warnings +#if defined(_MSC_VER) && !defined(__clang__) +#define IM_MSVC_WARNING_SUPPRESS(XXXX) __pragma(warning(suppress: XXXX)) +#else +#define IM_MSVC_WARNING_SUPPRESS(XXXX) +#endif + +// Debug Tools +// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item. +// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference. +#ifndef IM_DEBUG_BREAK +#if defined (_MSC_VER) +#define IM_DEBUG_BREAK() __debugbreak() +#elif defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define IM_DEBUG_BREAK() __asm__ volatile("int $0x03") +#elif defined(__GNUC__) && defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0"); +#else +#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! +#endif +#endif // #ifndef IM_DEBUG_BREAK + //----------------------------------------------------------------------------- -// Generic helpers +// [SECTION] Generic helpers +// Note that the ImXXX helpers functions are lower-level than ImGui functions. +// ImGui functions or the ImGui context are never called/used from other ImXXX functions. //----------------------------------------------------------------------------- -// - Helpers: Misc +// - Helpers: Hashing +// - Helpers: Sorting // - Helpers: Bit manipulation -// - Helpers: String, Formatting +// - Helpers: String +// - Helpers: Formatting // - Helpers: UTF-8 <> wchar conversions // - Helpers: ImVec2/ImVec4 operators // - Helpers: Maths // - Helpers: Geometry -// - Helper: ImBoolVector +// - Helper: ImVec1 +// - Helper: ImVec2ih +// - Helper: ImRect +// - Helper: ImBitArray +// - Helper: ImBitVector +// - Helper: ImSpan<>, ImSpanAllocator<> // - Helper: ImPool<> // - Helper: ImChunkStream<> +// - Helper: ImGuiTextIndex //----------------------------------------------------------------------------- -// Helpers: Misc -#define ImQsort qsort -IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); -IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] +// Helpers: Hashing +IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0); +IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0); + +// Helpers: Sorting +#ifndef ImQsort +static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } #endif +// Helpers: Color Blending +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); + // Helpers: Bit manipulation static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } -// Helpers: String, Formatting +// Helpers: String IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); @@ -229,46 +357,34 @@ IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* bu IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); IMGUI_API void ImStrTrimBlanks(char* str); IMGUI_API const char* ImStrSkipBlank(const char* str); +IM_MSVC_RUNTIME_CHECKS_OFF +static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helpers: Formatting IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API const char* ImParseFormatFindStart(const char* format); IMGUI_API const char* ImParseFormatFindEnd(const char* format); IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); +IMGUI_API void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size); +IMGUI_API const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); -static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } -static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } // Helpers: UTF-8 <> wchar conversions -IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count -IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count -IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count -IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) -IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 -IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 - -// Helpers: ImVec2/ImVec4 operators -// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) -// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. -#ifdef IMGUI_DEFINE_MATH_OPERATORS -static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } -static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } -static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); } -static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } -static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); } -static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w); } -static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } -#endif +IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf +IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 // Helpers: File System -#if defined(__EMSCRIPTEN__) && !defined(IMGUI_DISABLE_FILE_FUNCTIONS) -#define IMGUI_DISABLE_FILE_FUNCTIONS -#endif #ifdef IMGUI_DISABLE_FILE_FUNCTIONS #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS typedef void* ImFileHandle; @@ -278,7 +394,6 @@ static inline ImU64 ImFileGetSize(ImFileHandle) static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } #endif - #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS typedef FILE* ImFileHandle; IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); @@ -292,24 +407,37 @@ IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 coun IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); // Helpers: Maths +IM_MSVC_RUNTIME_CHECKS_OFF // - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) #ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS -static inline float ImFabs(float x) { return fabsf(x); } -static inline float ImSqrt(float x) { return sqrtf(x); } -static inline float ImPow(float x, float y) { return powf(x, y); } -static inline double ImPow(double x, double y) { return pow(x, y); } -static inline float ImFmod(float x, float y) { return fmodf(x, y); } -static inline double ImFmod(double x, double y) { return fmod(x, y); } -static inline float ImCos(float x) { return cosf(x); } -static inline float ImSin(float x) { return sinf(x); } -static inline float ImAcos(float x) { return acosf(x); } -static inline float ImAtan2(float y, float x) { return atan2f(y, x); } -static inline double ImAtof(const char* s) { return atof(s); } -static inline float ImFloorStd(float x) { return floorf(x); } // we already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by stb_truetype) -static inline float ImCeil(float x) { return ceilf(x); } +#define ImFabs(X) fabsf(X) +#define ImSqrt(X) sqrtf(X) +#define ImFmod(X, Y) fmodf((X), (Y)) +#define ImCos(X) cosf(X) +#define ImSin(X) sinf(X) +#define ImAcos(X) acosf(X) +#define ImAtan2(Y, X) atan2f((Y), (X)) +#define ImAtof(STR) atof(STR) +//#define ImFloorStd(X) floorf(X) // We use our own, see ImFloor() and ImFloorSigned() +#define ImCeil(X) ceilf(X) +static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision +static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision +static inline double ImLog(double x) { return log(x); } +static inline int ImAbs(int x) { return x < 0 ? -x : x; } +static inline float ImAbs(float x) { return fabsf(x); } +static inline double ImAbs(double x) { return fabs(x); } +static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument +static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } +#ifdef IMGUI_ENABLE_SSE +static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +#else +static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +#endif +static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } #endif -// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support for variety of types: signed/unsigned int/long long float/double -// (Exceptionally using templates here but we could also redefine them for variety of types) +// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double +// (Exceptionally using templates here but we could also redefine them for those types) template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } @@ -325,35 +453,191 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } -static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } -static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } -static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; } +static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } +static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } +static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } static inline float ImFloor(float f) { return (float)(int)(f); } +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +static inline ImVec2 ImFloorSigned(const ImVec2& v) { return ImVec2(ImFloorSigned(v.x), ImFloorSigned(v.y)); } static inline int ImModPositive(int a, int b) { return (a + b) % b; } static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } +static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; } +IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry +IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); +IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments +IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol +IMGUI_API ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t); IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } -IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); -// Helper: ImBoolVector -// Store 1-bit per value. Note that Resize() currently clears the whole vector. -struct IMGUI_API ImBoolVector +// Helper: ImVec1 (1D vector) +// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImVec1 +{ + float x; + constexpr ImVec1() : x(0.0f) { } + constexpr ImVec1(float _x) : x(_x) { } +}; + +// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) +struct ImVec2ih { - ImVector Storage; - ImBoolVector() { } - void Resize(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } - void Clear() { Storage.clear(); } - bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (Storage[off] & mask) != 0; } - void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; } + short x, y; + constexpr ImVec2ih() : x(0), y(0) {} + constexpr ImVec2ih(short _x, short _y) : x(_x), y(_y) {} + constexpr explicit ImVec2ih(const ImVec2& rhs) : x((short)rhs.x), y((short)rhs.y) {} +}; + +// Helper: ImRect (2D axis aligned bounding-box) +// NB: we can't rely on ImVec2 math operators being available here! +struct IMGUI_API ImRect +{ + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right + + constexpr ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + constexpr ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + constexpr ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + constexpr ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + + ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } + float GetWidth() const { return Max.x - Min.x; } + float GetHeight() const { return Max.y - Min.y; } + float GetArea() const { return (Max.x - Min.x) * (Max.y - Min.y); } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } + void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } + void TranslateX(float dx) { Min.x += dx; Max.x += dx; } + void TranslateY(float dy) { Min.y += dy; Max.y += dy; } + void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. + void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } + bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } + ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } +}; + +// Helper: ImBitArray +#define IM_BITARRAY_TESTBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly! +#define IM_BITARRAY_CLEARBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31)))) // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly! +inline size_t ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; } +inline void ImBitArrayClearAllBits(ImU32* arr, int bitcount){ memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); } +inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } +inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } +inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } +inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on range [n..n2) +{ + n2--; + while (n <= n2) + { + int a_mod = (n & 31); + int b_mod = (n2 > (n | 31) ? 31 : (n2 & 31)) + 1; + ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); + arr[n >> 5] |= mask; + n = (n + 32) & ~31; + } +} + +typedef ImU32* ImBitArrayPtr; // Name for use in structs + +// Helper: ImBitArray class (wrapper over ImBitArray functions) +// Store 1-bit per value. +template +struct ImBitArray +{ + ImU32 Storage[(BITCOUNT + 31) >> 5]; + ImBitArray() { ClearAllBits(); } + void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } + void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } + bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } + void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } + void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } + void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) + bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } +}; + +// Helper: ImBitVector +// Store 1-bit per value. +struct IMGUI_API ImBitVector +{ + ImVector Storage; + void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); } + void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } + void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helper: ImSpan<> +// Pointing to a span of data we don't own. +template +struct ImSpan +{ + T* Data; + T* DataEnd; + + // Constructors, destructor + inline ImSpan() { Data = DataEnd = NULL; } + inline ImSpan(T* data, int size) { Data = data; DataEnd = data + size; } + inline ImSpan(T* data, T* data_end) { Data = data; DataEnd = data_end; } + + inline void set(T* data, int size) { Data = data; DataEnd = data + size; } + inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; } + inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } + inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } + inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + inline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return DataEnd; } + inline const T* end() const { return DataEnd; } + + // Utilities + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; } +}; + +// Helper: ImSpanAllocator<> +// Facilitate storing multiple chunks into a single large block (the "arena") +// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges. +template +struct ImSpanAllocator +{ + char* BasePtr; + int CurrOff; + int CurrIdx; + int Offsets[CHUNKS]; + int Sizes[CHUNKS]; + + ImSpanAllocator() { memset(this, 0, sizeof(*this)); } + inline void Reserve(int n, size_t sz, int a=4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; } + inline int GetArenaSizeInBytes() { return CurrOff; } + inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } + inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); } + inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); } + template + inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } }; // Helper: ImPool<> @@ -361,330 +645,362 @@ struct IMGUI_API ImBoolVector // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. typedef int ImPoolIdx; template -struct IMGUI_API ImPool +struct ImPool { ImVector Buf; // Contiguous data ImGuiStorage Map; // ID->Index ImPoolIdx FreeIdx; // Next free idx to use + ImPoolIdx AliveCount; // Number of active/alive items (for display purpose) - ImPool() { FreeIdx = 0; } + ImPool() { FreeIdx = AliveCount = 0; } ~ImPool() { Clear(); } T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } - void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; } - T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = AliveCount = 0; } + T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); AliveCount++; return &Buf[idx]; } void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } - void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } + void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); AliveCount--; } void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } - int GetSize() const { return Buf.Size; } + + // To iterate a ImPool: for (int n = 0; n < pool.GetMapSize(); n++) if (T* t = pool.TryGetMapData(n)) { ... } + // Can be avoided if you know .Remove() has never been called on the pool, or AliveCount == GetMapSize() + int GetAliveCount() const { return AliveCount; } // Number of active/alive items in the pool (for display purpose) + int GetBufSize() const { return Buf.Size; } + int GetMapSize() const { return Map.Data.Size; } // It is the map we need iterate to find valid items, since we don't have "alive" storage anywhere + T* TryGetMapData(ImPoolIdx n) { int idx = Map.Data[n].val_i; if (idx == -1) return NULL; return GetByIndex(idx); } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + int GetSize() { return GetMapSize(); } // For ImPlot: should use GetMapSize() from (IMGUI_VERSION_NUM >= 18304) +#endif }; // Helper: ImChunkStream<> // Build and iterate a contiguous stream of variable-sized structures. // This is used by Settings to store persistent data while reducing allocation count. -// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for) +// We store the chunk size first, and align the final size on 4 bytes boundaries. // The tedious/zealous amount of casting is to avoid -Wcast-align warnings. template -struct IMGUI_API ImChunkStream +struct ImChunkStream { ImVector Buf; void clear() { Buf.clear(); } bool empty() const { return Buf.Size == 0; } int size() const { return Buf.Size; } - T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } + T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } int chunk_size(const T* p) { return ((const int*)p)[-1]; } T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } + void swap(ImChunkStream& rhs) { rhs.Buf.swap(Buf); } + +}; + +// Helper: ImGuiTextIndex<> +// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API. +struct ImGuiTextIndex +{ + ImVector LineOffsets; + int EndOffset = 0; // Because we don't own text buffer we need to maintain EndOffset (may bake in LineOffsets?) + + void clear() { LineOffsets.clear(); EndOffset = 0; } + int size() { return LineOffsets.Size; } + const char* get_line_begin(const char* base, int n) { return base + LineOffsets[n]; } + const char* get_line_end(const char* base, int n) { return base + (n + 1 < LineOffsets.Size ? (LineOffsets[n + 1] - 1) : EndOffset); } + void append(const char* base, int old_size, int new_size); }; //----------------------------------------------------------------------------- -// Misc data structures +// [SECTION] ImDrawList support //----------------------------------------------------------------------------- -enum ImGuiButtonFlags_ -{ - ImGuiButtonFlags_None = 0, - ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat - ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // [Default] return true on click + release on same item - ImGuiButtonFlags_PressedOnClick = 1 << 2, // return true on click (default requires click+release) - ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return true on release (default requires click+release) - ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return true on double-click (default requires click+release) - ImGuiButtonFlags_FlattenChildren = 1 << 5, // allow interactions even if a child window is overlapping - ImGuiButtonFlags_AllowItemOverlap = 1 << 6, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() - ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] - ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions - ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine - ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable mouse interaction if a key modifier is held - ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) - ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) - ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated - ImGuiButtonFlags_NoHoveredOnNav = 1 << 14 // don't report as hovered when navigated on -}; +// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. +// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693 +// Number of segments (N) is calculated using equation: +// N = ceil ( pi / acos(1 - error / r) ) where r > 0, error <= r +// Our equation is significantly simpler that one in the post thanks for choosing segment that is +// perpendicular to X axis. Follow steps in the article from this starting condition and you will +// will get this result. +// +// Rendering circles with an odd number of segments, while mathematically correct will produce +// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.) +#define IM_ROUNDUP_TO_EVEN(_V) ((((_V) + 1) / 2) * 2) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +// Raw equation from IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC rewritten for 'r' and 'error'. +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR) ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI)))) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD) ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD)) + +// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle. +#ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE +#define IM_DRAWLIST_ARCFAST_TABLE_SIZE 48 // Number of samples in lookup table. +#endif +#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. -enum ImGuiSliderFlags_ +// Data shared between all ImDrawList instances +// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +struct IMGUI_API ImDrawListSharedData { - ImGuiSliderFlags_None = 0, - ImGuiSliderFlags_Vertical = 1 << 0 -}; + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() + float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) -enum ImGuiDragFlags_ -{ - ImGuiDragFlags_None = 0, - ImGuiDragFlags_Vertical = 1 << 0 -}; + // [Internal] Temp write buffer + ImVector TempBuffer; -enum ImGuiColumnsFlags_ -{ - // Default: 0 - ImGuiColumnsFlags_None = 0, - ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers - ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers - ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns - ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window - ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. -}; + // [Internal] Lookup tables + ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. + float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() + ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas -// Extend ImGuiSelectableFlags_ -enum ImGuiSelectableFlagsPrivate_ -{ - // NB: need to be in sync with last value of ImGuiSelectableFlags_ - ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, - ImGuiSelectableFlags_PressedOnClick = 1 << 21, - ImGuiSelectableFlags_PressedOnRelease = 1 << 22, - ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 23, // FIXME: We may be able to remove this (added in 6251d379 for menus) - ImGuiSelectableFlags_DrawHoveredWhenHeld= 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. - ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25 + ImDrawListSharedData(); + void SetCircleTessellationMaxError(float max_error); }; -// Extend ImGuiTreeNodeFlags_ -enum ImGuiTreeNodeFlagsPrivate_ +struct ImDrawDataBuilder { - ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 -}; + ImVector Layers[2]; // Global layers for: regular, tooltip -enum ImGuiSeparatorFlags_ -{ - ImGuiSeparatorFlags_None = 0, - ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar - ImGuiSeparatorFlags_Vertical = 1 << 1, - ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + int GetDrawListCount() const { int count = 0; for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) count += Layers[n].Size; return count; } + IMGUI_API void FlattenIntoSingleLayer(); }; -// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +//----------------------------------------------------------------------------- +// [SECTION] Widgets support: flags, enums, data structures +//----------------------------------------------------------------------------- + +// Flags used by upcoming items +// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags. +// - output: stored in g.LastItemData.InFlags +// Current window shared by all windows. // This is going to be exposed in imgui.h when stabilized enough. enum ImGuiItemFlags_ { + // Controlled by user ImGuiItemFlags_None = 0, - ImGuiItemFlags_NoTabStop = 1 << 0, // false - ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. - ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 - ImGuiItemFlags_NoNav = 1 << 3, // false - ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false - ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window - ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) - ImGuiItemFlags_Default_ = 0 + ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav. + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls) + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items) + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window + ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) + ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. + ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() + + // Controlled by widget code + ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. }; -// Storage for LastItem data +// Status flags for an already submitted item +// - output: stored in g.LastItemData.StatusFlags enum ImGuiItemStatusFlags_ { ImGuiItemStatusFlags_None = 0, - ImGuiItemStatusFlags_HoveredRect = 1 << 0, - ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test) + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // g.LastItemData.DisplayRect is valid ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) - ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. - ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues. + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. - ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_Deactivated = 1 << 6, // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_HoveredWindow = 1 << 7, // Override the HoveredWindow test to allow cross-window hover testing. + ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Set when the Focusable item just got focused by Tabbing (FIXME: to be removed soon) + ImGuiItemStatusFlags_Visible = 1 << 9, // [WIP] Set when item is overlapping the current clipping rectangle (Used internally. Please don't use yet: API/system will change as we refactor Itemadd()). + // Additional status + semantic for ImGuiTestEngine #ifdef IMGUI_ENABLE_TEST_ENGINE - , // [imgui_tests only] - ImGuiItemStatusFlags_Openable = 1 << 10, // - ImGuiItemStatusFlags_Opened = 1 << 11, // - ImGuiItemStatusFlags_Checkable = 1 << 12, // - ImGuiItemStatusFlags_Checked = 1 << 13 // + ImGuiItemStatusFlags_Openable = 1 << 20, // Item is an openable (e.g. TreeNode) + ImGuiItemStatusFlags_Opened = 1 << 21, // Opened status + ImGuiItemStatusFlags_Checkable = 1 << 22, // Item is a checkable (e.g. CheckBox, MenuItem) + ImGuiItemStatusFlags_Checked = 1 << 23, // Checked status + ImGuiItemStatusFlags_Inputable = 1 << 24, // Item is a text-inputable (e.g. InputText, SliderXXX, DragXXX) #endif }; -enum ImGuiTextFlags_ +// Extend ImGuiInputTextFlags_ +enum ImGuiInputTextFlagsPrivate_ { - ImGuiTextFlags_None = 0, - ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_MergedItem = 1 << 28, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. }; -// FIXME: this is in development, not exposed/functional as a generic feature yet. -// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 -enum ImGuiLayoutType_ +// Extend ImGuiButtonFlags_ +enum ImGuiButtonFlagsPrivate_ { - ImGuiLayoutType_Horizontal = 0, - ImGuiLayoutType_Vertical = 1 + ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event) + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item + ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) + ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat + ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] + //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used everytime an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.InFlags) + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item + ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, }; -enum ImGuiLogType +// Extend ImGuiComboFlags_ +enum ImGuiComboFlagsPrivate_ { - ImGuiLogType_None = 0, - ImGuiLogType_TTY, - ImGuiLogType_File, - ImGuiLogType_Buffer, - ImGuiLogType_Clipboard + ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview() }; -// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 -enum ImGuiAxis +// Extend ImGuiSliderFlags_ +enum ImGuiSliderFlagsPrivate_ { - ImGuiAxis_None = -1, - ImGuiAxis_X = 0, - ImGuiAxis_Y = 1 + ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically? + ImGuiSliderFlags_ReadOnly = 1 << 21, }; -enum ImGuiPlotType +// Extend ImGuiSelectableFlags_ +enum ImGuiSelectableFlagsPrivate_ { - ImGuiPlotType_Lines, - ImGuiPlotType_Histogram + // NB: need to be in sync with last value of ImGuiSelectableFlags_ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnNav = 1 << 21, // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API. + ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release) + ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release) + ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem) + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26, // Disable padding each side with ItemSpacing * 0.5f + ImGuiSelectableFlags_NoSetKeyOwner = 1 << 27, // Don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) }; -enum ImGuiInputSource +// Extend ImGuiTreeNodeFlags_ +enum ImGuiTreeNodeFlagsPrivate_ { - ImGuiInputSource_None = 0, - ImGuiInputSource_Mouse, - ImGuiInputSource_Nav, - ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code - ImGuiInputSource_NavGamepad, // " - ImGuiInputSource_COUNT + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20, }; -// FIXME-NAV: Clarify/expose various repeat delay/rate -enum ImGuiInputReadMode +enum ImGuiSeparatorFlags_ { - ImGuiInputReadMode_Down, - ImGuiInputReadMode_Pressed, - ImGuiInputReadMode_Released, - ImGuiInputReadMode_Repeat, - ImGuiInputReadMode_RepeatSlow, - ImGuiInputReadMode_RepeatFast + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2, // Make separator cover all columns of a legacy Columns() set. }; -enum ImGuiNavHighlightFlags_ +// Flags for FocusWindow(). This is not called ImGuiFocusFlags to avoid confusion with public-facing ImGuiFocusedFlags. +// FIXME: Once we finishing replacing more uses of GetTopMostPopupModal()+IsWindowWithinBeginStackOf() +// and FindBlockingModal() with this, we may want to change the flag to be opt-out instead of opt-in. +enum ImGuiFocusRequestFlags_ { - ImGuiNavHighlightFlags_None = 0, - ImGuiNavHighlightFlags_TypeDefault = 1 << 0, - ImGuiNavHighlightFlags_TypeThin = 1 << 1, - ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. - ImGuiNavHighlightFlags_NoRounding = 1 << 3 + ImGuiFocusRequestFlags_None = 0, + ImGuiFocusRequestFlags_RestoreFocusedChild = 1 << 0, // Find last focused child (if any) and focus it instead. + ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 1, // Do not set focus if the window is below a modal. }; -enum ImGuiNavDirSourceFlags_ +enum ImGuiTextFlags_ { - ImGuiNavDirSourceFlags_None = 0, - ImGuiNavDirSourceFlags_Keyboard = 1 << 0, - ImGuiNavDirSourceFlags_PadDPad = 1 << 1, - ImGuiNavDirSourceFlags_PadLStick = 1 << 2 + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0, }; -enum ImGuiNavMoveFlags_ +enum ImGuiTooltipFlags_ { - ImGuiNavMoveFlags_None = 0, - ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side - ImGuiNavMoveFlags_LoopY = 1 << 1, - ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) - ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness - ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) - ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible. - ImGuiNavMoveFlags_ScrollToEdge = 1 << 6 + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0, // Override will clear/ignore previously submitted tooltip (defaults to append) }; -enum ImGuiNavForward +// FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiLayoutType_ { - ImGuiNavForward_None, - ImGuiNavForward_ForwardQueued, - ImGuiNavForward_ForwardActive + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 }; -enum ImGuiNavLayer +enum ImGuiLogType { - ImGuiNavLayer_Main = 0, // Main scrolling layer - ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) - ImGuiNavLayer_COUNT + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard, }; -enum ImGuiPopupPositionPolicy +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiAxis { - ImGuiPopupPositionPolicy_Default, - ImGuiPopupPositionPolicy_ComboBox + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 }; -// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) -struct ImVec1 +enum ImGuiPlotType { - float x; - ImVec1() { x = 0.0f; } - ImVec1(float _x) { x = _x; } + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram, }; -// 2D vector (half-size integer) -struct ImVec2ih +enum ImGuiPopupPositionPolicy { - short x, y; - ImVec2ih() { x = y = 0; } - ImVec2ih(short _x, short _y) { x = _x; y = _y; } + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip, }; -// 2D axis aligned bounding-box -// NB: we can't rely on ImVec2 math operators being available here -struct IMGUI_API ImRect +struct ImGuiDataVarInfo { - ImVec2 Min; // Upper-left - ImVec2 Max; // Lower-right - - ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {} - ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} - ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} - ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + ImGuiDataType Type; + ImU32 Count; // 1+ + ImU32 Offset; // Offset in parent structure + void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); } +}; - ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } - ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } - float GetWidth() const { return Max.x - Min.x; } - float GetHeight() const { return Max.y - Min.y; } - ImVec2 GetTL() const { return Min; } // Top-left - ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right - ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left - ImVec2 GetBR() const { return Max; } // Bottom-right - bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } - bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } - bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } - void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } - void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } - void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } - void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } - void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } - void TranslateX(float dx) { Min.x += dx; Max.x += dx; } - void TranslateY(float dy) { Min.y += dy; Max.y += dy; } - void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. - void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. - void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } - bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT }; // Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo(). struct ImGuiDataTypeInfo { - size_t Size; // Size in byte + size_t Size; // Size in bytes + const char* Name; // Short descriptive name for the type, for debugging const char* PrintFmt; // Default printf format for the type const char* ScanFmt; // Default scanf format for the type }; +// Extend ImGuiDataType_ +enum ImGuiDataTypePrivate_ +{ + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID, +}; + // Stacked color modifier, backup of modified data so we can restore it struct ImGuiColorMod { - ImGuiCol Col; - ImVec4 BackupValue; + ImGuiCol Col; + ImVec4 BackupValue; }; // Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. @@ -697,9 +1013,23 @@ struct ImGuiStyleMod ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } }; +// Storage data for BeginComboPreview()/EndComboPreview() +struct IMGUI_API ImGuiComboPreviewData +{ + ImRect PreviewRect; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; + float BackupPrevLineTextBaseOffset; + ImGuiLayoutType BackupLayout; + + ImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); } +}; + // Stacked storage data for BeginGroup()/EndGroup() -struct ImGuiGroupData +struct IMGUI_API ImGuiGroupData { + ImGuiID WindowID; ImVec2 BackupCursorPos; ImVec2 BackupCursorMaxPos; ImVec1 BackupIndent; @@ -708,27 +1038,44 @@ struct ImGuiGroupData float BackupCurrLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; bool EmitItem; }; // Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. struct IMGUI_API ImGuiMenuColumns { - float Spacing; - float Width, NextWidth; - float Pos[3], NextWidths[3]; - - ImGuiMenuColumns(); - void Update(int count, float spacing, bool clear); - float DeclColumns(float w0, float w1, float w2); - float CalcExtraSpace(float avail_w) const; + ImU32 TotalWidth; + ImU32 NextTotalWidth; + ImU16 Spacing; + ImU16 OffsetIcon; // Always zero for now + ImU16 OffsetLabel; // Offsets are locked in Update() + ImU16 OffsetShortcut; + ImU16 OffsetMark; + ImU16 Widths[4]; // Width of: Icon, Label, Shortcut, Mark (accumulators for current frame) + + ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } + void Update(float spacing, bool window_reappearing); + float DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark); + void CalcNextTotalWidth(bool update_offsets); }; +// Internal temporary state for deactivating InputText() instances. +struct IMGUI_API ImGuiInputTextDeactivatedState +{ + ImGuiID ID; // widget id owning the text state (which just got deactivated) + ImVector TextA; // text buffer + + ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } + void ClearFreeMemory() { ID = 0; TextA.clear(); } +}; // Internal state of the currently focused/edited text input box +// For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState { + ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). ImGuiID ID; // widget id owning the text state - int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 len is valid even if TextA is not. + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. ImVector InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) @@ -739,9 +1086,8 @@ struct IMGUI_API ImGuiInputTextState float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection - ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback - ImGuiInputTextCallback UserCallback; // " - void* UserCallbackData; // " + bool Edited; // edited this frame + ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } @@ -755,63 +1101,451 @@ struct IMGUI_API ImGuiInputTextState void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } bool HasSelection() const { return Stb.select_start != Stb.select_end; } void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + int GetCursorPos() const { return Stb.cursor; } + int GetSelectionStart() const { return Stb.select_start; } + int GetSelectionEnd() const { return Stb.select_end; } void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } }; -// Windows data saved in imgui.ini file -// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. -// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) -struct ImGuiWindowSettings +// Storage for current popup stack +struct ImGuiPopupData { - ImGuiID ID; - ImVec2ih Pos; - ImVec2ih Size; - bool Collapsed; + ImGuiID PopupId; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* BackupNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close + int ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as "not any of layers" value + int OpenFrameCount; // Set on OpenPopup() + ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) + ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) + ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup - ImGuiWindowSettings() { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; } - char* GetName() { return (char*)(this + 1); } + ImGuiPopupData() { memset(this, 0, sizeof(*this)); ParentNavLayer = OpenFrameCount = -1; } +}; + +enum ImGuiNextWindowDataFlags_ +{ + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7, +}; + +// Storage for SetNexWindow** functions +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; // Override background alpha + ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) + + ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } +}; + +enum ImGuiNextItemDataFlags_ +{ + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1, +}; + +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; // Set by SetNextItemWidth() + ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) + ImGuiCond OpenCond; + bool OpenVal; // Set by SetNextItemOpen() + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! +}; + +// Status storage for the last submitted item +struct ImGuiLastItemData +{ + ImGuiID ID; + ImGuiItemFlags InFlags; // See ImGuiItemFlags_ + ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ + ImRect Rect; // Full rectangle + ImRect NavRect; // Navigation scoring rectangle (not displayed) + ImRect DisplayRect; // Display rectangle (only if ImGuiItemStatusFlags_HasDisplayRect is set) + + ImGuiLastItemData() { memset(this, 0, sizeof(*this)); } +}; + +struct IMGUI_API ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfItemFlagsStack; + short SizeOfBeginPopupStack; + short SizeOfDisabledStack; + + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + void SetToContextState(ImGuiContext* ctx); + void CompareWithContextState(ImGuiContext* ctx); +}; + +// Data saved for each window pushed into the stack +struct ImGuiWindowStackData +{ + ImGuiWindow* Window; + ImGuiLastItemData ParentLastItemDataBackup; + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting +}; + +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; + float InitialWidth; +}; + +struct ImGuiPtrOrIndex +{ + void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. + int Index; // Usually index in a main pool. + + ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } + ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Inputs support +//----------------------------------------------------------------------------- + +// Bit array for named keys +typedef ImBitArray ImBitArrayForNamedKeys; + +// [Internal] Key ranges +#define ImGuiKey_LegacyNativeKey_BEGIN 0 +#define ImGuiKey_LegacyNativeKey_END 512 +#define ImGuiKey_Keyboard_BEGIN (ImGuiKey_NamedKey_BEGIN) +#define ImGuiKey_Keyboard_END (ImGuiKey_GamepadStart) +#define ImGuiKey_Gamepad_BEGIN (ImGuiKey_GamepadStart) +#define ImGuiKey_Gamepad_END (ImGuiKey_GamepadRStickDown + 1) +#define ImGuiKey_Mouse_BEGIN (ImGuiKey_MouseLeft) +#define ImGuiKey_Mouse_END (ImGuiKey_MouseWheelY + 1) +#define ImGuiKey_Aliases_BEGIN (ImGuiKey_Mouse_BEGIN) +#define ImGuiKey_Aliases_END (ImGuiKey_Mouse_END) + +// [Internal] Named shortcuts for Navigation +#define ImGuiKey_NavKeyboardTweakSlow ImGuiMod_Ctrl +#define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift +#define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1 +#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1 +#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown +#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight +#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft +#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp + +enum ImGuiInputEventType +{ + ImGuiInputEventType_None = 0, + ImGuiInputEventType_MousePos, + ImGuiInputEventType_MouseWheel, + ImGuiInputEventType_MouseButton, + ImGuiInputEventType_Key, + ImGuiInputEventType_Text, + ImGuiInputEventType_Focus, + ImGuiInputEventType_COUNT +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, // Note: may be Mouse or TouchScreen or Pen. See io.MouseSource to distinguish them. + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Clipboard, // Currently only used by InputText() + ImGuiInputSource_COUNT +}; + +// FIXME: Structures in the union below need to be declared as anonymous unions appears to be an extension? +// Using ImVec2() would fail on Clang 'union member 'MousePos' has a non-trivial default constructor' +struct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; }; +struct ImGuiInputEventText { unsigned int Char; }; +struct ImGuiInputEventAppFocused { bool Focused; }; + +struct ImGuiInputEvent +{ + ImGuiInputEventType Type; + ImGuiInputSource Source; + ImU32 EventId; // Unique, sequential increasing integer to identify an event (if you need to correlate them to other data). + union + { + ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos + ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel + ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton + ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key + ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text + ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus + }; + bool AddedByTestEngine; + + ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } +}; + +// Input function taking an 'ImGuiID owner_id' argument defaults to (ImGuiKeyOwner_Any == 0) aka don't test ownership, which matches legacy behavior. +#define ImGuiKeyOwner_Any ((ImGuiID)0) // Accept key that have an owner, UNLESS a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease. +#define ImGuiKeyOwner_None ((ImGuiID)-1) // Require key to have no owner. + +typedef ImS16 ImGuiKeyRoutingIndex; + +// Routing table entry (sizeof() == 16 bytes) +struct ImGuiKeyRoutingData +{ + ImGuiKeyRoutingIndex NextEntryIndex; + ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super. + ImU8 RoutingNextScore; // Lower is better (0: perfect score) + ImGuiID RoutingCurr; + ImGuiID RoutingNext; + + ImGuiKeyRoutingData() { NextEntryIndex = -1; Mods = 0; RoutingNextScore = 255; RoutingCurr = RoutingNext = ImGuiKeyOwner_None; } +}; + +// Routing table: maintain a desired owner for each possible key-chord (key + mods), and setup owner in NewFrame() when mods are matching. +// Stored in main context (1 instance) +struct ImGuiKeyRoutingTable +{ + ImGuiKeyRoutingIndex Index[ImGuiKey_NamedKey_COUNT]; // Index of first entry in Entries[] + ImVector Entries; + ImVector EntriesNext; // Double-buffer to avoid reallocation (could use a shared buffer) + + ImGuiKeyRoutingTable() { Clear(); } + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Index); n++) Index[n] = -1; Entries.clear(); EntriesNext.clear(); } +}; + +// This extends ImGuiKeyData but only for named keys (legacy keys don't support the new features) +// Stored in main context (1 per named key). In the future it might be merged into ImGuiKeyData. +struct ImGuiKeyOwnerData +{ + ImGuiID OwnerCurr; + ImGuiID OwnerNext; + bool LockThisFrame; // Reading this key requires explicit owner id (until end of frame). Set by ImGuiInputFlags_LockThisFrame. + bool LockUntilRelease; // Reading this key requires explicit owner id (until key is released). Set by ImGuiInputFlags_LockUntilRelease. When this is true LockThisFrame is always true as well. + + ImGuiKeyOwnerData() { OwnerCurr = OwnerNext = ImGuiKeyOwner_None; LockThisFrame = LockUntilRelease = false; } +}; + +// Flags for extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() +// Don't mistake with ImGuiInputTextFlags! (for ImGui::InputText() function) +enum ImGuiInputFlags_ +{ + // Flags for IsKeyPressed(), IsMouseClicked(), Shortcut() + ImGuiInputFlags_None = 0, + ImGuiInputFlags_Repeat = 1 << 0, // Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1. + ImGuiInputFlags_RepeatRateDefault = 1 << 1, // Repeat rate: Regular (default) + ImGuiInputFlags_RepeatRateNavMove = 1 << 2, // Repeat rate: Fast + ImGuiInputFlags_RepeatRateNavTweak = 1 << 3, // Repeat rate: Faster + ImGuiInputFlags_RepeatRateMask_ = ImGuiInputFlags_RepeatRateDefault | ImGuiInputFlags_RepeatRateNavMove | ImGuiInputFlags_RepeatRateNavTweak, + + // Flags for SetItemKeyOwner() + ImGuiInputFlags_CondHovered = 1 << 4, // Only set if item is hovered (default to both) + ImGuiInputFlags_CondActive = 1 << 5, // Only set if item is active (default to both) + ImGuiInputFlags_CondDefault_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive, + ImGuiInputFlags_CondMask_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive, + + // Flags for SetKeyOwner(), SetItemKeyOwner() + ImGuiInputFlags_LockThisFrame = 1 << 6, // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared at end of frame. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code. + ImGuiInputFlags_LockUntilRelease = 1 << 7, // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared when the key is released or at end of each frame if key is released. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code. + + // Routing policies for Shortcut() + low-level SetShortcutRouting() + // - The general idea is that several callers register interest in a shortcut, and only one owner gets it. + // - When a policy (other than _RouteAlways) is set, Shortcut() will register itself with SetShortcutRouting(), + // allowing the system to decide where to route the input among other route-aware calls. + // - Shortcut() uses ImGuiInputFlags_RouteFocused by default: meaning that a simple Shortcut() poll + // will register a route and only succeed when parent window is in the focus stack and if no-one + // with a higher priority is claiming the shortcut. + // - Using ImGuiInputFlags_RouteAlways is roughly equivalent to doing e.g. IsKeyPressed(key) + testing mods. + // - Priorities: GlobalHigh > Focused (when owner is active item) > Global > Focused (when focused window) > GlobalLow. + // - Can select only 1 policy among all available. + ImGuiInputFlags_RouteFocused = 1 << 8, // (Default) Register focused route: Accept inputs if window is in focus stack. Deep-most focused window takes inputs. ActiveId takes inputs over deep-most focused window. + ImGuiInputFlags_RouteGlobalLow = 1 << 9, // Register route globally (lowest priority: unless a focused window or active item registered the route) -> recommended Global priority. + ImGuiInputFlags_RouteGlobal = 1 << 10, // Register route globally (medium priority: unless an active item registered the route, e.g. CTRL+A registered by InputText). + ImGuiInputFlags_RouteGlobalHigh = 1 << 11, // Register route globally (highest priority: unlikely you need to use that: will interfere with every active items) + ImGuiInputFlags_RouteMask_ = ImGuiInputFlags_RouteFocused | ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteGlobalLow | ImGuiInputFlags_RouteGlobalHigh, // _Always not part of this! + ImGuiInputFlags_RouteAlways = 1 << 12, // Do not register route, poll keys directly. + ImGuiInputFlags_RouteUnlessBgFocused= 1 << 13, // Global routes will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications. + ImGuiInputFlags_RouteExtraMask_ = ImGuiInputFlags_RouteAlways | ImGuiInputFlags_RouteUnlessBgFocused, + + // [Internal] Mask of which function support which flags + ImGuiInputFlags_SupportedByIsKeyPressed = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_, + ImGuiInputFlags_SupportedByShortcut = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_ | ImGuiInputFlags_RouteMask_ | ImGuiInputFlags_RouteExtraMask_, + ImGuiInputFlags_SupportedBySetKeyOwner = ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease, + ImGuiInputFlags_SupportedBySetItemKeyOwner = ImGuiInputFlags_SupportedBySetKeyOwner | ImGuiInputFlags_CondMask_, +}; + +//----------------------------------------------------------------------------- +// [SECTION] Clipper support +//----------------------------------------------------------------------------- + +// Note that Max is exclusive, so perhaps should be using a Begin/End convention. +struct ImGuiListClipperRange +{ + int Min; + int Max; + bool PosToIndexConvert; // Begin/End are absolute position (will be converted to indices later) + ImS8 PosToIndexOffsetMin; // Add to Min after converting to indices + ImS8 PosToIndexOffsetMax; // Add to Min after converting to indices + + static ImGuiListClipperRange FromIndices(int min, int max) { ImGuiListClipperRange r = { min, max, false, 0, 0 }; return r; } + static ImGuiListClipperRange FromPositions(float y1, float y2, int off_min, int off_max) { ImGuiListClipperRange r = { (int)y1, (int)y2, true, (ImS8)off_min, (ImS8)off_max }; return r; } +}; + +// Temporary clipper data, buffers shared/reused between instances +struct ImGuiListClipperData +{ + ImGuiListClipper* ListClipper; + float LossynessOffset; + int StepNo; + int ItemsFrozen; + ImVector Ranges; + + ImGuiListClipperData() { memset(this, 0, sizeof(*this)); } + void Reset(ImGuiListClipper* clipper) { ListClipper = clipper; StepNo = ItemsFrozen = 0; Ranges.resize(0); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Navigation support +//----------------------------------------------------------------------------- + +enum ImGuiActivateFlags_ +{ + ImGuiActivateFlags_None = 0, + ImGuiActivateFlags_PreferInput = 1 << 0, // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default for Enter key. + ImGuiActivateFlags_PreferTweak = 1 << 1, // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default for Space key and if keyboard is not used. + ImGuiActivateFlags_TryToPreserveState = 1 << 2, // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection) +}; + +// Early work-in-progress API for ScrollToItem() +enum ImGuiScrollFlags_ +{ + ImGuiScrollFlags_None = 0, + ImGuiScrollFlags_KeepVisibleEdgeX = 1 << 0, // If item is not visible: scroll as little as possible on X axis to bring item back into view [default for X axis] + ImGuiScrollFlags_KeepVisibleEdgeY = 1 << 1, // If item is not visible: scroll as little as possible on Y axis to bring item back into view [default for Y axis for windows that are already visible] + ImGuiScrollFlags_KeepVisibleCenterX = 1 << 2, // If item is not visible: scroll to make the item centered on X axis [rarely used] + ImGuiScrollFlags_KeepVisibleCenterY = 1 << 3, // If item is not visible: scroll to make the item centered on Y axis + ImGuiScrollFlags_AlwaysCenterX = 1 << 4, // Always center the result item on X axis [rarely used] + ImGuiScrollFlags_AlwaysCenterY = 1 << 5, // Always center the result item on Y axis [default for Y axis for appearing window) + ImGuiScrollFlags_NoScrollParent = 1 << 6, // Disable forwarding scrolling to parent window if required to keep item/rect visible (only scroll window the function was applied to). + ImGuiScrollFlags_MaskX_ = ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleCenterX | ImGuiScrollFlags_AlwaysCenterX, + ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY, +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3, +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) + ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness + ImGuiNavMoveFlags_WrapMask_ = ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_WrapY, + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown) + ImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6, // Force scrolling to min/max (used by Home/End) // FIXME-NAV: Aim to remove or reword, probably unnecessary + ImGuiNavMoveFlags_Forwarded = 1 << 7, + ImGuiNavMoveFlags_DebugNoResult = 1 << 8, // Dummy scoring for debug purpose, don't apply result + ImGuiNavMoveFlags_FocusApi = 1 << 9, + ImGuiNavMoveFlags_Tabbing = 1 << 10, // == Focus + Activate if item is Inputable + DontChangeNavHighlight + ImGuiNavMoveFlags_Activate = 1 << 11, + ImGuiNavMoveFlags_DontSetNavHighlight = 1 << 12, // Do not alter the visible state of keyboard vs mouse nav highlight +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt) + ImGuiNavLayer_COUNT }; -struct ImGuiSettingsHandler +struct ImGuiNavItemData { - const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' - ImGuiID TypeHash; // == ImHashStr(TypeName) - std::function ReadOpenFn; // Read: Called when entering into a new ini entry e.g. "[Window][Name]" - std::function ReadLineFn; // Read: Called for every line of text within an ini entry - std::function WriteAllFn; // Write: Output every entries into 'out_buf' - void* UserData; - - ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } + ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window) + ImGuiID ID; // Init,Move // Best candidate item ID + ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID + ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space + ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags + float DistBox; // Move // Best candidate box distance to current NavId + float DistCenter; // Move // Best candidate center distance to current NavId + float DistAxial; // Move // Best candidate axial distance to current NavId + + ImGuiNavItemData() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; DistBox = DistCenter = DistAxial = FLT_MAX; } }; -// Storage for current popup stack -struct ImGuiPopupData -{ - ImGuiID PopupId; // Set on OpenPopup() - ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() - ImGuiWindow* SourceWindow; // Set on OpenPopup() copy of NavWindow at the time of opening the popup - int OpenFrameCount; // Set on OpenPopup() - ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) - ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) - ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup +//----------------------------------------------------------------------------- +// [SECTION] Columns support +//----------------------------------------------------------------------------- - ImGuiPopupData() { PopupId = 0; Window = SourceWindow = NULL; OpenFrameCount = -1; OpenParentId = 0; } +// Flags for internal's BeginColumns(). Prefix using BeginTable() nowadays! +enum ImGuiOldColumnFlags_ +{ + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, // Disable column dividers + ImGuiOldColumnFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4, // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiColumnsFlags_None = ImGuiOldColumnFlags_None, + ImGuiColumnsFlags_NoBorder = ImGuiOldColumnFlags_NoBorder, + ImGuiColumnsFlags_NoResize = ImGuiOldColumnFlags_NoResize, + ImGuiColumnsFlags_NoPreserveWidths = ImGuiOldColumnFlags_NoPreserveWidths, + ImGuiColumnsFlags_NoForceWithinWindow = ImGuiOldColumnFlags_NoForceWithinWindow, + ImGuiColumnsFlags_GrowParentContentsSize = ImGuiOldColumnFlags_GrowParentContentsSize, +#endif }; -struct ImGuiColumnData +struct ImGuiOldColumnData { - float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) float OffsetNormBeforeResize; - ImGuiColumnsFlags Flags; // Not exposed + ImGuiOldColumnFlags Flags; // Not exposed ImRect ClipRect; - ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; } + ImGuiOldColumnData() { memset(this, 0, sizeof(*this)); } }; -struct ImGuiColumns +struct ImGuiOldColumns { ImGuiID ID; - ImGuiColumnsFlags Flags; + ImGuiOldColumnFlags Flags; bool IsFirstFrame; bool IsBeingResized; int Current; @@ -820,140 +1554,199 @@ struct ImGuiColumns float LineMinY, LineMaxY; float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() - ImRect HostClipRect; // Backup of ClipRect at the time of BeginColumns() - ImRect HostWorkRect; // Backup of WorkRect at the time of BeginColumns() - ImVector Columns; + ImRect HostInitialClipRect; // Backup of ClipRect at the time of BeginColumns() + ImRect HostBackupClipRect; // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground() + ImRect HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns() + ImVector Columns; + ImDrawListSplitter Splitter; - ImGuiColumns() { Clear(); } - void Clear() - { - ID = 0; - Flags = ImGuiColumnsFlags_None; - IsFirstFrame = false; - IsBeingResized = false; - Current = 0; - Count = 1; - OffMinX = OffMaxX = 0.0f; - LineMinY = LineMaxY = 0.0f; - HostCursorPosY = 0.0f; - HostCursorMaxPosX = 0.0f; - Columns.clear(); - } + ImGuiOldColumns() { memset(this, 0, sizeof(*this)); } }; -// Data shared between all ImDrawList instances -struct IMGUI_API ImDrawListSharedData -{ - ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas - ImFont* Font; // Current/default font (optional, for simplified AddText overload) - float FontSize; // Current/default font size (optional, for simplified AddText overload) - float CurveTessellationTol; - ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() - ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) +//----------------------------------------------------------------------------- +// [SECTION] Multi-select support +//----------------------------------------------------------------------------- - // Const data - // FIXME: Bake rounded corners fill/borders in atlas - ImVec2 CircleVtx12[12]; +#ifdef IMGUI_HAS_MULTI_SELECT +// +#endif // #ifdef IMGUI_HAS_MULTI_SELECT - ImDrawListSharedData(); +//----------------------------------------------------------------------------- +// [SECTION] Docking support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_DOCK +// +#endif // #ifdef IMGUI_HAS_DOCK + +//----------------------------------------------------------------------------- +// [SECTION] Viewport support +//----------------------------------------------------------------------------- + +// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Every instance of ImGuiViewport is in fact a ImGuiViewportP. +struct ImGuiViewportP : public ImGuiViewport +{ + int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used + ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. + ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. + + ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + + // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) + ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields + + // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } }; -struct ImDrawDataBuilder +//----------------------------------------------------------------------------- +// [SECTION] Settings support +//----------------------------------------------------------------------------- + +// Windows data saved in imgui.ini file +// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. +// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) +struct ImGuiWindowSettings { - ImVector Layers[2]; // Global layers for: regular, tooltip + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + bool WantDelete; // Set to invalidate/delete the settings entry - void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } - void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } - IMGUI_API void FlattenIntoSingleLayer(); + ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } + char* GetName() { return (char*)(this + 1); } }; -struct ImGuiNavMoveResult +struct ImGuiSettingsHandler { - ImGuiID ID; // Best candidate - ImGuiID SelectScopeId;// Best candidate window current selectable group ID - ImGuiWindow* Window; // Best candidate window - float DistBox; // Best candidate box distance to current NavId - float DistCenter; // Best candidate center distance to current NavId - float DistAxial; - ImRect RectRel; // Best candidate bounding box in window relative space + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHashStr(TypeName) + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' + void* UserData; - ImGuiNavMoveResult() { Clear(); } - void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } }; -enum ImGuiNextWindowDataFlags_ +//----------------------------------------------------------------------------- +// [SECTION] Localization support +//----------------------------------------------------------------------------- + +// This is experimental and not officially supported, it'll probably fall short of features, if/when it does we may backtrack. +enum ImGuiLocKey : int { - ImGuiNextWindowDataFlags_None = 0, - ImGuiNextWindowDataFlags_HasPos = 1 << 0, - ImGuiNextWindowDataFlags_HasSize = 1 << 1, - ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, - ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, - ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, - ImGuiNextWindowDataFlags_HasFocus = 1 << 5, - ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6 + ImGuiLocKey_TableSizeOne, + ImGuiLocKey_TableSizeAllFit, + ImGuiLocKey_TableSizeAllDefault, + ImGuiLocKey_TableResetOrder, + ImGuiLocKey_WindowingMainMenuBar, + ImGuiLocKey_WindowingPopup, + ImGuiLocKey_WindowingUntitled, + ImGuiLocKey_COUNT }; -// Storage for SetNexWindow** functions -struct ImGuiNextWindowData +struct ImGuiLocEntry { - ImGuiNextWindowDataFlags Flags; - ImGuiCond PosCond; - ImGuiCond SizeCond; - ImGuiCond CollapsedCond; - ImVec2 PosVal; - ImVec2 PosPivotVal; - ImVec2 SizeVal; - ImVec2 ContentSizeVal; - bool CollapsedVal; - ImRect SizeConstraintRect; - ImGuiSizeCallback SizeCallback; - void* SizeCallbackUserData; - float BgAlphaVal; - ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it. + ImGuiLocKey Key; + const char* Text; +}; - ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } - inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } + +//----------------------------------------------------------------------------- +// [SECTION] Metrics, Debug Tools +//----------------------------------------------------------------------------- + +enum ImGuiDebugLogFlags_ +{ + // Event types + ImGuiDebugLogFlags_None = 0, + ImGuiDebugLogFlags_EventActiveId = 1 << 0, + ImGuiDebugLogFlags_EventFocus = 1 << 1, + ImGuiDebugLogFlags_EventPopup = 1 << 2, + ImGuiDebugLogFlags_EventNav = 1 << 3, + ImGuiDebugLogFlags_EventClipper = 1 << 4, + ImGuiDebugLogFlags_EventSelection = 1 << 5, + ImGuiDebugLogFlags_EventIO = 1 << 6, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO, + ImGuiDebugLogFlags_OutputToTTY = 1 << 10, // Also send output to TTY }; -enum ImGuiNextItemDataFlags_ +struct ImGuiMetricsConfig { - ImGuiNextItemDataFlags_None = 0, - ImGuiNextItemDataFlags_HasWidth = 1 << 0, - ImGuiNextItemDataFlags_HasOpen = 1 << 1 + bool ShowDebugLog = false; + bool ShowStackTool = false; + bool ShowWindowsRects = false; + bool ShowWindowsBeginOrder = false; + bool ShowTablesRects = false; + bool ShowDrawCmdMesh = true; + bool ShowDrawCmdBoundingBoxes = true; + bool ShowAtlasTintedWithTextColor = false; + int ShowWindowsRectsType = -1; + int ShowTablesRectsType = -1; }; -struct ImGuiNextItemData +struct ImGuiStackLevelInfo { - ImGuiNextItemDataFlags Flags; - float Width; // Set by SetNextItemWidth(). - bool OpenVal; // Set by SetNextItemOpen() function. - ImGuiCond OpenCond; + ImGuiID ID; + ImS8 QueryFrameCount; // >= 1: Query in progress + bool QuerySuccess; // Obtained result from DebugHookIdInfo() + ImGuiDataType DataType : 8; + char Desc[57]; // Arbitrarily sized buffer to hold a result (FIXME: could replace Results[] with a chunk stream?) FIXME: Now that we added CTRL+C this should be fixed. - ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } - inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } + ImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); } +}; + +// State for Stack tool queries +struct ImGuiStackTool +{ + int LastActiveFrame; + int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level + ImGuiID QueryId; // ID to query details for + ImVector Results; + bool CopyToClipboardOnCtrlC; + float CopyToClipboardLastTime; + + ImGuiStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; } }; //----------------------------------------------------------------------------- -// Tabs +// [SECTION] Generic context hooks //----------------------------------------------------------------------------- -struct ImGuiShrinkWidthItem -{ - int Index; - float Width; -}; +typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); +enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }; -struct ImGuiPtrOrIndex +struct ImGuiContextHook { - void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. - int Index; // Usually index in a main pool. + ImGuiID HookId; // A unique ID assigned by AddContextHook() + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; - ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } - ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } + ImGuiContextHook() { memset(this, 0, sizeof(*this)); } }; //----------------------------------------------------------------------------- -// Main imgui context +// [SECTION] ImGuiContext (main Dear ImGui context) //----------------------------------------------------------------------------- struct ImGuiContext @@ -973,26 +1766,41 @@ struct ImGuiContext bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed bool WithinEndChild; // Set within EndChild() + bool GcCompactAll; // Request full GC + bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() + void* TestEngine; // Test engine user data + + // Inputs + ImVector InputEventsQueue; // Input events which will be trickled/written into IO structure. + ImVector InputEventsTrail; // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail. + ImGuiMouseSource InputEventsNextMouseSource; + ImU32 InputEventsNextEventId; // Windows state ImVector Windows; // Windows, sorted in display order, back to front - ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front - ImVector WindowsSortBuffer; - ImVector CurrentWindowStack; + ImVector WindowsFocusOrder; // Root windows, sorted in focus order, back to front. + ImVector WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child + ImVector CurrentWindowStack; ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* int WindowsActiveCount; // Number of unique windows submitted by frame + ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) ImGuiWindow* CurrentWindow; // Window being drawn into - ImGuiWindow* HoveredWindow; // Will catch mouse inputs - ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) - ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. + ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. + ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; - float WheelingWindowTimer; + int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL + float WheelingWindowReleaseTimer; + ImVec2 WheelingWindowWheelRemainder; + ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information - ImGuiID HoveredId; // Hovered widget - bool HoveredIdAllowOverlap; + ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] + ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active ImGuiID ActiveId; // Active widget @@ -1000,15 +1808,14 @@ struct ImGuiContext float ActiveIdTimer; bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdNoClearOnFocusLoss; // Disable losing active id if the active id window gets unfocused. bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. bool ActiveIdHasBeenEditedThisFrame; - ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those directional navigation requests (e.g. can activate a button and move away from it) - ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs. - ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; - ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) + ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad + int ActiveIdMouseButton; ImGuiID ActiveIdPreviousFrame; bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameHasBeenEditedBefore; @@ -1016,134 +1823,195 @@ struct ImGuiContext ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + // [EXPERIMENTAL] Key/Input Ownership + Shortcut Routing system + // - The idea is that instead of "eating" a given key, we can link to an owner. + // - Input query can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID. + // - Routing is requested ahead of time for a given chord (Key + Mods) and granted in NewFrame(). + ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT]; + ImGuiKeyRoutingTable KeysRoutingTable; + ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) + bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (FIXME: This is a shortcut for not taking ownership of 100+ keys but perhaps best to not have the inconsistency) +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' +#endif + // Next window/item data - ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + ImGuiID CurrentFocusScopeId; // == g.FocusScopeStack.back() + ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back() + ImGuiID DebugLocateId; // Storage for DebugLocateItemOnHover() feature: this is read by ItemAdd() so we keep it in a hot/cached location ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions + ImGuiLastItemData LastItemData; // Storage for last submitted item (setup by ItemAdd) + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions // Shared stacks - ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() - ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() - ImVector FontStack; // Stack for PushFont()/PopFont() + ImVector ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() + ImVector StyleVarStack; // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin() + ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() + ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - inherited by BeginChild(), pushed into by Begin() + ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin() + ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + int BeginMenuCount; - // Navigation data (for gamepad/keyboard) - ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' + // Viewports + ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. + + // Gamepad/keyboard Navigation + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavId; // Focused item for navigation - ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() - ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 - ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 - ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 - ImGuiID NavJustTabbedId; // Just tabbed to this id. + ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) + ImGuiActivateFlags NavActivateFlags; ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). - ImGuiID NavJustMovedToMultiSelectScopeId; // Just navigated to this select scope id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). + ImGuiKeyChord NavJustMovedToKeyMods; ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. - ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. - ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. - int NavScoringCount; // Metrics for debugging - ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed top-most. - ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f - ImGuiWindow* NavWindowingList; - float NavWindowingTimer; - float NavWindowingHighlightAlpha; - bool NavWindowingToggleLayer; + ImGuiActivateFlags NavNextActivateFlags; + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. - int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing - bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. - bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest + + // Navigation: Init & Move Requests + bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() bool NavInitRequest; // Init request for appearing window to select first item bool NavInitRequestFromMove; - ImGuiID NavInitResultId; - ImRect NavInitResultRectRel; - bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items - bool NavMoveRequest; // Move request for this frame - ImGuiNavMoveFlags NavMoveRequestFlags; - ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) - ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request + ImGuiNavItemData NavInitResult; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + bool NavMoveSubmitted; // Move request submitted, will process result on next NewFrame() + bool NavMoveScoringItems; // Move request submitted, still scoring incoming items + bool NavMoveForwardToNextFrame; + ImGuiNavMoveFlags NavMoveFlags; + ImGuiScrollFlags NavMoveScrollFlags; + ImGuiKeyChord NavMoveKeyMods; + ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down) + ImGuiDir NavMoveDirForDebug; ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? - ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow - ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) - ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) - - // Tabbing system (older than Nav, active even if Nav is disabled. FIXME-NAV: This needs a redesign!) - ImGuiWindow* FocusRequestCurrWindow; // - ImGuiWindow* FocusRequestNextWindow; // - int FocusRequestCurrCounterAll; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) - int FocusRequestCurrCounterTab; // Tab item being requested for focus, stored as an index - int FocusRequestNextCounterAll; // Stored for next frame - int FocusRequestNextCounterTab; // " - bool FocusTabPressed; // + ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. + ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted + int NavScoringDebugCount; // Metrics for debugging + int NavTabbingDir; // Generally -1 or +1, 0 when tabbing without a nav id + int NavTabbingCounter; // >0 when counting items for tabbing + ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavItemData NavMoveResultLocalVisible; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy + + // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) + ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab, for reconfiguration (see #4828) + ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab + ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! + ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it. + ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + ImVec2 NavWindowingAccumDeltaPos; + ImVec2 NavWindowingAccumDeltaSize; // Render - ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user - ImDrawDataBuilder DrawDataBuilder; float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) - ImDrawList BackgroundDrawList; // First draw list to be rendered. - ImDrawList ForegroundDrawList; // Last draw list to be rendered. This is where we the render software mouse cursor (if io.MouseDrawCursor is set) and most debug overlays. ImGuiMouseCursor MouseCursor; // Drag and Drop bool DragDropActive; - bool DragDropWithinSourceOrTarget; + bool DragDropWithinSource; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source. + bool DragDropWithinTarget; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target. ImGuiDragDropFlags DragDropSourceFlags; int DragDropSourceFrameCount; int DragDropMouseButton; ImGuiPayload DragDropPayload; - ImRect DragDropTargetRect; + ImRect DragDropTargetRect; // Store rectangle of current target candidate (we favor small targets when overlapping) ImGuiID DragDropTargetId; ImGuiDragDropFlags DragDropAcceptFlags; float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source - ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly + ImGuiID DragDropHoldJustPressedId; // Set when holding a payload just made ButtonBehavior() return a press. + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads + // Clipper + int ClipperTempDataStacked; + ImVector ClipperTempData; + + // Tables + ImGuiTable* CurrentTable; + int TablesTempDataStacked; // Temporary table data size (because we leave previous instances undestructed, we generally don't use TablesTempData.Size) + ImVector TablesTempData; // Temporary table data (buffers reused/shared across instances, support nesting) + ImPool Tables; // Persistent table data + ImVector TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC) + ImVector DrawChannelsTempMergeBuffer; + // Tab bars ImGuiTabBar* CurrentTabBar; ImPool TabBars; ImVector CurrentTabBarStack; ImVector ShrinkWidthBuffer; + // Hover Delay system + ImGuiID HoverDelayId; + ImGuiID HoverDelayIdPreviousFrame; + float HoverDelayTimer; // Currently used IsItemHovered(), generally inferred from g.HoveredIdTimer but kept uncleared until clear timer elapse. + float HoverDelayClearTimer; // Currently used IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared. + // Widget state - ImVec2 LastValidMousePos; + ImVec2 MouseLastValidPos; ImGuiInputTextState InputTextState; + ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFont InputTextPasswordFont; - ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets - float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips - float ColorEditLastColor[3]; + ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others). + ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for + float ColorEditSavedHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips + float ColorEditSavedSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips + ImU32 ColorEditSavedColor; // RGB value with alpha set to 0. ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. + ImGuiComboPreviewData ComboPreviewData; + float SliderGrabClickOffset; + float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. + bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? bool DragCurrentAccumDirty; float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? - int TooltipOverrideCount; - ImVector PrivateClipboard; // If no custom clipboard handler is defined - - // Range-Select/Multi-Select - // [This is unused in this branch, but left here to facilitate merging/syncing multiple branches] - ImGuiID MultiSelectScopeId; + float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() + short DisabledStackSize; + short TooltipOverrideCount; + ImVector ClipboardHandlerData; // If no custom clipboard handler is defined + ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once // Platform support - ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor - ImVec2 PlatformImeLastPos; + ImGuiPlatformImeData PlatformImeData; // Data updated by current frame + ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn + char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point // Settings bool SettingsLoaded; float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero ImGuiTextBuffer SettingsIniData; // In memory .ini settings - std::vector SettingsHandlers; // List of .ini settings handlers + ImVector SettingsHandlers; // List of .ini settings handlers ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries + ImChunkStream SettingsTables; // ImGuiTable .ini settings entries + ImVector Hooks; // Hooks for extensions (e.g. test engine) + ImGuiID HookIdNext; // Next available HookId + + // Localization + const char* LocalizationTable[ImGuiLocKey_COUNT]; // Capture/Logging - bool LogEnabled; - ImGuiLogType LogType; + bool LogEnabled; // Currently capturing + ImGuiLogType LogType; // Capture target ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + const char* LogNextPrefix; + const char* LogNextSuffix; float LogLinePosY; bool LogLineFirstItem; int LogDepthRef; @@ -1151,56 +2019,76 @@ struct ImGuiContext int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. // Debug Tools - bool DebugItemPickerActive; - ImGuiID DebugItemPickerBreakID; // Will call IM_DEBUG_BREAK() when encountering this id + ImGuiDebugLogFlags DebugLogFlags; + ImGuiTextBuffer DebugLogBuf; + ImGuiTextIndex DebugLogIndex; + ImU8 DebugLogClipperAutoDisableFrames; + ImU8 DebugLocateFrames; // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above. + ImS8 DebugBeginReturnValueCullDepth; // Cycle between 0..9 then wrap around. + bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) + ImU8 DebugItemPickerMouseButton; + ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID + ImGuiMetricsConfig DebugMetricsConfig; + ImGuiStackTool DebugStackTool; // Misc - float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. + float FramerateSecPerFrame[60]; // Calculate estimate of framerate for user over the last 60 frames.. int FramerateSecPerFrameIdx; + int FramerateSecPerFrameCount; float FramerateSecPerFrameAccum; - int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags - int WantCaptureKeyboardNextFrame; + int WantCaptureMouseNextFrame; // Explicit capture override via SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). Default to -1. + int WantCaptureKeyboardNextFrame; // " int WantTextInputNextFrame; - char TempBuffer[1024*3+1]; // Temporary text buffer + ImVector TempBuffer; // Temporary text buffer - ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) + ImGuiContext(ImFontAtlas* shared_font_atlas) { + IO.Ctx = this; + InputTextState.Ctx = this; + Initialized = false; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; FontSize = FontBaseSize = 0.0f; - FontAtlasOwnedByContext = shared_font_atlas ? false : true; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + GcCompactAll = false; + TestEngineHookItems = false; + TestEngine = NULL; + + InputEventsNextMouseSource = ImGuiMouseSource_Mouse; + InputEventsNextEventId = 1; WindowsActiveCount = 0; CurrentWindow = NULL; HoveredWindow = NULL; - HoveredRootWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; MovingWindow = NULL; WheelingWindow = NULL; - WheelingWindowTimer = 0.0f; + WheelingWindowStartFrame = -1; + WheelingWindowReleaseTimer = 0.0f; - HoveredId = 0; + DebugHookIdInfo = 0; + HoveredId = HoveredIdPreviousFrame = 0; HoveredIdAllowOverlap = false; - HoveredIdPreviousFrame = 0; + HoveredIdDisabled = false; HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; ActiveId = 0; ActiveIdIsAlive = 0; ActiveIdTimer = 0.0f; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; + ActiveIdNoClearOnFocusLoss = false; ActiveIdHasBeenPressedBefore = false; ActiveIdHasBeenEditedBefore = false; ActiveIdHasBeenEditedThisFrame = false; - ActiveIdUsingNavDirMask = 0x00; - ActiveIdUsingNavInputMask = 0x00; - ActiveIdUsingKeyInputMask = 0x00; - ActiveIdClickOffset = ImVec2(-1,-1); + ActiveIdClickOffset = ImVec2(-1, -1); ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = -1; ActiveIdPreviousFrame = 0; ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEditedBefore = false; @@ -1208,17 +2096,23 @@ struct ImGuiContext LastActiveId = 0; LastActiveIdTimer = 0.0f; + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ActiveIdUsingNavInputMask = 0x00; +#endif + + CurrentFocusScopeId = 0; + CurrentItemFlags = ImGuiItemFlags_None; + BeginMenuCount = 0; + NavWindow = NULL; - NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; - NavJustTabbedId = NavJustMovedToId = NavJustMovedToMultiSelectScopeId = NavNextActivateId = 0; - NavInputSource = ImGuiInputSource_None; - NavScoringRectScreen = ImRect(); - NavScoringCount = 0; - NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL; - NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; - NavWindowingToggleLayer = false; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; + NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; + NavJustMovedToKeyMods = ImGuiMod_None; + NavInputSource = ImGuiInputSource_Keyboard; NavLayer = ImGuiNavLayer_Main; - NavIdTabCounter = INT_MAX; NavIdIsAlive = false; NavMousePosDirty = false; NavDisableHighlight = true; @@ -1226,172 +2120,173 @@ struct ImGuiContext NavAnyRequest = false; NavInitRequest = false; NavInitRequestFromMove = false; - NavInitResultId = 0; - NavMoveFromClampedRefRect = false; - NavMoveRequest = false; - NavMoveRequestFlags = 0; - NavMoveRequestForward = ImGuiNavForward_None; - NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; - - FocusRequestCurrWindow = FocusRequestNextWindow = NULL; - FocusRequestCurrCounterAll = FocusRequestCurrCounterTab = INT_MAX; - FocusRequestNextCounterAll = FocusRequestNextCounterTab = INT_MAX; - FocusTabPressed = false; + NavMoveSubmitted = false; + NavMoveScoringItems = false; + NavMoveForwardToNextFrame = false; + NavMoveFlags = ImGuiNavMoveFlags_None; + NavMoveScrollFlags = ImGuiScrollFlags_None; + NavMoveKeyMods = ImGuiMod_None; + NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; + NavScoringDebugCount = 0; + NavTabbingDir = 0; + NavTabbingCounter = 0; + + ConfigNavWindowingKeyNext = ImGuiMod_Ctrl | ImGuiKey_Tab; + ConfigNavWindowingKeyPrev = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab; + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; DimBgRatio = 0.0f; - BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging - ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging MouseCursor = ImGuiMouseCursor_Arrow; - DragDropActive = DragDropWithinSourceOrTarget = false; - DragDropSourceFlags = 0; + DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; + DragDropSourceFlags = ImGuiDragDropFlags_None; DragDropSourceFrameCount = -1; DragDropMouseButton = -1; DragDropTargetId = 0; - DragDropAcceptFlags = 0; + DragDropAcceptFlags = ImGuiDragDropFlags_None; DragDropAcceptIdCurrRectSurface = 0.0f; DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; DragDropAcceptFrameCount = -1; + DragDropHoldJustPressedId = 0; memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + ClipperTempDataStacked = 0; + + CurrentTable = NULL; + TablesTempDataStacked = 0; CurrentTabBar = NULL; - LastValidMousePos = ImVec2(0.0f, 0.0f); - TempInputTextId = 0; - ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; - ColorEditLastHue = 0.0f; - ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX; + HoverDelayId = HoverDelayIdPreviousFrame = 0; + HoverDelayTimer = HoverDelayClearTimer = 0.0f; + + TempInputId = 0; + ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; + ColorEditCurrentID = ColorEditSavedID = 0; + ColorEditSavedHue = ColorEditSavedSat = 0.0f; + ColorEditSavedColor = 0; + SliderGrabClickOffset = 0.0f; + SliderCurrentAccum = 0.0f; + SliderCurrentAccumDirty = false; DragCurrentAccumDirty = false; DragCurrentAccum = 0.0f; DragSpeedDefaultRatio = 1.0f / 100.0f; ScrollbarClickDeltaToGrabCenter = 0.0f; + DisabledAlphaBackup = 0.0f; + DisabledStackSize = 0; TooltipOverrideCount = 0; - MultiSelectScopeId = 0; - - PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); + PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission + PlatformLocaleDecimalPoint = '.'; SettingsLoaded = false; SettingsDirtyTimer = 0.0f; + HookIdNext = 0; + + memset(LocalizationTable, 0, sizeof(LocalizationTable)); LogEnabled = false; LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; LogFile = NULL; LogLinePosY = FLT_MAX; LogLineFirstItem = false; LogDepthRef = 0; LogDepthToExpand = LogDepthToExpandDefault = 2; + DebugLogFlags = ImGuiDebugLogFlags_OutputToTTY; + DebugLocateId = 0; + DebugLogClipperAutoDisableFrames = 0; + DebugLocateFrames = 0; + DebugBeginReturnValueCullDepth = -1; DebugItemPickerActive = false; - DebugItemPickerBreakID = 0; + DebugItemPickerMouseButton = ImGuiMouseButton_Left; + DebugItemPickerBreakId = 0; memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); - FramerateSecPerFrameIdx = 0; + FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; FramerateSecPerFrameAccum = 0.0f; WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; - memset(TempBuffer, 0, sizeof(TempBuffer)); } }; //----------------------------------------------------------------------------- -// ImGuiWindow +// [SECTION] ImGuiWindowTempData, ImGuiWindow //----------------------------------------------------------------------------- // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. -// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. +// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..) +// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin) struct IMGUI_API ImGuiWindowTempData { + // Layout ImVec2 CursorPos; // Current emitting position, in absolute coordinates. ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding. - ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame + ImVec2 CursorMaxPos; // Used to implicitly calculate ContentSize at the beginning of next frame, for scrolling range and auto-resize. Always growing during the frame. + ImVec2 IdealMaxPos; // Used to implicitly calculate ContentSizeIdeal at the beginning of next frame, for auto-resize only. Always growing during the frame. ImVec2 CurrLineSize; ImVec2 PrevLineSize; float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added). float PrevLineTextBaseOffset; - int TreeDepth; // Current tree depth. - ImU32 TreeMayJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. - ImGuiID LastItemId; // ID for last item - ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_) - ImRect LastItemRect; // Interaction rect for last item - ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) + bool IsSameLine; + bool IsSetPos; + ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. + ImVec1 GroupOffset; + ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensate and fix the most common use case of large scroll area. + + // Keyboard/Gamepad navigation ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) - int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. - int NavLayerActiveMask; // Which layer have been written to (result from previous frame) - int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) + short NavLayersActiveMask; // Which layers have been written to (result from previous frame) + short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) + bool NavIsScrollPushableX; // Set when current work location may be scrolled horizontally when moving left / right. This is generally always true UNLESS within a column. bool NavHideHighlightOneFrame; - bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) + bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) + + // Miscellaneous bool MenuBarAppending; // FIXME: Remove this ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. + ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement + int TreeDepth; // Current tree depth. + ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. ImVector ChildWindows; ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) + ImGuiOldColumns* CurrentColumns; // Current columns set + int CurrentTableIdx; // Current table index (into g.Tables) ImGuiLayoutType LayoutType; ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() - int FocusCounterAll; // Counter for focus/tabbing system. Start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign) - int FocusCounterTab; // (same, but only count widgets which you can Tab through) + // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. - ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] - float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window - float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] - ImVectorItemFlagsStack; - ImVector ItemWidthStack; - ImVector TextWrapPosStack; - ImVectorGroupStack; - short StackSizesBackup[6]; // Store size of various stacks for asserting - - ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) - ImVec1 GroupOffset; - ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. - ImGuiColumns* CurrentColumns; // Current columns set - - ImGuiWindowTempData() - { - CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); - CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); - CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; - TreeDepth = 0; - TreeMayJumpToParentOnPopMask = 0x00; - LastItemId = 0; - LastItemStatusFlags = 0; - LastItemRect = LastItemDisplayRect = ImRect(); - NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; - NavLayerCurrent = ImGuiNavLayer_Main; - NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); - NavHideHighlightOneFrame = false; - NavHasScroll = false; - MenuBarAppending = false; - MenuBarOffset = ImVec2(0.0f, 0.0f); - StateStorage = NULL; - LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; - FocusCounterAll = FocusCounterTab = -1; - - ItemFlags = ImGuiItemFlags_Default_; - ItemWidth = 0.0f; - TextWrapPos = -1.0f; - memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); - - Indent = ImVec1(0.0f); - GroupOffset = ImVec1(0.0f); - ColumnsOffset = ImVec1(0.0f); - CurrentColumns = NULL; - } + float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). + float TextWrapPos; // Current text wrap pos. + ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) + ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) }; // Storage for one window struct IMGUI_API ImGuiWindow { - char* Name; - ImGuiID ID; // == ImHash(Name) + ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). + char* Name; // Window name, owned by the window. + ImGuiID ID; // == ImHashStr(Name) ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ + ImGuiViewportP* Viewport; // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded. ImVec2 Pos; // Position (always rounded-up to nearest pixel) ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 ContentSizeIdeal; ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). ImVec2 WindowPadding; // Window padding at the time of Begin(). - float WindowRounding; // Window rounding at the time of Begin(). + float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. float WindowBorderSize; // Window border size at the time of Begin(). + float DecoOuterSizeX1, DecoOuterSizeY1; // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin(). + float DecoOuterSizeX2, DecoOuterSizeY2; // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y). + float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes). int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) @@ -1399,7 +2294,8 @@ struct IMGUI_API ImGuiWindow ImVec2 ScrollMax; ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered - ImVec2 ScrollbarSizes; // Size taken by scrollbars on each axis + ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold + ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. bool ScrollbarX, ScrollbarY; // Are scrollbars visible? bool Active; // Set to true on Begin(), unless Collapsed bool WasActive; @@ -1408,60 +2304,72 @@ struct IMGUI_API ImGuiWindow bool WantCollapseToggle; bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) bool Appearing; // Set during the frame where the window is appearing (or re-appearing) - bool Hidden; // Do not display (== (HiddenFrames*** > 0)) + bool Hidden; // Do not display (== HiddenFrames*** > 0) + bool IsFallbackWindow; // Set on the "Debug##Default" window. + bool IsExplicitChild; // Set when passed _ChildWindow, left to false by BeginDocked() bool HasCloseButton; // Set when the window has a close button (p_open != NULL) signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) - short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. - short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. + short BeginCountPreviousFrame; // Number of Begin() during the previous frame + short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. + short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) ImS8 AutoFitFramesX, AutoFitFramesY; ImS8 AutoFitChildAxises; bool AutoFitOnlyGrows; ImGuiDir AutoPosLastDirection; - int HiddenFramesCanSkipItems; // Hide the window for N frames - int HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size - ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. - ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. - ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames + ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only + ImS8 DisableInputsFrames; // Disable window interactions for N frames + ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) - ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. - // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. + // The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer. // The main 'OuterRect', omitted as a field, is window->Rect(). ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. - ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). + ImRect WorkRect; // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). + ImRect ParentWorkRect; // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack? ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + ImVec2ih HitTestHoleSize; // Define an optional rectangular hole where mouse will pass-through the window. + ImVec2ih HitTestHoleOffset; int LastFrameActive; // Last frame number the window was Active. float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) float ItemWidthDefault; - ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items ImGuiStorage StateStorage; - ImVector ColumnsStorage; + ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) ImDrawList DrawListInst; - ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. - ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. + ImGuiWindow* ParentWindow; // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* ParentWindowInBeginStack; + ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes. + ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child. ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space + ImVec2 NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]; // Preferred X/Y position updated when moving on a given axis, reset to FLT_MAX. + ImGuiID NavRootFocusScopeId; // Focus Scope ID at the time of Begin() - bool MemoryCompacted; - int MemoryDrawListIdxCapacity; + int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy int MemoryDrawListVtxCapacity; + bool MemoryCompacted; // Set when window extraneous data have been garbage collected public: ImGuiWindow(ImGuiContext* context, const char* name); @@ -1470,35 +2378,19 @@ struct IMGUI_API ImGuiWindow ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); ImGuiID GetID(int n); - ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); - ImGuiID GetIDNoKeepAlive(const void* ptr); - ImGuiID GetIDNoKeepAlive(int n); ImGuiID GetIDFromRectangle(const ImRect& r_abs); - // We don't use g.FontSize because the window may be != g.CurrentWidow. - ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } - float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } - float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } - ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } - float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } - ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } -}; - -// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. -struct ImGuiItemHoveredDataBackup -{ - ImGuiID LastItemId; - ImGuiItemStatusFlags LastItemStatusFlags; - ImRect LastItemRect; - ImRect LastItemDisplayRect; - - ImGuiItemHoveredDataBackup() { Backup(); } - void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } - void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } + // We don't use g.FontSize because the window may be != g.CurrentWindow. + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } + float MenuBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } }; //----------------------------------------------------------------------------- -// Tab bar, tab item +// [SECTION] Tab bar, Tab item support //----------------------------------------------------------------------------- // Extend ImGuiTabBarFlags_ @@ -1506,74 +2398,349 @@ enum ImGuiTabBarFlagsPrivate_ { ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] ImGuiTabBarFlags_IsFocused = 1 << 21, - ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs + ImGuiTabBarFlags_SaveSettings = 1 << 22, // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs }; // Extend ImGuiTabItemFlags_ enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute ContentWidth during layout. + ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) + ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button }; -// Storage for one active tab item (sizeof() 26~32 bytes) +// Storage for one active tab item (sizeof() 40 bytes) struct ImGuiTabItem { ImGuiID ID; ImGuiTabItemFlags Flags; int LastFrameVisible; int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance - int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames float Offset; // Position relative to beginning of tab float Width; // Width currently displayed - float ContentWidth; // Width of actual contents, stored during BeginTabItem() call - - ImGuiTabItem() { ID = 0; Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; } + float ContentWidth; // Width of label, stored during BeginTabItem() call + float RequestedWidth; // Width optionally requested by caller, -1.0f is unused + ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames + ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable + ImS16 IndexDuringLayout; // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions. + bool WantClose; // Marked as closed by SetTabItemClosed() + + ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } }; -// Storage for a tab bar (sizeof() 92~96 bytes) -struct ImGuiTabBar +// Storage for a tab bar (sizeof() 152 bytes) +struct IMGUI_API ImGuiTabBar { ImVector Tabs; + ImGuiTabBarFlags Flags; ImGuiID ID; // Zero for tab-bars used by docking - ImGuiID SelectedTabId; // Selected tab - ImGuiID NextSelectedTabId; + ImGuiID SelectedTabId; // Selected tab/window + ImGuiID NextSelectedTabId; // Next selected tab/window. Will also trigger a scrolling animation ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) int CurrFrameVisible; int PrevFrameVisible; ImRect BarRect; - float LastTabContentHeight; // Record the height of contents submitted below the tab bar - float OffsetMax; // Distance from BarRect.Min.x, locked during layout - float OffsetMaxIdeal; // Ideal offset if all tabs were visible and not clipped - float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set. + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; // Record the height of contents submitted below the tab bar + float WidthAllTabs; // Actual width of all tabs (locked during layout) + float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped float ScrollingAnim; float ScrollingTarget; float ScrollingTargetDistToVisibility; float ScrollingSpeed; - ImGuiTabBarFlags Flags; + float ScrollingRectMinX; + float ScrollingRectMaxX; ImGuiID ReorderRequestTabId; - ImS8 ReorderRequestDir; + ImS16 ReorderRequestOffset; + ImS8 BeginCount; bool WantLayout; bool VisibleTabWasSubmitted; - short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame + ImS16 TabsActiveCount; // Number of tabs submitted this frame. + ImS16 LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem() + float ItemSpacingY; ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + ImVec2 BackupCursorPos; ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. ImGuiTabBar(); - int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } - const char* GetTabName(const ImGuiTabItem* tab) const +}; + +//----------------------------------------------------------------------------- +// [SECTION] Table support +//----------------------------------------------------------------------------- + +#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. +#define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted + +// Our current column maximum is 64 but we may raise that in the future. +typedef ImS16 ImGuiTableColumnIdx; +typedef ImU16 ImGuiTableDrawChannelIdx; + +// [Internal] sizeof() ~ 112 +// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. +// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping. +// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped". +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_ + float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space. + float MinX; // Absolute positions + float MaxX; + float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() + float WidthAuto; // Automatic width + float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. + float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). + ImRect ClipRect; // Clipping rectangle for the column + ImGuiID UserID; // Optional, value passed to TableSetupColumn() + float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column + float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2) + float ItemWidth; // Current item width for the column, preserved across rows + float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width. + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; // Offset into parent ColumnsNames[] + ImGuiTableColumnIdx DisplayOrder; // Index within Table's IndexToDisplayOrder[] (column may be reordered by users) + ImGuiTableColumnIdx IndexWithinEnabledSet; // Index within enabled/visible set (<= IndexToDisplayOrder) + ImGuiTableColumnIdx PrevEnabledColumn; // Index of prev enabled/visible column within Columns[], -1 if first enabled/visible column + ImGuiTableColumnIdx NextEnabledColumn; // Index of next enabled/visible column within Columns[], -1 if last enabled/visible column + ImGuiTableColumnIdx SortOrder; // Index of this column within sort specs, -1 if not sorting on this column, 0 for single-sort, may be >0 on multi-sort + ImGuiTableDrawChannelIdx DrawChannelCurrent; // Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx DrawChannelFrozen; // Draw channels for frozen rows (often headers) + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; // Draw channels for unfrozen rows + bool IsEnabled; // IsUserEnabled && (Flags & ImGuiTableColumnFlags_Disabled) == 0 + bool IsUserEnabled; // Is the column not marked Hidden by the user? (unrelated to being off view, e.g. clipped by scrolling). + bool IsUserEnabledNextFrame; + bool IsVisibleX; // Is actually in view (e.g. overlapping the host window clipping rectangle, not scrolled). + bool IsVisibleY; + bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not. + bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte + ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit + ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem + ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) + ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) + ImU8 SortDirectionsAvailList; // Ordered list of available sort directions (2-bits each, total 8-bits) + + ImGuiTableColumn() + { + memset(this, 0, sizeof(*this)); + StretchWeight = WidthRequest = -1.0f; + NameOffset = -1; + DisplayOrder = IndexWithinEnabledSet = -1; + PrevEnabledColumn = NextEnabledColumn = -1; + SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1; + } +}; + +// Transient cell data stored per row. +// sizeof() ~ 6 +struct ImGuiTableCellData +{ + ImU32 BgColor; // Actual color + ImGuiTableColumnIdx Column; // Column number +}; + +// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?) +struct ImGuiTableInstanceData +{ + ImGuiID TableInstanceID; + float LastOuterHeight; // Outer height from last frame + float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked) + float LastFrozenHeight; // Height of frozen section from last frame + + ImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; } +}; + +// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData +// sizeof() ~ 580 bytes + heap allocs described in TableBeginInitMemory() +struct IMGUI_API ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[] + ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[] + ImSpan Columns; // Point within RawData[] + ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) + ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. + ImBitArrayPtr EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map + ImBitArrayPtr EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data + ImBitArrayPtr VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) + int SettingsOffset; // Offset in g.SettingsTables + int LastFrameActive; + int ColumnsCount; // Number of columns declared in BeginTable() + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. + ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with + float RowPosY1; + float RowPosY2; + float RowMinHeight; // Height submitted to TableNextRow() + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; // Current row flags, see ImGuiTableRowFlags_ + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; // Counter for alternating background colors (can be fast-forwarded by e.g clipper), not same as CurrentRow because header rows typically don't increase this. + ImU32 RowBgColor[2]; // Background color override for current row. + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; // Padding from each borders + float CellPaddingY; + float CellSpacingX1; // Spacing between non-bordered cells + float CellSpacingX2; + float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details. + float ColumnsGivenWidth; // Sum of current column width + float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window + float ColumnsStretchSumWeights; // Sum of weight of all enabled stretching columns + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; // Lock minimum contents width while resizing down in order to not create feedback loops. But we allow growing the table. + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable(). + ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries + ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped + ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. + ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. + ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground() + ImGuiWindow* OuterWindow; // Parent window for the table + ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) + ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names + ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly + ImGuiTableInstanceData InstanceDataFirst; + ImVector InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn() + ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column! + ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing). + ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit. + ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0. + ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. + ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. + ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) + ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1 + ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. + ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. + ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column. + ImGuiTableColumnIdx RightMostStretchedColumn; // Index of right-most stretched column. + ImGuiTableColumnIdx ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot + ImGuiTableColumnIdx FreezeRowsRequest; // Requested frozen rows count + ImGuiTableColumnIdx FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx FreezeColumnsRequest; // Requested frozen columns count + ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row + ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. + bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. + bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). + bool IsSettingsRequestLoad; + bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data. + bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; // Set when we got past the frozen row. + bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() + bool HasScrollbarYCurr; // Whether ANY instance of this table had a vertical scrollbar during the current frame. + bool HasScrollbarYPrev; // Whether ANY instance of this table had a vertical scrollbar during the previous. + bool MemoryCompacted; + bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis + + ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; } + ~ImGuiTable() { IM_FREE(RawData); } +}; + +// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). +// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. +// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. +// sizeof() ~ 112 bytes. +struct IMGUI_API ImGuiTableTempData +{ + int TableIndex; // Index in g.Tables.Buf[] pool + float LastTimeActive; // Last timestamp this structure was used + + ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() + ImDrawListSplitter DrawSplitter; + + ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() + ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() + ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable() + ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable() + ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() + ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable() + float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable() + int HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable() + + ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; } +}; + +// sizeof() ~ 12 +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; // "Visible" in ini file + ImU8 IsStretch : 1; + + ImGuiTableColumnSettings() { - IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); - return TabsNames.Buf.Data + tab->NameOffset; + WidthOrWeight = 0.0f; + UserID = 0; + Index = -1; + DisplayOrder = SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + IsEnabled = 1; + IsStretch = 0; } }; +// This is designed to be stored in a single ImChunkStream (1 header followed by N ImGuiTableColumnSettings, etc.) +struct ImGuiTableSettings +{ + ImGuiID ID; // Set to 0 to invalidate/delete the setting + ImGuiTableFlags SaveFlags; // Indicate data we want to save using the Resizable/Reorderable/Sortable/Hideable flags (could be using its own flags..) + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + + ImGuiTableSettings() { memset(this, 0, sizeof(*this)); } + ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } +}; + //----------------------------------------------------------------------------- -// Internal API -// No guarantee of forward compatibility here. +// [SECTION] ImGui internal API +// No guarantee of forward compatibility here! //----------------------------------------------------------------------------- namespace ImGui { + // Windows // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) // If this ever crash because g.CurrentWindow is NULL it means that either // - ImGui::NewFrame() has never been called, which is illegal. @@ -1582,53 +2749,92 @@ namespace ImGui inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); IMGUI_API ImGuiWindow* FindWindowByName(const char* name); - IMGUI_API void FocusWindow(ImGuiWindow* window); - IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); - IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); - IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); - IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); - IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window); - IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window); + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); + IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); - IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); - IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); - IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); + IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window); + inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } + inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } + inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } + + // Windows: Display Order and Focus Order + IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* above_window); + IMGUI_API int FindWindowDisplayIndex(ImGuiWindow* window); + IMGUI_API ImGuiWindow* FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); + // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } - inline ImDrawList* GetForegroundDrawList(ImGuiWindow*) { ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. // Init - IMGUI_API void Initialize(ImGuiContext* context); - IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). + IMGUI_API void Initialize(); + IMGUI_API void Shutdown(); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). // NewFrame + IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); IMGUI_API void UpdateMouseMovingWindowNewFrame(); IMGUI_API void UpdateMouseMovingWindowEndFrame(); + // Generic context hooks + IMGUI_API ImGuiID AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook); + IMGUI_API void RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove); + IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); + + // Viewports + IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); + // Settings IMGUI_API void MarkIniSettingsDirty(); IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); - IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); - IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API void ClearIniSettings(); + IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); + IMGUI_API void RemoveSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + // Settings - Windows + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); + IMGUI_API void ClearWindowSettings(const char* name); + + // Localization + IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); + inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; } + // Scrolling - IMGUI_API void SetScrollX(ImGuiWindow* window, float new_scroll_x); - IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y); - IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f); - IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f); - IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); + IMGUI_API void SetScrollX(ImGuiWindow* window, float scroll_x); + IMGUI_API void SetScrollY(ImGuiWindow* window, float scroll_y); + IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio); + IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio); + + // Early work-in-progress API (ScrollToItem() will become public) + IMGUI_API void ScrollToItem(ImGuiScrollFlags flags = 0); + IMGUI_API void ScrollToRect(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); + IMGUI_API ImVec2 ScrollToRectEx(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); +//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& rect) { ScrollToRect(window, rect, ImGuiScrollFlags_KeepVisibleEdgeY); } +//#endif // Basic Accessors - inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } + inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); @@ -1637,159 +2843,341 @@ namespace ImGui IMGUI_API ImGuiID GetHoveredID(); IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); - IMGUI_API void MarkItemEdited(ImGuiID id); - IMGUI_API void PushOverrideID(ImGuiID id); + IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. + IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) + IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); + IMGUI_API ImGuiID GetIDWithSeed(int n, ImGuiID seed); // Basic Helpers for widget code IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); - IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); - IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); + inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min. + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); - IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); - IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested - IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); + IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); - IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); - IMGUI_API void PopItemFlag(); - IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); + // Parameter stacks (shared) + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); + // Logging/Capture - IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. - IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); // Popups, Modals, Tooltips - IMGUI_API void OpenPopupEx(ImGuiID id); + IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); + IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); - IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! + IMGUI_API void ClosePopupsExceptModals(); + IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); - IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); + IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); + IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); + IMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); - IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default); + IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); + + // Menus + IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); + IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true); + IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); - // Navigation + // Combos + IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); + IMGUI_API bool BeginComboPreview(); + IMGUI_API void EndComboPreview(); + + // Gamepad/Keyboard Navigation IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API void NavInitRequestApplyResult(); IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); IMGUI_API void NavMoveRequestCancel(); - IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); - IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); - IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); - IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis); + IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. - IMGUI_API void SetNavID(ImGuiID id, int nav_layer); - IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel); + IMGUI_API void SetNavWindow(ImGuiWindow* window); + IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. + inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } + inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; } + inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } + inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; } + inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } + inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } + inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } + inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); } + inline ImGuiKey ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key) + { + ImGuiContext& g = *ctx; + if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; + if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; + if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; + if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; + if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl); + return key; + } + + IMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key); + inline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); } + IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size); + inline ImGuiKey MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); } + IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); + IMGUI_API ImVec2 GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down); + IMGUI_API float GetNavTweakPressedAmount(ImGuiAxis axis); + IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate); + IMGUI_API void SetActiveIdUsingAllKeyboardKeys(); inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } - inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } - inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } - IMGUI_API bool IsMouseDragPastThreshold(int button, float lock_threshold = -1.0f); - inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } - inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } - inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } + + // [EXPERIMENTAL] Low-Level: Key/Input Ownership + // - The idea is that instead of "eating" a given input, we can link to an owner id. + // - Ownership is most often claimed as a result of reacting to a press/down event (but occasionally may be claimed ahead). + // - Input queries can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID. + // - Legacy input queries (without specifying an owner or _Any or _None) are equivalent to using ImGuiKeyOwner_Any (== 0). + // - Input ownership is automatically released on the frame after a key is released. Therefore: + // - for ownership registration happening as a result of a down/press event, the SetKeyOwner() call may be done once (common case). + // - for ownership registration happening ahead of a down/press event, the SetKeyOwner() call needs to be made every frame (happens if e.g. claiming ownership on hover). + // - SetItemKeyOwner() is a shortcut for common simple case. A custom widget will probably want to call SetKeyOwner() multiple times directly based on its interaction state. + // - This is marked experimental because not all widgets are fully honoring the Set/Test idioms. We will need to move forward step by step. + // Please open a GitHub Issue to submit your usage scenario or if there's a use case you need solved. + IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key); + IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. + IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id' + inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } + + // [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership + // - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag. + // - Expected to be later promoted to public API, the prototypes are designed to replace existing ones (since owner_id can default to Any == 0) + // - Specifying a value for 'ImGuiID owner' will test that EITHER the key is NOT owned (UNLESS locked), EITHER the key is owned by 'owner'. + // Legacy functions use ImGuiKeyOwner_Any meaning that they typically ignore ownership, unless a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease. + // - Binding generators may want to ignore those for now, or suffix them with Ex() until we decide if this gets moved into public API. + IMGUI_API bool IsKeyDown(ImGuiKey key, ImGuiID owner_id); + IMGUI_API bool IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); // Important: when transitioning from old to new IsKeyPressed(): old API has "bool repeat = true", so would default to repeat. New API requiress explicit ImGuiInputFlags_Repeat. + IMGUI_API bool IsKeyReleased(ImGuiKey key, ImGuiID owner_id); + IMGUI_API bool IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id); + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id); + + // [EXPERIMENTAL] Shortcut Routing + // - ImGuiKeyChord = a ImGuiKey optionally OR-red with ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. + // ImGuiKey_C (accepted by functions taking ImGuiKey or ImGuiKeyChord) + // ImGuiKey_C | ImGuiMod_Ctrl (accepted by functions taking ImGuiKeyChord) + // ONLY ImGuiMod_XXX values are legal to 'OR' with an ImGuiKey. You CANNOT 'OR' two ImGuiKey values. + // - When using one of the routing flags (e.g. ImGuiInputFlags_RouteFocused): routes requested ahead of time given a chord (key + modifiers) and a routing policy. + // - Routes are resolved during NewFrame(): if keyboard modifiers are matching current ones: SetKeyOwner() is called + route is granted for the frame. + // - Route is granted to a single owner. When multiple requests are made we have policies to select the winning route. + // - Multiple read sites may use the same owner id and will all get the granted route. + // - For routing: when owner_id is 0 we use the current Focus Scope ID as a default owner in order to identify our location. + IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0); + IMGUI_API bool SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0); + IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id); + IMGUI_API ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord); + + // [EXPERIMENTAL] Focus Scope + // This is generally used to identify a unique input location (for e.g. a selection set) + // There is one per window (automatically set in Begin), but: + // - Selection patterns generally need to react (e.g. clear a selection) when landing on one item of the set. + // So in order to identify a set multiple lists in same window may each need a focus scope. + // If you imagine an hypothetical BeginSelectionGroup()/EndSelectionGroup() api, it would likely call PushFocusScope()/EndFocusScope() + // - Shortcut routing also use focus scope as a default location identifier if an owner is not provided. + // We don't use the ID Stack for this as it is common to want them separate. + IMGUI_API void PushFocusScope(ImGuiID id); + IMGUI_API void PopFocusScope(); + inline ImGuiID GetCurrentFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentFocusScopeId; } // Focus scope we are outputting into, set by PushFocusScope() // Drag and Drop + IMGUI_API bool IsDragDropActive(); IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); IMGUI_API void ClearDragDrop(); IMGUI_API bool IsDragDropPayloadBeingAccepted(); + IMGUI_API void RenderDragDropTargetRect(const ImRect& bb); - // New Columns API (FIXME-WIP) - IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). - IMGUI_API void EndColumns(); // close columns + // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns IMGUI_API void PushColumnClipRect(int column_index); IMGUI_API void PushColumnsBackground(); IMGUI_API void PopColumnsBackground(); IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); - IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); - IMGUI_API float GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm); - IMGUI_API float GetColumnNormFromOffset(const ImGuiColumns* columns, float offset); + IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); + IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); + + // Tables: Candidates for public API + IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnWidth(int column_n, float width); + IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); + IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. + IMGUI_API float TableGetHeaderRowHeight(); + IMGUI_API void TablePushBackgroundChannel(); + IMGUI_API void TablePopBackgroundChannel(); + + // Tables: Internals + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } + IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); + IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); + IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); + IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); + IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); + IMGUI_API void TableUpdateLayout(ImGuiTable* table); + IMGUI_API void TableUpdateBorders(ImGuiTable* table); + IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); + IMGUI_API void TableDrawBorders(ImGuiTable* table); + IMGUI_API void TableDrawContextMenu(ImGuiTable* table); + IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); + IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); + inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } + inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } + IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); + IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); + IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API void TableBeginRow(ImGuiTable* table); + IMGUI_API void TableEndRow(ImGuiTable* table); + IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); + IMGUI_API void TableEndCell(ImGuiTable* table); + IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); + IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); + IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableRemove(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); + IMGUI_API void TableGcCompactSettings(); + + // Tables: Settings + IMGUI_API void TableLoadSettings(ImGuiTable* table); + IMGUI_API void TableSaveSettings(ImGuiTable* table); + IMGUI_API void TableResetSettings(ImGuiTable* table); + IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); + IMGUI_API void TableSettingsAddSettingsHandler(); + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); // Tab Bars + inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order); + IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar); + inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); } + IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); - IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); - IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); - IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset); + IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos); + IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); + IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); - IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id); + IMGUI_API void TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped); // Render helpers // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); - IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); - IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. - IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); // Render helpers (those functions don't access any ImGui state!) IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); - IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); + IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while] - inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); } - inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); } -#endif + IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding); // Widgets IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); - IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); + IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); + IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); + IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); + IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); + + // Widgets: Window Decorations IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); - IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API void Scrollbar(ImGuiAxis axis); - IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); + IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); - IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders - IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners + IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); - IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags); - IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); - IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); - IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging IMGUI_API void TreePushOverrideID(ImGuiID id); + IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open); + IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging. // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " - template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, float power, ImGuiDragFlags flags); - template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); - template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos); - template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + template IMGUI_API bool CheckboxFlagsT(const char* label, T* flags, T flags_value); // Data type helpers IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); - IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2); - IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); // InputText IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format); - inline bool TempInputTextIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputTextId == id); } + IMGUI_API void InputTextDeactivateHook(ImGuiID id); + IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); + IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); + inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } + inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active // Color IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); @@ -1797,56 +3185,114 @@ namespace ImGui IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); // Plot - IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); + IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg); // Shade functions (write over already created vertices) IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); + // Garbage collection + IMGUI_API void GcCompactTransientMiscBuffers(); + IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + + // Debug Log + IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1); + IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1); + // Debug Tools - inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); } + IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time! + IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time! + IMGUI_API void DebugLocateItemResolveWithLastItem(); + inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); } inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } + IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); + IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); + IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); + IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); + IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); + IMGUI_API void DebugNodeFont(ImFont* font); + IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); + IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); + IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); + IMGUI_API void DebugNodeTable(ImGuiTable* table); + IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings); + IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state); + IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label); + IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); + IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); + IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); + IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); + IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); + + // Obsolete functions +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 + inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 + + // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): + // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' + // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' + // (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))' (WIP) + // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() + inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd() + inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem +#endif +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! +#endif } // namespace ImGui -// ImFontAtlas internals -IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); -IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); -IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); -IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); -// Debug Tools -// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item. -#ifndef IM_DEBUG_BREAK -#if defined(__clang__) -#define IM_DEBUG_BREAK() __builtin_debugtrap() -#elif defined (_MSC_VER) -#define IM_DEBUG_BREAK() __debugbreak() -#else -#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas internal API +//----------------------------------------------------------------------------- + +// This structure is likely to evolve as we add support for incremental atlas updates +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; + +// Helper for font builder +#ifdef IMGUI_ENABLE_STB_TRUETYPE +IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); #endif -#endif // #ifndef IM_DEBUG_BREAK +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +//----------------------------------------------------------------------------- +// [SECTION] Test Engine specific hooks (imgui_test_engine) +//----------------------------------------------------------------------------- -// Test Engine Hooks (imgui_tests) -//#define IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE -extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); -extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); -extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); -extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); -extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); -#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) -#define IMGUI_TEST_ENGINE_LOG(_FMT, ...) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data); // item_data may be NULL +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id); + +// In IMGUI_VERSION_NUM >= 18934: changed IMGUI_TEST_ENGINE_ITEM_ADD(bb,id) to IMGUI_TEST_ENGINE_ITEM_ADD(id,bb,item_data); +#define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _ID, _BB, _ITEM_DATA) // Register item bounding box +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #else -#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID) do { } while (0) -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) -#define IMGUI_TEST_ENGINE_LOG(_FMT, ...) do { } while (0) +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) #endif +//----------------------------------------------------------------------------- + #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) @@ -1856,3 +3302,5 @@ extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const cha #ifdef _MSC_VER #pragma warning (pop) #endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/src/ui/imguiLib/imgui_widgets.cpp b/src/ui/imguiLib/imgui_widgets.cpp index 816525427..83f27111b 100644 --- a/src/ui/imguiLib/imgui_widgets.cpp +++ b/src/ui/imguiLib/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.74 +// dear imgui, v1.89.6 // (widgets code) /* @@ -32,47 +32,66 @@ Index of this file: #define _CRT_SECURE_NO_WARNINGS #endif -#include "imgui.h" #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE #include "imgui_internal.h" -#include // toupper +// System includes #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else #include // intptr_t #endif +//------------------------------------------------------------------------- +// Warnings +//------------------------------------------------------------------------- + // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif // Clang/GCC warnings with -Weverything #if defined(__clang__) -#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. -#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 -#endif -#if __has_warning("-Wdouble-promotion") -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! #endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif //------------------------------------------------------------------------- // Data //------------------------------------------------------------------------- +// Widgets +static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f; // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior. +static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; // Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags. + // Those MIN/MAX values are not define because we need to point to them static const signed char IM_S8_MIN = -128; static const signed char IM_S8_MAX = 127; @@ -105,9 +124,9 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); //------------------------------------------------------------------------- // For InputTextEx() -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); -static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); //------------------------------------------------------------------------- // [SECTION] Widgets: Text, etc. @@ -133,9 +152,13 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - IM_ASSERT(text != NULL); + + // Accept null ranges + if (text == text_end) + text = text_end = ""; + + // Calculate length const char* text_begin = text; if (text_end == NULL) text_end = text + strlen(text); // FIXME-OPT @@ -143,7 +166,21 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); const float wrap_pos_x = window->DC.TextWrapPos; const bool wrap_enabled = (wrap_pos_x >= 0.0f); - if (text_end - text > 2000 && !wrap_enabled) + if (text_end - text <= 2000 || wrap_enabled) + { + // Common case + const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; + const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + if (!ItemAdd(bb, 0)) + return; + + // Render (we don't hide text after ## in this end-user function) + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } + else { // Long text! // Perform manual coarse clipping to optimize for long multi-line text @@ -152,7 +189,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. const char* line = text; const float line_height = GetTextLineHeight(); - ImVec2 text_size(0,0); + ImVec2 text_size(0, 0); // Lines to skip (can't skip when logging text) ImVec2 pos = text_pos; @@ -182,7 +219,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); while (line < text_end) { - if (IsClippedEx(line_rect, 0, false)) + if (IsClippedEx(line_rect, 0)) break; const char* line_end = (const char*)memchr(line, '\n', text_end - line); @@ -216,19 +253,6 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) ItemSize(text_size, 0.0f); ItemAdd(bb, 0); } - else - { - const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; - const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); - - ImRect bb(text_pos, text_pos + text_size); - ItemSize(text_size, 0.0f); - if (!ItemAdd(bb, 0)) - return; - - // Render (we don't hide text after ## in this end-user function) - RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); - } } void ImGui::TextUnformatted(const char* text, const char* text_end) @@ -250,9 +274,9 @@ void ImGui::TextV(const char* fmt, va_list args) if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); + const char* text, *text_end; + ImFormatStringToTempBufferV(&text, &text_end, fmt, args); + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); } void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) @@ -280,7 +304,8 @@ void ImGui::TextDisabled(const char* fmt, ...) void ImGui::TextDisabledV(const char* fmt, va_list args) { - PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); + ImGuiContext& g = *GImGui; + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); TextV(fmt, args); PopStyleColor(); } @@ -295,8 +320,8 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); - bool need_backup = (window->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + ImGuiContext& g = *GImGui; + const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); TextV(fmt, args); @@ -323,17 +348,20 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) const ImGuiStyle& style = g.Style; const float w = CalcItemWidth(); + const char* value_text_begin, *value_text_end; + ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args); + const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2)); - const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); + + const ImVec2 pos = window->DC.CursorPos; + const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2)); + const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0)) return; // Render - const char* value_text_begin = &g.TempBuffer[0]; - const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f)); + RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -356,8 +384,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const char* text_begin = g.TempBuffer; - const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const char* text_begin, *text_end; + ImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args); const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding ImVec2 pos = window->DC.CursorPos; @@ -369,7 +397,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Render ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, g.FontSize*0.5f), text_col); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col); RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); } @@ -383,11 +411,14 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // - ArrowButton() // - CloseButton() [Internal] // - CollapseButton() [Internal] -// - ScrollbarEx() [Internal] +// - GetWindowScrollbarID() [Internal] +// - GetWindowScrollbarRect() [Internal] // - Scrollbar() [Internal] +// - ScrollbarEx() [Internal] // - Image() // - ImageButton() // - Checkbox() +// - CheckboxFlagsT() [Internal] // - CheckboxFlags() // - RadioButton() // - ProgressBar() @@ -453,26 +484,23 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (flags & ImGuiButtonFlags_Disabled) - { - if (out_hovered) *out_hovered = false; - if (out_held) *out_held = false; - if (g.ActiveId == id) ClearActiveID(); - return false; - } + // Default only reacts to left mouse button + if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) + flags |= ImGuiButtonFlags_MouseButtonDefault_; - // Default behavior requires click+release on same spot - if ((flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick)) == 0) - flags |= ImGuiButtonFlags_PressedOnClickRelease; + // Default behavior requires click + release inside bounding box + if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) + flags |= ImGuiButtonFlags_PressedOnDefault_; ImGuiWindow* backup_hovered_window = g.HoveredWindow; - const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; if (flatten_hovered_children) g.HoveredWindow = window; #ifdef IMGUI_ENABLE_TEST_ENGINE - if (id != 0 && window->DC.LastItemId != id) - ImGuiTestEngineHook_ItemAdd(&g, bb, id); + // Alternate registration spot, for when caller didn't use ItemAdd() + if (id != 0 && g.LastItemData.ID != id) + IMGUI_TEST_ENGINE_ITEM_ADD(id, bb, NULL); #endif bool pressed = false; @@ -488,9 +516,10 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { hovered = true; SetHoveredID(id); - if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, 0.70f, 0.00f)) + if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) { pressed = true; + g.DragDropHoldJustPressedId = id; FocusWindow(window); } } @@ -502,38 +531,68 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) hovered = false; - // Mouse + // Mouse handling + const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; if (hovered) { + // Poll mouse buttons + // - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId. + // - Technically we only need some values in one code path, but since this is gated by hovered test this is fine. + int mouse_button_clicked = -1; + int mouse_button_released = -1; + for (int button = 0; button < 3; button++) + if (flags & (ImGuiButtonFlags_MouseButtonLeft << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here. + { + if (IsMouseClicked(button, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; } + if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; } + } + + // Process initial action if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { - if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) + if (mouse_button_clicked != -1 && g.ActiveId != id) { - SetActiveID(id, window); - if (!(flags & ImGuiButtonFlags_NoNavFocus)) - SetFocusID(id, window); - FocusWindow(window); + if (!(flags & ImGuiButtonFlags_NoSetKeyOwner)) + SetKeyOwner(MouseButtonToKey(mouse_button_clicked), id); + if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere)) + { + SetActiveID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveId) + ClearActiveID(); + else + SetActiveID(id, window); // Hold on ID + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); + } } - if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) + if (flags & ImGuiButtonFlags_PressedOnRelease) { - pressed = true; - if (flags & ImGuiButtonFlags_NoHoldingActiveID) + if (mouse_button_released != -1) + { + const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + if (!has_repeated_at_least_once) + pressed = true; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); ClearActiveID(); - else - SetActiveID(id, window); // Hold on ID - FocusWindow(window); - } - if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) - { - if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps - pressed = true; - ClearActiveID(); + } } // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. - if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true)) - pressed = true; + if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat)) + pressed = true; } if (pressed) @@ -543,45 +602,62 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Gamepad/Keyboard navigation // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) - if (!(flags & ImGuiButtonFlags_NoHoveredOnNav)) + if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) hovered = true; - if (g.NavActivateDownId == id) { bool nav_activated_by_code = (g.NavActivateId == id); - bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + bool nav_activated_by_inputs = (g.NavActivatePressedId == id); + if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat)) + { + // Avoid pressing multiple keys from triggering excessive amount of repeat events + const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); + const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter); + const ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate); + const float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration); + nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + } if (nav_activated_by_code || nav_activated_by_inputs) - pressed = true; - if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) { // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. - g.NavActivateId = id; // This is so SetActiveId assign a Nav source + pressed = true; SetActiveID(id, window); - if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) + g.ActiveIdSource = g.NavInputSource; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) SetFocusID(id, window); } } + // Process while held bool held = false; if (g.ActiveId == id) { - if (pressed) - g.ActiveIdHasBeenPressedBefore = true; if (g.ActiveIdSource == ImGuiInputSource_Mouse) { if (g.ActiveIdIsJustActivated) g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; - if (g.IO.MouseDown[0]) + + const int mouse_button = g.ActiveIdMouseButton; + if (mouse_button == -1) + { + // Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304). + ClearActiveID(); + } + else if (IsMouseDown(mouse_button, test_owner_id)) { held = true; } else { - if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) && !g.DragDropActive) + bool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0; + bool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0; + if ((release_in || release_anywhere) && !g.DragDropActive) { - bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDownWasDoubleClick[0]; - bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay; // Repeat mode trumps - if (!is_double_click_release && !is_repeating_already) + // Report as pressed when releasing the mouse (this is the most common path) + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; + bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); + if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) pressed = true; } ClearActiveID(); @@ -589,11 +665,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (!(flags & ImGuiButtonFlags_NoNavFocus)) g.NavDisableHighlight = true; } - else if (g.ActiveIdSource == ImGuiInputSource_Nav) + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { + // When activated using Nav, we hold on the ActiveID until activation button is released if (g.NavActivateDownId != id) ClearActiveID(); } + if (pressed) + g.ActiveIdHasBeenPressedBefore = true; } if (out_hovered) *out_hovered = hovered; @@ -623,8 +702,9 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, id)) return false; - if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -632,19 +712,22 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + + if (g.LogEnabled) + LogSetNextTextDecoration("[", "]"); RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) // CloseCurrentPopup(); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return pressed; } bool ImGui::Button(const char* label, const ImVec2& size_arg) { - return ButtonEx(label, size_arg, 0); + return ButtonEx(label, size_arg, ImGuiButtonFlags_None); } // Small buttons fits within text without additional vertical spacing. @@ -660,8 +743,9 @@ bool ImGui::SmallButton(const char* label) // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) -bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -677,18 +761,19 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) return false; bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; } bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; const ImGuiID id = window->GetID(str_id); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); const float default_size = GetFrameHeight(); @@ -696,7 +781,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu if (!ItemAdd(bb, id)) return false; - if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; bool hovered, held; @@ -709,42 +794,51 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; } bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) { float sz = GetFrameHeight(); - return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), 0); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); } // Button to close a window -bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size) +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. - // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) + // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); - bool is_clipped = !ItemAdd(bb, id); + ImRect bb_interact = bb; + const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); + if (area_to_visible_ratio < 1.5f) + bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); + + // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + bool is_clipped = !ItemAdd(bb_interact, id); bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held); + bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held); if (is_clipped) return pressed; // Render + // FIXME: Clarify this mess ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); ImVec2 center = bb.GetCenter(); if (hovered) - window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12); + window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col); float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; ImU32 cross_col = GetColorU32(ImGuiCol_Text); center -= ImVec2(0.5f, 0.5f); - window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f); - window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f); return pressed; } @@ -762,13 +856,12 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) // Render ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); - ImVec2 center = bb.GetCenter(); if (hovered || held) - window->DrawList->AddCircleFilled(center/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12); + window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col); RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); // Switch to moving the window after mouse is moved beyond the initial drag threshold - if (IsItemActive() && IsMouseDragging()) + if (IsItemActive() && IsMouseDragging(0)) StartMouseMovingWindow(window); return pressed; @@ -776,7 +869,50 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) { - return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); + return window->GetID(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. +ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) +{ + const ImRect outer_rect = window->Rect(); + const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) + IM_ASSERT(scrollbar_size > 0.0f); + if (axis == ImGuiAxis_X) + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x, outer_rect.Max.y); + else + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y); +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = GetWindowScrollbarID(window, axis); + + // Calculate scrollbar bounding box + ImRect bb = GetWindowScrollbarRect(window, axis); + ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone; + if (axis == ImGuiAxis_X) + { + rounding_corners |= ImDrawFlags_RoundCornersBottomLeft; + if (!window->ScrollbarY) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + else + { + if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) + rounding_corners |= ImDrawFlags_RoundCornersTopRight; + if (!window->ScrollbarX) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; + float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; + ImS64 scroll = (ImS64)window->Scroll[axis]; + ScrollbarEx(bb, id, axis, &scroll, (ImS64)size_avail, (ImS64)size_contents, rounding_corners); + window->Scroll[axis] = (float)scroll; } // Vertical/Horizontal scrollbar @@ -785,7 +921,7 @@ ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. // Still, the code should probably be made simpler.. -bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners) +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_avail_v, ImS64 size_contents_v, ImDrawFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -797,7 +933,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) return false; - // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) float alpha = 1.0f; if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); @@ -806,33 +942,33 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa const ImGuiStyle& style = g.Style; const bool allow_interaction = (alpha >= 1.0f); - const bool horizontal = (axis == ImGuiAxis_X); ImRect bb = bb_frame; bb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) - const float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); + const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) // But we maintain a minimum size in pixel to allow for the user to still aim inside. IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. - const float win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), 1.0f); - const float grab_h_pixels = ImClamp(scrollbar_size_v * (size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); + const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), (ImS64)1); + const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_avail_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). bool held = false; bool hovered = false; + ItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav); ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); - float scroll_max = ImMax(1.0f, size_contents_v - size_avail_v); - float scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); - float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space if (held && allow_interaction && grab_h_norm < 1.0f) { - float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; - float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; + const float scrollbar_pos_v = bb.Min[axis]; + const float mouse_pos_v = g.IO.MousePos[axis]; // Click position in scrollbar normalized space (0.0f->1.0f) const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); @@ -849,13 +985,13 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; } - // Apply scroll + // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); - *p_scroll_v = IM_ROUND(scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); + *p_scroll_v = (ImS64)(scroll_v_norm * scroll_max); // Update values for rendering - scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); + scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Update distance to grab now that we have seeked and saturated @@ -864,10 +1000,11 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa } // Render - window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, rounding_corners); + const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); ImRect grab_rect; - if (horizontal) + if (axis == ImGuiAxis_X) grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); else grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); @@ -876,38 +1013,6 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa return held; } -void ImGui::Scrollbar(ImGuiAxis axis) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - const ImGuiID id = GetWindowScrollbarID(window, axis); - KeepAliveID(id); - - // Calculate scrollbar bounding box - const ImRect outer_rect = window->Rect(); - const ImRect inner_rect = window->InnerRect; - const float border_size = window->WindowBorderSize; - const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; - IM_ASSERT(scrollbar_size > 0.0f); - const float other_scrollbar_size = window->ScrollbarSizes[axis]; - ImDrawCornerFlags rounding_corners = (other_scrollbar_size <= 0.0f) ? ImDrawCornerFlags_BotRight : 0; - ImRect bb; - if (axis == ImGuiAxis_X) - { - bb.Min = ImVec2(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size)); - bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y); - rounding_corners |= ImDrawCornerFlags_BotLeft; - } - else - { - bb.Min = ImVec2(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y); - bb.Max = ImVec2(outer_rect.Max.x, window->InnerRect.Max.y); - rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; - } - ScrollbarEx(bb, id, axis, &window->Scroll[axis], inner_rect.Max[axis] - inner_rect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); -} - void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { ImGuiWindow* window = GetCurrentWindow(); @@ -932,46 +1037,71 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& } } -// frame_padding < 0: uses FramePadding from style (default) -// frame_padding = 0: no framing -// frame_padding > 0: set framing size -// The color used are the button colors. -bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) +// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - - // Default to using texture ID as ID. User can still push string/integer prefixes. - // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. - PushID(user_texture_id.get()); - const ImGuiID id = window->GetID("#image"); - PopID(); - - const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; - const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); - const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); + const ImVec2 padding = g.Style.FramePadding; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2.0f); ItemSize(bb); if (!ItemAdd(bb, id)) return false; bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderNavHighlight(bb, id); - RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding)); + RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) - window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col)); - window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); + window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); return pressed; } +bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + return ImageButtonEx(window->GetID(str_id), user_texture_id, size, uv0, uv1, bg_col, tint_col); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy API obsoleted in 1.89. Two differences with new ImageButton() +// - new ImageButton() requires an explicit 'const char* str_id' Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID) +// - new ImageButton() always use style.FramePadding Old ImageButton() had an override argument. +// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions. +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + if (frame_padding >= 0) + PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding)); + bool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col); + if (frame_padding >= 0) + PopStyleVar(); + return ret; +} +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + bool ImGui::Checkbox(const char* label, bool* v) { ImGuiWindow* window = GetCurrentWindow(); @@ -988,7 +1118,10 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id)) + { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return false; + } bool hovered, held; bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); @@ -1002,42 +1135,79 @@ bool ImGui::Checkbox(const char* label, bool* v) RenderNavHighlight(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); - if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue) + bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) { // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); } else if (*v) { const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); - RenderCheckMark(check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad*2.0f); + RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); } + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]"); + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(label_pos, label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } -bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +template +bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) { - bool v = ((*flags & flags_value) == flags_value); - bool pressed = Checkbox(label, &v); + bool all_on = (*flags & flags_value) == flags_value; + bool any_on = (*flags & flags_value) != 0; + bool pressed; + if (!all_on && any_on) + { + ImGuiContext& g = *GImGui; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_MixedValue; + pressed = Checkbox(label, &all_on); + g.CurrentItemFlags = backup_item_flags; + } + else + { + pressed = Checkbox(label, &all_on); + + } if (pressed) { - if (v) + if (all_on) *flags |= flags_value; else *flags &= ~flags_value; } - return pressed; } +bool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + bool ImGui::RadioButton(const char* label, bool active) { ImGuiWindow* window = GetCurrentWindow(); @@ -1068,24 +1238,27 @@ bool ImGui::RadioButton(const char* label, bool active) MarkItemEdited(id); RenderNavHighlight(total_bb, id); - window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); + const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); if (active) { const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); - window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark)); } if (style.FrameBorderSize > 0.0f) { - window->DrawList->AddCircle(center + ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); - window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize); } + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); + LogRenderedText(&label_pos, active ? "(x)" : "( )"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(label_pos, label); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return pressed; } @@ -1109,7 +1282,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over const ImGuiStyle& style = g.Style; ImVec2 pos = window->DC.CursorPos; - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f); ImRect bb(pos, pos + size); ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, 0)) @@ -1126,13 +1299,13 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over char overlay_buf[32]; if (!overlay) { - ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f); + ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f); overlay = overlay_buf; } ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) - RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb); + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); } void ImGui::Bullet() @@ -1143,18 +1316,18 @@ void ImGui::Bullet() ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); ItemSize(bb); if (!ItemAdd(bb, 0)) { - SameLine(0, style.FramePadding.x*2); + SameLine(0, style.FramePadding.x * 2); return; } // Render and stay on same line ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), text_col); SameLine(0, style.FramePadding.x * 2.0f); } @@ -1176,7 +1349,7 @@ void ImGui::Spacing() ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - ItemSize(ImVec2(0,0)); + ItemSize(ImVec2(0, 0)); } void ImGui::Dummy(const ImVec2& size) @@ -1199,8 +1372,9 @@ void ImGui::NewLine() ImGuiContext& g = *GImGui; const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.IsSameLine = false; if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. - ItemSize(ImVec2(0,0)); + ItemSize(ImVec2(0, 0)); else ItemSize(ImVec2(0.0f, g.FontSize)); window->DC.LayoutType = backup_layout_type; @@ -1218,7 +1392,9 @@ void ImGui::AlignTextToFramePadding() } // Horizontal/vertical separating line -void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) +// FIXME: Surprisingly, this seemingly trivial widget is a victim of many different legacy/tricky layout issues. +// Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are. +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -1226,21 +1402,20 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) ImGuiContext& g = *GImGui; IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + IM_ASSERT(thickness > 0.0f); - float thickness_draw = 1.0f; - float thickness_layout = 0.0f; if (flags & ImGuiSeparatorFlags_Vertical) { - // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + // Vertical separator, for menu bars (use current line height). float y1 = window->DC.CursorPos.y; float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; - const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); - ItemSize(ImVec2(thickness_layout, 0.0f)); + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2)); + ItemSize(ImVec2(thickness, 0.0f)); if (!ItemAdd(bb, 0)) return; // Draw - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogText(" |"); } @@ -1249,31 +1424,39 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // Horizontal Separator float x1 = window->Pos.x; float x2 = window->Pos.x + window->Size.x; - if (!window->DC.GroupStack.empty()) + + // FIXME-WORKRECT: old hack (#205) until we decide of consistent behavior with WorkRect/Indent and Separator + if (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID) x1 += window->DC.Indent.x; - ImGuiColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + // FIXME-WORKRECT: In theory we should simply be using WorkRect.Min.x/Max.x everywhere but it isn't aesthetically what we want, + // need to introduce a variant of WorkRect for that purpose. (#4787) + if (ImGuiTable* table = g.CurrentTable) + { + x1 = table->Columns[table->CurrentColumn].MinX; + x2 = table->Columns[table->CurrentColumn].MaxX; + } + + // Before Tables API happened, we relied on Separator() to span all columns of a Columns() set. + // We currently don't need to provide the same feature for tables because tables naturally have border features. + ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; if (columns) PushColumnsBackground(); // We don't provide our width to the layout so that it doesn't get feed back into AutoFit - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); - ItemSize(ImVec2(0.0f, thickness_layout)); - if (!ItemAdd(bb, 0)) - { - if (columns) - { - PopColumnsBackground(); - columns->LineMinY = window->DC.CursorPos.y; - } - return; - } + // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) + const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); + ItemSize(ImVec2(0.0f, thickness_for_layout)); - // Draw - window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); - if (g.LogEnabled) - LogRenderedText(&bb.Min, "--------------------------------"); + if (ItemAdd(bb, 0)) + { + // Draw + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------\n"); + } if (columns) { PopColumnsBackground(); @@ -1289,33 +1472,97 @@ void ImGui::Separator() if (window->SkipItems) return; - // Those flags should eventually be overridable by the user + // Those flags should eventually be configurable by the user + // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; - flags |= ImGuiSeparatorFlags_SpanAllColumns; - SeparatorEx(flags); + flags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot. + SeparatorEx(flags, 1.0f); +} + +void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = g.Style; + + const ImVec2 label_size = CalcTextSize(label, label_end, false); + const ImVec2 pos = window->DC.CursorPos; + const ImVec2 padding = style.SeparatorTextPadding; + + const float separator_thickness = style.SeparatorTextBorderSize; + const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); + const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); + const float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); + ItemSize(min_size, text_baseline_y); + if (!ItemAdd(bb, id)) + return; + + const float sep1_x1 = pos.x; + const float sep2_x2 = bb.Max.x; + const float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); + + const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); + const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN + + // This allows using SameLine() to position something in the 'extra_w' + window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x; + + const ImU32 separator_col = GetColorU32(ImGuiCol_Separator); + if (label_size.x > 0.0f) + { + const float sep1_x2 = label_pos.x - style.ItemSpacing.x; + const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; + if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness); + if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + if (g.LogEnabled) + LogSetNextTextDecoration("---", NULL); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); + } + else + { + if (g.LogEnabled) + LogText("---"); + if (separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + } +} + +void ImGui::SeparatorText(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + // The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want: + // - allow separator-text to be draggable items (would require a stable ID + a noticeable highlight) + // - this high-level entry point to allow formatting? (which in turns may require ID separate from formatted string) + // - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...' + // Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item, + // and then we can turn this into a format function. + SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f); } // Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. -bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay) +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; - bool item_add = ItemAdd(bb, id); - window->DC.ItemFlags = item_flags_backup; - if (!item_add) + if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav)) return false; bool hovered, held; ImRect bb_interact = bb; bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (hovered) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb if (g.ActiveId != id) SetItemAllowOverlap(); - if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) + if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); ImRect bb_render = bb; @@ -1346,7 +1593,9 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float } } - // Render + // Render at new position + if (bg_col & IM_COL32_A_MASK) + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f); const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); @@ -1363,11 +1612,13 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) } // Shrink excess width from a set of item, by removing width from the larger items first. +// Set items Width to -1.0f to disable shrinking this item. void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess) { if (count == 1) { - items[0].Width = ImMax(items[0].Width - width_excess, 1.0f); + if (items[0].Width >= 0.0f) + items[0].Width = ImMax(items[0].Width - width_excess, 1.0f); return; } ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); @@ -1376,14 +1627,16 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc { while (count_same_width < count && items[0].Width <= items[count_same_width].Width) count_same_width++; - float max_width_to_remove_per_item = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + if (max_width_to_remove_per_item <= 0.0f) + break; float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item); for (int item_n = 0; item_n < count_same_width; item_n++) items[item_n].Width -= width_to_remove_per_item; width_excess -= width_to_remove_per_item * count_same_width; } - // Round width and redistribute remainder left-to-right (could make it an option of the function?) + // Round width and redistribute remainder // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator. width_excess = 0.0f; for (int n = 0; n < count; n++) @@ -1392,17 +1645,24 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc width_excess += items[n].Width - width_rounded; items[n].Width = width_rounded; } - if (width_excess > 0.0f) - for (int n = 0; n < count; n++) - if (items[n].Index < (int)(width_excess + 0.01f)) - items[n].Width += 1.0f; + while (width_excess > 0.0f) + for (int n = 0; n < count && width_excess > 0.0f; n++) + { + float width_to_add = ImMin(items[n].InitialWidth - items[n].Width, 1.0f); + items[n].Width += width_to_add; + width_excess -= width_to_add; + } } //------------------------------------------------------------------------- // [SECTION] Widgets: ComboBox //------------------------------------------------------------------------- +// - CalcMaxPopupHeightFromItemCount() [Internal] // - BeginCombo() +// - BeginComboPopup() [Internal] // - EndCombo() +// - BeginComboPreview() [Internal] +// - EndComboPreview() [Internal] // - Combo() //------------------------------------------------------------------------- @@ -1416,101 +1676,132 @@ static float CalcMaxPopupHeightFromItemCount(int items_count) bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) { - // Always consume the SetNextWindowSizeConstraint() call in our early return paths ImGuiContext& g = *GImGui; - bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0; - g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; - ImGuiWindow* window = GetCurrentWindow(); + + ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags; + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values if (window->SkipItems) return false; - IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together - const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float expected_w = CalcItemWidth(); - const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w; - const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); - const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &bb)) return false; + // Open on click bool hovered, held; - bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); - bool popup_open = IsPopupOpen(id); + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id); + bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None); + if (pressed && !popup_open) + { + OpenPopupEx(popup_id, ImGuiPopupFlags_None); + popup_open = true; + } + // Render shape const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size); - RenderNavHighlight(frame_bb, id); + const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); + RenderNavHighlight(bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) - window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Left); + window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); if (!(flags & ImGuiComboFlags_NoArrowButton)) { ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); - window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); - if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x) - RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); + if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); } - RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); - if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) - RenderTextClipped(frame_bb.Min + style.FramePadding, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f,0.0f)); - if (label_size.x > 0) - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); - if ((pressed || g.NavActivateId == id) && !popup_open) + // Custom preview + if (flags & ImGuiComboFlags_CustomPreview) { - if (window->DC.NavLayerCurrent == 0) - window->NavLastIds[0] = id; - OpenPopupEx(id); - popup_open = true; + g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); + IM_ASSERT(preview_value == NULL || preview_value[0] == 0); + preview_value = NULL; } + // Render preview and label + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + { + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL); + } + if (label_size.x > 0) + RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label); + if (!popup_open) return false; - if (has_window_size_constraint) + g.NextWindowData.Flags = backup_next_window_data_flags; + return BeginComboPopup(popup_id, bb, flags); +} + +bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); + return false; + } + + // Set popup size + float w = bb.GetWidth(); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) { - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); } else { if ((flags & ImGuiComboFlags_HeightMask_) == 0) flags |= ImGuiComboFlags_HeightRegular; - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one int popup_max_height_in_items = -1; if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; - SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX); + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size + constraint_min.x = w; + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) + constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); + SetNextWindowSizeConstraints(constraint_min, constraint_max); } + // This is essentially a specialized version of BeginPopupEx() char name[16]; ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth - // Peak into expected window size so we can position it + // Set position given a custom constraint (peak into expected window size so we can position it) + // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? + // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()? if (ImGuiWindow* popup_window = FindWindowByName(name)) if (popup_window->WasActive) { - ImVec2 size_expected = CalcWindowExpectedSize(popup_window); - if (flags & ImGuiComboFlags_PopupAlignLeft) - popup_window->AutoPosLastDirection = ImGuiDir_Left; - ImRect r_outer = GetWindowAllowedExtentRect(popup_window); - ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox); + // Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us. + ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window); + popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)" + ImRect r_outer = GetPopupAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox); SetNextWindowPos(pos); } // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; - - // Horizontally align ourselves with the framed text - PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y)); + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text bool ret = Begin(name, NULL, window_flags); PopStyleVar(); if (!ret) @@ -1527,6 +1818,59 @@ void ImGui::EndCombo() EndPopup(); } +// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements +// (Experimental, see GitHub issues: #1658, #4168) +bool ImGui::BeginComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)) + return false; + IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? + if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional) + return false; + + // FIXME: This could be contained in a PushWorkRect() api + preview_data->BackupCursorPos = window->DC.CursorPos; + preview_data->BackupCursorMaxPos = window->DC.CursorMaxPos; + preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; + preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + preview_data->BackupLayout = window->DC.LayoutType; + window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.IsSameLine = false; + PushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max, true); + + return true; +} + +void ImGui::EndComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + // FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future + ImDrawList* draw_list = window->DrawList; + if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) + if (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command + { + draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; + draw_list->_TryMergeDrawCmds(); + } + PopClipRect(); + window->DC.CursorPos = preview_data->BackupCursorPos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); + window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine; + window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset; + window->DC.LayoutType = preview_data->BackupLayout; + window->DC.IsSameLine = false; + preview_data->PreviewRect = ImRect(); +} + // Getter for the old Combo() API: const char*[] static bool Items_ArrayGetter(void* data, int idx, const char** out_text) { @@ -1569,7 +1913,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) - SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) return false; @@ -1579,7 +1923,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi bool value_changed = false; for (int i = 0; i < items_count; i++) { - PushID((void*)(intptr_t)i); + PushID(i); const bool item_selected = (i == *current_item); const char* item_text; if (!items_getter(data, i, &item_text)) @@ -1595,6 +1939,10 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi } EndCombo(); + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + return value_changed; } @@ -1622,59 +1970,36 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa //------------------------------------------------------------------------- // [SECTION] Data Type and Data Formatting Helpers [Internal] //------------------------------------------------------------------------- -// - PatchFormatStringFloatToInt() // - DataTypeGetInfo() // - DataTypeFormatString() // - DataTypeApplyOp() // - DataTypeApplyOpFromText() +// - DataTypeCompare() +// - DataTypeClamp() // - GetMinimumStepAtDecimalPrecision // - RoundScalarWithFormat<>() //------------------------------------------------------------------------- static const ImGuiDataTypeInfo GDataTypeInfo[] = { - { sizeof(char), "%d", "%d" }, // ImGuiDataType_S8 - { sizeof(unsigned char), "%u", "%u" }, - { sizeof(short), "%d", "%d" }, // ImGuiDataType_S16 - { sizeof(unsigned short), "%u", "%u" }, - { sizeof(int), "%d", "%d" }, // ImGuiDataType_S32 - { sizeof(unsigned int), "%u", "%u" }, + { sizeof(char), "S8", "%d", "%d" }, // ImGuiDataType_S8 + { sizeof(unsigned char), "U8", "%u", "%u" }, + { sizeof(short), "S16", "%d", "%d" }, // ImGuiDataType_S16 + { sizeof(unsigned short), "U16", "%u", "%u" }, + { sizeof(int), "S32", "%d", "%d" }, // ImGuiDataType_S32 + { sizeof(unsigned int), "U32", "%u", "%u" }, #ifdef _MSC_VER - { sizeof(ImS64), "%I64d","%I64d" }, // ImGuiDataType_S64 - { sizeof(ImU64), "%I64u","%I64u" }, + { sizeof(ImS64), "S64", "%I64d","%I64d" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%I64u","%I64u" }, #else - { sizeof(ImS64), "%lld", "%lld" }, // ImGuiDataType_S64 - { sizeof(ImU64), "%llu", "%llu" }, + { sizeof(ImS64), "S64", "%lld", "%lld" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%llu", "%llu" }, #endif - { sizeof(float), "%f", "%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) - { sizeof(double), "%f", "%lf" }, // ImGuiDataType_Double + { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double }; IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); -// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". -// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. -// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! -static const char* PatchFormatStringFloatToInt(const char* fmt) -{ - if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. - return "%d"; - const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) - const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). - if (fmt_end > fmt_start && fmt_end[-1] == 'f') - { -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (fmt_start == fmt && fmt_end[0] == 0) - return "%d"; - ImGuiContext& g = *GImGui; - ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. - return g.TempBuffer; -#else - IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" -#endif - } - return fmt; -} - const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type) { IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); @@ -1704,7 +2029,7 @@ int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type return 0; } -void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2) +void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg1, const void* arg2) { IM_ASSERT(op == '+' || op == '-'); switch (data_type) @@ -1756,92 +2081,33 @@ void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* // User can input math operators (e.g. +100) to edit a numerical values. // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. -bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) +bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format) { while (ImCharIsBlankA(*buf)) buf++; - - // We don't support '-' op because it would conflict with inputing negative value. - // Instead you can use +-100 to subtract from an existing value - char op = buf[0]; - if (op == '+' || op == '*' || op == '/') - { - buf++; - while (ImCharIsBlankA(*buf)) - buf++; - } - else - { - op = 0; - } if (!buf[0]) return false; // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. - IM_ASSERT(data_type < ImGuiDataType_COUNT); - int data_backup[2]; - const ImGuiDataTypeInfo* type_info = ImGui::DataTypeGetInfo(data_type); - IM_ASSERT(type_info->Size <= sizeof(data_backup)); - memcpy(data_backup, p_data, type_info->Size); - - if (format == NULL) + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, type_info->Size); + + // Sanitize format + // - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf + // - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %. + char format_sanitized[32]; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) format = type_info->ScanFmt; - - // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. - int arg1i = 0; - if (data_type == ImGuiDataType_S32) - { - int* v = (int*)p_data; - int arg0i = *v; - float arg1f = 0.0f; - if (op && sscanf(initial_value_buf, format, &arg0i) < 1) - return false; - // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision - if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) - else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply - else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide - else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant - } - else if (data_type == ImGuiDataType_Float) - { - // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in - format = "%f"; - float* v = (float*)p_data; - float arg0f = *v, arg1f = 0.0f; - if (op && sscanf(initial_value_buf, format, &arg0f) < 1) - return false; - if (sscanf(buf, format, &arg1f) < 1) - return false; - if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) - else if (op == '*') { *v = arg0f * arg1f; } // Multiply - else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide - else { *v = arg1f; } // Assign constant - } - else if (data_type == ImGuiDataType_Double) - { - format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis - double* v = (double*)p_data; - double arg0f = *v, arg1f = 0.0; - if (op && sscanf(initial_value_buf, format, &arg0f) < 1) - return false; - if (sscanf(buf, format, &arg1f) < 1) - return false; - if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) - else if (op == '*') { *v = arg0f * arg1f; } // Multiply - else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide - else { *v = arg1f; } // Assign constant - } - else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) - { - // All other types assign constant - // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. - sscanf(buf, format, p_data); - } else + format = ImParseFormatSanitizeForScanning(format, format_sanitized, IM_ARRAYSIZE(format_sanitized)); + + // Small types need a 32-bit buffer to receive the result from scanf() + int v32 = 0; + if (sscanf(buf, format, type_info->Size >= 4 ? p_data : &v32) < 1) + return false; + if (type_info->Size < 4) { - // Small types need a 32-bit buffer to receive the result from scanf() - int v32; - sscanf(buf, format, &v32); if (data_type == ImGuiDataType_S8) *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); else if (data_type == ImGuiDataType_U8) @@ -1854,7 +2120,64 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b IM_ASSERT(0); } - return memcmp(data_backup, p_data, type_info->Size) != 0; + return memcmp(&data_backup, p_data, type_info->Size) != 0; +} + +template +static int DataTypeCompareT(const T* lhs, const T* rhs) +{ + if (*lhs < *rhs) return -1; + if (*lhs > *rhs) return +1; + return 0; +} + +int ImGui::DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeCompareT((const ImS8* )arg_1, (const ImS8* )arg_2); + case ImGuiDataType_U8: return DataTypeCompareT((const ImU8* )arg_1, (const ImU8* )arg_2); + case ImGuiDataType_S16: return DataTypeCompareT((const ImS16* )arg_1, (const ImS16* )arg_2); + case ImGuiDataType_U16: return DataTypeCompareT((const ImU16* )arg_1, (const ImU16* )arg_2); + case ImGuiDataType_S32: return DataTypeCompareT((const ImS32* )arg_1, (const ImS32* )arg_2); + case ImGuiDataType_U32: return DataTypeCompareT((const ImU32* )arg_1, (const ImU32* )arg_2); + case ImGuiDataType_S64: return DataTypeCompareT((const ImS64* )arg_1, (const ImS64* )arg_2); + case ImGuiDataType_U64: return DataTypeCompareT((const ImU64* )arg_1, (const ImU64* )arg_2); + case ImGuiDataType_Float: return DataTypeCompareT((const float* )arg_1, (const float* )arg_2); + case ImGuiDataType_Double: return DataTypeCompareT((const double*)arg_1, (const double*)arg_2); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return 0; +} + +template +static bool DataTypeClampT(T* v, const T* v_min, const T* v_max) +{ + // Clamp, both sides are optional, return true if modified + if (v_min && *v < *v_min) { *v = *v_min; return true; } + if (v_max && *v > *v_max) { *v = *v_max; return true; } + return false; +} + +bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeClampT((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max); + case ImGuiDataType_U8: return DataTypeClampT((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max); + case ImGuiDataType_S16: return DataTypeClampT((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max); + case ImGuiDataType_U16: return DataTypeClampT((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max); + case ImGuiDataType_S32: return DataTypeClampT((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max); + case ImGuiDataType_U32: return DataTypeClampT((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max); + case ImGuiDataType_S64: return DataTypeClampT((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max); + case ImGuiDataType_U64: return DataTypeClampT((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max); + case ImGuiDataType_Float: return DataTypeClampT((float* )p_data, (const float* )p_min, (const float* )p_max); + case ImGuiDataType_Double: return DataTypeClampT((double*)p_data, (const double*)p_min, (const double*)p_max); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; } static float GetMinimumStepAtDecimalPrecision(int decimal_precision) @@ -1866,33 +2189,27 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) } template -static const char* ImAtoi(const char* src, TYPE* output) -{ - int negative = 0; - if (*src == '-') { negative = 1; src++; } - if (*src == '+') { src++; } - TYPE v = 0; - while (*src >= '0' && *src <= '9') - v = (v * 10) + (*src++ - '0'); - *output = negative ? -v : v; - return src; -} - -template TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) { + IM_UNUSED(data_type); + IM_ASSERT(data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); const char* fmt_start = ImParseFormatFindStart(format); if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string return v; + + // Sanitize format + char fmt_sanitized[32]; + ImParseFormatSanitizeForPrinting(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized)); + fmt_start = fmt_sanitized; + + // Format value with our rounding, and read back char v_str[64]; ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); const char* p = v_str; while (*p == ' ') p++; - if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) - v = (TYPE)ImAtof(p); - else - ImAtoi(p, (SIGNEDTYPE*)&v); + v = (TYPE)ImAtof(p); + return v; } @@ -1917,16 +2234,13 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, // This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) template -bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiDragFlags flags) +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags) { ImGuiContext& g = *GImGui; - const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_clamped = (v_min < v_max); - const bool is_power = (power != 1.0f && is_decimal && is_clamped && (v_max - v_min < FLT_MAX)); - const bool is_locked = (v_min > v_max); - if (is_locked) - return false; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); // Default tweak speed if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) @@ -1934,7 +2248,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings float adjust_delta = 0.0f; - if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && g.IO.MouseDragMaxDistanceSqr[0] > 1.0f*1.0f) + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { adjust_delta = g.IO.MouseDelta[axis]; if (g.IO.KeyAlt) @@ -1942,10 +2256,13 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (g.IO.KeyShift) adjust_delta *= 10.0f; } - else if (g.ActiveIdSource == ImGuiInputSource_Nav) + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { - int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; - adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); + const float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f; + adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } adjust_delta *= v_speed; @@ -1954,12 +2271,15 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (axis == ImGuiAxis_Y) adjust_delta = -adjust_delta; + // For logarithmic use our range is effectively 0..1 so scale the delta into that range + if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) // Epsilon to avoid /0 + adjust_delta /= (float)(v_max - v_min); + // Clear current value on activation // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. bool is_just_activated = g.ActiveIdIsJustActivated; bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); - bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0)); - if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power) + if (is_just_activated || is_already_past_limits_and_pushing_outward) { g.DragCurrentAccum = 0.0f; g.DragCurrentAccumDirty = false; @@ -1976,13 +2296,19 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_cur = *v; FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; - if (is_power) + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + const float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense) + if (is_logarithmic) { - // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range - FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); - FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); - v_cur = v_min + (SIGNEDTYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); - v_old_ref_for_accum_remainder = v_old_norm_curved; + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + + // Convert to parametric space, apply delta, convert back + float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = v_old_parametric + g.DragCurrentAccum; + v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_old_ref_for_accum_remainder = v_old_parametric; } else { @@ -1990,14 +2316,16 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const } // Round to user desired precision based on format string - v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. g.DragCurrentAccumDirty = false; - if (is_power) + if (is_logarithmic) { - FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); - g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); + // Convert to parametric space, apply delta, convert back + float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); } else { @@ -2011,9 +2339,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // Clamp values (+ handle overflow/wrap-around for integer types) if (*v != v_cur && is_clamped) { - if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal)) + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) v_cur = v_min; - if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_decimal)) + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) v_cur = v_max; } @@ -2024,31 +2352,37 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const return true; } -bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags) +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + ImGuiContext& g = *GImGui; if (g.ActiveId == id) { + // Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation. if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) ClearActiveID(); - else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) ClearActiveID(); } if (g.ActiveId != id) return false; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } - case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, power, flags); - case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, power, flags); - case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, power, flags); - case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, power, flags); - case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, power, flags); - case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, power, flags); + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags); case ImGuiDataType_COUNT: break; } IM_ASSERT(0); @@ -2056,82 +2390,96 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v } // Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. -// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - if (power != 1.0f) - IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds - ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w = CalcItemWidth(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) return false; // Default format string when passing NULL if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) - format = PatchFormatStringFloatToInt(format); - // Tabbing or CTRL-clicking on Drag turns it into an input box const bool hovered = ItemHoverable(frame_bb, id); - bool temp_input_is_active = TempInputTextIsActive(id); - bool temp_input_start = false; + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - const bool focus_requested = FocusableItemRegister(window, id); - const bool clicked = (hovered && g.IO.MouseClicked[0]); - const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); - if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) + // Tabbing or CTRL-clicking on Drag turns it into an InputText + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = hovered && IsMouseClicked(0, id); + const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id)); + const bool make_active = (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id); + if (make_active && (clicked || double_clicked)) + SetKeyOwner(ImGuiKey_MouseLeft, id); + if (make_active && temp_input_allowed) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + temp_input_is_active = true; + + // (Optional) simple click (without moving) turns Drag into an InputText + if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) + if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + { + g.NavActivateId = id; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + temp_input_is_active = true; + } + + if (make_active && !temp_input_is_active) { SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); - if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id) - { - temp_input_start = true; - FocusableItemUnregister(window); - } } } - if (temp_input_is_active || temp_input_start) - return TempInputTextScalar(frame_bb, id, label, data_type, p_data, format); + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Drag behavior - const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, power, ImGuiDragFlags_None); + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags); if (value_changed) MarkItemEdited(id); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); return value_changed; } -bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2148,7 +2496,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data PushID(i); if (i > 0) SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, power); + value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags); PopID(); PopItemWidth(); p_data = (void*)((char*)p_data + type_size); @@ -2166,27 +2514,28 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data return value_changed; } -bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) +bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) +bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2197,41 +2546,50 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu BeginGroup(); PushMultiItemsWidths(2, CalcItemWidth()); - bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); + float min_min = (v_min >= v_max) ? -FLT_MAX : v_min; + float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power); + + float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + float max_max = (v_min >= v_max) ? FLT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); TextEx(label, FindRenderedTextEnd(label)); EndGroup(); PopID(); + return value_changed; } // NB: v_speed is float to allow adjusting the drag speed with more precision -bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format) +bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format); + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format) +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format) +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max) +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2242,10 +2600,17 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ BeginGroup(); PushMultiItemsWidths(2, CalcItemWidth()); - bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); + int min_min = (v_min >= v_max) ? INT_MIN : v_min; + int min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragInt("##min", v_current_min, v_speed, min_min, min_max, format, min_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format); + + int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + int max_max = (v_min >= v_max) ? INT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); @@ -2259,6 +2624,8 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ //------------------------------------------------------------------------- // [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. //------------------------------------------------------------------------- +// - ScaleRatioFromValueT<> [Internal] +// - ScaleValueFromRatioT<> [Internal] // - SliderBehaviorT<>() [Internal] // - SliderBehavior() [Internal] // - SliderScalar() @@ -2277,67 +2644,161 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ // - VSliderInt() //------------------------------------------------------------------------- -template -float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos) +// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) +template +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) return 0.0f; + IM_UNUSED(data_type); - const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); - if (is_power) + if (is_logarithmic) + { + bool flipped = v_max < v_min; + + if (flipped) // Handle the case where the range is backwards + ImSwap(v_min, v_max); + + // Fudge min/max to avoid getting close to log(0) + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_min == 0.0f) && (v_max < 0.0f)) + v_min_fudged = -logarithmic_zero_epsilon; + else if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float result; + if (v_clamped <= v_min_fudged) + result = 0.0f; // Workaround for values that are in-range but below our fudge + else if (v_clamped >= v_max_fudged) + result = 1.0f; // Workaround for values that are in-range but above our fudge + else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions + { + float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (v == 0.0f) + result = zero_point_center; // Special case for exactly zero + else if (v < 0.0f) + result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L; + else + result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R)); + } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)); + else + result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged)); + + return flipped ? (1.0f - result) : result; + } + else { - if (v_clamped < 0.0f) + // Linear slider + return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); + } +} + +// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) +template +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +{ + // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" + // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. + if (t <= 0.0f || v_min == v_max) + return v_min; + if (t >= 1.0f) + return v_max; + + TYPE result = (TYPE)0; + if (is_logarithmic) + { + // Fudge min/max to avoid getting silly results close to zero + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + const bool flipped = v_max < v_min; // Check if range is "backwards" + if (flipped) + ImSwap(v_min_fudged, v_max_fudged); + + // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range + + if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts { - const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min)); - return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos; + float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R) + result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise) + else if (t_with_flip < zero_point_center) + result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); + else + result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); else + result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); + } + else + { + // Linear slider + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + if (is_floating_point) + { + result = ImLerp(v_min, v_max, t); + } + else if (t < 1.0) { - const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min))); - return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos); + // - For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 + // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. + FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; + result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); } } - // Linear slider - return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); + return result; } -// FIXME: Move some of the code into SliderBehavior(). Current responsability is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc. +// FIXME: Try to move more of the code into shared SliderBehavior() template -bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) { ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); - const bool is_power = (power != 1.0f) && is_decimal; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); - const float grab_padding = 2.0f; + // Calculate bounds + const float grab_padding = 2.0f; // FIXME: Should be part of style. const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; float grab_sz = style.GrabMinSize; - SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); - if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows - grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMin(grab_sz, slider_sz); const float slider_usable_sz = slider_sz - grab_sz; const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; - // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f - float linear_zero_pos; // 0.0->1.0f - if (is_power && v_min * v_max < 0.0f) - { - // Different sign - const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f / power); - const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f / power); - linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); - } - else + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true + if (is_logarithmic) { - // Same sign - linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f); } // Process interacting with the slider @@ -2355,95 +2816,99 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { const float mouse_abs_pos = g.IO.MousePos[axis]; - clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; + if (g.ActiveIdIsJustActivated) + { + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. + g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f; + } + if (slider_usable_sz > 0.0f) + clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz); if (axis == ImGuiAxis_Y) clicked_t = 1.0f - clicked_t; set_new_value = true; } } - else if (g.ActiveIdSource == ImGuiInputSource_Nav) + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { - const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); - float delta = (axis == ImGuiAxis_X) ? delta2.x : -delta2.y; - if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + if (g.ActiveIdIsJustActivated) { - ClearActiveID(); + g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation + g.SliderCurrentAccumDirty = false; } - else if (delta != 0.0f) + + float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis); + if (input_delta != 0.0f) { - clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); - const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; - if ((decimal_precision > 0) || is_power) + const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + if (decimal_precision > 0) { - delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds - if (IsNavInputDown(ImGuiNavInput_TweakSlow)) - delta /= 10.0f; + input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (tweak_slow) + input_delta /= 10.0f; } else { - if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow)) - delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + if ((v_range >= -100.0f && v_range <= 100.0f) || tweak_slow) + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps else - delta /= 100.0f; + input_delta /= 100.0f; } - if (IsNavInputDown(ImGuiNavInput_TweakFast)) - delta *= 10.0f; - set_new_value = true; - if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits - set_new_value = false; - else - clicked_t = ImSaturate(clicked_t + delta); + if (tweak_fast) + input_delta *= 10.0f; + + g.SliderCurrentAccum += input_delta; + g.SliderCurrentAccumDirty = true; } - } - if (set_new_value) - { - TYPE v_new; - if (is_power) + float delta = g.SliderCurrentAccum; + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) { - // Account for power curve scale on both sides of the zero - if (clicked_t < linear_zero_pos) - { - // Negative: rescale to the negative range before powering - float a = 1.0f - (clicked_t / linear_zero_pos); - a = ImPow(a, power); - v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a); - } - else - { - // Positive: rescale to the positive range before powering - float a; - if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f) - a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); - else - a = clicked_t; - a = ImPow(a, power); - v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a); - } + ClearActiveID(); } - else + else if (g.SliderCurrentAccumDirty) { - // Linear slider - if (is_decimal) + clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits { - v_new = ImLerp(v_min, v_max, clicked_t); + set_new_value = false; + g.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate } else { - // For integer values we want the clicking position to match the grab box so we round above - // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. - FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t; - TYPE v_new_off_floor = (TYPE)(v_new_off_f); - TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5); - if (v_new_off_floor < v_new_off_round) - v_new = v_min + v_new_off_round; + set_new_value = true; + float old_clicked_t = clicked_t; + clicked_t = ImSaturate(clicked_t + delta); + + // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if (delta > 0) + g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); else - v_new = v_min + v_new_off_floor; + g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta); } + + g.SliderCurrentAccumDirty = false; } + } + + if (set_new_value) + { + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); // Round to user desired precision based on format string - v_new = RoundScalarWithFormatT(format, data_type, v_new); + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); // Apply result if (*v != v_new) @@ -2461,7 +2926,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { // Output grab position so it can be displayed by the caller - float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -2477,32 +2942,40 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ // For 32-bit and larger types, slider bounds are limited to half the natural type range. // So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. // It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. -bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) { + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + + // Those are the things we can do easily outside the SliderBehaviorT<> template, saves code generation. + ImGuiContext& g = *GImGui; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; + switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } case ImGuiDataType_S32: - IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN/2 && *(const ImS32*)p_max <= IM_S32_MAX/2); - return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb); case ImGuiDataType_U32: - IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX/2); - return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb); case ImGuiDataType_S64: - IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN/2 && *(const ImS64*)p_max <= IM_S64_MAX/2); - return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb); case ImGuiDataType_U64: - IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX/2); - return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb); case ImGuiDataType_Float: - IM_ASSERT(*(const float*)p_min >= -FLT_MAX/2.0f && *(const float*)p_max <= FLT_MAX/2.0f); - return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb); case ImGuiDataType_Double: - IM_ASSERT(*(const double*)p_min >= -DBL_MAX/2.0f && *(const double*)p_max <= DBL_MAX/2.0f); - return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, power, flags, out_grab_bb); + IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb); case ImGuiDataType_COUNT: break; } IM_ASSERT(0); @@ -2511,7 +2984,7 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type // Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. // Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2523,51 +2996,56 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) return false; // Default format string when passing NULL if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) - format = PatchFormatStringFloatToInt(format); - // Tabbing or CTRL-clicking on Slider turns it into an input box const bool hovered = ItemHoverable(frame_bb, id); - bool temp_input_is_active = TempInputTextIsActive(id); - bool temp_input_start = false; + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - const bool focus_requested = FocusableItemRegister(window, id); - const bool clicked = (hovered && g.IO.MouseClicked[0]); - if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) + // Tabbing or CTRL-clicking on Slider turns it into an input box + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = hovered && IsMouseClicked(0, id); + const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id); + if (make_active && clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); + if (make_active && temp_input_allowed) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + temp_input_is_active = true; + + if (make_active && !temp_input_is_active) { SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); - if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id) - { - temp_input_start = true; - FocusableItemUnregister(window); - } } } - if (temp_input_is_active || temp_input_start) - return TempInputTextScalar(frame_bb, id, label, data_type, p_data, format); + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0; + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior ImRect grab_bb; - const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_None, &grab_bb); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb); if (value_changed) MarkItemEdited(id); @@ -2578,17 +3056,19 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); return value_changed; } // Add multiple sliders on 1 line for compact edition of multiple components -bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2605,7 +3085,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i PushID(i); if (i > 0) SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); PopID(); PopItemWidth(); v = (void*)((char*)v + type_size); @@ -2623,57 +3103,57 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i return value_changed; } -bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) +bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) +bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) +bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags); } -bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format) +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags) { if (format == NULL) format = "%.0f deg"; - float v_deg = (*v_rad) * 360.0f / (2*IM_PI); - bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, 1.0f); - *v_rad = v_deg * (2*IM_PI) / 360.0f; + float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags); + *v_rad = v_deg * (2 * IM_PI) / 360.0f; return value_changed; } -bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format) +bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format); + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format) +bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format) +bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format) +bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags); } -bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2694,12 +3174,13 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d // Default format string when passing NULL if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) - format = PatchFormatStringFloatToInt(format); const bool hovered = ItemHoverable(frame_bb, id); - if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) + const bool clicked = hovered && IsMouseClicked(0, id); + if (clicked || g.NavActivateId == id) { + if (clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); @@ -2707,13 +3188,13 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior ImRect grab_bb; - const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb); if (value_changed) MarkItemEdited(id); @@ -2725,21 +3206,21 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); return value_changed; } -bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { - return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power); + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); } -bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format) +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) { - return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format); + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); } //------------------------------------------------------------------------- @@ -2748,6 +3229,8 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, // - ImParseFormatFindStart() [Internal] // - ImParseFormatFindEnd() [Internal] // - ImParseFormatTrimDecorations() [Internal] +// - ImParseFormatSanitizeForPrinting() [Internal] +// - ImParseFormatSanitizeForScanning() [Internal] // - ImParseFormatPrecision() [Internal] // - TempInputTextScalar() [Internal] // - InputScalar() @@ -2795,7 +3278,7 @@ const char* ImParseFormatFindEnd(const char* fmt) } // Extract the format out of a format string with leading or trailing decorations -// fmt = "blah blah" -> return fmt +// fmt = "blah blah" -> return "" // fmt = "%.3f" -> return fmt // fmt = "hello %.3f" -> return fmt + 6 // fmt = "%.3f hello" -> return buf written with "%.3f" @@ -2803,7 +3286,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_ { const char* fmt_start = ImParseFormatFindStart(fmt); if (fmt_start[0] != '%') - return fmt; + return ""; const char* fmt_end = ImParseFormatFindEnd(fmt_start); if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. return fmt_start; @@ -2811,61 +3294,149 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_ return buf; } -// Parse display precision back from the display format string -// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. -int ImParseFormatPrecision(const char* fmt, int default_precision) +// Sanitize format +// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi +// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi. +void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size) { - fmt = ImParseFormatFindStart(fmt); - if (fmt[0] != '%') - return default_precision; - fmt++; - while (*fmt >= '0' && *fmt <= '9') - fmt++; - int precision = INT_MAX; - if (*fmt == '.') + const char* fmt_end = ImParseFormatFindEnd(fmt_in); + IM_UNUSED(fmt_out_size); + IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + while (fmt_in < fmt_end) { - fmt = ImAtoi(fmt + 1, &precision); - if (precision < 0 || precision > 99) - precision = default_precision; + char c = *fmt_in++; + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; } - if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation - precision = -1; - if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) - precision = -1; - return (precision == INT_MAX) ? default_precision : precision; + *fmt_out = 0; // Zero-terminate } -// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) -// FIXME: Facilitate using this in variety of other situations. -bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format) +// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" +const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size) { - ImGuiContext& g = *GImGui; + const char* fmt_end = ImParseFormatFindEnd(fmt_in); + const char* fmt_out_begin = fmt_out; + IM_UNUSED(fmt_out_size); + IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + bool has_type = false; + while (fmt_in < fmt_end) + { + char c = *fmt_in++; + if (!has_type && ((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '#')) + continue; + has_type |= ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); // Stop skipping digits + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; + } + *fmt_out = 0; // Zero-terminate + return fmt_out_begin; +} + +template +static const char* ImAtoi(const char* src, TYPE* output) +{ + int negative = 0; + if (*src == '-') { negative = 1; src++; } + if (*src == '+') { src++; } + TYPE v = 0; + while (*src >= '0' && *src <= '9') + v = (v * 10) + (*src++ - '0'); + *output = negative ? -v : v; + return src; +} + +// Parse display precision back from the display format string +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. +int ImParseFormatPrecision(const char* fmt, int default_precision) +{ + fmt = ImParseFormatFindStart(fmt); + if (fmt[0] != '%') + return default_precision; + fmt++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + int precision = INT_MAX; + if (*fmt == '.') + { + fmt = ImAtoi(fmt + 1, &precision); + if (precision < 0 || precision > 99) + precision = default_precision; + } + if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} +// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) +// FIXME: Facilitate using this in variety of other situations. +bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +{ // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. // We clear ActiveID on the first frame to allow the InputText() taking it back. - const bool init = (g.TempInputTextId != id); + ImGuiContext& g = *GImGui; + const bool init = (g.TempInputId != id); if (init) ClearActiveID(); + g.CurrentWindow->DC.CursorPos = bb.Min; + bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); + if (init) + { + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); + g.TempInputId = g.ActiveId; + } + return value_changed; +} + +static inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(ImGuiDataType data_type, const char* format) +{ + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + return ImGuiInputTextFlags_CharsScientific; + const char format_last_char = format[0] ? format[strlen(format) - 1] : 0; + return (format_last_char == 'x' || format_last_char == 'X') ? ImGuiInputTextFlags_CharsHexadecimal : ImGuiInputTextFlags_CharsDecimal; +} + +// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the ImGuiSliderFlags_AlwaysClamp flag is set! +// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility. +// However this may not be ideal for all uses, as some user code may break on out of bound values. +bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) +{ + // FIXME: May need to clarify display behavior if format doesn't contain %. + // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); char fmt_buf[32]; char data_buf[32]; format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + if (format[0] == 0) + format = type_info->PrintFmt; DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); ImStrTrimBlanks(data_buf); - g.CurrentWindow->DC.CursorPos = bb.Min; ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; - flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); - bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); - if (init) - { - // First frame we started displaying the InputText widget, we expect it to take the active id. - IM_ASSERT(g.ActiveId == id); - g.TempInputTextId = g.ActiveId; - } - if (value_changed) + flags |= InputScalar_DefaultCharsFilter(data_type, format); + + bool value_changed = false; + if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) { - value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); + // Backup old value + size_t data_type_size = type_info->Size; + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyFromText(data_buf, data_type, p_data, format); + if (p_clamp_min || p_clamp_max) + { + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + ImSwap(p_clamp_min, p_clamp_max); + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); + } + + // Only mark as edited if new value is different + value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; if (value_changed) MarkItemEdited(id); } @@ -2889,13 +3460,18 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data char buf[64]; DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); - bool value_changed = false; - if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) - flags |= ImGuiInputTextFlags_CharsDecimal; - flags |= ImGuiInputTextFlags_AutoSelectAll; - flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselve by comparing the actual data rather than the string. + // Testing ActiveId as a minor optimization as filtering is not needed until active + if (g.ActiveId == 0 && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= InputScalar_DefaultCharsFilter(data_type, format); + flags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. - if (p_step != NULL) + bool value_changed = false; + if (p_step == NULL) + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + } + else { const float button_size = GetFrameHeight(); @@ -2903,14 +3479,15 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PushID(label); SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; style.FramePadding.x = style.FramePadding.y; ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; if (flags & ImGuiInputTextFlags_ReadOnly) - button_flags |= ImGuiButtonFlags_Disabled; + BeginDisabled(); SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) { @@ -2923,6 +3500,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); value_changed = true; } + if (flags & ImGuiInputTextFlags_ReadOnly) + EndDisabled(); const char* label_end = FindRenderedTextEnd(label); if (label != label_end) @@ -2935,13 +3514,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PopID(); EndGroup(); } - else - { - if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); - } if (value_changed) - MarkItemEdited(window->DC.LastItemId); + MarkItemEdited(g.LastItemData.ID); return value_changed; } @@ -2984,7 +3558,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_dat bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) { flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, flags); + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags); } bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) @@ -3002,46 +3576,11 @@ bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGui return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); } -// Prefer using "const char* format" directly, which is more flexible and consistent with other API. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags) -{ - char format[16] = "%f"; - if (decimal_precision >= 0) - ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputFloat(label, v, step, step_fast, format, flags); -} - -bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags) -{ - char format[16] = "%f"; - if (decimal_precision >= 0) - ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); -} - -bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags) -{ - char format[16] = "%f"; - if (decimal_precision >= 0) - ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); -} - -bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags) -{ - char format[16] = "%f"; - if (decimal_precision >= 0) - ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); -} -#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS - bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) { // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; - return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, flags); + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags); } bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) @@ -3062,7 +3601,7 @@ bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) { flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, flags); + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags); } //------------------------------------------------------------------------- @@ -3071,13 +3610,17 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f // - InputText() // - InputTextWithHint() // - InputTextMultiline() +// - InputTextGetCharInfo() [Internal] +// - InputTextReindexLines() [Internal] +// - InputTextReindexLinesRange() [Internal] // - InputTextEx() [Internal] +// - DebugNodeInputTextState() [Internal] //------------------------------------------------------------------------- bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() - return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) @@ -3087,7 +3630,7 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { - IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or InputTextEx() manually if you need multi-line + hint. return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } @@ -3105,14 +3648,14 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** return line_count; } -static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) { - ImGuiContext& g = *GImGui; + ImGuiContext& g = *ctx; ImFont* font = g.Font; const float line_height = g.FontSize; const float scale = line_height / font->FontSize; - ImVec2 text_size = ImVec2(0,0); + ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; const ImWchar* s = text_begin; @@ -3154,16 +3697,16 @@ static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* t namespace ImStb { -static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } -static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; } -static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; -static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { const ImWchar* text = obj->TextW.Data; const ImWchar* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -3172,23 +3715,47 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } -static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->TextW[idx-1] ) && !is_separator( obj->TextW[idx] ) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } -#ifdef __APPLE__ // FIXME: Move setting to IO structure -static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->TextW[idx-1] ) && is_separator( obj->TextW[idx] ) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } -#else -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } -#endif -#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +static bool is_separator(unsigned int c) +{ + return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!'; +} + +static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) +{ + // When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. + if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) + return 0; + + bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool prev_separ = is_separator(obj->TextW[idx - 1]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx]); + bool curr_separ = is_separator(obj->TextW[idx]); + return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); +} +static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) +{ + if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) + return 0; + + bool prev_white = ImCharIsBlankW(obj->TextW[idx]); + bool prev_separ = is_separator(obj->TextW[idx]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool curr_separ = is_separator(obj->TextW[idx - 1]); + return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); +} +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL -static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) { ImWchar* dst = obj->TextW.Data + pos; // We maintain our buffer length in both UTF-8 and wchar formats + obj->Edited = true; obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); obj->CurLenW -= n; @@ -3199,9 +3766,9 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) *dst = '\0'; } -static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len) { - const bool is_resizable = (obj->UserFlags & ImGuiInputTextFlags_CallbackResize) != 0; + const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int text_len = obj->CurLenW; IM_ASSERT(pos <= text_len); @@ -3223,6 +3790,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); + obj->Edited = true; obj->CurLenW += new_text_len; obj->CurLenA += new_text_len_utf8; obj->TextW[obj->CurLenW] = '\0'; @@ -3245,13 +3813,33 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im #define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo #define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word #define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page +#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page #define STB_TEXTEDIT_K_SHIFT 0x400000 #define STB_TEXTEDIT_IMPLEMENTATION #include "imstb_textedit.h" +// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling +// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) +static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) +{ + stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); + state->cursor = state->select_start = state->select_end = 0; + if (text_len <= 0) + return; + if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len)) + { + state->cursor = state->select_start = state->select_end = text_len; + state->has_preferred_x = 0; + return; + } + IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() } +} // namespace ImStb + void ImGuiInputTextState::OnKeyPressed(int key) { stb_textedit_key(this, &Stb, key); @@ -3276,7 +3864,7 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) *dst++ = c; *dst = '\0'; - if (CursorPos + bytes_count >= pos) + if (CursorPos >= pos + bytes_count) CursorPos -= bytes_count; else if (CursorPos >= pos) CursorPos = pos; @@ -3294,8 +3882,8 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (!is_resizable) return; - // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the midly similar code (until we remove the U16 buffer alltogether!) - ImGuiContext& g = *GImGui; + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) + ImGuiContext& g = *Ctx; ImGuiInputTextState* edit_state = &g.InputTextState; IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(Buf == edit_state->TextA.Data); @@ -3318,61 +3906,90 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons } // Return false to discard a character. -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) { + IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); unsigned int c = *p_char; // Filter non-printable (NB: isprint is unreliable! see #2467) + bool apply_named_filters = true; if (c < 0x20) { bool pass = false; - pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); if (!pass) return false; + apply_named_filters = false; // Override named filters below so newline and tabs can still be inserted. } - // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) - if (c == 127) - return false; + if (input_source != ImGuiInputSource_Clipboard) + { + // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) + if (c == 127) + return false; - // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) - if (c >= 0xE000 && c <= 0xF8FF) - return false; + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) + return false; + } - // Filter Unicode ranges we are not handling in this build. + // Filter Unicode ranges we are not handling in this build if (c > IM_UNICODE_CODEPOINT_MAX) return false; // Generic named filters - if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) - { + if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific))) + { + // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'. + // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. + // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. + // Change the default decimal_point with: + // ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; + // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. + ImGuiContext& g = *GImGui; + const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + + // Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) + // While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may + // scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font. + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal)) + if (c >= 0xFF01 && c <= 0xFF5E) + c = c - 0xFF01 + 0x21; + + // Allow 0-9 . - + * / if (flags & ImGuiInputTextFlags_CharsDecimal) - if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) return false; + // Allow 0-9 . - + * / e E if (flags & ImGuiInputTextFlags_CharsScientific) - if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) return false; + // Allow 0-9 a-F A-F if (flags & ImGuiInputTextFlags_CharsHexadecimal) if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) return false; + // Turn a-z into A-Z if (flags & ImGuiInputTextFlags_CharsUppercase) if (c >= 'a' && c <= 'z') - *p_char = (c += (unsigned int)('A'-'a')); + c += (unsigned int)('A' - 'a'); if (flags & ImGuiInputTextFlags_CharsNoBlank) if (ImCharIsBlankW(c)) return false; + + *p_char = c; } // Custom callback filter if (flags & ImGuiInputTextFlags_CallbackCharFilter) { + ImGuiContext& g = *GImGui; ImGuiInputTextCallbackData callback_data; - memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.Ctx = &g; callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; callback_data.EventChar = (ImWchar)c; callback_data.Flags = flags; @@ -3387,6 +4004,56 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f return true; } +// Find the shortest single replacement we can make to get the new text from the old text. +// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end. +// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. +static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a) +{ + ImGuiContext& g = *GImGui; + const ImWchar* old_buf = state->TextW.Data; + const int old_length = state->CurLenW; + const int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a); + g.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar)); + ImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data; + ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a); + + const int shorter_length = ImMin(old_length, new_length); + int first_diff; + for (first_diff = 0; first_diff < shorter_length; first_diff++) + if (old_buf[first_diff] != new_buf[first_diff]) + break; + if (first_diff == old_length && first_diff == new_length) + return; + + int old_last_diff = old_length - 1; + int new_last_diff = new_length - 1; + for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--) + if (old_buf[old_last_diff] != new_buf[new_last_diff]) + break; + + const int insert_len = new_last_diff - first_diff + 1; + const int delete_len = old_last_diff - first_diff + 1; + if (insert_len > 0 || delete_len > 0) + if (STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len)) + for (int i = 0; i < delete_len; i++) + p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i); +} + +// As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables) +// we need some form of hook to reapply data back to user buffer on deactivation frame. (#4714) +// It would be more desirable that we discourage users from taking advantage of the "user not retaining data" trick, +// but that more likely be attractive when we do have _NoLiveEdit flag available. +void ImGui::InputTextDeactivateHook(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiInputTextState* state = &g.InputTextState; + if (id == 0 || state->ID != id) + return; + g.InputTextDeactivatedState.ID = state->ID; + g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1); + memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data ? state->TextA.Data : "", state->CurLenA + 1); +} + // Edit a string of text // - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". // This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match @@ -3401,6 +4068,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (window->SkipItems) return false; + IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) @@ -3417,11 +4085,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! - if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); @@ -3429,76 +4097,101 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImGuiWindow* draw_window = window; ImVec2 inner_size = frame_size; + ImGuiItemStatusFlags item_status_flags = 0; + ImGuiLastItemData item_data_backup; if (is_multiline) { - if (!ItemAdd(total_bb, id, &frame_bb)) + ImVec2 backup_pos = window->DC.CursorPos; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) { - ItemSize(total_bb, style.FramePadding.y); EndGroup(); return false; } - if (!BeginChildFrame(id, frame_bb.GetSize())) + item_status_flags = g.LastItemData.StatusFlags; + item_data_backup = g.LastItemData; + window->DC.CursorPos = backup_pos; + + // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. + // FIXME-NAV: Pressing NavActivate will trigger general child activation right before triggering our own below. Harmless but bizarre. + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(3); + PopStyleColor(); + if (!child_visible) { - EndChildFrame(); + EndChild(); EndGroup(); return false; } draw_window = g.CurrentWindow; // Child window - draw_window->DC.NavLayerActiveMaskNext |= draw_window->DC.NavLayerCurrentMask; // This is to ensure that EndChild() will display a navigation highlight + draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.CursorPos += style.FramePadding; inner_size.x -= draw_window->ScrollbarSizes.x; } else { + // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) - return false; + if (!(flags & ImGuiInputTextFlags_MergedItem)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) + return false; + item_status_flags = g.LastItemData.StatusFlags; } const bool hovered = ItemHoverable(frame_bb, id); if (hovered) g.MouseCursor = ImGuiMouseCursor_TextInput; - // NB: we are only allowed to access 'edit_state' if we are the active widget. - ImGuiInputTextState* state = NULL; - if (g.InputTextState.ID == id) - state = &g.InputTextState; + // We are only allowed to access the state if we are already the active widget. + ImGuiInputTextState* state = GetInputTextState(id); - const bool focus_requested = FocusableItemRegister(window, id); - const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterAll == window->DC.FocusCounterAll); - const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; + const bool input_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); const bool user_clicked = hovered && io.MouseClicked[0]; - const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); - bool clear_active_id = false; - bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); + bool select_all = false; + + float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; - const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start); + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state. + const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing); const bool init_state = (init_make_active || user_scroll_active); - if (init_state && g.ActiveId != id) + if ((init_state && g.ActiveId != id) || init_changed_specs) { // Access state even if we don't own it yet. state = &g.InputTextState; state->CursorAnimReset(); + // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) + InputTextDeactivateHook(state->ID); + // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)strlen(buf); state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. memcpy(state->InitialTextA.Data, buf, buf_len + 1); + // Preserve cursor position and undo/redo stack if we come back to same widget + // FIXME: Since we reworked this on 2022/06, may want to differenciate recycle_cursor vs recycle_undostate? + bool recycle_state = (state->ID == id && !init_changed_specs); + if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0))) + recycle_state = false; + // Start edition const char* buf_end = NULL; + state->ID = id; state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextA.resize(0); state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. - // Preserve cursor position and undo/redo stack if we come back to same widget - // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed. - const bool recycle_state = (state->ID == id); if (recycle_state) { // Recycle existing cursor/selection/undo stack but clamp position @@ -3507,36 +4200,51 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - state->ID = id; state->ScrollX = 0.0f; stb_textedit_initialize_state(&state->Stb, !is_multiline); - if (!is_multiline && focus_requested_by_code) + } + + if (!is_multiline) + { + if (flags & ImGuiInputTextFlags_AutoSelectAll) + select_all = true; + if (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) + select_all = true; + if (input_requested_by_tabbing || (user_clicked && io.KeyCtrl)) select_all = true; } - if (flags & ImGuiInputTextFlags_AlwaysInsertMode) - state->Stb.insert_mode = 1; - if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) - select_all = true; + + if (flags & ImGuiInputTextFlags_AlwaysOverwrite) + state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) } + const bool is_osx = io.ConfigMacOSXBehaviors; if (g.ActiveId != id && init_make_active) { IM_ASSERT(state && state->ID == id); SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); - - // Declare our inputs - IM_ASSERT(ImGuiNavInput_COUNT < 32); + } + if (g.ActiveId == id) + { + // Declare some inputs, the other are registered and polled via Shortcut() routing system. + if (user_clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End); + SetKeyOwner(ImGuiKey_Home, id); + SetKeyOwner(ImGuiKey_End, id); if (is_multiline) - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); // FIXME-NAV: Page up/down actually not supported yet by widget, but claim them ahead. - if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); + { + SetKeyOwner(ImGuiKey_PageUp, id); + SetKeyOwner(ImGuiKey_PageDown, id); + } + if (is_osx) + SetKeyOwner(ImGuiMod_Alt, id); + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. + SetShortcutRouting(ImGuiKey_Tab, id); } // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) @@ -3548,10 +4256,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ clear_active_id = true; // Lock the decision of whether we are going to take the path displaying the cursor or selection - const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); - bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); bool value_changed = false; - bool enter_pressed = false; + bool validated = false; // When read-only we always use the live data passed to the function // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( @@ -3576,7 +4284,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImFont* password_font = &g.InputTextPasswordFont; password_font->FontSize = g.Font->FontSize; password_font->Scale = g.Font->Scale; - password_font->DisplayOffset = g.Font->DisplayOffset; password_font->Ascent = g.Font->Ascent; password_font->Descent = g.Font->Descent; password_font->ContainerAtlas = g.Font->ContainerAtlas; @@ -3592,37 +4299,66 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { IM_ASSERT(state != NULL); backup_current_text_length = state->CurLenA; + state->Edited = false; state->BufCapacityA = buf_size; - state->UserFlags = flags; - state->UserCallback = callback; - state->UserCallbackData = callback_user_data; + state->Flags = flags; // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. // Down the line we should have a cleaner library-wide concept of Selected vs Active. g.ActiveIdAllowOverlap = !io.MouseDown[0]; - g.WantTextInputNextFrame = 1; // Edit in progress const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; - const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); - const bool is_osx = io.ConfigMacOSXBehaviors; - if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) + if (select_all) { state->SelectAll(); state->SelectedAllMouseLock = true; } - else if (hovered && is_osx && io.MouseDoubleClicked[0]) + else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift) { - // Double-click select a word only, OS X style (by simulating keystrokes) - state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); - state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + const int multiclick_count = (io.MouseClickedCount[0] - 2); + if ((multiclick_count % 2) == 0) + { + // Double-click: Select word + // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: + // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) + const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\n'; + if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + if (!STB_TEXT_HAS_SELECTION(&state->Stb)) + ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb); + state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor); + state->Stb.select_end = state->Stb.cursor; + ImStb::stb_textedit_clamp(state, &state->Stb); + } + else + { + // Triple-click: Select line + const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\n'; + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART); + state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT); + state->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT); + if (!is_eol && is_multiline) + { + ImSwap(state->Stb.select_start, state->Stb.select_end); + state->Stb.cursor = state->Stb.select_end; + } + state->CursorFollow = false; + } + state->CursorAnimReset(); } else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) { if (hovered) { - stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + if (io.KeyShift) + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + else + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); } } @@ -3635,29 +4371,28 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (state->SelectedAllMouseLock && !io.MouseDown[0]) state->SelectedAllMouseLock = false; - // It is ill-defined whether the back-end needs to send a \t character when pressing the TAB keys. - // Win32 and GLFW naturally do it but not SDL. - const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); - if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) - if (!io.InputQueueCharacters.contains('\t')) - { - unsigned int c = '\t'; // Insert TAB - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) - state->OnKeyPressed((int)c); - } + // We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336) + // (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes) + if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } // Process regular text input (before we check for Return because using some IME will effectively send a Return?) // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); if (io.InputQueueCharacters.Size > 0) { - if (!ignore_char_inputs && !is_readonly && !user_nav_input_start) + if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav) for (int n = 0; n < io.InputQueueCharacters.Size; n++) { // Insert character if they pass filtering unsigned int c = (unsigned int)io.InputQueueCharacters[n]; - if (c == '\t' && io.KeyShift) + if (c == '\t') // Skip Tab, see above. continue; - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } @@ -3667,67 +4402,109 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Process other shortcuts/key-presses - bool cancel_edit = false; + bool revert_edit = false; if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) { IM_ASSERT(state != NULL); + + const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); + state->Stb.row_count_per_page = row_count_per_page; + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_osx = io.ConfigMacOSXBehaviors; - const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl - const bool is_osx_shift_shortcut = is_osx && io.KeySuper && io.KeyShift && !io.KeyCtrl && !io.KeyAlt; const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End - const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper; - const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper; - - const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); - const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); - const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; - const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); - const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; - - if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) + + // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText) + // Otherwise we could simply assume that we own the keys as we are active. + const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat; + const bool is_cut = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, id, f_repeat)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, id)) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, id, f_repeat)) && !is_readonly; + const bool is_undo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z, id, f_repeat)) && !is_readonly && is_undoable; + const bool is_redo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y, id, f_repeat) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z, id, f_repeat))) && !is_readonly && is_undoable; + const bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A, id); + + // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true); + const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false)); + const bool is_cancel = Shortcut(ImGuiKey_Escape, id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, id, f_repeat)); + + // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of. + if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) + { + if (!state->HasSelection()) + { + // OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace) + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); + } + else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) { if (!state->HasSelection()) { if (is_wordmove_key_down) - state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT); else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) - state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT); } state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + else if (is_enter_pressed || is_gamepad_validate) { + // Determine if we turn Enter into a \n character bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; - if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) { - enter_pressed = clear_active_id = true; + validated = true; + if (io.ConfigInputTextEnterKeepActive && !is_multiline) + state->SelectAll(); // No need to scroll + else + clear_active_id = true; } else if (!is_readonly) { unsigned int c = '\n'; // Insert new line - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } } - else if (IsKeyPressedMap(ImGuiKey_Escape)) + else if (is_cancel) { - clear_active_id = cancel_edit = true; + if (flags & ImGuiInputTextFlags_EscapeClearsAll) + { + if (state->CurLenA > 0) + { + revert_edit = true; + } + else + { + render_cursor = render_selection = false; + clear_active_id = true; + } + } + else + { + clear_active_id = revert_edit = true; + render_cursor = render_selection = false; + } } else if (is_undo || is_redo) { state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); state->ClearSelection(); } - else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + else if (is_select_all) { state->SelectAll(); state->CursorFollow = true; @@ -3759,15 +4536,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); - ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar)); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); int clipboard_filtered_len = 0; - for (const char* s = clipboard; *s; ) + for (const char* s = clipboard; *s != 0; ) { unsigned int c; s += ImTextCharFromUtf8(&c, s, NULL); - if (c == 0) - break; - if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) continue; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } @@ -3786,73 +4561,100 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Process callbacks and apply result back to user's buffer. + const char* apply_new_text = NULL; + int apply_new_text_length = 0; if (g.ActiveId == id) { IM_ASSERT(state != NULL); - const char* apply_new_text = NULL; - int apply_new_text_length = 0; - if (cancel_edit) + if (revert_edit && !is_readonly) { - // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. - if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0) + if (flags & ImGuiInputTextFlags_EscapeClearsAll) + { + // Clear input + apply_new_text = ""; + apply_new_text_length = 0; + STB_TEXTEDIT_CHARTYPE empty_string; + stb_textedit_replace(state, &state->Stb, &empty_string, 0); + } + else if (strcmp(buf, state->InitialTextA.Data) != 0) { + // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. + // Push records into the undo stack so we can CTRL+Z the revert operation itself apply_new_text = state->InitialTextA.Data; apply_new_text_length = state->InitialTextA.Size - 1; + value_changed = true; + ImVector w_text; + if (apply_new_text_length > 0) + { + w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); + ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); + } + stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); } } + // Apply ASCII value + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. - // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage. - bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). + const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); if (apply_edit_back_to_user_buffer) { // Apply new value immediately - copy modified buffer back // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. - if (!is_readonly) - { - state->TextAIsValid = true; - state->TextA.resize(state->TextW.Size * 4 + 1); - ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); - } // User callback - if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0) + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) { IM_ASSERT(callback != NULL); // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. ImGuiInputTextFlags event_flag = 0; - ImGuiKey event_key = ImGuiKey_COUNT; - if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + ImGuiKey event_key = ImGuiKey_None; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, id)) { event_flag = ImGuiInputTextFlags_CallbackCompletion; event_key = ImGuiKey_Tab; } - else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow)) { event_flag = ImGuiInputTextFlags_CallbackHistory; event_key = ImGuiKey_UpArrow; } - else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow)) { event_flag = ImGuiInputTextFlags_CallbackHistory; event_key = ImGuiKey_DownArrow; } + else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited) + { + event_flag = ImGuiInputTextFlags_CallbackEdit; + } else if (flags & ImGuiInputTextFlags_CallbackAlways) + { event_flag = ImGuiInputTextFlags_CallbackAlways; + } if (event_flag) { ImGuiInputTextCallbackData callback_data; - memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.Ctx = &g; callback_data.EventFlag = event_flag; callback_data.Flags = flags; callback_data.UserData = callback_user_data; + char* callback_buf = is_readonly ? buf : state->TextA.Data; callback_data.EventKey = event_key; - callback_data.Buf = state->TextA.Data; + callback_data.Buf = callback_buf; callback_data.BufTextLen = state->CurLenA; callback_data.BufSize = state->BufCapacityA; callback_data.BufDirty = false; @@ -3867,17 +4669,21 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback(&callback_data); // Read back what user may have modified - IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields + callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback + IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields IM_ASSERT(callback_data.BufSize == state->BufCapacityA); IM_ASSERT(callback_data.Flags == flags); - if (callback_data.CursorPos != utf8_cursor_pos) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } - if (callback_data.SelectionEnd != utf8_selection_end) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } - if (callback_data.BufDirty) + const bool buf_dirty = callback_data.BufDirty; + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (buf_dirty) { + IM_ASSERT((flags & ImGuiInputTextFlags_ReadOnly) == 0); IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? if (callback_data.BufTextLen > backup_current_text_length && is_resizable) - state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CursorAnimReset(); @@ -3890,43 +4696,59 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { apply_new_text = state->TextA.Data; apply_new_text_length = state->CurLenA; + value_changed = true; } } + } - // Copy result to user buffer - if (apply_new_text) + // Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details) + if (g.InputTextDeactivatedState.ID == id) + { + if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly) { - IM_ASSERT(apply_new_text_length >= 0); - if (backup_current_text_length != apply_new_text_length && is_resizable) - { - ImGuiInputTextCallbackData callback_data; - callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; - callback_data.Flags = flags; - callback_data.Buf = buf; - callback_data.BufTextLen = apply_new_text_length; - callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); - callback_data.UserData = callback_user_data; - callback(&callback_data); - buf = callback_data.Buf; - buf_size = callback_data.BufSize; - apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); - IM_ASSERT(apply_new_text_length <= buf_size); - } + apply_new_text = g.InputTextDeactivatedState.TextA.Data; + apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1; + value_changed |= (strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0); + //IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text); + } + g.InputTextDeactivatedState.ID = 0; + } - // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. - ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); - value_changed = true; + // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) + if (apply_new_text != NULL) + { + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.Ctx = &g; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); } + //IMGUI_DEBUG_PRINT("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); - // Clear temporary user storage - state->UserFlags = 0; - state->UserCallback = NULL; - state->UserCallbackData = NULL; + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); } // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) - if (clear_active_id && g.ActiveId == id) + // Otherwise request text input ahead for next frame. + if (g.ActiveId == id && clear_active_id) ClearActiveID(); + else if (g.ActiveId == id) + g.WantTextInputNextFrame = 1; // Render frame if (!is_multiline) @@ -4006,11 +4828,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ searches_result_line_no[1] = line_count; // Calculate 2d position by finding the beginning of the line and measuring distance - cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; cursor_offset.y = searches_result_line_no[0] * g.FontSize; if (searches_result_line_no[1] >= 0) { - select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; select_start_offset.y = searches_result_line_no[1] * g.FontSize; } @@ -4026,10 +4848,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) { const float scroll_increment_x = inner_size.x * 0.25f; + const float visible_width = inner_size.x - style.FramePadding.x; if (cursor_offset.x < state->ScrollX) state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); - else if (cursor_offset.x - inner_size.x >= state->ScrollX) - state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x); } else { @@ -4039,11 +4862,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Vertical scroll if (is_multiline) { - float scroll_y = draw_window->Scroll.y; + // Test if cursor is vertically visible if (cursor_offset.y - g.FontSize < scroll_y) scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); - else if (cursor_offset.y - inner_size.y >= scroll_y) - scroll_y = cursor_offset.y - inner_size.y; + else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y) + scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; + const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); + scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y); draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag draw_window->Scroll.y = scroll_y; } @@ -4076,9 +4901,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true); if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines - ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn)); + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); @@ -4100,14 +4925,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { state->CursorAnim += io.DeltaTime; bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; - ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll; + ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (!is_readonly) - g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + { + g.PlatformImeData.WantVisible = true; + g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + g.PlatformImeData.InputLineHeight = g.FontSize; + } } } else @@ -4127,19 +4956,36 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } + if (is_password && !is_displaying_hint) + PopFont(); + if (is_multiline) { - Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line - EndChildFrame(); + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + EndChild(); + item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); + g.CurrentItemFlags = backup_item_flags; + + // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... + // FIXME: This quite messy/tricky, should attempt to get rid of the child window. EndGroup(); + if (g.LastItemData.ID == 0) + { + g.LastItemData.ID = id; + g.LastItemData.InFlags = item_data_backup.InFlags; + g.LastItemData.StatusFlags = item_data_backup.StatusFlags; + } } - if (is_password && !is_displaying_hint) - PopFont(); - // Log as text - if (g.LogEnabled && !(is_password && !is_displaying_hint)) + if (g.LogEnabled && (!is_password || is_displaying_hint)) + { + LogSetNextTextDecoration("{", "}"); LogRenderedText(&draw_pos, buf_display, buf_display_end); + } if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -4147,13 +4993,49 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) MarkItemEdited(id); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) - return enter_pressed; + return validated; else return value_changed; } +void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) +{ +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + ImGuiContext& g = *GImGui; + ImStb::STB_TexteditState* stb_state = &state->Stb; + ImStb::StbUndoState* undo_state = &stb_state->undostate; + Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); + DebugLocateItemOnHover(state->ID); + Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); + Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); + Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state + { + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + for (int n = 0; n < STB_TEXTEDIT_UNDOSTATECOUNT; n++) + { + ImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n]; + const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' '; + if (undo_rec_type == ' ') + BeginDisabled(); + char buf[64] = ""; + if (undo_rec_type != ' ' && undo_rec->char_storage != -1) + ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length); + Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"", + undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf); + if (undo_rec_type == ' ') + EndDisabled(); + } + PopStyleVar(); + } + EndChild(); +#else + IM_UNUSED(state); +#endif +} + //------------------------------------------------------------------------- // [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. //------------------------------------------------------------------------- @@ -4174,9 +5056,37 @@ bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flag return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); } -// Edit colors components (each component in 0.0f..1.0f range). -// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. -// With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +static void ColorEditRestoreH(const float* col, float* H) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ColorEditCurrentID != 0); + if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + return; + *H = g.ColorEditSavedHue; +} + +// ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. +// Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. +static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ColorEditCurrentID != 0); + if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + return; + + // When S == 0, H is undefined. + // When H == 1 it wraps around to 0. + if (*S == 0.0f || (*H == 0.0f && g.ColorEditSavedHue == 1)) + *H = g.ColorEditSavedHue; + + // When V == 0, S is undefined. + if (*V == 0.0f) + *S = g.ColorEditSavedSat; +} + +// Edit colors components (each component in 0.0f..1.0f range). +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) { ImGuiWindow* window = GetCurrentWindow(); @@ -4194,28 +5104,31 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag BeginGroup(); PushID(label); + const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); + if (set_current_color_edit_id) + g.ColorEditCurrentID = window->IDStack.back(); // If we're not showing any slider there's no point in doing any HSV conversions const ImGuiColorEditFlags flags_untouched = flags; if (flags & ImGuiColorEditFlags_NoInputs) - flags = (flags & (~ImGuiColorEditFlags__DisplayMask)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; // Context menu: display and modify options (before defaults are applied) if (!(flags & ImGuiColorEditFlags_NoOptions)) ColorEditOptionsPopup(col, flags); // Read stored options - if (!(flags & ImGuiColorEditFlags__DisplayMask)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DisplayMask); - if (!(flags & ImGuiColorEditFlags__DataTypeMask)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask); - if (!(flags & ImGuiColorEditFlags__PickerMask)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask); - if (!(flags & ImGuiColorEditFlags__InputMask)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputMask); - flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask)); - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check that only 1 is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_DisplayMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_); + if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_); + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_); + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; @@ -4227,10 +5140,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) { - // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); - if (f[1] == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) - f[0] = g.ColorEditLastHue; + ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); } int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; @@ -4244,8 +5156,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) { // RGB/HSV 0..255 Sliders - const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); - const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; @@ -4269,19 +5181,18 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag SameLine(0, style.ItemInnerSpacing.x); SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last); - // Disable Hue edit when Saturation is zero - const bool disable_hue_edit = (n == 0 && (flags & ImGuiColorEditFlags_DisplayHSV) && i[1] == 0); + // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0. if (flags & ImGuiColorEditFlags_Float) { - value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, disable_hue_edit ? +FLT_MAX : 0.0f, disable_hue_edit ? -FLT_MAX : hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); value_changed_as_float |= value_changed; } else { - value_changed |= DragInt(ids[n], &i[n], 1.0f, disable_hue_edit ? INT_MAX : 0, disable_hue_edit ? INT_MIN : hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } } else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) @@ -4289,9 +5200,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // RGB Hexadecimal Input char buf[64]; if (alpha) - ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255)); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); else - ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255)); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); SetNextItemWidth(w_inputs); if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) { @@ -4299,14 +5210,17 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag char* p = buf; while (*p == '#' || ImCharIsBlankA(*p)) p++; - i[0] = i[1] = i[2] = i[3] = 0; + i[0] = i[1] = i[2] = 0; + i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. inputting #FFFFFF omitting alpha) + int r; if (alpha) - sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) else - sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } ImGuiWindow* picker_active_window = NULL; @@ -4323,31 +5237,37 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Store current color and open a picker g.ColorPickerRef = col_v4; OpenPopup("picker"); - SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y)); + SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(0.0f, style.ItemSpacing.y)); } } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (BeginPopup("picker")) { - picker_active_window = g.CurrentWindow; - if (label != label_display_end) + if (g.CurrentWindow->BeginCount == 1) { - TextEx(label, label_display_end); - Spacing(); + picker_active_window = g.CurrentWindow; + if (label != label_display_end) + { + TextEx(label, label_display_end); + Spacing(); + } + ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); } - ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; - ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; - SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? - value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); EndPopup(); } } if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) { - window->DC.CursorPos = ImVec2(pos.x + w_full + style.ItemInnerSpacing.x, pos.y + style.FramePadding.y); + // Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left), + // but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this. + SameLine(0.0f, style.ItemInnerSpacing.x); + window->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x); TextEx(label, label_display_end); } @@ -4359,9 +5279,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag f[n] = i[n] / 255.0f; if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) { - g.ColorEditLastHue = f[0]; + g.ColorEditSavedHue = f[0]; + g.ColorEditSavedSat = f[1]; ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); - memcpy(g.ColorEditLastColor, f, sizeof(float) * 3); + g.ColorEditSavedID = g.ColorEditCurrentID; + g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); } if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); @@ -4373,17 +5295,19 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag col[3] = f[3]; } + if (set_current_color_edit_id) + g.ColorEditCurrentID = 0; PopID(); EndGroup(); // Drag and Drop Target // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. - if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) { bool accepted_drag_drop = false; if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086 value_changed = accepted_drag_drop = true; } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) @@ -4400,10 +5324,10 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) - window->DC.LastItemId = g.ActiveId; + g.LastItemData.ID = g.ActiveId; - if (value_changed) - MarkItemEdited(window->DC.LastItemId); + if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + MarkItemEdited(g.LastItemData.ID); return value_changed; } @@ -4417,52 +5341,6 @@ bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags fl return true; } -static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b) -{ - float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; - int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); - int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); - int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); - return IM_COL32(r, g, b, 0xFF); -} - -// Helper for ColorPicker4() -// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. -// I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether. -void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) - { - ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204,204,204,255), col)); - ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128,128,128,255), col)); - window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); - - int yi = 0; - for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) - { - float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); - if (y2 <= y1) - continue; - for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) - { - float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); - if (x2 <= x1) - continue; - int rounding_corners_flags_cell = 0; - if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } - if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } - rounding_corners_flags_cell &= rounding_corners_flags; - window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); - } - } - } - else - { - window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); - } -} - // Helper for ColorPicker4() static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) { @@ -4492,6 +5370,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl g.NextItemData.ClearFlags(); PushID(label); + const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); + if (set_current_color_edit_id) + g.ColorEditCurrentID = window->IDStack.back(); BeginGroup(); if (!(flags & ImGuiColorEditFlags_NoSidePreview)) @@ -4502,12 +5383,12 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ColorPickerOptionsPopup(col, flags); // Read stored options - if (!(flags & ImGuiColorEditFlags__PickerMask)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask; - if (!(flags & ImGuiColorEditFlags__InputMask)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__InputMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__InputMask; - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check that only 1 is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected if (!(flags & ImGuiColorEditFlags_NoOptions)) flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); @@ -4528,7 +5409,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl float wheel_thickness = sv_picker_size * 0.08f; float wheel_r_outer = sv_picker_size * 0.50f; float wheel_r_inner = wheel_r_outer - wheel_thickness; - ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f); + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); @@ -4540,10 +5421,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl float R = col[0], G = col[1], B = col[2]; if (flags & ImGuiColorEditFlags_InputRGB) { - // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. ColorConvertRGBtoHSV(R, G, B, H, S, V); - if (S == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) - H = g.ColorEditLastHue; + ColorEditRestoreHS(col, &H, &S, &V); } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -4562,10 +5442,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; ImVec2 current_off = g.IO.MousePos - wheel_center; float initial_dist2 = ImLengthSqr(initial_off); - if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1)) + if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1)) { // Interactive with Hue wheel - H = ImAtan2(current_off.y, current_off.x) / IM_PI*0.5f; + H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f; if (H < 0.0f) H += 1.0f; value_changed = value_changed_h = true; @@ -4586,7 +5466,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } else if (flags & ImGuiColorEditFlags_PickerHueBar) { @@ -4594,19 +5474,20 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); if (IsItemActive()) { - S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1)); - V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); + V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. value_changed = value_changed_sv = true; } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); // Hue bar logic SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); if (IsItemActive()) { - H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); value_changed = value_changed_h = true; } } @@ -4618,7 +5499,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); if (IsItemActive()) { - col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); value_changed = true; } } @@ -4648,7 +5529,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoLabel)) Text("Current"); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); if (ref_col != NULL) { @@ -4669,9 +5550,11 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { if (flags & ImGuiColorEditFlags_InputRGB) { - ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); - g.ColorEditLastHue = H; - memcpy(g.ColorEditLastColor, col, sizeof(float) * 3); + ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]); + g.ColorEditSavedHue = H; + g.ColorEditSavedSat = S; + g.ColorEditSavedID = g.ColorEditCurrentID; + g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -4686,19 +5569,19 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoInputs) == 0) { PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; - if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) { - // FIXME: Hackily differenciating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. + // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); value_changed = true; } - if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV); - if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex); PopItemWidth(); } @@ -4725,8 +5608,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl G = col[1]; B = col[2]; ColorConvertRGBtoHSV(R, G, B, H, S, V); - if (S == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) // Fix local Hue as display below will use it immediately. - H = g.ColorEditLastHue; + ColorEditRestoreHS(col, &H, &S, &V); // Fix local Hue as display below will use it immediately. } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -4760,23 +5642,23 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; const int vert_start_idx = draw_list->VtxBuffer.Size; draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); - draw_list->PathStroke(col_white, false, wheel_thickness); + draw_list->PathStroke(col_white, 0, wheel_thickness); const int vert_end_idx = draw_list->VtxBuffer.Size; // Paint colors over existing vertices ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); - ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n+1]); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]); } // Render Cursor + preview on Hue Wheel float cos_hue_angle = ImCos(H * 2.0f * IM_PI); float sin_hue_angle = ImSin(H * 2.0f * IM_PI); - ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; - int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); + int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others. draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); - draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, col_midgrey, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); // Render SV triangle (rotated according to hue) @@ -4784,13 +5666,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); ImVec2 uv_white = GetFontTexUvWhitePixel(); - draw_list->PrimReserve(6, 6); + draw_list->PrimReserve(3, 3); draw_list->PrimVtx(tra, uv_white, hue_color32); - draw_list->PrimVtx(trb, uv_white, hue_color32); - draw_list->PrimVtx(trc, uv_white, col_white); - draw_list->PrimVtx(tra, uv_white, 0); draw_list->PrimVtx(trb, uv_white, col_black); - draw_list->PrimVtx(trc, uv_white, 0); + draw_list->PrimVtx(trc, uv_white, col_white); draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); } @@ -4813,16 +5692,17 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; - draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12); - draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, col_midgrey, 12); - draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12); + int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others. + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments); // Render alpha bar if (alpha_bar) { float alpha = ImSaturate(col[3]); ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); - RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); @@ -4833,19 +5713,21 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) value_changed = false; - if (value_changed) - MarkItemEdited(window->DC.LastItemId); + if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + MarkItemEdited(g.LastItemData.ID); + if (set_current_color_edit_id) + g.ColorEditCurrentID = 0; PopID(); return value_changed; } -// A little colored square. Return true when clicked. +// A little color square. Return true when clicked. // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. // Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. -bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, const ImVec2& size_arg) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -4853,11 +5735,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl ImGuiContext& g = *GImGui; const ImGuiID id = window->GetID(desc_id); - float default_size = GetFrameHeight(); - if (size.x == 0.0f) - size.x = default_size; - if (size.y == 0.0f) - size.y = default_size; + const float default_size = GetFrameHeight(); + const ImVec2 size(size_arg.x == 0.0f ? default_size : size_arg.x, size_arg.y == 0.0f ? default_size : size_arg.y); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); if (!ItemAdd(bb, id)) @@ -4877,28 +5756,35 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl float grid_step = ImMin(size.x, size.y) / 2.99f; float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); ImRect bb_inner = bb; - float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. - bb_inner.Expand(off); + float off = 0.0f; + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + bb_inner.Expand(off); + } if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); - RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight); - window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); } else { // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; if (col_source.w < 1.0f) - RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); else - window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); } RenderNavHighlight(bb, id); - if (g.Style.FrameBorderSize > 0.0f) - RenderFrameBorder(bb.Min, bb.Max, rounding); - else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + if (g.Style.FrameBorderSize > 0.0f) + RenderFrameBorder(bb.Min, bb.Max, rounding); + else + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + } // Drag and Drop Source // NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. @@ -4916,7 +5802,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl // Tooltip if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) - ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); return pressed; } @@ -4925,18 +5811,18 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) { ImGuiContext& g = *GImGui; - if ((flags & ImGuiColorEditFlags__DisplayMask) == 0) - flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DisplayMask; - if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0) - flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask; - if ((flags & ImGuiColorEditFlags__PickerMask) == 0) - flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask; - if ((flags & ImGuiColorEditFlags__InputMask) == 0) - flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputMask; - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DataTypeMask)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check only 1 option is selected + if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; + if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; + if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; + if ((flags & ImGuiColorEditFlags_InputMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected g.ColorEditOptions = flags; } @@ -4945,7 +5831,8 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags { ImGuiContext& g = *GImGui; - BeginTooltipEx(0, true); + if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None)) + return; const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; if (text_end > text) { @@ -4956,9 +5843,9 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); - ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); SameLine(); - if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags__InputMask)) + if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) { if (flags & ImGuiColorEditFlags_NoAlpha) Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); @@ -4977,28 +5864,28 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) { - bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__DisplayMask); - bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask); + bool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_); + bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) return; ImGuiContext& g = *GImGui; ImGuiColorEditFlags opts = g.ColorEditOptions; if (allow_opt_inputs) { - if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayRGB; - if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHSV; - if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHex; + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex; } if (allow_opt_datatype) { if (allow_opt_inputs) Separator(); - if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8; - if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float; + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float; } if (allow_opt_inputs || allow_opt_datatype) Separator(); - if (Button("Copy as..", ImVec2(-1,0))) + if (Button("Copy as..", ImVec2(-1, 0))) OpenPopup("Copy"); if (BeginPopup("Copy")) { @@ -5010,12 +5897,15 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); if (Selectable(buf)) SetClipboardText(buf); - if (flags & ImGuiColorEditFlags_NoAlpha) - ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb); - else - ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, cb); if (Selectable(buf)) SetClipboardText(buf); + if (!(flags & ImGuiColorEditFlags_NoAlpha)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + } EndPopup(); } @@ -5025,7 +5915,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) { - bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask); + bool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_); bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) return; @@ -5039,16 +5929,16 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl // Draw small/thumbnail version of each picker type (over an invisible button for selection) if (picker_type > 0) Separator(); PushID(picker_type); - ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs|ImGuiColorEditFlags_NoOptions|ImGuiColorEditFlags_NoLabel|ImGuiColorEditFlags_NoSidePreview|(flags & ImGuiColorEditFlags_NoAlpha); + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha); if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; ImVec2 backup_pos = GetCursorScreenPos(); if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup - g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); SetCursorScreenPos(backup_pos); - ImVec4 dummy_ref_col; - memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); - ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); + ImVec4 previewing_ref_col; + memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + ColorPicker4("##previewing_picker", &previewing_ref_col.x, picker_flags); PopID(); } PopItemWidth(); @@ -5056,7 +5946,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_alpha_bar) { if (allow_opt_picker) Separator(); - CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); } EndPopup(); } @@ -5145,9 +6035,9 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); + const char* label, *label_end; + ImFormatStringToTempBufferV(&label, &label_end, fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, label, label_end); } bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) @@ -5156,12 +6046,19 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char if (window->SkipItems) return false; + const char* label, *label_end; + ImFormatStringToTempBufferV(&label, &label_end, fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end); +} + +void ImGui::TreeNodeSetOpen(ImGuiID id, bool open) +{ ImGuiContext& g = *GImGui; - const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); + ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage; + storage->SetInt(id, open ? 1 : 0); } -bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags) { if (flags & ImGuiTreeNodeFlags_Leaf) return true; @@ -5177,7 +6074,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) if (g.NextItemData.OpenCond & ImGuiCond_Always) { is_open = g.NextItemData.OpenVal; - storage->SetInt(id, is_open); + TreeNodeSetOpen(id, is_open); } else { @@ -5186,7 +6083,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) if (stored_value == -1) { is_open = g.NextItemData.OpenVal; - storage->SetInt(id, is_open); + TreeNodeSetOpen(id, is_open); } else { @@ -5223,7 +6120,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const ImVec2 label_size = CalcTextSize(label, label_end, false); // We vertically grow up to current line height up the typical widget height. - const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); ImRect frame_bb; frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; frame_bb.Min.y = window->DC.CursorPos.y; @@ -5237,9 +6134,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f); } - const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing + const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapser arrow width + Spacing const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it - const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapser ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); ItemSize(ImVec2(text_width, frame_height), padding.y); @@ -5252,72 +6149,87 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; - bool is_open = TreeNodeBehaviorIsOpen(id, flags); + bool is_open = TreeNodeUpdateNextOpen(id, flags); if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) - window->DC.TreeMayJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); + window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); bool item_add = ItemAdd(interact_bb, id); - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; - window->DC.LastItemDisplayRect = frame_bb; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + g.LastItemData.DisplayRect = frame_bb; if (!item_add) { if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); - IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } - // Flags that affects opening behavior: - // - 0 (default) .................... single-click anywhere to open - // - OpenOnDoubleClick .............. double-click anywhere to open - // - OpenOnArrow .................... single-click on arrow to open - // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open - ImGuiButtonFlags button_flags = 0; + ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) button_flags |= ImGuiButtonFlags_AllowItemOverlap; - if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) - button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; - // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily // allow browsing a tree while preserving selection with code implementing multi-selection patterns. // When clicking on the rest of the tree node we always disallow keyboard modifiers. - const float hit_padding_x = style.TouchExtraPadding.x; - const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x; - const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x; - if (window != g.HoveredWindow || !(g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2)) + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; + const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); + if (window != g.HoveredWindow || !is_mouse_x_over_arrow) button_flags |= ImGuiButtonFlags_NoKeyModifiers; - + + // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. + // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. + // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1) + // - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1) + // - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0) + // It is rather standard that arrow click react on Down rather than Up. + // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work. + if (is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_PressedOnClick; + else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + else + button_flags |= ImGuiButtonFlags_PressedOnClickRelease; + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; const bool was_selected = selected; bool hovered, held; bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); + bool toggled = false; if (!is_leaf) { - bool toggled = false; - if (pressed) + if (pressed && g.DragDropHoldJustPressedId != id) { if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) toggled = true; if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job - if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0]) + toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) + toggled = true; + } + else if (pressed && g.DragDropHoldJustPressedId == id) + { + IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); + if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. toggled = true; - if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. - toggled = false; } - if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) { toggled = true; + NavClearPreferredPosForAxis(ImGuiAxis_X); NavMoveRequestCancel(); } - if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? { toggled = true; + NavClearPreferredPosForAxis(ImGuiAxis_X); NavMoveRequestCancel(); } @@ -5325,7 +6237,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { is_open = !is_open; window->DC.StateStorage->SetInt(id, is_open); - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) @@ -5333,7 +6245,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; // Render const ImU32 text_col = GetColorU32(ImGuiCol_Text); @@ -5352,19 +6264,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l text_pos.x -= text_offset_x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) - { - // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. - const char log_prefix[] = "\n##"; - const char log_suffix[] = "##"; - LogRenderedText(&text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - LogRenderedText(&text_pos, log_suffix, log_suffix+2); - } - else - { - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - } + LogSetNextTextDecoration("###", "###"); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); } else { @@ -5373,20 +6276,20 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); - RenderNavHighlight(frame_bb, id, nav_highlight_flags); } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); if (g.LogEnabled) - LogRenderedText(&text_pos, ">"); + LogSetNextTextDecoration(">", NULL); RenderText(text_pos, label, label_end, false); } if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5395,7 +6298,7 @@ void ImGui::TreePush(const char* str_id) ImGuiWindow* window = GetCurrentWindow(); Indent(); window->DC.TreeDepth++; - PushID(str_id ? str_id : "#TreePush"); + PushID(str_id); } void ImGui::TreePush(const void* ptr_id) @@ -5403,15 +6306,16 @@ void ImGui::TreePush(const void* ptr_id) ImGuiWindow* window = GetCurrentWindow(); Indent(); window->DC.TreeDepth++; - PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); + PushID(ptr_id); } void ImGui::TreePushOverrideID(ImGuiID id) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; Indent(); window->DC.TreeDepth++; - window->IDStack.push_back(id); + PushOverrideID(id); } void ImGui::TreePop() @@ -5425,12 +6329,12 @@ void ImGui::TreePop() // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) - if (g.NavIdIsAlive && (window->DC.TreeMayJumpToParentOnPopMask & tree_depth_mask)) + if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) { - SetNavID(window->IDStack.back(), g.NavLayer); + SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); NavMoveRequestCancel(); } - window->DC.TreeMayJumpToParentOnPopMask &= tree_depth_mask - 1; + window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. PopID(); @@ -5465,31 +6369,38 @@ bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); } -bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) +// p_visible == NULL : regular collapsing header +// p_visible != NULL && *p_visible == true : show a small close button on the corner of the header, clicking the button will set *p_visible = false +// p_visible != NULL && *p_visible == false : do not show the header at all +// Do not mistake this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or ImGuiTreeNodeFlags_DefaultOpen. +bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - if (p_open && !*p_open) + if (p_visible && !*p_visible) return false; ImGuiID id = window->GetID(label); - flags |= ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton : 0); + flags |= ImGuiTreeNodeFlags_CollapsingHeader; + if (p_visible) + flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; bool is_open = TreeNodeBehavior(id, flags, label); - if (p_open) + if (p_visible != NULL) { // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. ImGuiContext& g = *GImGui; - ImGuiItemHoveredDataBackup last_item_backup; + ImGuiLastItemData last_item_backup = g.LastItemData; float button_size = g.FontSize; - float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); - float button_y = window->DC.LastItemRect.Min.y; - if (CloseButton(window->GetID((void*)((intptr_t)id + 1)), ImVec2(button_x, button_y))) - *p_open = false; - last_item_backup.Restore(); + float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); + float button_y = g.LastItemData.Rect.Min.y; + ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); + if (CloseButton(close_button_id, ImVec2(button_x, button_y))) + *p_visible = false; + g.LastItemData = last_item_backup; } return is_open; @@ -5501,8 +6412,10 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags // - Selectable() //------------------------------------------------------------------------- -// Tip: pass a non-visible label (e.g. "##dummy") then you can use the space to draw other text or image. +// Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags. +// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) { ImGuiWindow* window = GetCurrentWindow(); @@ -5512,78 +6425,103 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped. - PushColumnsBackground(); - + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. ImGuiID id = window->GetID(label); ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImVec2 pos = window->DC.CursorPos; pos.y += window->DC.CurrLineTextBaseOffset; - ImRect bb_inner(pos, pos + size); ItemSize(size, 0.0f); - // Fill horizontal space. - ImVec2 window_padding = window->WindowPadding; - float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x; - float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - pos.x); - ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); - ImRect bb(pos, pos + size_draw); - if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth)) - bb.Max.x += window_padding.x; - - // Selectables are tightly packed together so we extend the box to cover spacing between selectable. - const float spacing_x = style.ItemSpacing.x; - const float spacing_y = style.ItemSpacing.y; - const float spacing_L = IM_FLOOR(spacing_x * 0.50f); - const float spacing_U = IM_FLOOR(spacing_y * 0.50f); - bb.Min.x -= spacing_L; - bb.Min.y -= spacing_U; - bb.Max.x += (spacing_x - spacing_L); - bb.Max.y += (spacing_y - spacing_U); - - bool item_add; - if (flags & ImGuiSelectableFlags_Disabled) - { - ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; - item_add = ItemAdd(bb, id); - window->DC.ItemFlags = backup_item_flags; + // Fill horizontal space + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; + const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; + const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) + size.x = ImMax(label_size.x, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); + if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) + { + const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += (spacing_x - spacing_L); + bb.Max.y += (spacing_y - spacing_U); } - else + //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) { - item_add = ItemAdd(bb, id); + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; } - if (!item_add) + + const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; + const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None); + if (span_all_columns) { - if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) - PopColumnsBackground(); - return false; + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; } + if (!item_add) + return false; + + const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (disabled_item && !disabled_global) // Only testing this as an optimization + BeginDisabled(); + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries ImGuiButtonFlags button_flags = 0; - if (flags & ImGuiSelectableFlags_NoHoldingActiveID) button_flags |= ImGuiButtonFlags_NoHoldingActiveID; - if (flags & ImGuiSelectableFlags_PressedOnClick) button_flags |= ImGuiButtonFlags_PressedOnClick; - if (flags & ImGuiSelectableFlags_PressedOnRelease) button_flags |= ImGuiButtonFlags_PressedOnRelease; - if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; - if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; - if (flags & ImGuiSelectableFlags_AllowItemOverlap) button_flags |= ImGuiButtonFlags_AllowItemOverlap; - - if (flags & ImGuiSelectableFlags_Disabled) - selected = false; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } const bool was_selected = selected; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + // Auto-select when moved into + // - This will be more fully fleshed in the range-select branch + // - This is not exposed as it won't nicely work with some user side handling of shift/control + // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons + // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) + // - (2) usage will fail with clipped items + // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId) + if (g.NavJustMovedToId == id) + selected = pressed = true; + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { + SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) g.NavDisableHighlight = true; - SetNavID(id, window->DC.NavLayerCurrent); } } if (pressed) @@ -5594,34 +6532,32 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // In this branch, Selectable() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 - window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; // Render - if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) - hovered = true; if (hovered || selected) { const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); - if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) - { + if (span_all_columns && window->DC.CurrentColumns) PopColumnsBackground(); - bb.Max.x -= (GetContentRegionMax().x - max_x); - } + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); - if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); - RenderTextClipped(bb_inner.Min, bb_inner.Max, label, NULL, &label_size, style.SelectableTextAlign, &bb); - if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup)) CloseCurrentPopup(); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); - return pressed; + if (disabled_item && !disabled_global) + EndDisabled(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; //-V1020 } bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) @@ -5637,18 +6573,14 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags //------------------------------------------------------------------------- // [SECTION] Widgets: ListBox //------------------------------------------------------------------------- +// - BeginListBox() +// - EndListBox() // - ListBox() -// - ListBoxHeader() -// - ListBoxFooter() -//------------------------------------------------------------------------- -// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox -// and promote using them over existing ListBox() functions, similarly to change with combo boxes. //------------------------------------------------------------------------- -// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. -// Helper to calculate the size of a listbox and display a label on the right. -// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" -bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) +// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). +bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -5659,12 +6591,12 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + // Size default to hold ~7.25 items. + // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. g.NextItemData.ClearFlags(); if (!IsRectVisible(bb.Min, bb.Max)) @@ -5674,48 +6606,28 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) return false; } + // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. BeginGroup(); - if (label_size.x > 0) - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } BeginChildFrame(id, frame_bb.GetSize()); return true; } -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. -bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +void ImGui::EndListBox() { - // Size default to hold ~7.25 items. - // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. - // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. - // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. - if (height_in_items < 0) - height_in_items = ImMin(items_count, 7); - const ImGuiStyle& style = GetStyle(); - float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); - - // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). - ImVec2 size; - size.x = 0.0f; - size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f); - return ListBoxHeader(label, size); -} - -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. -void ImGui::ListBoxFooter() -{ - ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow; - const ImRect bb = parent_window->DC.LastItemRect; - const ImGuiStyle& style = GetStyle(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); + IM_UNUSED(window); EndChildFrame(); - - // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) - // We call SameLine() to restore DC.CurrentLine* data - SameLine(); - parent_window->DC.CursorPos = bb.Min; - ItemSize(bb, style.FramePadding.y); - EndGroup(); + EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label } bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) @@ -5724,24 +6636,35 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* const item return value_changed; } +// This is merely a helper around BeginListBox(), EndListBox(). +// Considering using those directly to submit custom data or store selection differently. bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) { - if (!ListBoxHeader(label, items_count, height_in_items)) + ImGuiContext& g = *GImGui; + + // Calculate size from "height_in_items" + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + float height_in_items_f = height_in_items + 0.25f; + ImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f)); + + if (!BeginListBox(label, size)) return false; - // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. - ImGuiContext& g = *GImGui; + // Assume all items have even height (= 1 line of text). If you need items of different height, + // you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; - ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + ImGuiListClipper clipper; + clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const bool item_selected = (i == *current_item); const char* item_text; if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; PushID(i); + const bool item_selected = (i == *current_item); if (Selectable(item_text, item_selected)) { *current_item = i; @@ -5751,9 +6674,10 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v SetItemDefaultFocus(); PopID(); } - ListBoxFooter(); + EndListBox(); + if (value_changed) - MarkItemEdited(g.CurrentWindow->DC.LastItemId); + MarkItemEdited(g.LastItemData.ID); return value_changed; } @@ -5765,29 +6689,31 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v // - PlotLines() // - PlotHistogram() //------------------------------------------------------------------------- +// Plot/Graph widgets are not very good. +// Consider writing your own, or using a third-party one, see: +// - ImPlot https://github.com/epezent/implot +// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions +//------------------------------------------------------------------------- -void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) +int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) - return; + return -1; - ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - if (frame_size.x == 0.0f) - frame_size.x = CalcItemWidth(); - if (frame_size.y == 0.0f) - frame_size.y = label_size.y + (style.FramePadding.y * 2); + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0, &frame_bb)) - return; + return -1; const bool hovered = ItemHoverable(frame_bb, id); // Determine scale from values if not specified @@ -5812,13 +6738,13 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1; + int idx_hovered = -1; if (values_count >= values_count_min) { int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); // Tooltip on hover - int v_hovered = -1; if (hovered && inner_bb.Contains(g.IO.MousePos)) { const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); @@ -5828,10 +6754,10 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge const float v0 = values_getter(data, (v_idx + values_offset) % values_count); const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); if (plot_type == ImGuiPlotType_Lines) - SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1); else if (plot_type == ImGuiPlotType_Histogram) SetTooltip("%d: %8.4g", v_idx, v0); - v_hovered = v_idx; + idx_hovered = v_idx; } const float t_step = 1.0f / (float)res_w; @@ -5840,7 +6766,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge float v0 = values_getter(data, (0 + values_offset) % values_count); float t0 = 0.0f; ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle - float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); @@ -5858,13 +6784,13 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); if (plot_type == ImGuiPlotType_Lines) { - window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); } else if (plot_type == ImGuiPlotType_Histogram) { if (pos1.x >= pos0.x + 2.0f) pos1.x -= 1.0f; - window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); } t0 = t1; @@ -5874,10 +6800,14 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f)); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + // Return hovered index or -1 if none are hovered. + // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + return idx_hovered; } struct ImGuiPlotArrayGetterData @@ -5963,49 +6893,51 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) // - EndMainMenuBar() // - BeginMenu() // - EndMenu() +// - MenuItemEx() [Internal] // - MenuItem() //------------------------------------------------------------------------- // Helpers for internal use -ImGuiMenuColumns::ImGuiMenuColumns() +void ImGuiMenuColumns::Update(float spacing, bool window_reappearing) { - Spacing = Width = NextWidth = 0.0f; - memset(Pos, 0, sizeof(Pos)); - memset(NextWidths, 0, sizeof(NextWidths)); + if (window_reappearing) + memset(Widths, 0, sizeof(Widths)); + Spacing = (ImU16)spacing; + CalcNextTotalWidth(true); + memset(Widths, 0, sizeof(Widths)); + TotalWidth = NextTotalWidth; + NextTotalWidth = 0; } -void ImGuiMenuColumns::Update(int count, float spacing, bool clear) +void ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets) { - IM_ASSERT(count == IM_ARRAYSIZE(Pos)); - IM_UNUSED(count); - Width = NextWidth = 0.0f; - Spacing = spacing; - if (clear) - memset(NextWidths, 0, sizeof(NextWidths)); - for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + ImU16 offset = 0; + bool want_spacing = false; + for (int i = 0; i < IM_ARRAYSIZE(Widths); i++) { - if (i > 0 && NextWidths[i] > 0.0f) - Width += Spacing; - Pos[i] = IM_FLOOR(Width); - Width += NextWidths[i]; - NextWidths[i] = 0.0f; + ImU16 width = Widths[i]; + if (want_spacing && width > 0) + offset += Spacing; + want_spacing |= (width > 0); + if (update_offsets) + { + if (i == 1) { OffsetLabel = offset; } + if (i == 2) { OffsetShortcut = offset; } + if (i == 3) { OffsetMark = offset; } + } + offset += width; } + NextTotalWidth = offset; } -float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double -{ - NextWidth = 0.0f; - NextWidths[0] = ImMax(NextWidths[0], w0); - NextWidths[1] = ImMax(NextWidths[1], w1); - NextWidths[2] = ImMax(NextWidths[2], w2); - for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) - NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); - return ImMax(Width, NextWidth); -} - -float ImGuiMenuColumns::CalcExtraSpace(float avail_w) const +float ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark) { - return ImMax(0.0f, avail_w - Width); + Widths[0] = ImMax(Widths[0], (ImU16)w_icon); + Widths[1] = ImMax(Widths[1], (ImU16)w_label); + Widths[2] = ImMax(Widths[2], (ImU16)w_shortcut); + Widths[3] = ImMax(Widths[3], (ImU16)w_mark); + CalcNextTotalWidth(false); + return (float)ImMax(TotalWidth, NextTotalWidth); } // FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. @@ -6027,14 +6959,15 @@ bool ImGui::BeginMenuBar() // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(IM_ROUND(bar_rect.Min.x), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding)), IM_ROUND(bar_rect.Max.y)); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); - window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). + window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.IsSameLine = false; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); window->DC.MenuBarAppending = true; AlignTextToFramePadding(); return true; @@ -6050,56 +6983,95 @@ void ImGui::EndMenuBar() // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) { + // Try to find out if the request is for one of our child menu ImGuiWindow* nav_earliest_child = g.NavWindow; while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) nav_earliest_child = nav_earliest_child->ParentWindow; - if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None) + if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) { // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. - // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) + // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering) const ImGuiNavLayer layer = ImGuiNavLayer_Menu; - IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); // Sanity check + IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) FocusWindow(window); - SetNavIDWithRectRel(window->NavLastIds[layer], layer, window->NavRectRel[layer]); - g.NavLayer = layer; + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. - g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; - NavMoveRequestCancel(); + g.NavDisableMouseHover = g.NavMousePosDirty = true; + NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat } } + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); PopID(); - window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. - window->DC.GroupStack.back().EmitItem = false; + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + g.GroupStack.back().EmitItem = false; EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.IsSameLine = false; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->DC.MenuBarAppending = false; } -// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. +// Important: calling order matters! +// FIXME: Somehow overlapping with docking tech. +// FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts) +bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags) +{ + IM_ASSERT(dir != ImGuiDir_None); + + ImGuiWindow* bar_window = FindWindowByName(name); + if (bar_window == NULL || bar_window->BeginCount == 0) + { + // Calculate and set window size/position + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); + ImRect avail_rect = viewport->GetBuildWorkRect(); + ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + ImVec2 pos = avail_rect.Min; + if (dir == ImGuiDir_Right || dir == ImGuiDir_Down) + pos[axis] = avail_rect.Max[axis] - axis_size; + ImVec2 size = avail_rect.GetSize(); + size[axis] = axis_size; + SetNextWindowPos(pos); + SetNextWindowSize(size); + + // Report our size into work area (for next frame) using actual window size + if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) + viewport->BuildWorkOffsetMin[axis] += axis_size; + else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) + viewport->BuildWorkOffsetMax[axis] -= axis_size; + } + + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint + bool is_open = Begin(name, NULL, window_flags); + PopStyleVar(2); + + return is_open; +} + bool ImGui::BeginMainMenuBar() { ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. + // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea? + // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings. g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); - SetNextWindowPos(ImVec2(0.0f, 0.0f)); - SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); - PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; - bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); - PopStyleVar(2); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + float height = GetFrameHeight(); + bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - if (!is_open) - { + + if (is_open) + BeginMenuBar(); + else End(); - return false; - } - return true; //-V1020 + return is_open; } void ImGui::EndMainMenuBar() @@ -6109,13 +7081,37 @@ void ImGui::EndMainMenuBar() // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; - if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL); + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); End(); } -bool ImGui::BeginMenu(const char* label, bool enabled) +static bool IsRootOfOpenMenuSet() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu)) + return false; + + // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others + // (e.g. inside menu bar vs loose menu items) based on parent ID. + // This would however prevent the use of e.g. PushID() user code submitting menus. + // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, + // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. + // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup + // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu. + // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer. + // This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still + // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart + // it likely won't be a problem anyone runs into. + const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; + if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer) + return false; + return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true); +} + +bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -6124,20 +7120,49 @@ bool ImGui::BeginMenu(const char* label, bool enabled) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); + bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); + + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) + // The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + window_flags |= ImGuiWindowFlags_ChildWindow; + + // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). + // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. + // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. + if (g.MenusIdSubmittedThisFrame.contains(id)) + { + if (menu_is_open) + menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + else + g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values + return menu_is_open; + } + + // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu + g.MenusIdSubmittedThisFrame.push_back(id); ImVec2 label_size = CalcTextSize(label, NULL, true); - bool pressed; - bool menu_is_open = IsPopupOpen(id); - bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); - ImGuiWindow* backed_nav_window = g.NavWindow; + // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) + // This is only done for items for the menu set and not the full parent window. + const bool menuset_is_open = IsRootOfOpenMenuSet(); if (menuset_is_open) - g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, - // However the final position is going to be different! It is choosen by FindBestWindowPosForPopup(). + // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. ImVec2 popup_pos, pos = window->DC.CursorPos; + PushID(label); + if (!enabled) + BeginDisabled(); + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + bool pressed; + + // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { // Menu inside an horizontal menu bar @@ -6147,24 +7172,35 @@ bool ImGui::BeginMenu(const char* label, bool enabled) window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); float w = label_size.x; - pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); + RenderText(text_pos, label); PopStyleVar(); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). } else { - // Menu inside a menu + // Menu inside a regular/vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); - float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, IM_FLOOR(g.FontSize * 1.20f)); // Feedback to next frame - float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); - pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); - ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled); - RenderArrow(window->DrawList, pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), text_col, ImGuiDir_Right); - } - - const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + RenderText(text_pos, label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); + } + if (!enabled) + EndDisabled(); + + const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover; if (menuset_is_open) - g.NavWindow = backed_nav_window; + PopItemFlag(); bool want_open = false; bool want_close = false; @@ -6172,37 +7208,39 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. - bool moving_toward_other_child_menu = false; - - ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; - if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) + bool moving_toward_child_menu = false; + ImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below) + ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL; + if (g.HoveredWindow == window && child_menu_window != NULL) { - // FIXME-DPI: Values should be derived from a master "scale" factor. + float ref_unit = g.FontSize; // FIXME-DPI + float child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f; ImRect next_window_rect = child_menu_window->Rect(); - ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; - ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); - ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); - float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. - ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues - tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? - tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); - moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); - //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] + ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); + ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack. + ta.x += child_dir * -0.5f; + tb.x += child_dir * ref_unit; + tc.x += child_dir * ref_unit; + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle has maximum height to limit the slope and the bias toward large sub-menus + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f); + moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] } - if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu) + + // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) + // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. + // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover) want_close = true; - if (!menu_is_open && hovered && pressed) // Click to open + // Open + if (!menu_is_open && pressed) // Click/activate to open want_open = true; - else if (!menu_is_open && hovered && !moving_toward_other_child_menu) // Hover to open + else if (!menu_is_open && hovered && !moving_toward_child_menu) // Hover to open want_open = true; - - if (g.NavActivateId == id) - { - want_close = menu_is_open; - want_open = !menu_is_open; - } - if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open { want_open = true; NavMoveRequestCancel(); @@ -6220,7 +7258,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { want_open = true; } - else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open + else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open { want_open = true; NavMoveRequestCancel(); @@ -6229,52 +7267,71 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' want_close = true; - if (want_close && IsPopupOpen(id)) + if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) ClosePopupToLevel(g.BeginPopupStack.Size, true); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + PopID(); - if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + if (want_open && !menu_is_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) { - // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. + // Don't reopen/recycle same menu level in the same frame, first close the other menu and yield for a frame. OpenPopup(label); - return false; } - - menu_is_open |= want_open; - if (want_open) + else if (want_open) + { + menu_is_open = true; OpenPopup(label); + } if (menu_is_open) { - // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) - SetNextWindowPos(popup_pos, ImGuiCond_Always); - ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; - if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) - flags |= ImGuiWindowFlags_ChildWindow; - menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + ImGuiLastItemData last_item_in_parent = g.LastItemData; + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos. + PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding + menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + PopStyleVar(); + if (menu_is_open) + { + // Restore LastItemData so IsItemXXXX functions can work after BeginMenu()/EndMenu() + // (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for ImGuiItemFlags_NoWindowHoverableCheck) + g.LastItemData = last_item_in_parent; + if (g.HoveredWindow == window) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + } + } + else + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values } return menu_is_open; } +bool ImGui::BeginMenu(const char* label, bool enabled) +{ + return BeginMenuEx(label, NULL, enabled); +} + void ImGui::EndMenu() { - // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). - // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. - // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. + // Nav: When a left move request our menu failed, close ourselves. ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) - { - ClosePopupToLevel(g.BeginPopupStack.Size, true); - NavMoveRequestCancel(); - } + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls + ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. + if (window->BeginCount == window->BeginCountPreviousFrame) + if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) + if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size - 1, true); + NavMoveRequestCancel(); + } EndPopup(); } -bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -6285,44 +7342,79 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo ImVec2 pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); + // See BeginMenuEx() for comments about this. + const bool menuset_is_open = IsRootOfOpenMenuSet(); + if (menuset_is_open) + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); + // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. - ImGuiSelectableFlags flags = ImGuiSelectableFlags_PressedOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled); bool pressed; + PushID(label); + if (!enabled) + BeginDisabled(); + + // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover; + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful - // Note that in this situation we render neither the shortcut neither the selected tick mark + // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark. float w = label_size.x; window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); - pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); + pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); PopStyleVar(); + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) + RenderText(text_pos, label); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). } else { - ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); - float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame - float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); - pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f)); - if (shortcut_size.x > 0.0f) + // Menu item inside a vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame + float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) { - PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); - PopStyleColor(); + RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + if (shortcut_w > 0.0f) + { + PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); } - if (selected) - RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); } + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + if (!enabled) + EndDisabled(); + PopID(); + if (menuset_is_open) + PopItemFlag(); - IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +{ + return MenuItemEx(label, NULL, shortcut, selected, enabled); +} + bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) { - if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) + if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled)) { if (p_selected) *p_selected = !*p_selected; @@ -6334,9 +7426,6 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, //------------------------------------------------------------------------- // [SECTION] Widgets: BeginTabBar, EndTabBar, etc. //------------------------------------------------------------------------- -// [BETA API] API may evolve! This code has been extracted out of the Docking branch, -// and some of the construct which are not used in Master may be left here to facilitate merging. -//------------------------------------------------------------------------- // - BeginTabBar() // - BeginTabBarEx() [Internal] // - EndTabBar() @@ -6344,46 +7433,69 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, // - TabBarCalcTabID() [Internal] // - TabBarCalcMaxTabWidth() [Internal] // - TabBarFindTabById() [Internal] +// - TabBarFindTabByOrder() [Internal] +// - TabBarGetCurrentTab() [Internal] +// - TabBarGetTabName() [Internal] // - TabBarRemoveTab() [Internal] // - TabBarCloseTab() [Internal] -// - TabBarScrollClamp()v +// - TabBarScrollClamp() [Internal] // - TabBarScrollToTab() [Internal] -// - TabBarQueueChangeTabOrder() [Internal] +// - TabBarQueueFocus() [Internal] +// - TabBarQueueReorder() [Internal] +// - TabBarProcessReorderFromMousePos() [Internal] +// - TabBarProcessReorder() [Internal] // - TabBarScrollingButtons() [Internal] // - TabBarTabListPopupButton() [Internal] //------------------------------------------------------------------------- +struct ImGuiTabBarSection +{ + int TabCount; // Number of tabs in this section. + float Width; // Sum of width of tabs in this section (after shrinking down) + float Spacing; // Horizontal spacing at the end of the section. + + ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); } +}; + namespace ImGui { static void TabBarLayout(ImGuiTabBar* tab_bar); - static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window); static float TabBarCalcMaxTabWidth(); static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); - static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); } ImGuiTabBar::ImGuiTabBar() { - ID = 0; - SelectedTabId = NextSelectedTabId = VisibleTabId = 0; + memset(this, 0, sizeof(*this)); CurrFrameVisible = PrevFrameVisible = -1; - LastTabContentHeight = 0.0f; - OffsetMax = OffsetMaxIdeal = OffsetNextTab = 0.0f; - ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f; - Flags = ImGuiTabBarFlags_None; - ReorderRequestTabId = 0; - ReorderRequestDir = 0; - WantLayout = VisibleTabWasSubmitted = false; LastTabItemIdx = -1; } -static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs) +static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab) +{ + return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; +} + +static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + const int a_section = TabItemGetSectionIdx(a); + const int b_section = TabItemGetSectionIdx(b); + if (a_section != b_section) + return a_section - b_section; + return (int)(a->IndexDuringLayout - b->IndexDuringLayout); +} + +static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs) { const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; - return (int)(a->Offset - b->Offset); + return (int)(a->BeginOrder - b->BeginOrder); } static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) @@ -6428,17 +7540,19 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); g.CurrentTabBar = tab_bar; + // Append with multiple BeginTabBar()/EndTabBar() pairs. + tab_bar->BackupCursorPos = window->DC.CursorPos; if (tab_bar->CurrFrameVisible == g.FrameCount) { - //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount); - IM_ASSERT(0); + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + tab_bar->BeginCount++; return true; } - // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. - // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. - if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) - ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); + // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); + tab_bar->TabsAddedNew = false; // Flags if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) @@ -6449,11 +7563,16 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->PrevTabsContentsHeight = tab_bar->CurrTabsContentsHeight; + tab_bar->CurrTabsContentsHeight = 0.0f; + tab_bar->ItemSpacingY = g.Style.ItemSpacing.y; tab_bar->FramePadding = g.Style.FramePadding; + tab_bar->TabsActiveCount = 0; + tab_bar->LastTabItemIdx = -1; + tab_bar->BeginCount = 1; - // Layout - ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); - window->DC.CursorPos.x = tab_bar->BarRect.Min.x; + // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); // Draw separator const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); @@ -6479,16 +7598,26 @@ void ImGui::EndTabBar() IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); return; } + + // Fallback in case no TabItem have been submitted if (tab_bar->WantLayout) TabBarLayout(tab_bar); // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) - tab_bar->LastTabContentHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f); + { + tab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight); + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight; + } else - window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->LastTabContentHeight; + { + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->PrevTabsContentsHeight; + } + if (tab_bar->BeginCount > 1) + window->DC.CursorPos = tab_bar->BackupCursorPos; + tab_bar->LastTabItemIdx = -1; if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) PopID(); @@ -6496,6 +7625,12 @@ void ImGui::EndTabBar() g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); } +// Scrolling happens only in the central section (leading/trailing sections are not scrolling) +static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections) +{ + return tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; +} + // This is called only once a frame before by the first call to ItemTab() // The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) @@ -6503,149 +7638,218 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) ImGuiContext& g = *GImGui; tab_bar->WantLayout = false; - // Garbage collect + // Garbage collect by compacting list + // Detect if we need to sort out tab list (e.g. in rare case where a tab changed section) int tab_dst_n = 0; + bool need_sort_by_section = false; + ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; - if (tab->LastFrameVisible < tab_bar->PrevFrameVisible) + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose) { - if (tab->ID == tab_bar->SelectedTabId) - tab_bar->SelectedTabId = 0; + // Remove tab + if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; } continue; } if (tab_dst_n != tab_src_n) tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + + tab = &tab_bar->Tabs[tab_dst_n]; + tab->IndexDuringLayout = (ImS16)tab_dst_n; + + // We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another) + int curr_tab_section_n = TabItemGetSectionIdx(tab); + if (tab_dst_n > 0) + { + ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; + int prev_tab_section_n = TabItemGetSectionIdx(prev_tab); + if (curr_tab_section_n == 0 && prev_tab_section_n != 0) + need_sort_by_section = true; + if (prev_tab_section_n == 2 && curr_tab_section_n != 2) + need_sort_by_section = true; + } + + sections[curr_tab_section_n].TabCount++; tab_dst_n++; } if (tab_bar->Tabs.Size != tab_dst_n) tab_bar->Tabs.resize(tab_dst_n); + if (need_sort_by_section) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection); + + // Calculate spacing between sections + sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + // Setup next selected tab - ImGuiID scroll_track_selected_tab_id = 0; + ImGuiID scroll_to_tab_id = 0; if (tab_bar->NextSelectedTabId) { tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; tab_bar->NextSelectedTabId = 0; - scroll_track_selected_tab_id = tab_bar->SelectedTabId; + scroll_to_tab_id = tab_bar->SelectedTabId; } // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). if (tab_bar->ReorderRequestTabId != 0) { - if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId)) - { - //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools - int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; - if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size) - { - ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; - ImGuiTabItem item_tmp = *tab1; - *tab1 = *tab2; - *tab2 = item_tmp; - if (tab2->ID == tab_bar->SelectedTabId) - scroll_track_selected_tab_id = tab2->ID; - tab1 = tab2 = NULL; - } - if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) - MarkIniSettingsDirty(); - } + if (TabBarProcessReorder(tab_bar)) + if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId) + scroll_to_tab_id = tab_bar->ReorderRequestTabId; tab_bar->ReorderRequestTabId = 0; } // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; if (tab_list_popup_button) - if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! - scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! + scroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; - // Compute ideal widths + // Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central + // (whereas our tabs are stored as: leading, central, trailing) + int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount }; g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); - float width_total_contents = 0.0f; + + // Compute ideal tabs widths + store them into shrink buffer ImGuiTabItem* most_recently_selected_tab = NULL; + int curr_section_n = -1; bool found_selected_tab_id = false; for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); - if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button)) most_recently_selected_tab = tab; if (tab->ID == tab_bar->SelectedTabId) found_selected_tab_id = true; + if (scroll_to_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_to_tab_id = tab->ID; // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. - const char* tab_name = tab_bar->GetTabName(tab); - const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true; - tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; + const char* tab_name = TabBarGetTabName(tab_bar, tab); + const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; - width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth; + int section_n = TabItemGetSectionIdx(tab); + ImGuiTabBarSection* section = §ions[section_n]; + section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f); + curr_section_n = section_n; // Store data so we can build an array sorted by width if we need to shrink tabs down - g.ShrinkWidthBuffer[tab_n].Index = tab_n; - g.ShrinkWidthBuffer[tab_n].Width = tab->ContentWidth; + IM_MSVC_WARNING_SUPPRESS(6385); + ImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++]; + shrink_width_item->Index = tab_n; + shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth; + tab->Width = ImMax(tab->ContentWidth, 1.0f); } - // Compute width - const float initial_offset_x = 0.0f; // g.Style.ItemInnerSpacing.x; - const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - initial_offset_x, 0.0f); - float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; - if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) - { - // If we don't have enough room, resize down the largest tabs first - ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess); - for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) - tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); - } + // Compute total ideal width (used for e.g. auto-resizing a window) + tab_bar->WidthAllTabsIdeal = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) + tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing; + + // Horizontal scrolling buttons + // (note that TabBarScrollButtons() will alter BarRect.Max.x) + if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) + { + scroll_to_tab_id = scroll_and_select_tab->ID; + if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) + tab_bar->SelectedTabId = scroll_to_tab_id; + } + + // Shrink widths if full tabs don't fit in their allocated space + float section_0_w = sections[0].Width + sections[0].Spacing; + float section_1_w = sections[1].Width + sections[1].Spacing; + float section_2_w = sections[2].Width + sections[2].Spacing; + bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth(); + float width_excess; + if (central_section_is_visible) + width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section else + width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section + + // With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore + if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible)) { - const float tab_max_width = TabBarCalcMaxTabWidth(); - for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount); + int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0); + ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess); + + // Apply shrunk values into tabs and sections + for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - tab->Width = ImMin(tab->ContentWidth, tab_max_width); - IM_ASSERT(tab->Width > 0.0f); + ImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index]; + float shrinked_width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); + if (shrinked_width < 0.0f) + continue; + + shrinked_width = ImMax(1.0f, shrinked_width); + int section_n = TabItemGetSectionIdx(tab); + sections[section_n].Width -= (tab->Width - shrinked_width); + tab->Width = shrinked_width; } } // Layout all active tabs - float offset_x = initial_offset_x; - float offset_x_ideal = offset_x; - tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored. - for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + int section_tab_index = 0; + float tab_offset = 0.0f; + tab_bar->WidthAllTabs = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - tab->Offset = offset_x; - if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) - scroll_track_selected_tab_id = tab->ID; - offset_x += tab->Width + g.Style.ItemInnerSpacing.x; - offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x; + ImGuiTabBarSection* section = §ions[section_n]; + if (section_n == 2) + tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset); + + for (int tab_n = 0; tab_n < section->TabCount; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n]; + tab->Offset = tab_offset; + tab->NameOffset = -1; + tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f); + } + tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f); + tab_offset += section->Spacing; + section_tab_index += section->TabCount; } - tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); - tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f); - // Horizontal scrolling buttons - const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); - if (scrolling_buttons) - if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x! - scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + // Clear name buffers + tab_bar->TabsNames.Buf.resize(0); // If we have lost the selected tab, select the next most recently active one if (found_selected_tab_id == false) tab_bar->SelectedTabId = 0; if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) - scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + scroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; // Lock in visible tab tab_bar->VisibleTabId = tab_bar->SelectedTabId; tab_bar->VisibleTabWasSubmitted = false; + // Apply request requests + if (scroll_to_tab_id != 0) + TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); + else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow)) + { + const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH; + const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX; + if (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f) + { + const float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f; + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step); + } + SetKeyOwner(wheel_key, tab_bar->ID); + } + // Update scrolling - if (scroll_track_selected_tab_id) - if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) - TabBarScrollToTab(tab_bar, scroll_track_selected_tab); tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) @@ -6661,15 +7865,21 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) { tab_bar->ScrollingSpeed = 0.0f; } + tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing; + tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing; - // Clear name buffers - if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) - tab_bar->TabsNames.Buf.resize(0); + // Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame) + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos = tab_bar->BarRect.Min; + ItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); + window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal); } -// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. -static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +// Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window) { + IM_ASSERT(docked_window == NULL); // master branch only + IM_UNUSED(docked_window); if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) { ImGuiID id = ImHashStr(label); @@ -6698,7 +7908,30 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) return NULL; } -// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +// Order = visible order, not submission order! (which is tab->BeginOrder) +ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order) +{ + if (order < 0 || order >= tab_bar->Tabs.Size) + return NULL; + return &tab_bar->Tabs[order]; +} + +ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar) +{ + if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size) + return NULL; + return &tab_bar->Tabs[tab_bar->LastTabItemIdx]; +} + +const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if (tab->NameOffset == -1) + return "N/A"; + IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size); + return tab_bar->TabsNames.Buf.Data + tab->NameOffset; +} + +// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) { if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) @@ -6711,52 +7944,146 @@ void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) // Called on manual closure attempt void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { - if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + if (tab->Flags & ImGuiTabItemFlags_Button) + return; // A button appended with TabItemButton(). + + if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) { // This will remove a frame of lag for selecting another tab on closure. // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure - tab->LastFrameVisible = -1; - tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + tab->WantClose = true; + if (tab_bar->VisibleTabId == tab->ID) + { + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } } - else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + else { - // Actually select before expecting closure - tab_bar->NextSelectedTabId = tab->ID; + // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) + if (tab_bar->VisibleTabId != tab->ID) + TabBarQueueFocus(tab_bar, tab); } } static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) { - scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth()); + scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth()); return ImMax(scrolling, 0.0f); } -static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +// Note: we may scroll to tab that are not selected! e.g. using keyboard arrow keys +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections) { + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); + if (tab == NULL) + return; + if (tab->Flags & ImGuiTabItemFlags_SectionMask_) + return; + ImGuiContext& g = *GImGui; float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) - int order = tab_bar->GetTabOrder(tab); - float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f); - float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); + int order = TabBarGetTabOrder(tab_bar, tab); + + // Scrolling happens only in the central section (leading/trailing sections are not scrolling) + float scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections); + + // We make all tabs positions all relative Sections[0].Width to make code simpler + float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f); + float tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f); tab_bar->ScrollingTargetDistToVisibility = 0.0f; - if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth())) + if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width)) { + // Scroll to the left tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); tab_bar->ScrollingTarget = tab_x1; } - else if (tab_bar->ScrollingTarget < tab_x2 - tab_bar->BarRect.GetWidth()) + else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width) { - tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - tab_bar->BarRect.GetWidth()) - tab_bar->ScrollingAnim, 0.0f); - tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth(); + // Scroll to the right + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - scrollable_width; } } -void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { - IM_ASSERT(dir == -1 || dir == +1); + tab_bar->NextSelectedTabId = tab->ID; +} + +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset) +{ + IM_ASSERT(offset != 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0); tab_bar->ReorderRequestTabId = tab->ID; - tab_bar->ReorderRequestDir = (ImS8)dir; + tab_bar->ReorderRequestOffset = (ImS16)offset; +} + +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0) + return; + + const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0); + + // Count number of contiguous tabs we are crossing over + const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1; + const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab); + int dst_idx = src_idx; + for (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir) + { + // Reordered tabs must share the same section + const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i]; + if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder) + break; + if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_)) + break; + dst_idx = i; + + // Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered. + const float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x; + const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x; + //GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255)); + if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2)) + break; + } + + if (dst_idx != src_idx) + TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx); +} + +bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); + if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder)) + return false; + + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset; + if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) + return false; + + // Reordered tabs must share the same section + // (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too) + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + if (tab2->Flags & ImGuiTabItemFlags_NoReorder) + return false; + if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_)) + return false; + + ImGuiTabItem item_tmp = *tab1; + ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2; + ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1; + const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset; + memmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem)); + *tab2 = item_tmp; + + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + return true; } static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) @@ -6770,13 +8097,6 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) const ImVec2 backup_cursor_pos = window->DC.CursorPos; //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); - const ImRect avail_bar_rect = tab_bar->BarRect; - bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f))); - if (want_clip_rect) - PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true); - - ImGuiTabItem* tab_to_select = NULL; - int select_dir = 0; ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; arrow_col.w *= 0.5f; @@ -6787,30 +8107,44 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) const float backup_repeat_rate = g.IO.KeyRepeatRate; g.IO.KeyRepeatDelay = 0.250f; g.IO.KeyRepeatRate = 0.200f; - window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y); + float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width); + window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y); if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) select_dir = -1; - window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y); + window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y); if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) select_dir = +1; PopStyleColor(2); g.IO.KeyRepeatRate = backup_repeat_rate; g.IO.KeyRepeatDelay = backup_repeat_delay; - if (want_clip_rect) - PopClipRect(); - + ImGuiTabItem* tab_to_scroll_to = NULL; if (select_dir != 0) if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) { - int selected_order = tab_bar->GetTabOrder(tab_item); + int selected_order = TabBarGetTabOrder(tab_bar, tab_item); int target_order = selected_order + select_dir; - tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible + + // Skip tab item buttons until another tab item is found or end is reached + while (tab_to_scroll_to == NULL) + { + // If we are at the end of the list, still scroll to make our tab visible + tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; + + // Cross through buttons + // (even if first/last item is a button, return it so we can update the scroll) + if (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button) + { + target_order += select_dir; + selected_order += select_dir; + tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; + } + } } window->DC.CursorPos = backup_cursor_pos; tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; - return tab_to_select; + return tab_to_scroll_to; } static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) @@ -6828,7 +8162,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) arrow_col.w *= 0.5f; PushStyleColor(ImGuiCol_Text, arrow_col); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview); + bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest); PopStyleColor(2); ImGuiTabItem* tab_to_select = NULL; @@ -6837,7 +8171,10 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - const char* tab_name = tab_bar->GetTabName(tab); + if (tab->Flags & ImGuiTabItemFlags_Button) + continue; + + const char* tab_name = TabBarGetTabName(tab_bar, tab); if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) tab_to_select = tab; } @@ -6851,11 +8188,9 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) //------------------------------------------------------------------------- // [SECTION] Widgets: BeginTabItem, EndTabItem, etc. //------------------------------------------------------------------------- -// [BETA API] API may evolve! This code has been extracted out of the Docking branch, -// and some of the construct which are not used in Master may be left here to facilitate merging. -//------------------------------------------------------------------------- // - BeginTabItem() // - EndTabItem() +// - TabItemButton() // - TabItemEx() [Internal] // - SetTabItemClosed() // - TabItemCalcSize() [Internal] @@ -6873,10 +8208,12 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!"); + IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - bool ret = TabItemEx(tab_bar, label, p_open, flags); + IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + + bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; @@ -6895,40 +8232,65 @@ void ImGui::EndTabItem() ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT(tab_bar != NULL && "Needs to be called between BeginTabBar() and EndTabBar()!"); + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return; } IM_ASSERT(tab_bar->LastTabItemIdx >= 0); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) - window->IDStack.pop_back(); + PopID(); } -bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) +bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) { // Layout whole tab bar if not already done + ImGuiContext& g = *GImGui; if (tab_bar->WantLayout) + { + ImGuiNextItemData backup_next_item_data = g.NextItemData; TabBarLayout(tab_bar); - - ImGuiContext& g = *GImGui; + g.NextItemData = backup_next_item_data; + } ImGuiWindow* window = g.CurrentWindow; if (window->SkipItems) return false; const ImGuiStyle& style = g.Style; - const ImGuiID id = TabBarCalcTabID(tab_bar, label); + const ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window); - // If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + // If the user called us with *p_open == false, we early out and don't render. + // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); if (p_open && !*p_open) { - PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); - ItemAdd(ImRect(), id); - PopItemFlag(); + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav); return false; } - // Calculate tab contents size - ImVec2 size = TabItemCalcSize(label, p_open != NULL); + IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing + + // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) + if (flags & ImGuiTabItemFlags_NoCloseButton) + p_open = NULL; + else if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; // Acquire tab data ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); @@ -6938,41 +8300,51 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, tab_bar->Tabs.push_back(ImGuiTabItem()); tab = &tab_bar->Tabs.back(); tab->ID = id; - tab->Width = size.x; - tab_is_new = true; + tab_bar->TabsAddedNew = tab_is_new = true; } - tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); - tab->ContentWidth = size.x; + tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab); - if (p_open == NULL) - flags |= ImGuiTabItemFlags_NoCloseButton; + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument)); + tab->RequestedWidth = -1.0f; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + size.x = tab->RequestedWidth = g.NextItemData.Width; + if (tab_is_new) + tab->Width = ImMax(1.0f, size.x); + tab->ContentWidth = size.x; + tab->BeginOrder = tab_bar->TabsActiveCount++; const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + const bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; tab->LastFrameVisible = g.FrameCount; tab->Flags = flags; - // Append name with zero-terminator - tab->NameOffset = tab_bar->TabsNames.size(); - tab_bar->TabsNames.append(label, label + strlen(label) + 1); - - // If we are not reorderable, always reset offset based on submission order. - // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) - if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + // Append name _WITH_ the zero-terminator + if (docked_window != NULL) { - tab->Offset = tab_bar->OffsetNextTab; - tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x; + IM_ASSERT(docked_window == NULL); // master branch only + } + else + { + tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); } // Update selected tab - if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) - if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) - tab_bar->NextSelectedTabId = id; // New tabs gets activated - if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar - tab_bar->NextSelectedTabId = id; + if (!is_tab_button) + { + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + TabBarQueueFocus(tab_bar, tab); // New tabs gets activated + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar + TabBarQueueFocus(tab_bar, tab); + } // Lock visibility + // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!) bool tab_contents_visible = (tab_bar->VisibleTabId == id); if (tab_contents_visible) tab_bar->VisibleTabWasSubmitted = true; @@ -6982,11 +8354,13 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) tab_contents_visible = true; - if (tab_appearing && !(tab_bar_appearing && !tab_is_new)) + // Note that tab_is_new is not necessarily the same as tab_appearing! When a tab bar stops being submitted + // and then gets submitted again, the tabs will have 'tab_appearing=true' but 'tab_is_new=false'. + if (tab_appearing && (!tab_bar_appearing || tab_is_new)) { - PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); - ItemAdd(ImRect(), id); - PopItemFlag(); + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav); + if (is_tab_button) + return false; return tab_contents_visible; } @@ -6997,15 +8371,19 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; // Layout + const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; size.x = tab->Width; - window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + if (is_central_section) + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + else + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); ImVec2 pos = window->DC.CursorPos; ImRect bb(pos, pos + size); // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) - bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x > tab_bar->BarRect.Max.x); + const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); if (want_clip_rect) - PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; ItemSize(bb.GetSize(), style.FramePadding.y); @@ -7020,17 +8398,16 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Click to Select a tab - ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap); + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); - if (pressed) - tab_bar->NextSelectedTabId = id; - hovered |= (g.HoveredId == id); + if (pressed && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) - if (!held) + if (g.ActiveId != id) SetItemAllowOverlap(); // Drag and drop: re-order tabs @@ -7041,19 +8418,17 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) { - if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) - TabBarQueueChangeTabOrder(tab_bar, tab, -1); + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); } else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) { - if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) - TabBarQueueChangeTabOrder(tab_bar, tab, +1); + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); } } } #if 0 - if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->ContentWidth) + if (hovered && g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth) { // Enlarge tab display when hovering bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); @@ -7070,15 +8445,17 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) - tab_bar->NextSelectedTabId = id; + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; // Render tab label, process close button - const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; - bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id); + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; + bool just_closed; + bool text_clipped; + TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); if (just_closed && p_open != NULL) { *p_open = false; @@ -7090,17 +8467,25 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, PopClipRect(); window->DC.CursorPos = backup_main_cursor_pos; - // Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer) - // We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar (which g.HoveredId ignores) - if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f && IsItemHovered()) - if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip)) - SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); - + // Tooltip + // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // FIXME: This is a mess. + // FIXME: We may want disabled tab to still display the tooltip? + if (text_clipped && g.HoveredId == id && !held) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + if (IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected + if (is_tab_button) + return pressed; return tab_contents_visible; } // [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. -// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem() +// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar(). +// Tabs closed by the close button will automatically be flagged to avoid this issue. void ImGui::SetTabItemClosed(const char* label) { ImGuiContext& g = *GImGui; @@ -7108,24 +8493,30 @@ void ImGui::SetTabItemClosed(const char* label) if (is_within_manual_tab_bar) { ImGuiTabBar* tab_bar = g.CurrentTabBar; - IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem() - ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); - TabBarRemoveTab(tab_bar, tab_id); + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL); + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab->WantClose = true; // Will be processed by next call to TabBarLayout() } } -ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker) { ImGuiContext& g = *GImGui; ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); - if (has_close_button) + if (has_close_button_or_unsaved_marker) size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. else size.x += g.Style.FramePadding.x + 1.0f; return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); } +ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*) +{ + IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch. + return ImVec2(0.0f, 0.0f); +} + void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) { // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. @@ -7133,7 +8524,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI const float width = bb.GetWidth(); IM_UNUSED(flags); IM_ASSERT(width > 0.0f); - const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); + const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); const float y1 = bb.Min.y + 1.0f; const float y2 = bb.Max.y - 1.0f; draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); @@ -7147,31 +8538,48 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); - draw_list->PathStroke(GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize); } } // Render text label (with custom clipping) + Unsaved Document marker + Close Button logic // We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. -bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id) +void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped) { ImGuiContext& g = *GImGui; ImVec2 label_size = CalcTextSize(label, NULL, true); + + if (out_just_closed) + *out_just_closed = false; + if (out_text_clipped) + *out_text_clipped = false; + if (bb.GetWidth() <= 1.0f) - return false; + return; + + // In Style V2 we'll have full override of all colors per state (e.g. focused, selected) + // But right now if you want to alter text color of tabs this is what you need to do. +#if 0 + const float backup_alpha = g.Style.Alpha; + if (!is_contents_visible) + g.Style.Alpha *= 0.7f; +#endif // Render text label (with clipping + alpha gradient) + unsaved marker - const char* TAB_UNSAVED_MARKER = "*"; ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); - if (flags & ImGuiTabItemFlags_UnsavedDocument) + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Return clipped state ignoring the close button + if (out_text_clipped) { - text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; - ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + IM_FLOOR(-g.FontSize * 0.25f)); - RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x; + //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); } - ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; - // Close Button + const float button_sz = g.FontSize; + const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); + + // Close Button & Unsaved Marker // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() // 'hovered' will be true when hovering the Tab but NOT when hovering the close button // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button @@ -7179,449 +8587,50 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, bool close_button_pressed = false; bool close_button_visible = false; if (close_button_id != 0) - if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == close_button_id) - close_button_visible = true; + if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton)) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id) + close_button_visible = true; + bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); + if (close_button_visible) { - ImGuiItemHoveredDataBackup last_item_backup; - const float close_button_sz = g.FontSize; + ImGuiLastItemData last_item_backup = g.LastItemData; PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); - if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y))) + if (CloseButton(close_button_id, button_pos)) close_button_pressed = true; PopStyleVar(); - last_item_backup.Restore(); + g.LastItemData = last_item_backup; // Close with middle mouse button if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) close_button_pressed = true; - - text_pixel_clip_bb.Max.x -= close_button_sz; } - - float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; - RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); - - return close_button_pressed; -} - - -//------------------------------------------------------------------------- -// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. -// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. -//------------------------------------------------------------------------- -// - GetColumnIndex() -// - GetColumnCount() -// - GetColumnOffset() -// - GetColumnWidth() -// - SetColumnOffset() -// - SetColumnWidth() -// - PushColumnClipRect() [Internal] -// - PushColumnsBackground() [Internal] -// - PopColumnsBackground() [Internal] -// - FindOrCreateColumns() [Internal] -// - GetColumnsID() [Internal] -// - BeginColumns() -// - NextColumn() -// - EndColumns() -// - Columns() -//------------------------------------------------------------------------- - -int ImGui::GetColumnIndex() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; -} - -int ImGui::GetColumnsCount() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; -} - -float ImGui::GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm) -{ - return offset_norm * (columns->OffMaxX - columns->OffMinX); -} - -float ImGui::GetColumnNormFromOffset(const ImGuiColumns* columns, float offset) -{ - return offset / (columns->OffMaxX - columns->OffMinX); -} - -static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; - -static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index) -{ - // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing - // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. - IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); - - float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; - x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); - if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) - x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); - - return x; -} - -float ImGui::GetColumnOffset(int column_index) -{ - ImGuiWindow* window = GetCurrentWindowRead(); - ImGuiColumns* columns = window->DC.CurrentColumns; - if (columns == NULL) - return 0.0f; - - if (column_index < 0) - column_index = columns->Current; - IM_ASSERT(column_index < columns->Columns.Size); - - const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); - return x_offset; -} - -static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false) -{ - if (column_index < 0) - column_index = columns->Current; - - float offset_norm; - if (before_resize) - offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; - else - offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; - return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); -} - -float ImGui::GetColumnWidth(int column_index) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiColumns* columns = window->DC.CurrentColumns; - if (columns == NULL) - return GetContentRegionAvail().x; - - if (column_index < 0) - column_index = columns->Current; - return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); -} - -void ImGui::SetColumnOffset(int column_index, float offset) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiColumns* columns = window->DC.CurrentColumns; - IM_ASSERT(columns != NULL); - - if (column_index < 0) - column_index = columns->Current; - IM_ASSERT(column_index < columns->Columns.Size); - - const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1); - const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; - - if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); - - if (preserve_width) - SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); -} - -void ImGui::SetColumnWidth(int column_index, float width) -{ - ImGuiWindow* window = GetCurrentWindowRead(); - ImGuiColumns* columns = window->DC.CurrentColumns; - IM_ASSERT(columns != NULL); - - if (column_index < 0) - column_index = columns->Current; - SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); -} - -void ImGui::PushColumnClipRect(int column_index) -{ - ImGuiWindow* window = GetCurrentWindowRead(); - ImGuiColumns* columns = window->DC.CurrentColumns; - if (column_index < 0) - column_index = columns->Current; - - ImGuiColumnData* column = &columns->Columns[column_index]; - PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); -} - -// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) -void ImGui::PushColumnsBackground() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - ImGuiColumns* columns = window->DC.CurrentColumns; - if (columns->Count == 1) - return; - window->DrawList->ChannelsSetCurrent(0); - int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); - IM_UNUSED(cmd_size); - IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd -} - -void ImGui::PopColumnsBackground() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - ImGuiColumns* columns = window->DC.CurrentColumns; - if (columns->Count == 1) - return; - window->DrawList->ChannelsSetCurrent(columns->Current + 1); - PopClipRect(); -} - -ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) -{ - // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. - for (int n = 0; n < window->ColumnsStorage.Size; n++) - if (window->ColumnsStorage[n].ID == id) - return &window->ColumnsStorage[n]; - - window->ColumnsStorage.push_back(ImGuiColumns()); - ImGuiColumns* columns = &window->ColumnsStorage.back(); - columns->ID = id; - return columns; -} - -ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) -{ - ImGuiWindow* window = GetCurrentWindow(); - - // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. - // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. - PushID(0x11223347 + (str_id ? 0 : columns_count)); - ImGuiID id = window->GetID(str_id ? str_id : "columns"); - PopID(); - - return id; -} - -void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - - IM_ASSERT(columns_count >= 1); - IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - - // Acquire storage for the columns set - ImGuiID id = GetColumnsID(str_id, columns_count); - ImGuiColumns* columns = FindOrCreateColumns(window, id); - IM_ASSERT(columns->ID == id); - columns->Current = 0; - columns->Count = columns_count; - columns->Flags = flags; - window->DC.CurrentColumns = columns; - - columns->HostCursorPosY = window->DC.CursorPos.y; - columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->HostClipRect = window->ClipRect; - columns->HostWorkRect = window->WorkRect; - - // Set state for first column - // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect - const float column_padding = g.Style.ItemSpacing.x; - const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); - const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); - const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; - columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); - columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); - columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; - - // Clear data if columns count changed - if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) - columns->Columns.resize(0); - - // Initialize default widths - columns->IsFirstFrame = (columns->Columns.Size == 0); - if (columns->Columns.Size == 0) - { - columns->Columns.reserve(columns_count + 1); - for (int n = 0; n < columns_count + 1; n++) - { - ImGuiColumnData column; - column.OffsetNorm = n / (float)columns_count; - columns->Columns.push_back(column); - } - } - - for (int n = 0; n < columns_count; n++) - { - // Compute clipping rectangle - ImGuiColumnData* column = &columns->Columns[n]; - float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); - float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); - column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); - column->ClipRect.ClipWith(window->ClipRect); - } - - if (columns->Count > 1) + else if (unsaved_marker_visible) { - window->DrawList->ChannelsSplit(1 + columns->Count); - window->DrawList->ChannelsSetCurrent(1); - PushColumnClipRect(0); + const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f); + RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); } - // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. - float offset_0 = GetColumnOffset(columns->Current); - float offset_1 = GetColumnOffset(columns->Current + 1); - float width = offset_1 - offset_0; - PushItemWidth(width * 0.65f); - window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); - window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); - window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; -} - -void ImGui::NextColumn() -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems || window->DC.CurrentColumns == NULL) - return; - - ImGuiContext& g = *GImGui; - ImGuiColumns* columns = window->DC.CurrentColumns; - - if (columns->Count == 1) - { - window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); - IM_ASSERT(columns->Current == 0); - return; - } - PopItemWidth(); - PopClipRect(); - - const float column_padding = g.Style.ItemSpacing.x; - columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); - if (++columns->Current < columns->Count) - { - // Columns 1+ ignore IndentX (by canceling it out) - // FIXME-COLUMNS: Unnecessary, could be locked? - window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; - window->DrawList->ChannelsSetCurrent(columns->Current + 1); - } - else - { - // New row/line - // Column 0 honor IndentX - window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); - window->DrawList->ChannelsSetCurrent(1); - columns->Current = 0; - columns->LineMinY = columns->LineMaxY; - } - window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); - window->DC.CursorPos.y = columns->LineMinY; - window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); - window->DC.CurrLineTextBaseOffset = 0.0f; - - PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite? - - // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. - float offset_0 = GetColumnOffset(columns->Current); - float offset_1 = GetColumnOffset(columns->Current + 1); - float width = offset_1 - offset_0; - PushItemWidth(width * 0.65f); - window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; -} - -void ImGui::EndColumns() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - ImGuiColumns* columns = window->DC.CurrentColumns; - IM_ASSERT(columns != NULL); - - PopItemWidth(); - if (columns->Count > 1) + // This is all rather complicated + // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) + // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + if (close_button_visible || unsaved_marker_visible) { - PopClipRect(); - window->DrawList->ChannelsMerge(); + text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); + text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; + ellipsis_max_x = text_pixel_clip_bb.Max.x; } + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); - const ImGuiColumnsFlags flags = columns->Flags; - columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); - window->DC.CursorPos.y = columns->LineMaxY; - if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent - - // Draw columns borders and handle resize - // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy - bool is_being_resized = false; - if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) - { - // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); - const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); - int dragging_column = -1; - for (int n = 1; n < columns->Count; n++) - { - ImGuiColumnData* column = &columns->Columns[n]; - float x = window->Pos.x + GetColumnOffset(n); - const ImGuiID column_id = columns->ID + ImGuiID(n); - const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; - const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); - KeepAliveID(column_id); - if (IsClippedEx(column_hit_rect, column_id, false)) - continue; - - bool hovered = false, held = false; - if (!(flags & ImGuiColumnsFlags_NoResize)) - { - ButtonBehavior(column_hit_rect, column_id, &hovered, &held); - if (hovered || held) - g.MouseCursor = ImGuiMouseCursor_ResizeEW; - if (held && !(column->Flags & ImGuiColumnsFlags_NoResize)) - dragging_column = n; - } - - // Draw column - const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); - const float xi = IM_FLOOR(x); - window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); - } - - // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. - if (dragging_column != -1) - { - if (!columns->IsBeingResized) - for (int n = 0; n < columns->Count + 1; n++) - columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; - columns->IsBeingResized = is_being_resized = true; - float x = GetDraggedColumnOffset(columns, dragging_column); - SetColumnOffset(dragging_column, x); - } - } - columns->IsBeingResized = is_being_resized; +#if 0 + if (!is_contents_visible) + g.Style.Alpha = backup_alpha; +#endif - window->WorkRect = columns->HostWorkRect; - window->DC.CurrentColumns = NULL; - window->DC.ColumnsOffset.x = 0.0f; - window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + if (out_just_closed) + *out_just_closed = close_button_pressed; } -// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] -void ImGui::Columns(int columns_count, const char* id, bool border) -{ - ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(columns_count >= 1); - - ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); - //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior - ImGuiColumns* columns = window->DC.CurrentColumns; - if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) - return; - if (columns != NULL) - EndColumns(); - - if (columns_count != 1) - BeginColumns(id, columns_count, flags); -} - -//------------------------------------------------------------------------- +#endif // #ifndef IMGUI_DISABLE diff --git a/src/ui/imguiLib/imstb_rectpack.h b/src/ui/imguiLib/imstb_rectpack.h index ff2a85df4..f6917e7a6 100644 --- a/src/ui/imguiLib/imstb_rectpack.h +++ b/src/ui/imguiLib/imstb_rectpack.h @@ -1,15 +1,19 @@ // [DEAR IMGUI] -// This is a slightly modified version of stb_rect_pack.h 1.00. -// Those changes would need to be pushed into nothings/stb: -// - Added STBRP__CDECL +// This is a slightly modified version of stb_rect_pack.h 1.01. // Grep for [DEAR IMGUI] to find the changes. - -// stb_rect_pack.h - v1.00 - public domain - rectangle packing +// +// stb_rect_pack.h - v1.01 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. // Does not do rotation. // +// Before #including, +// +// #define STB_RECT_PACK_IMPLEMENTATION +// +// in the file that you want to have the implementation. +// // Not necessarily the awesomest packing method, but better than // the totally naive one in stb_truetype (which is primarily what // this is meant to replace). @@ -34,13 +38,14 @@ // Minor features // Martins Mozeiko // github:IntellectualKitty -// +// // Bugfixes / warning fixes // Jeremy Jaussaud // Fabian Giesen // // Version history: // +// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles // 0.99 (2019-02-07) warning fixes // 0.11 (2017-03-03) return packing success/fail result @@ -81,11 +86,10 @@ typedef struct stbrp_context stbrp_context; typedef struct stbrp_node stbrp_node; typedef struct stbrp_rect stbrp_rect; -#ifdef STBRP_LARGE_RECTS typedef int stbrp_coord; -#else -typedef unsigned short stbrp_coord; -#endif + +#define STBRP__MAXVAL 0x7fffffff +// Mostly for internal use, but this is the maximum supported coordinate value. STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); // Assign packed locations to rectangles. The rectangles are of type @@ -213,10 +217,9 @@ struct stbrp_context #define STBRP_ASSERT assert #endif -// [DEAR IMGUI] Added STBRP__CDECL #ifdef _MSC_VER #define STBRP__NOTUSED(v) (void)(v) -#define STBRP__CDECL __cdecl +#define STBRP__CDECL __cdecl #else #define STBRP__NOTUSED(v) (void)sizeof(v) #define STBRP__CDECL @@ -262,9 +265,6 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) { int i; -#ifndef STBRP_LARGE_RECTS - STBRP_ASSERT(width <= 0xffff && height <= 0xffff); -#endif for (i=0; i < num_nodes-1; ++i) nodes[i].next = &nodes[i+1]; @@ -283,11 +283,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, context->extra[0].y = 0; context->extra[0].next = &context->extra[1]; context->extra[1].x = (stbrp_coord) width; -#ifdef STBRP_LARGE_RECTS context->extra[1].y = (1<<30); -#else - context->extra[1].y = 65535; -#endif context->extra[1].next = NULL; } @@ -433,7 +429,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt if (y <= best_y) { if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { best_x = xpos; - STBRP_ASSERT(y <= best_y); + //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] best_y = y; best_waste = waste; best = prev; @@ -441,7 +437,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt } } tail = tail->next; - } + } } fr.prev_link = best; @@ -529,7 +525,6 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i return res; } -// [DEAR IMGUI] Added STBRP__CDECL static int STBRP__CDECL rect_height_compare(const void *a, const void *b) { const stbrp_rect *p = (const stbrp_rect *) a; @@ -541,7 +536,6 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b) return (p->w > q->w) ? -1 : (p->w < q->w); } -// [DEAR IMGUI] Added STBRP__CDECL static int STBRP__CDECL rect_original_order(const void *a, const void *b) { const stbrp_rect *p = (const stbrp_rect *) a; @@ -549,12 +543,6 @@ static int STBRP__CDECL rect_original_order(const void *a, const void *b) return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); } -#ifdef STBRP_LARGE_RECTS -#define STBRP__MAXVAL 0xffffffff -#else -#define STBRP__MAXVAL 0xffff -#endif - STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) { int i, all_rects_packed = 1; @@ -602,38 +590,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ diff --git a/src/ui/imguiLib/imstb_textedit.h b/src/ui/imguiLib/imstb_textedit.h index 2077d02ae..a8a823110 100644 --- a/src/ui/imguiLib/imstb_textedit.h +++ b/src/ui/imguiLib/imstb_textedit.h @@ -1,10 +1,11 @@ // [DEAR IMGUI] -// This is a slightly modified version of stb_textedit.h 1.13. +// This is a slightly modified version of stb_textedit.h 1.14. // Those changes would need to be pushed into nothings/stb: // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) +// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000) // Grep for [DEAR IMGUI] to find the changes. -// stb_textedit.h - v1.13 - public domain - Sean Barrett +// stb_textedit.h - v1.14 - public domain - Sean Barrett // Development of this library was sponsored by RAD Game Tools // // This C header file implements the guts of a multi-line text-editing @@ -19,7 +20,7 @@ // texts, as its performance does not scale and it has limited undo). // // Non-trivial behaviors are modelled after Windows text controls. -// +// // // LICENSE // @@ -35,6 +36,7 @@ // // VERSION HISTORY // +// 1.14 (2021-07-11) page up/down, various fixes // 1.13 (2019-02-07) fix bug in undo size management // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield @@ -58,6 +60,7 @@ // Ulf Winklemann: move-by-word in 1.1 // Fabian Giesen: secondary key inputs in 1.5 // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 +// Louis Schnellbach: page up/down in 1.14 // // Bugfixes: // Scott Graham @@ -93,8 +96,8 @@ // moderate sizes. The undo system does no memory allocations, so // it grows STB_TexteditState by the worst-case storage which is (in bytes): // -// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT -// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT +// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATECOUNT +// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHARCOUNT // // // Implementation mode: @@ -148,6 +151,8 @@ // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right // STB_TEXTEDIT_K_UP keyboard input to move cursor up // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down +// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page +// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME @@ -170,14 +175,10 @@ // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // -// Todo: -// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page -// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page -// // Keyboard input must be encoded as a single integer value; e.g. a character code // and some bitflags that represent shift states. to simplify the interface, SHIFT must // be a bitflag, so we can test the shifted state of cursor movements to allow selection, -// i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. +// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. // // You can encode other things, such as CONTROL or ALT, in additional bits, and // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, @@ -219,20 +220,20 @@ // call this with the mouse x,y on a mouse down; it will update the cursor // and reset the selection start/end to the cursor point. the x,y must // be relative to the text widget, with (0,0) being the top left. -// +// // drag: // call this with the mouse x,y on a mouse drag/up; it will update the // cursor and the selection end point -// +// // cut: // call this to delete the current selection; returns true if there was // one. you should FIRST copy the current selection to the system paste buffer. // (To copy, just copy the current selection out of the string yourself.) -// +// // paste: // call this to paste text at the current cursor point or over the current // selection if there is one. -// +// // key: // call this for keyboard inputs sent to the textfield. you can use it // for "key down" events or for "translated" key events. if you need to @@ -243,7 +244,7 @@ // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to // anything other type you wante before including. // -// +// // When rendering, you can read the cursor position and selection state from // the STB_TexteditState. // @@ -337,6 +338,10 @@ typedef struct // each textfield keeps its own insert mode state. to keep an app-wide // insert mode, copy this value in/out of the app state + int row_count_per_page; + // page size in number of row. + // this value MUST be set to >0 for pageup or pagedown in multilines documents. + ///////////////////// // // private data @@ -520,29 +525,14 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s int z = STB_TEXTEDIT_STRINGLEN(str); int i=0, first; - if (n == z) { - // if it's at the end, then find the last line -- simpler than trying to - // explicitly handle this case in the regular code - if (single_line) { - STB_TEXTEDIT_LAYOUTROW(&r, str, 0); - find->y = 0; - find->first_char = 0; - find->length = z; - find->height = r.ymax - r.ymin; - find->x = r.x1; - } else { - find->y = 0; - find->x = 0; - find->height = 1; - while (i < z) { - STB_TEXTEDIT_LAYOUTROW(&r, str, i); - prev_start = i; - i += r.num_chars; - } - find->first_char = i; - find->length = 0; - find->prev_first = prev_start; - } + if (n == z && single_line) { + // special case if it's at the end (may not be needed?) + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + find->y = 0; + find->first_char = 0; + find->length = z; + find->height = r.ymax - r.ymin; + find->x = r.x1; return; } @@ -553,9 +543,13 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s STB_TEXTEDIT_LAYOUTROW(&r, str, i); if (n < i + r.num_chars) break; + if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line + break; // [DEAR IMGUI] prev_start = i; i += r.num_chars; find->y += r.baseline_y_delta; + if (i == z) // [DEAR IMGUI] + break; // [DEAR IMGUI] } find->first_char = first = i; @@ -714,9 +708,7 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta state->has_preferred_x = 0; return 1; } - // remove the undo since we didn't actually insert the characters - if (state->undostate.undo_point) - --state->undostate.undo_point; + // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) return 0; } @@ -762,7 +754,7 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, state->insert_mode = !state->insert_mode; break; #endif - + case STB_TEXTEDIT_K_UNDO: stb_text_undo(str, state); state->has_preferred_x = 0; @@ -777,7 +769,7 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, // if currently there's a selection, move cursor to start of selection if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_first(state); - else + else if (state->cursor > 0) --state->cursor; state->has_preferred_x = 0; @@ -826,7 +818,7 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, #ifdef STB_TEXTEDIT_MOVEWORDRIGHT case STB_TEXTEDIT_K_WORDRIGHT: - if (STB_TEXT_HAS_SELECTION(state)) + if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_last(str, state); else { state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); @@ -855,12 +847,16 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, break; case STB_TEXTEDIT_K_DOWN: - case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { + case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGDOWN: + case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { StbFindState find; StbTexteditRow row; - int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; + int row_count = is_page ? state->row_count_per_page : 1; - if (state->single_line) { + if (!is_page && state->single_line) { // on windows, up&down in single-line behave like left&right key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); goto retry; @@ -869,17 +865,25 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, if (sel) stb_textedit_prep_selection_at_cursor(state); else if (STB_TEXT_HAS_SELECTION(state)) - stb_textedit_move_to_last(str,state); + stb_textedit_move_to_last(str, state); // compute current position of cursor point stb_textedit_clamp(str, state); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - // now find character position down a row - if (find.length) { - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - float x; + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; int start = find.first_char + find.length; + + if (find.length == 0) + break; + + // [DEAR IMGUI] + // going down while being on the last line shouldn't bring us to that line end + if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) + break; + + // now find character position down a row state->cursor = start; STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); x = row.x0; @@ -901,17 +905,25 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, if (sel) state->select_end = state->cursor; + + // go to next line + find.first_char = find.first_char + find.length; + find.length = row.num_chars; } break; } - + case STB_TEXTEDIT_K_UP: - case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { + case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGUP: + case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { StbFindState find; StbTexteditRow row; - int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; + int row_count = is_page ? state->row_count_per_page : 1; - if (state->single_line) { + if (!is_page && state->single_line) { // on windows, up&down become left&right key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); goto retry; @@ -926,11 +938,14 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, stb_textedit_clamp(str, state); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - // can only go up if there's a previous row - if (find.prev_first != find.first_char) { + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; + + // can only go up if there's a previous row + if (find.prev_first == find.first_char) + break; + // now find character position up a row - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - float x; state->cursor = find.prev_first; STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); x = row.x0; @@ -952,6 +967,14 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, if (sel) state->select_end = state->cursor; + + // go to previous line + // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) + prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; + while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) + --prev_scan; + find.first_char = find.prev_first; + find.prev_first = prev_scan; } break; } @@ -981,7 +1004,7 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, } state->has_preferred_x = 0; break; - + #ifdef STB_TEXTEDIT_K_TEXTSTART2 case STB_TEXTEDIT_K_TEXTSTART2: #endif @@ -998,7 +1021,7 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, state->select_start = state->select_end = 0; state->has_preferred_x = 0; break; - + #ifdef STB_TEXTEDIT_K_TEXTSTART2 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: #endif @@ -1075,10 +1098,6 @@ static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, state->has_preferred_x = 0; break; } - -// @TODO: -// STB_TEXTEDIT_K_PGUP - move cursor up a page -// STB_TEXTEDIT_K_PGDOWN - move cursor down a page } } @@ -1134,7 +1153,7 @@ static void stb_textedit_discard_redo(StbUndoState *state) state->undo_rec[i].char_storage += n; } // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' - // {DEAR IMGUI] + // [DEAR IMGUI] size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; @@ -1350,6 +1369,7 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin state->initialized = 1; state->single_line = (unsigned char) is_single_line; state->insert_mode = 0; + state->row_count_per_page = 0; } // API initialize @@ -1380,38 +1400,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ diff --git a/src/ui/imguiLib/imstb_truetype.h b/src/ui/imguiLib/imstb_truetype.h index 193338afb..35c827e6b 100644 --- a/src/ui/imguiLib/imstb_truetype.h +++ b/src/ui/imguiLib/imstb_truetype.h @@ -1,10 +1,19 @@ // [DEAR IMGUI] -// This is a slightly modified version of stb_truetype.h 1.20. +// This is a slightly modified version of stb_truetype.h 1.26. // Mostly fixing for compiler and static analyzer warnings. // Grep for [DEAR IMGUI] to find the changes. -// stb_truetype.h - v1.20 - public domain -// authored from 2009-2016 by Sean Barrett / RAD Game Tools +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= // // This library processes TrueType files: // parse files @@ -37,11 +46,11 @@ // Daniel Ribeiro Maciel // // Bug/warning reports/fixes: -// "Zer" on mollyrocket Fabian "ryg" Giesen -// Cass Everitt Martins Mozeiko -// stoiko (Haemimont Games) Cap Petschulat -// Brian Hook Omar Cornut -// Walter van Niftrik github:aloucks +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege // David Gow Peter LaValle // David Given Sergey Popov // Ivan-Assen Ivanov Giumo X. Clanjor @@ -49,11 +58,17 @@ // Johan Duparc Thomas Fields // Hou Qiming Derek Vinyard // Rob Loach Cort Stratton -// Kenney Phillis Jr. github:oyvindjam -// Brian Costabile github:vassvik -// +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) +// // VERSION HISTORY // +// 1.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod // 1.18 (2018-01-29) add missing function @@ -212,7 +227,7 @@ // // Advancing for the next character: // Call GlyphHMetrics, and compute 'current_point += SF * advance'. -// +// // // ADVANCED USAGE // @@ -248,19 +263,6 @@ // recommend it. // // -// SOURCE STATISTICS (based on v0.6c, 2050 LOC) -// -// Documentation & header file 520 LOC \___ 660 LOC documentation -// Sample code 140 LOC / -// Truetype parsing 620 LOC ---- 620 LOC TrueType -// Software rasterization 240 LOC \. -// Curve tessellation 120 LOC \__ 550 LOC Bitmap creation -// Bitmap management 100 LOC / -// Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 -// C runtime library abstraction 60 LOC ---- 60 -// -// // PERFORMANCE MEASUREMENTS FOR 1.06: // // 32-bit 64-bit @@ -275,8 +277,8 @@ //// SAMPLE PROGRAMS //// // -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless -// +// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. +// See "tests/truetype_demo_win32.c" for a complete version. #if 0 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" @@ -302,6 +304,8 @@ void my_stbtt_initfont(void) void my_stbtt_print(float x, float y, char *text) { // assume orthographic projection with units = screen pixels, origin at top left + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, ftex); glBegin(GL_QUADS); @@ -309,10 +313,10 @@ void my_stbtt_print(float x, float y, char *text) if (*text >= 32 && *text < 128) { stbtt_aligned_quad q; stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); } ++text; } @@ -350,7 +354,7 @@ int main(int argc, char **argv) } return 0; } -#endif +#endif // // Output: // @@ -364,9 +368,9 @@ int main(int argc, char **argv) // :@@. M@M // @@@o@@@@ // :M@@V:@@. -// +// ////////////////////////////////////////////////////////////////////////////// -// +// // Complete program: print "Hello World!" banner, with bugs // #if 0 @@ -667,7 +671,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look -// at the source to of stbtt_PackFontRanges() and create a custom version +// at the source to of stbtt_PackFontRanges() and create a custom version // using these functions, e.g. call GatherRects multiple times, // building up a single array of rects, then call PackRects once, // then call RenderIntoRects repeatedly. This may result in a @@ -719,7 +723,7 @@ struct stbtt_fontinfo int numGlyphs; // number of glyphs, needed for range checking - int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf int index_map; // a cmap mapping for our chosen character encoding int indexToLocFormat; // format needed to map from glyph index to glyph @@ -802,6 +806,18 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); // as above, but takes one or more glyph indices for greater efficiency +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) ////////////////////////////////////////////////////////////////////////////// // @@ -846,6 +862,12 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); // frees the data allocated above +STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + ////////////////////////////////////////////////////////////////////////////// // // BITMAP RENDERING @@ -975,7 +997,7 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // and computing from that can allow drop-out prevention). // // The algorithm has not been optimized at all, so expect it to be slow -// if computing lots of characters or very large sizes. +// if computing lots of characters or very large sizes. @@ -1347,6 +1369,22 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) return stbtt__cff_get_index(&cff); } +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) { stbtt_uint32 cmap, t; @@ -1426,6 +1464,8 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in else info->numGlyphs = 0xffff; + info->svg = -1; + // find a cmap encoding table we understand *now* to avoid searching // later. (todo: could make this installable) // the same regardless of glyph. @@ -1509,12 +1549,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep search += 2; { - stbtt_uint16 offset, start; + stbtt_uint16 offset, start, last; stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) return 0; offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); @@ -1732,7 +1772,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s if (i != 0) num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - // now start the new one + // now start the new one start_off = !(flags & 1); if (start_off) { // if we start off with an off-curve point, then when we need to find a point on the curve @@ -1774,7 +1814,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s } } num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { + } else if (numberOfContours < 0) { // Compound shapes. int more = 1; stbtt_uint8 *comp = data + g + 10; @@ -1785,7 +1825,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s int comp_num_verts = 0, i; stbtt_vertex *comp_verts = 0, *tmp = 0; float mtx[6] = {1,0,0,1,0,0}, m, n; - + flags = ttSHORT(comp); comp+=2; gidx = ttSHORT(comp); comp+=2; @@ -1815,7 +1855,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; } - + // Find transformation scales. m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); @@ -1841,7 +1881,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s if (comp_verts) STBTT_free(comp_verts, info->userdata); return 0; } - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 + if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); if (vertices) STBTT_free(vertices, info->userdata); vertices = tmp; @@ -1851,9 +1891,6 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s // More components ? more = flags & (1<<5); } - } else if (numberOfContours < 0) { - // @TODO other compound variations? - STBTT_assert(0); } else { // numberOfCounters == 0, do nothing } @@ -1971,7 +2008,7 @@ static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int gly start = end; } } - if (fdselector == -1) stbtt__new_buf(NULL, 0); + if (fdselector == -1) return stbtt__new_buf(NULL, 0); // [DEAR IMGUI] fixed, see #6007 and nothings/stb#1422 return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); } @@ -2107,7 +2144,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); has_subrs = 1; } - // fallthrough + // FALLTHROUGH case 0x1D: // callgsubr if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); v = (int) s[--sp]; @@ -2212,7 +2249,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st } break; default: - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 + if (b0 != 255 && b0 != 28 && b0 < 32) return STBTT__CSERR("reserved operator"); // push immediate @@ -2282,7 +2319,49 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde } } -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) { stbtt_uint8 *data = info->data + info->kern; stbtt_uint32 needle, straw; @@ -2312,245 +2391,225 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph return 0; } -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) -{ - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch(coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); - - // Binary search. - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { - stbtt_uint8 *glyphArray = coverageTable + 4; - stbtt_uint16 glyphID; - m = (l + r) >> 1; - glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - return m; - } +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; } - } break; - - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; - - // Binary search. - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; - rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; - } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; } - } break; + } + break; + } - default: { - // There are no other cases. - STBTT_assert(0); - } break; - } + default: return -1; // unsupported + } - return -1; + return -1; } static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) { - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch(classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - - // [DEAR IMGUI] Commented to fix static analyzer warning - //classDefTable = classDef1ValueArray + 2 * glyphCount; - } break; - - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; - - // Binary search. - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; - classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } - // [DEAR IMGUI] Commented to fix static analyzer warning - //classDefTable = classRangeRecords + 6 * classRangeCount; - } break; + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } - default: { - // There are no other cases. - STBTT_assert(0); - } break; - } + default: + return -1; // Unsupported definition type, return an error. + } - return -1; + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; } // Define to STBTT_assert(x) if you want to break on unimplemented formats. #define STBTT_GPOS_TODO_assert(x) -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i; - - if (!info->gpos) return 0; - - data = info->data + info->gpos; - - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 - - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); - - for (i=0; i> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } break; - - case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - STBTT_assert(glyph1class < class1Count); - STBTT_assert(glyph2class < class2Count); - - // TODO: Support more formats. - STBTT_GPOS_TODO_assert(valueFormat1 == 4); - if (valueFormat1 != 4) return 0; - STBTT_GPOS_TODO_assert(valueFormat2 == 0); - if (valueFormat2 != 0) return 0; - - if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { - stbtt_uint8 *class1Records = table + 16; - stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); - stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } - } break; - - default: { - // There are no other cases. - STBTT_assert(0); - break; - }; - } - } - break; - }; +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } default: - // TODO: Implement other stuff. - break; - } - } + return 0; // Unsupported position format + } + } + } - return 0; + return 0; } STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) @@ -2559,8 +2618,7 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int if (info->gpos) xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); - - if (info->kern) + else if (info->kern) xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); return xAdvance; @@ -2621,6 +2679,45 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) STBTT_free(v, info->userdata); } +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + ////////////////////////////////////////////////////////////////////////////// // // antialiasing software rasterizer @@ -2746,7 +2843,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); STBTT_assert(z != NULL); if (!z) return z; - + // round dx down to avoid overshooting if (dxdy < 0) z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); @@ -2824,7 +2921,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac } } } - + e = e->next; } } @@ -2970,6 +3067,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg } } +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) { float y_bottom = y_top+1; @@ -3024,13 +3138,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, float height; // simple case, only spans one pixel int x = (int) x_top; - height = sy1 - sy0; + height = (sy1 - sy0) * e->direction; STBTT_assert(x >= 0 && x < len); - scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; - scanline_fill[x] += e->direction * height; // everything right of this pixel is filled + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled } else { int x,x1,x2; - float y_crossing, step, sign, area; + float y_crossing, y_final, step, sign, area; // covers 2+ pixels if (x_top > x_bottom) { // flip scanline vertically; signed area is the same @@ -3042,32 +3156,83 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, dx = -dx; dy = -dy; t = x0, x0 = xb, xb = t; - // [DEAR IMGUI] Fix static analyzer warning - (void)dx; // [ImGui: fix static analyzer warning] } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); x1 = (int) x_top; x2 = (int) x_bottom; // compute intersection with y axis at x1+1 - y_crossing = (x1+1 - x0) * dy + y_top; + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; sign = e->direction; - // area of the rectangle covered from y0..y_crossing + + // area of the rectangle covered from sy0..y_crossing area = sign * (y_crossing-sy0); - // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) - scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); - step = sign * dy; + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + int denom = (x2 - (x1+1)); + y_final = y_bottom; + if (denom != 0) { // [DEAR IMGUI] Avoid div by zero (https://github.com/nothings/stb/issues/1316) + dy = (y_final - y_crossing ) / denom; // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 area += step; } - y_crossing += dy * (x2 - (x1+1)); + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); - STBTT_assert(STBTT_fabs(area) <= 1.01f); - - scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + // the rest of the line is filled based on the total height of the line segment in this pixel scanline_fill[x2] += sign * (sy1-sy0); } } else { @@ -3075,6 +3240,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, // clipping logic. since this does not match the intended use // of this library, we use a different, very slow brute // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box int x; for (x=0; x < len; ++x) { // cases: @@ -3554,7 +3722,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info { int ix0,iy0,ix1,iy1; stbtt__bitmap gbm; - stbtt_vertex *vertices; + stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); if (scale_x == 0) scale_x = scale_y; @@ -3577,7 +3745,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info if (height) *height = gbm.h; if (xoff ) *xoff = ix0; if (yoff ) *yoff = iy0; - + if (gbm.w && gbm.h) { gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); if (gbm.pixels) { @@ -3588,7 +3756,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info } STBTT_free(vertices, info->userdata); return gbm.pixels; -} +} STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) { @@ -3600,7 +3768,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigne int ix0,iy0; stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; + stbtt__bitmap gbm; stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); gbm.pixels = output; @@ -3622,7 +3790,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char * STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) { @@ -3637,7 +3805,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) { @@ -3762,7 +3930,7 @@ static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *no con->y = 0; con->bottom_y = 0; STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); + STBTT__NOTUSED(num_nodes); } static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) @@ -3989,6 +4157,7 @@ static float stbtt__oversample_shift(int oversample) STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { int i,j,k; + int missing_glyph_added = 0; k=0; for (i=0; i < num_ranges; ++i) { @@ -4000,7 +4169,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb int x0,y0,x1,y1; int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; int glyph = stbtt_FindGlyphIndex(info, codepoint); - if (glyph == 0 && spc->skip_missing) { + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { rects[k].w = rects[k].h = 0; } else { stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, @@ -4010,6 +4179,8 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb &x0,&y0,&x1,&y1); rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; } ++k; } @@ -4044,7 +4215,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info // rects array must be big enough to accommodate all characters in the given ranges STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { - int i,j,k, return_value = 1; + int i,j,k, missing_glyph = -1, return_value = 1; // save current values int old_h_over = spc->h_oversample; @@ -4109,6 +4280,13 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const bc->yoff = (float) y0 * recip_v + sub_y; bc->xoff2 = (x0 + r->w) * recip_h + sub_x; bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; } else { return_value = 0; // if any fail, report failure } @@ -4132,7 +4310,7 @@ STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) { stbtt_fontinfo info; - int i,j,n, return_value = 1; + int i, j, n, return_value; // [DEAR IMGUI] removed = 1; //stbrp_context *context = (stbrp_context *) spc->pack_info; stbrp_rect *rects; @@ -4147,7 +4325,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char n = 0; for (i=0; i < num_ranges; ++i) n += ranges[i].num_chars; - + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); if (rects == NULL) return 0; @@ -4158,7 +4336,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); stbtt_PackFontRangesPackRects(spc, rects, n); - + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); STBTT_free(rects, spc->user_allocator_context); @@ -4301,15 +4479,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex float y_frac; int winding = 0; - orig[0] = x; - //orig[1] = y; // [DEAR IMGUI] commmented double assignment - // make sure y never passes through a vertex of the shape y_frac = (float) STBTT_fmod(y, 1.0f); if (y_frac < 0.01f) y += 0.01f; else if (y_frac > 0.99f) y -= 0.01f; + + orig[0] = x; orig[1] = y; // test a ray from (-infinity,y) to (x,y) @@ -4319,7 +4496,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) + if (x_inter < x) winding += (y0 < y1) ? 1 : -1; } } @@ -4345,7 +4522,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex y1 = (int)verts[i ].y; if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) + if (x_inter < x) winding += (y0 < y1) ? 1 : -1; } } else { @@ -4357,7 +4534,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex if (hits[1][0] < 0) winding += (hits[1][1] < 0 ? -1 : 1); } - } + } } } return winding; @@ -4371,35 +4548,35 @@ static float stbtt__cuberoot( float x ) return (float) STBTT_pow( x,1.0f/3.0f); } -// x^3 + c*x^2 + b*x + a = 0 +// x^3 + a*x^2 + b*x + c = 0 static int stbtt__solve_cubic(float a, float b, float c, float* r) { - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; + return 3; } } @@ -4410,12 +4587,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc int w,h; unsigned char *data; - // if one scale is 0, use same scale for both - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) return NULL; // if both scales are 0, return NULL - scale_y = scale_x; - } + if (scale == 0) return NULL; stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); @@ -4438,7 +4610,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc // invert for y-downwards bitmaps scale_y = -scale_y; - + { int x,y,i,j; float *precompute; @@ -4481,18 +4653,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc for (i=0; i < num_verts; ++i) { float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve - float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (verts[i].type == STBTT_vline) { + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + // coarse culling against bbox //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; STBTT_assert(i != 0); if (dist < min_dist) { // check position along line @@ -4519,7 +4690,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc float ax = x1-x0, ay = y1-y0; float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; float mx = x0 - sx, my = y0 - sy; - float res[3],px,py,t,it; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; float a_inv = precompute[i]; if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula float a = 3*(ax*bx + ay*by); @@ -4546,6 +4718,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc float d = (mx*ax+my*ay) * a_inv; num = stbtt__solve_cubic(b, c, d, res); } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { t = res[0], it = 1.0f - t; px = it*it*x0 + 2*t*it*x1 + t*t*x2; @@ -4587,7 +4763,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc STBTT_free(verts, info->userdata); } return data; -} +} STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) { @@ -4605,7 +4781,7 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) // // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) { stbtt_int32 i=0; @@ -4644,7 +4820,7 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, s return i; } -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) { return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); } @@ -4773,7 +4949,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) { - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); } STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) @@ -4805,6 +4981,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const // FULL VERSION HISTORY // +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod // 1.18 (2018-01-29) add missing function // 1.17 (2017-07-23) make more arguments const; doc fix @@ -4866,38 +5048,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ From 5828d5499092faea53fa553985917abe6cda33c9 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 3 Jun 2023 02:59:48 +0300 Subject: [PATCH 080/212] changes backported, imgui updated --- CMakeLists.txt | 1 + src/ui/FrontendUI.cpp | 2 +- .../disablableButton/disablableButton.cpp | 2 +- src/ui/imguiLib/fileBrowser/imfilebrowser.h | 7 +- src/ui/imguiLib/groupPanel/groupPanel.cpp | 7 +- src/ui/imguiLib/groupPanel/groupPanel.h | 3 + src/ui/imguiLib/imageButton2/imageButton2.cpp | 3 - src/ui/imguiLib/imageButton2/imageButton2.h | 3 + src/ui/imguiLib/imgui.cpp | 40 +- src/ui/imguiLib/imgui.h | 9 + src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp | 4 + src/ui/imguiLib/imgui_internal.h | 8 +- src/ui/imguiLib/imgui_widgets.cpp | 2 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 22 +- src/ui/renderer/uiScene/ImGUIPlan.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- 16 files changed, 581 insertions(+), 550 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2405b206..3673fa2f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,6 +183,7 @@ set(SOURCE_FILES src/ui/imguiLib/imgui_demo.cpp src/ui/imguiLib/imgui_draw.cpp src/ui/imguiLib/imgui_widgets.cpp + src/ui/imguiLib/imgui_tables.cpp src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp src/ui/FrontendUI.cpp src/ui/FrontendUI.h src/database/CSqliteDB.cpp src/database/CSqliteDB.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 47d1d5465..67040c7f6 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -348,7 +348,7 @@ void FrontendUI::showMapSelectionDialog() { //Left panel { //Filter - if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), ImGuiInputTextFlags_AlwaysInsertMode)) { + if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), ImGuiInputTextFlags_AlwaysOverwrite)) { refilterIsNeeded = true; } //The table diff --git a/src/ui/imguiLib/disablableButton/disablableButton.cpp b/src/ui/imguiLib/disablableButton/disablableButton.cpp index 87169a896..020d5b342 100644 --- a/src/ui/imguiLib/disablableButton/disablableButton.cpp +++ b/src/ui/imguiLib/disablableButton/disablableButton.cpp @@ -10,7 +10,7 @@ bool ImGui::ButtonDisablable(const char* label, bool disabled, const struct ImVe bool result; if (disabled) { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.5f,0.5f,0.5f,1.0)); - result = ImGui::ButtonEx(label, size_arg, ImGuiButtonFlags_Disabled); + result = ImGui::ButtonEx(label, size_arg, ImGuiItemFlags_Disabled); ImGui::PopStyleColor(1); } else { result = ImGui::Button(label, size_arg); diff --git a/src/ui/imguiLib/fileBrowser/imfilebrowser.h b/src/ui/imguiLib/fileBrowser/imfilebrowser.h index fd2090eb2..c264dcedd 100644 --- a/src/ui/imguiLib/fileBrowser/imfilebrowser.h +++ b/src/ui/imguiLib/fileBrowser/imfilebrowser.h @@ -434,10 +434,10 @@ inline void ImGui::FileBrowser::Display() // browse files in a child window - float reserveHeight = GetItemsLineHeightWithSpacing(); + float reserveHeight = GetFrameHeightWithSpacing(); ghc::filesystem::path newPwd; bool setNewPwd = false; if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) && (flags_ & ImGuiFileBrowserFlags_EnterNewFilename)) - reserveHeight += GetItemsLineHeightWithSpacing(); + reserveHeight += GetFrameHeightWithSpacing(); { BeginChild("ch", ImVec2(0, -reserveHeight), true, (flags_ & ImGuiFileBrowserFlags_NoModal) ? ImGuiWindowFlags_AlwaysHorizontalScrollbar : 0); @@ -520,9 +520,8 @@ inline void ImGui::FileBrowser::Display() SameLine(); - int escIdx = GetIO().KeyMap[ImGuiKey_Escape]; if(Button("cancel") || closeFlag_ || - ((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) && IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && escIdx >= 0 && IsKeyPressed(escIdx))) + ((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) && IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && IsKeyPressed(ImGuiKey::ImGuiKey_Escape))) CloseCurrentPopup(); if (m_cascOpenMode) { diff --git a/src/ui/imguiLib/groupPanel/groupPanel.cpp b/src/ui/imguiLib/groupPanel/groupPanel.cpp index fcf1ecfcc..ec922533b 100644 --- a/src/ui/imguiLib/groupPanel/groupPanel.cpp +++ b/src/ui/imguiLib/groupPanel/groupPanel.cpp @@ -3,8 +3,8 @@ // #include "groupPanel.h" -#define IMGUI_DEFINE_MATH_OPERATORS -#include "imgui_internal.h" + +#include static ImVector s_GroupPanelLabelStack; @@ -21,8 +21,9 @@ void ImGui::BeginGroupPanel(const char* name, const ImVec2& size) ImGui::BeginGroup(); ImVec2 effectiveSize = size; + auto contentRegionAvailable = ImGui::GetContentRegionAvail(); if (size.x < 0.0f) - effectiveSize.x = ImGui::GetContentRegionAvailWidth(); + effectiveSize.x = contentRegionAvailable.x; else effectiveSize.x = size.x; ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f)); diff --git a/src/ui/imguiLib/groupPanel/groupPanel.h b/src/ui/imguiLib/groupPanel/groupPanel.h index 96c9472cd..a0fdbbf97 100644 --- a/src/ui/imguiLib/groupPanel/groupPanel.h +++ b/src/ui/imguiLib/groupPanel/groupPanel.h @@ -5,6 +5,9 @@ #ifndef AWEBWOWVIEWERCPP_GROUPPANEL_H #define AWEBWOWVIEWERCPP_GROUPPANEL_H +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS 1 +#endif #include namespace ImGui { diff --git a/src/ui/imguiLib/imageButton2/imageButton2.cpp b/src/ui/imguiLib/imageButton2/imageButton2.cpp index 579c50ee0..4e8970b90 100644 --- a/src/ui/imguiLib/imageButton2/imageButton2.cpp +++ b/src/ui/imguiLib/imageButton2/imageButton2.cpp @@ -3,9 +3,6 @@ // #include "imageButton2.h" -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include bool ImGui::ImageButton2(ImTextureID user_texture_id, char *idText, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) diff --git a/src/ui/imguiLib/imageButton2/imageButton2.h b/src/ui/imguiLib/imageButton2/imageButton2.h index f0c31a6f2..0ccff679f 100644 --- a/src/ui/imguiLib/imageButton2/imageButton2.h +++ b/src/ui/imguiLib/imageButton2/imageButton2.h @@ -5,6 +5,9 @@ #ifndef AWEBWOWVIEWERCPP_IMAGEBUTTON2_H #define AWEBWOWVIEWERCPP_IMAGEBUTTON2_H +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS 1 +#endif #include namespace ImGui { diff --git a/src/ui/imguiLib/imgui.cpp b/src/ui/imguiLib/imgui.cpp index 400dcb22b..2cbe9ce10 100644 --- a/src/ui/imguiLib/imgui.cpp +++ b/src/ui/imguiLib/imgui.cpp @@ -3530,10 +3530,16 @@ void ImGui::Initialize() ini_handler.TypeName = "Window"; ini_handler.TypeHash = ImHashStr("Window"); ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; - ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; - ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ReadOpenFn = [](ImGuiContext* g, ImGuiSettingsHandler* gg, const char* name) -> void* { + return WindowSettingsHandler_ReadOpen(g, gg, name); + }; + ini_handler.ReadLineFn = [](ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line) -> void { + WindowSettingsHandler_ReadLine(ctx, handler, entry, line); + }; + ini_handler.WriteAllFn = [](ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) -> void { + WindowSettingsHandler_WriteAll(ctx, handler, buf); + }; ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; - ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; AddSettingsHandler(&ini_handler); } TableSettingsAddSettingsHandler(); @@ -6640,6 +6646,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - BeginTabBar() for right-most edge const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); + //TODO: this was changed in prev version. Check if change is still needed const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); @@ -6816,6 +6823,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) return !window->SkipItems; } +float ImGui::GetWindowContentRegionHeight() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.GetHeight(); +} void ImGui::End() { @@ -12782,15 +12794,17 @@ void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) void ImGui::RemoveSettingsHandler(const char* type_name) { ImGuiContext& g = *GImGui; - if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name)) - g.SettingsHandlers.erase(handler); + if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name)) { + auto index = (handler - g.SettingsHandlers.data()); + g.SettingsHandlers.erase(g.SettingsHandlers.begin() + index); + } } ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) { ImGuiContext& g = *GImGui; const ImGuiID type_hash = ImHashStr(type_name); - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) if (g.SettingsHandlers[handler_n].TypeHash == type_hash) return &g.SettingsHandlers[handler_n]; return NULL; @@ -12801,7 +12815,7 @@ void ImGui::ClearIniSettings() { ImGuiContext& g = *GImGui; g.SettingsIniData.clear(); - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) if (g.SettingsHandlers[handler_n].ClearAllFn) g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); } @@ -12838,7 +12852,7 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) // Call pre-read handlers // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) if (g.SettingsHandlers[handler_n].ReadInitFn) g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); @@ -12884,7 +12898,7 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) memcpy(buf, ini_data, ini_size); // Call post-read handlers - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) if (g.SettingsHandlers[handler_n].ApplyAllFn) g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); } @@ -12912,7 +12926,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) g.SettingsDirtyTimer = 0.0f; g.SettingsIniData.Buf.resize(0); g.SettingsIniData.Buf.push_back(0); - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + for (int handler_n = 0; handler_n < g.SettingsHandlers.size(); handler_n++) { ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; handler->WriteAllFn(&g, handler, &g.SettingsIniData); @@ -13793,9 +13807,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) else TextUnformatted(""); Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); - if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) + if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.size())) { - for (int n = 0; n < g.SettingsHandlers.Size; n++) + for (int n = 0; n < g.SettingsHandlers.size(); n++) BulletText("%s", g.SettingsHandlers[n].TypeName); TreePop(); } @@ -14066,7 +14080,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, char buf[300]; ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", - pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId.get(), pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) diff --git a/src/ui/imguiLib/imgui.h b/src/ui/imguiLib/imgui.h index 8da4ea1b3..bc5c19224 100644 --- a/src/ui/imguiLib/imgui.h +++ b/src/ui/imguiLib/imgui.h @@ -382,6 +382,7 @@ namespace ImGui IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates + IMGUI_API float GetWindowContentRegionHeight(); // Windows Scrolling // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). @@ -508,6 +509,13 @@ namespace ImGui IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer + template + IMGUI_API bool RadioButton(const char* label, T* v, T v_button) { + const bool pressed = RadioButton(label, *v == v_button); + if (pressed) + *v = v_button; + return pressed; + } // shortcut to handle the above pattern when value is an integer IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses @@ -2030,6 +2038,7 @@ struct ImGuiIO int MetricsActiveWindows; // Number of active windows int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + float uiScale = 1.0f; // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). diff --git a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp index 31b22681b..ba1d03107 100644 --- a/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp +++ b/src/ui/imguiLib/imguiImpl/imgui_impl_glfw.cpp @@ -678,6 +678,10 @@ static void ImGui_ImplGlfw_UpdateMouseData() { double mouse_x, mouse_y; glfwGetCursorPos(window, &mouse_x, &mouse_y); + auto uiScale = ImGui::GetIO().uiScale; + mouse_x /= uiScale; + mouse_y /= uiScale; + bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); io.AddMousePosEvent((float)mouse_x, (float)mouse_y); } diff --git a/src/ui/imguiLib/imgui_internal.h b/src/ui/imguiLib/imgui_internal.h index 3311d6595..78f848644 100644 --- a/src/ui/imguiLib/imgui_internal.h +++ b/src/ui/imguiLib/imgui_internal.h @@ -1637,10 +1637,10 @@ struct ImGuiSettingsHandler ImGuiID TypeHash; // == ImHashStr(TypeName) void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) - void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" - void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + std::function ReadOpenFn; // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + std::function ReadLineFn; // Read: Called for every line of text within an ini entry + std::function WriteAllFn; // Write: Output every entries into 'out_buf' void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) - void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' void* UserData; ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } @@ -1996,7 +1996,7 @@ struct ImGuiContext bool SettingsLoaded; float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero ImGuiTextBuffer SettingsIniData; // In memory .ini settings - ImVector SettingsHandlers; // List of .ini settings handlers + std::vector SettingsHandlers; // List of .ini settings handlers ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries ImChunkStream SettingsTables; // ImGuiTable .ini settings entries ImVector Hooks; // Hooks for extensions (e.g. test engine) diff --git a/src/ui/imguiLib/imgui_widgets.cpp b/src/ui/imguiLib/imgui_widgets.cpp index 83f27111b..1b6c8eb18 100644 --- a/src/ui/imguiLib/imgui_widgets.cpp +++ b/src/ui/imguiLib/imgui_widgets.cpp @@ -1089,7 +1089,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I return false; // Default to using texture ID as ID. User can still push string/integer prefixes. - PushID((void*)(intptr_t)user_texture_id); + PushID(user_texture_id.get()); const ImGuiID id = window->GetID("#image"); PopID(); diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index a576488c0..8bd1d4bb6 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -79,13 +79,13 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + if (clip_min.x < fb_width && clip_min.y < fb_height && clip_max.x >= 0.0f && clip_max.y >= 0.0f) { // Apply scissor/clipping rectangle // Create mesh and add it to collected meshes @@ -93,14 +93,14 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrgetIsVulkanAxisSystem()) { - meshTemplate.scissorOffset = {static_cast(clip_rect.x * uiScale), static_cast((fb_height - clip_rect.w)* uiScale)}; - meshTemplate.scissorSize = {static_cast((clip_rect.z - clip_rect.x) * uiScale), static_cast((clip_rect.w - clip_rect.y)* uiScale)}; + meshTemplate.scissorOffset = {static_cast(clip_min.x * uiScale), static_cast((fb_height - clip_max.y)* uiScale)}; + meshTemplate.scissorSize = {static_cast((clip_max.x - clip_min.x) * uiScale), static_cast((clip_max.y - clip_min.y)* uiScale)}; } else { - meshTemplate.scissorOffset = {static_cast(clip_rect.x * uiScale), static_cast((clip_rect.y) * uiScale)}; - meshTemplate.scissorSize = {static_cast((clip_rect.z - clip_rect.x)* uiScale), static_cast((clip_rect.w - clip_rect.y)* uiScale)}; + meshTemplate.scissorOffset = {static_cast(clip_min.x * uiScale), static_cast((clip_min.y) * uiScale)}; + meshTemplate.scissorSize = {static_cast((clip_max.x - clip_min.x)* uiScale), static_cast((clip_max.y - clip_min.y)* uiScale)}; } - meshTemplate.start = pcmd->IdxOffset * 2; + meshTemplate.start = pcmd->IdxOffset * sizeof(ImDrawIdx); meshTemplate.end = pcmd->ElemCount; auto material = pcmd->TextureId; diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index 0ec7796e1..fe266c1c7 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -30,7 +30,7 @@ namespace ImGuiFramePlan { ~ImGUIParam() { if (m_imData.CmdLists != nullptr) { for (int i = 0; i < m_imData.CmdListsCount; i++) { - m_imData.CmdLists[i]->ClearFreeMemory(); + m_imData.CmdLists[i]->~ImDrawList(); IM_FREE(m_imData.CmdLists[i]); } delete m_imData.CmdLists; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 4aac3c3cf..d2f5ac48a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +430,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,19 +499,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,13 +633,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +814,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -877,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,96}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,21 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,13 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {1,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,21 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {0,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,11 +1524,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,16 +1543,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,10 +1585,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1612,21 +1623,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1984,13 +1954,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2006,23 +1990,29 @@ const std::unordered_map Date: Sun, 4 Jun 2023 23:31:26 +0300 Subject: [PATCH 081/212] missing imgui file --- src/ui/imguiLib/imgui_tables.cpp | 4114 ++++++++++++++++++++++++++++++ 1 file changed, 4114 insertions(+) create mode 100644 src/ui/imguiLib/imgui_tables.cpp diff --git a/src/ui/imguiLib/imgui_tables.cpp b/src/ui/imguiLib/imgui_tables.cpp new file mode 100644 index 000000000..8850094de --- /dev/null +++ b/src/ui/imguiLib/imgui_tables.cpp @@ -0,0 +1,4114 @@ +// dear imgui, v1.89.6 +// (tables and columns code) + +/* + +Index of this file: + +// [SECTION] Commentary +// [SECTION] Header mess +// [SECTION] Tables: Main code +// [SECTION] Tables: Simple accessors +// [SECTION] Tables: Row changes +// [SECTION] Tables: Columns changes +// [SECTION] Tables: Columns width management +// [SECTION] Tables: Drawing +// [SECTION] Tables: Sorting +// [SECTION] Tables: Headers +// [SECTION] Tables: Context Menu +// [SECTION] Tables: Settings (.ini data) +// [SECTION] Tables: Garbage Collection +// [SECTION] Tables: Debugging +// [SECTION] Columns, BeginColumns, EndColumns, etc. + +*/ + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + +//----------------------------------------------------------------------------- +// [SECTION] Commentary +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typical tables call flow: (root level is generally public API): +//----------------------------------------------------------------------------- +// - BeginTable() user begin into a table +// | BeginChild() - (if ScrollX/ScrollY is set) +// | TableBeginInitMemory() - first time table is used +// | TableResetSettings() - on settings reset +// | TableLoadSettings() - on settings load +// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests +// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) +// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width +// - TableSetupColumn() user submit columns details (optional) +// - TableSetupScrollFreeze() user submit scroll freeze information (optional) +//----------------------------------------------------------------------------- +// - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). +// | TableSetupDrawChannels() - setup ImDrawList channels +// | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission +// | TableDrawContextMenu() - draw right-click context menu +//----------------------------------------------------------------------------- +// - TableHeadersRow() or TableHeader() user submit a headers row (optional) +// | TableSortSpecsClickColumn() - when left-clicked: alter sort order and sort direction +// | TableOpenContextMenu() - when right-clicked: trigger opening of the default context menu +// - TableGetSortSpecs() user queries updated sort specs (optional, generally after submitting headers) +// - TableNextRow() user begin into a new row (also automatically called by TableHeadersRow()) +// | TableEndRow() - finish existing row +// | TableBeginRow() - add a new row +// - TableSetColumnIndex() / TableNextColumn() user begin into a cell +// | TableEndCell() - close existing column/cell +// | TableBeginCell() - enter into current column/cell +// - [...] user emit contents +//----------------------------------------------------------------------------- +// - EndTable() user ends the table +// | TableDrawBorders() - draw outer borders, inner vertical borders +// | TableMergeDrawChannels() - merge draw channels if clipping isn't required +// | EndChild() - (if ScrollX/ScrollY is set) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// TABLE SIZING +//----------------------------------------------------------------------------- +// (Read carefully because this is subtle but it does make sense!) +//----------------------------------------------------------------------------- +// About 'outer_size': +// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags. +// Default value is ImVec2(0.0f, 0.0f). +// X +// - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge. +// - outer_size.x > 0.0f -> Set Fixed width. +// Y with ScrollX/ScrollY disabled: we output table directly in current window +// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll. +// - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) +// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) +// Y with ScrollX/ScrollY enabled: using a child window for scrolling +// - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll. +// - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. +// - outer_size.y > 0.0f -> Set Exact height. Recommended when using Scrolling on any axis. +//----------------------------------------------------------------------------- +// Outer size is also affected by the NoHostExtendX/NoHostExtendY flags. +// Important to note how the two flags have slightly different behaviors! +// - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. +// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible. +// In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height. +// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not useful and not easily noticeable). +//----------------------------------------------------------------------------- +// About 'inner_width': +// With ScrollX disabled: +// - inner_width -> *ignored* +// With ScrollX enabled: +// - inner_width < 0.0f -> *illegal* fit in known width (right align from outer_size.x) <-- weird +// - inner_width = 0.0f -> fit in outer_width: Fixed size columns will take space they need (if avail, otherwise shrink down), Stretch columns becomes Fixed columns. +// - inner_width > 0.0f -> override scrolling width, generally to be larger than outer_size.x. Fixed column take space they need (if avail, otherwise shrink down), Stretch columns share remaining space! +//----------------------------------------------------------------------------- +// Details: +// - If you want to use Stretch columns with ScrollX, you generally need to specify 'inner_width' otherwise the concept +// of "available space" doesn't make sense. +// - Even if not really useful, we allow 'inner_width < outer_size.x' for consistency and to facilitate understanding +// of what the value does. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// COLUMNS SIZING POLICIES +// (Reference: ImGuiTableFlags_SizingXXX flags and ImGuiTableColumnFlags_WidthXXX flags) +//----------------------------------------------------------------------------- +// About overriding column sizing policy and width/weight with TableSetupColumn(): +// We use a default parameter of -1 for 'init_width'/'init_weight'. +// - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic +// - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom +// - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f +// - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom +// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f) +// and you can fit a 100.0f wide item in it without clipping and with padding honored. +//----------------------------------------------------------------------------- +// About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag) +// - with Table policy ImGuiTableFlags_SizingFixedFit --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width +// - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width +// - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f +// - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents +// Default Width and default Weight can be overridden when calling TableSetupColumn(). +//----------------------------------------------------------------------------- +// About mixing Fixed/Auto and Stretch columns together: +// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! +// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. +// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents. +// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weights/widths. +//----------------------------------------------------------------------------- +// About using column width: +// If a column is manually resizable or has a width specified with TableSetupColumn(): +// - you may use GetContentRegionAvail().x to query the width available in a given column. +// - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width. +// If the column is not resizable and has no width specified with TableSetupColumn(): +// - its width will be automatic and be set to the max of items submitted. +// - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN). +// - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN). +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// TABLES CLIPPING/CULLING +//----------------------------------------------------------------------------- +// About clipping/culling of Rows in Tables: +// - For large numbers of rows, it is recommended you use ImGuiListClipper to submit only visible rows. +// ImGuiListClipper is reliant on the fact that rows are of equal height. +// See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper. +// - Note that auto-resizing columns don't play well with using the clipper. +// By default a table with _ScrollX but without _Resizable will have column auto-resize. +// So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns width explicitly with _WidthFixed. +//----------------------------------------------------------------------------- +// About clipping/culling of Columns in Tables: +// - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing +// width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know +// it is not going to contribute to row height. +// In many situations, you may skip submitting contents for every column but one (e.g. the first one). +// - Case A: column is not hidden by user, and at least partially in sight (most common case). +// - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output. +// - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.). +// +// [A] [B] [C] +// TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() returns false, user can skip submitting items but only if the column doesn't contribute to row height. +// SkipItems: false false true -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output. +// ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way. +// ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway). +// +// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row. +// However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer. +//----------------------------------------------------------------------------- +// About clipping/culling of whole Tables: +// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" + +// System includes +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Main code +//----------------------------------------------------------------------------- +// - TableFixFlags() [Internal] +// - TableFindByID() [Internal] +// - BeginTable() +// - BeginTableEx() [Internal] +// - TableBeginInitMemory() [Internal] +// - TableBeginApplyRequests() [Internal] +// - TableSetupColumnFlags() [Internal] +// - TableUpdateLayout() [Internal] +// - TableUpdateBorders() [Internal] +// - EndTable() +// - TableSetupColumn() +// - TableSetupScrollFreeze() +//----------------------------------------------------------------------------- + +// Configuration +static const int TABLE_DRAW_CHANNEL_BG0 = 0; +static const int TABLE_DRAW_CHANNEL_BG2_FROZEN = 1; +static const int TABLE_DRAW_CHANNEL_NOCLIP = 2; // When using ImGuiTableFlags_NoClip (this becomes the last visible channel) +static const float TABLE_BORDER_SIZE = 1.0f; // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering. +static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; // Extend outside inner borders. +static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped. + +// Helper +inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window) +{ + // Adjust flags: set default sizing policy + if ((flags & ImGuiTableFlags_SizingMask_) == 0) + flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame; + + // Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame + if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableFlags_NoKeepColumnsVisible; + + // Adjust flags: enforce borders when resizable + if (flags & ImGuiTableFlags_Resizable) + flags |= ImGuiTableFlags_BordersInnerV; + + // Adjust flags: disable NoHostExtendX/NoHostExtendY if we have any scrolling going on + if (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) + flags &= ~(ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY); + + // Adjust flags: NoBordersInBodyUntilResize takes priority over NoBordersInBody + if (flags & ImGuiTableFlags_NoBordersInBodyUntilResize) + flags &= ~ImGuiTableFlags_NoBordersInBody; + + // Adjust flags: disable saved settings if there's nothing to save + if ((flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable)) == 0) + flags |= ImGuiTableFlags_NoSavedSettings; + + // Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set) + if (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings) + flags |= ImGuiTableFlags_NoSavedSettings; + + return flags; +} + +ImGuiTable* ImGui::TableFindByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.Tables.GetByKey(id); +} + +// Read about "TABLE SIZING" at the top of this file. +bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiID id = GetID(str_id); + return BeginTableEx(str_id, id, columns_count, flags, outer_size, inner_width); +} + +bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* outer_window = GetCurrentWindow(); + if (outer_window->SkipItems) // Consistent with other tables + beneficial side effect that assert on miscalling EndTable() will be more visible. + return false; + + // Sanity checks + IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS); + if (flags & ImGuiTableFlags_ScrollX) + IM_ASSERT(inner_width >= 0.0f); + + // If an outer size is specified ahead we will be able to early out when not visible. Exact clipping criteria may evolve. + const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; + const ImVec2 avail_size = GetContentRegionAvail(); + ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); + ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); + if (use_child_window && IsClippedEx(outer_rect, 0)) + { + ItemSize(outer_rect); + return false; + } + + // Acquire storage for the table + ImGuiTable* table = g.Tables.GetOrAddByKey(id); + const ImGuiTableFlags table_last_flags = table->Flags; + + // Acquire temporary buffers + const int table_idx = g.Tables.GetIndex(table); + if (++g.TablesTempDataStacked > g.TablesTempData.Size) + g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData()); + ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1]; + temp_data->TableIndex = table_idx; + table->DrawSplitter = &table->TempData->DrawSplitter; + table->DrawSplitter->Clear(); + + // Fix flags + table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0; + flags = TableFixFlags(flags, outer_window); + + // Initialize + const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; + table->ID = id; + table->Flags = flags; + table->LastFrameActive = g.FrameCount; + table->OuterWindow = table->InnerWindow = outer_window; + table->ColumnsCount = columns_count; + table->IsLayoutLocked = false; + table->InnerWidth = inner_width; + temp_data->UserOuterSize = outer_size; + + // Instance data (for instance 0, TableID == TableInstanceID) + ImGuiID instance_id; + table->InstanceCurrent = (ImS16)instance_no; + if (instance_no > 0) + { + IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); + if (table->InstanceDataExtra.Size < instance_no) + table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); + instance_id = GetIDWithSeed(instance_no, GetIDWithSeed("##Instances", NULL, id)); // Push "##Instances" followed by (int)instance_no in ID stack. + } + else + { + instance_id = id; + } + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + table_instance->TableInstanceID = instance_id; + + // When not using a child window, WorkRect.Max will grow as we append contents. + if (use_child_window) + { + // Ensure no vertical scrollbar appears if we only want horizontal one, to make flag consistent + // (we have no other way to disable vertical scrollbar of a window while keeping the horizontal one showing) + ImVec2 override_content_size(FLT_MAX, FLT_MAX); + if ((flags & ImGuiTableFlags_ScrollX) && !(flags & ImGuiTableFlags_ScrollY)) + override_content_size.y = FLT_MIN; + + // Ensure specified width (when not specified, Stretched columns will act as if the width == OuterWidth and + // never lead to any scrolling). We don't handle inner_width < 0.0f, we could potentially use it to right-align + // based on the right side of the child window work rect, which would require knowing ahead if we are going to + // have decoration taking horizontal spaces (typically a vertical scrollbar). + if ((flags & ImGuiTableFlags_ScrollX) && inner_width > 0.0f) + override_content_size.x = inner_width; + + if (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX) + SetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f)); + + // Reset scroll if we are reactivating it + if ((table_last_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + + // Create scrolling region (without border and zero window padding) + ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; + BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags); + table->InnerWindow = g.CurrentWindow; + table->WorkRect = table->InnerWindow->WorkRect; + table->OuterRect = table->InnerWindow->Rect(); + table->InnerRect = table->InnerWindow->InnerRect; + IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f); + + // When using multiple instances, ensure they have the same amount of horizontal decorations (aka vertical scrollbar) so stretched columns can be aligned) + if (instance_no == 0) + { + table->HasScrollbarYPrev = table->HasScrollbarYCurr; + table->HasScrollbarYCurr = false; + } + table->HasScrollbarYCurr |= (table->InnerWindow->ScrollMax.y > 0.0f); + } + else + { + // For non-scrolling tables, WorkRect == OuterRect == InnerRect. + // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable(). + table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; + } + + // Push a standardized ID for both child-using and not-child-using tables + PushOverrideID(id); + if (instance_no > 0) + PushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol. + + // Backup a copy of host window members we will modify + ImGuiWindow* inner_window = table->InnerWindow; + table->HostIndentX = inner_window->DC.Indent.x; + table->HostClipRect = inner_window->ClipRect; + table->HostSkipItems = inner_window->SkipItems; + temp_data->HostBackupWorkRect = inner_window->WorkRect; + temp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect; + temp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; + temp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; + temp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; + temp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; + temp_data->HostBackupItemWidth = outer_window->DC.ItemWidth; + temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; + inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + + // Padding and Spacing + // - None ........Content..... Pad .....Content........ + // - PadOuter | Pad ..Content..... Pad .....Content.. Pad | + // - PadInner ........Content.. Pad | Pad ..Content........ + // - PadOuter+PadInner | Pad ..Content.. Pad | Pad ..Content.. Pad | + const bool pad_outer_x = (flags & ImGuiTableFlags_NoPadOuterX) ? false : (flags & ImGuiTableFlags_PadOuterX) ? true : (flags & ImGuiTableFlags_BordersOuterV) != 0; + const bool pad_inner_x = (flags & ImGuiTableFlags_NoPadInnerX) ? false : true; + const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f; + const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f; + const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f; + table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border; + table->CellSpacingX2 = inner_spacing_explicit; + table->CellPaddingX = inner_padding_explicit; + table->CellPaddingY = g.Style.CellPadding.y; + + const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f; + table->OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table->CellPaddingX; + + table->CurrentColumn = -1; + table->CurrentRow = -1; + table->RowBgColorCounter = 0; + table->LastRowFlags = ImGuiTableRowFlags_None; + table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect; + table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width + table->InnerClipRect.ClipWithFull(table->HostClipRect); + table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; + + table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow + table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() + table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any + table->FreezeColumnsRequest = table->FreezeColumnsCount = 0; + table->IsUnfrozenRows = true; + table->DeclColumnsCount = 0; + + // Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders() + table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); + table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); + + // Make table current + g.CurrentTable = table; + outer_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); + outer_window->DC.CurrentTableIdx = table_idx; + if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. + inner_window->DC.CurrentTableIdx = table_idx; + + if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) + table->IsResetDisplayOrderRequest = true; + + // Mark as used to avoid GC + if (table_idx >= g.TablesLastTimeActive.Size) + g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); + g.TablesLastTimeActive[table_idx] = (float)g.Time; + temp_data->LastTimeActive = (float)g.Time; + table->MemoryCompacted = false; + + // Setup memory buffer (clear data if columns count changed) + ImGuiTableColumn* old_columns_to_preserve = NULL; + void* old_columns_raw_data = NULL; + const int old_columns_count = table->Columns.size(); + if (old_columns_count != 0 && old_columns_count != columns_count) + { + // Attempt to preserve width on column count change (#4046) + old_columns_to_preserve = table->Columns.Data; + old_columns_raw_data = table->RawData; + table->RawData = NULL; + } + if (table->RawData == NULL) + { + TableBeginInitMemory(table, columns_count); + table->IsInitializing = table->IsSettingsRequestLoad = true; + } + if (table->IsResetAllRequest) + TableResetSettings(table); + if (table->IsInitializing) + { + // Initialize + table->SettingsOffset = -1; + table->IsSortSpecsDirty = true; + table->InstanceInteracted = -1; + table->ContextPopupColumn = -1; + table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; + table->AutoFitSingleColumn = -1; + table->HoveredColumnBody = table->HoveredColumnBorder = -1; + for (int n = 0; n < columns_count; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + if (old_columns_to_preserve && n < old_columns_count) + { + // FIXME: We don't attempt to preserve column order in this path. + *column = old_columns_to_preserve[n]; + } + else + { + float width_auto = column->WidthAuto; + *column = ImGuiTableColumn(); + column->WidthAuto = width_auto; + column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker + column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true; + } + column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; + } + } + if (old_columns_raw_data) + IM_FREE(old_columns_raw_data); + + // Load settings + if (table->IsSettingsRequestLoad) + TableLoadSettings(table); + + // Handle DPI/font resize + // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. + // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. + // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. + // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. + const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) + { + const float scale_factor = new_ref_scale_unit / table->RefScale; + //IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor); + for (int n = 0; n < columns_count; n++) + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; + } + table->RefScale = new_ref_scale_unit; + + // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. + // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user. + // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. + inner_window->SkipItems = true; + + // Clear names + // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() + if (table->ColumnsNames.Buf.Size > 0) + table->ColumnsNames.Buf.resize(0); + + // Apply queued resizing/reordering/hiding requests + TableBeginApplyRequests(table); + + return true; +} + +// For reference, the average total _allocation count_ for a table is: +// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables[]) +// + 1 (for table->RawData allocated below) +// + 1 (for table->ColumnsNames, if names are used) +// Shared allocations for the maximum number of simultaneously nested tables (generally a very small number) +// + 1 (for table->Splitter._Channels) +// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels) +// Where active_channels_count is variable but often == columns_count or == columns_count + 1, see TableSetupDrawChannels() for details. +// Unused channels don't perform their +2 allocations. +void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) +{ + // Allocate single buffer for our arrays + const int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count); + ImSpanAllocator<6> span_allocator; + span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); + span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); + span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); + for (int n = 3; n < 6; n++) + span_allocator.Reserve(n, columns_bit_array_size); + table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); + memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); + span_allocator.SetArenaBasePtr(table->RawData); + span_allocator.GetSpan(0, &table->Columns); + span_allocator.GetSpan(1, &table->DisplayOrderToIndex); + span_allocator.GetSpan(2, &table->RowCellData); + table->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3); + table->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4); + table->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5); +} + +// Apply queued resizing/reordering/hiding requests +void ImGui::TableBeginApplyRequests(ImGuiTable* table) +{ + // Handle resizing request + // (We process this in the TableBegin() of the first instance of each table) + // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling? + if (table->InstanceCurrent == 0) + { + if (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX) + TableSetColumnWidth(table->ResizedColumn, table->ResizedColumnNextWidth); + table->LastResizedColumn = table->ResizedColumn; + table->ResizedColumnNextWidth = FLT_MAX; + table->ResizedColumn = -1; + + // Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy. + // FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings. + if (table->AutoFitSingleColumn != -1) + { + TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto); + table->AutoFitSingleColumn = -1; + } + } + + // Handle reordering request + // Note: we don't clear ReorderColumn after handling the request. + if (table->InstanceCurrent == 0) + { + if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) + table->ReorderColumn = -1; + table->HeldHeaderColumn = -1; + if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0) + { + // We need to handle reordering across hidden columns. + // In the configuration below, moving C to the right of E will lead to: + // ... C [D] E ---> ... [D] E C (Column name/index) + // ... 2 3 4 ... 2 3 4 (Display order) + const int reorder_dir = table->ReorderColumnDir; + IM_ASSERT(reorder_dir == -1 || reorder_dir == +1); + IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable); + ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn]; + ImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; + IM_UNUSED(dst_column); + const int src_order = src_column->DisplayOrder; + const int dst_order = dst_column->DisplayOrder; + src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; + for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) + table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; + IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); + + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; + table->ReorderColumnDir = 0; + table->IsSettingsDirty = true; + } + } + + // Handle display order reset request + if (table->IsResetDisplayOrderRequest) + { + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[n] = table->Columns[n].DisplayOrder = (ImGuiTableColumnIdx)n; + table->IsResetDisplayOrderRequest = false; + table->IsSettingsDirty = true; + } +} + +// Adjust flags: default width mode + stretch columns are not allowed when auto extending +static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) +{ + ImGuiTableColumnFlags flags = flags_in; + + // Sizing Policy + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) + { + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + if (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + else + flags |= ImGuiTableColumnFlags_WidthStretch; + } + else + { + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. + } + + // Resize + if ((table->Flags & ImGuiTableFlags_Resizable) == 0) + flags |= ImGuiTableColumnFlags_NoResize; + + // Sorting + if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending)) + flags |= ImGuiTableColumnFlags_NoSort; + + // Indentation + if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0) + flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + + // Alignment + //if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0) + // flags |= ImGuiTableColumnFlags_AlignCenter; + //IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used. + + // Preserve status flags + column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); + + // Build an ordered list of available sort directions + column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0; + if (table->Flags & ImGuiTableFlags_Sortable) + { + int count = 0, mask = 0, list = 0; + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; } + column->SortDirectionsAvailList = (ImU8)list; + column->SortDirectionsAvailMask = (ImU8)mask; + column->SortDirectionsAvailCount = (ImU8)count; + ImGui::TableFixColumnSortDirection(table, column); + } +} + +// Layout columns for the frame. This is in essence the followup to BeginTable() and this is our largest function. +// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() and other TableSetupXXXXX() functions to be called first. +// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns. +// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns? +void ImGui::TableUpdateLayout(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->IsLayoutLocked == false); + + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + table->IsDefaultDisplayOrder = true; + table->ColumnsEnabledCount = 0; + ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount); + ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount); + table->LeftMostEnabledColumn = -1; + table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE + + // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns. + // Process columns in their visible orders as we are building the Prev/Next indices. + int count_fixed = 0; // Number of columns that have fixed sizing policies + int count_stretch = 0; // Number of columns that have stretch sizing policies + int prev_visible_column_idx = -1; + bool has_auto_fit_request = false; + bool has_resizable = false; + float stretch_sum_width_auto = 0.0f; + float fixed_max_width_auto = 0.0f; + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + if (column_n != order_n) + table->IsDefaultDisplayOrder = false; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame. + // It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway. + // We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect. + if (table->DeclColumnsCount <= column_n) + { + TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); + column->NameOffset = -1; + column->UserID = 0; + column->InitStretchWeightOrWidth = -1.0f; + } + + // Update Enabled state, mark settings and sort specs dirty + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) + column->IsUserEnabledNextFrame = true; + if (column->IsUserEnabled != column->IsUserEnabledNextFrame) + { + column->IsUserEnabled = column->IsUserEnabledNextFrame; + table->IsSettingsDirty = true; + } + column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0; + + if (column->SortOrder != -1 && !column->IsEnabled) + table->IsSortSpecsDirty = true; + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) + table->IsSortSpecsDirty = true; + + // Auto-fit unsized columns + const bool start_auto_fit = (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f); + if (start_auto_fit) + column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames + + if (!column->IsEnabled) + { + column->IndexWithinEnabledSet = -1; + continue; + } + + // Mark as enabled and link to previous/next enabled column + column->PrevEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + column->NextEnabledColumn = -1; + if (prev_visible_column_idx != -1) + table->Columns[prev_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + else + table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; + column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; + ImBitArraySetBit(table->EnabledMaskByIndex, column_n); + ImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder); + prev_visible_column_idx = column_n; + IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); + + // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) + // Combine width from regular rows + width from headers unless requested not to. + if (!column->IsPreserveWidthAuto) + column->WidthAuto = TableGetColumnWidthAuto(table, column); + + // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column_is_resizable) + has_resizable = true; + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable) + column->WidthAuto = column->InitStretchWeightOrWidth; + + if (column->AutoFitQueue != 0x00) + has_auto_fit_request = true; + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + stretch_sum_width_auto += column->WidthAuto; + count_stretch++; + } + else + { + fixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto); + count_fixed++; + } + } + if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + table->IsSortSpecsDirty = true; + table->RightMostEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + IM_ASSERT(table->LeftMostEnabledColumn >= 0 && table->RightMostEnabledColumn >= 0); + + // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible + // to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing). + // FIXME-TABLE: for always auto-resizing columns may not want to do that all the time. + if (has_auto_fit_request && table->OuterWindow != table->InnerWindow) + table->InnerWindow->SkipItems = false; + if (has_auto_fit_request) + table->IsSettingsDirty = true; + + // [Part 3] Fix column flags and record a few extra information. + float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. + float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. + table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + { + // Apply same widths policy + float width_auto = column->WidthAuto; + if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable)) + width_auto = fixed_max_width_auto; + + // Apply automatic width + // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) + if (column->AutoFitQueue != 0x00) + column->WidthRequest = width_auto; + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput) + column->WidthRequest = width_auto; + + // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets + // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very + // large height (= first frame scrollbar display very off + clipper would skip lots of items). + // This is merely making the side-effect less extreme, but doesn't properly fixes it. + // FIXME: Move this to ->WidthGiven to avoid temporary lossyless? + // FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller. + if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto) + column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale? + sum_width_requests += column->WidthRequest; + } + else + { + // Initialize stretch weight + if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable) + { + if (column->InitStretchWeightOrWidth > 0.0f) + column->StretchWeight = column->InitStretchWeightOrWidth; + else if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp) + column->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch; + else + column->StretchWeight = 1.0f; + } + + stretch_sum_weights += column->StretchWeight; + if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder) + table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder) + table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + } + column->IsPreserveWidthAuto = false; + sum_width_requests += table->CellPaddingX * 2.0f; + } + table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed; + table->ColumnsStretchSumWeights = stretch_sum_weights; + + // [Part 4] Apply final widths based on requested widths + const ImRect work_rect = table->WorkRect; + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920) + const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed); + const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; + float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; + table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest) + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + float weight_ratio = column->StretchWeight / stretch_sum_weights; + column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f); + width_remaining_for_stretched_columns -= column->WidthRequest; + } + + // [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column + // See additional comments in TableSetColumnWidth(). + if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1) + column->Flags |= ImGuiTableColumnFlags_NoDirectResize_; + + // Assign final width, record width in case we will need to shrink + column->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth)); + table->ColumnsGivenWidth += column->WidthGiven; + } + + // [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). + // Using right-to-left distribution (more likely to match resizing cursor). + if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) + for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; + if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->WidthRequest += 1.0f; + column->WidthGiven += 1.0f; + width_remaining_for_stretched_columns -= 1.0f; + } + + // Determine if table is hovered which will be used to flag columns as hovered. + // - In principle we'd like to use the equivalent of IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + // but because our item is partially submitted at this point we use ItemHoverable() and a workaround (temporarily + // clear ActiveId, which is equivalent to the change provided by _AllowWhenBLockedByActiveItem). + // - This allows columns to be marked as hovered when e.g. clicking a button inside the column, or using drag and drop. + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + table->HoveredColumnBody = -1; + table->HoveredColumnBorder = -1; + const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight)); + const ImGuiID backup_active_id = g.ActiveId; + g.ActiveId = 0; + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); + g.ActiveId = backup_active_id; + + // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column + // Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping. + int visible_n = 0; + bool offset_x_frozen = (table->FreezeColumnsCount > 0); + float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; + ImRect host_clip_rect = table->InnerClipRect; + //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; + ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount); + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + + column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen + + if (offset_x_frozen && table->FreezeColumnsCount == visible_n) + { + offset_x += work_rect.Min.x - table->OuterRect.Min.x; + offset_x_frozen = false; + } + + // Clear status flags + column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; + + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + { + // Hidden column: clear a few fields and we are done with it for the remainder of the function. + // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. + column->MinX = column->MaxX = column->WorkMinX = column->ClipRect.Min.x = column->ClipRect.Max.x = offset_x; + column->WidthGiven = 0.0f; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + column->IsVisibleX = column->IsVisibleY = column->IsRequestOutput = false; + column->IsSkipItems = true; + column->ItemWidth = 1.0f; + continue; + } + + // Detect hovered column + if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x) + table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; + + // Lock start position + column->MinX = offset_x; + + // Lock width based on start position and minimum/maximum width for this position + float max_width = TableGetMaxColumnWidth(table, column_n); + column->WidthGiven = ImMin(column->WidthGiven, max_width); + column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth)); + column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + + // Lock other positions + // - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging. + // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column. + // - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow. + // - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter. + column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1; + column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max + column->ItemWidth = ImFloor(column->WidthGiven * 0.65f); + column->ClipRect.Min.x = column->MinX; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + + // Mark column as Clipped (not in sight) + // Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables. + // FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY. + // Taking advantage of LastOuterHeight would yield good results there... + // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x, + // and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else). + // Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small. + column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); + column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); + const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; + if (is_visible) + ImBitArraySetBit(table->VisibleMaskByIndex, column_n); + + // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. + column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; + + // Mark column as SkipItems (ignoring all items/layout) + column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; + if (column->IsSkipItems) + IM_ASSERT(!is_visible); + + // Update status flags + column->Flags |= ImGuiTableColumnFlags_IsEnabled; + if (is_visible) + column->Flags |= ImGuiTableColumnFlags_IsVisible; + if (column->SortOrder != -1) + column->Flags |= ImGuiTableColumnFlags_IsSorted; + if (table->HoveredColumnBody == column_n) + column->Flags |= ImGuiTableColumnFlags_IsHovered; + + // Alignment + // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in + // many cases (to be able to honor this we might be able to store a log of cells width, per row, for + // visible rows, but nav/programmatic scroll would have visible artifacts.) + //if (column->Flags & ImGuiTableColumnFlags_AlignRight) + // column->WorkMinX = ImMax(column->WorkMinX, column->MaxX - column->ContentWidthRowsUnfrozen); + //else if (column->Flags & ImGuiTableColumnFlags_AlignCenter) + // column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f); + + // Reset content width variables + column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX; + column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX; + + // Don't decrement auto-fit counters until container window got a chance to submit its items + if (table->HostSkipItems == false) + { + column->AutoFitQueue >>= 1; + column->CannotSkipItemsQueue >>= 1; + } + + if (visible_n < table->FreezeColumnsCount) + host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x); + + offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + visible_n++; + } + + // [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it) + // Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either + // because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu. + const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); + if (is_hovering_table && table->HoveredColumnBody == -1) + { + if (g.IO.MousePos.x >= unused_x1) + table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount; + } + if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable)) + table->Flags &= ~ImGuiTableFlags_Resizable; + + // [Part 8] Lock actual OuterRect/WorkRect right-most position. + // This is done late to handle the case of fixed-columns tables not claiming more widths that they need. + // Because of this we are careful with uses of WorkRect and InnerClipRect before this point. + if (table->RightMostStretchedColumn != -1) + table->Flags &= ~ImGuiTableFlags_NoHostExtendX; + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + table->OuterRect.Max.x = table->WorkRect.Max.x = unused_x1; + table->InnerClipRect.Max.x = ImMin(table->InnerClipRect.Max.x, unused_x1); + } + table->InnerWindow->ParentWorkRect = table->WorkRect; + table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f); + table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f); + + // [Part 9] Allocate draw channels and setup background cliprect + TableSetupDrawChannels(table); + + // [Part 10] Hit testing on borders + if (table->Flags & ImGuiTableFlags_Resizable) + TableUpdateBorders(table); + table_instance->LastFirstRowHeight = 0.0f; + table->IsLayoutLocked = true; + table->IsUsingHeaders = false; + + // [Part 11] Context menu + if (TableBeginContextMenuPopup(table)) + { + TableDrawContextMenu(table); + EndPopup(); + } + + // [Part 12] Sanitize and build sort specs before we have a chance to use them for display. + // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) + if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) + TableSortSpecsBuild(table); + + // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) + if (table->FreezeColumnsRequest > 0) + table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; + if (table->FreezeRowsRequest > 0) + table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight; + table_instance->LastFrozenHeight = 0.0f; + + // Initial state + ImGuiWindow* inner_window = table->InnerWindow; + if (table->Flags & ImGuiTableFlags_NoClip) + table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + else + inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); +} + +// Process hit-testing on resizing borders. Actual size change will be applied in EndTable() +// - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise. +// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize +// widgets overlapping the same area. +void ImGui::TableUpdateBorders(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->Flags & ImGuiTableFlags_Resizable); + + // At this point OuterRect height may be zero or under actual final height, so we rely on temporal coherency and + // use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not + // really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height). + // Actual columns highlight/render will be performed in EndTable() and not be affected. + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS; + const float hit_y1 = table->OuterRect.Min.y; + const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight); + const float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight; + + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) + continue; + + // ImGuiTableFlags_NoBordersInBodyUntilResize will be honored in TableDrawBorders() + const float border_y2_hit = (table->Flags & ImGuiTableFlags_NoBordersInBody) ? hit_y2_head : hit_y2_body; + if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false) + continue; + + if (!column->IsVisibleX && table->LastResizedColumn != column_n) + continue; + + ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent); + ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit); + ItemAdd(hit_rect, column_id, NULL, ImGuiItemFlags_NoNav); + //GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100)); + + bool hovered = false, held = false; + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); + if (pressed && IsMouseDoubleClicked(0)) + { + TableSetColumnWidthAutoSingle(table, column_n); + ClearActiveID(); + held = hovered = false; + } + if (held) + { + if (table->LastResizedColumn == -1) + table->ResizeLockMinContentsX2 = table->RightMostEnabledColumn != -1 ? table->Columns[table->RightMostEnabledColumn].MaxX : -FLT_MAX; + table->ResizedColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + } + if ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held) + { + table->HoveredColumnBorder = (ImGuiTableColumnIdx)column_n; + SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + } +} + +void ImGui::EndTable() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!"); + + // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some + // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) + //IM_ASSERT(table->IsLayoutLocked && "Table unused: never called TableNextRow(), is that the intent?"); + + // If the user never got to call TableNextRow() or TableNextColumn(), we call layout ourselves to ensure all our + // code paths are consistent (instead of just hoping that TableBegin/TableEnd will work), get borders drawn, etc. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + const ImGuiTableFlags flags = table->Flags; + ImGuiWindow* inner_window = table->InnerWindow; + ImGuiWindow* outer_window = table->OuterWindow; + ImGuiTableTempData* temp_data = table->TempData; + IM_ASSERT(inner_window == g.CurrentWindow); + IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow); + + if (table->IsInsideRow) + TableEndRow(table); + + // Context menu in columns body + if (flags & ImGuiTableFlags_ContextMenuInBody) + if (table->HoveredColumnBody != -1 && !IsAnyItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + TableOpenContextMenu((int)table->HoveredColumnBody); + + // Finalize table height + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize; + inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize; + inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos; + const float inner_content_max_y = table->RowPosY2; + IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y); + if (inner_window != outer_window) + inner_window->DC.CursorMaxPos.y = inner_content_max_y; + else if (!(flags & ImGuiTableFlags_NoHostExtendY)) + table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height + table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y); + table_instance->LastOuterHeight = table->OuterRect.GetHeight(); + + // Setup inner scrolling range + // FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y, + // but since the later is likely to be impossible to do we'd rather update both axises together. + if (table->Flags & ImGuiTableFlags_ScrollX) + { + const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + float max_pos_x = table->InnerWindow->DC.CursorMaxPos.x; + if (table->RightMostEnabledColumn != -1) + max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border); + if (table->ResizedColumn != -1) + max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2); + table->InnerWindow->DC.CursorMaxPos.x = max_pos_x; + } + + // Pop clipping rect + if (!(flags & ImGuiTableFlags_NoClip)) + inner_window->DrawList->PopClipRect(); + inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back(); + + // Draw borders + if ((flags & ImGuiTableFlags_Borders) != 0) + TableDrawBorders(table); + +#if 0 + // Strip out dummy channel draw calls + // We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out) + // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway. + // Cons: making it harder for users watching metrics/debugger to spot the wasted vertices. + if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) + { + ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; + dummy_channel->_CmdBuffer.resize(0); + dummy_channel->_IdxBuffer.resize(0); + } +#endif + + // Flatten channels and merge draw calls + ImDrawListSplitter* splitter = table->DrawSplitter; + splitter->SetCurrentChannel(inner_window->DrawList, 0); + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + TableMergeDrawChannels(table); + splitter->Merge(inner_window->DrawList); + + // Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable() + float auto_fit_width_for_fixed = 0.0f; + float auto_fit_width_for_stretched = 0.0f; + float auto_fit_width_for_stretched_min = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + auto_fit_width_for_fixed += column_width_request; + else + auto_fit_width_for_stretched += column_width_request; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->Flags & ImGuiTableColumnFlags_NoResize) != 0) + auto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column->StretchWeight / table->ColumnsStretchSumWeights)); + } + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min); + + // Update scroll + if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window) + { + inner_window->Scroll.x = 0.0f; + } + else if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent) + { + // When releasing a column being resized, scroll to keep the resulting column in sight + const float neighbor_width_to_keep_visible = table->MinColumnWidth + table->CellPaddingX * 2.0f; + ImGuiTableColumn* column = &table->Columns[table->LastResizedColumn]; + if (column->MaxX < table->InnerClipRect.Min.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - neighbor_width_to_keep_visible, 1.0f); + else if (column->MaxX > table->InnerClipRect.Max.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + neighbor_width_to_keep_visible, 1.0f); + } + + // Apply resizing/dragging at the end of the frame + if (table->ResizedColumn != -1 && table->InstanceCurrent == table->InstanceInteracted) + { + ImGuiTableColumn* column = &table->Columns[table->ResizedColumn]; + const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS); + const float new_width = ImFloor(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f); + table->ResizedColumnNextWidth = new_width; + } + + // Pop from id stack + IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!"); + IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); + if (table->InstanceCurrent > 0) + PopID(); + PopID(); + + // Restore window data that we modified + const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos; + inner_window->WorkRect = temp_data->HostBackupWorkRect; + inner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect; + inner_window->SkipItems = table->HostSkipItems; + outer_window->DC.CursorPos = table->OuterRect.Min; + outer_window->DC.ItemWidth = temp_data->HostBackupItemWidth; + outer_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize; + outer_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset; + + // Layout in outer window + // (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding + // CursorPosPrevLine and CursorMaxPos manually. That should be a more general layout feature, see same problem e.g. #3414) + if (inner_window != outer_window) + { + EndChild(); + } + else + { + ItemSize(table->OuterRect.GetSize()); + ItemAdd(table->OuterRect, 0); + } + + // Override declared contents width/height to enable auto-resize while not needlessly adding a scrollbar + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + // FIXME-TABLE: Could we remove this section? + // ColumnsAutoFitWidth may be one frame ahead here since for Fixed+NoResize is calculated from latest contents + IM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth); + } + else if (temp_data->UserOuterSize.x <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f; + outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); + } + else + { + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x); + } + if (temp_data->UserOuterSize.y <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f; + outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); + } + else + { + // OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags_NoHostExtendY is set) + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table->OuterRect.Max.y); + } + + // Save settings + if (table->IsSettingsDirty) + TableSaveSettings(table); + table->IsInitializing = false; + + // Clear or restore current table, if any + IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); + IM_ASSERT(g.TablesTempDataStacked > 0); + temp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL; + g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL; + if (g.CurrentTable) + { + g.CurrentTable->TempData = temp_data; + g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; + } + outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; + NavUpdateCurrentWindowIsScrollPushableX(); +} + +// See "COLUMN SIZING POLICIES" comments at the top of this file +// If (init_width_or_weight <= 0.0f) it is ignored +void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!"); + IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); + if (table->DeclColumnsCount >= table->ColumnsCount) + { + IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "Called TableSetupColumn() too many times!"); + return; + } + + ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; + table->DeclColumnsCount++; + + // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. + // Give a grace to users of ImGuiTableFlags_ScrollX. + if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) + IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); + + // When passing a width automatically enforce WidthFixed policy + // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f) + if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + + TableSetupColumnFlags(table, column, flags); + column->UserID = user_id; + flags = column->Flags; + + // Initialize defaults + column->InitStretchWeightOrWidth = init_width_or_weight; + if (table->IsInitializing) + { + // Init width or weight + if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) + { + if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) + column->WidthRequest = init_width_or_weight; + if (flags & ImGuiTableColumnFlags_WidthStretch) + column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f; + + // Disable auto-fit if an explicit width/weight has been specified + if (init_width_or_weight > 0.0f) + column->AutoFitQueue = 0x00; + } + + // Init default visibility/sort state + if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) + column->IsUserEnabled = column->IsUserEnabledNextFrame = false; + if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) + { + column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + } + } + + // Store name (append with zero-terminator in contiguous buffer) + column->NameOffset = -1; + if (label != NULL && label[0] != 0) + { + column->NameOffset = (ImS16)table->ColumnsNames.size(); + table->ColumnsNames.append(label, label + strlen(label) + 1); + } +} + +// [Public] +void ImGui::TableSetupScrollFreeze(int columns, int rows) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); + IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit + + table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0; + table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0; + table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0; + table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0; + table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b + + // Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered. + // FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section) + for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++) + { + int order_n = table->DisplayOrderToIndex[column_n]; + if (order_n != column_n && order_n >= table->FreezeColumnsRequest) + { + ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder); + ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Simple accessors +//----------------------------------------------------------------------------- +// - TableGetColumnCount() +// - TableGetColumnName() +// - TableGetColumnName() [Internal] +// - TableSetColumnEnabled() +// - TableGetColumnFlags() +// - TableGetCellBgRect() [Internal] +// - TableGetColumnResizeID() [Internal] +// - TableGetHoveredColumn() [Internal] +// - TableSetBgColor() +//----------------------------------------------------------------------------- + +int ImGui::TableGetColumnCount() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + return table ? table->ColumnsCount : 0; +} + +const char* ImGui::TableGetColumnName(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return NULL; + if (column_n < 0) + column_n = table->CurrentColumn; + return TableGetColumnName(table, column_n); +} + +const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) +{ + if (table->IsLayoutLocked == false && column_n >= table->DeclColumnsCount) + return ""; // NameOffset is invalid at this point + const ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->NameOffset == -1) + return ""; + return &table->ColumnsNames.Buf[column->NameOffset]; +} + +// Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view) +// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) +// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state. +// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable(). +// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0. +// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu. +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsUserEnabledNextFrame = enabled; +} + +// We allow querying for an extra column in order to poll the IsHovered state of the right-most section +ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return ImGuiTableColumnFlags_None; + if (column_n < 0) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) + return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None; + return table->Columns[column_n].Flags; +} + +// Return the cell rectangle based on currently known height. +// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height. +// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right +// columns report a small offset so their CellBgRect can extend up to the outer border. +// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling. +ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float x1 = column->MinX; + float x2 = column->MaxX; + //if (column->PrevEnabledColumn == -1) + // x1 -= table->OuterPaddingX; + //if (column->NextEnabledColumn == -1) + // x2 += table->OuterPaddingX; + x1 = ImMax(x1, table->WorkRect.Min.x); + x2 = ImMin(x2, table->WorkRect.Max.x); + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); +} + +// Return the resizing ID for the right-side of the given column. +ImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiID instance_id = TableGetInstanceID(table, instance_no); + return instance_id + 1 + column_n; // FIXME: #6140: still not ideal +} + +// Return -1 when table is not hovered. return columns_count if hovering the unused space at the right of the right-most visible column. +int ImGui::TableGetHoveredColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + return (int)table->HoveredColumnBody; +} + +void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(target != ImGuiTableBgTarget_None); + + if (color == IM_COL32_DISABLE) + color = 0; + + // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. + switch (target) + { + case ImGuiTableBgTarget_CellBg: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + if (column_n == -1) + column_n = table->CurrentColumn; + if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + return; + if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) + table->RowCellDataCurrent++; + ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent]; + cell_data->BgColor = color; + cell_data->Column = (ImGuiTableColumnIdx)column_n; + break; + } + case ImGuiTableBgTarget_RowBg0: + case ImGuiTableBgTarget_RowBg1: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + IM_ASSERT(column_n == -1); + int bg_idx = (target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; + table->RowBgColor[bg_idx] = color; + break; + } + default: + IM_ASSERT(0); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Row changes +//------------------------------------------------------------------------- +// - TableGetRowIndex() +// - TableNextRow() +// - TableBeginRow() [Internal] +// - TableEndRow() [Internal] +//------------------------------------------------------------------------- + +// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows +int ImGui::TableGetRowIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentRow; +} + +// [Public] Starts into the first cell of a new row +void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + if (table->IsInsideRow) + TableEndRow(table); + + table->LastRowFlags = table->RowFlags; + table->RowFlags = row_flags; + table->RowMinHeight = row_min_height; + TableBeginRow(table); + + // We honor min_row_height requested by user, but cannot guarantee per-row maximum height, + // because that would essentially require a unique clipping rectangle per-cell. + table->RowPosY2 += table->CellPaddingY * 2.0f; + table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height); + + // Disable output until user calls TableNextColumn() + table->InnerWindow->SkipItems = true; +} + +// [Internal] Called by TableNextRow() +void ImGui::TableBeginRow(ImGuiTable* table) +{ + ImGuiWindow* window = table->InnerWindow; + IM_ASSERT(!table->IsInsideRow); + + // New row + table->CurrentRow++; + table->CurrentColumn = -1; + table->RowBgColor[0] = table->RowBgColor[1] = IM_COL32_DISABLE; + table->RowCellDataCurrent = -1; + table->IsInsideRow = true; + + // Begin frozen rows + float next_y1 = table->RowPosY2; + if (table->CurrentRow == 0 && table->FreezeRowsCount > 0) + next_y1 = window->DC.CursorPos.y = table->OuterRect.Min.y; + + table->RowPosY1 = table->RowPosY2 = next_y1; + table->RowTextBaseline = 0.0f; + table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent + window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.IsSameLine = window->DC.IsSetPos = false; + window->DC.CursorMaxPos.y = next_y1; + + // Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging. + if (table->RowFlags & ImGuiTableRowFlags_Headers) + { + TableSetBgColor(ImGuiTableBgTarget_RowBg0, GetColorU32(ImGuiCol_TableHeaderBg)); + if (table->CurrentRow == 0) + table->IsUsingHeaders = true; + } +} + +// [Internal] Called by TableNextRow() +void ImGui::TableEndRow(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window == table->InnerWindow); + IM_ASSERT(table->IsInsideRow); + + if (table->CurrentColumn != -1) + TableEndCell(table); + + // Logging + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + + // Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is + // likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding. + window->DC.CursorPos.y = table->RowPosY2; + + // Row background fill + const float bg_y1 = table->RowPosY1; + const float bg_y2 = table->RowPosY2; + const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount); + const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest); + if (table->CurrentRow == 0) + TableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1; + + const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y); + if (is_visible) + { + // Decide of background color for the row + ImU32 bg_col0 = 0; + ImU32 bg_col1 = 0; + if (table->RowBgColor[0] != IM_COL32_DISABLE) + bg_col0 = table->RowBgColor[0]; + else if (table->Flags & ImGuiTableFlags_RowBg) + bg_col0 = GetColorU32((table->RowBgColorCounter & 1) ? ImGuiCol_TableRowBgAlt : ImGuiCol_TableRowBg); + if (table->RowBgColor[1] != IM_COL32_DISABLE) + bg_col1 = table->RowBgColor[1]; + + // Decide of top border color + ImU32 border_col = 0; + const float border_size = TABLE_BORDER_SIZE; + if (table->CurrentRow > 0 || table->InnerWindow == table->OuterWindow) + if (table->Flags & ImGuiTableFlags_BordersInnerH) + border_col = (table->LastRowFlags & ImGuiTableRowFlags_Headers) ? table->BorderColorStrong : table->BorderColorLight; + + const bool draw_cell_bg_color = table->RowCellDataCurrent >= 0; + const bool draw_strong_bottom_border = unfreeze_rows_actual; + if ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color) + { + // In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is + // always followed by a change of clipping rectangle we perform the smallest overwrite possible here. + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4(); + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); + } + + // Draw row background + // We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle + if (bg_col0 || bg_col1) + { + ImRect row_rect(table->WorkRect.Min.x, bg_y1, table->WorkRect.Max.x, bg_y2); + row_rect.ClipWith(table->BgClipRect); + if (bg_col0 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col0); + if (bg_col1 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col1); + } + + // Draw cell background color + if (draw_cell_bg_color) + { + ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; + for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) + { + // As we render the BG here we need to clip things (for layout we would not) + // FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling. + const ImGuiTableColumn* column = &table->Columns[cell_data->Column]; + ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); + cell_bg_rect.ClipWith(table->BgClipRect); + cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling + cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); + window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); + } + } + + // Draw top border + if (border_col && bg_y1 >= table->BgClipRect.Min.y && bg_y1 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), border_col, border_size); + + // Draw bottom border at the row unfreezing mark (always strong) + if (draw_strong_bottom_border && bg_y2 >= table->BgClipRect.Min.y && bg_y2 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong, border_size); + } + + // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle) + // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and + // get the new cursor position. + if (unfreeze_rows_request) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; + if (unfreeze_rows_actual) + { + IM_ASSERT(table->IsUnfrozenRows == false); + const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); + table->IsUnfrozenRows = true; + TableGetInstanceData(table, table->InstanceCurrent)->LastFrozenHeight = y0 - table->OuterRect.Min.y; + + // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); + table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; + table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; + IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); + + float row_height = table->RowPosY2 - table->RowPosY1; + table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; + table->RowPosY1 = table->RowPosY2 - row_height; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->DrawChannelCurrent = column->DrawChannelUnfrozen; + column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; + } + + // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y + SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + } + + if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) + table->RowBgColorCounter++; + table->IsInsideRow = false; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns changes +//------------------------------------------------------------------------- +// - TableGetColumnIndex() +// - TableSetColumnIndex() +// - TableNextColumn() +// - TableBeginCell() [Internal] +// - TableEndCell() [Internal] +//------------------------------------------------------------------------- + +int ImGui::TableGetColumnIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentColumn; +} + +// [Public] Append into a specific column +bool ImGui::TableSetColumnIndex(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->CurrentColumn != column_n) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + IM_ASSERT(column_n >= 0 && table->ColumnsCount); + TableBeginCell(table, column_n); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return table->Columns[column_n].IsRequestOutput; +} + +// [Public] Append into the next column, wrap and create a new row when already on last column +bool ImGui::TableNextColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + TableBeginCell(table, table->CurrentColumn + 1); + } + else + { + TableNextRow(); + TableBeginCell(table, 0); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return table->Columns[table->CurrentColumn].IsRequestOutput; +} + + +// [Internal] Called by TableSetColumnIndex()/TableNextColumn() +// This is called very frequently, so we need to be mindful of unnecessary overhead. +// FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns. +void ImGui::TableBeginCell(ImGuiTable* table, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTableColumn* column = &table->Columns[column_n]; + ImGuiWindow* window = table->InnerWindow; + table->CurrentColumn = column_n; + + // Start position is roughly ~~ CellRect.Min + CellPadding + Indent + float start_x = column->WorkMinX; + if (column->Flags & ImGuiTableColumnFlags_IndentEnable) + start_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row. + + window->DC.CursorPos.x = start_x; + window->DC.CursorPos.y = table->RowPosY1 + table->CellPaddingY; + window->DC.CursorMaxPos.x = window->DC.CursorPos.x; + window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT + window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; + window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; + + window->WorkRect.Min.y = window->DC.CursorPos.y; + window->WorkRect.Min.x = column->WorkMinX; + window->WorkRect.Max.x = column->WorkMaxX; + window->DC.ItemWidth = column->ItemWidth; + + window->SkipItems = column->IsSkipItems; + if (column->IsSkipItems) + { + g.LastItemData.ID = 0; + g.LastItemData.StatusFlags = 0; + } + + if (table->Flags & ImGuiTableFlags_NoClip) + { + // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP); + } + else + { + // FIXME-TABLE: Could avoid this if draw channel is dummy channel? + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + } + + // Logging + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } +} + +// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() +void ImGui::TableEndCell(ImGuiTable* table) +{ + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + ImGuiWindow* window = table->InnerWindow; + + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + + // Report maximum position so we can infer content size per column. + float* p_max_pos_x; + if (table->RowFlags & ImGuiTableRowFlags_Headers) + p_max_pos_x = &column->ContentMaxXHeadersUsed; // Useful in case user submit contents in header row that is not a TableHeader() call + else + p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; + *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); + if (column->IsEnabled) + table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); + column->ItemWidth = window->DC.ItemWidth; + + // Propagate text baseline for the entire row + // FIXME-TABLE: Here we propagate text baseline from the last line of the cell.. instead of the first one. + table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns width management +//------------------------------------------------------------------------- +// - TableGetMaxColumnWidth() [Internal] +// - TableGetColumnWidthAuto() [Internal] +// - TableSetColumnWidth() +// - TableSetColumnWidthAutoSingle() [Internal] +// - TableSetColumnWidthAutoAll() [Internal] +// - TableUpdateColumnsWeightFromWidth() [Internal] +//------------------------------------------------------------------------- + +// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. +float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float max_width = FLT_MAX; + const float min_column_distance = table->MinColumnWidth + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2; + if (table->Flags & ImGuiTableFlags_ScrollX) + { + // Frozen columns can't reach beyond visible width else scrolling will naturally break. + // (we use DisplayOrder as within a set of multiple frozen column reordering is possible) + if (column->DisplayOrder < table->FreezeColumnsRequest) + { + max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX; + max_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2; + } + } + else if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0) + { + // If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make + // sure they are all visible. Because of this we also know that all of the columns will always fit in + // table->WorkRect and therefore in table->InnerRect (because ScrollX is off) + // FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match. + // See "table_width_distrib" and "table_width_keep_visible" tests + max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX; + //max_width -= table->CellSpacingX1; + max_width -= table->CellSpacingX2; + max_width -= table->CellPaddingX * 2.0f; + max_width -= table->OuterPaddingX; + } + return max_width; +} + +// Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field +float ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column) +{ + const float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; + const float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX; + float width_auto = content_width_body; + if (!(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth)) + width_auto = ImMax(width_auto, content_width_headers); + + // Non-resizable fixed columns preserve their requested width + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) + if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize)) + width_auto = column->InitStretchWeightOrWidth; + + return ImMax(width_auto, table->MinColumnWidth); +} + +// 'width' = inner column width, without padding +void ImGui::TableSetColumnWidth(int column_n, float width) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && table->IsLayoutLocked == false); + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column_0 = &table->Columns[column_n]; + float column_0_width = width; + + // Apply constraints early + // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) + IM_ASSERT(table->MinColumnWidth > 0.0f); + const float min_width = table->MinColumnWidth; + const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); + column_0_width = ImClamp(column_0_width, min_width, max_width); + if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) + return; + + //IMGUI_DEBUG_PRINT("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width); + ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; + + // In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns. + // - All fixed: easy. + // - All stretch: easy. + // - One or more fixed + one stretch: easy. + // - One or more fixed + more than one stretch: tricky. + // Qt when manual resize is enabled only supports a single _trailing_ stretch column, we support more cases here. + + // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. + // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. + // Scenarios: + // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset. + // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered. + // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size. + // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 W3 resize from W1| or W2| --> ok + // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 F3 resize from W1| or W2| --> ok + // - W1 F2 W3 resize from W1| or F2| --> ok + // - F1 W2 F3 resize from W2| --> ok + // - F1 W3 F2 resize from W3| --> ok + // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. + // - W1 F2 F3 resize from F2| --> ok + // All resizes from a Wx columns are locking other columns. + + // Possible improvements: + // - W1 W2 W3 resize W1| --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns. + // - W3 F1 F2 resize W3| --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix. + + // [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout(). + + // If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize. + // This is the preferred resize path + if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed) + if (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder) + { + column_0->WidthRequest = column_0_width; + table->IsSettingsDirty = true; + return; + } + + // We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column) + if (column_1 == NULL) + column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; + if (column_1 == NULL) + return; + + // Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column. + // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) + float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); + column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + IM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f); + column_0->WidthRequest = column_0_width; + column_1->WidthRequest = column_1_width; + if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch) + TableUpdateColumnsWeightFromWidth(table); + table->IsSettingsDirty = true; +} + +// Disable clipping then auto-fit, will take 2 frames +// (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns) +void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n) +{ + // Single auto width uses auto-fit + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled) + return; + column->CannotSkipItemsQueue = (1 << 0); + table->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n; +} + +void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table) +{ + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column + continue; + column->CannotSkipItemsQueue = (1 << 0); + column->AutoFitQueue = (1 << 1); + } +} + +void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) +{ + IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1); + + // Measure existing quantities + float visible_weight = 0.0f; + float visible_width = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + IM_ASSERT(column->StretchWeight > 0.0f); + visible_weight += column->StretchWeight; + visible_width += column->WidthRequest; + } + IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); + + // Apply new weights + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->StretchWeight = (column->WidthRequest / visible_width) * visible_weight; + IM_ASSERT(column->StretchWeight > 0.0f); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Drawing +//------------------------------------------------------------------------- +// - TablePushBackgroundChannel() [Internal] +// - TablePopBackgroundChannel() [Internal] +// - TableSetupDrawChannels() [Internal] +// - TableMergeDrawChannels() [Internal] +// - TableDrawBorders() [Internal] +//------------------------------------------------------------------------- + +// Bg2 is used by Selectable (and possibly other widgets) to render to the background. +// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect. +void ImGui::TablePushBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + table->HostBackupInnerClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent); +} + +void ImGui::TablePopBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); +} + +// Allocate draw channels. Called by TableUpdateLayout() +// - We allocate them following storage order instead of display order so reordering columns won't needlessly +// increase overall dormant memory cost. +// - We isolate headers draw commands in their own channels instead of just altering clip rects. +// This is in order to facilitate merging of draw commands. +// - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels. +// - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other +// channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged. +// - We allocate 1 or 2 background draw channels. This is because we know TablePushBackgroundChannel() is only used for +// horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4). +// Draw channel allocation (before merging): +// - NoClip --> 2+D+1 channels: bg0/1 + bg2 + foreground (same clip rect == always 1 draw call) +// - Clip --> 2+D+N channels +// - FreezeRows --> 2+D+N*2 (unless scrolling value is zero) +// - FreezeRows || FreezeColunns --> 3+D+N*2 (unless scrolling value is zero) +// Where D is 1 if any column is clipped or hidden (dummy channel) otherwise 0. +void ImGui::TableSetupDrawChannels(ImGuiTable* table) +{ + const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; + const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount; + const int channels_for_bg = 1 + 1 * freeze_row_multiplier; + const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0; + const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; + table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); + table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); + table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN; + table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN); + + int draw_channel_current = 2; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsVisibleX && column->IsVisibleY) + { + column->DrawChannelFrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current); + column->DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row + 1 : 0)); + if (!(table->Flags & ImGuiTableFlags_NoClip)) + draw_channel_current++; + } + else + { + column->DrawChannelFrozen = column->DrawChannelUnfrozen = table->DummyDrawChannel; + } + column->DrawChannelCurrent = column->DrawChannelFrozen; + } + + // Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default. + // All our cell highlight are manually clipped with BgClipRect. When unfreezing it will be made smaller to fit scrolling rect. + // (This technically isn't part of setting up draw channels, but is reasonably related to be done here) + table->BgClipRect = table->InnerClipRect; + table->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect; + table->Bg2ClipRectForDrawCmd = table->HostClipRect; + IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y); +} + +// This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable(). +// For simplicity we call it TableMergeDrawChannels() but in fact it only reorder channels + overwrite ClipRect, +// actual merging is done by table->DrawSplitter.Merge() which is called right after TableMergeDrawChannels(). +// +// Columns where the contents didn't stray off their local clip rectangle can be merged. To achieve +// this we merge their clip rect and make them contiguous in the channel list, so they can be merged +// by the call to DrawSplitter.Merge() following to the call to this function. +// We reorder draw commands by arranging them into a maximum of 4 distinct groups: +// +// 1 group: 2 groups: 2 groups: 4 groups: +// [ 0. ] no freeze [ 0. ] row freeze [ 01 ] col freeze [ 01 ] row+col freeze +// [ .. ] or no scroll [ 2. ] and v-scroll [ .. ] and h-scroll [ 23 ] and v+h-scroll +// +// Each column itself can use 1 channel (row freeze disabled) or 2 channels (row freeze enabled). +// When the contents of a column didn't stray off its limit, we move its channels into the corresponding group +// based on its position (within frozen rows/columns groups or not). +// At the end of the operation our 1-4 groups will each have a ImDrawCmd using the same ClipRect. +// This function assume that each column are pointing to a distinct draw channel, +// otherwise merge_group->ChannelsCount will not match set bit count of merge_group->ChannelsMask. +// +// Column channels will not be merged into one of the 1-4 groups in the following cases: +// - The contents stray off its clipping rectangle (we only compare the MaxX value, not the MinX value). +// Direct ImDrawList calls won't be taken into account by default, if you use them make sure the ImGui:: bounds +// matches, by e.g. calling SetCursorScreenPos(). +// - The channel uses more than one draw command itself. We drop all our attempt at merging stuff here.. +// we could do better but it's going to be rare and probably not worth the hassle. +// Columns for which the draw channel(s) haven't been merged with other will use their own ImDrawCmd. +// +// This function is particularly tricky to understand.. take a breath. +void ImGui::TableMergeDrawChannels(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImDrawListSplitter* splitter = table->DrawSplitter; + const bool has_freeze_v = (table->FreezeRowsCount > 0); + const bool has_freeze_h = (table->FreezeColumnsCount > 0); + IM_ASSERT(splitter->_Current == 0); + + // Track which groups we are going to attempt to merge, and which channels goes into each group. + struct MergeGroup + { + ImRect ClipRect; + int ChannelsCount = 0; + ImBitArrayPtr ChannelsMask = NULL; + }; + int merge_group_mask = 0x00; + MergeGroup merge_groups[4]; + + // Use a reusable temp buffer for the merge masks as they are dynamically sized. + const int max_draw_channels = (4 + table->ColumnsCount * 2); + const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels); + g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5); + memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5); + for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++) + merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n)); + ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4)); + + // 1. Scan channels and take note of those which can be merged + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const int merge_group_sub_count = has_freeze_v ? 2 : 1; + for (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++) + { + const int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen; + + // Don't attempt to merge if there are multiple draw calls within the column + ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; + if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() + src_channel->_CmdBuffer.pop_back(); + if (src_channel->_CmdBuffer.Size != 1) + continue; + + // Find out the width of this merge group and check if it will fit in our column + // (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it) + if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) + { + float content_max_x; + if (!has_freeze_v) + content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze + else if (merge_group_sub_n == 0) + content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); // Row freeze: use width before freeze + else + content_max_x = column->ContentMaxXUnfrozen; // Row freeze: use width after freeze + if (content_max_x > column->ClipRect.Max.x) + continue; + } + + const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); + IM_ASSERT(channel_no < max_draw_channels); + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + ImBitArraySetBit(merge_group->ChannelsMask, channel_no); + merge_group->ChannelsCount++; + merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); + merge_group_mask |= (1 << merge_group_n); + } + + // Invalidate current draw channel + // (we don't clear DrawChannelFrozen/DrawChannelUnfrozen solely to facilitate debugging/later inspection of data) + column->DrawChannelCurrent = (ImGuiTableDrawChannelIdx)-1; + } + + // [DEBUG] Display merge groups +#if 0 + if (g.IO.KeyShift) + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + continue; + char buf[32]; + ImFormatString(buf, 32, "MG%d:%d", merge_group_n, merge_group->ChannelsCount); + ImVec2 text_pos = merge_group->ClipRect.Min + ImVec2(4, 4); + ImVec2 text_size = CalcTextSize(buf, NULL); + GetForegroundDrawList()->AddRectFilled(text_pos, text_pos + text_size, IM_COL32(0, 0, 0, 255)); + GetForegroundDrawList()->AddText(text_pos, IM_COL32(255, 255, 0, 255), buf, NULL); + GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 255, 0, 255)); + } +#endif + + // 2. Rewrite channel list in our preferred order + if (merge_group_mask != 0) + { + // We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels(). + const int LEADING_DRAW_CHANNELS = 2; + g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized + ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; + ImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count); + ImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen); + IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); + int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS); + //ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect; + ImRect host_rect = table->HostClipRect; + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + if (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + ImRect merge_clip_rect = merge_group->ClipRect; + + // Extend outer-most clip limits to match those of host, so draw calls can be merged even if + // outer-most columns have some outer padding offsetting them from their parent ClipRect. + // The principal cases this is dealing with are: + // - On a same-window table (not scrolling = single group), all fitting columns ClipRect -> will extend and match host ClipRect -> will merge + // - Columns can use padding and have left-most ClipRect.Min.x and right-most ClipRect.Max.x != from host ClipRect -> will extend and match host ClipRect -> will merge + // FIXME-TABLE FIXME-WORKRECT: We are wasting a merge opportunity on tables without scrolling if column doesn't fit + // within host clip rect, solely because of the half-padding difference between window->WorkRect and window->InnerClipRect. + if ((merge_group_n & 1) == 0 || !has_freeze_h) + merge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x); + if ((merge_group_n & 2) == 0 || !has_freeze_v) + merge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y); + if ((merge_group_n & 1) != 0) + merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x); + if ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0) + merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y); + //GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); // [DEBUG] + //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); + //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); + remaining_count -= merge_group->ChannelsCount; + for (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++) + remaining_mask[n] &= ~merge_group->ChannelsMask[n]; + for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) + { + // Copy + overwrite new clip rect + if (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n)) + continue; + IM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n); + merge_channels_count--; + + ImDrawChannel* channel = &splitter->_Channels[n]; + IM_ASSERT(channel->_CmdBuffer.Size == 1 && merge_clip_rect.Contains(ImRect(channel->_CmdBuffer[0].ClipRect))); + channel->_CmdBuffer[0].ClipRect = merge_clip_rect.ToVec4(); + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + } + } + + // Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1) + if (merge_group_n == 1 && has_freeze_v) + memcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel)); + } + + // Append unmergeable channels that we didn't reorder at the end of the list + for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) + { + if (!IM_BITARRAY_TESTBIT(remaining_mask, n)) + continue; + ImDrawChannel* channel = &splitter->_Channels[n]; + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + remaining_count--; + } + IM_ASSERT(dst_tmp == g.DrawChannelsTempMergeBuffer.Data + g.DrawChannelsTempMergeBuffer.Size); + memcpy(splitter->_Channels.Data + LEADING_DRAW_CHANNELS, g.DrawChannelsTempMergeBuffer.Data, (splitter->_Count - LEADING_DRAW_CHANNELS) * sizeof(ImDrawChannel)); + } +} + +// FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow) +void ImGui::TableDrawBorders(ImGuiTable* table) +{ + ImGuiWindow* inner_window = table->InnerWindow; + if (!table->OuterWindow->ClipRect.Overlaps(table->OuterRect)) + return; + + ImDrawList* inner_drawlist = inner_window->DrawList; + table->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0); + inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false); + + // Draw inner border and resizing feedback + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + const float border_size = TABLE_BORDER_SIZE; + const float draw_y1 = table->InnerRect.Min.y; + const float draw_y2_body = table->InnerRect.Max.y; + const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1; + if (table->Flags & ImGuiTableFlags_BordersInnerV) + { + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + const bool is_hovered = (table->HoveredColumnBorder == column_n); + const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent); + const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0; + const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1); + if (column->MaxX > table->InnerClipRect.Max.x && !is_resized) + continue; + + // Decide whether right-most column is visible + if (column->NextEnabledColumn == -1 && !is_resizable) + if ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || (table->Flags & ImGuiTableFlags_NoHostExtendX)) + continue; + if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. + continue; + + // Draw in outer window so right-most column won't be clipped + // Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling. + ImU32 col; + float draw_y2; + if (is_hovered || is_resized || is_frozen_separator) + { + draw_y2 = draw_y2_body; + col = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong; + } + else + { + draw_y2 = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? draw_y2_head : draw_y2_body; + col = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? table->BorderColorStrong : table->BorderColorLight; + } + + if (draw_y2 > draw_y1) + inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), col, border_size); + } + } + + // Draw outer border + // FIXME: could use AddRect or explicit VLine/HLine helper? + if (table->Flags & ImGuiTableFlags_BordersOuter) + { + // Display outer border offset by 1 which is a simple way to display it without adding an extra draw call + // (Without the offset, in outer_window it would be rendered behind cells, because child windows are above their + // parent. In inner_window, it won't reach out over scrollbars. Another weird solution would be to display part + // of it in inner window, and the part that's over scrollbars in the outer window..) + // Either solution currently won't allow us to use a larger border size: the border would clipped. + const ImRect outer_border = table->OuterRect; + const ImU32 outer_col = table->BorderColorStrong; + if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) + { + inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterV) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterH) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size); + } + } + if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y) + { + // Draw bottom-most row border + const float border_y = table->RowPosY2; + if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y) + inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size); + } + + inner_drawlist->PopClipRect(); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Sorting +//------------------------------------------------------------------------- +// - TableGetSortSpecs() +// - TableFixColumnSortDirection() [Internal] +// - TableGetColumnNextSortDirection() [Internal] +// - TableSetColumnSortDirection() [Internal] +// - TableSortSpecsSanitize() [Internal] +// - TableSortSpecsBuild() [Internal] +//------------------------------------------------------------------------- + +// Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set) +// You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since +// last call, or the first time. +// Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! +ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + + if (!(table->Flags & ImGuiTableFlags_Sortable)) + return NULL; + + // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + TableSortSpecsBuild(table); + return &table->SortSpecs; +} + +static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) +{ + IM_ASSERT(n < column->SortDirectionsAvailCount); + return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; +} + +// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) +void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column) +{ + if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0) + return; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + table->IsSortSpecsDirty = true; +} + +// Calculate next sort direction that would be set after clicking the column +// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click. +// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op. +IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2); +ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column) +{ + IM_ASSERT(column->SortDirectionsAvailCount > 0); + if (column->SortOrder == -1) + return TableGetColumnAvailSortDirection(column, 0); + for (int n = 0; n < 3; n++) + if (column->SortDirection == TableGetColumnAvailSortDirection(column, n)) + return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount); + IM_ASSERT(0); + return ImGuiSortDirection_None; +} + +// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert +// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. +void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!(table->Flags & ImGuiTableFlags_SortMulti)) + append_to_sort_specs = false; + if (!(table->Flags & ImGuiTableFlags_SortTristate)) + IM_ASSERT(sort_direction != ImGuiSortDirection_None); + + ImGuiTableColumnIdx sort_order_max = 0; + if (append_to_sort_specs) + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder); + + ImGuiTableColumn* column = &table->Columns[column_n]; + column->SortDirection = (ImU8)sort_direction; + if (column->SortDirection == ImGuiSortDirection_None) + column->SortOrder = -1; + else if (column->SortOrder == -1 || !append_to_sort_specs) + column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0; + + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column != column && !append_to_sort_specs) + other_column->SortOrder = -1; + TableFixColumnSortDirection(table, other_column); + } + table->IsSettingsDirty = true; + table->IsSortSpecsDirty = true; +} + +void ImGui::TableSortSpecsSanitize(ImGuiTable* table) +{ + IM_ASSERT(table->Flags & ImGuiTableFlags_Sortable); + + // Clear SortOrder from hidden column and verify that there's no gap or duplicate. + int sort_order_count = 0; + ImU64 sort_order_mask = 0x00; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder != -1 && !column->IsEnabled) + column->SortOrder = -1; + if (column->SortOrder == -1) + continue; + sort_order_count++; + sort_order_mask |= ((ImU64)1 << column->SortOrder); + IM_ASSERT(sort_order_count < (int)sizeof(sort_order_mask) * 8); + } + + const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1); + const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti); + if (need_fix_linearize || need_fix_single_sort_order) + { + ImU64 fixed_mask = 0x00; + for (int sort_n = 0; sort_n < sort_order_count; sort_n++) + { + // Fix: Rewrite sort order fields if needed so they have no gap or duplicate. + // (e.g. SortOrder 0 disappeared, SortOrder 1..2 exists --> rewrite then as SortOrder 0..1) + int column_with_smallest_sort_order = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if ((fixed_mask & ((ImU64)1 << (ImU64)column_n)) == 0 && table->Columns[column_n].SortOrder != -1) + if (column_with_smallest_sort_order == -1 || table->Columns[column_n].SortOrder < table->Columns[column_with_smallest_sort_order].SortOrder) + column_with_smallest_sort_order = column_n; + IM_ASSERT(column_with_smallest_sort_order != -1); + fixed_mask |= ((ImU64)1 << column_with_smallest_sort_order); + table->Columns[column_with_smallest_sort_order].SortOrder = (ImGuiTableColumnIdx)sort_n; + + // Fix: Make sure only one column has a SortOrder if ImGuiTableFlags_MultiSortable is not set. + if (need_fix_single_sort_order) + { + sort_order_count = 1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (column_n != column_with_smallest_sort_order) + table->Columns[column_n].SortOrder = -1; + break; + } + } + } + + // Fallback default sort order (if no column with the ImGuiTableColumnFlags_DefaultSort flag) + if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + sort_order_count = 1; + column->SortOrder = 0; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + break; + } + } + + table->SortSpecsCount = (ImGuiTableColumnIdx)sort_order_count; +} + +void ImGui::TableSortSpecsBuild(ImGuiTable* table) +{ + bool dirty = table->IsSortSpecsDirty; + if (dirty) + { + TableSortSpecsSanitize(table); + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + table->SortSpecs.SpecsDirty = true; // Mark as dirty for user + table->IsSortSpecsDirty = false; // Mark as not dirty for us + } + + // Write output + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + if (dirty && sort_specs != NULL) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder == -1) + continue; + IM_ASSERT(column->SortOrder < table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; + sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; + sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; + sort_spec->SortDirection = column->SortDirection; + } + + table->SortSpecs.Specs = sort_specs; + table->SortSpecs.SpecsCount = table->SortSpecsCount; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Headers +//------------------------------------------------------------------------- +// - TableGetHeaderRowHeight() [Internal] +// - TableHeadersRow() +// - TableHeader() +//------------------------------------------------------------------------- + +float ImGui::TableGetHeaderRowHeight() +{ + // Caring for a minor edge case: + // Calculate row height, for the unlikely case that some labels may be taller than others. + // If we didn't do that, uneven header height would highlight but smaller one before the tallest wouldn't catch input for all height. + // In your custom header row you may omit this all together and just call TableNextRow() without a height... + float row_height = GetTextLineHeight(); + int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + ImGuiTableColumnFlags flags = TableGetColumnFlags(column_n); + if ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel)) + row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y); + } + row_height += GetStyle().CellPadding.y * 2.0f; + return row_height; +} + +// [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn(). +// The intent is that advanced users willing to create customized headers would not need to use this helper +// and can create their own! For example: TableHeader() may be preceeded by Checkbox() or other custom widgets. +// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this. +// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy. +// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public. +void ImGui::TableHeadersRow() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + + // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout) + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + // Open row + const float row_y1 = GetCursorScreenPos().y; + const float row_height = TableGetHeaderRowHeight(); + TableNextRow(ImGuiTableRowFlags_Headers, row_height); + if (table->HostSkipItems) // Merely an optimization, you may skip in your own code. + return; + + const int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + if (!TableSetColumnIndex(column_n)) + continue; + + // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) + // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide. + const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); + PushID(column_n); + TableHeader(name); + PopID(); + } + + // Allow opening popup from the right-most section after the last column. + ImVec2 mouse_pos = ImGui::GetMousePos(); + if (IsMouseReleased(1) && TableGetHoveredColumn() == columns_count) + if (mouse_pos.y >= row_y1 && mouse_pos.y < row_y1 + row_height) + TableOpenContextMenu(-1); // Will open a non-column-specific popup. +} + +// Emit a column header (text + optional sort order) +// We cpu-clip text here so that all columns headers can be merged into a same draw call. +// Note that because of how we cpu-clip and display sorting indicators, you _cannot_ use SameLine() after a TableHeader() +void ImGui::TableHeader(const char* label) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!"); + IM_ASSERT(table->CurrentColumn != -1); + const int column_n = table->CurrentColumn; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Label + if (label == NULL) + label = ""; + const char* label_end = FindRenderedTextEnd(label); + ImVec2 label_size = CalcTextSize(label, label_end, true); + ImVec2 label_pos = window->DC.CursorPos; + + // If we already got a row height, there's use that. + // FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect? + ImRect cell_r = TableGetCellBgRect(table, column_n); + float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f); + + // Calculate ideal size for sort order arrow + float w_arrow = 0.0f; + float w_sort_text = 0.0f; + char sort_order_suf[4] = ""; + const float ARROW_SCALE = 0.65f; + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x); + if (column->SortOrder > 0) + { + ImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), "%d", column->SortOrder + 1); + w_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x; + } + } + + // We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging. + float max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow; + column->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX); + column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x); + + // Keep header highlighted when context menu is open. + const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent); + ImGuiID id = window->GetID(label); + ImRect bb(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0f)); + ItemSize(ImVec2(0.0f, label_height)); // Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal + if (!ItemAdd(bb, id)) + return; + + //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + + // Using AllowItemOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + if (held || hovered || selected) + { + const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + //RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); + } + else + { + // Submit single cell bg color in the case we didn't submit a full header row + if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + if (held) + table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; + window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; + + // Drag and drop to re-order columns. + // FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone. + if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive) + { + // While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x + table->ReorderColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + + // We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder. + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x) + if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL) + if (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = -1; + if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x) + if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL) + if (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = +1; + } + + // Sort order arrow + const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x); + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + if (column->SortOrder != -1) + { + float x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text); + float y = label_pos.y; + if (column->SortOrder > 0) + { + PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text, 0.70f)); + RenderText(ImVec2(x + g.Style.ItemInnerSpacing.x, y), sort_order_suf); + PopStyleColor(); + x += w_sort_text; + } + RenderArrow(window->DrawList, ImVec2(x, y), GetColorU32(ImGuiCol_Text), column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE); + } + + // Handle clicking on column header to adjust Sort Order + if (pressed && table->ReorderColumn != column_n) + { + ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column); + TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); + } + } + + // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will + // be merged into a single draw call. + //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); + + const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); + if (text_clipped && hovered && g.ActiveId == 0 && IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + SetTooltip("%.*s", (int)(label_end - label), label); + + // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden + if (IsMouseReleased(1) && IsItemHovered()) + TableOpenContextMenu(column_n); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Context Menu +//------------------------------------------------------------------------- +// - TableOpenContextMenu() [Internal] +// - TableDrawContextMenu() [Internal] +//------------------------------------------------------------------------- + +// Use -1 to open menu not specific to a given column. +void ImGui::TableOpenContextMenu(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (column_n == -1 && table->CurrentColumn != -1) // When called within a column automatically use this one (for consistency) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) // To facilitate using with TableGetHoveredColumn() + column_n = -1; + IM_ASSERT(column_n >= -1 && column_n < table->ColumnsCount); + if (table->Flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + table->IsContextPopupOpen = true; + table->ContextPopupColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + OpenPopupEx(context_menu_id, ImGuiPopupFlags_None); + } +} + +bool ImGui::TableBeginContextMenuPopup(ImGuiTable* table) +{ + if (!table->IsContextPopupOpen || table->InstanceCurrent != table->InstanceInteracted) + return false; + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) + return true; + table->IsContextPopupOpen = false; + return false; +} + +// Output context menu into current window (generally a popup) +// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data? +void ImGui::TableDrawContextMenu(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + bool want_separator = false; + const int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1; + ImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL; + + // Sizing + if (table->Flags & ImGuiTableFlags_Resizable) + { + if (column != NULL) + { + const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled; + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // "###SizeOne" + TableSetColumnWidthAutoSingle(table, column_n); + } + + const char* size_all_desc; + if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame) + size_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllFit); // "###SizeAll" All fixed + else + size_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllDefault); // "###SizeAll" All stretch or mixed + if (MenuItem(size_all_desc, NULL)) + TableSetColumnWidthAutoAll(table); + want_separator = true; + } + + // Ordering + if (table->Flags & ImGuiTableFlags_Reorderable) + { + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) + table->IsResetDisplayOrderRequest = true; + want_separator = true; + } + + // Reset all (should work but seems unnecessary/noisy to expose?) + //if (MenuItem("Reset all")) + // table->IsResetAllRequest = true; + + // Sorting + // (modify TableOpenContextMenu() to add _Sortable flag if enabling this) +#if 0 + if ((table->Flags & ImGuiTableFlags_Sortable) && column != NULL && (column->Flags & ImGuiTableColumnFlags_NoSort) == 0) + { + if (want_separator) + Separator(); + want_separator = true; + + bool append_to_sort_specs = g.IO.KeyShift; + if (MenuItem("Sort in Ascending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Ascending, (column->Flags & ImGuiTableColumnFlags_NoSortAscending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Ascending, append_to_sort_specs); + if (MenuItem("Sort in Descending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Descending, (column->Flags & ImGuiTableColumnFlags_NoSortDescending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Descending, append_to_sort_specs); + } +#endif + + // Hiding / Visibility + if (table->Flags & ImGuiTableFlags_Hideable) + { + if (want_separator) + Separator(); + want_separator = true; + + PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true); + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column->Flags & ImGuiTableColumnFlags_Disabled) + continue; + + const char* name = TableGetColumnName(table, other_column_n); + if (name == NULL || name[0] == 0) + name = ""; + + // Make sure we can't hide the last active column + bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true; + if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1) + menu_item_active = false; + if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active)) + other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled; + } + PopItemFlag(); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Settings (.ini data) +//------------------------------------------------------------------------- +// FIXME: The binding/finding/creating flow are too confusing. +//------------------------------------------------------------------------- +// - TableSettingsInit() [Internal] +// - TableSettingsCalcChunkSize() [Internal] +// - TableSettingsCreate() [Internal] +// - TableSettingsFindByID() [Internal] +// - TableGetBoundSettings() [Internal] +// - TableResetSettings() +// - TableSaveSettings() [Internal] +// - TableLoadSettings() [Internal] +// - TableSettingsHandler_ClearAll() [Internal] +// - TableSettingsHandler_ApplyAll() [Internal] +// - TableSettingsHandler_ReadOpen() [Internal] +// - TableSettingsHandler_ReadLine() [Internal] +// - TableSettingsHandler_WriteAll() [Internal] +// - TableSettingsInstallHandler() [Internal] +//------------------------------------------------------------------------- +// [Init] 1: TableSettingsHandler_ReadXXXX() Load and parse .ini file into TableSettings. +// [Main] 2: TableLoadSettings() When table is created, bind Table to TableSettings, serialize TableSettings data into Table. +// [Main] 3: TableSaveSettings() When table properties are modified, serialize Table data into bound or new TableSettings, mark .ini as dirty. +// [Main] 4: TableSettingsHandler_WriteAll() When .ini file is dirty (which can come from other source), save TableSettings into .ini file. +//------------------------------------------------------------------------- + +// Clear and initialize empty settings instance +static void TableSettingsInit(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max) +{ + IM_PLACEMENT_NEW(settings) ImGuiTableSettings(); + ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings(); + for (int n = 0; n < columns_count_max; n++, settings_column++) + IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings(); + settings->ID = id; + settings->ColumnsCount = (ImGuiTableColumnIdx)columns_count; + settings->ColumnsCountMax = (ImGuiTableColumnIdx)columns_count_max; + settings->WantApply = true; +} + +static size_t TableSettingsCalcChunkSize(int columns_count) +{ + return sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings); +} + +ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count) +{ + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count)); + TableSettingsInit(settings, id, columns_count, columns_count); + return settings; +} + +// Find existing settings +ImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id) +{ + // FIXME-OPT: Might want to store a lookup map for this? + ImGuiContext& g = *GImGui; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +// Get settings for a given table, NULL if none +ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table) +{ + if (table->SettingsOffset != -1) + { + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); + IM_ASSERT(settings->ID == table->ID); + if (settings->ColumnsCountMax >= table->ColumnsCount) + return settings; // OK + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return NULL; +} + +// Restore initial state of table (with or without saved settings) +void ImGui::TableResetSettings(ImGuiTable* table) +{ + table->IsInitializing = table->IsSettingsDirty = true; + table->IsResetAllRequest = false; + table->IsSettingsRequestLoad = false; // Don't reload from ini + table->SettingsLoadedFlags = ImGuiTableFlags_None; // Mark as nothing loaded so our initialized data becomes authoritative +} + +void ImGui::TableSaveSettings(ImGuiTable* table) +{ + table->IsSettingsDirty = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind or create settings data + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = TableGetBoundSettings(table); + if (settings == NULL) + { + settings = TableSettingsCreate(table->ID, table->ColumnsCount); + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + settings->ColumnsCount = (ImGuiTableColumnIdx)table->ColumnsCount; + + // Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings + IM_ASSERT(settings->ID == table->ID); + IM_ASSERT(settings->ColumnsCount == table->ColumnsCount && settings->ColumnsCountMax >= settings->ColumnsCount); + ImGuiTableColumn* column = table->Columns.Data; + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + + bool save_ref_scale = false; + settings->SaveFlags = ImGuiTableFlags_None; + for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) + { + const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; + column_settings->WidthOrWeight = width_or_weight; + column_settings->Index = (ImGuiTableColumnIdx)n; + column_settings->DisplayOrder = column->DisplayOrder; + column_settings->SortOrder = column->SortOrder; + column_settings->SortDirection = column->SortDirection; + column_settings->IsEnabled = column->IsUserEnabled; + column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0) + save_ref_scale = true; + + // We skip saving some data in the .ini file when they are unnecessary to restore our state. + // Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f. + // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present. + if (width_or_weight != column->InitStretchWeightOrWidth) + settings->SaveFlags |= ImGuiTableFlags_Resizable; + if (column->DisplayOrder != n) + settings->SaveFlags |= ImGuiTableFlags_Reorderable; + if (column->SortOrder != -1) + settings->SaveFlags |= ImGuiTableFlags_Sortable; + if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) + settings->SaveFlags |= ImGuiTableFlags_Hideable; + } + settings->SaveFlags &= table->Flags; + settings->RefScale = save_ref_scale ? table->RefScale : 0.0f; + + MarkIniSettingsDirty(); +} + +void ImGui::TableLoadSettings(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + table->IsSettingsRequestLoad = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind settings + ImGuiTableSettings* settings; + if (table->SettingsOffset == -1) + { + settings = TableSettingsFindByID(table->ID); + if (settings == NULL) + return; + if (settings->ColumnsCount != table->ColumnsCount) // Allow settings if columns count changed. We could otherwise decide to return... + table->IsSettingsDirty = true; + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + else + { + settings = TableGetBoundSettings(table); + } + + table->SettingsLoadedFlags = settings->SaveFlags; + table->RefScale = settings->RefScale; + + // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + ImU64 display_order_mask = 0; + for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++) + { + int column_n = column_settings->Index; + if (column_n < 0 || column_n >= table->ColumnsCount) + continue; + + ImGuiTableColumn* column = &table->Columns[column_n]; + if (settings->SaveFlags & ImGuiTableFlags_Resizable) + { + if (column_settings->IsStretch) + column->StretchWeight = column_settings->WidthOrWeight; + else + column->WidthRequest = column_settings->WidthOrWeight; + column->AutoFitQueue = 0x00; + } + if (settings->SaveFlags & ImGuiTableFlags_Reorderable) + column->DisplayOrder = column_settings->DisplayOrder; + else + column->DisplayOrder = (ImGuiTableColumnIdx)column_n; + display_order_mask |= (ImU64)1 << column->DisplayOrder; + column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled; + column->SortOrder = column_settings->SortOrder; + column->SortDirection = column_settings->SortDirection; + } + + // Validate and fix invalid display order data + const ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1; + if (display_order_mask != expected_display_order_mask) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n; + + // Rebuild index + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; +} + +static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + table->SettingsOffset = -1; + g.SettingsTables.clear(); +} + +// Apply to existing windows (if any) +static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + { + table->IsSettingsRequestLoad = true; + table->SettingsOffset = -1; + } +} + +static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiID id = 0; + int columns_count = 0; + if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2) + return NULL; + + if (ImGuiTableSettings* settings = ImGui::TableSettingsFindByID(id)) + { + if (settings->ColumnsCountMax >= columns_count) + { + TableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle + return settings; + } + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return ImGui::TableSettingsCreate(id, columns_count); +} + +static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + ImGuiTableSettings* settings = (ImGuiTableSettings*)entry; + float f = 0.0f; + int column_n = 0, r = 0, n = 0; + + if (sscanf(line, "RefScale=%f", &f) == 1) { settings->RefScale = f; return; } + + if (sscanf(line, "Column %d%n", &column_n, &r) == 1) + { + if (column_n < 0 || column_n >= settings->ColumnsCount) + return; + line = ImStrSkipBlank(line + r); + char c = 0; + ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n; + column->Index = (ImGuiTableColumnIdx)column_n; + if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; } + if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; } + if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; } + if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; } + } +} + +static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + ImGuiContext& g = *ctx; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + { + if (settings->ID == 0) // Skip ditched settings + continue; + + // TableSaveSettings() may clear some of those flags when we establish that the data can be stripped + // (e.g. Order was unchanged) + const bool save_size = (settings->SaveFlags & ImGuiTableFlags_Resizable) != 0; + const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0; + const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0; + const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0; + if (!save_size && !save_visible && !save_order && !save_sort) + continue; + + buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve + buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount); + if (settings->RefScale != 0.0f) + buf->appendf("RefScale=%g\n", settings->RefScale); + ImGuiTableColumnSettings* column = settings->GetColumnSettings(); + for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) + { + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); + if (!save_column) + continue; + buf->appendf("Column %-2d", column_n); + if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); } + if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); } + if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); } + if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); } + if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); } + if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); } + buf->append("\n"); + } + buf->append("\n"); + } +} + +void ImGui::TableSettingsAddSettingsHandler() +{ + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Table"; + ini_handler.TypeHash = ImHashStr("Table"); + ini_handler.ClearAllFn = TableSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = TableSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = TableSettingsHandler_WriteAll; + AddSettingsHandler(&ini_handler); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Garbage Collection +//------------------------------------------------------------------------- +// - TableRemove() [Internal] +// - TableGcCompactTransientBuffers() [Internal] +// - TableGcCompactSettings() [Internal] +//------------------------------------------------------------------------- + +// Remove Table (currently only used by TestEngine) +void ImGui::TableRemove(ImGuiTable* table) +{ + //IMGUI_DEBUG_PRINT("TableRemove() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + int table_idx = g.Tables.GetIndex(table); + //memset(table->RawData.Data, 0, table->RawData.size_in_bytes()); + //memset(table, 0, sizeof(ImGuiTable)); + g.Tables.Remove(table->ID, table); + g.TablesLastTimeActive[table_idx] = -1.0f; +} + +// Free up/compact internal Table buffers for when it gets unused +void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) +{ + //IMGUI_DEBUG_PRINT("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + IM_ASSERT(table->MemoryCompacted == false); + table->SortSpecs.Specs = NULL; + table->SortSpecsMulti.clear(); + table->IsSortSpecsDirty = true; // FIXME: In theory shouldn't have to leak into user performing a sort on resume. + table->ColumnsNames.clear(); + table->MemoryCompacted = true; + for (int n = 0; n < table->ColumnsCount; n++) + table->Columns[n].NameOffset = -1; + g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f; +} + +void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) +{ + temp_data->DrawSplitter.ClearFreeMemory(); + temp_data->LastTimeActive = -1.0f; +} + +// Compact and remove unused settings data (currently only used by TestEngine) +void ImGui::TableGcCompactSettings() +{ + ImGuiContext& g = *GImGui; + int required_memory = 0; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + required_memory += (int)TableSettingsCalcChunkSize(settings->ColumnsCount); + if (required_memory == g.SettingsTables.Buf.Size) + return; + ImChunkStream new_chunk_stream; + new_chunk_stream.Buf.reserve(required_memory); + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount)); + g.SettingsTables.swap(new_chunk_stream); +} + + +//------------------------------------------------------------------------- +// [SECTION] Tables: Debugging +//------------------------------------------------------------------------- +// - DebugNodeTable() [Internal] +//------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + +static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy) +{ + sizing_policy &= ImGuiTableFlags_SizingMask_; + if (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return "FixedFit"; } + if (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return "FixedSame"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return "StretchProp"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return "StretchSame"; } + return "N/A"; +} + +void ImGui::DebugNodeTable(ImGuiTable* table) +{ + const bool is_active = (table->LastFrameActive >= GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(table, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); + if (IsItemVisible() && table->HoveredColumnBody != -1) + GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + if (!open) + return; + if (table->InstanceCurrent > 0) + Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1); + bool clear_settings = SmallButton("Clear settings"); + BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags)); + BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); + BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); + BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); + BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); + //BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen); + float sum_weights = 0.0f; + for (int n = 0; n < table->ColumnsCount; n++) + if (table->Columns[n].Flags & ImGuiTableColumnFlags_WidthStretch) + sum_weights += table->Columns[n].StretchWeight; + for (int n = 0; n < table->ColumnsCount; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + const char* name = TableGetColumnName(table, n); + char buf[512]; + ImFormatString(buf, IM_ARRAYSIZE(buf), + "Column %d order %d '%s': offset %+.2f to %+.2f%s\n" + "Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n" + "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n" + "MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n" + "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n" + "Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..", + n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "", + column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen, + column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f, + column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x, + column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX, + column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags, + (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", + (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", + (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); + Bullet(); + Selectable(buf); + if (IsItemHovered()) + { + ImRect r(column->MinX, table->OuterRect.Min.y, column->MaxX, table->OuterRect.Max.y); + GetForegroundDrawList()->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255)); + } + } + if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) + DebugNodeTableSettings(settings); + if (clear_settings) + table->IsResetAllRequest = true; + TreePop(); +} + +void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings) +{ + if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount)) + return; + BulletText("SaveFlags: 0x%08X", settings->SaveFlags); + BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); + for (int n = 0; n < settings->ColumnsCount; n++) + { + ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; + ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; + BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X", + n, column_settings->DisplayOrder, column_settings->SortOrder, + (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", + column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID); + } + TreePop(); +} + +#else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS + +void ImGui::DebugNodeTable(ImGuiTable*) {} +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} + +#endif + + +//------------------------------------------------------------------------- +// [SECTION] Columns, BeginColumns, EndColumns, etc. +// (This is a legacy API, prefer using BeginTable/EndTable!) +//------------------------------------------------------------------------- +// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.) +//------------------------------------------------------------------------- +// - SetWindowClipRectBeforeSetChannel() [Internal] +// - GetColumnIndex() +// - GetColumnsCount() +// - GetColumnOffset() +// - GetColumnWidth() +// - SetColumnOffset() +// - SetColumnWidth() +// - PushColumnClipRect() [Internal] +// - PushColumnsBackground() [Internal] +// - PopColumnsBackground() [Internal] +// - FindOrCreateColumns() [Internal] +// - GetColumnsID() [Internal] +// - BeginColumns() +// - NextColumn() +// - EndColumns() +// - Columns() +//------------------------------------------------------------------------- + +// [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences, +// they would meddle many times with the underlying ImDrawCmd. +// Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let +// the subsequent single call to SetCurrentChannel() does it things once. +void ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect) +{ + ImVec4 clip_rect_vec4 = clip_rect.ToVec4(); + window->ClipRect = clip_rect; + window->DrawList->_CmdHeader.ClipRect = clip_rect_vec4; + window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4; +} + +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; +} + +float ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm) +{ + return offset_norm * (columns->OffMaxX - columns->OffMinX); +} + +float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset) +{ + return offset / (columns->OffMaxX - columns->OffMinX); +} + +static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; + +static float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index) +{ + // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing + // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. + IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); + + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; + x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); + if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) + x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); + + return x; +} + +float ImGui::GetColumnOffset(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return 0.0f; + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const float t = columns->Columns[column_index].OffsetNorm; + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); + return x_offset; +} + +static float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false) +{ + if (column_index < 0) + column_index = columns->Current; + + float offset_norm; + if (before_resize) + offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; + else + offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; + return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); +} + +float ImGui::GetColumnWidth(int column_index) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return GetContentRegionAvail().x; + + if (column_index < 0) + column_index = columns->Current; + return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); +} + +void ImGui::SetColumnOffset(int column_index, float offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1); + const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; + + if (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow)) + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); + + if (preserve_width) + SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); +} + +void ImGui::SetColumnWidth(int column_index, float width) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); +} + +void ImGui::PushColumnClipRect(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (column_index < 0) + column_index = columns->Current; + + ImGuiOldColumnData* column = &columns->Columns[column_index]; + PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); +} + +// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + columns->HostBackupClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, 0); +} + +void ImGui::PopColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); +} + +ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) +{ + // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. + for (int n = 0; n < window->ColumnsStorage.Size; n++) + if (window->ColumnsStorage[n].ID == id) + return &window->ColumnsStorage[n]; + + window->ColumnsStorage.push_back(ImGuiOldColumns()); + ImGuiOldColumns* columns = &window->ColumnsStorage.back(); + columns->ID = id; + return columns; +} + +ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) +{ + ImGuiWindow* window = GetCurrentWindow(); + + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. + PushID(0x11223347 + (str_id ? 0 : columns_count)); + ImGuiID id = window->GetID(str_id ? str_id : "columns"); + PopID(); + + return id; +} + +void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT(columns_count >= 1); + IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported + + // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); + ImGuiOldColumns* columns = FindOrCreateColumns(window, id); + IM_ASSERT(columns->ID == id); + columns->Current = 0; + columns->Count = columns_count; + columns->Flags = flags; + window->DC.CurrentColumns = columns; + window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); + + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostInitialClipRect = window->ClipRect; + columns->HostBackupParentWorkRect = window->ParentWorkRect; + window->ParentWorkRect = window->WorkRect; + + // Set state for first column + // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect + const float column_padding = g.Style.ItemSpacing.x; + const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); + const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); + const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; + columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); + columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; + + // Clear data if columns count changed + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + // Initialize default widths + columns->IsFirstFrame = (columns->Columns.Size == 0); + if (columns->Columns.Size == 0) + { + columns->Columns.reserve(columns_count + 1); + for (int n = 0; n < columns_count + 1; n++) + { + ImGuiOldColumnData column; + column.OffsetNorm = n / (float)columns_count; + columns->Columns.push_back(column); + } + } + + for (int n = 0; n < columns_count; n++) + { + // Compute clipping rectangle + ImGuiOldColumnData* column = &columns->Columns[n]; + float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); + float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); + column->ClipRect.ClipWithFull(window->ClipRect); + } + + if (columns->Count > 1) + { + columns->Splitter.Split(window->DrawList, 1 + columns->Count); + columns->Splitter.SetCurrentChannel(window->DrawList, 1); + PushColumnClipRect(0); + } + + // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::NextColumn() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems || window->DC.CurrentColumns == NULL) + return; + + ImGuiContext& g = *GImGui; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + + if (columns->Count == 1) + { + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + IM_ASSERT(columns->Current == 0); + return; + } + + // Next column + if (++columns->Current == columns->Count) + columns->Current = 0; + + PopItemWidth(); + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() + // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), + ImGuiOldColumnData* column = &columns->Columns[columns->Current]; + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); + + const float column_padding = g.Style.ItemSpacing.x; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + if (columns->Current > 0) + { + // Columns 1+ ignore IndentX (by canceling it out) + // FIXME-COLUMNS: Unnecessary, could be locked? + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; + } + else + { + // New row/line: column 0 honor IndentX. + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.IsSameLine = false; + columns->LineMinY = columns->LineMaxY; + } + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = columns->LineMinY; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = 0.0f; + + // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::EndColumns() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + PopItemWidth(); + if (columns->Count > 1) + { + PopClipRect(); + columns->Splitter.Merge(window->DrawList); + } + + const ImGuiOldColumnFlags flags = columns->Flags; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + window->DC.CursorPos.y = columns->LineMaxY; + if (!(flags & ImGuiOldColumnFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + + // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy + bool is_being_resized = false; + if (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) + { + // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); + const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); + int dragging_column = -1; + for (int n = 1; n < columns->Count; n++) + { + ImGuiOldColumnData* column = &columns->Columns[n]; + float x = window->Pos.x + GetColumnOffset(n); + const ImGuiID column_id = columns->ID + ImGuiID(n); + const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); + if (!ItemAdd(column_hit_rect, column_id, NULL, ImGuiItemFlags_NoNav)) + continue; + + bool hovered = false, held = false; + if (!(flags & ImGuiOldColumnFlags_NoResize)) + { + ButtonBehavior(column_hit_rect, column_id, &hovered, &held); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; + if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) + dragging_column = n; + } + + // Draw column + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const float xi = IM_FLOOR(x); + window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); + } + + // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. + if (dragging_column != -1) + { + if (!columns->IsBeingResized) + for (int n = 0; n < columns->Count + 1; n++) + columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; + columns->IsBeingResized = is_being_resized = true; + float x = GetDraggedColumnOffset(columns, dragging_column); + SetColumnOffset(dragging_column, x); + } + } + columns->IsBeingResized = is_being_resized; + + window->WorkRect = window->ParentWorkRect; + window->ParentWorkRect = columns->HostBackupParentWorkRect; + window->DC.CurrentColumns = NULL; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + NavUpdateCurrentWindowIsScrollPushableX(); +} + +void ImGui::Columns(int columns_count, const char* id, bool border) +{ + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(columns_count >= 1); + + ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); + //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) + return; + + if (columns != NULL) + EndColumns(); + + if (columns_count != 1) + BeginColumns(id, columns_count, flags); +} + +//------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE From 3feb650ab206516af5fce5247916c2e18dd1b2f4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 4 Jun 2023 23:32:15 +0300 Subject: [PATCH 082/212] fix WMO's skybox rendering --- src/ui/FrontendUI.cpp | 203 ++-- src/ui/FrontendUI.h | 4 +- .../src/engine/objects/ViewsObjects.cpp | 4 +- .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- .../vulkan/MapSceneRenderForwardVLK.cpp | 8 +- 6 files changed, 657 insertions(+), 582 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 67040c7f6..86691bd63 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -106,8 +106,9 @@ void FrontendUI::composeUI() { } -// if (show_demo_window) -// ImGui::ShowDemoWindow(&show_demo_window); + static bool show_demo_window = true; + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); if (m_databaseUpdateWorkflow != nullptr) { if (m_databaseUpdateWorkflow->isDatabaseUpdated()) { @@ -303,43 +304,57 @@ int ci_find_substr( const T& str1, const T& str2, const std::locale& loc = std:: if ( it != str1.end() ) return it - str1.begin(); else return -1; // not found } -void FrontendUI::filterMapList(std::string text) { +void FrontendUI::filterMapList(const std::string &text) { filteredMapList = {}; for (int i = 0; i < mapList.size(); i++) { auto ¤tRec = mapList[i]; if (text == "" || ( (ci_find_substr(currentRec.MapName, text) != std::string::npos) || - (ci_find_substr(currentRec.MapDirectory, text) != std::string::npos) + (ci_find_substr(currentRec.MapDirectory, text) != std::string::npos) || + (ci_find_substr(std::to_string(currentRec.ID), text) != std::string::npos) ) ) { filteredMapList.push_back(currentRec); } } } +void FrontendUI::fillMapListStrings() { + mapListStringMap = {}; + for (int i = 0; i < filteredMapList.size(); i++) { + auto mapRec = filteredMapList[i]; + + std::vector mapStrRec; + mapStrRec.push_back(std::to_string(mapRec.ID)); + mapStrRec.push_back(mapRec.MapName); + mapStrRec.push_back(mapRec.MapDirectory); + mapStrRec.push_back(std::to_string(mapRec.WdtFileID)); + mapStrRec.push_back(std::to_string(mapRec.MapType)); + + mapListStringMap.push_back(mapStrRec); + } +} void FrontendUI::showMapSelectionDialog() { if (showSelectMap) { + enum MyMapTableColumnID + { + MyItemColumnID_ID, + MyItemColumnID_Name, + MyItemColumnID_Directory, + MyItemColumnID_WDTId, + MyItemColumnID_MapType + }; + if (mapList.size() == 0) { getMapList(mapList); refilterIsNeeded = true; } if (refilterIsNeeded) { filterMapList(std::string(&filterText[0])); - mapListStringMap = {}; - for (int i = 0; i < filteredMapList.size(); i++) { - auto mapRec = filteredMapList[i]; - - std::vector mapStrRec; - mapStrRec.push_back(std::to_string(mapRec.ID)); - mapStrRec.push_back(mapRec.MapName); - mapStrRec.push_back(mapRec.MapDirectory); - mapStrRec.push_back(std::to_string(mapRec.WdtFileID)); - mapStrRec.push_back(std::to_string(mapRec.MapType)); - - mapListStringMap.push_back(mapStrRec); - } + fillMapListStrings(); refilterIsNeeded = false; + resortIsNeeded = true; } ImGui::Begin("Map Select Dialog", &showSelectMap); @@ -348,61 +363,108 @@ void FrontendUI::showMapSelectionDialog() { //Left panel { //Filter - if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), ImGuiInputTextFlags_AlwaysOverwrite)) { + if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), + ImGuiInputTextFlags_AlwaysOverwrite)) { refilterIsNeeded = true; } //The table + ImGui::BeginChild("Map Select Dialog Left panel"); + if (ImGui::BeginTable("MapListSelector", 5, ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Sortable | + ImGuiTableFlags_NoHostExtendX | + ImGuiTableFlags_NoHostExtendY | + ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, + ImVec2(-1, -1) + )){ + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_ID ); + ImGui::TableSetupColumn("MapName", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Name ); + ImGui::TableSetupColumn("MapDirectory", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Directory ); + ImGui::TableSetupColumn("WdtFileID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_WDTId ); + ImGui::TableSetupColumn("MapType", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_MapType ); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + + ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty) + resortIsNeeded = true; + + if (sorts_specs && resortIsNeeded) { + std::sort(filteredMapList.begin(), filteredMapList.end(), + [sorts_specs](const auto &a, const auto &b) -> bool { + + for (int n = 0; n < sorts_specs->SpecsCount; n++) + { + const ImGuiTableColumnSortSpecs* sort_spec = &sorts_specs->Specs[n]; + int delta = 0; + + switch (sort_spec->ColumnUserID) + { + + case MyItemColumnID_ID: delta = a.ID - b.ID; break; + case MyItemColumnID_Name: delta = a.MapName.compare(b.MapName); break; + case MyItemColumnID_Directory: delta = a.MapDirectory.compare(b.MapDirectory); break; + case MyItemColumnID_WDTId: delta = a.WdtFileID - b.WdtFileID; break; + case MyItemColumnID_MapType: delta = a.MapType - b.MapType; break; + + default: IM_ASSERT(0); break; + } + if (delta > 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? true : false; + if (delta < 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? false : true; + } + + return (a.ID - b.ID) > 0; + }); + + sorts_specs->SpecsDirty = false; + resortIsNeeded = false; + fillMapListStrings(); + } - ImGui::Columns(5, "mycolumns"); // 5-ways, with border - ImGui::Separator(); - ImGui::Text("ID"); - ImGui::NextColumn(); - ImGui::Text("MapName"); - ImGui::NextColumn(); - ImGui::Text("MapDirectory"); - ImGui::NextColumn(); - ImGui::Text("WdtFileID"); - ImGui::NextColumn(); - ImGui::Text("MapType"); - ImGui::NextColumn(); - ImGui::Separator(); + static int selected = -1; + for (int i = 0; i < filteredMapList.size(); i++) { + ImGui::TableNextRow(); + auto mapRec = filteredMapList[i]; + + ImGui::TableSetColumnIndex(0); + + if (ImGui::Selectable(mapListStringMap[i][0].c_str(), selected == i, + ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { + if (mapRec.ID != prevMapId) { + mapCanBeOpened = true; + adtMinimapFilled = false; + prevMapRec = mapRec; + + isWmoMap = false; + adtSelectionMinimapTextures = {}; + adtSelectionMinimapMaterials = {}; + if (mapRec.WdtFileID > 0) { + getAdtSelectionMinimap(mapRec.WdtFileID); + } else { + getAdtSelectionMinimap( + "world/maps/" + mapRec.MapDirectory + "/" + mapRec.MapDirectory + ".wdt"); + } - static int selected = -1; - for (int i = 0; i < filteredMapList.size(); i++) { - auto mapRec = filteredMapList[i]; - - if (ImGui::Selectable(mapListStringMap[i][0].c_str(), selected == i, ImGuiSelectableFlags_SpanAllColumns)) { - if (mapRec.ID != prevMapId) { - mapCanBeOpened = true; - adtMinimapFilled = false; - prevMapRec = mapRec; - - isWmoMap = false; - adtSelectionMinimapTextures = {}; - adtSelectionMinimapMaterials = {}; - if (mapRec.WdtFileID > 0) { - getAdtSelectionMinimap(mapRec.WdtFileID); - } else { - getAdtSelectionMinimap("world/maps/"+mapRec.MapDirectory+"/"+mapRec.MapDirectory+".wdt"); } - + prevMapId = mapRec.ID; + selected = i; } - prevMapId = mapRec.ID; - selected = i; + bool hovered = ImGui::IsItemHovered(); + + ImGui::TableSetColumnIndex(1); + ImGui::Text("%s", mapListStringMap[i][1].c_str()); + ImGui::TableSetColumnIndex(2); + ImGui::Text("%s", mapListStringMap[i][2].c_str()); + ImGui::TableSetColumnIndex(3); + ImGui::Text("%s", mapListStringMap[i][3].c_str()); + ImGui::TableSetColumnIndex(4); + ImGui::Text("%s", mapListStringMap[i][4].c_str()); } - bool hovered = ImGui::IsItemHovered(); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][1].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][2].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][3].c_str()); - ImGui::NextColumn(); - ImGui::Text("%s", mapListStringMap[i][4].c_str()); - ImGui::NextColumn(); + ImGui::EndTable(); } - ImGui::Columns(1); ImGui::Separator(); ImGui::EndChild(); } @@ -481,7 +543,7 @@ void FrontendUI::showAdtSelectionMinimap() { } } else { - ImGui::Dummy(ImVec2(100 * minimapZoom, 100 * minimapZoom)); + ImGui::Dummy(ImVec2(defaultImageDimension * minimapZoom, defaultImageDimension * minimapZoom)); } ImGui::SameLine(0, 0); @@ -511,10 +573,16 @@ void FrontendUI::showAdtSelectionMinimap() { if (prevMinimapZoom != minimapZoom) { auto windowSize = ImGui::GetWindowSize(); - ImGui::SetScrollX((ImGui::GetScrollX() + windowSize.x / 2.0f) * minimapZoom / prevMinimapZoom - - windowSize.x / 2.0f); - ImGui::SetScrollY((ImGui::GetScrollY() + windowSize.y / 2.0f) * minimapZoom / prevMinimapZoom - - windowSize.y / 2.0f); + auto scrollX = ImGui::GetScrollX(); + auto scrollY = ImGui::GetScrollY(); + + auto maxScrollX = ImGui::GetScrollMaxX(); + auto maxScrollY = ImGui::GetScrollMaxY(); + + float newScrollX = (scrollX + windowSize.x / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.x / 2.0f; + float newScrollY = (scrollY + windowSize.y / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.y / 2.0f; + ImGui::SetScrollX(newScrollX); + ImGui::SetScrollY(newScrollY); } prevMinimapZoom = minimapZoom; @@ -1882,3 +1950,4 @@ void FrontendUI::createFontTexture() { // Store our identifier io.Fonts->TexID = this->m_uiRenderer->createUIMaterial({this->m_uiRenderer->uploadFontTexture(pixels, width, height)}); } + diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 32f4cbee2..9d388efea 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -113,7 +113,9 @@ class FrontendUI : public IScene, public std::enable_shared_from_this filterText = {0}; bool refilterIsNeeded = false; - void filterMapList(std::string text); + bool resortIsNeeded = false; + void filterMapList(const std::string &text); + void fillMapListStrings(); ImGui::FileBrowser fileDialog = ImGui::FileBrowser(ImGuiFileBrowserFlags_SelectDirectory, true); ImGui::FileBrowser createFileDialog = ImGui::FileBrowser(ImGuiFileBrowserFlags_EnterNewFilename); diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 55d1d9369..77dcd8323 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -161,7 +161,6 @@ void InteriorView::setM2Lights(std::shared_ptr &m2Object) { HExteriorView FrameViewsHolder::getOrCreateExterior(const MathHelper::FrustumCullingData &frustumData) { if (exteriorView == nullptr) { exteriorView = std::make_shared(); - skyBoxView = std::make_shared(); exteriorView->frustumData = frustumData; } @@ -182,5 +181,8 @@ HExteriorView FrameViewsHolder::getExterior() { } HExteriorView FrameViewsHolder::getSkybox() { + if (!skyBoxView) { + skyBoxView = std::make_shared(); + } return skyBoxView; } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 6402d38d3..867190777 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1000,8 +1000,8 @@ void WmoObject::traverseGroupWmo( if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.showSkyBox) { if (groupObjects[groupId]->getWmoGroupGeom()->mogp->flags.INTERIOR > 0 || !m_api->getConfig()->usePortalCulling) { - if (skyBox != nullptr) { - traverseTempData.ivPerWMOGroup[groupId]->m2List.addToDraw(skyBox); + if (traversingStartedFromInterior && skyBox != nullptr) { + traverseTempData.viewsHolder.getSkybox()->m2List.addToDraw(skyBox); } } else { //TODO: WHAT ???? diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d2f5ac48a..4aac3c3cf 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,96}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +658,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,16384}, - {0,1,64}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,16 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,5,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1524,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, }, { { {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1543,19 +1546,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,48}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {9,9,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,21 +1585,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1623,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1954,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1990,29 +2006,23 @@ const std::unordered_map MapSceneRenderForwardVLK::update(const std::sha for (auto const &mesh: *opaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } - if (renderSky) { - if (skyMesh) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); + if (true) { + if (renderSky && skyMesh) + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); + for (auto const &mesh: *skyOpaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } @@ -604,7 +606,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } - if (skyMesh0x4) + if (renderSky && skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } for (auto const &mesh: *transparentMeshes) { From cb7fb38e3fbfc8e6e5f84f86fb972065e1e98e06 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 7 Jun 2023 18:55:11 +0300 Subject: [PATCH 083/212] implement the non-holes rendering for ADT --- src/ui/FrontendUI.cpp | 22 + .../mapSelectionWindow/MapSelectDialog.cpp | 5 + .../mapSelectionWindow/MapSelectDialog.h | 15 + .../glsl/forwardRendering/adtShader.frag | 2 +- .../src/engine/algorithms/mathHelper.cpp | 3 + .../src/engine/objects/ViewsObjects.cpp | 20 +- .../src/engine/objects/ViewsObjects.h | 8 +- .../src/engine/objects/adt/adtObject.cpp | 56 +- .../src/engine/objects/adt/adtObject.h | 6 + .../src/engine/objects/m2/m2Object.cpp | 68 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../src/engine/objects/scenes/map.cpp | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/persistance/adtFile.cpp | 17 +- wowViewerLib/src/engine/persistance/adtFile.h | 6 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- .../src/gapi/interface/buffers/IBuffer.h | 3 +- .../src/gapi/interface/buffers/IBufferChunk.h | 5 - .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 21 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 6 +- .../buffers/GVertexBufferDynamicVLK.cpp | 2 +- .../vulkan/buffers/GVertexBufferDynamicVLK.h | 2 +- wowViewerLib/src/include/config.h | 4 +- .../renderer/mapScene/MapSceneRenderer.cpp | 7 +- 24 files changed, 674 insertions(+), 628 deletions(-) create mode 100644 src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp create mode 100644 src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 86691bd63..c75f52a58 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -513,6 +513,17 @@ void FrontendUI::showAdtSelectionMinimap() { if (minimapZoom < 0.001) minimapZoom = 0.001; +// TODO: create a custom component with internal dependency to not pollute this file +// ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY); +// if (ImGui::IsItemHovered()) +// { +// float wheel = ImGui::GetIO().MouseWheel; +// if (!feq(wheel, 0.0f)) +// { +// wheel; +// } +// } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); @@ -1177,6 +1188,11 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->disableFog = disableFog; } + bool renderADT = m_api->getConfig()->renderAdt; + if (ImGui::Checkbox("Render ADT", &renderADT)) { + m_api->getConfig()->renderAdt = renderADT; + } + bool renderM2 = m_api->getConfig()->renderM2; if (ImGui::Checkbox("Render M2", &renderM2)) { m_api->getConfig()->renderM2 = renderM2; @@ -1192,6 +1208,12 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->drawM2BB = drawM2BB; } + bool ignoreADTHoles = m_api->getConfig()->ignoreADTHoles; + if (ImGui::Checkbox("Ignore ADT holes for rendering", &ignoreADTHoles)) { + m_api->getConfig()->ignoreADTHoles = ignoreADTHoles; + } + + bool disablePortalCulling = !m_api->getConfig()->usePortalCulling; if (ImGui::Checkbox("Disable portal culling", &disablePortalCulling)) { m_api->getConfig()->usePortalCulling = !disablePortalCulling; diff --git a/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp b/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp new file mode 100644 index 000000000..e4cf9712c --- /dev/null +++ b/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 6/3/2023. +// + +#include "MapSelectDialog.h" diff --git a/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h b/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h new file mode 100644 index 000000000..797becaae --- /dev/null +++ b/src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h @@ -0,0 +1,15 @@ +// +// Created by Deamon on 6/3/2023. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSELECTDIALOG_H +#define AWEBWOWVIEWERCPP_MAPSELECTDIALOG_H + + +class MapSelectDialog { +public: + MapSelectDialog(); +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSELECTDIALOG_H diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index e656f93a2..f33195ada 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -124,7 +124,7 @@ void main() { //Spec part float specBlend = final.a; vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); - vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, vNormal)), 20.0))); + vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult.x; finalColor.rgb += specTerm; diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.cpp b/wowViewerLib/src/engine/algorithms/mathHelper.cpp index 3ad6721a7..d660bd1a9 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.cpp +++ b/wowViewerLib/src/engine/algorithms/mathHelper.cpp @@ -604,12 +604,15 @@ mathfu::vec3 MathHelper::getBarycentric(mathfu::vec3 &p, mathfu::vec3 &a, mathfu float d20 = mathfu::vec3::DotProduct(v2, v0); float d21 = mathfu::vec3::DotProduct(v2, v1); float denom = d00 * d11 - d01 * d01; +// float denom = v0.x * v1.y - v1.x * v0.y; if ((denom < 0.0001f) && (denom > -0.0001f)) { return mathfu::vec3(-1, -1, -1); }; float v = (d11 * d20 - d01 * d21) / denom; float w = (d00 * d21 - d01 * d20) / denom; +// float v = (v2.x * v1.y - v1.x * v2.y) / denom; +// float w = (v0.x * v2.y - v2.x * v0.y) / denom; float u = 1.0f - v - w; return mathfu::vec3(u, v, w); } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 77dcd8323..053552caf 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -13,24 +13,26 @@ #include "../algorithms/mathHelper_culling.h" #include "../../gapi/interface/materials/IMaterial.h" -void ExteriorView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { - { +void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) { + if (renderADT) { auto inserter = std::back_inserter(opaqueMeshes); - std::copy(this->m_opaqueMeshes.begin(), this->m_opaqueMeshes.end(), inserter); + std::copy(this->m_adtOpaqueMeshes.begin(), this->m_adtOpaqueMeshes.end(), inserter); } - { + if (renderAdtLiquid) { auto inserter = std::back_inserter(transparentMeshes); - std::copy(this->m_transparentMeshes.begin(), this->m_transparentMeshes.end(), inserter); + std::copy(this->m_adtLiquidTransparentMeshes.begin(), this->m_adtLiquidTransparentMeshes.end(), inserter); } - GeneralView::collectMeshes(opaqueMeshes, transparentMeshes); + GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshes, transparentMeshes); } -void GeneralView::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) { - for (auto& wmoGroup : wmoGroupArray.getToDraw()) { - wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); +void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) { + if (renderWMO) { + for (auto &wmoGroup: wmoGroupArray.getToDraw()) { + wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); + } } for (auto const &mesh : portalPointsFrame.m_meshes) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index a8d809544..f9b57aaea 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -49,7 +49,7 @@ class GeneralView { std::vector m_meshes = {}; } portalPointsFrame; - virtual void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes); + virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer); @@ -66,11 +66,11 @@ class InteriorView : public GeneralView { class ExteriorView : public GeneralView { public: std::vector> drawnADTs = {}; - std::vector m_opaqueMeshes = {}; - std::vector m_transparentMeshes = {}; + std::vector m_adtOpaqueMeshes = {}; + std::vector m_adtLiquidTransparentMeshes = {}; public: - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes) override; + void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) override; }; class FrameViewsHolder { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 39c5d8a68..1e1715ff7 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -23,10 +23,10 @@ void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { texturesPerMCNK = std::vector(m_adtFile->mcnkRead+1); animationTranslationPerMCNK = std::vector(m_adtFile->mcnkRead+1); - createVBO(sceneRenderer); loadAlphaTextures(); + + createVBO(sceneRenderer); createMeshes(sceneRenderer); -// createIndexVBO(); calcBoundingBoxes(); @@ -268,15 +268,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { /* 2. Strips */ - if (m_adtFile->strips.size() > 0) { - stripIBO = sceneRenderer->createADTIndexBuffer(m_adtFile->strips.size() * sizeof(int16_t)); - stripIBO->uploadData(m_adtFile->strips.data(), m_adtFile->strips.size() * sizeof(int16_t)); - - adtVertexBindings = sceneRenderer->createADTVAO(combinedVbo, stripIBO); - } else { - stripIBO = nullptr; - adtVertexBindings = nullptr; - } + createIBOAndBinding(sceneRenderer); //Sometimes mvli can be zero, while there is still data in floatDataBlob if (m_adtFileLod!= nullptr && m_adtFileLod->getStatus()==FileStatus::FSLoaded && m_adtFileLod->floatDataBlob_len > 0 && m_adtFileLod->mvli_len > 0) { @@ -305,13 +297,6 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { GVertexBufferBinding vertexBinding; vertexBinding.vertexBuffer = combinedVbo; - //TODO: -// GBufferBinding adtLodBufferBinding = { +adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 4, 0 }; -// vertexBinding.bindings.push_back(adtLodBufferBinding); -// GBufferBinding adtLodBufferBinding2 = {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 4, static_cast(indexVBOLodOffset * sizeof(float))}; -// vertexBinding.bindings.push_back(adtLodBufferBinding2); - -// lodVertexBindings->addVertexBufferBinding(vertexBinding, ); lodVertexBindings->save(); } } @@ -366,6 +351,13 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { pipelineTemplate.backFaceCulling = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + auto const &stripOffsets = !m_api->getConfig()->ignoreADTHoles ? + m_adtFile->stripOffsets : + m_adtFile->stripOffsetsNoHoles; + + adtMeshes = {}; + adtMaterials = {}; + if (adtVertexBindings != nullptr) { for (int i = 0; i < 256; i++) { //Cant be used only in Wotlk @@ -381,8 +373,8 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { gMeshTemplate aTemplate(adtVertexBindings); aTemplate.meshType = MeshType::eAdtMesh; - aTemplate.start = m_adtFile->stripOffsets[i] * 2; - aTemplate.end = m_adtFile->stripOffsets[i + 1] - m_adtFile->stripOffsets[i]; + aTemplate.start = stripOffsets[i] * 2; + aTemplate.end = stripOffsets[i + 1] - stripOffsets[i]; HGMesh hgMesh = sceneRenderer->createMesh(aTemplate, adtMaterial); adtMeshes[i] = hgMesh; @@ -571,6 +563,11 @@ void AdtObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { m_loaded = true; } } + + if (m_loaded && m_holesIgnored != m_api->getConfig()->ignoreADTHoles) { + createIBOAndBinding(sceneRenderer); + createMeshes(sceneRenderer); + } } void AdtObject::update(animTime_t deltaTime ) { m_lastDeltaTime = deltaTime; @@ -1176,3 +1173,22 @@ int AdtObject::getAreaId(int mcnk_x, int mcnk_y) { return 0; } + +void AdtObject::createIBOAndBinding(const HMapSceneBufferCreate &sceneRenderer) { + auto const &strips = !m_api->getConfig()->ignoreADTHoles ? + m_adtFile->strips : + m_adtFile->stripsNoHoles; + + + if (strips.size() > 0) { + stripIBO = sceneRenderer->createADTIndexBuffer(strips.size() * sizeof(int16_t)); + stripIBO->uploadData(strips.data(), strips.size() * sizeof(int16_t)); + + adtVertexBindings = sceneRenderer->createADTVAO(combinedVbo, stripIBO); + } else { + stripIBO = nullptr; + adtVertexBindings = nullptr; + } + + m_holesIgnored = m_api->getConfig()->ignoreADTHoles; +} diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index e6b6a610a..c4a1c8df4 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -91,7 +91,10 @@ class AdtObject { }; void loadingFinished(const HMapSceneBufferCreate &sceneRenderer); + void createVBO(const HMapSceneBufferCreate &sceneRenderer); + void createIBOAndBinding(const HMapSceneBufferCreate &sceneRenderer); + void createMeshes(const HMapSceneBufferCreate &sceneRenderer); void loadAlphaTextures(); @@ -120,6 +123,7 @@ class AdtObject { HGVertexBuffer combinedVbo ; HGIndexBuffer stripIBO ; HGVertexBufferBindings adtVertexBindings; + bool m_holesIgnored = false; HGVertexBuffer heightVboLod; HGIndexBuffer stripVBOLod; @@ -194,6 +198,8 @@ class AdtObject { WMOListContainer &wmoCandidates); void fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMaterialTemplate &adtMaterialTemplate); + + }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 53f57f535..9e991c3f7 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -457,8 +457,6 @@ int getShaderNames(M2Batch *m2Batch, std::string &vertexShader, std::string &pix } M2Object::~M2Object() { - delete m_animationManager; - for (auto obj: ribbonEmitters) { delete obj; } @@ -1289,29 +1287,30 @@ void M2Object::createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer) std::shared_ptr> bbBlockVS = nullptr; auto l_m2Geom = m_m2Geom; - bbBlockVS->setUpdateHandler([this, l_m2Geom](auto &data, const HFrameDependantData &frameDepedantData){ - M2Data *m2Data = l_m2Geom->getM2Data(); - CAaBox &aaBox = m2Data->bounding_box; - - mathfu::vec3 center = mathfu::vec3( - (aaBox.min.x + aaBox.max.x) / 2, - (aaBox.min.y + aaBox.max.y) / 2, - (aaBox.min.z + aaBox.max.z) / 2 - ); - mathfu::vec3 scale = mathfu::vec3( - aaBox.max.x - center[0], - aaBox.max.y - center[1], - aaBox.max.z - center[2] - ); + //Bunding box material */ + /* + M2Data *m2Data = l_m2Geom->getM2Data(); + CAaBox &aaBox = m2Data->bounding_box; + + mathfu::vec3 center = mathfu::vec3( + (aaBox.min.x + aaBox.max.x) / 2, + (aaBox.min.y + aaBox.max.y) / 2, + (aaBox.min.z + aaBox.max.z) / 2 + ); - bbModelWideBlockVS &blockVS = data; - blockVS.uPlacementMat = m_placementMatrix; - blockVS.uBBScale = mathfu::vec4_packed(mathfu::vec4(scale, 0.0)); - blockVS.uBBCenter = mathfu::vec4_packed(mathfu::vec4(center, 0.0)); - blockVS.uColor = mathfu::vec4_packed(mathfu::vec4(0.1f, 0.7f, 0.1f, 0.1f)); - }); + mathfu::vec3 scale = mathfu::vec3( + aaBox.max.x - center[0], + aaBox.max.y - center[1], + aaBox.max.z - center[2] + ); + bbModelWideBlockVS &blockVS = data; + blockVS.uPlacementMat = m_placementMatrix; + blockVS.uBBScale = mathfu::vec4_packed(mathfu::vec4(scale, 0.0)); + blockVS.uBBCenter = mathfu::vec4_packed(mathfu::vec4(center, 0.0)); + blockVS.uColor = mathfu::vec4_packed(mathfu::vec4(0.1f, 0.7f, 0.1f, 0.1f)); + */ //TODO: // boundingBoxMesh = sceneRenderer->createSortableMesh(meshTemplate); } @@ -1531,20 +1530,23 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { dynamicMeshes.push_back(dynamicMeshData); } + + { + M2Data* m2File = this->m_m2Geom->getM2Data(); + M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); + for (auto& material : m_materialArray) { + M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); + } + for (auto& material : m_forcedTranspMaterialArray) { + M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); + } + } + } else { m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); } - { - M2Data *m2File = this->m_m2Geom->getM2Data(); - M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); - for (auto &material: m_materialArray) { - M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); - } - for (auto &material: m_forcedTranspMaterialArray) { - M2MeshBufferUpdater::updateMaterialData(material, this, m2File, skinData); - } - } + } EGxBlendEnum M2Object::getBlendMode(int batchIndex) { @@ -1661,7 +1663,7 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorm_animationManager = new AnimationManager(m_api, m_boneMasterData, m_m2Geom->exp2 != nullptr); + this->m_animationManager = std::make_unique(m_api, m_boneMasterData, m_m2Geom->exp2 != nullptr); } void M2Object::initBoneAnimMatrices() { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 141c66199..f842bd940 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -141,7 +141,7 @@ class M2Object { //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; - AnimationManager *m_animationManager; + std::unique_ptr m_animationManager; bool m_interiorAmbientWasSet = false; // For static only bool m_boolSkybox = false; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 013c5ad6b..8bdfedcbf 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -501,8 +501,8 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams if (exteriorView != nullptr) { exteriorView->addM2FromGroups(frustumData, cameraPos); for (auto &adtRes: exteriorView->drawnADTs) { - adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_opaqueMeshes, - exteriorView->m_transparentMeshes, + adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_adtOpaqueMeshes, + exteriorView->m_adtLiquidTransparentMeshes, exteriorView->renderOrder); } mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index fc8e987c4..6e95faa5c 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -414,7 +414,7 @@ void WmoGroupObject::queryBspTree(CAaBox &bbox, int nodeId, Y &nodes, std::vecto if (rightSide) { WmoGroupObject::queryBspTree(bbox, nodes[nodeId].children[1], nodes, bspLeafIdList); } - } + } } bool WmoGroupObject::getTopAndBottomTriangleFromBsp( diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index c54a93fc5..3255e1279 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -598,15 +598,17 @@ void AdtFile::createTriangleStrip() { strips = std::vector(); stripOffsets = std::vector(); + stripsNoHoles = std::vector(); + stripOffsetsNoHoles = std::vector(); + for (int i = 0; i <= mcnkRead; i++) { SMChunk &mcnkObj = mapTile[i]; int holeLow = mcnkObj.holes_low_res; uint64_t holeHigh = mcnkObj.postMop.holes_high_res; stripOffsets.push_back(strips.size()); + stripOffsetsNoHoles.push_back(stripsNoHoles.size()); - int j = 0; - bool first = true; for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { bool isHole = (!mcnkObj.flags.high_res_holes) ? @@ -615,21 +617,14 @@ void AdtFile::createTriangleStrip() { if (!isHole) { //There are 8 squares in width and 8 square in height. //Each square is 4 triangles -// -// -// if (!first) { -// strips.push_back((i * vertCountPerMCNK) + squareIndsStrip[0] + 17 * y + x); -// } -// first = false; -// for (int k = 0; k < stripLenght; k++) { -// strips.push_back((i* vertCountPerMCNK) + squareIndsStrip[k] + 17 * y + x); -// } addSquare(i * vertCountPerMCNK, x, y, strips); } + addSquare(i * vertCountPerMCNK, x, y, stripsNoHoles); } } } stripOffsets.push_back(strips.size()); + stripOffsetsNoHoles.push_back(stripsNoHoles.size()); } void AdtFile::process(HFileContent adtFile, const std::string &fileName) { diff --git a/wowViewerLib/src/engine/persistance/adtFile.h b/wowViewerLib/src/engine/persistance/adtFile.h index d2536c619..3b1e391d3 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.h +++ b/wowViewerLib/src/engine/persistance/adtFile.h @@ -120,9 +120,6 @@ class AdtFile: public PersistentFile { PointerChecker mH2OBlob = mH2OBlob_len; int mH2OBlob_len = 0; - - - int mcnkRead = -1; std::array mapTile; std::array mcnkStructs; @@ -130,6 +127,9 @@ class AdtFile: public PersistentFile { std::vector strips; std::vector stripOffsets; + + std::vector stripsNoHoles; + std::vector stripOffsetsNoHoles; private: bool m_mainAdt = false; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 4aac3c3cf..d2f5ac48a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +430,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,19 +499,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,13 +633,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +814,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -877,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,96}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,21 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,13 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {1,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,21 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {0,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,11 +1524,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,16 +1543,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,10 +1585,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1612,21 +1623,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1984,13 +1954,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2006,23 +1990,29 @@ const std::unordered_map -using IChunkHandlerType = std::function ; - template class IBufferChunk { public: @@ -21,7 +18,5 @@ class IBufferChunk { virtual ~IBufferChunk() = default; virtual T &getObject() = 0; virtual void save() = 0; - - virtual void setUpdateHandler(IChunkHandlerType handler) {}; }; #endif //AWEBWOWVIEWERCPP_IBUFFERCHUNK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 22047ff1a..35b286f6c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -129,7 +129,7 @@ void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocat } } -void GBufferVLK::uploadData(void *data, int length) { +void GBufferVLK::uploadData(const void *data, int length) { if (length > m_bufferSize) { resize(length); } @@ -139,13 +139,6 @@ void GBufferVLK::uploadData(void *data, int length) { uploadFromStaging(0, 0, length); } -void GBufferVLK::subUploadData(void *data, int offset, int length) { - if (offset+length > m_bufferSize) { - resize(offset+length); - } - memcpy((uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+offset, data, length); -} - void GBufferVLK::resize(int newLength) { std::unique_lock lock(m_mutex, std::defer_lock); lock.lock(); @@ -368,7 +361,7 @@ GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { m_parentBuffer->deleteSubBuffer(m_iterator, m_alloc, m_uiaAlloc, m_size); } -void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { +void GBufferVLK::GSubBufferVLK::uploadData(const void *data, int length) { if (length > m_size) { std::cerr << "invalid dataSize" << std::endl; } @@ -379,16 +372,6 @@ void GBufferVLK::GSubBufferVLK::uploadData(void *data, int length) { // m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } -void GBufferVLK::GSubBufferVLK::subUploadData(void *data, int offset, int length) { - if (offset + length > m_size) { - std::cerr << "invalid dataSize" << std::endl; - } - - memcpy(m_dataPointer + offset, data, length); - - m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); -} - void *GBufferVLK::GSubBufferVLK::getPointer() { if (m_size <= 0) return nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 320c58b67..c11cc0038 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -29,8 +29,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this &rende // Put everything into one array and sort interiorViewCollectMeshCounter.beginMeasurement(); bool renderPortals = m_config->renderPortals; + bool renderADT = m_config->renderAdt; + bool renderWMO = m_config->renderWMO; + for (auto &view : cullStage->viewsHolder.getInteriorViews()) { - view->collectMeshes(opaqueMeshes, transparentMeshes); + view->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); } interiorViewCollectMeshCounter.endMeasurement(); @@ -55,7 +58,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende { auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { - exteriorView->collectMeshes(opaqueMeshes, transparentMeshes); + exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); } } exteriorViewCollectMeshCounter.endMeasurement(); From da74bd6732abbbae3fbb502114890655ef5cfe9b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 12 Jun 2023 03:36:26 +0300 Subject: [PATCH 084/212] add tracy and do some parallelization --- .gitmodules | 3 + CMakeLists.txt | 2 +- src/main.cpp | 3 + src/ui/FrontendUI.cpp | 23 +- src/ui/FrontendUI.h | 1 + wowViewerLib/3rdparty/tracy | 1 + wowViewerLib/CMakeLists.txt | 20 + .../glsl/forwardRendering/m2Shader.frag | 8 +- .../src/engine/managers/animationManager.cpp | 5 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 46 +- .../src/engine/objects/scenes/map.cpp | 175 ++- .../src/engine/objects/wmo/wmoGroupObject.h | 37 +- .../src/engine/objects/wmo/wmoObject.cpp | 2 + .../src/engine/objects/wmo/wmoObject.h | 35 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- wowViewerLib/src/gapi/interface/sortLambda.h | 6 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 15 +- wowViewerLib/src/include/config.h | 4 + .../src/renderer/frame/SceneComposer.cpp | 9 + .../src/renderer/mapScene/MapScenePlan.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 8 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 85 +- 22 files changed, 863 insertions(+), 642 deletions(-) create mode 160000 wowViewerLib/3rdparty/tracy diff --git a/.gitmodules b/.gitmodules index 4cdf8a8da..71a05eaca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,3 +47,6 @@ [submodule "3rdparty/hiberlite"] path = 3rdparty/hiberlite url = https://github.com/paulftw/hiberlite.git +[submodule "wowViewerLib/3rdparty/tracy"] + path = wowViewerLib/3rdparty/tracy + url = https://github.com/wolfpld/tracy.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3673fa2f0..3490bd6a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ set(SOURCE_FILES src/ui/renderer/uiScene/ImGUIPlan.h src/ui/renderer/uiScene/IFrontendUIBufferCreate.h src/ui/renderer/uiScene/materials/UIMaterial.h - ) + src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h) set(SOURCE_FILES_VULKAN diff --git a/src/main.cpp b/src/main.cpp index f45bd56ff..084ebf834 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,7 @@ #include "screenshots/screenshotMaker.h" #include "database/CEmptySqliteDB.h" #include +#include "Tracy.hpp" int mleft_pressed = 0; int mright_pressed = 0; @@ -510,6 +511,8 @@ int main(){ if (rendererName == "ogl3" || rendererName == "ogl2") { glfwSwapBuffers(window); } + + FrameMark; } //} catch(const std::exception &e){ // std::cerr << e.what() << std::endl; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index c75f52a58..a4fde569c 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -513,6 +513,8 @@ void FrontendUI::showAdtSelectionMinimap() { if (minimapZoom < 0.001) minimapZoom = 0.001; + + // TODO: create a custom component with internal dependency to not pollute this file // ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY); // if (ImGui::IsItemHovered()) @@ -530,19 +532,23 @@ void FrontendUI::showAdtSelectionMinimap() { // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); const float defaultImageDimension = 100; + int newZoomedSize = (defaultImageDimension * minimapZoom); + if (prevZoomedSize == 0) + prevZoomedSize = defaultImageDimension * prevMinimapZoom; + for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { if (adtSelectionMinimapMaterials[i][j] != nullptr) { if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j], - ImVec2(defaultImageDimension * minimapZoom, defaultImageDimension * minimapZoom))) { + ImVec2(prevZoomedSize, prevZoomedSize))) { auto mousePos = ImGui::GetMousePos(); ImGuiStyle &style = ImGui::GetStyle(); mousePos.x += ImGui::GetScrollX() - ImGui::GetWindowPos().x - style.WindowPadding.x; mousePos.y += ImGui::GetScrollY() - ImGui::GetWindowPos().y - style.WindowPadding.y; - mousePos.x = ((mousePos.x / minimapZoom) / defaultImageDimension); - mousePos.y = ((mousePos.y / minimapZoom) / defaultImageDimension); + mousePos.x = ((mousePos.x / prevMinimapZoom) / defaultImageDimension); + mousePos.y = ((mousePos.y / prevMinimapZoom) / defaultImageDimension); worldPosX = AdtIndexToWorldCoordinate(mousePos.y); worldPosY = AdtIndexToWorldCoordinate(mousePos.x); @@ -554,7 +560,7 @@ void FrontendUI::showAdtSelectionMinimap() { } } else { - ImGui::Dummy(ImVec2(defaultImageDimension * minimapZoom, defaultImageDimension * minimapZoom)); + ImGui::Dummy(ImVec2(prevZoomedSize, prevZoomedSize)); } ImGui::SameLine(0, 0); @@ -582,7 +588,7 @@ void FrontendUI::showAdtSelectionMinimap() { ImGui::EndPopup(); } - if (prevMinimapZoom != minimapZoom) { + if (prevZoomedSize != newZoomedSize && prevMinimapZoom != minimapZoom) { auto windowSize = ImGui::GetWindowSize(); auto scrollX = ImGui::GetScrollX(); auto scrollY = ImGui::GetScrollY(); @@ -592,10 +598,15 @@ void FrontendUI::showAdtSelectionMinimap() { float newScrollX = (scrollX + windowSize.x / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.x / 2.0f; float newScrollY = (scrollY + windowSize.y / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.y / 2.0f; + + newScrollX = trunc(newScrollX); + newScrollY = trunc(newScrollY); + ImGui::SetScrollX(newScrollX); ImGui::SetScrollY(newScrollY); + prevZoomedSize = newZoomedSize; + prevMinimapZoom = minimapZoom; } - prevMinimapZoom = minimapZoom; ImGui::EndChild(); } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 9d388efea..c45353c6e 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -145,6 +145,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this 0, interiorExteriorBlend.x, scene, diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index d9b72b9ee..c569c4508 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -784,10 +784,9 @@ void AnimationManager::update( ) { M2Array * sequences = boneMasterData->getSkelData()->m_sequences; if (this->animationInfo.currentAnimation.animationFoundInParent) { - sequences = boneMasterData->getParentSkelData()->m_sequences;; + sequences = boneMasterData->getParentSkelData()->m_sequences; } - //if (currentAnimationPlayedTimes) int probability = ((float)rand() / (float)RAND_MAX) * 0x7FFF; int calcProb = 0; @@ -828,7 +827,7 @@ void AnimationManager::update( ) { M2Array * sequences = boneMasterData->getSkelData()->m_sequences; if (this->animationInfo.nextSubAnimation.animationFoundInParent) { - sequences = boneMasterData->getParentSkelData()->m_sequences;; + sequences = boneMasterData->getParentSkelData()->m_sequences; } subAnimRecord = (*sequences)[this->animationInfo.nextSubAnimation.animationIndex]; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index f842bd940..935e2d02c 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -324,6 +324,8 @@ class M2ObjectListContainer { std::vector> toLoadMain; std::vector> toLoadGeom; + bool m_locked = false; + bool candCanHaveDuplicates = false; bool drawnCanHaveDuplicates = false; bool toLoadMainCanHaveDuplicates = false; @@ -349,6 +351,10 @@ class M2ObjectListContainer { drawn.reserve(10000); } void addCandidate(const std::shared_ptr &cand) { + if (m_locked) { + throw "oops"; + } + if (cand == nullptr) return; if (cand->getHasBoundingBox()) { candidates.push_back(cand); @@ -360,6 +366,10 @@ class M2ObjectListContainer { } void addToDraw(const std::shared_ptr &toDraw) { + if (m_locked) { + throw "oops"; + } + if (toDraw->getGetIsLoaded()) { drawn.push_back(toDraw); drawnCanHaveDuplicates = true; @@ -371,6 +381,25 @@ class M2ObjectListContainer { toLoadGeomCanHaveDuplicates = true; } } + void addDrawnAndToLoad(M2ObjectListContainer &anotherList) { + if (m_locked) { + throw "oops"; + } + + auto &anotherDrawn = anotherList.getDrawn(); + this->drawn.insert(this->drawn.end(), anotherDrawn.begin(), anotherDrawn.end()); + + auto &anotherToLoadMain = anotherList.getToLoadMain(); + this->toLoadMain.insert(this->toLoadMain.end(), anotherToLoadMain.begin(), anotherToLoadMain.end()); + + auto &anotherToLoadGeom = anotherList.getToLoadGeom(); + this->toLoadGeom.insert(this->toLoadGeom.end(), anotherToLoadGeom.begin(), anotherToLoadGeom.end()); + + toLoadMainCanHaveDuplicates = true; + toLoadGeomCanHaveDuplicates = true; + drawnCanHaveDuplicates = true; + } + const std::vector> &getCandidates() { if (this->candCanHaveDuplicates) { @@ -408,19 +437,14 @@ class M2ObjectListContainer { return toLoadGeom; } - void addDrawnAndToLoad(M2ObjectListContainer &anotherList) { - auto &anotherDrawn = anotherList.getDrawn(); - this->drawn.insert(this->drawn.end(), anotherDrawn.begin(), anotherDrawn.end()); - - auto &anotherToLoadMain = anotherList.getToLoadMain(); - this->toLoadMain.insert(this->toLoadMain.end(), anotherToLoadMain.begin(), anotherToLoadMain.end()); - auto &anotherToLoadGeom = anotherList.getToLoadGeom(); - this->toLoadGeom.insert(this->toLoadGeom.end(), anotherToLoadGeom.begin(), anotherToLoadGeom.end()); + void lock() { + getCandidates(); + getToLoadGeom(); + getToLoadMain(); + getDrawn(); - toLoadMainCanHaveDuplicates = true; - toLoadGeomCanHaveDuplicates = true; - drawnCanHaveDuplicates = true; + m_locked = true; } }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 8bdfedcbf..08b2e4764 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -22,6 +22,7 @@ #endif #include "../../algorithms/mathHelper_culling.h" #include "../../../gapi/interface/materials/IMaterial.h" +#include "Tracy.hpp" std::array skyConusVBO = { { @@ -320,6 +321,8 @@ std::tuple> createSkyMesh(const HMapSc } void Map::makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { + ZoneScoped ; + cullCreateVarsCounter.beginMeasurement(); Config* config = this->m_api->getConfig(); @@ -372,30 +375,34 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams cullCreateVarsCounter.endMeasurement(); - - cullGetCurrentWMOCounter.beginMeasurement(); - //Hack that is needed to get the current WMO the camera is in. Basically it does frustum culling over current ADT - getPotentialEntities(frustumData, cameraPos, mapRenderPlan, potentialM2, potentialWmo); - - for (auto &checkingWmoObj : potentialWmo.getCandidates()) { - WmoGroupResult groupResult; - bool result = checkingWmoObj->getGroupWmoThatCameraIsInside(camera4, groupResult); - - if (result) { - mapRenderPlan->m_currentWMO = checkingWmoObj; - mapRenderPlan->m_currentWmoGroup = groupResult.groupIndex; - if (checkingWmoObj->isGroupWmoInterior(groupResult.groupIndex)) { - mapRenderPlan->m_currentInteriorGroups.push_back(groupResult); - interiorGroupNum = groupResult.groupIndex; - mapRenderPlan->currentWmoGroupIsExtLit = checkingWmoObj->isGroupWmoExteriorLit(groupResult.groupIndex); - mapRenderPlan->currentWmoGroupShowExtSkybox = checkingWmoObj->isGroupWmoExtSkybox(groupResult.groupIndex); - } else { + { + ZoneScopedN("cullGetCurrentWMOCounter"); + cullGetCurrentWMOCounter.beginMeasurement(); + //Hack that is needed to get the current WMO the camera is in. Basically it does frustum culling over current ADT + getPotentialEntities(frustumData, cameraPos, mapRenderPlan, potentialM2, potentialWmo); + + for (auto &checkingWmoObj: potentialWmo.getCandidates()) { + WmoGroupResult groupResult; + bool result = checkingWmoObj->getGroupWmoThatCameraIsInside(camera4, groupResult); + + if (result) { + mapRenderPlan->m_currentWMO = checkingWmoObj; + mapRenderPlan->m_currentWmoGroup = groupResult.groupIndex; + if (checkingWmoObj->isGroupWmoInterior(groupResult.groupIndex)) { + mapRenderPlan->m_currentInteriorGroups.push_back(groupResult); + interiorGroupNum = groupResult.groupIndex; + mapRenderPlan->currentWmoGroupIsExtLit = checkingWmoObj->isGroupWmoExteriorLit( + groupResult.groupIndex); + mapRenderPlan->currentWmoGroupShowExtSkybox = checkingWmoObj->isGroupWmoExtSkybox( + groupResult.groupIndex); + } else { + } + bspNodeId = groupResult.nodeId; + break; } - bspNodeId = groupResult.nodeId; - break; } + cullGetCurrentWMOCounter.endMeasurement(); } - cullGetCurrentWMOCounter.endMeasurement(); cullGetCurrentZoneCounter.beginMeasurement(); @@ -561,7 +568,9 @@ mathfu::vec3 blendV3(mathfu::vec3 a, mathfu::vec3 b, float alpha) { } void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, - StateForConditions &stateForConditions, const AreaRecord &areaRecord) {///----------------------------------- + StateForConditions &stateForConditions, const AreaRecord &areaRecord) { + ZoneScoped ; + Config* config = this->m_api->getConfig(); bool fogRecordWasFound = false; @@ -1050,6 +1059,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, int viewRenderOrder, HMapRenderPlan &mapRenderPlan ) { + ZoneScoped ; // std::cout << "Map::checkExterior finished called" << std::endl; if (m_wdlObject == nullptr && m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { if (m_wdtfile->mphd->flags.wdt_has_maid) { @@ -1300,6 +1310,7 @@ void Map::createAdtFreeLamdas() { void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan) { + ZoneScoped; int processedThisFrame = 0; int m2ProcessedThisFrame = 0; int wmoProcessedThisFrame = 0; @@ -1402,6 +1413,8 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende }; void Map::update(const HMapRenderPlan &renderPlan) { + ZoneScoped; + mathfu::vec3 cameraVec3 = renderPlan->renderingMatrices->cameraPos.xyz(); mathfu::mat4 &frustumMat = renderPlan->renderingMatrices->perspectiveMat; mathfu::mat4 &lookAtMat = renderPlan->renderingMatrices->lookAtMat; @@ -1411,15 +1424,23 @@ void Map::update(const HMapRenderPlan &renderPlan) { auto &m2ToDraw = renderPlan->m2Array.getDrawn(); { + ZoneScopedN("m2UpdateframeCounter"); m2UpdateframeCounter.beginMeasurement(); - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 1000), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto& m2Object = m2ToDraw[i]; - m2Object->update(deltaTime, cameraVec3, lookAtMat); - } - }, tbb::simple_partitioner()); + auto threadsAvailable = m_api->getConfig()->hardwareThreadCount(); + + int granSize = m2ToDraw.size() / (2 * threadsAvailable); + if (granSize == 0) granSize = m2ToDraw.size(); + + if (granSize > 0) { + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + m2Object->update(deltaTime, cameraVec3, lookAtMat); + } + }, tbb::simple_partitioner()); + } if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { for (auto &m2Object : skyBoxView->m2List.getDrawn()) { @@ -1430,34 +1451,41 @@ void Map::update(const HMapRenderPlan &renderPlan) { m2UpdateframeCounter.endMeasurement(); } - wmoUpdate.beginMeasurement(); - for (const auto &wmoObject : renderPlan->wmoArray.getToDrawn()) { - if (wmoObject == nullptr) continue; - wmoObject->update(); + { + ZoneScopedN("wmoUpdate"); + wmoUpdate.beginMeasurement(); + for (const auto &wmoObject: renderPlan->wmoArray.getToDrawn()) { + if (wmoObject == nullptr) continue; + wmoObject->update(); + } + wmoUpdate.endMeasurement(); } - wmoUpdate.endMeasurement(); - wmoGroupUpdate.beginMeasurement(); - for (const auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { - if (wmoGroupObject == nullptr) continue; - wmoGroupObject->update(); + { + ZoneScopedN("wmoGroupUpdate"); + wmoGroupUpdate.beginMeasurement(); + for (const auto &wmoGroupObject: renderPlan->wmoGroupArray.getToDraw()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->update(); + } + wmoGroupUpdate.endMeasurement(); } - wmoGroupUpdate.endMeasurement(); - adtUpdate.beginMeasurement(); { - std::unordered_set> processedADT; - for (const auto &adtObjectRes: renderPlan->adtArray) { - if (processedADT.count(adtObjectRes->adtObject) == 0) { - adtObjectRes->adtObject->update(deltaTime); - processedADT.insert(adtObjectRes->adtObject); + ZoneScopedN("adtUpdate"); + adtUpdate.beginMeasurement(); + { + std::unordered_set> processedADT; + for (const auto &adtObjectRes: renderPlan->adtArray) { + if (processedADT.count(adtObjectRes->adtObject) == 0) { + adtObjectRes->adtObject->update(deltaTime); + processedADT.insert(adtObjectRes->adtObject); + } } } + adtUpdate.endMeasurement(); } - for (const auto &adtObjectRes : renderPlan->adtArray) { - } - adtUpdate.endMeasurement(); //2. Calc distance every 100 ms m2calcDistanceCounter.beginMeasurement(); @@ -1501,6 +1529,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { } void Map::updateBuffers(const HMapRenderPlan &renderPlan) { + ZoneScoped; { auto &meshblockVS = skyMeshMat0x4->m_skyColors->getObject(); auto EndFogColorV4_1 = mathfu::vec4(renderPlan->frameDependentData->EndFogColor, 0.0); @@ -1524,25 +1553,53 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { skyMeshMat->m_skyColors->save(); } - for (auto &m2Object : renderPlan->m2Array.getDrawn()) { - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); + { + ZoneScopedN("m2BuffersUpdate"); + auto threadsAvailable = m_api->getConfig()->hardwareThreadCount(); + auto &m2ToDraw = renderPlan->m2Array.getDrawn(); + int granSize = m2ToDraw.size() / (2 * threadsAvailable); + if (granSize == 0) granSize = m2ToDraw.size(); + + if (granSize > 0) { + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } + }, tbb::simple_partitioner()); } + +// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } } - if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { - for (auto &m2Object : skyBoxView->m2List.getDrawn()) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); + { + ZoneScopedN("m2SkyboxBuffersUpdate"); + if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { + for (auto &m2Object: skyBoxView->m2List.getDrawn()) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } } } - for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToDraw()) { - if (wmoGroupObject == nullptr) continue; - wmoGroupObject->uploadGeneratorBuffers(renderPlan->frameDependentData, getCurrentSceneTime()); + { + ZoneScopedN("wmoBuffersUpdate"); + for (auto &wmoGroupObject: renderPlan->wmoGroupArray.getToDraw()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->uploadGeneratorBuffers(renderPlan->frameDependentData, getCurrentSceneTime()); + } } { + ZoneScopedN("adtBuffersUpdate"); std::unordered_set> processedADT; for (const auto &adtObjectRes: renderPlan->adtArray) { if (processedADT.count(adtObjectRes->adtObject) == 0) { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 6ffaa28a6..2c528eb65 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -156,6 +156,8 @@ class WMOGroupListContainer { bool toCheckM2CanHaveDuplicates = false; bool toLoadCanHaveDuplicates = false; + bool m_locked = false; + void inline removeDuplicates(std::vector> &array) { if (array.size() < 1000) { std::sort(array.begin(), array.end()); @@ -176,6 +178,10 @@ class WMOGroupListContainer { } void addToDraw(const std::shared_ptr &toDraw) { + if (m_locked) { + throw "oops"; + } + if (toDraw->getIsLoaded()) { wmoGroupToDraw.push_back(toDraw); toDrawCanHaveDuplicates = true; @@ -186,6 +192,10 @@ class WMOGroupListContainer { } void addToCheckM2(const std::shared_ptr &toCheckM2) { + if (m_locked) { + throw "oops"; + } + if (toCheckM2->getIsLoaded()) { wmoGroupToCheckM2.push_back(toCheckM2); toCheckM2CanHaveDuplicates = true; @@ -195,12 +205,28 @@ class WMOGroupListContainer { } } void addToLoad(const std::shared_ptr &toLoad) { + if (m_locked) { + throw "oops"; + } + if (!toLoad->getIsLoaded()) { wmoGroupToLoad.push_back(toLoad); toLoadCanHaveDuplicates = true; } } + void addToLoadAndDraw(WMOGroupListContainer &otherList) { + if (m_locked) { + throw "oops"; + } + + this->wmoGroupToDraw.insert(this->wmoGroupToDraw.end(), otherList.wmoGroupToDraw.begin(), otherList.wmoGroupToDraw.end()); + this->wmoGroupToLoad.insert(this->wmoGroupToLoad.end(), otherList.wmoGroupToLoad.begin(), otherList.wmoGroupToLoad.end()); + + toDrawCanHaveDuplicates = true; + toLoadCanHaveDuplicates = true; + } + const std::vector> &getToDraw() { if (this->toDrawCanHaveDuplicates) { removeDuplicates(wmoGroupToDraw); @@ -228,12 +254,13 @@ class WMOGroupListContainer { return wmoGroupToLoad; } - void addToLoadAndDraw(WMOGroupListContainer &otherList) { - this->wmoGroupToDraw.insert(this->wmoGroupToDraw.end(), otherList.wmoGroupToDraw.begin(), otherList.wmoGroupToDraw.end()); - this->wmoGroupToLoad.insert(this->wmoGroupToLoad.end(), otherList.wmoGroupToLoad.begin(), otherList.wmoGroupToLoad.end()); - toDrawCanHaveDuplicates = true; - toLoadCanHaveDuplicates = true; + void lock() { + getToDraw(); + getToCheckM2(); + getToLoad(); + + m_locked = true; } }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 867190777..70c999d0b 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -7,6 +7,7 @@ #include "../../algorithms/grahamScan.h" #include "../../persistance/header/commonFileStructs.h" #include "./../../../gapi/interface/IDevice.h" +#include "Tracy.hpp" #include std::vector createOccluders(const HWmoGroupGeom& groupGeom) @@ -804,6 +805,7 @@ bool WmoObject::startTraversingWMOGroup( bool traversingFromInterior, FrameViewsHolder &viewsHolder ) { + ZoneScoped; if (!m_loaded) return false; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 5023f92fa..82a3aeb07 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -209,6 +209,8 @@ class WMOListContainer { bool toLoadCanHaveDuplicates = false; bool toDrawmCanHaveDuplicates = false; + bool m_locked = false; + void inline removeDuplicates(std::vector> &array) { if (array.size() < 1000) { std::sort(array.begin(), array.end()); @@ -228,6 +230,10 @@ class WMOListContainer { } void addCand(const std::shared_ptr &toDraw) { + if (m_locked) { + throw "oops"; + } + if (toDraw->isLoaded()) { wmoCandidates.push_back(toDraw); candCanHaveDuplicates = true; @@ -238,12 +244,27 @@ class WMOListContainer { } void addToLoad(const std::shared_ptr &toLoad) { + if (m_locked) { + throw "oops"; + } + if (!toLoad->isLoaded()) { wmoToLoad.push_back(toLoad); toLoadCanHaveDuplicates = true; } } + void addToDrawn(const std::shared_ptr &toDrawn) { + if (m_locked) { + throw "oops"; + } + + if (toDrawn->isLoaded()) { + wmoToDrawn.push_back(toDrawn); + toDrawmCanHaveDuplicates = true; + } + } + const std::vector> &getCandidates() { if (this->candCanHaveDuplicates) { removeDuplicates(wmoCandidates); @@ -262,12 +283,6 @@ class WMOListContainer { return wmoToLoad; } - void addToDrawn(const std::shared_ptr &toDrawn) { - if (toDrawn->isLoaded()) { - wmoToDrawn.push_back(toDrawn); - toDrawmCanHaveDuplicates = true; - } - } const std::vector> &getToDrawn() { if (this->toDrawmCanHaveDuplicates) { @@ -278,6 +293,14 @@ class WMOListContainer { return wmoToDrawn; } + void lock() { + getToDrawn(); + getToLoad(); + getCandidates(); + + m_locked = true; + } + }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d2f5ac48a..4aac3c3cf 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,96}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,16 +658,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,256}, {0,1,64}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,16384}, - {0,1,64}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,16 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,5,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1524,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, }, { { {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1543,19 +1546,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,48}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {9,9,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,21 +1585,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1623,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1954,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1990,29 +2006,23 @@ const std::unordered_map(indexA.get()); - ISortableMesh * pB = dynamic_cast(indexB.get()); +static const bool SortMeshes(const HGSortableMesh &indexA, const HGSortableMesh &indexB) { + ISortableMesh * pA = indexA.get(); + ISortableMesh * pB = indexB.get(); if (pA == nullptr) return false; if (pB == nullptr) return true; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 35b286f6c..ec8bc8cd8 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -215,7 +215,7 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy { OffsetAllocator::Allocation uiaAlloc; { - std::unique_lock lock(m_mutex, std::defer_lock); + std::unique_lock lock(m_mutex); uiaAlloc = uiaAllocator.allocate(1); if (uiaAlloc.offset == OffsetAllocator::Allocation::NO_SPACE) { this->uiaAllocator.growSize(1000); @@ -232,11 +232,12 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy uiaAlloc, (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+alloc.offset); - std::unique_lock lock(m_mutex, std::defer_lock); - lock.lock(); - currentSubBuffers.push_back(subBuffer); - subBuffer->m_iterator = std::prev(currentSubBuffers.end()); - lock.unlock(); + + { + std::unique_lock lock(m_mutex); + currentSubBuffers.push_back(subBuffer); + subBuffer->m_iterator = std::prev(currentSubBuffers.end()); + } return subBuffer; } else @@ -251,6 +252,8 @@ void GBufferVLK::deleteSubBuffer(std::list>::const_ const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc, int subBuffersize) { + + std::unique_lock lock(m_mutex); if (subBuffersize > 0) { deallocateSubBuffer(currentBuffer, alloc, uiaAlloc); } diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 66f826db8..d51797dd9 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -36,9 +36,11 @@ class Config { public: Config() { threadCount = std::max((int)std::thread::hardware_concurrency()-2, 1); + m_hardwareThreadCount = std::max((int)std::thread::hardware_concurrency()-2, 1); } public: + auto hardwareThreadCount() const -> int { return m_hardwareThreadCount;} bool renderAdt = true; bool renderWMO = true; bool renderM2 = true; @@ -196,6 +198,8 @@ class Config { double cullCombineAllObjects = 0; HRiverColorOverrideHolder colorOverrideHolder = nullptr; +private: + int m_hardwareThreadCount; }; //ADT STUFF FOR MAP GENERATION diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 2ca1f3ab0..98bf8f05e 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -9,6 +9,8 @@ #include #endif +#include "Tracy.hpp" + void SceneComposer::processCaches(int limit) { if (m_apiContainer->cacheStorage) { m_apiContainer->cacheStorage->processCaches(limit); @@ -23,6 +25,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon if (m_supportThreads) { loadingResourcesThread = std::thread([&]() { + tracy::SetThreadName("ResourceLoader"); using namespace std::chrono_literals; while (!this->m_isTerminating) { std::this_thread::sleep_for(1ms); @@ -34,6 +37,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon cullingThread = std::thread(([&]() { using namespace std::chrono_literals; FrameCounter frameCounter; + tracy::SetThreadName("Culling"); while (!this->m_isTerminating) { auto frameScenario = cullingInput.waitForNewInput(); @@ -90,6 +94,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon } void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { + ZoneScoped ; if (frameScenario == nullptr) return; @@ -100,6 +105,8 @@ void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions) { + ZoneScoped ; + if (frameScenario == nullptr) return; @@ -113,6 +120,7 @@ void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFuncs) { + ZoneScoped ; deviceDrawFrame.beginMeasurement(); m_apiContainer->hDevice->drawFrame(renderFuncs); deviceDrawFrame.endMeasurement(); @@ -128,6 +136,7 @@ void SceneComposer::consumeDraw(const std::vector> adtArray = {}; + M2ObjectListContainer m2Array; WMOListContainer wmoArray; WMOGroupListContainer wmoGroupArray; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 5e51a62eb..7d5713312 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -5,6 +5,7 @@ #include "MapSceneRenderer.h" #include "../../engine/objects/scenes/map.h" #include "../../gapi/interface/sortLambda.h" +#include "Tracy.hpp" std::shared_ptr MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { @@ -19,7 +20,7 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan, +void MapSceneRenderer:: collectMeshes(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, @@ -85,12 +86,11 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende //No need to sort array which has only one element sortMeshCounter.beginMeasurement(); if (transparentMeshes.size() > 1) { - tbb::parallel_sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); + std::sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); } if (skyTransparentMeshes.size() > 1) { - tbb::parallel_sort(skyTransparentMeshes.begin(), skyTransparentMeshes.end(), SortMeshes); + std::sort(skyTransparentMeshes.begin(), skyTransparentMeshes.end(), SortMeshes); } - sortMeshCounter.endMeasurement(); mapProduceUpdateCounter.endMeasurement(); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index ee202c143..833d8511a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -11,6 +11,8 @@ #include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" #include "materials/IMaterialInstance.h" #include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" +#include "Tracy.hpp" +#include MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { @@ -503,6 +505,8 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + ZoneScoped; + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); @@ -526,6 +530,25 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } + + //Create meshes + auto opaqueMeshes = std::make_shared>(); + auto transparentMeshes = std::make_shared>(); + + auto skyOpaqueMeshes = std::make_shared>(); + auto skyTransparentMeshes = std::make_shared>(); + framePlan->m2Array.lock(); + framePlan->wmoArray.lock(); + framePlan->wmoGroupArray.lock(); + + TracyMessageL("collect meshes created"); + std::future collectMeshAsync = std::async(std::launch::async, + [&]() { + collectMeshes(framePlan, opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes); + } + ); + mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); mapScene->updateBuffers(framePlan); @@ -533,14 +556,12 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); - //Create meshes - auto opaqueMeshes = std::make_shared>(); - auto transparentMeshes = std::make_shared>(); - auto skyOpaqueMeshes = std::make_shared>(); - auto skyTransparentMeshes = std::make_shared>(); + { + ZoneScopedN("collect meshes wait"); + collectMeshAsync.wait(); + } - collectMeshes(framePlan, opaqueMeshes, transparentMeshes, skyOpaqueMeshes, skyTransparentMeshes); bool renderSky = framePlan->renderSky; auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; @@ -553,23 +574,26 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // --------------------- // Upload stuff // --------------------- - uploadCmd.submitBufferUploads(l_this->uboBuffer); - uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); - - uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); - - uploadCmd.submitBufferUploads(l_this->vboM2Buffer); - uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); - uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); - uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); - uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); - - uploadCmd.submitBufferUploads(l_this->iboBuffer); - uploadCmd.submitBufferUploads(l_this->m_vboQuad); - uploadCmd.submitBufferUploads(l_this->m_iboQuad); + { + ZoneScopedN("submit buffers"); + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + + uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); + } // ---------------------- // Draw meshes @@ -584,8 +608,11 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha true ); - for (auto const &mesh: *opaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + { + ZoneScopedN("submit opaque"); + for (auto const &mesh: *opaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } } if (true) { if (renderSky && skyMesh) @@ -609,7 +636,10 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha if (renderSky && skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } - for (auto const &mesh: *transparentMeshes) { + { + ZoneScopedN("submit transparent"); + for (auto const &mesh: *transparentMeshes) { + // std::string debugMess = // "Drawing mesh " // " meshType = " + std::to_string((int)mesh->getMeshType()) + @@ -619,7 +649,8 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } } } From ac8e19582a4340dc07963041b751caeff94f381c Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 22 Jun 2023 03:11:00 +0300 Subject: [PATCH 085/212] wheel capture for map selection and more proper zoom --- src/ui/FrontendUI.cpp | 72 ++++++++++++------- src/ui/imguiLib/wheelCapture/wheelCapture.cpp | 21 ++++++ src/ui/imguiLib/wheelCapture/wheelCapture.h | 13 ++++ 3 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 src/ui/imguiLib/wheelCapture/wheelCapture.cpp create mode 100644 src/ui/imguiLib/wheelCapture/wheelCapture.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index a4fde569c..aed405410 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -34,6 +34,7 @@ #include "renderer/uiScene/IFrontendUIBufferCreate.h" #include "renderer/uiScene/FrontendUIRendererFactory.h" #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h" +#include "wheelCapture/wheelCapture.h" FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { m_api = api; @@ -510,21 +511,35 @@ void FrontendUI::showAdtSelectionMinimap() { ImGui::BeginChild("Adt selection minimap", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_AlwaysVerticalScrollbar); - if (minimapZoom < 0.001) - minimapZoom = 0.001; + float wheel = 0.0f; + + float pivotForZoomX; + float pivotForZoomY; + { + auto windowSize = ImGui::GetWindowSize(); + const ImGuiStyle &style = ImGui::GetStyle(); + + if (ImGui::CaptureMouseWheel(wheel)) { + minimapZoom += wheel * 0.1; + auto windowPos = ImGui::GetWindowPos(); + auto mousePos = ImGui::GetMousePos(); + + float windowRelativeMouseX = mousePos.x - windowPos.x - style.WindowPadding.x / 2.0f; + float windowRelativeMouseY = mousePos.y - windowPos.y - style.WindowPadding.y / 2.0f; + + pivotForZoomX = windowRelativeMouseX; + pivotForZoomY = windowRelativeMouseY; + } else { + pivotForZoomX = ((windowSize.x - style.WindowPadding.x) / 2.0f); + pivotForZoomY = ((windowSize.x - style.WindowPadding.y) / 2.0f); + } + } + + if (minimapZoom < 0.1) + minimapZoom = 0.1; -// TODO: create a custom component with internal dependency to not pollute this file -// ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY); -// if (ImGui::IsItemHovered()) -// { -// float wheel = ImGui::GetIO().MouseWheel; -// if (!feq(wheel, 0.0f)) -// { -// wheel; -// } -// } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); @@ -542,18 +557,23 @@ void FrontendUI::showAdtSelectionMinimap() { if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j], ImVec2(prevZoomedSize, prevZoomedSize))) { auto mousePos = ImGui::GetMousePos(); - ImGuiStyle &style = ImGui::GetStyle(); + const ImGuiStyle &style = ImGui::GetStyle(); + auto content = ImGui::GetWindowContentRegionMin(); + auto windowPos = ImGui::GetWindowPos(); + auto windowSize = ImGui::GetWindowSize(); + + float windowRelativeMouseX = mousePos.x - windowPos.x - style.WindowPadding.x / 2.0f; + float windowRelativeMouseY = mousePos.y - windowPos.y - style.WindowPadding.y / 2.0f; - mousePos.x += ImGui::GetScrollX() - ImGui::GetWindowPos().x - style.WindowPadding.x; - mousePos.y += ImGui::GetScrollY() - ImGui::GetWindowPos().y - style.WindowPadding.y; + float screenSpaceCoordX = ImGui::GetScrollX() + windowRelativeMouseX - style.WindowPadding.x / 2.0f; + float screenSpaceCoordY = ImGui::GetScrollY() + windowRelativeMouseY - style.WindowPadding.y / 2.0f; - mousePos.x = ((mousePos.x / prevMinimapZoom) / defaultImageDimension); - mousePos.y = ((mousePos.y / prevMinimapZoom) / defaultImageDimension); + float adtIndexX = (screenSpaceCoordX) / (prevMinimapZoom * defaultImageDimension); + float adtIndexY = (screenSpaceCoordY) / (prevMinimapZoom * defaultImageDimension); - worldPosX = AdtIndexToWorldCoordinate(mousePos.y); - worldPosY = AdtIndexToWorldCoordinate(mousePos.x); + worldPosX = AdtIndexToWorldCoordinate(adtIndexY); //? + worldPosY = AdtIndexToWorldCoordinate(adtIndexX); -// if () ImGui::OpenPopup("AdtWorldCoordsTest"); std::cout << "world coords : x = " << worldPosX << " y = " << worldPosY << std::endl; @@ -592,15 +612,13 @@ void FrontendUI::showAdtSelectionMinimap() { auto windowSize = ImGui::GetWindowSize(); auto scrollX = ImGui::GetScrollX(); auto scrollY = ImGui::GetScrollY(); - - auto maxScrollX = ImGui::GetScrollMaxX(); - auto maxScrollY = ImGui::GetScrollMaxY(); + const ImGuiStyle &style = ImGui::GetStyle(); - float newScrollX = (scrollX + windowSize.x / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.x / 2.0f; - float newScrollY = (scrollY + windowSize.y / 2.0f) * minimapZoom / prevMinimapZoom - windowSize.y / 2.0f; + float pivotX = ImGui::GetScrollX() + pivotForZoomX - style.WindowPadding.x / 2.0f; + float pivotY = ImGui::GetScrollY() + pivotForZoomY - style.WindowPadding.y / 2.0f; - newScrollX = trunc(newScrollX); - newScrollY = trunc(newScrollY); + float newScrollX = (pivotX) * minimapZoom / prevMinimapZoom - pivotForZoomX + style.WindowPadding.x / 2.0f; + float newScrollY = (pivotY) * minimapZoom / prevMinimapZoom - pivotForZoomY + style.WindowPadding.y / 2.0f; ImGui::SetScrollX(newScrollX); ImGui::SetScrollY(newScrollY); diff --git a/src/ui/imguiLib/wheelCapture/wheelCapture.cpp b/src/ui/imguiLib/wheelCapture/wheelCapture.cpp new file mode 100644 index 000000000..e7f6ccf96 --- /dev/null +++ b/src/ui/imguiLib/wheelCapture/wheelCapture.cpp @@ -0,0 +1,21 @@ +// +// Created by Deamon on 6/22/2023. +// + +#include "wheelCapture.h" +#include "imgui_internal.h" +#include "../../../../wowViewerLib/src/engine/algorithms/mathHelper.h" + +bool ImGui::CaptureMouseWheel(float &wheel) { + ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY); + if ((IsKeyDown(ImGuiKey_RightCtrl) || IsKeyDown(ImGuiKey_LeftCtrl))) { + if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows )) { + + + wheel = ImGui::GetIO().MouseWheel; + return !feq(wheel, 0.0); + } + } + + return false; +} \ No newline at end of file diff --git a/src/ui/imguiLib/wheelCapture/wheelCapture.h b/src/ui/imguiLib/wheelCapture/wheelCapture.h new file mode 100644 index 000000000..a0dd3c30d --- /dev/null +++ b/src/ui/imguiLib/wheelCapture/wheelCapture.h @@ -0,0 +1,13 @@ +// +// Created by Deamon on 6/22/2023. +// + +#ifndef AWEBWOWVIEWERCPP_WHEELCAPTURE_H +#define AWEBWOWVIEWERCPP_WHEELCAPTURE_H + +namespace ImGui { + bool CaptureMouseWheel(float &wheel); +} + + +#endif //AWEBWOWVIEWERCPP_WHEELCAPTURE_H From f289fd06c94a3198b12b2b9caab458402688e0a0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 4 Jul 2023 15:03:47 +0300 Subject: [PATCH 086/212] Add support for Dynamic UBO --- CMakeLists.txt | 5 +- src/ui/FrontendUI.cpp | 20 ++--- src/ui/renderer/uiScene/FrontendUIRenderer.h | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- wowViewerLib/CMakeLists.txt | 21 +++-- .../glsl/forwardRendering/m2Shader.frag | 1 - .../glsl/forwardRendering/m2Shader.vert | 1 + .../src/engine/managers/animationManager.cpp | 21 +---- .../src/engine/managers/animationManager.h | 1 - .../managers/particles/particleEmitter.cpp | 4 + .../src/engine/objects/m2/m2Object.cpp | 26 +++--- wowViewerLib/src/engine/objects/m2/m2Object.h | 1 + .../src/engine/objects/scenes/map.cpp | 36 ++++---- .../persistance/header/commonFileStructs.h | 4 +- wowViewerLib/src/gapi/interface/IDevice.h | 2 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 25 +++--- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 29 +++++- ...BufferChunkVLK.cpp => CBufferChunkVLK.cpp} | 2 +- .../{IBufferChunkVLK.h => CBufferChunkVLK.h} | 6 +- .../vulkan/buffers/GBufferChunkDynamicVLK.cpp | 5 ++ .../vulkan/buffers/GBufferChunkDynamicVLK.h | 90 +++++++++++++++++++ .../CommandBufferRecorder.cpp | 9 +- .../TextureUploadHelper.cpp | 2 + .../descriptorSets/GDescriptorPoolVLK.cpp | 14 ++- .../descriptorSets/GDescriptorPoolVLK.h | 1 + .../vulkan/descriptorSets/GDescriptorSet.cpp | 32 ++++++- .../vulkan/descriptorSets/GDescriptorSet.h | 12 ++- .../descriptorSets/GDescriptorSetLayout.cpp | 22 ++++- .../descriptorSets/GDescriptorSetLayout.h | 7 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 24 ++++- .../vulkan/materials/MaterialBuilderVLK.h | 8 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 1 + .../vulkan/shaders/GShaderPermutationVLK.cpp | 29 +++--- .../vulkan/shaders/GShaderPermutationVLK.h | 12 +-- .../src/gapi/vulkan/shaders/ShaderConfig.h | 15 ++++ .../renderer/mapScene/MapSceneRenderer.cpp | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 67 +++++++------- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 9 +- 38 files changed, 410 insertions(+), 161 deletions(-) rename wowViewerLib/src/gapi/vulkan/buffers/{IBufferChunkVLK.cpp => CBufferChunkVLK.cpp} (58%) rename wowViewerLib/src/gapi/vulkan/buffers/{IBufferChunkVLK.h => CBufferChunkVLK.h} (91%) create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3490bd6a3..34641cbf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,10 @@ set(SOURCE_FILES src/ui/renderer/uiScene/ImGUIPlan.h src/ui/renderer/uiScene/IFrontendUIBufferCreate.h src/ui/renderer/uiScene/materials/UIMaterial.h - src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h) + src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp + src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h + src/ui/imguiLib/wheelCapture/wheelCapture.cpp + src/ui/imguiLib/wheelCapture/wheelCapture.h) set(SOURCE_FILES_VULKAN diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index aed405410..4d7661d89 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -108,8 +108,8 @@ void FrontendUI::composeUI() { static bool show_demo_window = true; - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); +// if (show_demo_window) +// ImGui::ShowDemoWindow(&show_demo_window); if (m_databaseUpdateWorkflow != nullptr) { if (m_databaseUpdateWorkflow->isDatabaseUpdated()) { @@ -520,7 +520,7 @@ void FrontendUI::showAdtSelectionMinimap() { const ImGuiStyle &style = ImGui::GetStyle(); if (ImGui::CaptureMouseWheel(wheel)) { - minimapZoom += wheel * 0.1; + minimapZoom = pow(2.0f, (std::log(minimapZoom)/std::log(2.0f)) + wheel * 0.1f); auto windowPos = ImGui::GetWindowPos(); auto mousePos = ImGui::GetMousePos(); @@ -546,10 +546,10 @@ void FrontendUI::showAdtSelectionMinimap() { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - const float defaultImageDimension = 100; - int newZoomedSize = (defaultImageDimension * minimapZoom); + const float defaultImageDimension = 100.0f; + float newZoomedSize = defaultImageDimension * minimapZoom; if (prevZoomedSize == 0) - prevZoomedSize = defaultImageDimension * prevMinimapZoom; + prevZoomedSize = defaultImageDimension * prevMinimapZoom; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { @@ -568,8 +568,8 @@ void FrontendUI::showAdtSelectionMinimap() { float screenSpaceCoordX = ImGui::GetScrollX() + windowRelativeMouseX - style.WindowPadding.x / 2.0f; float screenSpaceCoordY = ImGui::GetScrollY() + windowRelativeMouseY - style.WindowPadding.y / 2.0f; - float adtIndexX = (screenSpaceCoordX) / (prevMinimapZoom * defaultImageDimension); - float adtIndexY = (screenSpaceCoordY) / (prevMinimapZoom * defaultImageDimension); + float adtIndexX = (screenSpaceCoordX) / (prevZoomedSize); + float adtIndexY = (screenSpaceCoordY) / (prevZoomedSize); worldPosX = AdtIndexToWorldCoordinate(adtIndexY); //? worldPosY = AdtIndexToWorldCoordinate(adtIndexX); @@ -617,8 +617,8 @@ void FrontendUI::showAdtSelectionMinimap() { float pivotX = ImGui::GetScrollX() + pivotForZoomX - style.WindowPadding.x / 2.0f; float pivotY = ImGui::GetScrollY() + pivotForZoomY - style.WindowPadding.y / 2.0f; - float newScrollX = (pivotX) * minimapZoom / prevMinimapZoom - pivotForZoomX + style.WindowPadding.x / 2.0f; - float newScrollY = (pivotY) * minimapZoom / prevMinimapZoom - pivotForZoomY + style.WindowPadding.y / 2.0f; + float newScrollX = (pivotX) * minimapZoom / prevMinimapZoom - pivotForZoomX + style.WindowPadding.x / 2.0f; + float newScrollY = (pivotY) * minimapZoom / prevMinimapZoom - pivotForZoomY + style.WindowPadding.y / 2.0f; ImGui::SetScrollX(newScrollX); ImGui::SetScrollY(newScrollY); diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index ad176c669..46e475779 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -9,7 +9,7 @@ #include "ImGUIPlan.h" #include "../../../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" #include "IFrontendUIBufferCreate.h" -#include "../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" static const std::array imguiBindings = {{ {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index fb1da153d..26dbd47b6 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -5,7 +5,7 @@ #include "FrontendUIRenderForwardVLK.h" #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h" -#include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h" @@ -56,7 +56,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}, {}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 193203830..e91d096a0 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -350,7 +350,14 @@ set(SOURCE_FILES src/gapi/interface/materials/IMaterial.h src/renderer/mapScene/MapSceneParams.h src/include/custom_container_key.h - src/renderer/mapScene/materials/IMaterialStructs.h src/gapi/interface/textures/ITextureSampler.h src/gapi/interface/textures/ISamplableTexture.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h src/engine/objects/liquid/LiquidDataGetters.h) + src/renderer/mapScene/materials/IMaterialStructs.h + src/gapi/interface/textures/ITextureSampler.h + src/gapi/interface/textures/ISamplableTexture.h + src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp + src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h + src/engine/objects/liquid/LiquidInstance.cpp + src/engine/objects/liquid/LiquidInstance.h + src/engine/objects/liquid/LiquidDataGetters.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -512,8 +519,8 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/IBufferVLK.h src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp src/gapi/vulkan/materials/ISimpleMaterialVLK.h - src/gapi/vulkan/buffers/IBufferChunkVLK.cpp - src/gapi/vulkan/buffers/IBufferChunkVLK.h + src/gapi/vulkan/buffers/CBufferChunkVLK.cpp + src/gapi/vulkan/buffers/CBufferChunkVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -544,7 +551,11 @@ if (LINK_VULKAN) src/gapi/vulkan/textures/GTextureSamplerVLK.cpp src/gapi/vulkan/textures/GTextureSamplerVLK.h src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.cpp - src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h) + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferDebugLabel.h + src/gapi/vulkan/context/vulkan_context.h + src/gapi/vulkan/shaders/ShaderConfig.h + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) @@ -588,7 +599,7 @@ if (LINK_VULKAN) # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() #Add volk loader - set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c src/gapi/vulkan/context/vulkan_context.h src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.cpp src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h) + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c ) endif() diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index ec4c38e1d..06a70e6a7 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -91,7 +91,6 @@ void main() { vMeshColorAlpha.a *= textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightIndexes.x / 4][textureWeightIndexes.x % 4]; - vec3 l_Normal = vNormal; //Accumulate and apply lighting diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 3734acfa0..cad7f7c59 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -90,6 +90,7 @@ void main() { mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); + vec3 minusNormal = normalize((viewModelMatForNormal * vec4(-aNormal, 0.0)).xyz); vTexCoord = aTexCoord; vTexCoord2 = aTexCoord2; diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index c569c4508..19ac1ee81 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -32,7 +32,6 @@ AnimationManager::AnimationManager(HApiContainer api, std::shared_ptrfirstCalc = true; this->initBonesIsCalc(); - this->initBlendMatrices(); this->initGlobalSequenceTimes(); this->calculateBoneTree(); @@ -50,13 +49,6 @@ void AnimationManager::initBonesIsCalc() { } } -void AnimationManager::initBlendMatrices() { - auto &bones = *boneMasterData->getSkelData()->m_m2CompBones; - - unsigned long matCount = (unsigned long) std::max(bones.size, boneMasterData->getM2Geom()->getM2Data()->texture_transforms.size); - blendMatrixArray = std::vector(matCount, mathfu::mat4::Identity()); -} - void AnimationManager::initGlobalSequenceTimes() { globalSequenceTimes = std::vector( (unsigned long) (boneMasterData->getSkelData()->m_globalSequences->size > 0 ? @@ -116,7 +108,7 @@ bool AnimationManager::setAnimationId(int animationId, bool reset) { bool animationIsBanned = false; //Test against PABC auto &bannedAnims = boneMasterData->getM2Geom()->blackListAnimations; - for (auto const a : bannedAnims) { + for (auto const &a : bannedAnims) { if (a == animationId) { animationIsBanned = true; break; @@ -170,15 +162,6 @@ bool AnimationManager::setAnimationId(int animationId, bool reset) { return (animationIndex > -1); } -void blendMatrices(std::vector &origMat, std::vector &blendMat, int count, float blendAlpha) { -//Actual blend - for (int i = 0; i < count; i++) { -// mathfu::mat4 &blendTransformMatrix = blendMat[i]; -// mathfu::mat4 &tranformMat = origMat[i]; - origMat[i] = ((blendMat[i] - origMat[i]) * (const float &) (1.0 - blendAlpha)) + origMat[i]; - } -} - template inline void calcAnimationTransform( mathfu::mat4 &tranformMat, @@ -862,6 +845,8 @@ void AnimationManager::update( } this->animationInfo.currentAnimation = this->animationInfo.nextSubAnimation; + //Update bounding box + this->firstCalc = true; diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index 557b5e74a..ee3e22dde 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -37,7 +37,6 @@ class AnimationManager { std::vector> childBonesLookup; void initBonesIsCalc(); - void initBlendMatrices(); void initGlobalSequenceTimes(); void calculateBoneTree(); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 5f42dffe6..ca0915136 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -445,6 +445,10 @@ void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathf } this->InternalUpdate(delta); } + + const HGParticleMesh &mesh = frame[m_api->hDevice->getDrawFrameNumber()].m_mesh; + mesh->setSortDistance(m_currentBonePos); + } //void ParticleEmitter::Sync() { // diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 9e991c3f7..f2cf31c2e 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -600,6 +600,7 @@ void M2Object:: createPlacementMatrix(SMODoodadDef &def, mathfu::mat4 &wmoPlacem m_localPosition = mathfu::vec3(def.position); m_placementMatrix = placementMatrix; m_placementInvertMatrix = invertPlacementMatrix; + m_placementMatrixChanged = true; m_localUpVector = (invertPlacementMatrix * mathfu::vec4(0,0,1,0)).xyz().Normalized(); @@ -630,6 +631,7 @@ void M2Object::createPlacementMatrix(SMDoodadDef &def) { m_localPosition = mathfu::vec3(def.position); m_placementInvertMatrix = placementInvertMatrix; m_placementMatrix = placementMatrix; + m_placementMatrixChanged = true; m_localUpVector = (placementInvertMatrix * mathfu::vec4(0,0,1,0)).xyz().Normalized(); m_localRightVector = (placementInvertMatrix * mathfu::vec4(1,0,0,0)).xyz().Normalized(); @@ -649,6 +651,7 @@ void M2Object::createPlacementMatrix (mathfu::vec3 pos, float f, mathfu::vec3 sc mathfu::mat4 placementInvertMatrix = placementMatrix.Inverse(); m_placementInvertMatrix = placementInvertMatrix; m_placementMatrix = placementMatrix; + m_placementMatrixChanged = true; m_localUpVector = (placementInvertMatrix * mathfu::vec4(0,0,1,0)).xyz().Normalized(); m_localRightVector = (placementInvertMatrix * mathfu::vec4(1,0,0,0)).xyz().Normalized(); @@ -678,6 +681,7 @@ void M2Object::updatePlacementMatrixFromParentAttachment(M2Object *parent, int a m_placementInvertMatrix = placementInvertMatrix; m_placementMatrix = placementMatrix; + m_placementMatrixChanged = true; m_localUpVector = (placementInvertMatrix * mathfu::vec4(0,0,1,0)).xyz().Normalized(); m_localRightVector = (placementInvertMatrix * mathfu::vec4(1,0,0,0)).xyz().Normalized(); @@ -935,6 +939,7 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v if (m_boolSkybox && m_overrideSkyModelMat) { m_placementMatrix.GetColumn(3) = mathfu::vec4(cameraPos, 1.0); + m_placementMatrixChanged = true; m_placementInvertMatrix = m_placementMatrix.Inverse(); } @@ -1010,16 +1015,17 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { if (!this->m_loaded) return; - mathfu::mat4 modelViewMat = viewMat * m_placementMatrix; +// mathfu::mat4 modelViewMat = viewMat * m_placementMatrix; M2Data * m2File = this->m_m2Geom->getM2Data(); M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); //Update materials - { + if (m_placementMatrixChanged) { auto &placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); placementMatrix.uPlacementMat = m_placementMatrix; m_modelWideDataBuff->m_placementMatrix->save(); + m_placementMatrixChanged = false; } if (bonesMatrices.size() > 0) { auto &bonesData = m_modelWideDataBuff->m_bonesData->getObject(); @@ -1267,7 +1273,7 @@ void M2Object::createBoundingBoxMesh(const HMapSceneBufferCreate &sceneRenderer) return; //Create bounding box mesh - HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", nullptr); +// HGShaderPermutation boundingBoxshaderPermutation = m_api->hDevice->getShader("drawBBShader", "drawBBShader", ); //TODO: PipelineTemplate pipelineTemplate; @@ -1960,22 +1966,22 @@ void M2Object::updateDynamicMeshes() { for (int vertIndex = skinSection->vertexStart; vertIndex < (skinSection->vertexStart + skinSection->vertexCount); ++vertIndex) { auto &overrideVert = overrideVertexes[vertIndex - skinSection->vertexStart]; - overrideVert = *m2Data->vertices[vertIndex]; + auto const &originalVert = *m2Data->vertices[vertIndex]; mathfu::mat4 matrix = mathfu::mat4::Identity(); - if (overrideVert.bone_indices[0] > 0) { - matrix = bonesMatrices[overrideVert.bone_indices[0]] * overrideVert.bone_weights[0]; + if (originalVert.bone_indices[0] > 0) { + matrix = bonesMatrices[originalVert.bone_indices[0]] * originalVert.bone_weights[0]; } for (int i = 1; i < MAX_BONES_PER_VERTEX; i++) { if (overrideVert.bone_indices[i] > 0) { - matrix += (bonesMatrices[overrideVert.bone_indices[i]] * overrideVert.bone_weights[i]); + matrix += (bonesMatrices[originalVert.bone_indices[i]] * originalVert.bone_weights[i]); } } - overrideVert.pos = - mathfu::vec3_packed(rootMatInverse * matrix * mathfu::vec4(mathfu::vec3(overrideVert.pos), 1.0).xyz()); - + overrideVert = originalVert; + overrideVert.pos = + mathfu::vec3_packed(rootMatInverse * matrix * mathfu::vec4(mathfu::vec3(originalVert.pos), 1.0).xyz()); overrideVert.bone_indices[0] = 0; overrideVert.bone_indices[1] = 0; overrideVert.bone_indices[2] = 0; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 935e2d02c..c96f42198 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -68,6 +68,7 @@ class M2Object { private: mathfu::mat4 m_placementMatrix = mathfu::mat4::Identity(); + bool m_placementMatrixChanged = false; mathfu::mat4 m_placementInvertMatrix; mathfu::vec3 m_worldPosition; mathfu::vec3 m_localPosition; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 08b2e4764..6aa0f421a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1560,25 +1560,25 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { int granSize = m2ToDraw.size() / (2 * threadsAvailable); if (granSize == 0) granSize = m2ToDraw.size(); - if (granSize > 0) { - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } - } - }, tbb::simple_partitioner()); - } - -// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { -// if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, -// renderPlan->frameDependentData); -// } +// if (granSize > 0) { +// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), +// [&](tbb::blocked_range r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { +// auto &m2Object = m2ToDraw[i]; +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } +// }, tbb::simple_partitioner()); // } + + for (auto &m2Object: renderPlan->m2Array.getDrawn()) { + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h index a309d1099..77268da6c 100644 --- a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h +++ b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h @@ -236,9 +236,9 @@ struct M2Sequence { uint32_t flags; // See below. int16_t frequency; // This is used to determine how often the animation is played. For all animations of the same type, this adds up to 0x7FFF (32767). uint16_t _padding; - M2RangeInt replay; // May both be 0 to not repeat. Client will pick a random number of repetitions within bounds if given. + M2RangeInt replay; // May both be 0 to not repeat. Client will pick a random number of repetitions within bounds if given. uint32_t blendtime; // The client blends (lerp) animation states between animations where the end and start values differ. This specifies how long that blending takes. Values: 0, 50, 100, 150, 200, 250, 300, 350, 500. - M2Bounds bounds; + M2Bounds bounds; // Bounding box int16_t variationNext; // id of the following animation of this AnimationID, points to an Index or is -1 if none. uint16_t aliasNext; // id in the list of animations. Used to find actual animation if this sequence is an alias (flags & 0x40) }; diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 78910d18a..5fccd8520 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -188,8 +188,6 @@ class IDevice { virtual double getWaitForUpdate() {return 0;} public: - virtual HGShaderPermutation getShader(std::string shaderName, std::string fragmentName, void *permutationDescriptor) = 0; - virtual HGPUFence createFence() = 0; virtual HGVertexBufferBindings createVertexBufferBindings() = 0; //Creates or receives framebuffer and tells it would be occupied for frameNumber frames diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 034daea0a..bb5448802 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -25,6 +25,7 @@ #include "synchronization/GFenceVLK.h" #include "../../renderer/vulkan/IRenderFunctionVLK.h" #include "commandBuffer/commandBufferRecorder/TextureUploadHelper.h" +#include "Tracy.hpp" #include const int WIDTH = 1900; @@ -801,6 +802,7 @@ float GDeviceVLK::getAnisLevel() { } void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { + ZoneScoped; this->waitInDrawStageAndDeps.beginMeasurement(); int currentDrawFrame = getDrawFrameNumber(); @@ -811,7 +813,7 @@ void GDeviceVLK::drawFrame(const std::vector> & uint32_t imageIndex = -1; { { - + ZoneScopedN("frameBuf CMD wait"); //Wait for frameBuf CMD buffer to become available frameBufFences[currentDrawFrame]->wait(std::numeric_limits::max()); uploadFences[currentDrawFrame]->wait(std::numeric_limits::max()); @@ -825,6 +827,7 @@ void GDeviceVLK::drawFrame(const std::vector> & //Do Texture update { + ZoneScopedN("Texture update"); m_textureManager->processBLPTextures(); auto textureVector = m_textureManager->getReadyToUploadTextures(); textureUploadStrategy(textureVector.get(), frameBufCmd, uploadCmd); @@ -838,6 +841,7 @@ void GDeviceVLK::drawFrame(const std::vector> & //Wait for swapchain { + ZoneScopedN("Swapchain wait"); inFlightFences[currentDrawFrame]->wait(std::numeric_limits::max()); inFlightFences[currentDrawFrame]->reset(); } @@ -1040,20 +1044,21 @@ void GDeviceVLK::updateBuffers(std::vector &frameDepedantDa void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) {} -std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) { - std::string combinedName = vertexName + " " + fragmentName; - const char * cstr = combinedName.c_str(); - size_t hash = CalculateFNV(cstr); - if (m_shaderPermuteCache.count(hash) > 0) { - HGShaderPermutation ptr = m_shaderPermuteCache.at(hash); +std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConfig) { + + ShaderPermutationCacheRecord cacheRecord; + cacheRecord.name = vertexName + " " + fragmentName; + cacheRecord.shaderConfig = shaderConfig; + + if (m_shaderPermuteCache.find(cacheRecord) != m_shaderPermuteCache.end()) { + HGShaderPermutation ptr = m_shaderPermuteCache.at(cacheRecord); return ptr; } - std::shared_ptr sharedPtr = std::make_shared(vertexName, fragmentName, this->shared_from_this()); + std::shared_ptr sharedPtr = std::make_shared(vertexName, fragmentName, this->shared_from_this(), shaderConfig); sharedPtr->compileShader("", ""); - m_shaderPermuteCache[hash] = sharedPtr; - + m_shaderPermuteCache[cacheRecord] = sharedPtr; return sharedPtr; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index a7725188a..bbd90ee31 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -42,6 +42,7 @@ class gMeshTemplate; #include "synchronization/GSemaphoreVLK.h" #include "commandBuffer/commandBufferRecorder/RenderPassHelper.h" #include "TextureManagerVLK.h" +#include "shaders/ShaderConfig.h" #include @@ -101,7 +102,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thiswaitInDrawStageAndDeps.getTimePerFrame(); } - std::shared_ptr getShader(std::string vertexName, std::string fragmentName, void *permutationDescriptor) override; + std::shared_ptr getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); HGBufferVLK createUniformBuffer(size_t size); HGBufferVLK createVertexBuffer(size_t size); @@ -329,10 +330,30 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_textureManager; protected: //Caches - std::unordered_map m_shaderPermuteCache; - struct FrameUniformBuffers { - HGUniformBuffer m_uniformBufferForUpload; + + struct ShaderPermutationCacheRecord { + std::string name; + ShaderConfig shaderConfig; + + bool operator==(const ShaderPermutationCacheRecord &other) const { + return + (name == other.name) && + (shaderConfig.typeOverrides == other.shaderConfig.typeOverrides); + }; + }; + struct ShaderPermutationRecordHasher { + std::size_t operator()(const ShaderPermutationCacheRecord& k) const { + using std::hash; + + size_t mapHash = 0; + for (auto &rec : k.shaderConfig.typeOverrides) + mapHash ^= hash{}(rec.second) ^ hash{}(rec.first); + + return hash{}(k.name) ^ mapHash; + + }; }; + std::unordered_map m_shaderPermuteCache; std::vector aggregationBufferForUpload = std::vector(1024*1024); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.cpp similarity index 58% rename from wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp rename to wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.cpp index 52d62d2ea..75102d08d 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.cpp @@ -2,4 +2,4 @@ // Created by Deamon on 30.01.23. // -#include "IBufferChunkVLK.h" +#include "CBufferChunkVLK.h" diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h similarity index 91% rename from wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h rename to wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index b11a5344c..e9558c1dd 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -2,8 +2,8 @@ // Created by Deamon on 30.01.23. // -#ifndef AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H -#define AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H +#ifndef AWEBWOWVIEWERCPP_CBUFFERCHUNKVLK_H +#define AWEBWOWVIEWERCPP_CBUFFERCHUNKVLK_H #include "../../interface/buffers/IBufferChunk.h" @@ -52,4 +52,4 @@ namespace BufferChunkHelperVLK { } }; -#endif //AWEBWOWVIEWERCPP_IBUFFERCHUNKVLK_H +#endif //AWEBWOWVIEWERCPP_CBUFFERCHUNKVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp new file mode 100644 index 000000000..b096d6025 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 7/2/2023. +// + +#include "GBufferChunkDynamicVLK.h" diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h new file mode 100644 index 000000000..1857ac13b --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -0,0 +1,90 @@ +// +// Created by Deamon on 7/2/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVLK_H +#define AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVLK_H + + +#include "../../interface/buffers/IBufferChunk.h" +#include "GBufferVLK.h" + +template +class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { +public: + GBufferChunkDynamicVLK(const HGDeviceVLK &device, const std::shared_ptr &mainBuffer, int realSize = -1) : m_device(device) { + m_realSize = realSize; + + if (m_realSize < 0) + m_realSize = sizeof(T); + + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + auto subBuffer = mainBuffer->getSubBuffer(m_realSize, sizeof(T)); + subBuffers[i] = subBuffer; + pSubBuffers[i] = subBuffer.get(); + } + + iteratorUnique = pSubBuffers[0]->addOnHandleChange([&]() -> void { + this->executeOnChange(); + }); + } + + ~GBufferChunkDynamicVLK() { + pSubBuffers[0]->eraseOnHandleChange(iteratorUnique); + } + void uploadData(const void *, int length) override { + + }; + void *getPointer() override { + auto index = m_device->getUpdateFrameNumber(); + return pSubBuffers[index]->getPointer(); + }; + void save(int length) override{ + auto index = m_device->getUpdateFrameNumber(); + pSubBuffers[index]->save(m_realSize); + }; + VkBuffer getGPUBuffer() override { + auto index = m_device->getUpdateFrameNumber(); + return pSubBuffers[index]->getGPUBuffer(); + } + size_t getOffset() override { + auto index = m_device->getUpdateFrameNumber(); + return pSubBuffers[index]->getOffset(); + } + + size_t getSize() override { + return m_realSize; + } + T &getObject() override { + auto index = m_device->getUpdateFrameNumber(); + return *(T*)pSubBuffers[index]->getPointer(); + }; + void save() override { + auto index = m_device->getUpdateFrameNumber(); + pSubBuffers[index]->save(m_realSize); + }; + +private: + HGDeviceVLK m_device; + int m_realSize = 0; + void *ptr = nullptr; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> subBuffers = {nullptr}; + std::array pSubBuffers = {nullptr}; + + std::unique_ptr iteratorUnique = nullptr; +}; + +namespace DynamicBufferChunkHelperVLK { + template + static const inline std::shared_ptr cast(const std::shared_ptr> &chunk) { + return std::dynamic_pointer_cast>(chunk); + } + + template + static const inline void create(const HGDeviceVLK &device, const HGBufferVLK &parentBuffer, std::shared_ptr> &chunk, int realSize = -1) { + chunk = std::make_shared>(device, parentBuffer, realSize); + } +}; + + +#endif //AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 580918747..15f189b1a 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -89,8 +89,15 @@ void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t b auto vkDescSet = pDescriptorSet->getDescSet(); constexpr uint32_t vkDescCnt = 1; + + std::vector dynamicOffsets; + pDescriptorSet->getDynamicOffsets(dynamicOffsets); + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, - m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, 0, nullptr); + m_currentPipeline->getLayout(), + bindIndex, + vkDescCnt, &vkDescSet, + dynamicOffsets.size(), dynamicOffsets.size() > 0 ? dynamicOffsets.data() : nullptr); m_currentDescriptorSet[bindIndex] = pDescriptorSet; } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index ec717921e..7757457df 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -3,6 +3,7 @@ // #include "TextureUploadHelper.h" +#include "Tracy.hpp" void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, const std::vector> &textures, @@ -51,6 +52,7 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, } void textureUploadStrategy(const std::vector> &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) { + ZoneScoped; if (textures.empty()) return; // ------------------------------------ diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index 434135d21..385524b9c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -7,15 +7,18 @@ #include "GDescriptorPoolVLK.h" GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) { - uniformsAvailable = 40*4096; + uniformsAvailable = 4*4096; + dynUniformsAvailable = 4*4096; imageAvailable = 4096 * 4; setsAvailable = 4096 * 4; - std::array poolSizes = {}; + std::array poolSizes = {}; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].descriptorCount = static_cast(uniformsAvailable); poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSizes[1].descriptorCount = static_cast(imageAvailable); + poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + poolSizes[2].descriptorCount = static_cast(dynUniformsAvailable); VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -31,7 +34,10 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) } VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptr &hDescriptorSetLayout) { - if (uniformsAvailable < hDescriptorSetLayout->getTotalUbos() || imageAvailable < hDescriptorSetLayout->getTotalImages() || setsAvailable < 1) return nullptr; + if (uniformsAvailable < hDescriptorSetLayout->getTotalUbos() || + dynUniformsAvailable < hDescriptorSetLayout->getTotalDynUbos() || + imageAvailable < hDescriptorSetLayout->getTotalImages() || + setsAvailable < 1) return nullptr; constexpr int descSetCount = 1; std::array descLayouts = {hDescriptorSetLayout->getSetLayout()}; @@ -54,6 +60,7 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptrgetTotalUbos(); + dynUniformsAvailable -= hDescriptorSetLayout->getTotalDynUbos(); imageAvailable -= hDescriptorSetLayout->getTotalImages(); setsAvailable -= 1; } @@ -69,6 +76,7 @@ void GDescriptorPoolVLK::deallocate(const std::shared_ptr h_this->imageAvailable+= hDescriptorLayout->getTotalImages(); h_this->uniformsAvailable+= hDescriptorLayout->getTotalUbos(); + h_this->dynUniformsAvailable+= hDescriptorLayout->getTotalDynUbos(); h_this->setsAvailable+=1; }); } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h index 2f7b5d5fe..86a156978 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -23,6 +23,7 @@ class GDescriptorPoolVLK : public std::enable_shared_from_this &descriptorWrites, std::vector &imageInfo) { +void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo, std::vector &dynamicBufferIndexes) { vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); m_firstUpdate = false; + m_dynamicBufferIndexes = dynamicBufferIndexes; // m_updateBitSet |= updatedBindsBitSet; // @@ -52,6 +53,16 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de // } } +void GDescriptorSet::getDynamicOffsets(std::vector &dynamicOffsets) { + for (int i = 0; i < m_dynamicBufferIndexes.size(); i++) { + + auto &descriptor = boundDescriptors[m_dynamicBufferIndexes[i]]; + assert(descriptor->descType == DescriptorRecord::DescriptorRecordType::UBODynamic); + + dynamicOffsets.push_back(descriptor->buffer->getOffset()); + } +} + // ------------------------------------- // Update Helper @@ -61,10 +72,12 @@ GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture &samplableTextureVlk) { auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); +#if (!defined(NDEBUG)) if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { std::cerr << "descriptor mismatch for image" << std::endl; throw std::runtime_error("descriptor mismatch for image"); } +#endif auto textureVlk = samplableTextureVlk!=nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getTexture()) : nullptr; auto samplerVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getSampler()) : nullptr; @@ -110,11 +123,14 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture GDescriptorSet::SetUpdateHelper & GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_ptr &buffer) { auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); + typeOverrides[bindIndex] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; +#if (!defined(NDEBUG)) if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { std::cerr << "descriptor mismatch for UBO dynamic" << std::endl; throw std::runtime_error("descriptor mismatch for UBO dynamic"); } +#endif assignBoundDescriptors(bindIndex, buffer, DescriptorRecord::DescriptorRecordType::UBODynamic); m_updateBindPoints[bindIndex] = true; @@ -122,7 +138,7 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); bufferInfo = {}; bufferInfo.buffer = buffer->getGPUBuffer(); - bufferInfo.offset = buffer->getOffset(); + bufferInfo.offset = 0; //Mandatory for VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC to work bufferInfo.range = buffer->getSize(); VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); @@ -137,6 +153,8 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt writeDescriptor.pImageInfo = nullptr; writeDescriptor.pTexelBufferView = nullptr; + dynamicBufferIndexes.push_back(bindIndex); + return *this; } @@ -192,6 +210,8 @@ GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptr { ~GDescriptorSet(); void update(); - void writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo); + void writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo, std::vector &dynamicBufferIndexes); const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} + void getDynamicOffsets(std::vector &dynamicOffsets); @@ -54,6 +55,7 @@ class GDescriptorSet : public std::enable_shared_from_this { //TODO: add version of this array texture case (aka bindless) SetUpdateHelper& texture(int bindIndex, const HGSamplableTexture &textureVlk); + void cancelUpdate(); template void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, DescriptorRecord::DescriptorRecordType descType) { @@ -79,12 +81,19 @@ class GDescriptorSet : public std::enable_shared_from_this { m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); } } + std::unordered_map &getAccumulatedTypeOverrides() { + return typeOverrides; + } private: + bool updateCancelled = false; GDescriptorSet &m_set; std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &m_boundDescriptors; std::vector imageInfos; std::vector bufferInfos; + std::vector dynamicBufferIndexes; + std::unordered_map typeOverrides; + std::vector updates; std::bitset m_updateBindPoints = 0; @@ -98,6 +107,7 @@ class GDescriptorSet : public std::enable_shared_from_this { std::shared_ptr m_parentPool; const std::shared_ptr m_hDescriptorSetLayout; + std::vector m_dynamicBufferIndexes; bool m_firstUpdate = true; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index a238974bc..31ac12c03 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -7,7 +7,10 @@ #include "../GDeviceVulkan.h" -GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaDatas, int setIndex) : m_device(device) { +GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr &device, + const std::vector &metaDatas, + int setIndex, + const std::unordered_map &typeOverrides) : m_device(device) { //Create Layout auto &shaderLayoutBindings = m_shaderLayoutBindings; @@ -32,10 +35,17 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr if (uboBinding.set != setIndex) continue; + auto uniformType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + if (typeOverrides.find(uboBinding.binding) != typeOverrides.end()) { + auto overrideType = typeOverrides.at(uboBinding.binding); + assert(overrideType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); + uniformType = overrideType; + } + auto it = shaderLayoutBindings.find(uboBinding.binding); if (it != std::end( shaderLayoutBindings )) { it->second.stageFlags |= vkStageFlag; - if (it->second.descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + if (it->second.descriptorType != uniformType) { std::cerr << "Type mismatch for ubo in GDescriptorSetLayout" << std::endl; throw std::runtime_error("types mismatch"); } @@ -43,7 +53,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr VkDescriptorSetLayoutBinding uboLayoutBinding = {}; uboLayoutBinding.binding = uboBinding.binding; uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.descriptorType = uniformType; uboLayoutBinding.pImmutableSamplers = nullptr; uboLayoutBinding.stageFlags = vkStageFlag; @@ -58,7 +68,11 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } } } - m_totalUbos++; + if (uniformType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + m_totalUbos++; + } else if (uniformType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { + m_totalDynUbos++; + } m_requiredBindPoints[uboBinding.binding] = true; } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 85da59c53..b671ff28f 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -19,7 +19,10 @@ class GDescriptorSetLayout { public: static const constexpr int MAX_BINDPOINT_NUMBER = 16; - GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaData, int setIndex); + GDescriptorSetLayout(const std::shared_ptr &device, + const std::vector &metaData, + int setIndex, + const std::unordered_map &typeOverrides); ~GDescriptorSetLayout(); @@ -29,6 +32,7 @@ class GDescriptorSetLayout { const std::unordered_map& getRequiredUBOSize() const {return m_requiredUBOSize;} ; int getTotalUbos() { return m_totalUbos; }; + int getTotalDynUbos() { return m_totalDynUbos; }; int getTotalImages() { return m_totalImages; }; std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; private: @@ -39,6 +43,7 @@ class GDescriptorSetLayout { VkDescriptorSetLayout m_descriptorSetLayout; int m_totalImages = 0; int m_totalUbos = 0; + int m_totalDynUbos = 0; std::shared_ptr m_device; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index 0577d114b..491f349c6 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -8,11 +8,11 @@ #include "ISimpleMaterialVLK.h" MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &device, - const std::vector &shaderFiles) : m_device(device) { + const std::vector &shaderFiles, const ShaderConfig &shaderConfig) : m_device(device) { m_shader = std::dynamic_pointer_cast(device)->getShader( shaderFiles[0], - shaderFiles[1], nullptr); + shaderFiles[1], shaderConfig); } MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, @@ -28,6 +28,26 @@ MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, return *this; } +//MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, +// const std::function &, GDescriptorSet::SetUpdateHelper &)> &callback) { +// auto shaderVLK = std::dynamic_pointer_cast(m_shader); +// +// auto ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint, {})); +// auto updater = ds->beginUpdate(); +// callback(ds, updater); +// auto &overrides = updater.getAccumulatedTypeOverrides(); +// if (!overrides.empty()) { +// updater.cancelUpdate(); +// ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint, overrides)); +// auto updater2 = ds->beginUpdate(); +// callback(ds, updater2); +// } +// +// descriptorSets[bindPoint] = ds; +// +// return *this; +//} + MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::shared_ptr &ds) { //TODO: check DS layout compatibility diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 2c1ead9ab..be4f9e61f 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -8,7 +8,7 @@ #include #include #include "../../interface/IDevice.h" -#include "ISimpleMaterialVLK.h" + #include "ISimpleMaterialVLK.h" #include "../../../renderer/mapScene/vulkan/materials/IMaterialInstance.h" #include "../descriptorSets/GDescriptorSet.h" @@ -18,8 +18,8 @@ class MaterialBuilderVLK { MaterialBuilderVLK& operator=(MaterialBuilderVLK const& ) = delete; static MaterialBuilderVLK fromShader(const std::shared_ptr &device, - const std::vector &shaderFiles) { - return {device, shaderFiles}; + const std::vector &shaderFiles, const ShaderConfig &shaderConfig) { + return {device, shaderFiles, shaderConfig}; } MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); @@ -41,7 +41,7 @@ class MaterialBuilderVLK { ~MaterialBuilderVLK() = default; private: MaterialBuilderVLK(const std::shared_ptr &device, - const std::vector &shaderFiles); + const std::vector &shaderFiles, const ShaderConfig &shaderConfig); private: diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index a7346ca0a..810801680 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -18,6 +18,7 @@ GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, m_isScissorsEnabled = meshTemplate.scissorEnabled; if (m_isScissorsEnabled) { m_scissorSize = meshTemplate.scissorSize; + assert(m_scissorOffset[0] >= 0 && m_scissorOffset[1] >= 0); m_scissorOffset = meshTemplate.scissorOffset; } diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 2e75dfc02..153384a76 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -44,19 +44,25 @@ VkShaderModule GShaderPermutationVLK::createShaderModule(const std::vector } GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, - const std::shared_ptr &device) : - m_device(device), m_combinedName(shaderVertName + " "+ shaderFragName), m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName){ + const std::shared_ptr &device, + const ShaderConfig &shaderConf) : + m_device(device), m_combinedName(shaderVertName + " "+ shaderFragName), m_shaderConf(shaderConf), + m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName){ } +std::vector GShaderPermutationVLK::createMetaArray() { + return {fragShaderMeta, vertShaderMeta}; +} + void GShaderPermutationVLK::createSetDescriptorLayouts() { - std::vector metas = {fragShaderMeta, vertShaderMeta}; + std::vector metas = createMetaArray(); for (int i = 0; i < combinedShaderLayout.setLayouts.size(); i++) { auto &setLayout = combinedShaderLayout.setLayouts[i]; if (setLayout.imageBindings.length == 0 && setLayout.uboBindings.length == 0) continue; - descriptorSetLayouts[i] = std::make_shared(m_device, metas, i); + descriptorSetLayouts[i] = std::make_shared(m_device, metas, i, m_shaderConf.typeOverrides); } } @@ -77,14 +83,6 @@ void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const this->createPipelineLayout(); } -int GShaderPermutationVLK::getTextureBindingStart() { - return combinedShaderLayout.setLayouts[1].imageBindings.start; -} - -int GShaderPermutationVLK::getTextureCount() { - return combinedShaderLayout.setLayouts[1].imageBindings.length; -} - inline void makeMin(unsigned int &a, const unsigned int b) { a = std::min(a, b); } @@ -93,8 +91,6 @@ inline void makeMax(unsigned int &a, const unsigned int b) { } void GShaderPermutationVLK::createShaderLayout() { - //Check the buffer sizes - //UBO stuff for (int i = 0; i < this->vertShaderMeta->uboBindings.size(); i++) { auto &uboVertBinding = this->vertShaderMeta->uboBindings[i]; @@ -200,3 +196,8 @@ void GShaderPermutationVLK::createPipelineLayout() { } } +const std::shared_ptr +GShaderPermutationVLK::getDescriptorLayout(int bindPoint) { + return descriptorSetLayouts[bindPoint]; +} + diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index be0769e5b..bfec13638 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -13,6 +13,7 @@ #include "../descriptorSets/GDescriptorSet.h" #include "../../../engine/shader/ShaderDefinitions.h" + struct ShaderSetLayout { std::unordered_map uboSizesPerBinding; bindingAmountData uboBindings; @@ -29,17 +30,14 @@ class GShaderPermutationVLK : public IShaderPermutation { static const constexpr int UBO_SET_INDEX = 0; static const constexpr int IMAGE_SET_INDEX = 1; - explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device); + explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device, const ShaderConfig &shaderConf); ~GShaderPermutationVLK() override {}; VkShaderModule getVertexModule() {return vertShaderModule;} VkShaderModule getFragmentModule() {return fragShaderModule;} - const std::shared_ptr getDescriptorLayout(int bindPoint) {return descriptorSetLayouts[bindPoint];} - - virtual int getTextureBindingStart(); - virtual int getTextureCount(); + const std::shared_ptr getDescriptorLayout(int bindPoint); const shaderMetaData *fragShaderMeta; const shaderMetaData *vertShaderMeta; @@ -79,9 +77,11 @@ class GShaderPermutationVLK : public IShaderPermutation { std::string m_shaderNameFrag; CombinedShaderLayout combinedShaderLayout; + ShaderConfig m_shaderConf; - void createSetDescriptorLayouts(); + void createSetDescriptorLayouts(); + std::vector createMetaArray(); void createShaderLayout(); void createPipelineLayout(); }; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h new file mode 100644 index 000000000..6e1c44a82 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -0,0 +1,15 @@ +// +// Created by Deamon on 7/3/2023. +// + +#ifndef AWEBWOWVIEWERCPP_SHADERCONFIG_H +#define AWEBWOWVIEWERCPP_SHADERCONFIG_H + +#include +#include "../context/vulkan_context.h" + +struct ShaderConfig { + std::unordered_map typeOverrides; +}; + +#endif //AWEBWOWVIEWERCPP_SHADERCONFIG_H diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 7d5713312..45dab74fb 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -110,6 +110,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : @@ -75,7 +76,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C createFrameBuffers(); - sceneWideChunk = std::make_shared>(uboBuffer); + sceneWideChunk = std::make_shared>(hDevice, uboBuffer); } // ------------------ @@ -203,6 +204,7 @@ HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } +static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; std::shared_ptr MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { @@ -210,11 +212,11 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp auto vertexFragmentData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, vertexFragmentData->getSubBuffer()) .ubo(2, fragmentData->getSubBuffer()); }) @@ -246,11 +248,11 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, forwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) @@ -286,11 +288,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal auto vertexData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, forwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) @@ -320,11 +322,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM auto &l_sceneWideChunk = sceneWideChunk; auto l_fragmentData = std::make_shared>(uboBuffer); ; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(4, l_fragmentData->getSubBuffer()); }) .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { @@ -351,11 +353,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) .ubo(2, l_vertexData->getSubBuffer()) .ubo(4, l_fragmentData->getSubBuffer()); @@ -386,11 +388,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) .ubo(4, l_fragmentData->getSubBuffer()); }) @@ -415,11 +417,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria auto &l_sceneWideChunk = sceneWideChunk; auto skyColors = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, skyColors->getSubBuffer()); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { @@ -433,11 +435,11 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( auto &l_sceneWideChunk = sceneWideChunk; auto materialPS = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, BufferChunkHelperVLK::cast(l_sceneWideChunk)->getSubBuffer()) + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, materialPS->getSubBuffer()); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { @@ -541,13 +543,13 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - TracyMessageL("collect meshes created"); - std::future collectMeshAsync = std::async(std::launch::async, - [&]() { +// TracyMessageL("collect meshes created"); +// std::future collectMeshAsync = std::async(std::launch::async, +// [&]() { collectMeshes(framePlan, opaqueMeshes, transparentMeshes, skyOpaqueMeshes, skyTransparentMeshes); - } - ); +// } +// ); mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); @@ -557,10 +559,10 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); - { - ZoneScopedN("collect meshes wait"); - collectMeshAsync.wait(); - } +// { +// ZoneScopedN("collect meshes wait"); +// collectMeshAsync.wait(); +// } bool renderSky = framePlan->renderSky; auto skyMesh = framePlan->skyMesh; @@ -575,6 +577,11 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // Upload stuff // --------------------- { + { + std::string debugMess = "sceneWideChunk = " + std::to_string( + DynamicBufferChunkHelperVLK::cast(l_this->sceneWideChunk)->getOffset()); + auto debugLabel = uploadCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + } ZoneScopedN("submit buffers"); uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -639,15 +646,15 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { ZoneScopedN("submit transparent"); for (auto const &mesh: *transparentMeshes) { - +// // std::string debugMess = // "Drawing mesh " // " meshType = " + std::to_string((int)mesh->getMeshType()) + // " priorityPlane = " + std::to_string(mesh->priorityPlane()) + // " sortDistance = " + std::to_string(mesh->getSortDistance()) + // " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); -// -// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 4cd837a8a..ffbab4de2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -3,9 +3,10 @@ // #include "FFXGlowPassVLK.h" -#include "../../../../gapi/vulkan/buffers/IBufferChunkVLK.h" +#include "../../../../gapi/vulkan/buffers/CBufferChunkVLK.h" #include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" #include "../../../../gapi/vulkan/GVertexBufferBindingsVLK.h" +#include "Tracy.hpp" FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device), m_drawQuadVao(quadVAO) { m_ffxGlowVs = std::make_shared>(uboBuffer); @@ -124,6 +125,8 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapCha } void FFXGlowPassVLK::assignFFXGlowUBOConsts(float glow) { + ZoneScoped; + auto &ffxGlowVs = m_ffxGlowVs->getObject(); ffxGlowVs = {1,1,0,0}; m_ffxGlowVs->save(); @@ -195,7 +198,7 @@ FFXGlowPassVLK::createFFXGaussMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() @@ -220,7 +223,7 @@ FFXGlowPassVLK::createFFXGlowMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() From 372725cf2255805bf0ddd6c4bd553cae2febc7d1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 5 Jul 2023 16:19:01 +0300 Subject: [PATCH 087/212] App can be compiled without Tracy, DescriptorsSets updated from single place --- src/main.cpp | 4 + src/ui/FrontendUI.cpp | 363 +++--- .../OffsetAllocator/offsetAllocator.cpp | 30 +- .../OffsetAllocator/offsetAllocator.hpp | 2 +- wowViewerLib/CMakeLists.txt | 7 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 3 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1016 ++++++++--------- .../src/engine/texture/BlpTexture.cpp | 6 +- wowViewerLib/src/engine/texture/BlpTexture.h | 6 +- .../src/gapi/vulkan/GDescriptorSetUpdater.cpp | 26 + .../src/gapi/vulkan/GDescriptorSetUpdater.h | 26 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 365 +----- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 8 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 5 + .../src/gapi/vulkan/TextureManagerVLK.cpp | 2 +- .../src/gapi/vulkan/buffers/CBufferChunkVLK.h | 2 +- .../vulkan/buffers/GBufferChunkDynamicVLK.h | 2 +- .../TextureUploadHelper.cpp | 6 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 15 +- .../vulkan/descriptorSets/GDescriptorSet.h | 17 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 27 +- .../src/renderer/frame/FrameProfile.h | 20 + .../src/renderer/frame/SceneComposer.cpp | 8 +- .../renderer/mapScene/MapSceneRenderer.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 3 +- 30 files changed, 890 insertions(+), 1093 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.h create mode 100644 wowViewerLib/src/renderer/frame/FrameProfile.h diff --git a/src/main.cpp b/src/main.cpp index 084ebf834..5ba8de361 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,7 +41,9 @@ #include "screenshots/screenshotMaker.h" #include "database/CEmptySqliteDB.h" #include +#ifdef LINK_TRACY #include "Tracy.hpp" +#endif int mleft_pressed = 0; int mright_pressed = 0; @@ -512,7 +514,9 @@ int main(){ glfwSwapBuffers(window); } +#ifdef LINK_TRACY FrameMark; +#endif } //} catch(const std::exception &e){ // std::cerr << e.what() << std::endl; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 4d7661d89..5a64d5460 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -335,178 +335,6 @@ void FrontendUI::fillMapListStrings() { mapListStringMap.push_back(mapStrRec); } } -void FrontendUI::showMapSelectionDialog() { - if (showSelectMap) { - enum MyMapTableColumnID - { - MyItemColumnID_ID, - MyItemColumnID_Name, - MyItemColumnID_Directory, - MyItemColumnID_WDTId, - MyItemColumnID_MapType - }; - - if (mapList.size() == 0) { - getMapList(mapList); - refilterIsNeeded = true; - } - if (refilterIsNeeded) { - filterMapList(std::string(&filterText[0])); - fillMapListStrings(); - - refilterIsNeeded = false; - resortIsNeeded = true; - } - - ImGui::Begin("Map Select Dialog", &showSelectMap); - { - ImGui::Columns(2, NULL, true); - //Left panel - { - //Filter - if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), - ImGuiInputTextFlags_AlwaysOverwrite)) { - refilterIsNeeded = true; - } - //The table - - ImGui::BeginChild("Map Select Dialog Left panel"); - if (ImGui::BeginTable("MapListSelector", 5, ImGuiTableFlags_Resizable | - ImGuiTableFlags_Reorderable | - ImGuiTableFlags_Sortable | - ImGuiTableFlags_NoHostExtendX | - ImGuiTableFlags_NoHostExtendY | - ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, - ImVec2(-1, -1) - )){ - ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_ID ); - ImGui::TableSetupColumn("MapName", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Name ); - ImGui::TableSetupColumn("MapDirectory", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Directory ); - ImGui::TableSetupColumn("WdtFileID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_WDTId ); - ImGui::TableSetupColumn("MapType", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_MapType ); - ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableHeadersRow(); - - ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); - if (sorts_specs && sorts_specs->SpecsDirty) - resortIsNeeded = true; - - if (sorts_specs && resortIsNeeded) { - std::sort(filteredMapList.begin(), filteredMapList.end(), - [sorts_specs](const auto &a, const auto &b) -> bool { - - for (int n = 0; n < sorts_specs->SpecsCount; n++) - { - const ImGuiTableColumnSortSpecs* sort_spec = &sorts_specs->Specs[n]; - int delta = 0; - - switch (sort_spec->ColumnUserID) - { - - case MyItemColumnID_ID: delta = a.ID - b.ID; break; - case MyItemColumnID_Name: delta = a.MapName.compare(b.MapName); break; - case MyItemColumnID_Directory: delta = a.MapDirectory.compare(b.MapDirectory); break; - case MyItemColumnID_WDTId: delta = a.WdtFileID - b.WdtFileID; break; - case MyItemColumnID_MapType: delta = a.MapType - b.MapType; break; - - default: IM_ASSERT(0); break; - } - if (delta > 0) - return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? true : false; - if (delta < 0) - return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? false : true; - } - - return (a.ID - b.ID) > 0; - }); - - sorts_specs->SpecsDirty = false; - resortIsNeeded = false; - fillMapListStrings(); - } - - static int selected = -1; - for (int i = 0; i < filteredMapList.size(); i++) { - ImGui::TableNextRow(); - auto mapRec = filteredMapList[i]; - - ImGui::TableSetColumnIndex(0); - - if (ImGui::Selectable(mapListStringMap[i][0].c_str(), selected == i, - ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - if (mapRec.ID != prevMapId) { - mapCanBeOpened = true; - adtMinimapFilled = false; - prevMapRec = mapRec; - - isWmoMap = false; - adtSelectionMinimapTextures = {}; - adtSelectionMinimapMaterials = {}; - if (mapRec.WdtFileID > 0) { - getAdtSelectionMinimap(mapRec.WdtFileID); - } else { - getAdtSelectionMinimap( - "world/maps/" + mapRec.MapDirectory + "/" + mapRec.MapDirectory + ".wdt"); - } - - } - prevMapId = mapRec.ID; - selected = i; - } - bool hovered = ImGui::IsItemHovered(); - - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", mapListStringMap[i][1].c_str()); - ImGui::TableSetColumnIndex(2); - ImGui::Text("%s", mapListStringMap[i][2].c_str()); - ImGui::TableSetColumnIndex(3); - ImGui::Text("%s", mapListStringMap[i][3].c_str()); - ImGui::TableSetColumnIndex(4); - ImGui::Text("%s", mapListStringMap[i][4].c_str()); - } - ImGui::EndTable(); - } - ImGui::Separator(); - ImGui::EndChild(); - } - ImGui::NextColumn(); - - { - ImGui::BeginChild("Map Select Dialog Right panel", ImVec2(0, 0)); - { - if (!mapCanBeOpened) { - ImGui::Text("Cannot open this map."); - ImGui::Text("WDT file either does not exist in CASC repository or is encrypted"); - } else if (!isWmoMap) { - ImGui::SliderFloat("Zoom", &minimapZoom, 0.1, 10); -// ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - showAdtSelectionMinimap(); - } else { - worldPosX = 0; - worldPosY = 0; - if (ImGui::Button("Open WMO Map", ImVec2(-1, 0))) { - if (prevMapRec.WdtFileID > 0) { - openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0); - } else { - //Try to open map by fileName - openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, 17066.6641f, 17066.67380f, 0); - } - showSelectMap = false; - } - } - - } - ImGui::EndChild(); - - - } - ImGui::Columns(1); - - ImGui::End(); - } - } -} - void FrontendUI::showAdtSelectionMinimap() { ImGui::BeginChild("Adt selection minimap", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_AlwaysVerticalScrollbar); @@ -629,6 +457,197 @@ void FrontendUI::showAdtSelectionMinimap() { ImGui::EndChild(); } + +void FrontendUI::showMapSelectionDialog() { + if (!showSelectMap) { + for (int i = 0; i < 64; i++) + for (int j = 0; j < 64; j++) + adtSelectionMinimapMaterials[i][j] = nullptr; + return; + } + + enum MyMapTableColumnID { + MyItemColumnID_ID, + MyItemColumnID_Name, + MyItemColumnID_Directory, + MyItemColumnID_WDTId, + MyItemColumnID_MapType + }; + + if (mapList.size() == 0) { + getMapList(mapList); + refilterIsNeeded = true; + } + if (refilterIsNeeded) { + filterMapList(std::string(&filterText[0])); + fillMapListStrings(); + + refilterIsNeeded = false; + resortIsNeeded = true; + } + + ImGui::Begin("Map Select Dialog", &showSelectMap); + { + ImGui::Columns(2, NULL, true); + //Left panel + { + //Filter + if (ImGui::InputText("Filter: ", filterText.data(), filterText.size(), + ImGuiInputTextFlags_AlwaysOverwrite)) { + refilterIsNeeded = true; + } + //The table + + ImGui::BeginChild("Map Select Dialog Left panel"); + if (ImGui::BeginTable("MapListSelector", 5, ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Sortable | + ImGuiTableFlags_NoHostExtendX | + ImGuiTableFlags_NoHostExtendY | + ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, + ImVec2(-1, -1) + )) { + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("MapName", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("MapDirectory", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_Directory); + ImGui::TableSetupColumn("WdtFileID", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_WDTId); + ImGui::TableSetupColumn("MapType", ImGuiTableColumnFlags_None, 0.0f, MyItemColumnID_MapType); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + + ImGuiTableSortSpecs *sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty) + resortIsNeeded = true; + + if (sorts_specs && resortIsNeeded) { + std::sort(filteredMapList.begin(), filteredMapList.end(), + [sorts_specs](const auto &a, const auto &b) -> bool { + + for (int n = 0; n < sorts_specs->SpecsCount; n++) { + const ImGuiTableColumnSortSpecs *sort_spec = &sorts_specs->Specs[n]; + int delta = 0; + + switch (sort_spec->ColumnUserID) { + + case MyItemColumnID_ID: + delta = a.ID - b.ID; + break; + case MyItemColumnID_Name: + delta = a.MapName.compare(b.MapName); + break; + case MyItemColumnID_Directory: + delta = a.MapDirectory.compare(b.MapDirectory); + break; + case MyItemColumnID_WDTId: + delta = a.WdtFileID - b.WdtFileID; + break; + case MyItemColumnID_MapType: + delta = a.MapType - b.MapType; + break; + + default: + IM_ASSERT(0); + break; + } + if (delta > 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? true + : false; + if (delta < 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? false + : true; + } + + return (a.ID - b.ID) > 0; + }); + + sorts_specs->SpecsDirty = false; + resortIsNeeded = false; + fillMapListStrings(); + } + + static int selected = -1; + for (int i = 0; i < filteredMapList.size(); i++) { + ImGui::TableNextRow(); + auto mapRec = filteredMapList[i]; + + ImGui::TableSetColumnIndex(0); + + if (ImGui::Selectable(mapListStringMap[i][0].c_str(), selected == i, + ImGuiSelectableFlags_SpanAllColumns | + ImGuiSelectableFlags_AllowItemOverlap)) { + if (mapRec.ID != prevMapId) { + mapCanBeOpened = true; + adtMinimapFilled = false; + prevMapRec = mapRec; + + isWmoMap = false; + adtSelectionMinimapTextures = {}; + adtSelectionMinimapMaterials = {}; + if (mapRec.WdtFileID > 0) { + getAdtSelectionMinimap(mapRec.WdtFileID); + } else { + getAdtSelectionMinimap( + "world/maps/" + mapRec.MapDirectory + "/" + mapRec.MapDirectory + ".wdt"); + } + + } + prevMapId = mapRec.ID; + selected = i; + } + bool hovered = ImGui::IsItemHovered(); + + ImGui::TableSetColumnIndex(1); + ImGui::Text("%s", mapListStringMap[i][1].c_str()); + ImGui::TableSetColumnIndex(2); + ImGui::Text("%s", mapListStringMap[i][2].c_str()); + ImGui::TableSetColumnIndex(3); + ImGui::Text("%s", mapListStringMap[i][3].c_str()); + ImGui::TableSetColumnIndex(4); + ImGui::Text("%s", mapListStringMap[i][4].c_str()); + } + ImGui::EndTable(); + } + ImGui::Separator(); + ImGui::EndChild(); + } + ImGui::NextColumn(); + + { + ImGui::BeginChild("Map Select Dialog Right panel", ImVec2(0, 0)); + { + if (!mapCanBeOpened) { + ImGui::Text("Cannot open this map."); + ImGui::Text("WDT file either does not exist in CASC repository or is encrypted"); + } else if (!isWmoMap) { + ImGui::SliderFloat("Zoom", &minimapZoom, 0.1, 10); +// ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); + showAdtSelectionMinimap(); + } else { + worldPosX = 0; + worldPosY = 0; + if (ImGui::Button("Open WMO Map", ImVec2(-1, 0))) { + if (prevMapRec.WdtFileID > 0) { + openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0); + } else { + //Try to open map by fileName + openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, 17066.6641f, 17066.67380f, + 0); + } + showSelectMap = false; + } + } + + } + ImGui::EndChild(); + + + } + ImGui::Columns(1); + + ImGui::End(); + } +} + void FrontendUI::showMainMenu() { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp index fab5f940b..81115aa11 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -197,12 +197,6 @@ namespace OffsetAllocator Allocation Allocator::allocate(uint32 size) { - // Out of allocations? - if (m_freeNodes.empty()) - { - return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE}; - } - // Round up to bin index to ensure that alloc >= bin // Gives us min bin index that fits the size uint32 minBinIndex = SmallFloat::uintToFloatRoundUp(size); @@ -269,10 +263,13 @@ namespace OffsetAllocator if (reminderSize > 0) { uint32 newNodeIndex = insertNodeIntoBin(reminderSize, node.dataOffset + size); - + //After insert node ptr may change due to m_nodes resize + Node& node = m_nodes[nodeIndex]; + // Link nodes next to each other so that we can merge them later if both are free // And update the old next neighbor to point to the new node (in middle) - if (node.neighborNext != Node::unused) m_nodes[node.neighborNext].neighborPrev = newNodeIndex; + if (node.neighborNext != Node::unused) + m_nodes[node.neighborNext].neighborPrev = newNodeIndex; m_nodes[newNodeIndex].neighborPrev = nodeIndex; m_nodes[newNodeIndex].neighborNext = node.neighborNext; node.neighborNext = newNodeIndex; @@ -281,8 +278,11 @@ namespace OffsetAllocator m_lastNode = newNodeIndex; } } - - return {.offset = node.dataOffset, .metadata = nodeIndex}; + + { + Node &node = m_nodes[nodeIndex]; + return {.offset = node.dataOffset, .metadata = nodeIndex}; + } } void Allocator::free(Allocation allocation) @@ -380,8 +380,14 @@ namespace OffsetAllocator // Take a freelist node and insert on top of the bin linked list (next = old top) uint32 topNodeIndex = m_binIndices[binIndex]; - uint32 nodeIndex = m_freeNodes.top(); - m_freeNodes.pop(); + uint32 nodeIndex = 0; + if (!m_freeNodes.empty()) { + nodeIndex = m_freeNodes.top(); + m_freeNodes.pop(); + } else { + nodeIndex = m_nodes.size(); + m_nodes.emplace_back(); + } #ifdef DEBUG_VERBOSE printf("Getting node %u from freelist[%u]\n", nodeIndex, m_freeOffset + 1); #endif diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp index be44e167a..eea8f63d1 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -55,7 +55,7 @@ namespace OffsetAllocator class Allocator { public: - Allocator(uint32 size, uint32 maxAllocs = 128 * 1024*20); + Allocator(uint32 size, uint32 maxAllocs = 1024); Allocator(Allocator &&other); // user-defined copy assignment (copy-and-swap idiom) diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index e91d096a0..7cc9ec2f8 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 1) +set(LINK_TRACY 0) option(EMSCRIPTEN_SIMD "Enable SIMD for Emscripten " OFF) @@ -357,7 +357,7 @@ set(SOURCE_FILES src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h - src/engine/objects/liquid/LiquidDataGetters.h) + src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -555,7 +555,7 @@ if (LINK_VULKAN) src/gapi/vulkan/context/vulkan_context.h src/gapi/vulkan/shaders/ShaderConfig.h src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp - src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h) + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) @@ -657,6 +657,7 @@ if (LINK_VULKAN) endif() if (LINK_TRACY) + target_compile_definitions(WoWViewerLib PUBLIC -DLINK_TRACY) target_include_directories(WoWViewerLib PUBLIC ${TRACY_INCLUDE_DIR}) target_link_libraries (WoWViewerLib Tracy::TracyClient ) endif() diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index f2cf31c2e..eeb97e68b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -927,7 +927,9 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ //deltaTime = miliseconds void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat) { - if (!this->m_loaded) return; + if (!this->m_loaded) return; + + m_postLoadEvents.clear(); static const mathfu::mat4 particleCoordinatesFix = mathfu::mat4( diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 6aa0f421a..d29dd7220 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -22,7 +22,8 @@ #endif #include "../../algorithms/mathHelper_culling.h" #include "../../../gapi/interface/materials/IMaterial.h" -#include "Tracy.hpp" +#include "../../../renderer/frame/FrameProfile.h" + std::array skyConusVBO = { { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 6e95faa5c..4126ddfe2 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -245,7 +245,7 @@ void WmoGroupObject::loadDoodads() { auto newDoodad = m_wmoApi->getDoodad(this->m_geom->doodadRefs[i]); m_doodads.push_back(newDoodad); if (newDoodad != nullptr) { - std::function event = [&, newDoodad]() -> void { + std::function event = [&]() -> void { this->m_recalcBoundries = true; }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 70c999d0b..f8ad2862c 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -7,7 +7,7 @@ #include "../../algorithms/grahamScan.h" #include "../../persistance/header/commonFileStructs.h" #include "./../../../gapi/interface/IDevice.h" -#include "Tracy.hpp" +#include "../../../renderer/frame/FrameProfile.h" #include std::vector createOccluders(const HWmoGroupGeom& groupGeom) diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 4aac3c3cf..d2f5ac48a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +430,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,19 +499,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,256}, + {0,1,64}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,13 +633,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,17 +657,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,256}, - {0,1,64}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +814,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -877,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,96}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,21 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,13 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {1,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,21 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {0,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,11 +1524,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,16 +1543,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,10 +1585,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1612,21 +1623,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1984,13 +1954,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2006,23 +1990,29 @@ const std::unordered_mapm_textureFormat != TextureFormat::Undetected); - m_mipmaps = parseMipmaps(pBlpFile, m_textureFormat); + m_blpFile = blpFile; // /* Load texture into GL memory */ // this->texture = createGlTexture(pBlpFile, textureFormat, mipmaps, fileName); @@ -169,3 +169,7 @@ void BlpTexture::process(HFileContent blpFile, const std::string &fileName) { this->m_textureName = fileName; } +const HMipmapsVector BlpTexture::getMipmapsVector() { + return parseMipmaps( (BlpFile *)m_blpFile->data(), m_textureFormat); +} + diff --git a/wowViewerLib/src/engine/texture/BlpTexture.h b/wowViewerLib/src/engine/texture/BlpTexture.h index 5a1a0beef..44278b1be 100644 --- a/wowViewerLib/src/engine/texture/BlpTexture.h +++ b/wowViewerLib/src/engine/texture/BlpTexture.h @@ -38,9 +38,7 @@ class BlpTexture : public PersistentFile{ std::string getTextureName() { return m_textureName; }; void process(HFileContent blpFile, const std::string &fileName) override; - const HMipmapsVector& getMipmapsVector() { - return m_mipmaps; - } + const HMipmapsVector getMipmapsVector(); TextureFormat getTextureFormat() { return m_textureFormat; @@ -49,7 +47,7 @@ class BlpTexture : public PersistentFile{ std::string m_textureName; int m_fileDataId = 0; - HMipmapsVector m_mipmaps; + HFileContent m_blpFile = nullptr; TextureFormat m_textureFormat = TextureFormat::Undetected; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.cpp b/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.cpp new file mode 100644 index 000000000..0fac91e69 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.cpp @@ -0,0 +1,26 @@ +// +// Created by Deamon on 7/5/2023. +// + +#include "GDescriptorSetUpdater.h" + +GDescriptorSetUpdater::GDescriptorSetUpdater() { +} + +void GDescriptorSetUpdater::addToUpdate(const std::shared_ptr& descSet) { + std::lock_guard lock(descriptorUpdateMutex); + m_descriptorSetToBeUpdated.push_back(descSet); +} + +void GDescriptorSetUpdater::updateDescriptorSets() { + std::lock_guard lock(descriptorUpdateMutex); + + std::sort(m_descriptorSetToBeUpdated.begin(), m_descriptorSetToBeUpdated.end()); + m_descriptorSetToBeUpdated.erase(std::unique(m_descriptorSetToBeUpdated.begin(), m_descriptorSetToBeUpdated.end()), m_descriptorSetToBeUpdated.end()); + + for (const auto& descriptor : m_descriptorSetToBeUpdated) { + descriptor->update(); + } + + m_descriptorSetToBeUpdated.clear(); +} diff --git a/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.h b/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.h new file mode 100644 index 000000000..0ae514014 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/GDescriptorSetUpdater.h @@ -0,0 +1,26 @@ +// +// Created by Deamon on 7/5/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GDESCRIPTORSETUPDATER_H +#define AWEBWOWVIEWERCPP_GDESCRIPTORSETUPDATER_H + +#include +#include +#include "descriptorSets/GDescriptorSet.h" + +class GDescriptorSetUpdater : public std::enable_shared_from_this { +public: + GDescriptorSetUpdater(); + + void addToUpdate(const std::shared_ptr& descSet); + + void updateDescriptorSets(); +private: + std::mutex descriptorUpdateMutex; + + std::vector> m_descriptorSetToBeUpdated; +}; + + +#endif //AWEBWOWVIEWERCPP_GDESCRIPTORSETUPDATER_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index bb5448802..8175e55e5 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -25,7 +25,7 @@ #include "synchronization/GFenceVLK.h" #include "../../renderer/vulkan/IRenderFunctionVLK.h" #include "commandBuffer/commandBufferRecorder/TextureUploadHelper.h" -#include "Tracy.hpp" +#include "../../renderer/frame/FrameProfile.h" #include const int WIDTH = 1900; @@ -171,7 +171,8 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create } -GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)){ +GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), + m_descriptorSetUpdater(std::make_shared()){ enableValidationLayers = false; if (volkInitialize()) { @@ -838,6 +839,10 @@ void GDeviceVLK::drawFrame(const std::vector> & } } } + { + ZoneScopedN("DescriptorSet update"); + m_descriptorSetUpdater->updateDescriptorSets(); + } //Wait for swapchain { @@ -1249,15 +1254,16 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings bool depthCulling, bool depthWrite) { - PipelineCacheRecord pipelineCacheRecord; - pipelineCacheRecord.shader = shader; - pipelineCacheRecord.renderPass = renderPass; - pipelineCacheRecord.element = element; - pipelineCacheRecord.backFaceCulling = backFaceCulling; - pipelineCacheRecord.triCCW = triCCW; - pipelineCacheRecord.blendMode = blendMode; - pipelineCacheRecord.depthCulling = depthCulling; - pipelineCacheRecord.depthWrite = depthWrite; + PipelineCacheRecord pipelineCacheRecord = { + .shader = shader, + .renderPass = std::weak_ptr(renderPass), + .element = element, + .backFaceCulling = backFaceCulling, + .triCCW = triCCW, + .blendMode = blendMode, + .depthCulling = depthCulling, + .depthWrite = depthWrite + }; auto i = loadedPipeLines.find(pipelineCacheRecord); if (i != loadedPipeLines.end()) { @@ -1310,343 +1316,6 @@ GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescript return result; } -//void GDeviceVLK::internalDrawStageAndDeps(HDrawStage drawStage) { -// //Draw deps -// for (int i = 0; i < drawStage->drawStageDependencies.size(); i++) { -// this->internalDrawStageAndDeps(drawStage->drawStageDependencies[i]); -// } -// -// this->setInvertZ(drawStage->invertedZ); -// -// if (drawStage->clearScreen) { -// clearColor[0] = drawStage->clearColor[0]; -// clearColor[1] = drawStage->clearColor[1]; -// clearColor[2] = drawStage->clearColor[2]; -// } -// -// int updateFrame = getUpdateFrameNumber(); -// auto commandBufferForFilling = renderCommandBuffers[updateFrame]; -// //Default renderPass for rendering to screen framebuffers -// std::shared_ptr renderPass = swapchainRenderPass; -// -// if (drawStage->target != nullptr) { -// commandBufferForFilling = renderCommandBuffersForFrameBuffers[updateFrame]; -// -// GFrameBufferVLK *frameBufferVlk = dynamic_cast(drawStage->target.get()); -// -// renderPass = frameBufferVlk->m_renderPass; -// -// std::vector clearValues = renderPass->produceClearColorVec( -// { clearColor[0], clearColor[1], clearColor[2] }, -// drawStage->invertedZ ? 0.0f : 1.0f -// ); -// -// VkRenderPassBeginInfo renderPassInfo = {}; -// renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; -// renderPassInfo.pNext = NULL; -// renderPassInfo.renderPass = renderPass->getRenderPass(); -// renderPassInfo.framebuffer = frameBufferVlk->m_frameBuffer; -// renderPassInfo.renderArea.offset = {drawStage->viewPortDimensions.mins[0], drawStage->viewPortDimensions.mins[1]}; -// renderPassInfo.renderArea.extent = {static_cast(drawStage->viewPortDimensions.maxs[0]), static_cast(drawStage->viewPortDimensions.maxs[1])}; -// renderPassInfo.clearValueCount = clearValues.size(); -// renderPassInfo.pClearValues = clearValues.data(); -// -// vkCmdBeginRenderPass(commandBufferForFilling, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); -// } -// -// std::array viewportsForThisStage; -// -// VkViewport &usualViewport = viewportsForThisStage[(int)ViewportType::vp_usual]; -// usualViewport.width = drawStage->viewPortDimensions.maxs[0]; -// usualViewport.height = drawStage->viewPortDimensions.maxs[1]; -// usualViewport.x = drawStage->viewPortDimensions.mins[0]; -// usualViewport.y = drawStage->viewPortDimensions.mins[1]; -// if (!getInvertZ()) { -// usualViewport.minDepth = 0; -// usualViewport.maxDepth = 0.990f; -// } else { -// usualViewport.minDepth = 0.06f; -// usualViewport.maxDepth = 1.0f; -// } -// -// VkViewport &mapAreaViewport = viewportsForThisStage[(int)ViewportType::vp_mapArea]; -// mapAreaViewport = usualViewport; -// if (!getInvertZ()) { -// mapAreaViewport.minDepth = 0.991f; -// mapAreaViewport.maxDepth = 0.996f; -// } else { -// mapAreaViewport.minDepth = 0.04f; -// mapAreaViewport.maxDepth = 0.05f; -// } -// -// VkViewport &skyBoxViewport = viewportsForThisStage[(int)ViewportType::vp_skyBox]; -// skyBoxViewport = usualViewport; -// if (!getInvertZ()) { -// skyBoxViewport.minDepth = 0.997f; -// skyBoxViewport.maxDepth = 1.0f; -// } else { -// skyBoxViewport.minDepth = 0; -// skyBoxViewport.maxDepth = 0.03f; -// } -// -// -// //Set scissors -// VkRect2D defaultScissor = {}; -// defaultScissor.offset = {0, 0}; -// defaultScissor.extent = { -// static_cast(drawStage->viewPortDimensions.maxs[0]), -// static_cast(drawStage->viewPortDimensions.maxs[1]) -// }; -// -// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); -// -// //Set new viewport -// vkCmdSetViewport(commandBufferForFilling, 0, 1, &usualViewport); -// -// bool atLeastOneDrawCall = false; -// if (drawStage->opaqueMeshes != nullptr) -// atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, -// drawStage->opaqueMeshes, viewportsForThisStage, -// defaultScissor) || atLeastOneDrawCall; -// if (drawStage->transparentMeshes != nullptr) -// atLeastOneDrawCall = drawMeshesInternal(drawStage, commandBufferForFilling, renderPass, -// drawStage->transparentMeshes, viewportsForThisStage, -// defaultScissor) || atLeastOneDrawCall; -// -// if (drawStage->target != nullptr) { -// vkCmdEndRenderPass(commandBufferForFilling); -// renderCommandBuffersForFrameBuffersNotNull[updateFrame] = renderCommandBuffersForFrameBuffersNotNull[updateFrame] || atLeastOneDrawCall; -// } else { -// renderCommandBuffersNotNull[updateFrame] = renderCommandBuffersNotNull[updateFrame] || atLeastOneDrawCall; -// } -// -//} - -//Returns true if at least once command was written to buffer -//bool GDeviceVLK::drawMeshesInternal( -// const HDrawStage &drawStage, -// VkCommandBuffer commandBufferForFilling, -// std::shared_ptr renderPass, -// const HMeshesToRender &meshes, -// const std::array &viewportsForThisStage, -// VkRect2D &defaultScissor) { -// -// int updateFrame = getUpdateFrameNumber(); -// -// ViewportType lastViewPort = ViewportType::vp_none; -// -// VkBuffer lastIndexBuffer = VK_NULL_HANDLE; -// VkBuffer lastVertexBuffer = VK_NULL_HANDLE; -// int8_t lastIsScissorsEnabled = -1; -// std::shared_ptr lastPipeline = nullptr; -//// uint32_t dynamicOffset[7] = {}; -// -// auto &iMeshes = meshes->meshes; -// -// auto dynamicOffsetPerMesh = std::vector>(iMeshes.size()); -// auto uboIndPerMesh = std::vector(iMeshes.size()); -// -// tbb::parallel_for( -// tbb::blocked_range(0, iMeshes.size(), 500), -// [&](tbb::blocked_range r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); -// auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); -// uint32_t uboInd = 0; -// auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); -// if (uboB) { -// dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); -// } -// -// for (int k = 1; k < 6; k++) { -// if (shaderVLK->hasBondUBO[k]) { -// auto *uboB = (meshVLK->getUniformBuffer(k).get()); -// if (uboB) { -// dynamicOffsetPerMesh[i][uboInd++] = (uboB)->getOffset(); -// } -// } -// } -// uboIndPerMesh[i] = uboInd; -// } -// }, tbb::simple_partitioner()); -// -// bool atLeastOneDrawcall = false; -// VkDeviceSize offsets[] = {0}; -// -// for (int i = 0; i < iMeshes.size(); i++) { -// auto *meshVLK = ((GMeshVLK *)iMeshes[i].get()); -//// auto *meshVLK = ((GMeshVLK *)mesh.get()); -// auto *binding = ((GVertexBufferBindingsVLK *)meshVLK->m_bindings.get()); -// auto *shaderVLK = ((GShaderPermutationVLK*)meshVLK->m_shader.get()); -// -//// uint32_t uboInd = 0; -//// auto *uboB = drawStage->sceneWideBlockVSPSChunk.get(); -//// if (uboB) { -//// dynamicOffset[uboInd++] = (uboB)->getOffset(); -//// } -//// -//// for (int k = 1; k < 6; k++) { -//// if (shaderVLK->hasBondUBO[k]) { -//// auto *uboB = (meshVLK->getUniformBuffer(k).get()); -//// if (uboB) { -//// dynamicOffset[uboInd++] = (uboB)->getOffset(); -//// } -//// } -//// } -// -// std::shared_ptr h_pipeLine = meshVLK->getPipeLineForRenderPass(renderPass, drawStage->invertedZ); -// -// if (lastPipeline != h_pipeLine) { -// vkCmdBindPipeline(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, -// h_pipeLine->graphicsPipeline); -// -// lastPipeline = h_pipeLine; -// } -// -// ViewportType newViewPort = meshVLK->m_isSkyBox ? ViewportType::vp_skyBox : ViewportType::vp_usual; -// if (lastViewPort != newViewPort) { -// if (viewportsForThisStage[+newViewPort].height > 32768) { -// std::cout << "newViewPort = " << +newViewPort << std::endl; -// } -// vkCmdSetViewport(commandBufferForFilling, 0, 1, &viewportsForThisStage[+newViewPort]); -// -// lastViewPort = newViewPort; -// } -// -// -// if (meshVLK->m_isScissorsEnabled > 0) { -// VkRect2D rect; -// rect.offset.x = meshVLK->m_scissorOffset[0]; -// rect.offset.y = meshVLK->m_scissorOffset[1]; -// rect.extent.width = meshVLK->m_scissorSize[0]; -// rect.extent.height = meshVLK->m_scissorSize[1]; -// -// vkCmdSetScissor(commandBufferForFilling, 0, 1, &rect); -// } else if (lastIsScissorsEnabled != meshVLK->m_isScissorsEnabled) { -// vkCmdSetScissor(commandBufferForFilling, 0, 1, &defaultScissor); -// } -// lastIsScissorsEnabled = meshVLK->m_isScissorsEnabled; -// -// -// auto indexBuffer = ((GIndexBufferVLK *)binding->m_indexBuffer.get())->g_hIndexBuffer; -// auto vertexBuffer = ((GVertexBufferVLK *)binding->m_bindings[0].vertexBuffer.get())->g_hVertexBuffer; -// -// -// if (lastIndexBuffer != indexBuffer) { -// vkCmdBindIndexBuffer(commandBufferForFilling, indexBuffer, 0, VK_INDEX_TYPE_UINT16); -// lastIndexBuffer = indexBuffer; -// } -// -// if (lastVertexBuffer != vertexBuffer) { -// uint32_t vboBind = 0; -// -// vkCmdBindVertexBuffers(commandBufferForFilling, vboBind++, 1, &vertexBuffer, offsets); -// lastVertexBuffer = vertexBuffer; -// } -// -// auto uboDescSet = shaderVLK->uboDescriptorSets[updateFrame]->getDescSet(); -// auto imageDescSet = meshVLK->imageDescriptorSets[updateFrame]->getDescSet(); -// -// atLeastOneDrawcall = true; -// -// //UBO -// vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, -// h_pipeLine->pipelineLayout, 0, 1, &uboDescSet, uboIndPerMesh[i], dynamicOffsetPerMesh[i].data()); -// -// //Image -// vkCmdBindDescriptorSets(commandBufferForFilling, VK_PIPELINE_BIND_POINT_GRAPHICS, -// h_pipeLine->pipelineLayout, 1, 1, &imageDescSet, 0, nullptr); -// -// vkCmdDrawIndexed(commandBufferForFilling, meshVLK->m_end, 1, meshVLK->m_start/2, 0, 0); -// } -// -// return atLeastOneDrawcall; -//} -// -//void GDeviceVLK::drawStageAndDeps(HDrawStage drawStage) { -// int updateFrame = getUpdateFrameNumber(); -// -//// std::cout << "drawStageAndDeps: updateFrame = " << updateFrame << std::endl; -// -// if (drawStage->target == nullptr && -// ( -// (drawStage->viewPortDimensions.maxs[0] != swapChainExtent.width) || -// (drawStage->viewPortDimensions.maxs[1] != swapChainExtent.height) -// ) -// ) { -// recreateSwapChain(); -// } -// -// vkWaitForFences(device, 1, &inFlightFences[updateFrame], VK_TRUE, std::numeric_limits::max()); -// -// //Update -// if (m_shaderDescriptorUpdateNeeded) { -// for (auto shaderVLKRec : m_shaderPermutCache) { -// ((GShaderPermutationVLK *) shaderVLKRec.second.get())->updateDescriptorSet(updateFrame); -// } -// m_shaderDescriptorUpdateNeeded = false; -// } -// -// auto commandBufferForFilling = renderCommandBuffers[updateFrame]; -// auto commandBufferForFillingFrameBuf = renderCommandBuffersForFrameBuffers[updateFrame]; -// -// renderCommandBuffersNotNull[updateFrame] = false; -// renderCommandBuffersForFrameBuffersNotNull[updateFrame] = false; -// -// { -// VkCommandBufferInheritanceInfo bufferInheritanceInfo; -// bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; -// bufferInheritanceInfo.pNext = nullptr; -// bufferInheritanceInfo.renderPass = swapchainRenderPass->getRenderPass(); -// bufferInheritanceInfo.subpass = 0; -// bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; -// bufferInheritanceInfo.occlusionQueryEnable = false; -// bufferInheritanceInfo.queryFlags = 0; -// bufferInheritanceInfo.pipelineStatistics = 0; -// -// VkCommandBufferBeginInfo beginInfo = {}; -// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; -// beginInfo.pNext = NULL; -// beginInfo.pInheritanceInfo = &bufferInheritanceInfo; -// -// if (vkBeginCommandBuffer(commandBufferForFilling, &beginInfo) != VK_SUCCESS) { -// throw std::runtime_error("failed to begin recording command buffer!"); -// } -// } -// -// { -// VkCommandBufferInheritanceInfo bufferInheritanceInfo; -// bufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; -// bufferInheritanceInfo.pNext = nullptr; -// bufferInheritanceInfo.renderPass = VK_NULL_HANDLE; -// bufferInheritanceInfo.subpass = 0; -// bufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; -// bufferInheritanceInfo.occlusionQueryEnable = false; -// bufferInheritanceInfo.queryFlags = 0; -// bufferInheritanceInfo.pipelineStatistics = 0; -// -// VkCommandBufferBeginInfo beginInfo = {}; -// beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -// beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; -// beginInfo.pNext = NULL; -// beginInfo.pInheritanceInfo = &bufferInheritanceInfo; -// -// if (vkBeginCommandBuffer(commandBufferForFillingFrameBuf, &beginInfo) != VK_SUCCESS) { -// throw std::runtime_error("failed to begin recording command buffer!"); -// } -// } -// -// internalDrawStageAndDeps(drawStage); -// -// if (vkEndCommandBuffer(commandBufferForFilling) != VK_SUCCESS) { -// throw std::runtime_error("failed to record command buffer!"); -// } -// if (vkEndCommandBuffer(commandBufferForFillingFrameBuf) != VK_SUCCESS) { -// throw std::runtime_error("failed to record command buffer!"); -// } -//} - void GDeviceVLK::initUploadThread() { } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index bbd90ee31..2dcc97f39 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -43,6 +43,7 @@ class gMeshTemplate; #include "commandBuffer/commandBufferRecorder/RenderPassHelper.h" #include "TextureManagerVLK.h" #include "shaders/ShaderConfig.h" +#include "GDescriptorSetUpdater.h" #include @@ -113,6 +114,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getDescriptorSetUpdater() override { return m_descriptorSetUpdater;}; + HGMesh createMesh(gMeshTemplate &meshTemplate) override; HGPUFence createFence() override; @@ -222,7 +225,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this renderPass; + wtf::KeyContainer> renderPass; DrawElementMode element; bool backFaceCulling; bool triCCW; @@ -247,7 +250,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.shader.get()) ^ - hash{}(k.renderPass.get()) ^ + hash{}(k.renderPass) ^ (hash{}(k.backFaceCulling) << 2) ^ (hash{}(k.triCCW) << 4) ^ (hash{}(k.depthCulling) << 8) ^ @@ -328,6 +331,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_textureManager; + std::shared_ptr m_descriptorSetUpdater; protected: //Caches diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index 1de03c0c0..58e0e4f79 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -12,6 +12,9 @@ #include "../interface/textures/ITexture.h" #include "../interface/textures/ISamplableTexture.h" + +class GDescriptorSetUpdater; + struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; @@ -37,6 +40,8 @@ class IDeviceVulkan { virtual HGSamplableTexture getWhiteTexturePixel() = 0; virtual HGSamplableTexture getBlackTexturePixel() = 0; + virtual std::shared_ptr getDescriptorSetUpdater() = 0; + //TODO: virtual bool getIsAnisFiltrationSupported() {return true;}; //TODO: diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index 74278aa3e..efce34e45 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -44,7 +44,7 @@ HGSamplableTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture, boo std::weak_ptr weakPtr(hgSamplableTexture); - sampledTextureCache[sampledTextureCacheRecord] = hgSamplableTexture; + sampledTextureCache[sampledTextureCacheRecord] = weakPtr; return hgSamplableTexture; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index e9558c1dd..3e402d2fc 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -20,8 +20,8 @@ class CBufferChunkVLK : public IBufferChunk { subBuffer = mainBuffer->getSubBuffer(m_realSize,sizeof(T)); pSubBuffer = subBuffer.get(); - } + ~CBufferChunkVLK() final = default; T &getObject() override { return *(T*)pSubBuffer->getPointer(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 1857ac13b..17a042bfd 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -29,7 +29,7 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { }); } - ~GBufferChunkDynamicVLK() { + ~GBufferChunkDynamicVLK() final { pSubBuffers[0]->eraseOnHandleChange(iteratorUnique); } void uploadData(const void *, int length) override { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index 7757457df..a8e419320 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -3,7 +3,7 @@ // #include "TextureUploadHelper.h" -#include "Tracy.hpp" +#include "../../../../renderer/frame/FrameProfile.h" void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, const std::vector> &textures, @@ -80,10 +80,10 @@ void textureUploadStrategy(const std::vector> &textur // ------------------------------------ for ( auto &wtextureVlk : textures) { - if (wtextureVlk.expired()) continue; auto textureVlk = wtextureVlk.lock(); + if (!textureVlk) continue; - auto updateRecord = textureVlk->getAndPlanDestroy(); + const auto &updateRecord = textureVlk->getAndPlanDestroy(); uploadCmdBufRecorder.copyBufferToImage( updateRecord->stagingBuffer, diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 821318f0e..414215f37 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -6,6 +6,7 @@ #include "../textures/GTextureVLK.h" #include "../textures/GTextureSamplerVLK.h" +#include "../GDescriptorSetUpdater.h" GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, const std::shared_ptr &hDescriptorSetLayout) : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { @@ -28,7 +29,7 @@ GDescriptorSet::SetUpdateHelper GDescriptorSet::beginUpdate() { m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); assert(m_descriptorSet != nullptr); } - return SetUpdateHelper(*this, boundDescriptors); + return SetUpdateHelper(*this, boundDescriptors, m_device->getDescriptorSetUpdater()); } void GDescriptorSet::update() { @@ -280,3 +281,15 @@ void GDescriptorSet::SetUpdateHelper::cancelUpdate() { updateCancelled = true; } +std::function GDescriptorSet::SetUpdateHelper::createCallback() { + auto ds_weak = m_set.weak_from_this(); + auto l_descriptorSetUpdater = m_descriptorSetUpdater; + const std::function callback = ([ds_weak, l_descriptorSetUpdater]() -> void { + if (auto ds = ds_weak.lock()) { + l_descriptorSetUpdater->addToUpdate(ds); + } + }); + + return callback; +} + diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index ffc58a0c3..f4cfb0496 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -35,8 +35,9 @@ class GDescriptorSet : public std::enable_shared_from_this { class SetUpdateHelper { public: - explicit SetUpdateHelper(GDescriptorSet &set, std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors) : - m_set(set), m_boundDescriptors(boundDescriptors) { + explicit SetUpdateHelper(GDescriptorSet &set, std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors, + std::shared_ptr descriptorSetUpdater) : + m_set(set), m_boundDescriptors(boundDescriptors), m_descriptorSetUpdater(descriptorSetUpdater) { //So that the resize of these vectors would not lead to pointer invalidation in updates vector bufferInfos.reserve(32); imageInfos.reserve(32); @@ -70,14 +71,7 @@ class GDescriptorSet : public std::enable_shared_from_this { } } if (createDescRecord) { - auto ds_weak = m_set.weak_from_this(); - - auto callback = ([ds_weak]() -> void { - if (auto ds = ds_weak.lock()) { - ds->update(); - } - }); - + std::function callback = createCallback(); m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); } } @@ -94,9 +88,12 @@ class GDescriptorSet : public std::enable_shared_from_this { std::vector dynamicBufferIndexes; std::unordered_map typeOverrides; + std::shared_ptr m_descriptorSetUpdater; std::vector updates; std::bitset m_updateBindPoints = 0; + + std::function createCallback(); }; SetUpdateHelper beginUpdate(); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index be02550e9..45a5fcf39 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -118,7 +118,7 @@ void GTextureVLK::createTexture(const HMipmapsVector &hmipmaps, const VkFormat & std::cout << "oops!" << std::endl << std::flush; } - m_tempUpdateData = new std::remove_pointer::type(); + m_tempUpdateData = std::make_unique(); auto &mipmaps = *hmipmaps; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 1934a90d8..7137b4891 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -38,6 +38,15 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, const std::vector &unitedBuffer); +private: + struct updateData { + VkBuffer stagingBuffer; + VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; + VmaAllocationInfo stagingBufferAllocInfo = {}; + + std::vector bufferCopyRegions = {}; + }; + public: ~GTextureVLK() override; @@ -48,12 +57,11 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this & getAndPlanDestroy() { if (!stagingBufferCreated || m_tempUpdateData == nullptr) { - return (decltype(m_tempUpdateData)) nullptr; + throw "Something went wrong"; } auto *l_device = &m_device; - auto *l_tempUpdateData = m_tempUpdateData; auto &l_stagingBuffer = m_tempUpdateData->stagingBuffer; auto &l_stagingBufferAlloc = m_tempUpdateData->stagingBufferAlloc; @@ -64,18 +72,14 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_thisgetVMAAllocator(), l_stagingBuffer, l_stagingBufferAlloc); if (auto texture = w_this.lock()) { - delete texture->m_tempUpdateData; texture->m_tempUpdateData = nullptr; - } - }); - m_tempUpdateData = nullptr; m_uploaded = true; m_loaded = true; - return l_tempUpdateData; + return m_tempUpdateData; } TextureStatus postLoad() override; @@ -89,13 +93,8 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this bufferCopyRegions = {}; - } * m_tempUpdateData = nullptr; + std::unique_ptr m_tempUpdateData = nullptr; VmaAllocation imageAllocation = VK_NULL_HANDLE; diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h new file mode 100644 index 000000000..67d9ba9fb --- /dev/null +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -0,0 +1,20 @@ +// +// Created by Deamon on 7/5/2023. +// + +#ifndef AWEBWOWVIEWERCPP_FRAMEPROFILE_H +#define AWEBWOWVIEWERCPP_FRAMEPROFILE_H + +#ifdef LINK_TRACY +#include "Tracy.hpp" + +#define setThreadName(a) tracy::SetThreadName(a); +#else +#define setThreadName(a) +#define ZoneScoped +#define ZoneScopedN(a) + +#endif + + +#endif //AWEBWOWVIEWERCPP_FRAMEPROFILE_H diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 98bf8f05e..78edf94e1 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -5,11 +5,13 @@ #include #include #include "SceneComposer.h" +#include "FrameProfile.h" + #ifdef __EMSCRIPTEN__ #include #endif -#include "Tracy.hpp" + void SceneComposer::processCaches(int limit) { if (m_apiContainer->cacheStorage) { @@ -25,7 +27,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon if (m_supportThreads) { loadingResourcesThread = std::thread([&]() { - tracy::SetThreadName("ResourceLoader"); + setThreadName("ResourceLoader"); using namespace std::chrono_literals; while (!this->m_isTerminating) { std::this_thread::sleep_for(1ms); @@ -37,7 +39,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon cullingThread = std::thread(([&]() { using namespace std::chrono_literals; FrameCounter frameCounter; - tracy::SetThreadName("Culling"); + setThreadName("Culling"); while (!this->m_isTerminating) { auto frameScenario = cullingInput.waitForNewInput(); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 45dab74fb..a4453d5f5 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -5,7 +5,7 @@ #include "MapSceneRenderer.h" #include "../../engine/objects/scenes/map.h" #include "../../gapi/interface/sortLambda.h" -#include "Tracy.hpp" +#include "../frame/FrameProfile.h" std::shared_ptr MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 963ca16e2..9687c7599 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -11,8 +11,8 @@ #include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" #include "materials/IMaterialInstance.h" #include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" -#include "Tracy.hpp" #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" +#include "../../frame/FrameProfile.h" #include MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index ffbab4de2..40f08132c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -6,7 +6,8 @@ #include "../../../../gapi/vulkan/buffers/CBufferChunkVLK.h" #include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" #include "../../../../gapi/vulkan/GVertexBufferBindingsVLK.h" -#include "Tracy.hpp" +#include "../../../frame/FrameProfile.h" + FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device), m_drawQuadVao(quadVAO) { m_ffxGlowVs = std::make_shared>(uboBuffer); From 49cd53e8a146d727f58e5a963cbe9353483e54a8 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 5 Jul 2023 21:40:05 +0300 Subject: [PATCH 088/212] move ADT matrix calculation to shader --- wowViewerLib/CMakeLists.txt | 2 +- .../glsl/common/commonLightFunctions.glsl | 4 +- .../glsl/forwardRendering/adtShader.frag | 44 +- .../src/engine/objects/adt/adtObject.cpp | 28 +- wowViewerLib/src/engine/objects/scenes/map.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1040 +++++++++-------- .../src/gapi/UniformBufferStructures.h | 6 +- .../renderer/mapScene/MapSceneRenderer.cpp | 6 +- .../src/renderer/mapScene/MapSceneRenderer.h | 3 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 6 +- 10 files changed, 605 insertions(+), 536 deletions(-) diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 7cc9ec2f8..60f60bf96 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 0) +set(LINK_TRACY 1) option(EMSCRIPTEN_SIMD "Enable SIMD for Emscripten " OFF) diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index a2baa067e..bfe996665 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -14,7 +14,7 @@ struct SceneExteriorLight { struct SceneWideParams { mat4 uLookAtMat; mat4 uPMatrix; - vec4 uViewUp; + vec4 uViewUpSceneTime; vec4 uInteriorSunDir; SceneExteriorLight extLight; }; @@ -59,7 +59,7 @@ vec3 calcLight( if (intLight.uInteriorDirectColorAndApplyExteriorLight.w > 0) { float nDotL = clamp(dot(normalizedN, normalize(-(sceneParams.extLight.uExteriorDirectColorDir.xyz))), 0.0, 1.0); - float nDotUp = dot(normalizedN, normalize(sceneParams.uViewUp.xyz)); + float nDotUp = dot(normalizedN, normalize(sceneParams.uViewUpSceneTime.xyz)); vec3 adjAmbient = (sceneParams.extLight.uExteriorAmbientColor.rgb + precomputedLight); vec3 adjHorizAmbient = (sceneParams.extLight.uExteriorHorizontAmbientColor.rgb + precomputedLight); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index f33195ada..72a306a19 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -37,7 +37,9 @@ layout(std140, binding=1) uniform meshWideBlockVSPS { }; layout(std140, binding=2) uniform meshWideBlockPS { - mat4 animationMat[4]; + vec4 scaleFactorPerLayer; + ivec4 animation_rotationPerLayer; + ivec4 animation_speedPerLayer; }; @@ -52,6 +54,38 @@ vec4 mixTextures(vec4 tex0, vec4 tex1, float alpha) { return (alpha*(tex1-tex0)+tex0); } +const vec2 s_texDir[8] = { + {-1.0, 0.0}, + {-1.0, 1.0}, + {0.0, 1.0}, + {1.0, 1.0}, + {1.0, 0.0}, + {1.0, -1.0}, + {0.0, -1.0}, + {-1.0, -1.0} +}; +const float s_tempTexSpeed[8] = {64.0, 48.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0}; + +float fmod1(float x, float y) { + return x - (y * trunc(x/y)); +} + +vec2 transformUV(in vec2 uv, in int layer) { + vec2 translate = vec2(0.0); + int animation_rotation = animation_rotationPerLayer[layer]; + if (animation_rotation >= 0 && animation_rotation < 8) { + vec2 transVector = s_texDir[animation_rotation] * (scene.uViewUpSceneTime.w * 0.001); + transVector.xy = transVector.yx; //why? + transVector.x = fmod1(transVector.x, 64); + transVector.y = fmod1(transVector.y, 64); + + translate = + transVector * + (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[animation_speedPerLayer[layer]])); + } + return (uv * scaleFactorPerLayer[layer]) + translate; +} + void main() { vec2 vTexCoord = vChunkCoords; const float threshold = 1.5; @@ -59,10 +93,10 @@ void main() { vec2 alphaCoord = vec2(vChunkCoords.x/8.0, vChunkCoords.y/8.0 ); vec3 alphaBlend = texture( uAlphaTexture, alphaCoord).gba; - vec2 tcLayer0 = (animationMat[0]*vec4(vTexCoord, 0, 1)).xy; - vec2 tcLayer1 = (animationMat[1]*vec4(vTexCoord, 0, 1)).xy; - vec2 tcLayer2 = (animationMat[2]*vec4(vTexCoord, 0, 1)).xy; - vec2 tcLayer3 = (animationMat[3]*vec4(vTexCoord, 0, 1)).xy; + vec2 tcLayer0 = transformUV(vTexCoord, 0); + vec2 tcLayer1 = transformUV(vTexCoord, 1); + vec2 tcLayer2 = transformUV(vTexCoord, 2); + vec2 tcLayer3 = transformUV(vTexCoord, 3); vec4 final; if (uUseHeightMixFormula.r > 0) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 1e1715ff7..98f69a28d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -402,6 +402,28 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } } adtMaterial->m_materialVSPS->save(); + + { + auto &matPS = adtMaterial->m_materialPS->getObject(); + for (int j = 0; j < 4; j++) { + matPS.scaleFactorPerLayer[j] = 1; + matPS.animation_rotationPerLayer[j] = -1; + matPS.animation_speedPerLayer[j] = 0; + } + for (int j = 0; j < adtFileTex->mcnkStructs[i].mclyCnt; j++) { + if ((adtFileTex->mtxp_len > 0) && !noLayers) { + auto const &textureParams = adtFileTex->mtxp[adtFileTex->mcnkStructs[i].mcly[j].textureId]; + float scaleFactor = (1.0f / (float)(1u << (textureParams.flags.texture_scale ))); + + matPS.scaleFactorPerLayer[j] = scaleFactor; + } + if (m_adtFileTex->mcnkStructs[i].mcly[j].flags.animation_enabled != 0) { + matPS.animation_rotationPerLayer[j] = m_adtFileTex->mcnkStructs[i].mcly[j].flags.animation_rotation; + matPS.animation_speedPerLayer[j] = m_adtFileTex->mcnkStructs[i].mcly[j].flags.animation_speed; + } + } + adtMaterial->m_materialPS->save(); + } } } } @@ -577,7 +599,9 @@ void AdtObject::update(animTime_t deltaTime ) { if (!m_loaded) { return; } -// if (adtWideBlockPS == nullptr) return; + + return; + for (int i = 0; i < 256; i++) { for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { @@ -638,7 +662,7 @@ void AdtObject::update(animTime_t deltaTime ) { auto &psBlock = adtMaterials[i]->m_materialPS->getObject(); for (int j = 0; j < 4; j++) { - psBlock.animationMat[j] = this->texturesPerMCNK[i].animTexture[j]; + //psBlock.animationMat[j] = this->texturesPerMCNK[i].animTexture[j]; } adtMaterials[i]->m_materialPS->save(); } diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index b859fe52e..02731812c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -114,7 +114,6 @@ class Map : public IScene, public IMapApi { std::shared_ptr getWmoObject(std::string fileName, SMMapObjDefObj1 &mapObjDef) override ; std::shared_ptr getWmoObject(int fileDataId, SMMapObjDefObj1 &mapObjDef) override ; - animTime_t getCurrentSceneTime() override ; virtual void getPotentialEntities( const MathHelper::FrustumCullingData &frustumData, @@ -200,6 +199,7 @@ class Map : public IScene, public IMapApi { ~Map() override { // std::cout << "Map destroyed " << std::endl; }; + animTime_t getCurrentSceneTime() override; void makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d2f5ac48a..505649e7c 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,96}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,256}, - {0,1,64}, - {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,10 +658,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,2,48}, {0,0,368}, {0,1,64}, }, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,16384}, - {0,1,64}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,16 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,5,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1524,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, }, { { {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1543,19 +1546,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,48}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {9,9,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,28 +1585,17 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, @@ -1623,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUp", true, 128, 1, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, @@ -1954,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1990,21 +2006,23 @@ const std::unordered_map &rend const std::shared_ptr> &htransparentMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes) { + ZoneScoped; mapProduceUpdateCounter.beginMeasurement(); auto &opaqueMeshes = *hopaqueMeshes; @@ -108,7 +109,8 @@ void MapSceneRenderer:: collectMeshes(const std::shared_ptr &rend void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, - bool isVulkan + bool isVulkan, + animTime_t sceneTime ) { ZoneScoped; @@ -126,7 +128,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrperspectiveMat; } blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; - blockPSVS.uViewUp = renderingMatrices->viewUp; + blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); blockPSVS.extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index fecb8b6f9..899765691 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -94,7 +94,8 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, - bool isVulkan); + bool isVulkan, + animTime_t sceneTime); private: FrameCounter mapProduceUpdateCounter; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 9687c7599..f1e5c56a1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -556,7 +556,11 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha mapScene->updateBuffers(framePlan); glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); - updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, framePlan->frameDependentData, true); + updateSceneWideChunk(sceneWideChunk, + framePlan->renderingMatrices, + framePlan->frameDependentData, + true, + mapScene->getCurrentSceneTime()); // { From cb3b61738af76fcd9153bd3acf012ee512a73b80 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 11 Jul 2023 02:57:13 +0300 Subject: [PATCH 089/212] - Add global blp counters - Do M2 update in threaded manner --- src/ui/FrontendUI.cpp | 13 +- wowViewerLib/CMakeLists.txt | 2 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 12 +- wowViewerLib/src/engine/geometry/m2Geom.h | 2 + .../managers/particles/particleEmitter.cpp | 73 +- .../managers/particles/particleEmitter.h | 3 + .../src/engine/objects/adt/adtObject.cpp | 7 +- .../src/engine/objects/adt/adtObject.h | 18 +- .../src/engine/objects/m2/m2Object.cpp | 9 + wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/scenes/map.cpp | 37 +- .../src/engine/shader/ShaderDefinitions.h | 1038 ++++++++--------- .../src/engine/texture/BlpTexture.cpp | 13 + wowViewerLib/src/engine/texture/BlpTexture.h | 10 + wowViewerLib/src/gapi/interface/IDevice.h | 2 +- .../src/gapi/interface/textures/ITexture.h | 3 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- .../commandBuffer/CommandBufferThread.cpp | 5 + .../commandBuffer/CommandBufferThread.h | 18 + .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 9 + 20 files changed, 691 insertions(+), 589 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 5a64d5460..c5a4aba8e 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -162,7 +162,18 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current area name: %s", getCurrentAreaName().c_str()); ImGui::Text("Uniform data for GPU: %.3f MB", m_api->hDevice->getUploadSize() / (1024.0f * 1024.0f)); - ImGui::Text("Current textures in use %d", m_api->hDevice->getCurrentTextureAllocated()); + + float m2s = m2SizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Total size of m2 files loaded %f MB", m2s); + int l_blpTexturesLoaded = blpTexturesLoaded; + float l_blpTexturesSizeLoaded = blpTexturesSizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Current blp files loaded %d", l_blpTexturesLoaded); + ImGui::Text("Current blp files size %f MB", l_blpTexturesSizeLoaded); + + int l_blpTexturesVulkanLoaded = blpTexturesVulkanLoaded; + float l_blpTexturesVulkanSizeLoaded = blpTexturesVulkanSizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Current blp vulkan textures loaded %d", l_blpTexturesVulkanLoaded); + ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); ImGui::NewLine(); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 60f60bf96..b3df3d61d 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -555,7 +555,7 @@ if (LINK_VULKAN) src/gapi/vulkan/context/vulkan_context.h src/gapi/vulkan/shaders/ShaderConfig.h src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp - src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h) + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp src/gapi/vulkan/commandBuffer/CommandBufferThread.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index e4c3b529e..d8deb6d2a 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -5,7 +5,9 @@ #include "m2Geom.h" #include "skinGeom.h" #include "../shader/ShaderDefinitions.h" -#include "../../gapi/interface/IDevice.h" +#include + +std::atomic m2SizeLoaded = 0; chunkDef M2Geom::m2FileTable = { [](M2Geom& file, ChunkData& chunkData){}, @@ -215,6 +217,8 @@ chunkDef M2Geom::m2FileTable = { void M2Geom::process(HFileContent m2File, const std::string &fileName) { this->m2File = m2File; + m2SizeLoaded.fetch_add(m2File->size()); + auto &m2FileData = *m2File.get(); if ( m2FileData[0] == 'M' && @@ -456,4 +460,8 @@ void M2Geom::loadLowPriority(const HApiContainer& m_api, uint32_t animationId, u m_m2Data->sequences[animationIndex]->flags |= 0x20; }); loadedAnimationMap[animCacheRecord] = animFile; -} \ No newline at end of file +} + +M2Geom::~M2Geom() { + m2SizeLoaded.fetch_add(-m2File->size()); +} diff --git a/wowViewerLib/src/engine/geometry/m2Geom.h b/wowViewerLib/src/engine/geometry/m2Geom.h index 18824cce5..f4b96d017 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.h +++ b/wowViewerLib/src/engine/geometry/m2Geom.h @@ -29,6 +29,7 @@ class M2Geom : public PersistentFile { useFileId = true; m_modelFileId = fileDataId; }; + ~M2Geom(); std::string getName() { return m_modelName; @@ -105,4 +106,5 @@ class M2Geom : public PersistentFile { }; typedef std::shared_ptr HM2Geom; +extern std::atomic m2SizeLoaded; #endif //WOWVIEWERLIB_M2GEOM_H diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index ca0915136..1753a0062 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -311,6 +311,28 @@ void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } m_material = sceneRenderer->createM2ParticleMaterial(pipelineTemplate, particleTemplate); + + //Update material + { + Particle::meshParticleWideBlockPS &blockPS = m_material->m_fragmentData->getObject(); + uint8_t blendMode = m_data->old.blendingType; + if (blendMode == 0) { + blockPS.uAlphaTest = -1.0f; + } else if (blendMode == 1) { + blockPS.uAlphaTest = 0.501960814f; + } else { + blockPS.uAlphaTest = 0.0039215689f; + } + + int uPixelShader = particleMaterialShader[this->shaderId].pixelShader; + + blockPS.uPixelShader = uPixelShader; + blockPS.uBlendMode = static_cast(blendMode < ParticleBlendingModeToEGxBlendEnum.size() ? + ParticleBlendingModeToEGxBlendEnum[blendMode] : + EGxBlendEnum::GxBlend_Opaque); + + m_material->m_fragmentData->save(); + } } @@ -631,15 +653,6 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { int frameNum = m_api->hDevice->getDrawFrameNumber(); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; - size_t maxFutureSize = particles.size() * sizeof(ParticleBuffStructQuad); - if ((m_data->old.flags & 0x60000) == 0x60000) { - maxFutureSize *= 2; - } - - if (maxFutureSize > vboBufferDynamic->getSize()) { - createMesh(m_sceneRenderer, frame[frameNum], maxFutureSize); - vboBufferDynamic = frame[frameNum].m_bufferVBO; - } szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); szVertexCnt = 0; @@ -657,6 +670,23 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { } } +void ParticleEmitter::fitBuffersToSize() { + if (particles.size() == 0) { + return; + } + + size_t maxFutureSize = particles.size() * sizeof(ParticleBuffStructQuad); + if ((m_data->old.flags & 0x60000) == 0x60000) { + maxFutureSize *= 2; + } + int frameNum = m_api->hDevice->getDrawFrameNumber(); + auto vboBufferDynamic = frame[frameNum].m_bufferVBO; + + if (maxFutureSize > vboBufferDynamic->getSize()) { + createMesh(m_sceneRenderer, frame[frameNum], maxFutureSize); + } +} + int ParticleEmitter::buildVertex1(CParticle2 &p, ParticlePreRenderData &particlePreRenderData) { int coefXInt = (particlePreRenderData.m_ageDependentValues.timedHeadCell & this->textureColMask); float coefXf; @@ -801,8 +831,6 @@ int ParticleEmitter::buildVertex1(CParticle2 &p, ParticlePreRenderData &particle particlePreRenderData.m_ageDependentValues.m_alpha, texScaleVec.x, texScaleVec.y, p.texPos); - - return 0; } @@ -1104,28 +1132,5 @@ void ParticleEmitter::updateBuffers() { currentFrame.m_mesh->setEnd(szVertexCnt * 6); currentFrame.m_mesh->setSortDistance(m_currentBonePos); - - //Update material - { - Particle::meshParticleWideBlockPS &blockPS = m_material->m_fragmentData->getObject(); - uint8_t blendMode = m_data->old.blendingType; - if (blendMode == 0) { - blockPS.uAlphaTest = -1.0f; - } else if (blendMode == 1) { - blockPS.uAlphaTest = 0.501960814f; - } else { - blockPS.uAlphaTest = 0.0039215689f; - } - - int uPixelShader = particleMaterialShader[this->shaderId].pixelShader; - - blockPS.uPixelShader = uPixelShader; - blockPS.uBlendMode = static_cast(blendMode < ParticleBlendingModeToEGxBlendEnum.size() ? - ParticleBlendingModeToEGxBlendEnum[blendMode] : - EGxBlendEnum::GxBlend_Opaque); - - m_material->m_fragmentData->save(); - } - } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index d95febeed..da96c9d27 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -70,6 +70,8 @@ class ParticleEmitter { void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); + void fitBuffersToSize(); + int flags = 6; CParticleMaterialFlags materialFlags; bool emittingLastFrame = false; @@ -204,6 +206,7 @@ class ParticleEmitter { void GetSpin(CParticle2 &p, float &baseSpin, float &deltaSpin) const; void createMesh(const HMapSceneBufferCreate &sceneRenderer, particleFrame &frame, int size); + }; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 98f69a28d..a252fb648 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -20,8 +20,8 @@ void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { // std::cout << "AdtObject::loadingFinished finished called"; - texturesPerMCNK = std::vector(m_adtFile->mcnkRead+1); - animationTranslationPerMCNK = std::vector(m_adtFile->mcnkRead+1); +// texturesPerMCNK = std::vector(m_adtFile->mcnkRead+1); +// animationTranslationPerMCNK = std::vector(m_adtFile->mcnkRead+1); loadAlphaTextures(); @@ -602,7 +602,7 @@ void AdtObject::update(animTime_t deltaTime ) { return; - +/* for (int i = 0; i < 256; i++) { for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { texturesPerMCNK[i].animTexture[j] = mathfu::mat4::Identity(); @@ -667,6 +667,7 @@ void AdtObject::update(animTime_t deltaTime ) { adtMaterials[i]->m_materialPS->save(); } } +*/ } void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index c4a1c8df4..9409d3944 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -168,15 +168,15 @@ class AdtObject { HGSamplableTexture getAdtHeightTexture(int textureId); HGSamplableTexture getAdtSpecularTexture(int textureId); - struct AnimTextures { - std::array animTexture; - }; - struct AnimTrans { - std::array transVectors; - }; - std::vector texturesPerMCNK; - - std::vector animationTranslationPerMCNK; +// struct AnimTextures { +// std::array animTexture; +// }; +// struct AnimTrans { +// std::array transVectors; +// }; +// std::vector texturesPerMCNK; +// +// std::vector animationTranslationPerMCNK; void calcBoundingBoxes(); void loadM2s(); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index eeb97e68b..5e8abb647 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1014,6 +1014,15 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v } } +void M2Object::fitParticleBuffersToSize() { + int minParticle = m_api->getConfig()->minParticle; + int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); + + for (int i = minParticle; i < maxParticle; i++) { + particleEmitters[i]->fitBuffersToSize(); + } +} + void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { if (!this->m_loaded) return; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index c96f42198..a23ed8a59 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -246,9 +246,6 @@ class M2Object { void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { -// if (hasModf0x2Flag) { -// m_useLocalDiffuseColor = 0; -// } if (m_useLocalDiffuseColor == -1) { m_useLocalDiffuseColor = value ? 1 : 0; } @@ -268,6 +265,7 @@ class M2Object { void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); + void fitParticleBuffersToSize(); void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); void drawDebugLight(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index d29dd7220..f817d84a1 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1561,25 +1561,32 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { int granSize = m2ToDraw.size() / (2 * threadsAvailable); if (granSize == 0) granSize = m2ToDraw.size(); -// if (granSize > 0) { -// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), -// [&](tbb::blocked_range r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto &m2Object = m2ToDraw[i]; -// if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, -// renderPlan->frameDependentData); -// } -// } -// }, tbb::simple_partitioner()); -// } - + //Can't be paralleled? for (auto &m2Object: renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); + m2Object->fitParticleBuffersToSize(); } } + + if (granSize > 0) { + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } + }, tbb::simple_partitioner()); + } + +// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 505649e7c..a94e70dab 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -214,19 +246,16 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +263,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +273,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +287,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -326,16 +326,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +345,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +360,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +379,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +394,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +413,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +430,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +464,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,19 +499,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,12 +519,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +543,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +577,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +596,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,15 +612,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,48}, + {0,0,368}, + {0,1,64}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,13 +633,20 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,11 +657,10 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,48}, {0,0,368}, {0,1,64}, }, @@ -679,20 +677,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +692,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +760,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +779,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +794,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +814,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,11 +829,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,16}, }, { { @@ -877,15 +863,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +897,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +931,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +950,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +966,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +999,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1018,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,15 +1035,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, + {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {4,4,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,12 +1060,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,15 +1113,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1153,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,15 +1187,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,96}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,11 +1207,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,21 +1223,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {0,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,15 +1243,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1349,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1366,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,15 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,4,48}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,13 +1419,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {1,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,16 +1469,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {0,1,96}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,21 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {0,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,11 +1524,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,16 +1543,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,48}, - {0,0,368}, - }, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, + {0,0,368}, + {0,1,64}, + }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,10 +1585,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1612,21 +1623,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1984,51 +1954,57 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, }}, - {"renderFrameBufferShader", { + {"drawBBShader", { { - 2, { - {"_0_2_gauss_offsets[0]", true, 0, 1, 1, 5}, - {"_0_2_gauss_weights[0]", true, 80, 1, 1, 5}, - {"_0_2_uResolution", true, 160, 1, 2, 0}, + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, - {"drawPortalShader", { + {"adtLodShader", { { - 1, { - {"_0_1_uColor", true, 0, 1, 4, 0}, + 0, { + {"_0_0_uViewUp", true, 0, 1, 4, 0}, + {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, + {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, + {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, + {"_0_0_FogColor", true, 64, 1, 4, 0}, + {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + } + }, + }}, + {"drawDepthShader", { + { + 2, { + {"_0_2_drawDepth", false, 0, 1, 1, 0}, + {"_0_2_uFarPlane", true, 4, 1, 1, 0}, + {"_0_2_uNearPlane", true, 8, 1, 1, 0}, } }, }}, {"adtShader", { { - 1, { - {"_0_1_uPos", true, 0, 1, 4, 0}, - {"_0_1_uUseHeightMixFormula", false, 16, 1, 4, 0}, - {"_0_1_uHeightScale", true, 32, 1, 4, 0}, - {"_0_1_uHeightOffset", true, 48, 1, 4, 0}, + 2, { + {"_0_2_scaleFactorPerLayer", true, 0, 1, 4, 0}, + {"_0_2_animation_rotationPerLayer", false, 16, 1, 4, 0}, + {"_0_2_animation_speedPerLayer", false, 32, 1, 4, 0}, } }, { @@ -2053,24 +2029,93 @@ const std::unordered_map blpTexturesLoaded = 0; +std::atomic blpTexturesSizeLoaded = 0; + TextureFormat getTextureType(BlpFile *blpFile) { TextureFormat textureFormat = TextureFormat::Undetected; switch (blpFile->preferredFormat) { @@ -167,9 +170,19 @@ void BlpTexture::process(HFileContent blpFile, const std::string &fileName) { // this->texture = createGlTexture(pBlpFile, textureFormat, mipmaps, fileName); this->fsStatus = FileStatus ::FSLoaded; this->m_textureName = fileName; + + blpTexturesLoaded.fetch_add(1); + blpTexturesSizeLoaded.fetch_add(blpFile->size()); } const HMipmapsVector BlpTexture::getMipmapsVector() { return parseMipmaps( (BlpFile *)m_blpFile->data(), m_textureFormat); } +BlpTexture::~BlpTexture() { + if (m_blpFile) { + blpTexturesLoaded.fetch_add(-1); + blpTexturesSizeLoaded.fetch_add(-m_blpFile->size()); + } +} + diff --git a/wowViewerLib/src/engine/texture/BlpTexture.h b/wowViewerLib/src/engine/texture/BlpTexture.h index 44278b1be..48a0ee57f 100644 --- a/wowViewerLib/src/engine/texture/BlpTexture.h +++ b/wowViewerLib/src/engine/texture/BlpTexture.h @@ -9,6 +9,7 @@ #include "../../include/sharedFile.h" #include "../persistance/PersistentFile.h" #include +#include enum class TextureFormat { Undetected, @@ -36,6 +37,8 @@ class BlpTexture : public PersistentFile{ explicit BlpTexture(std::string fileName){ m_textureName = fileName;}; explicit BlpTexture(int fileDataId){m_textureName = std::to_string(fileDataId); m_fileDataId = fileDataId; }; + ~BlpTexture(); + std::string getTextureName() { return m_textureName; }; void process(HFileContent blpFile, const std::string &fileName) override; const HMipmapsVector getMipmapsVector(); @@ -43,6 +46,10 @@ class BlpTexture : public PersistentFile{ TextureFormat getTextureFormat() { return m_textureFormat; } + int getFileSize() { + if (m_blpFile == nullptr) return 0; + return m_blpFile->size(); + } private: std::string m_textureName; int m_fileDataId = 0; @@ -51,5 +58,8 @@ class BlpTexture : public PersistentFile{ TextureFormat m_textureFormat = TextureFormat::Undetected; }; +extern std::atomic blpTexturesLoaded; +extern std::atomic blpTexturesSizeLoaded; + #endif //WOWVIEWERLIB_BLPTEXTURE_H diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 5fccd8520..e15762b1e 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -151,7 +151,7 @@ enum class GDeviceType { class IDevice { public: - static const constexpr uint8_t MAX_FRAMES_IN_FLIGHT = 5; + static const constexpr uint8_t MAX_FRAMES_IN_FLIGHT = 2; virtual ~IDevice() {}; diff --git a/wowViewerLib/src/gapi/interface/textures/ITexture.h b/wowViewerLib/src/gapi/interface/textures/ITexture.h index 974c91c85..8bff95d07 100644 --- a/wowViewerLib/src/gapi/interface/textures/ITexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ITexture.h @@ -36,4 +36,7 @@ class ITexture { virtual void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) = 0; }; + +extern std::atomic blpTexturesVulkanLoaded; +extern std::atomic blpTexturesVulkanSizeLoaded; #endif //AWEBWOWVIEWERCPP_ITEXTURE_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index ec8bc8cd8..6552e1c6b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -107,7 +107,7 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc) { //Destruction of this virtualBlock happens only in deallocation queue. - //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, + //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, //the virtualBlock was still not been free'd //So there would be no error diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp new file mode 100644 index 000000000..06ecc7224 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 7/7/2023. +// + +#include "CommandBufferThread.h" diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.h new file mode 100644 index 000000000..59bcc4871 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBufferThread.h @@ -0,0 +1,18 @@ +// +// Created by Deamon on 7/7/2023. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFERTHREAD_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFERTHREAD_H + +#include + +class CommandBufferThread { +public: + +private: + std::thread m_commandBufferThread; +}; + + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFERTHREAD_H diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index 2b7d57e99..38970d35d 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -12,6 +12,9 @@ inline static std::string addrToStr(void *addr) { return ss.str(); } +std::atomic blpTexturesVulkanLoaded = 0; +std::atomic blpTexturesVulkanSizeLoaded = 0; + GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, const HBlpTexture &texture, bool xWrapTex, bool yWrapTex, @@ -30,6 +33,10 @@ GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, GBlpTextureVLK::~GBlpTextureVLK() { // std::cout << "destroyed blp text!" << std::endl; + if (m_loaded && m_uploaded && m_texture && m_texture->getStatus() == FileStatus::FSLoaded) { + blpTexturesVulkanLoaded.fetch_add(-1); + blpTexturesVulkanSizeLoaded.fetch_add(-m_texture->getFileSize()); + } } @@ -93,6 +100,8 @@ TextureStatus GBlpTextureVLK::postLoad() { if (!m_uploaded) { if (m_texture == nullptr) return TextureStatus::TSNotLoaded; if (m_texture->getStatus() != FileStatus::FSLoaded) return TextureStatus::TSNotLoaded; + blpTexturesVulkanLoaded.fetch_add(1); + blpTexturesVulkanSizeLoaded.fetch_add(m_texture->getFileSize()); this->createTexture(m_texture->getTextureFormat(), m_texture->getMipmapsVector()); // m_texture = nullptr; From 42ea434b0f8c79878aff7a1d81827e1e22811f7b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 15 Jul 2023 01:24:53 +0300 Subject: [PATCH 090/212] - Add rendering of antiportals - Add BLP viewer - Fix heap corruption in BLP --- CMakeLists.txt | 2 +- src/ui/FrontendUI.cpp | 22 +- src/ui/FrontendUI.h | 3 + src/ui/childWindow/BLPViewer.cpp | 53 + src/ui/childWindow/BLPViewer.h | 29 + src/ui/imguiLib/fileBrowser/imfilebrowser.h | 4 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 4 +- .../src/engine/objects/ViewsObjects.cpp | 39 +- .../src/engine/objects/ViewsObjects.h | 10 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 16 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 50 +- .../persistance/header/commonFileStructs.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1024 ++++++++--------- .../src/engine/texture/BlpTexture.cpp | 26 +- wowViewerLib/src/engine/texture/BlpTexture.h | 3 +- wowViewerLib/src/gapi/interface/IDevice.cpp | 3 + wowViewerLib/src/gapi/interface/IDevice.h | 1 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 2 +- .../commandBuffer/CommandBufferThread.h | 1 + .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 9 +- wowViewerLib/src/include/config.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 18 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 715 ++++++++++++ .../vulkan/MapSceneRenderVisBufferVLK.h | 139 +++ 29 files changed, 1590 insertions(+), 598 deletions(-) create mode 100644 src/ui/childWindow/BLPViewer.cpp create mode 100644 src/ui/childWindow/BLPViewer.h create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 34641cbf5..4568dcda7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,7 +237,7 @@ set(SOURCE_FILES src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h src/ui/imguiLib/wheelCapture/wheelCapture.cpp - src/ui/imguiLib/wheelCapture/wheelCapture.h) + src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h) set(SOURCE_FILES_VULKAN diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index c5a4aba8e..6c400a123 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -127,6 +127,7 @@ void FrontendUI::composeUI() { showMakeScreenshotDialog(); showCurrentStatsDialog(); showMinimapGenerationSettingsDialog(); + showBlpViewer(); // Rendering ImGui::Render(); @@ -296,6 +297,14 @@ void FrontendUI::showCurrentStatsDialog() { } } +void FrontendUI::showBlpViewer() { + if (!m_blpViewerWindow) return; + + if (!m_blpViewerWindow->draw()) { + m_blpViewerWindow = nullptr; + } +} + // templated version of my_equal so it could work with both char and wchar_t template struct my_equal { @@ -692,6 +701,10 @@ void FrontendUI::showMainMenu() { if (ImGui::MenuItem("Open minimap generator", "", false, cascOpened)) { showMinimapGeneratorSettings = true; } + if (ImGui::MenuItem("Open BLP viewer", "", false, cascOpened)) { + if (!m_blpViewerWindow) + m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer); + } if (ImGui::MenuItem("Test export")) { if (m_currentScene != nullptr) { exporter = std::make_shared("./gltf/"); @@ -872,6 +885,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { openWMOSceneByfdid(1120838); } + if (ImGui::Button("8du_zuldazarraid_antiportal01.wmo", ImVec2(-1, 0))) { + openWMOSceneByfdid(2574165); + } if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, "world/wmo/dungeon/az_karazahn/karazhan.wmo"); @@ -1282,8 +1298,12 @@ void FrontendUI::showSettingsDialog() { if (ImGui::Checkbox("Render portals", &renderPortals)) { m_api->getConfig()->renderPortals = renderPortals; } + bool renderAntiPortals = m_api->getConfig()->renderAntiPortals; + if (ImGui::Checkbox("Render anti portals", &renderAntiPortals)) { + m_api->getConfig()->renderAntiPortals = renderAntiPortals; + } - if (renderPortals) { + if (renderPortals || renderAntiPortals) { bool renderPortalsIgnoreDepth = m_api->getConfig()->renderPortalsIgnoreDepth; if (ImGui::Checkbox("Ignore depth test for rendering portals", &renderPortalsIgnoreDepth)) { m_api->getConfig()->renderPortalsIgnoreDepth = renderPortalsIgnoreDepth; diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index c45353c6e..fc9f5a5ed 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -25,6 +25,7 @@ #include "renderer/uiScene/IFrontendUIBufferCreate.h" #include "renderer/uiScene/FrontendUIRenderer.h" #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" +#include "childWindow/BLPViewer.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -193,6 +194,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_minimapGenerationWindow = nullptr; + std::shared_ptr m_blpViewerWindow = nullptr; //Test export @@ -235,6 +237,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this + +BLPViewer::BLPViewer(HApiContainer &api, std::shared_ptr uiRenderer) : m_api(api), m_uiRenderer(uiRenderer) { + +} + +bool BLPViewer::draw() { + + ImGui::Begin("BLP Viewer", &m_showWindow); + { + if (ImGui::InputText("BlpName/FileDataId: ", blpName.data(), blpName.size()-1)) { + blpName[blpName.size()-1] = 0; + } + ImGui::SameLine(); + if (ImGui::Button("Load")) { + int fileDataId = 0; + + try{ + fileDataId = std::stoi(blpName.data()); + } catch (...) {} + + if (fileDataId > 0) { + m_blpTexture = m_api->cacheStorage->getTextureCache()->getFileId(fileDataId); + auto textureObj = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({textureObj}); + } else { + m_blpTexture = m_api->cacheStorage->getTextureCache()->get(blpName.data()); + auto textureObj = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({textureObj}); + } + } + if (m_blpTexture && m_blpTexture->getStatus() == FileStatus::FSRejected) { + ImGui::Text("Failed to load BLP file"); + } else + if (m_blpTexture && m_blpTexture->getStatus() == FileStatus::FSLoaded && material) { + float sizeX = 0, sizeY = 0; + auto windowSize = ImGui::GetContentRegionAvail(); + sizeX = windowSize.x; + sizeY = windowSize.y; + + ImGui::ImageButton(material, ImVec2(sizeX, sizeY)); + } + } + ImGui::End(); + + return m_showWindow; +} diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h new file mode 100644 index 000000000..a0582b3a3 --- /dev/null +++ b/src/ui/childWindow/BLPViewer.h @@ -0,0 +1,29 @@ +// +// Created by Deamon on 7/14/2023. +// + +#ifndef AWEBWOWVIEWERCPP_BLPVIEWER_H +#define AWEBWOWVIEWERCPP_BLPVIEWER_H + +#include +#include "../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" +#include "../../../wowViewerLib/src/engine/ApiContainer.h" +#include "../renderer/uiScene/FrontendUIRenderer.h" + +class BLPViewer { +public: + BLPViewer(HApiContainer &api, std::shared_ptr uiRenderer); + + bool draw(); +private: + bool m_showWindow = true; + std::array blpName = {0};\ + + HApiContainer m_api; + std::shared_ptr m_uiRenderer; + std::shared_ptr m_blpTexture; + HMaterial material = nullptr; +}; + + +#endif //AWEBWOWVIEWERCPP_BLPVIEWER_H diff --git a/src/ui/imguiLib/fileBrowser/imfilebrowser.h b/src/ui/imguiLib/fileBrowser/imfilebrowser.h index c264dcedd..d74076cfd 100644 --- a/src/ui/imguiLib/fileBrowser/imfilebrowser.h +++ b/src/ui/imguiLib/fileBrowser/imfilebrowser.h @@ -206,8 +206,8 @@ inline ImGui::FileBrowser &ImGui::FileBrowser::operator=(const FileBrowser © inline void ImGui::FileBrowser::SetTitle(std::string title) { title_ = std::move(title); - openLabel_ = title_ + "##filebrowser_" + std::to_string(reinterpret_cast(this)); - openNewDirLabel_ = "new dir##new_dir_" + std::to_string(reinterpret_cast(this)); + openLabel_ = title_ + "##filebrowser_"; + openNewDirLabel_ = "new dir##new_dir_"; } inline void ImGui::FileBrowser::Open() diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index d8deb6d2a..0dd6ac51f 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -463,5 +463,7 @@ void M2Geom::loadLowPriority(const HApiContainer& m_api, uint32_t animationId, u } M2Geom::~M2Geom() { - m2SizeLoaded.fetch_add(-m2File->size()); + if (m2File != nullptr) { + m2SizeLoaded.fetch_add(-m2File->size()); + } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 053552caf..dac070328 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -35,7 +35,7 @@ void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool rende } } - for (auto const &mesh : portalPointsFrame.m_meshes) { + for (auto const &mesh : m_portalMeshes) { transparentMeshes.push_back(mesh); } } @@ -78,7 +78,8 @@ void GeneralView::setM2Lights(std::shared_ptr &m2Object) { m2Object->setUseLocalLighting(false); } -void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer) { +void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, + const std::vector> &portalsVerts, bool isAntiportal) { std::vector indiciesArray; std::vector verticles; int k = 0; @@ -87,26 +88,32 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc stripOffsets.push_back(0); int verticleOffset = 0; int stripOffset = 0; - for (int i = 0; i < this->worldPortalVertices.size(); i++) { + for (int i = 0; i < portalsVerts.size(); i++) { //if (portalInfo.index_count != 4) throw new Error("portalInfo.index_count != 4"); - int verticlesCount = this->worldPortalVertices[i].size(); + int verticlesCount = portalsVerts[i].size(); if ((verticlesCount - 2) <= 0) { stripOffsets.push_back(stripOffsets[i]); continue; }; - for (int j =0; j < (((int)verticlesCount)-2); j++) { - indiciesArray.push_back(verticleOffset+0); - indiciesArray.push_back(verticleOffset+j+1); - indiciesArray.push_back(verticleOffset+j+2); + if (!isAntiportal) { + for (int j = 0; j < (((int) verticlesCount) - 2); j++) { + indiciesArray.push_back(verticleOffset + 0); + indiciesArray.push_back(verticleOffset + j + 1); + indiciesArray.push_back(verticleOffset + j + 2); + } + } else { + for (int j = 0; j < (verticlesCount); j++) { + indiciesArray.push_back(verticleOffset + j); + } } stripOffset += ((verticlesCount-2) * 3); for (int j =0; j < verticlesCount; j++) { - verticles.push_back(this->worldPortalVertices[i][j].x); - verticles.push_back(this->worldPortalVertices[i][j].y); - verticles.push_back(this->worldPortalVertices[i][j].z); + verticles.push_back(portalsVerts[i][j].x); + verticles.push_back(portalsVerts[i][j].y); + verticles.push_back(portalsVerts[i][j].z); } verticleOffset += verticlesCount; @@ -115,7 +122,7 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc if (verticles.empty()) return; - //TODO: + auto &portalPointsFrame = portals.emplace_back(); portalPointsFrame.m_indexVBO = sceneRenderer->createPortalIndexBuffer((indiciesArray.size() * sizeof(uint16_t))); portalPointsFrame.m_bufferVBO = sceneRenderer->createPortalVertexBuffer((verticles.size() * sizeof(float))); @@ -136,7 +143,11 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc auto material = sceneRenderer->createPortalMaterial(pipelineTemplate); auto &portalColor = material->m_materialPS->getObject(); - portalColor.uColor = {0.058, 0.058, 0.819607843, 0.3}; + if (!isAntiportal) { + portalColor.uColor = {0.058, 0.058, 0.819607843, 0.3}; + } else { + portalColor.uColor = {0.819607843, 0.058, 0.058, 0.3}; + } material->m_materialPS->save(); //Create mesh @@ -146,7 +157,7 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc auto mesh = sceneRenderer->createSortableMesh(meshTemplate, material, 0); - portalPointsFrame.m_meshes.push_back(mesh); + m_portalMeshes.push_back(mesh); } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index f9b57aaea..4f271d13a 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -37,6 +37,7 @@ class GeneralView { //Support several frustum planes because of how portal culling works std::vector> worldPortalVertices = {}; + std::vector> worldAntiPortalVertices = {}; MathHelper::FrustumCullingData frustumData; int level = -1; @@ -46,13 +47,16 @@ class GeneralView { HGVertexBuffer m_bufferVBO; HGVertexBufferBindings m_bindings; - std::vector m_meshes = {}; - } portalPointsFrame; + }; + std::vector m_portalMeshes = {}; + + std::vector portals; virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); - void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer); + void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, + const std::vector> &portalsVerts, bool isAntiportal = false); void addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos); }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 5e8abb647..db3c0ab7f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1031,8 +1031,8 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa M2Data * m2File = this->m_m2Geom->getM2Data(); M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); - //Update materials - if (m_placementMatrixChanged) { + //Update materials` + if (true) { auto &placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); placementMatrix.uPlacementMat = m_placementMatrix; m_modelWideDataBuff->m_placementMatrix->save(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f817d84a1..32bc31b56 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1316,7 +1316,6 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende int m2ProcessedThisFrame = 0; int wmoProcessedThisFrame = 0; int wmoGroupsProcessedThisFrame = 0; -// if (m_api->getConfig()->getRenderM2()) { for (auto &m2Object : renderPlan->m2Array.getToLoadMain()) { if (m2Object == nullptr) continue; @@ -1404,10 +1403,19 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende std::tie(skyMesh0x4Sky, skyMeshMat0x4) = createSkyMesh(sceneRenderer, skyMeshBinding, true); } bool renderPortals = m_api->getConfig()->renderPortals; + bool renderAntiPortals = m_api->getConfig()->renderAntiPortals; - for (auto &view : renderPlan->viewsHolder.getInteriorViews()) { - if (renderPortals) { - view->produceTransformedPortalMeshes(sceneRenderer, m_api); + if (renderPortals) { + for (auto &view : renderPlan->viewsHolder.getInteriorViews()) { + view->produceTransformedPortalMeshes(sceneRenderer, m_api, view->worldPortalVertices); + } + } + + + if (renderAntiPortals) { + if(auto const &exterior = renderPlan->viewsHolder.getExterior()) { + exterior->produceTransformedPortalMeshes(sceneRenderer, m_api, + exterior->worldAntiPortalVertices, true); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 4126ddfe2..1b8b2d170 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -313,7 +313,7 @@ void WmoGroupObject::checkGroupFrustum(bool &drawDoodads, bool &drawGroup, drawGroup = false; if (!m_loaded) { //Force load of group if it's exterior - if (m_main_groupInfo->flags.EXTERIOR > 0) { + if (m_main_groupInfo->flags.EXTERIOR > 0 || !m_api->getConfig()->usePortalCulling) { drawGroup = true; drawDoodads = true; } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index f8ad2862c..d7e9f51cf 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -10,7 +10,7 @@ #include "../../../renderer/frame/FrameProfile.h" #include -std::vector createOccluders(const HWmoGroupGeom& groupGeom) +std::vector createAntiPortal(const HWmoGroupGeom& groupGeom, const mathfu::mat4 &placementMat) { std::vector points(0); @@ -20,37 +20,9 @@ std::vector createOccluders(const HWmoGroupGeom& groupGeom) ; ++mopy_index, ++movi_index ) { - points.push_back(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+0]])); - points.push_back(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+1]])); - points.push_back(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+2]])); -// C3Vector points[3] = -// { groupGeom->verticles[groupGeom->indicies[movi_index]] -// groupGeom->verticles[groupGeom->indicies[movi_index]] -// groupGeom->verticles[groupGeom->indicies[movi_index]] -// }; -// -// float avg ((points[0]->z + points[1]->z + points[2]->z) / 3.0); -// -// unsigned int two_points[2]; -// unsigned int two_points_index (0); -// -// for (unsigned int i (0); i < 3; ++i) -// { -// if (points[i]->z > avg) -// { -// two_points[two_points_index++] = i; -// } -// } -// -// if (two_points_index > 1) -// { -// CMapObjOccluder* occluder (CMapObj::AllocOccluder()); -// occluder->p1 = points[two_points[0]]; -// occluder->p2 = points[two_points[1]]; -// -// append (this->occluders, occluder); -// } - + points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+0]]), 1.0f)).xyz()); + points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+1]]), 1.0f)).xyz()); + points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+2]]), 1.0f)).xyz()); } return points; } @@ -921,6 +893,20 @@ bool WmoObject::startTraversingWMOGroup( auto exteriorView = viewsHolder.getOrCreateExterior(frustumDataGlobal); exteriorView->wmoGroupArray.addToDraw(this->groupObjects[i]); } + + if (m_api->getConfig()->renderAntiPortals) { + auto exteriorView = viewsHolder.getOrCreateExterior(frustumDataGlobal); + if (!this->groupObjects[i]->getIsLoaded()) { + exteriorView->wmoGroupArray.addToLoad(this->groupObjects[i]); + } else { + if ((mainGeom->groups[i].flags.ANTIPORTAL) > 0) { //ANTIPORTAL + if (this->groupObjects[i]->getIsLoaded()) { + exteriorView->worldAntiPortalVertices.push_back( + createAntiPortal(this->groupObjects[i]->getWmoGroupGeom(), m_placementMatrix)); + } + } + } + } } //Process results diff --git a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h index 77268da6c..266758012 100644 --- a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h +++ b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h @@ -51,7 +51,7 @@ #endif #endif -#define DEBUGPOINTER 0 +//#define DEBUGPOINTER 1 template struct PointerChecker { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a94e70dab..505649e7c 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -246,16 +214,19 @@ const std::unordered_map> attributesPe { "aTexcoord2", 4}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -263,7 +234,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -273,6 +244,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -287,6 +268,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -326,15 +326,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,4,32}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -345,11 +346,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, + {1,8, "uTexture4"}, + {1,9, "uTexture5"}, + {1,10, "uTexture6"}, + {1,11, "uTexture7"}, + {1,12, "uTexture8"}, + {1,13, "uTexture9"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -360,15 +370,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,4,96}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,11 +390,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -394,11 +406,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,5,96}, + {0,0,368}, }, { { @@ -413,13 +426,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {1,10, "uNormalTex"}, + {1,8, "uNoise"}, + {1,7, "uWhiteWater"}, + {1,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,15 +445,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,12 +480,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -499,16 +514,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,4,16}, + {0,3,4096}, + {0,2,14080}, {0,0,368}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -519,20 +537,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, + {1,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,13,9}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -543,15 +553,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -577,15 +588,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -596,11 +607,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -612,17 +622,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,2,48}, - {0,0,368}, - {0,1,64}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,20 +641,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {5,13,9}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -657,10 +658,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,2,48}, {0,0,368}, {0,1,64}, }, @@ -677,11 +679,20 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9, "uAlphaTexture"}, + {1,10, "uLayerHeight0"}, + {1,11, "uLayerHeight1"}, + {1,12, "uLayerHeight2"}, + {1,13, "uLayerHeight3"}, + {1,5, "uLayer0"}, + {1,6, "uLayer1"}, + {1,7, "uLayer2"}, + {1,8, "uLayer3"}, }, { { {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,15 +703,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +738,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -760,15 +772,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,10 +791,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,16 +807,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +826,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -829,11 +843,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,1,12}, }, { { @@ -863,15 +877,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -897,15 +911,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -931,15 +945,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, }, { { - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +963,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -999,15 +1012,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1018,13 +1031,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,21 +1046,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, - {0,0,368}, - {0,1,64}, - {0,6,4096}, + {0,4,32}, }, { { - {6,6,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1060,15 +1065,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, - {6,9,4}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,21 +1115,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {0,3,16384}, - {0,1,64}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, }, { { - {7,7,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1153,15 +1149,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1187,16 +1183,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1207,12 +1202,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1223,16 +1217,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,7,64}, + {0,5,256}, + {0,4,4096}, + {0,2,256}, {0,0,368}, + {0,1,64}, + {0,6,4096}, }, { { - {0,0,1}, + {6,6,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1243,14 +1242,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, + {1,6, "uTexture"}, + {1,7, "uTexture2"}, + {1,8, "uTexture3"}, + {1,9, "uTexture4"}, }, { { {0,0,0}, - {5,7,3}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1296,7 +1296,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1330,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,12 +1349,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,14 +1364,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {0,1,96}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1399,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,48}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1419,12 +1418,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1435,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1469,16 +1468,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,32}, {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,11 +1488,14 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "uTexture"}, + {1,6, "uTexture2"}, + {1,7, "uTexture3"}, }, { { {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1504,16 +1506,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,5,96}, + {0,3,16384}, + {0,1,64}, {0,0,368}, + {0,4,4096}, + {0,5,256}, + {0,6,4096}, + {0,7,64}, }, { { - {0,0,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1524,15 +1531,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, }, { { {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1543,19 +1546,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,14080}, + {0,4,48}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,12 +1566,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {1,5, "uTexture"}, }, { { {0,0,0}, - {9,9,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,21 +1585,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1623,6 +1612,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1954,27 +1984,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_0_5_values0", true, 0, 1, 4, 0}, + {"_0_5_values1", true, 16, 1, 4, 0}, + {"_0_5_values2", true, 32, 1, 4, 0}, + {"_0_5_values3", true, 48, 1, 4, 0}, + {"_0_5_values4", true, 64, 1, 4, 0}, + {"_0_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -1990,21 +2006,29 @@ const std::unordered_mapwidth; int32_t height = blpFile->height; @@ -73,11 +76,17 @@ HMipmapsVector parseMipmaps(BlpFile *blpFile, TextureFormat textureFormat) { mipmapsCnt++; } auto mipmaps = std::make_shared>(); - - mipmaps->resize(mipmapsCnt); + auto &pmipmaps = (*mipmaps); + pmipmaps.resize(mipmapsCnt); for (int i = 0; i < mipmapsCnt; i++) { if ((blpFile->lengths[i] == 0) || (blpFile->offsets[i] == 0)) break; + if ( (blpFile->offsets[i] >= blpFileSize) || + ((blpFile->offsets[i] + blpFile->lengths[i]) >= blpFileSize) + ) { + std::cout << "wrong offset in blp file" << std::endl; + continue; + } uint8_t *data = ((uint8_t *) blpFile)+blpFile->offsets[i]; //blpFile->lengths[i]); @@ -92,7 +101,7 @@ HMipmapsVector parseMipmaps(BlpFile *blpFile, TextureFormat textureFormat) { // if (minSize == validSize) break; - mipmapStruct_t &mipmapStruct = (*mipmaps)[i]; + mipmapStruct_t &mipmapStruct = pmipmaps[i]; mipmapStruct.height = height; mipmapStruct.width = width; mipmapStruct.texture.resize(validSize, 0); @@ -139,7 +148,9 @@ HMipmapsVector parseMipmaps(BlpFile *blpFile, TextureFormat textureFormat) { mipmapStruct.texture[j * 4 + 3] = a; } } else { - std::copy(data, data + blpFile->lengths[i], &mipmapStruct.texture[0]); + size_t sizeToCopy = std::min(blpFile->lengths[i], mipmapStruct.texture.size()); + assert(sizeToCopy <= mipmapStruct.texture.size()); + std::copy(data, data + sizeToCopy, mipmapStruct.texture.data()); } height = height / 2; @@ -158,7 +169,8 @@ void BlpTexture::process(HFileContent blpFile, const std::string &fileName) { BlpFile *pBlpFile = (BlpFile *) blpFile->data(); if (pBlpFile->fileIdent != '2PLB') { std::cerr << "Wrong ident for BLP2 file " << pBlpFile->fileIdent << " " << fileName << std::endl; - throw std::runtime_error("Wrong ident for BLP2 file"); + this->fsStatus = FileStatus ::FSRejected; + return; } this->m_textureFormat = getTextureType(pBlpFile); @@ -176,7 +188,7 @@ void BlpTexture::process(HFileContent blpFile, const std::string &fileName) { } const HMipmapsVector BlpTexture::getMipmapsVector() { - return parseMipmaps( (BlpFile *)m_blpFile->data(), m_textureFormat); + return parseMipmaps( (BlpFile *)m_blpFile->data(), m_textureFormat, m_blpFile->size()); } BlpTexture::~BlpTexture() { diff --git a/wowViewerLib/src/engine/texture/BlpTexture.h b/wowViewerLib/src/engine/texture/BlpTexture.h index 48a0ee57f..bc4a2a23c 100644 --- a/wowViewerLib/src/engine/texture/BlpTexture.h +++ b/wowViewerLib/src/engine/texture/BlpTexture.h @@ -21,7 +21,8 @@ enum class TextureFormat { RGBA, PalARGB1555DitherFloydSteinberg, PalARGB4444DitherFloydSteinberg, - PalARGB2565DitherFloydSteinberg + PalARGB2565DitherFloydSteinberg, + BC5_UNORM }; class mipmapStruct_t { diff --git a/wowViewerLib/src/gapi/interface/IDevice.cpp b/wowViewerLib/src/gapi/interface/IDevice.cpp index 5211c199d..44c78e170 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.cpp +++ b/wowViewerLib/src/gapi/interface/IDevice.cpp @@ -18,6 +18,7 @@ int anisFiltrationSupported = -1; #include #endif +/* bool IDevice::getIsDTXCompressedTexturesSupported() { #ifdef __EMSCRIPTEN__ if (compressedTexturesSupported == -1){ @@ -37,6 +38,8 @@ bool IDevice::getIsDTXCompressedTexturesSupported() { return true; #endif } +*/ + bool IDevice::getIsAnisFiltrationSupported() { #ifdef __EMSCRIPTEN__ if (anisFiltrationSupported == -1){ diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index e15762b1e..4feca653d 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -178,7 +178,6 @@ class IDevice { virtual void drawFrame(const std::vector> &renderFuncs) = 0; // virtual void drawStageAndDeps(HDrawStage drawStage) = 0; - virtual bool getIsDTXCompressedTexturesSupported(); virtual bool getIsAnisFiltrationSupported(); virtual float getAnisLevel() = 0; virtual bool getIsVulkanAxisSystem() {return false;} diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 8175e55e5..13cf44235 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -794,7 +794,7 @@ void GDeviceVLK::increaseFrameNumber() { bool GDeviceVLK::getIsAnisFiltrationSupported() { return supportedFeatures.samplerAnisotropy; }; -bool GDeviceVLK::getIsDTXCompressedTexturesSupported() { +bool GDeviceVLK::getIsBCCompressedTexturesSupported() { return supportedFeatures.textureCompressionBC; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 2dcc97f39..90d54012f 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -81,7 +81,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thisgetTextureName() == "3071385") { - std::cout << "3071385 loaded" << std::endl; - } - m_debugName = "Texture FDID " + texture->getTextureName() + " blp ptr: "+ blpAddress_str + " self ptr :" + selfAddr_str ; } @@ -66,6 +62,9 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe case TextureFormat::RGBA: textureFormatGPU = VK_FORMAT_R8G8B8A8_UNORM; break; + case TextureFormat::BC5_UNORM: + textureFormatGPU = VK_FORMAT_BC5_UNORM_BLOCK; + break; default: debuglog("Unknown texture format found in file: ") @@ -76,7 +75,7 @@ void GBlpTextureVLK::createTexture(TextureFormat textureFormat, const HMipmapsVe auto &mipmaps = *hmipmaps; /* S3TC is not supported on mobile platforms */ - bool compressedTextSupported = m_device.getIsDTXCompressedTexturesSupported(); + bool compressedTextSupported = m_device.getIsBCCompressedTexturesSupported(); if (!compressedTextSupported && textureFormat != TextureFormat::BGRA) { this->decompressAndUpload(textureFormat, hmipmaps); return; diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index d51797dd9..2781ff896 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -46,6 +46,7 @@ class Config { bool renderM2 = true; bool renderBSP = false; bool renderPortals = false; + bool renderAntiPortals = false; bool renderPortalsIgnoreDepth = false; bool usePortalCulling = true; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index eed4ae430..fddfe5a3a 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -20,7 +20,7 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan, +void MapSceneRenderer::collectMeshes(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index f1e5c56a1..f871ee2e1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -205,6 +205,10 @@ HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { } static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; +static const ShaderConfig m2ForwardShaderConfig = {{ + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}, + {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} +}}; std::shared_ptr MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { @@ -248,12 +252,12 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)->getSubBuffer()) @@ -288,12 +292,12 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal auto vertexData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) .ubo(4, vertexData->getSubBuffer()) @@ -452,7 +456,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); - BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); + DynamicBufferChunkHelperVLK::create(m_device, uboBuffer, result->m_placementMatrix); BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); @@ -543,6 +547,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); + //The portal meshes are created here. Need to call doPostLoad before CollectMeshes + mapScene->doPostLoad(l_this, framePlan); + // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { @@ -551,7 +558,6 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // } // ); - mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); mapScene->updateBuffers(framePlan); glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp new file mode 100644 index 000000000..a6acd0cf8 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -0,0 +1,715 @@ +// +// Created by Deamon on 12/1/2022. +// + +#include "MapSceneRenderVisBufferVLK.h" +#include "../../vulkan/IRenderFunctionVLK.h" +#include "../../../engine/objects/scenes/map.h" +#include "../../../gapi/vulkan/materials/MaterialBuilderVLK.h" +#include "../../../gapi/vulkan/meshes/GMeshVLK.h" +#include "../../../gapi/vulkan/buffers/CBufferChunkVLK.h" +#include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" +#include "materials/IMaterialInstance.h" +#include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" +#include "../../frame/FrameProfile.h" +#include + +MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : + m_device(hDevice), MapSceneRenderer(config) { + iboBuffer = m_device->createIndexBuffer(1024*1024); + + vboM2Buffer = m_device->createVertexBuffer(1024*1024); + vboPortalBuffer = m_device->createVertexBuffer(1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); + vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); + vboWMOBuffer = m_device->createVertexBuffer(1024*1024); + vboWaterBuffer = m_device->createVertexBuffer(1024*1024); + vboSkyBuffer = m_device->createVertexBuffer(1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); + + { + const float epsilon = 0.f; + std::array vertexBuffer = { + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, 1.0f - epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, 1.f - epsilon)) + }; + std::vector indexBuffer = { + 0, 1, 2, + 2, 1, 3 + }; + m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + m_drawQuadVao = m_device->createVertexBufferBindings(); + m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); + m_drawQuadVao->setIndexBuffer(m_iboQuad); + m_drawQuadVao->save(); + } + + uboBuffer = m_device->createUniformBuffer(1024*1024); + uboStaticBuffer = m_device->createUniformBuffer(1024*1024); + + uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); + + m_emptyADTVAO = createADTVAO(nullptr, nullptr); + m_emptyM2VAO = createM2VAO(nullptr, nullptr); + m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); + m_emptySkyVAO = createSkyVAO(nullptr, nullptr); + m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); + m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); + m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); + + //Framebuffers for rendering + auto const dataFormat = { ITextureFormat::itRGBA}; + + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, +// VK_SAMPLE_COUNT_1_BIT, + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + true, false); + + glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); + + createFrameBuffers(); + + sceneWideChunk = std::make_shared>(hDevice, uboBuffer); +} + +// ------------------ +// Buffer creation +// ------------------ + +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto adtVAO = m_device->createVertexBufferBindings(); + adtVAO->addVertexBufferBinding(vertexBuffer, adtVertexBufferBinding); + adtVAO->setIndexBuffer(indexBuffer); + + return adtVAO; +}; + +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto wmoVAO = m_device->createVertexBufferBindings(); + + HGVertexBuffer ambientBuffer = nullptr; + if (vertexBuffer != nullptr) { + ambientBuffer = vboWMOGroupAmbient->getSubBuffer(sizeof(mathfu::vec4_packed)); + auto packedAmbient = mathfu::vec4_packed(localAmbient); + static_assert(sizeof(packedAmbient) == 16); static_assert(sizeof(mathfu::vec4_packed) == 16); + + ambientBuffer->uploadData(&packedAmbient, sizeof(mathfu::vec4_packed)); + } + wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); + wmoVAO->addVertexBufferBinding(ambientBuffer, std::vector(staticWmoGroupAmbient.begin(), staticWmoGroupAmbient.end()), true); + wmoVAO->setIndexBuffer(indexBuffer); + + return wmoVAO; +} +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2VAO = m_device->createVertexBufferBindings(); + m2VAO->addVertexBufferBinding(vertexBuffer, staticM2Bindings); + m2VAO->setIndexBuffer(indexBuffer); + + return m2VAO; +} +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2ParticleVAO = m_device->createVertexBufferBindings(); + m2ParticleVAO->addVertexBufferBinding(vertexBuffer, staticM2ParticleBindings); + m2ParticleVAO->setIndexBuffer(indexBuffer); + + return m2ParticleVAO; +} + +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto waterVAO = m_device->createVertexBufferBindings(); + waterVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); + waterVAO->setIndexBuffer(indexBuffer); + + return waterVAO; +}; + +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto skyVAO = m_device->createVertexBufferBindings(); + skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(skyConusBinding.begin(), skyConusBinding.end())); + skyVAO->setIndexBuffer(indexBuffer); + + return skyVAO; +} + +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto portalVAO = m_device->createVertexBufferBindings(); + portalVAO->addVertexBufferBinding(vertexBuffer, std::vector(drawPortalBindings.begin(), drawPortalBindings.end())); + portalVAO->setIndexBuffer(indexBuffer); + + return portalVAO; +}; + +HGVertexBuffer MapSceneRenderVisBufferVLK::createPortalVertexBuffer(int sizeInBytes) { + return vboPortalBuffer->getSubBuffer(sizeInBytes); +}; +HGIndexBuffer MapSceneRenderVisBufferVLK::createPortalIndexBuffer(int sizeInBytes){ + return iboBuffer->getSubBuffer(sizeInBytes); +}; + +HGVertexBuffer MapSceneRenderVisBufferVLK::createM2VertexBuffer(int sizeInBytes) { + return vboM2Buffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderVisBufferVLK::createM2ParticleVertexBuffer(int sizeInBytes) { + return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderVisBufferVLK::createM2IndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderVisBufferVLK::createADTVertexBuffer(int sizeInBytes) { + return vboAdtBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderVisBufferVLK::createADTIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderVisBufferVLK::createWMOVertexBuffer(int sizeInBytes) { + return vboWMOBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderVisBufferVLK::createWMOIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderVisBufferVLK::createWaterVertexBuffer(int sizeInBytes) { + return vboWaterBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderVisBufferVLK::createWaterIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} +HGVertexBuffer MapSceneRenderVisBufferVLK::createSkyVertexBuffer(int sizeInBytes) { + return vboSkyBuffer->getSubBuffer(sizeInBytes);; +}; + +HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; + +std::shared_ptr +MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexFragmentData = std::make_shared>(uboStaticBuffer); + auto fragmentData = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, vertexFragmentData->getSubBuffer()) + .ubo(2, fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, adtMaterialTemplate.textures[0]) + .texture(6, adtMaterialTemplate.textures[1]) + .texture(7, adtMaterialTemplate.textures[2]) + .texture(8, adtMaterialTemplate.textures[3]) + .texture(9, adtMaterialTemplate.textures[4]) + .texture(10, adtMaterialTemplate.textures[5]) + .texture(11, adtMaterialTemplate.textures[6]) + .texture(12, adtMaterialTemplate.textures[7]) + .texture(13, adtMaterialTemplate.textures[8]); + }) + .toMaterial([&vertexFragmentData, &fragmentData](IADTMaterial *instance) -> void { + instance->m_materialVSPS = vertexFragmentData; + instance->m_materialPS = fragmentData; + }); + + return material; +} + +std::shared_ptr +MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) { + + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexFragmentData = std::make_shared>(uboStaticBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, forwardShaderConfig) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)->getSubBuffer()) + .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)->getSubBuffer()) + .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) + .ubo(7, vertexFragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(6, m2MaterialTemplate.textures[0]) + .texture(7, m2MaterialTemplate.textures[1]) + .texture(8, m2MaterialTemplate.textures[2]) + .texture(9, m2MaterialTemplate.textures[3]); + }) + .toMaterial([&vertexFragmentData](IM2Material *instance) -> void { + instance->m_vertexFragmentData = vertexFragmentData; + }); + + material->blendMode = pipelineTemplate.blendMode; + material->batchIndex = m2MaterialTemplate.batchIndex; + material->vertexShader = m2MaterialTemplate.vertexShader; + material->pixelShader = m2MaterialTemplate.pixelShader; + + + return material; +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexData = std::make_shared>(uboStaticBuffer); + auto fragmentData = std::make_shared>(uboStaticBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, forwardShaderConfig) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) + .ubo(4, vertexData->getSubBuffer()) + .ubo(5, fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(6, m2MaterialTemplate.textures[0]) + .texture(7, m2MaterialTemplate.textures[1]) + .texture(8, m2MaterialTemplate.textures[2]) + .texture(9, m2MaterialTemplate.textures[3]) + .texture(10, m2MaterialTemplate.textures[4]); + }) + .toMaterial([&vertexData, fragmentData](IM2WaterFallMaterial *instance) -> void { + instance->m_vertexData = vertexData; + instance->m_fragmentData = fragmentData; + }); + + return material; +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createM2ParticleMaterial( + const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2ParticleMatTemplate) { + + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) + .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, m2ParticleMatTemplate.textures[0]) + .texture(6, m2ParticleMatTemplate.textures[1]) + .texture(7, m2ParticleMatTemplate.textures[2]); + }) + .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +} + +std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOWideChunk() { + return std::make_shared>(uboBuffer); +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) { + auto l_vertexData = std::make_shared>(uboStaticBuffer); ; + auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; + + auto &l_sceneWideChunk = sceneWideChunk; + auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) + .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) + .ubo(2, l_vertexData->getSubBuffer()) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, wmoMaterialTemplate.textures[0]) + .texture(6, wmoMaterialTemplate.textures[1]) + .texture(7, wmoMaterialTemplate.textures[2]) + .texture(8, wmoMaterialTemplate.textures[3]) + .texture(9, wmoMaterialTemplate.textures[4]) + .texture(10, wmoMaterialTemplate.textures[5]) + .texture(11, wmoMaterialTemplate.textures[6]) + .texture(12, wmoMaterialTemplate.textures[7]) + .texture(13, wmoMaterialTemplate.textures[8]); + }) + .toMaterial([&l_vertexData, &l_fragmentData](IWMOMaterial *instance) -> void { + instance->m_materialVS = l_vertexData; + instance->m_materialPS = l_fragmentData; + }); + + return material; +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) { + auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; + + auto &l_sceneWideChunk = sceneWideChunk; + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) + .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, waterMaterialTemplate.texture); + }) + .toMaterial([&l_fragmentData](IWaterMaterial *instance) -> void { + instance->m_materialPS = l_fragmentData; + }); + + material->color = waterMaterialTemplate.color; + material->liquidFlags = waterMaterialTemplate.liquidFlags; + material->materialId = waterMaterialTemplate.liquidMaterialId; + + return material; +} + + + +std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto skyColors = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) + .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, skyColors->getSubBuffer()); + }) + .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { + instance->m_skyColors = skyColors; + }); + + return material; +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto materialPS = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) + .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(1, materialPS->getSubBuffer()); + }) + .toMaterial([&materialPS](IPortalMaterial *instance) -> void { + instance->m_materialPS = materialPS; + }); + + return material; +} + +std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { + auto result = std::make_shared(); + + BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); + BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); + BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); + + return result; +} + +inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { + if (mesh == nullptr) return; + + const auto &meshVlk = std::dynamic_pointer_cast(mesh); + auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); + + //1. Bind VBOs + cmdBuf.bindVertexBuffers(vulkanBindings->getVertexBuffers()); + + //2. Bind IBOs + cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); + + //3. Bind pipeline + auto material = meshVlk->material(); + cmdBuf.bindPipeline(material->getPipeline()); + + //4. Bind Descriptor sets + auto const &descSets = material->getDescriptorSets(); + for (int i = 0; i < descSets.size(); i++) { + if (descSets[i] != nullptr) { + cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); + } + } + + //5. Set view port + cmdBuf.setViewPort(viewportType); + + //6. Set scissors + if (meshVlk->scissorEnabled()) { + cmdBuf.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); + } else { + cmdBuf.setDefaultScissors(); + } + + //7. Draw the mesh + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); +} + +static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { + return {vec[0], vec[1], vec[2]}; +} + +std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::shared_ptr> &frameInputParams, + const std::shared_ptr &framePlan) { + + ZoneScoped; + + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); + auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); + + if (frameInputParams->viewPortDimensions.maxs[0] != m_width || + frameInputParams->viewPortDimensions.maxs[1] != m_height) { + m_width = frameInputParams->viewPortDimensions.maxs[0]; + m_height = frameInputParams->viewPortDimensions.maxs[1]; + + createFrameBuffers(); + + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + m_device->getSwapChainRenderPass()); + } + + } + + + //Create meshes + auto opaqueMeshes = std::make_shared>(); + auto transparentMeshes = std::make_shared>(); + + auto skyOpaqueMeshes = std::make_shared>(); + auto skyTransparentMeshes = std::make_shared>(); + framePlan->m2Array.lock(); + framePlan->wmoArray.lock(); + framePlan->wmoGroupArray.lock(); + +// TracyMessageL("collect meshes created"); +// std::future collectMeshAsync = std::async(std::launch::async, +// [&]() { + collectMeshes(framePlan, opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes); +// } +// ); + + mapScene->doPostLoad(l_this, framePlan); + mapScene->update(framePlan); + mapScene->updateBuffers(framePlan); + glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); + + updateSceneWideChunk(sceneWideChunk, + framePlan->renderingMatrices, + framePlan->frameDependentData, + true, + mapScene->getCurrentSceneTime()); + + +// { +// ZoneScopedN("collect meshes wait"); +// collectMeshAsync.wait(); +// } + + bool renderSky = framePlan->renderSky; + auto skyMesh = framePlan->skyMesh; + auto skyMesh0x4 = framePlan->skyMesh0x4; + return createRenderFuncVLK([opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + // --------------------- + // Upload stuff + // --------------------- + { + { + std::string debugMess = "sceneWideChunk = " + std::to_string( + DynamicBufferChunkHelperVLK::cast(l_this->sceneWideChunk)->getOffset()); + auto debugLabel = uploadCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + } + ZoneScopedN("submit buffers"); + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + + uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); + } + + // ---------------------- + // Draw meshes + // ---------------------- + { + auto passHelper = frameBufCmd.beginRenderPass(false, + l_this->m_renderPass, + l_this->m_colorFrameBuffers[l_this->m_device->getDrawFrameNumber()], + frameInputParams->viewPortDimensions.mins, + frameInputParams->viewPortDimensions.maxs, + vec4ToArr3(frameInputParams->frameParameters->clearColor), + true + ); + + { + ZoneScopedN("submit opaque"); + for (auto const &mesh: *opaqueMeshes) { + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } + } + if (true) { + if (renderSky && skyMesh) + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); + + for (auto const &mesh: *skyOpaqueMeshes) { + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + } + for (auto const &mesh: *skyTransparentMeshes) { +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); +// +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); + } + if (renderSky && skyMesh0x4) + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); + } + { + ZoneScopedN("submit transparent"); + for (auto const &mesh: *transparentMeshes) { +// +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); + +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } + } + } + + l_this->glowPass->doPass(frameBufCmd, swapChainCmd, + l_this->m_device->getSwapChainRenderPass(), + frameInputParams->viewPortDimensions); + }); +} + +std::shared_ptr MapSceneRenderVisBufferVLK::getLastCreatedPlan() { + return nullptr; +} + +HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); +} + +HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane); + return mesh; +} + +HGM2Mesh +MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + int layer, int priorityPlane) { + + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + return mesh; +} +HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, + const std::shared_ptr &material, + int layer, int priorityPlane) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + return mesh; +} +void MapSceneRenderVisBufferVLK::createFrameBuffers() { + { + auto const dataFormat = {ITextureFormat::itRGBA}; + + for (auto &colorFrameBuffer: m_colorFrameBuffers) { + colorFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itDepth32, + m_device->getMaxSamplesCnt(), + m_width, m_height + ); + } + } + +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h new file mode 100644 index 000000000..dc7021aae --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -0,0 +1,139 @@ +// +// Created by Deamon on 12/1/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H + + +#include "../MapSceneRenderer.h" +#include "../../../gapi/vulkan/GDeviceVulkan.h" +#include "../materials/IMaterialStructs.h" +#include "passes/FFXGlowPassVLK.h" + +class MapSceneRenderVisBufferVLK : public MapSceneRenderer { +public: + explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderVisBufferVLK() override = default; + + std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType); + + std::shared_ptr getLastCreatedPlan() override; + +//------------------------------------- +// Buffer creation +//------------------------------------- + HGVertexBufferBindings createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; + HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + + HGVertexBuffer createPortalVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createPortalIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; + HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; + + HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createWMOVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createWMOIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createWaterVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createWaterIndexBuffer(int sizeInBytes) override; + + HGVertexBuffer createSkyVertexBuffer(int sizeInBytes) override; + HGIndexBuffer createSkyIndexBuffer(int sizeInBytes) override; + +//------------------------------------- +// Material creation +//------------------------------------- + + std::shared_ptr createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) override; + std::shared_ptr createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) override; + std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr> createWMOWideChunk() override; + + std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) override; + std::shared_ptr createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) override; + + std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; + + std::shared_ptr createPortalMaterial(const PipelineTemplate &pipelineTemplate) override; + +//------------------------------------- +// Mesh creation +//------------------------------------- + + HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; + HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; + HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; +private: + HGDeviceVLK m_device; + + int m_width = 640; + int m_height = 480; + + std::unique_ptr glowPass; + + HGBufferVLK vboM2Buffer; + HGBufferVLK vboM2ParticleBuffer; + HGBufferVLK vboPortalBuffer; + + HGBufferVLK vboAdtBuffer; + HGBufferVLK vboWMOBuffer; + HGBufferVLK vboWMOGroupAmbient; + HGBufferVLK vboWaterBuffer; + HGBufferVLK vboSkyBuffer; + + HGBufferVLK iboBuffer; + + HGBufferVLK uboStaticBuffer; + HGBufferVLK uboBuffer; + HGBufferVLK uboM2BoneMatrixBuffer; + + HGBufferVLK m_vboQuad; + HGBufferVLK m_iboQuad; + + HGVertexBufferBindings m_drawQuadVao = nullptr; + + std::shared_ptr> sceneWideChunk; + + + std::shared_ptr m_renderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + + HGVertexBufferBindings m_emptyM2VAO = nullptr; + HGVertexBufferBindings m_emptyADTVAO = nullptr; + HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; + HGVertexBufferBindings m_emptyPortalVAO = nullptr; + HGVertexBufferBindings m_emptySkyVAO = nullptr; + HGVertexBufferBindings m_emptyWMOVAO = nullptr; + HGVertexBufferBindings m_emptyWaterVAO = nullptr; + + void createFrameBuffers(); +}; + + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H From 3da10ab9361b0412329c25ce521dee07d06bcb99 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 18 Jul 2023 17:57:14 +0300 Subject: [PATCH 091/212] - restore rendering on ribbon emitters --- .../glsl/forwardRendering/ribbonShader.frag | 16 +- .../src/engine/managers/CRibbonEmitter.cpp | 256 +++++++++--------- .../src/engine/managers/CRibbonEmitter.h | 17 +- .../src/engine/objects/m2/m2Object.cpp | 49 ++-- wowViewerLib/src/engine/objects/m2/m2Object.h | 5 +- .../src/engine/objects/scenes/map.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 177 ------------ .../src/engine/objects/wmo/wmoObject.h | 5 - .../src/engine/shader/ShaderDefinitions.h | 16 +- .../src/gapi/UniformBufferStructures.h | 10 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 7 + .../src/renderer/mapScene/MapSceneRenderer.h | 33 ++- .../mapScene/materials/IMaterialStructs.h | 8 + .../vulkan/MapSceneRenderForwardVLK.cpp | 39 +++ .../vulkan/MapSceneRenderForwardVLK.h | 8 + 15 files changed, 273 insertions(+), 375 deletions(-) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index bda57d969..6c522b006 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -17,10 +17,12 @@ layout(std140, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; + +//layout(std140, binding=3) uniform textureMatrices { +// mat4 textureMatrix[64]; +//}; layout(std140, binding=4) uniform meshWideBlockPS { - vec4 uAlphaTestScalev; - ivec4 uPixelShaderv; - vec4 uTextureTranslate; + ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; layout(set=1, binding=5) uniform sampler2D uTexture; @@ -28,10 +30,10 @@ layout(set=1, binding=5) uniform sampler2D uTexture; layout(location = 0) out vec4 outputColor; void main() { - vec2 textCoordScale = uAlphaTestScalev.yz; - vec2 texcoord = (vTexcoord0 * textCoordScale) + uTextureTranslate.xy; +// vec2 textCoordScale = uAlphaTestScalev.yz; +// vec2 texcoord = (vTexcoord0 * textCoordScale) + uTextureTranslate.xy; - vec4 tex = texture(uTexture, texcoord).rgba; + vec4 tex = texture(uTexture, vTexcoord0).rgba; vec4 finalColor = vec4((vColor.rgb*tex.rgb), tex.a * vColor.a); @@ -45,7 +47,7 @@ void main() { // .xyz; vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, uPixelShaderv.y); + finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); outputColor = finalColor; } diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 92a319402..fea97daa5 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -7,17 +7,12 @@ #include "../../gapi/UniformBufferStructures.h" #include "../../gapi/interface/materials/IMaterial.h" -static std::array staticRibbonBindings = {{ - {+ribbonShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, pos) }, // 0 - {+ribbonShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(CRibbonVertex), offsetof(CRibbonVertex, diffuseColor)}, // 12 - {+ribbonShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, texCoord)}, // 16 - //24 -}}; - //----- (00A19710) -------------------------------------------------------- -CRibbonEmitter::CRibbonEmitter(HApiContainer api, M2Object *object, +CRibbonEmitter::CRibbonEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, + const std::shared_ptr &m2ModelData, + M2Object *object, std::vector &materials, - std::vector &textureIndicies, int textureTransformLookup) : m_api(api) + std::vector &textureIndicies, int textureTransformLookup) : m_api(api), m_sceneRenderer(sceneRenderer) { this->textureTransformLookup = textureTransformLookup; this->m_refCount = 1; @@ -85,92 +80,76 @@ CRibbonEmitter::CRibbonEmitter(HApiContainer api, M2Object *object, check_offset(); check_offset(); - createMesh(object, materials, textureIndicies); + createMaterials(sceneRenderer, m2ModelData, object, materials, textureIndicies); } -extern EGxBlendEnum M2BlendingModeToEGxBlendEnum [8]; -void CRibbonEmitter::createMesh(M2Object *m2Object, std::vector &materials, std::vector &textureIndicies) { - auto device = m_api->hDevice; -// -// //Create Buffers -// auto ribbonBindings = std::vector(staticRibbonBindings.begin(), staticRibbonBindings.end()); -// for (int k = 0; k < 4; k++) { -// //TODO: -// /* -// frame[k].m_indexVBO = device->createIndexBuffer(); -// frame[k].m_bufferVBO = device->createVertexBuffer(); -// */ -// -// frame[k].m_bindings = device->createVertexBufferBindings(); -// frame[k].m_bindings->setIndexBuffer(frame[k].m_indexVBO); -// -// frame[k].m_bindings->addVertexBufferBinding(frame[k].m_bufferVBO, ribbonBindings); -// frame[k].m_bindings->save(); -// -// -// //Get shader -// for(int i = 0; i < materials.size(); i++) { -// auto &material = materials[i]; -// auto &textureIndex = textureIndicies[i]; -// -// HGShaderPermutation shaderPermutation = device->getShader("ribbonShader", "ribbonShader", nullptr); -// -// -// //TODO: -// PipelineTemplate pipelineTemplate; -// pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; -// pipelineTemplate.depthWrite = !(material.flags & 0x10);; -// pipelineTemplate.depthCulling = !(material.flags & 0x8);; -// pipelineTemplate.backFaceCulling = !(material.flags & 0x4);; -// pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; -// -// -// //Let's assume ribbons are always at least transparent -// if (pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { -// pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; -// } -// -// //Create mesh -// gMeshTemplate meshTemplate(frame[k].m_bindings); -// -// meshTemplate.start = 0; -// meshTemplate.end = 0; -// -// meshTemplate.texture = std::vector(1, nullptr); -// HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndicies[i]); -// meshTemplate.texture[0] = device->createBlpTexture(tex0, true, true); -// -// auto blendMode = pipelineTemplate.blendMode; -// auto textureTransformLookupIndex = (this->textureTransformLookup>=0) ? this->textureTransformLookup + i : -1; -// std::shared_ptr> meshRibbonWideBlockPS = nullptr; -// -// meshRibbonWideBlockPS->setUpdateHandler([blendMode, m2Object, textureTransformLookupIndex](auto &data, const HFrameDependantData &frameDepedantData) { -// Ribbon::meshRibbonWideBlockPS& blockPS = data; -// -// blockPS.uAlphaTest = -1.0f; -// blockPS.uPixelShader = 0; -// blockPS.uBlendMode = static_cast(blendMode); -// -// mathfu::mat4 textureTransformMat = mathfu::mat4::Identity(); -// if (textureTransformLookupIndex >= 0) { -// textureTransformMat = m2Object->getTextureTransformByLookup(textureTransformLookupIndex); -// } -// -// auto textureTranslate = textureTransformMat.GetColumn(3); -// blockPS.textureTranslate0 = textureTranslate.x; -// blockPS.textureTranslate1 = textureTranslate.y; -// blockPS.textureTranslate2 = textureTranslate.z; -// -// blockPS.textureScale0 = textureTransformMat.GetColumn(0).Length(); -// blockPS.textureScale1 = textureTransformMat.GetColumn(1).Length(); -// blockPS.textureScale2 = textureTransformMat.GetColumn(2).Length(); -// -// }); -// -// -// frame[k].m_meshes.push_back(device->createMesh(meshTemplate)); -// } -// } +extern const std::array M2BlendingModeToEGxBlendEnum; +void CRibbonEmitter::createMaterials(const HMapSceneBufferCreate &sceneRenderer, + const std::shared_ptr &m2ModelData, + M2Object *m2Object, std::vector &materials, std::vector &textureIndices) { + + m_ribbonMaterials.resize(materials.size()); + for (int i = 0; i < materials.size(); i++) { + auto &material = materials[i]; + + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; + pipelineTemplate.depthWrite = !(material.flags & 0x10);; + pipelineTemplate.depthCulling = !(material.flags & 0x8);; + pipelineTemplate.backFaceCulling = !(material.flags & 0x4);; + pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode]; + + //Let's assume ribbons are always at least transparent + if (pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque) { + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; + } + + M2RibbonMaterialTemplate m2RibbonMaterialTemplate; + HBlpTexture tex0 = m2Object->getBlpTextureData(textureIndices[i]); + m2RibbonMaterialTemplate.textures[0] = m_api->hDevice->createBlpTexture(tex0, true, true); + + auto ribbonMaterial = sceneRenderer->createM2RibbonMaterial(m2ModelData, pipelineTemplate, + m2RibbonMaterialTemplate); + + //Create mesh + auto blendMode = pipelineTemplate.blendMode; + auto textureTransformLookupIndex = (this->textureTransformLookup >= 0) ? this->textureTransformLookup + i : -1; + { + std::shared_ptr> meshRibbonWideBlockPS = ribbonMaterial->m_fragmentData; + Ribbon::meshRibbonWideBlockPS &blockPS = meshRibbonWideBlockPS->getObject(); + blockPS.uPixelShader = 0; + blockPS.uBlendMode = static_cast(blendMode); + + int32_t transformIndex = -1; + if (textureTransformLookupIndex >= 0) { + transformIndex = m2Object->getTextureTransformIndexByLookup(textureTransformLookupIndex); + } + blockPS.uTextureTransformIndex = transformIndex; + meshRibbonWideBlockPS->save(); + } + m_ribbonMaterials[i] = ribbonMaterial; + } +} + +void CRibbonEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer, RibbonFrame &ribbonFrame) { + auto device = m_api->hDevice; + + //Create Buffers + ribbonFrame.m_bufferVBO = sceneRenderer->createM2RibbonVertexBuffer(m_gxVertices.size() * sizeof(CRibbonVertex)); + ribbonFrame.m_indexVBO = sceneRenderer->createM2IndexBuffer(m_gxIndices.size() * sizeof(uint16_t)); + ribbonFrame.m_bindings = sceneRenderer->createM2RibbonVAO(ribbonFrame.m_bufferVBO, ribbonFrame.m_indexVBO); + + ribbonFrame.m_meshes = {}; + for (int i = 0; i < m_ribbonMaterials.size(); i++) { + + //Create mesh + gMeshTemplate meshTemplate(ribbonFrame.m_bindings); + + meshTemplate.start = 0; + meshTemplate.end = 0; + + ribbonFrame.m_meshes.push_back(sceneRenderer->createSortableMesh(meshTemplate, m_ribbonMaterials[i], 0)); + } } //----- (00A199E0) -------------------------------------------------------- @@ -219,13 +198,13 @@ void CRibbonEmitter::SetAbove(float above) this->m_above = above; } + //----- (00A19B80) -------------------------------------------------------- void CRibbonEmitter::SetAlpha(float a2) { this->m_diffuseClr.a = fmaxf(255.0f * a2, 0.0f); } - //----- (00A19C50) -------------------------------------------------------- void CRibbonEmitter::InitInterpDeltas() { @@ -415,7 +394,6 @@ void CRibbonEmitter::ChangeFrameOfReference(const mathfu::mat4 *frameOfReference while ( this->m_gxVertices.size() > v16 ); } } - //----- (00A1A4E0) -------------------------------------------------------- void CRibbonEmitter::SetColor(float a3, float a4, float a5) { @@ -424,13 +402,14 @@ void CRibbonEmitter::SetColor(float a3, float a4, float a5) this->m_diffuseClr.b = a3 * 255.0f; } + // FCBEB0: using guessed type int dword_FCBEB0; //----- (00A1A820) -------------------------------------------------------- void CRibbonEmitter::SetTexSlot(unsigned int texSlot) { assert(texSlot < m_rows * m_cols); - + if ( this->m_texSlot != texSlot ) { this->m_texSlot = texSlot; @@ -440,7 +419,7 @@ void CRibbonEmitter::SetTexSlot(unsigned int texSlot) texSlotModf = (float) (((texSlotMod) & 1) | (texSlotMod >> 1)) + (float) ((texSlotMod & 1) | (texSlotMod >> 1)); } - + float minx = (texSlotModf * this->m_tmpDU) + this->m_texBox.minx; this->m_texSlotBox.minx = minx; @@ -457,7 +436,7 @@ void CRibbonEmitter::SetTexSlot(unsigned int texSlot) this->m_texSlotBox.maxx = minx + this->m_tmpDU; this->m_texSlotBox.maxy = miny + this->m_tmpDV; } - + } //----- (00A1A960) -------------------------------------------------------- @@ -508,7 +487,6 @@ void CRibbonEmitter::Advance(int &pos, unsigned int amount) { if (v4 >= v5) pos = v4 - v5; } - //----- (00A1AD60) -------------------------------------------------------- void CRibbonEmitter::Update(float deltaTime, int suppressNewEdges) { @@ -780,6 +758,7 @@ void CRibbonEmitter::Update(float deltaTime, int suppressNewEdges) this->m_ribbonEmitterflags.m_singletonUpdated = 1; } + // 10131A0: using guessed type __int128 xmmword_10131A0; //----- (00A1C1A0) -------------------------------------------------------- @@ -861,40 +840,55 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV } void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { + auto &currFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + if (currFrame.isDead) return; + + for (int i = 0; i < currFrame.m_meshes.size(); i++) { + auto mesh = currFrame.m_meshes[i]; + if (mesh->getIsTransparent()) { + transparentMeshes.push_back(mesh); + } else { + opaqueMeshes.push_back(mesh); + } + } +} -// auto &currFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; -// if (currFrame.isDead) return; -// -// for (int i = 0; i < currFrame.m_meshes.size(); i++) { -// auto mesh = currFrame.m_meshes[i]; -// -// mesh->setRenderOrder(renderOrder); -// if (mesh->getIsTransparent()) { -// transparentMeshes.push_back(mesh); -// } else { -// opaqueMeshes.push_back(mesh); -// } -// } +void CRibbonEmitter::fitBuffersToSize() { + if (this->IsDead()) { + return; + } + + size_t sizeInd = m_gxIndices.size() * sizeof(uint16_t); + size_t sizeVert = m_gxVertices.size() * sizeof(CRibbonVertex); + + int frameNum = m_api->hDevice->getDrawFrameNumber(); + auto vboBufferDynamic = frame[frameNum].m_bufferVBO; + auto iboBufferDynamic = frame[frameNum].m_indexVBO; + + if (!iboBufferDynamic || + !vboBufferDynamic || + sizeInd > iboBufferDynamic->getSize() || + sizeVert > vboBufferDynamic->getSize() + ) { + createMesh(m_sceneRenderer, frame[frameNum]); + } } void CRibbonEmitter::updateBuffers() { -// return; -// -// auto ¤tFrame = frame[m_api->hDevice->getUpdateFrameNumber()]; -// currentFrame.isDead = this->IsDead(); -// if (currentFrame.isDead) return; -// -// currentFrame.m_indexVBO->uploadData((void *) m_gxIndices.data(), (int) (m_gxIndices.size() * sizeof(uint16_t))); -// currentFrame.m_bufferVBO->uploadData((void *) m_gxVertices.data(), (int) (m_gxVertices.size() * sizeof(CRibbonVertex))); -// -// int indexCount = m_writePos > m_readPos ? -// 2 *(m_writePos - m_readPos) + 2: -// 2 *((int)m_edges.size() + m_writePos - m_readPos) + 2; -// for (auto mesh : currentFrame.m_meshes) { -// mesh->setStart(2 * m_readPos * sizeof(uint16_t)); -// mesh->setEnd(indexCount); -// mesh->setSortDistance(0); -// mesh->setPriorityPlane(this->m_priority); -// } + auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + currentFrame.isDead = this->IsDead(); + if (currentFrame.isDead) return; + + currentFrame.m_indexVBO->uploadData((void *) m_gxIndices.data(), (int) (m_gxIndices.size() * sizeof(uint16_t))); + currentFrame.m_bufferVBO->uploadData((void *) m_gxVertices.data(), (int) (m_gxVertices.size() * sizeof(CRibbonVertex))); + + int indexCount = m_writePos > m_readPos ? + 2 *(m_writePos - m_readPos) + 2: + 2 *((int)m_edges.size() + m_writePos - m_readPos) + 2; + for (auto mesh : currentFrame.m_meshes) { + mesh->setStart(2 * m_readPos * sizeof(uint16_t)); + mesh->setEnd(indexCount); + mesh->setSortDistance(0); + } -} \ No newline at end of file +} diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index 6c2cbcb7f..c414d96a1 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -74,6 +74,7 @@ class CRibbonEmitter { private: HApiContainer m_api; + HMapSceneBufferCreate m_sceneRenderer; struct RibbonFrame { HGIndexBuffer m_indexVBO; @@ -84,12 +85,19 @@ class CRibbonEmitter { bool isDead = true; }; - std::array frame; + std::array frame; + std::vector> m_ribbonMaterials; - void createMesh(M2Object *object, std::vector &materials, std::vector &textureIndicies); + void createMaterials(const HMapSceneBufferCreate &sceneRenderer, + const std::shared_ptr &m2ModelData, + M2Object *m2Object, std::vector &materials, std::vector &textureIndices); + void createMesh(const HMapSceneBufferCreate &sceneRenderer, RibbonFrame &ribbonFrame); public: - CRibbonEmitter(HApiContainer m_api, M2Object *object, std::vector &materials, std::vector &textureIndicies, int textureTransformLookup); + CRibbonEmitter(const HApiContainer &m_api, + const HMapSceneBufferCreate &sceneRenderer, + const std::shared_ptr &m2ModelData, + M2Object *object, std::vector &materials, std::vector &textureIndicies, int textureTransformLookup); void SetDataEnabled(char a2); void SetUserEnabled(char a2); CRibbonEmitter *SetGravity(float a2); @@ -118,6 +126,9 @@ class CRibbonEmitter { void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); + void fitBuffersToSize(); + + }; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index db3c0ab7f..16d8f0508 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -95,17 +95,18 @@ enum class M2VertexShader : int { inline constexpr const int operator+ (M2PixelShader const val) { return static_cast(val); }; inline constexpr const int operator+ (M2VertexShader const val) { return static_cast(val); }; -const static EGxBlendEnum M2BlendingModeToEGxBlendEnum [8] = - { - EGxBlendEnum::GxBlend_Opaque, - EGxBlendEnum::GxBlend_AlphaKey, - EGxBlendEnum::GxBlend_Alpha, - EGxBlendEnum::GxBlend_NoAlphaAdd, - EGxBlendEnum::GxBlend_Add, - EGxBlendEnum::GxBlend_Mod, - EGxBlendEnum::GxBlend_Mod2x, - EGxBlendEnum::GxBlend_BlendAdd - }; +extern const std::array M2BlendingModeToEGxBlendEnum; +const std::array M2BlendingModeToEGxBlendEnum = +{ + EGxBlendEnum::GxBlend_Opaque, + EGxBlendEnum::GxBlend_AlphaKey, + EGxBlendEnum::GxBlend_Alpha, + EGxBlendEnum::GxBlend_NoAlphaAdd, + EGxBlendEnum::GxBlend_Add, + EGxBlendEnum::GxBlend_Mod, + EGxBlendEnum::GxBlend_Mod2x, + EGxBlendEnum::GxBlend_BlendAdd +}; struct M2Shaders{ unsigned int pixel; @@ -897,12 +898,11 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ //3. Do post load procedures m_skinGeom->fixData(m_m2Geom->getM2Data()); + m_boneMasterData = std::make_shared(m_m2Geom, m_skelGeom, m_parentSkelGeom); this->createVertexBindings(sceneRenderer); this->createMeshes(sceneRenderer); - m_boneMasterData = std::make_shared(m_m2Geom, m_skelGeom, m_parentSkelGeom); - this->initAnimationManager(); this->initBoneAnimMatrices(); this->initTextAnimMatrices(); @@ -910,7 +910,7 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ this->initTransparencies(); this->initLights(); this->initParticleEmitters(sceneRenderer); - this->initRibbonEmitters(); + this->initRibbonEmitters(sceneRenderer); this->m_loaded = true; @@ -1014,13 +1014,16 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v } } -void M2Object::fitParticleBuffersToSize() { +void M2Object::fitParticleAndRibbonBuffersToSize() { int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); for (int i = minParticle; i < maxParticle; i++) { particleEmitters[i]->fitBuffersToSize(); } + for (int i = 0; i < ribbonEmitters.size(); i++) { + ribbonEmitters[i]->fitBuffersToSize(); + } } void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { @@ -1721,7 +1724,7 @@ void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) } } -void M2Object::initRibbonEmitters() { +void M2Object::initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer) { ribbonEmitters = std::vector(); // ribbonEmitters.reserve(m_m2Geom->getM2Data()->ribbon_emitters.size); auto m2Data = m_m2Geom->getM2Data(); @@ -1740,7 +1743,8 @@ void M2Object::initRibbonEmitters() { int textureTransformLookup = (m2Data->global_flags.flag_unk_0x20000 != 0) ? m2Ribbon->textureTransformLookupIndex : -1; - auto emitter = new CRibbonEmitter(m_api, this, materials, textureIndicies, textureTransformLookup); + auto emitter = new CRibbonEmitter(m_api, sceneRenderer, m_modelWideDataBuff, + this, materials, textureIndicies, textureTransformLookup); ribbonEmitters.push_back(emitter); CImVector color; @@ -1863,7 +1867,16 @@ mathfu::mat4 M2Object::getTextureTransformByLookup(int textureTrasformlookup) { return mathfu::mat4::Identity(); } +int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { + if (textureTrasformlookup < this->m_m2Geom->getM2Data()->texture_transforms_lookup_table.size) { + auto textureTransformIndex = *this->m_m2Geom->getM2Data()->texture_transforms_lookup_table.getElement(textureTrasformlookup); + if (textureTransformIndex >= 0 && textureTransformIndex < this->textAnimMatrices.size()) { + return textureTransformIndex; + } + } + return -1; +} void M2Object::drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { // return; @@ -1951,7 +1964,7 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) //3. Create model wide uniform buffer m_modelWideDataBuff = sceneRenderer->createM2ModelMat( - m_m2Geom->m_m2Data->bones.size, + m_boneMasterData->getSkelData()->m_m2CompBones->size, m_m2Geom->m_m2Data->colors.size, m_m2Geom->m_m2Data->texture_weights.size, m_m2Geom->m_m2Data->texture_transforms.size diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index a23ed8a59..7b8e436eb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -160,7 +160,7 @@ class M2Object { void initTransparencies(); void initLights(); void initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer); - void initRibbonEmitters(); + void initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer); void sortMaterials(mathfu::Matrix &modelViewMat); bool checkifBonesAreInRange(M2SkinProfile *skinProfile, M2SkinSection *mesh); @@ -239,6 +239,7 @@ class M2Object { void getAvailableAnimation(std::vector &allAnimationList); void getMeshIds(std::vector &meshIdList); mathfu::mat4 getTextureTransformByLookup(int textureTrasformlookup); + int32_t getTextureTransformIndexByLookup(int textureTrasformlookup); bool getGetIsLoaded() { return m_loaded; }; mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; @@ -265,7 +266,7 @@ class M2Object { void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); - void fitParticleBuffersToSize(); + void fitParticleAndRibbonBuffersToSize(); void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); void drawDebugLight(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 32bc31b56..337634110 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1572,7 +1572,7 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { //Can't be paralleled? for (auto &m2Object: renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { - m2Object->fitParticleBuffersToSize(); + m2Object->fitParticleAndRibbonBuffersToSize(); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index d7e9f51cf..6d076d97c 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -466,183 +466,6 @@ void WmoObject::drawDebugLights(){ */ } - -void WmoObject::drawTransformedPortalPoints(){ - -#ifndef CULLED_NO_PORTAL_DRAWING - /* - if (!m_loaded) return; - - std::vector indiciesArray; - std::vector verticles; - int k = 0; - //int l = 0; - std::vector stripOffsets; - stripOffsets.push_back(0); - int verticleOffset = 0; - int stripOffset = 0; - for (int i = 0; i < this->interiorPortals.size(); i++) { - //if (portalInfo.index_count != 4) throw new Error("portalInfo.index_count != 4"); - - int verticlesCount = this->interiorPortals[i].portalVertices.size(); - if ((verticlesCount - 2) <= 0) { - stripOffsets.push_back(stripOffsets[i]); - continue; - }; - - for (int j =0; j < (((int)verticlesCount)-2); j++) { - indiciesArray.push_back(verticleOffset+0); - indiciesArray.push_back(verticleOffset+j+1); - indiciesArray.push_back(verticleOffset+j+2); - } - stripOffset += ((verticlesCount-2) * 3); - - for (int j =0; j < verticlesCount; j++) { - verticles.push_back(this->interiorPortals[i].portalVertices[j].x); - verticles.push_back(this->interiorPortals[i].portalVertices[j].y); - verticles.push_back(this->interiorPortals[i].portalVertices[j].z); - } - - verticleOffset += verticlesCount; - stripOffsets.push_back(stripOffset); - } - GLuint indexVBO; - GLuint bufferVBO; - glGenBuffers(1, &indexVBO); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, indexVBO); - if (indiciesArray.size() > 0) { - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indiciesArray.size() * 2, &indiciesArray[0], GL_STATIC_DRAW); - } - glGenBuffers(1, &bufferVBO); - glBindBuffer( GL_ARRAY_BUFFER, bufferVBO); - if (verticles.size() > 0) { - glBufferData(GL_ARRAY_BUFFER, verticles.size() * 4, &verticles[0], GL_STATIC_DRAW); - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // default blend func - - glVertexAttribPointer(+drawPortalShader::Attribute::aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0); // position - - auto drawPortalShader = m_api->getPortalShader(); - static float colorArr[4] = {0.058, 0.058, 0.819607843, 0.3}; - glUniformMatrix4fv(drawPortalShader->getUnf("uPlacementMat"), 1, GL_FALSE, &this->m_placementMatrix[0]); - glUniform4fv(drawPortalShader->getUnf("uColor"), 1, &colorArr[0]); - - glDisable(GL_CULL_FACE); - glDepthMask(GL_FALSE); - - int offset = 0; - for (int i = 0; i < this->interiorPortals.size(); i++) { - int indeciesLen = stripOffsets[i+1] - stripOffsets[i]; - - glDrawElements(GL_TRIANGLES, indeciesLen, GL_UNSIGNED_SHORT, (void *)(offset * 2)); - - offset += indeciesLen; - } - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_ZERO); - glBindBuffer( GL_ARRAY_BUFFER, GL_ZERO); - - glDeleteBuffers(1, &indexVBO); - glDeleteBuffers(1, &bufferVBO); - */ -#endif -} - -void WmoObject::createTransformedAntiPortalMesh() { - -} - -void WmoObject::updateTransformedAntiPortalPoints(){ -#ifndef CULLED_NO_PORTAL_DRAWING - if (!m_loaded) return; - - std::vector indiciesArray; - std::vector verticles; - int k = 0; - //int l = 0; - std::vector stripOffsets; - stripOffsets.push_back(0); - int verticleOffset = 0; - int stripOffset = 0; - - // - -// for (int i = 0; i < this->antiPortals.size(); i++) { -// //if (portalInfo.index_count != 4) throw new Error("portalInfo.index_count != 4"); -// -// int verticlesCount = this->antiPortals[i].portalVertices.size(); -//// if ((verticlesCount - 2) <= 0) { -//// stripOffsets.push_back(stripOffsets[i]); -//// continue; -//// }; -//// -//// for (int j =0; j < (((int)verticlesCount)-2); j++) { -//// indiciesArray.push_back(verticleOffset+0); -//// indiciesArray.push_back(verticleOffset+j+1); -//// indiciesArray.push_back(verticleOffset+j+2); -//// } -//// stripOffset += ((verticlesCount-2) * 3); -// -// for (int j =0; j < verticlesCount; j++) { -// verticles.push_back(this->antiPortals[i].portalVertices[j].x); -// verticles.push_back(this->antiPortals[i].portalVertices[j].y); -// verticles.push_back(this->antiPortals[i].portalVertices[j].z); -// } -// -// verticleOffset += verticlesCount; -// stripOffsets.push_back(stripOffset); -// } -// GLuint indexVBO; -// GLuint bufferVBO; -//// glGenBuffers(1, &indexVBO); -//// glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, indexVBO); -//// if (indiciesArray.size() > 0) { -//// glBufferData(GL_ELEMENT_ARRAY_BUFFER, indiciesArray.size() * 2, &indiciesArray[0], GL_STATIC_DRAW); -//// } -// glGenBuffers(1, &bufferVBO); -// glBindBuffer( GL_ARRAY_BUFFER, bufferVBO); -// if (verticles.size() > 0) { -// glBufferData(GL_ARRAY_BUFFER, verticles.size() * 4, &verticles[0], GL_STATIC_DRAW); -// } -// -// glDisable(GL_BLEND); -// -// glVertexAttribPointer(+drawPortalShader::Attribute::aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0); // position -// -// auto drawPortalShader = m_api->getPortalShader(); -// static float colorArr[4] = {0.819607843, 0.058, 0.058, 0.3}; -// glUniformMatrix4fv(drawPortalShader->getUnf("uPlacementMat"), 1, GL_FALSE, &this->m_placementMatrix[0]); -// glUniform4fv(drawPortalShader->getUnf("uColor"), 1, &colorArr[0]); -// -// glDisable(GL_CULL_FACE); -// glDepthMask(GL_FALSE); -// -// int offset = 0; -// for (int i = 0; i < this->antiPortals.size(); i++) { -//// int indeciesLen = stripOffsets[i+1] - stripOffsets[i]; -// -//// glDrawElements(GL_TRIANGLES, indeciesLen, GL_UNSIGNED_SHORT, (void *)(offset * 2)); -// glDrawArrays(GL_TRIANGLES, 0, verticles.size()*4); -// -//// offset += indeciesLen; -// } -// glDepthMask(GL_TRUE); -// glDisable(GL_BLEND); -// -// glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_ZERO); -// glBindBuffer( GL_ARRAY_BUFFER, GL_ZERO); -// -// glDeleteBuffers(1, &indexVBO); -// glDeleteBuffers(1, &bufferVBO); - -#endif - -} - void WmoObject::setLoadingParam(SMMapObjDef &mapObjDef) { createPlacementMatrix(mapObjDef); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 82a3aeb07..b8c066311 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -180,14 +180,9 @@ class WmoObject : public IWmoApi { bool isGroupWmoExteriorLit(int groupId); bool isGroupWmoExtSkybox(int groupId); - void drawTransformedPortalPoints(); - void drawDebugLights(); void createWorldPortals(); - - void createTransformedAntiPortalMesh(); - void updateTransformedAntiPortalPoints(); }; struct WMOObjectHasher diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 505649e7c..a57273d0c 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1550,12 +1550,12 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,48}, {0,0,368}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2071,6 +2071,11 @@ const std::unordered_map createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) = 0; + + virtual std::shared_ptr createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) = 0; + virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; virtual std::shared_ptr> createWMOWideChunk() = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 899765691..bbb8678e3 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -27,7 +27,7 @@ static const std::vector staticWMOBindings = {{ {+wmoShader::Attribute::aColorSecond, 4, GBindingType::GUNSIGNED_BYTE, true,sizeof(WMOVertex), offsetof(WMOVertex, colorSecond)} }}; static const std::vector staticWmoGroupAmbient = {{ - {+wmoShader::Attribute::wmoAmbient, 4, GBindingType::GFLOAT, false, sizeof(mathfu::vec4_packed), 0}, + {+wmoShader::Attribute::wmoAmbient, 4, GBindingType::GFLOAT, false, sizeof(mathfu::vec4_packed), 0}, }}; static const std::vector staticWaterBindings = {{ @@ -51,27 +51,34 @@ static const std::vector skyConusBinding = {{ }}; static const std::vector fullScreenQuad = {{ - {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, + {+drawQuad::Attribute::position, 2, GBindingType::GFLOAT, false, 0, 0}, }}; static const std::vector staticM2ParticleBindings = {{ - {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, - {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, - {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, - {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, - {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, + {+m2ParticleShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, position) }, + {+m2ParticleShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, color)}, + {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, + {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, + {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, +}}; + +static std::vector staticM2RibbonBindings = {{ + {+ribbonShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, pos) }, // 0 + {+ribbonShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(CRibbonVertex), offsetof(CRibbonVertex, diffuseColor)}, // 12 + {+ribbonShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(CRibbonVertex), offsetof(CRibbonVertex, texCoord)}, // 16 + //24 }}; static std::vector adtVertexBufferBinding = {{ - {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, - {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, - {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, - {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, + {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, + {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, + {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, + {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, }}; static std::vector adtVertexBufferLODBinding = {{ - {+adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 8, 0 }, - {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} + {+adtLodShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, 8, 0 }, + {+adtLodShader::Attribute::aIndex, 1, GBindingType::GFLOAT, false, 8, 4} }}; static std::vector drawPortalBindings = {{ diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 732045113..df875cf1e 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -26,6 +26,9 @@ struct M2WaterfallMaterialTemplate { struct M2ParticleMaterialTemplate { std::array textures = {nullptr, nullptr, nullptr}; }; +struct M2RibbonMaterialTemplate { + std::array textures = {nullptr}; +}; struct WMOMaterialTemplate { std::shared_ptr> m_modelWide; @@ -83,6 +86,11 @@ class IM2ParticleMaterial : public IMaterial { std::shared_ptr> m_fragmentData = nullptr; }; +class IM2RibbonMaterial : public IMaterial { +public: + std::shared_ptr> m_fragmentData = nullptr; +}; + class ISkyMeshMaterial : public IMaterial { public: std::shared_ptr> m_skyColors = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index f871ee2e1..8d8efbd07 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -22,6 +22,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C vboM2Buffer = m_device->createVertexBuffer(1024*1024); vboPortalBuffer = m_device->createVertexBuffer(1024*1024); vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer(1024*1024); vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); vboWMOBuffer = m_device->createVertexBuffer(1024*1024); vboWaterBuffer = m_device->createVertexBuffer(1024*1024); @@ -59,6 +60,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); + m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); @@ -127,6 +129,15 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createM2ParticleVAO(HGVertexBuf return m2ParticleVAO; } +HGVertexBufferBindings MapSceneRenderForwardVLK::createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2RibbonVAO = m_device->createVertexBufferBindings(); + m2RibbonVAO->addVertexBufferBinding(vertexBuffer, staticM2RibbonBindings); + m2RibbonVAO->setIndexBuffer(indexBuffer); + + return m2RibbonVAO; +}; + HGVertexBufferBindings MapSceneRenderForwardVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto waterVAO = m_device->createVertexBufferBindings(); @@ -168,6 +179,9 @@ HGVertexBuffer MapSceneRenderForwardVLK::createM2VertexBuffer(int sizeInBytes) { HGVertexBuffer MapSceneRenderForwardVLK::createM2ParticleVertexBuffer(int sizeInBytes) { return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); } +HGVertexBuffer MapSceneRenderForwardVLK::createM2RibbonVertexBuffer(int sizeInBytes) { + return vboM2RibbonBuffer->getSubBuffer(sizeInBytes); +} HGIndexBuffer MapSceneRenderForwardVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); @@ -346,6 +360,30 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM return material; } +std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) + .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) + .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(4, l_fragmentData->getSubBuffer()); + }) + .createDescriptorSet(1, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, m2RibbonMaterialTemplate.textures[0]); + }) + .toMaterial([l_fragmentData](IM2RibbonMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +}; + std::shared_ptr> MapSceneRenderForwardVLK::createWMOWideChunk() { return std::make_shared>(uboBuffer); } @@ -601,6 +639,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->vboM2Buffer); uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 493d56300..44340e3e0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -28,6 +28,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; @@ -39,6 +40,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; + HGVertexBuffer createM2RibbonVertexBuffer(int sizeInBytes) override; HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; @@ -68,6 +70,10 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) override; + std::shared_ptr> createWMOWideChunk() override; std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, @@ -99,6 +105,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; + HGBufferVLK vboM2RibbonBuffer; HGBufferVLK vboPortalBuffer; HGBufferVLK vboAdtBuffer; @@ -128,6 +135,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptyADTVAO = nullptr; HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; + HGVertexBufferBindings m_emptyM2RibbonVAO = nullptr; HGVertexBufferBindings m_emptyPortalVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; From 8916851cac1fc1d60c616be97226ca2a2fc6a198 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 19 Jul 2023 00:53:45 +0300 Subject: [PATCH 092/212] - Implement loading of encryption keys - Fix the mesh sorting - Add additional checks when loading m2 --- CMakeLists.txt | 2 +- .../dataExporter/DataExporterClass.h | 21 +++- src/persistance/CascRequestProcessor.cpp | 6 ++ src/persistance/CascRequestProcessor.h | 4 + src/ui/FrontendUI.cpp | 10 ++ src/ui/FrontendUI.h | 2 + .../DatabaseUpdateWorkflow.h | 2 +- .../keysUpdateWorkflow/KeysUpdateWorkflow.cpp | 97 +++++++++++++++++++ .../keysUpdateWorkflow/KeysUpdateWorkflow.h | 35 +++++++ .../shaders/glsl/common/commonM2Material.glsl | 4 + .../glsl/forwardRendering/m2Shader.vert | 3 - .../glsl/forwardRendering/ribbonShader.frag | 27 +++--- .../forwardRendering/waterfallShader.vert | 5 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 21 ++-- wowViewerLib/src/engine/geometry/skinGeom.cpp | 6 ++ .../src/engine/objects/wmo/wmoObject.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 24 +++-- wowViewerLib/src/gapi/interface/sortLambda.h | 3 + .../src/renderer/frame/FrameProfile.h | 3 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 25 +++-- 20 files changed, 250 insertions(+), 52 deletions(-) create mode 100644 src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp create mode 100644 src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4568dcda7..31842fb45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,7 +237,7 @@ set(SOURCE_FILES src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h src/ui/imguiLib/wheelCapture/wheelCapture.cpp - src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h) + src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h) set(SOURCE_FILES_VULKAN diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index c4a70882f..c62a776e5 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -121,7 +121,26 @@ namespace DataExporter { make_column("textureTransformComboIndex", &DBM2Batch::textureTransformComboIndex), foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) - ) + ), + make_table("M2Ribbon", + make_column("m2Id", &DBM2Batch::m2Id), + make_column("ribbonIndex", &DBM2Batch::batchIndex), + make_column("_flags", &DBM2Batch::flags), + make_column("priorityPlane", &DBM2Batch::priorityPlane), + make_column("shader_id", &DBM2Batch::shader_id), + make_column("skinSectionIndex", &DBM2Batch::skinSectionIndex), + make_column("geosetIndex", &DBM2Batch::geosetIndex), + make_column("colorIndex", &DBM2Batch::colorIndex), + make_column("materialIndex", &DBM2Batch::materialIndex), + make_column("materialLayer", &DBM2Batch::materialLayer), + make_column("textureCount", &DBM2Batch::textureCount), + make_column("textureComboIndex", &DBM2Batch::textureComboIndex), + make_column("textureCoordComboIndex", &DBM2Batch::textureCoordComboIndex), + make_column("textureWeightComboIndex", &DBM2Batch::textureWeightComboIndex), + make_column("textureTransformComboIndex", &DBM2Batch::textureTransformComboIndex), + foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), + unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) + ) ); }; diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 4abd93dc2..09951541d 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -61,6 +61,7 @@ CascRequestProcessor::CascRequestProcessor(std::string &path, BuildDefinition &b openResult = CascOpenStorage(path.c_str(), localMask, &this->m_storage); if (openResult) { std::cout << "Opened local Casc Storage at "<< path << std::endl; + updateKeys(); } else { std::cout << "Could not open local Casc Storage at "<< path << std::endl; } @@ -207,3 +208,8 @@ CascRequestProcessor::~CascRequestProcessor() { if (m_storageOnline != nullptr) CascCloseStorage(m_storageOnline); } + +void CascRequestProcessor::updateKeys() { + if (m_storage != nullptr) + CascImportKeysFromFile(m_storage, CASC_KEYS_FILE.c_str()); +} diff --git a/src/persistance/CascRequestProcessor.h b/src/persistance/CascRequestProcessor.h index 20a0e36df..88475496a 100644 --- a/src/persistance/CascRequestProcessor.h +++ b/src/persistance/CascRequestProcessor.h @@ -10,10 +10,14 @@ #include "fileBrowser/buildDefinition.h" +const std::string CASC_KEYS_FILE = "KnownCascKeys.txt"; + class CascRequestProcessor : public RequestProcessor { public: CascRequestProcessor(std::string &path, BuildDefinition &buildDef); ~CascRequestProcessor() override; + + void updateKeys(); private: std::string m_cascDir = ""; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 6c400a123..ccf433e1d 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -35,6 +35,7 @@ #include "renderer/uiScene/FrontendUIRendererFactory.h" #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h" #include "wheelCapture/wheelCapture.h" +#include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { m_api = api; @@ -119,6 +120,10 @@ void FrontendUI::composeUI() { m_databaseUpdateWorkflow->render(); } } + if (m_keyUpdateWorkFlow != nullptr) { + if (!m_keyUpdateWorkFlow->render()) + m_keyUpdateWorkFlow = nullptr; + } showSettingsDialog(); showQuickLinksDialog(); @@ -689,6 +694,11 @@ void FrontendUI::showMainMenu() { contains(fileDialog.getProductBuild().productName, "classic") ); } + if (ImGui::MenuItem("Update keys", "", false)) { + m_keyUpdateWorkFlow = std::make_shared( + std::dynamic_pointer_cast(m_processor) + ); + } ImGui::EndMenu(); } if (ImGui::BeginMenu("View")) { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index fc9f5a5ed..50acf50cb 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -26,6 +26,7 @@ #include "renderer/uiScene/FrontendUIRenderer.h" #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" #include "childWindow/BLPViewer.h" +#include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -201,6 +202,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_dataExporter = nullptr; std::shared_ptr m_databaseUpdateWorkflow = nullptr; + std::shared_ptr m_keyUpdateWorkFlow = nullptr; public: void overrideCascOpened(bool value) { diff --git a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h index a0dc4ed54..39093a551 100644 --- a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h +++ b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.h @@ -35,8 +35,8 @@ class DatabaseUpdateWorkflow { int m_currentDBDFile = 0; std::shared_ptr httpDownloadThread = nullptr; - bool m_httpDownloadThreadFinished = true; + bool m_httpDownloadThreadFinished = true; std::string m_failedToDownloadFile = ""; diff --git a/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp b/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp new file mode 100644 index 000000000..7d42ee7b7 --- /dev/null +++ b/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp @@ -0,0 +1,97 @@ +// +// Created by Deamon on 7/18/2023. +// + +#include "KeysUpdateWorkflow.h" +#include "imgui.h" +#include "imgui_internal.h" +#include "../../../../3rdparty/filesystem_impl/include/ghc/filesystem.hpp" +#include "../../../persistance/httpFile/httpFile.h" +#include "../../../persistance/CascRequestProcessor.h" + +static const std::string POPUP_DOWNLOADING_KEYS = "Downloading key from git"; +static const std::string POPUP_DOWNLOADING_FAILED = "Updating keys failed"; +static const std::string POPUP_DOWNLOADING_SUCCESS = "Updating keys success"; + +KeysUpdateWorkflow::KeysUpdateWorkflow(const std::shared_ptr &cascRequestProcessor) : m_cascRequestProcessor(cascRequestProcessor) { + +} + +bool KeysUpdateWorkflow::render() { + if (m_showDownloading) { + ImGui::OpenPopup(POPUP_DOWNLOADING_KEYS.c_str()); + } else if(m_showDownloadingSuccess) { + ImGui::OpenPopup(POPUP_DOWNLOADING_SUCCESS.c_str()); + } else if (m_showDownloadingFailed) { + ImGui::OpenPopup(POPUP_DOWNLOADING_FAILED.c_str()); + } + + return defineDialogs(); +} + +bool KeysUpdateWorkflow::defineDialogs() { + bool return_value = true; + if (ImGui::BeginPopupModal(POPUP_DOWNLOADING_KEYS.c_str())) + { + keyThreadDownloadLogic(); + if (m_failedToDownloadFile) { + m_showDownloading = false; + m_showDownloadingFailed = true; + } else if (m_httpDownloadThreadFinished && !m_failedToDownloadFile) { + m_showDownloading = false; + m_showDownloadingSuccess = true; + if (m_cascRequestProcessor) + m_cascRequestProcessor->updateKeys(); + } + + ImGui::Text("Downloading keys from git"); + ImGui::EndPopup(); + } + + if (ImGui::BeginPopupModal(POPUP_DOWNLOADING_SUCCESS.c_str())) { + ImGui::Text("Keys were updated succesfully"); + if (ImGui::Button("Ok", ImVec2(-1, 23))) { + return_value = false; + } + ImGui::EndPopup(); + } + + if (ImGui::BeginPopupModal(POPUP_DOWNLOADING_FAILED.c_str())) { + ImGui::Text("Failed to download keys"); + if (ImGui::Button("Ok", ImVec2(-1, 23))) { + return_value = false; + } + ImGui::EndPopup(); + } + + return return_value; +} + +void KeysUpdateWorkflow::keyThreadDownloadLogic() { + if (httpDownloadThread == nullptr) { + auto &l_httpDownloadThreadFinished = m_httpDownloadThreadFinished; + auto &l_failedToDownloadFile = m_failedToDownloadFile; + httpDownloadThread = std::make_shared([&l_httpDownloadThreadFinished, &l_failedToDownloadFile]() -> void { + std::string fileToDownload = "https://raw.githubusercontent.com/wowdev/TACTKeys/master/WoW.txt"; + HttpFile httpFile = HttpFile(fileToDownload); + httpFile.setCallback([](HFileContent fileContent) -> void { + std::string outputFileName = CASC_KEYS_FILE; + + std::ofstream FILE(outputFileName, std::ios::out | std::ios::binary); + std::copy(fileContent->begin(), fileContent->end(), std::ostreambuf_iterator(FILE)); + FILE.flush(); + FILE.close(); + }); + + httpFile.setFailCallback([fileToDownload, &l_failedToDownloadFile](HFileContent fileContent) -> void { + l_failedToDownloadFile = true; + }); + httpFile.startDownloading(); + l_httpDownloadThreadFinished = true; + }); + } + if (m_httpDownloadThreadFinished || m_failedToDownloadFile) { + httpDownloadThread->detach(); + httpDownloadThread = nullptr; + } +} diff --git a/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h b/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h new file mode 100644 index 000000000..313252a9a --- /dev/null +++ b/src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h @@ -0,0 +1,35 @@ +// +// Created by Deamon on 7/18/2023. +// + +#ifndef AWEBWOWVIEWERCPP_KEYSUPDATEWORKFLOW_H +#define AWEBWOWVIEWERCPP_KEYSUPDATEWORKFLOW_H + +#include +#include +#include "../../../../wowViewerLib/src/engine/WowFilesCacheStorage.h" +#include "../../../persistance/CascRequestProcessor.h" + +class KeysUpdateWorkflow { +public: + KeysUpdateWorkflow(const std::shared_ptr &cascRequestProcessor); + bool render(); +private: + std::shared_ptr m_cascRequestProcessor; + + bool m_showDownloading = true; + bool m_showDownloadingSuccess = false; + bool m_showDownloadingFailed = false; + + + std::shared_ptr httpDownloadThread = nullptr; + bool m_httpDownloadThreadFinished = true; + bool m_failedToDownloadFile = false; + + bool defineDialogs(); + + void keyThreadDownloadLogic(); +}; + + +#endif //AWEBWOWVIEWERCPP_KEYSUPDATEWORKFLOW_H diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index 8549e14f5..d32ef3b9c 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -1,5 +1,9 @@ #include "commonFunctions.glsl" +#ifndef MAX_MATRIX_NUM +#define MAX_MATRIX_NUM 256 +#endif + void calcM2FragMaterial(const in int uPixelShader, in sampler2D texSampler1, in sampler2D texSampler2, diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index cad7f7c59..04ad45ab5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -2,9 +2,6 @@ #extension GL_GOOGLE_include_directive: require -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 256 -#endif precision highp float; precision highp int; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index 6c522b006..f814b4f13 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -18,9 +18,9 @@ layout(std140, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -//layout(std140, binding=3) uniform textureMatrices { -// mat4 textureMatrix[64]; -//}; +layout(std140, binding=3) uniform textureMatrices { + mat4 textureMatrix[64]; +}; layout(std140, binding=4) uniform meshWideBlockPS { ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; @@ -30,22 +30,21 @@ layout(set=1, binding=5) uniform sampler2D uTexture; layout(location = 0) out vec4 outputColor; void main() { -// vec2 textCoordScale = uAlphaTestScalev.yz; -// vec2 texcoord = (vTexcoord0 * textCoordScale) + uTextureTranslate.xy; + int textureTransformIndex = uPixelShader_BlendMode_TextureTransformIndex.z; + + vec2 texcoord = vTexcoord0; + if (textureTransformIndex >= 0) { + mat4 textMat = textureMatrix[textureTransformIndex]; + vec2 textCoordScale = vec2(length(textMat[0].xyz), length(textMat[2].xyz)); + vec2 textureTranslate = textMat[3].xy; + texcoord = (vTexcoord0 * textCoordScale) + textureTranslate.xy; + } vec4 tex = texture(uTexture, vTexcoord0).rgba; vec4 finalColor = vec4((vColor.rgb*tex.rgb), tex.a * vColor.a); - -// vec3 sunDir = -// mix( -// scene.uInteriorSunDir, -// scene.extLight.uExteriorDirectColorDir, -// interiorExteriorBlend.x -// ) -// .xyz; - vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index c4520d53a..ae7f73be6 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -2,14 +2,11 @@ #extension GL_GOOGLE_include_directive: require -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 -#endif - precision highp float; precision highp int; #include "../common/commonFunctions.glsl" +#include "../common/commonM2Material.glsl" #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 0dd6ac51f..97bee4249 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -216,16 +216,23 @@ chunkDef M2Geom::m2FileTable = { void M2Geom::process(HFileContent m2File, const std::string &fileName) { this->m2File = m2File; + auto &m2FileData = *m2File.get(); + if (m2FileData.empty()) { + std::cout << "M2 file is empty" << std::endl; + fsStatus = FileStatus::FSRejected; + return; + } + + uint32_t ident = *(uint32_t *)m2FileData.data(); + if (ident != '12DM' && ident != '02DM') { + std::cout << "wrong file header for M2 file" << std::endl; + fsStatus = FileStatus::FSRejected; + return; + } m2SizeLoaded.fetch_add(m2File->size()); - auto &m2FileData = *m2File.get(); - if ( - m2FileData[0] == 'M' && - m2FileData[1] == 'D' && - m2FileData[2] == '2' && - m2FileData[3] == '1' - ) { + if (ident == '12DM') { CChunkFileReader reader(*this->m2File.get()); reader.processFile(*this, &M2Geom::m2FileTable); } else { diff --git a/wowViewerLib/src/engine/geometry/skinGeom.cpp b/wowViewerLib/src/engine/geometry/skinGeom.cpp index 23388dfb7..4e52c6313 100644 --- a/wowViewerLib/src/engine/geometry/skinGeom.cpp +++ b/wowViewerLib/src/engine/geometry/skinGeom.cpp @@ -10,6 +10,12 @@ void SkinGeom::process(HFileContent skinFile, const std::string &fileName) { this->m2Skin = skinFile; M2SkinProfile *skinHeader = (M2SkinProfile *) &(*this->m2Skin.get())[0]; + if (skinHeader->magic != 'NIKS') { + std::cout << "wrong file header for SKIN file" << std::endl; + fsStatus = FileStatus::FSRejected; + return; + } + this->m_skinData = skinHeader; //Step 1: Init all m2Arrays diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 6d076d97c..648b23d14 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -104,7 +104,7 @@ std::shared_ptr WmoObject::getDoodad(int index) { m2Object->setDiffuseColor(light.color); - std::cout << "Found index into MOLT = " << (int)doodadDef->color.a << std::endl; +// std::cout << "Found index into MOLT = " << (int)doodadDef->color.a << std::endl; } else { m2Object->setDiffuseColor(doodadDef->color); } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a57273d0c..a2f280a43 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -520,7 +520,7 @@ const std::unordered_map shaderMetaInfo = { { {0,4,16}, {0,3,4096}, - {0,2,14080}, + {0,2,16384}, {0,0,368}, {0,1,64}, }, @@ -1550,12 +1550,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,368}, {0,4,16}, + {0,3,4096}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1614,7 +1615,7 @@ const std::unordered_maplayer() > pA2->layer(); } } + if (pA->getGxBlendMode() != pB->getGxBlendMode()) { + return pB->getGxBlendMode() > pA->getGxBlendMode(); + } } else { if (pA->getSortDistance() < pB->getSortDistance()) { return true; diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h index 67d9ba9fb..25d230fa4 100644 --- a/wowViewerLib/src/renderer/frame/FrameProfile.h +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -7,12 +7,13 @@ #ifdef LINK_TRACY #include "Tracy.hpp" - +//#include "tracy/TracyVulkan.hpp" #define setThreadName(a) tracy::SetThreadName(a); #else #define setThreadName(a) #define ZoneScoped #define ZoneScopedN(a) +#define TracyVkContext(x,y,z,w) #endif diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 8d8efbd07..7b67cc4e0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -365,12 +365,14 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto l_fragmentData = std::make_shared>(uboBuffer); ; + auto &l_m2ModelData = m2ModelData; auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + .createDescriptorSet(0, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) + .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)->getSubBuffer()) .ubo(4, l_fragmentData->getSubBuffer()); }) .createDescriptorSet(1, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { @@ -677,7 +679,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha for (auto const &mesh: *skyOpaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } - for (auto const &mesh: *skyTransparentMeshes) { + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); + // std::string debugMess = // "Drawing mesh " // " meshType = " + std::to_string((int)mesh->getMeshType()) + @@ -694,15 +698,16 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } { ZoneScopedN("submit transparent"); - for (auto const &mesh: *transparentMeshes) { + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); +// +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); // -// std::string debugMess = -// "Drawing mesh " -// " meshType = " + std::to_string((int)mesh->getMeshType()) + -// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + -// " sortDistance = " + std::to_string(mesh->getSortDistance()) + -// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); - // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); From 0a23ed6cd97cce1c5db4e0e77f3a12924825e928 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 22 Jul 2023 21:58:32 +0300 Subject: [PATCH 093/212] - Allow frameBuffers to have no depth attachment - Add more stuff to data exporter --- .../dataExporter/DataExporterClass.cpp | 45 +++++++++- .../dataExporter/DataExporterClass.h | 74 +++++++++++---- src/ui/FrontendUI.cpp | 11 ++- .../renderer/uiScene/FrontendUIRenderer.cpp | 4 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- wowViewerLib/CMakeLists.txt | 1 - .../shaders/glsl/common/commonM2Material.glsl | 4 +- .../src/engine/objects/m2/m2Object.cpp | 88 ++++++++++-------- wowViewerLib/src/gapi/interface/sortLambda.h | 4 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 19 ++-- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 9 +- .../src/gapi/vulkan/GFrameBufferVLK.h | 2 +- .../src/gapi/vulkan/GRenderPassVLK.cpp | 89 ++++++++++++++----- wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h | 16 +++- .../src/gapi/vulkan/buffers/CBufferChunkVLK.h | 8 +- .../buffers/GVertexBufferDynamicVLK.cpp | 83 ----------------- .../vulkan/buffers/GVertexBufferDynamicVLK.h | 41 --------- .../src/gapi/vulkan/buffers/IBufferVLK.h | 2 + .../src/renderer/frame/FrameInputParams.h | 2 - .../vulkan/MapSceneRenderForwardVLK.cpp | 44 ++++----- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 15 ++-- 22 files changed, 300 insertions(+), 265 deletions(-) delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp delete mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h diff --git a/src/exporters/dataExporter/DataExporterClass.cpp b/src/exporters/dataExporter/DataExporterClass.cpp index 5314a61d1..755c5ff46 100644 --- a/src/exporters/dataExporter/DataExporterClass.cpp +++ b/src/exporters/dataExporter/DataExporterClass.cpp @@ -138,6 +138,7 @@ int DataExporter::DataExporterClass::exportDBM2() { DBM2 dbm2; dbm2.fileDataId = currentFileDataId; dbm2.fileName = currentFileName; + dbm2.version = m2Data->version; dbm2.global_flags = *(uint32_t *)&m2Data->global_flags; dbm2.global_loops_count = m2Data->global_loops.size; dbm2.sequences_count = m2Data->sequences.size; @@ -169,7 +170,49 @@ int DataExporter::DataExporterClass::exportDBM2() { dbm2.particle_emitters_count = m2Data->particle_emitters.size; dbm2.blend_map_overrides_count = m2Data->blend_map_overrides.size; - return m_storage.insert(dbm2); + int m2Id = m_storage.insert(dbm2); + + for (int i = 0; i < m2Data->materials.size; i++){ + auto material = m2Data->materials.getElement(i); + + DBM2Material dbm2Material; + dbm2Material.m2Id = m2Id; + dbm2Material.materialIndex = i; + dbm2Material.flags = material->flags; + dbm2Material.blending_mode = material->blending_mode; + m_storage.insert(dbm2Material); + } + + for (int i = 0; i < m2Data->ribbon_emitters.size; i++){ + auto const &ribbonEmitter = m2Data->ribbon_emitters.getElement(i); + + DBM2RibbonData dbm2RibbonData; + dbm2RibbonData.m2Id = m2Id; + dbm2RibbonData.ribbonIndex = i; + dbm2RibbonData.ribbonId = ribbonEmitter->ribbonId; + dbm2RibbonData.boneIndex = ribbonEmitter->boneIndex; + dbm2RibbonData.textureRows = ribbonEmitter->textureRows; + dbm2RibbonData.textureCols = ribbonEmitter->textureCols; + dbm2RibbonData.priorityPlane = ribbonEmitter->priorityPlane; + dbm2RibbonData.ribbonColorIndex = ribbonEmitter->ribbonColorIndex; + dbm2RibbonData.textureTransformLookupIndex = ribbonEmitter->textureTransformLookupIndex; + + m_storage.insert(dbm2RibbonData); + + for (int j = 0; j < ribbonEmitter->materialIndices.size; j++) { + int materialIndex = *ribbonEmitter->materialIndices.getElement(j); + + DBM2RibbonMaterial dbm2RibbonMaterial; + dbm2RibbonMaterial.ribbonIndex = i; + dbm2RibbonMaterial.materialIndex = j; + dbm2RibbonMaterial.m2MaterialIndex = materialIndex; + dbm2RibbonMaterial.m2Id = m2Id; + + m_storage.insert(dbm2RibbonMaterial); + } + } + + return m2Id; } void DataExporter::DataExporterClass::exportDBSkin(int id) { diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index c62a776e5..e67320004 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -27,10 +27,35 @@ namespace DataExporter { M2SkinSection skinSection; }; + struct DBM2Material : M2Material{ + int m2Id = -1; + int materialIndex; + }; + + struct DBM2RibbonData { + int m2Id = -1; + int ribbonIndex; + uint32_t ribbonId; + uint32_t boneIndex; + int textureRows; + int textureCols; + int priorityPlane; + int ribbonColorIndex; + int textureTransformLookupIndex; + }; + + struct DBM2RibbonMaterial { + int m2Id = -1; + int ribbonIndex; + int materialIndex; + int m2MaterialIndex; + }; + struct DBM2 { int m2Id = -1; int fileDataId; std::string fileName; + int version; int global_flags; int global_loops_count; int sequences_count; @@ -70,6 +95,7 @@ namespace DataExporter { make_column("id", &DBM2::m2Id, autoincrement(), primary_key()), make_column("fileDataId", &DBM2::fileDataId), make_column("fileName", &DBM2::fileName), + make_column("version", &DBM2::version), make_column("global_flags", &DBM2::global_flags), make_column("global_loops_count", &DBM2::global_loops_count), make_column("sequences_count", &DBM2::sequences_count), @@ -122,24 +148,36 @@ namespace DataExporter { foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) ), - make_table("M2Ribbon", - make_column("m2Id", &DBM2Batch::m2Id), - make_column("ribbonIndex", &DBM2Batch::batchIndex), - make_column("_flags", &DBM2Batch::flags), - make_column("priorityPlane", &DBM2Batch::priorityPlane), - make_column("shader_id", &DBM2Batch::shader_id), - make_column("skinSectionIndex", &DBM2Batch::skinSectionIndex), - make_column("geosetIndex", &DBM2Batch::geosetIndex), - make_column("colorIndex", &DBM2Batch::colorIndex), - make_column("materialIndex", &DBM2Batch::materialIndex), - make_column("materialLayer", &DBM2Batch::materialLayer), - make_column("textureCount", &DBM2Batch::textureCount), - make_column("textureComboIndex", &DBM2Batch::textureComboIndex), - make_column("textureCoordComboIndex", &DBM2Batch::textureCoordComboIndex), - make_column("textureWeightComboIndex", &DBM2Batch::textureWeightComboIndex), - make_column("textureTransformComboIndex", &DBM2Batch::textureTransformComboIndex), - foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), - unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) + make_table("M2Material", + make_column("m2Id", &DBM2Material::m2Id), + make_column("materialIndex", &DBM2Material::materialIndex), + make_column("flags", &DBM2Material::flags), + make_column("blending_mode", &DBM2Material::blending_mode), + foreign_key(&DBM2Material::m2Id).references(&DBM2::m2Id), + unique(&DBM2Material::m2Id, &DBM2Material::materialIndex) + ), + make_table("M2RibbonData", + make_column("m2Id", &DBM2RibbonData::m2Id), + make_column("ribbonIndex", &DBM2RibbonData::ribbonIndex), + make_column("ribbonId", &DBM2RibbonData::ribbonId), + make_column("boneIndex", &DBM2RibbonData::boneIndex), + make_column("textureRows", &DBM2RibbonData::textureRows), + make_column("textureCols", &DBM2RibbonData::textureCols), + make_column("priorityPlane", &DBM2RibbonData::priorityPlane), + make_column("ribbonColorIndex", &DBM2RibbonData::ribbonColorIndex), + make_column("textureTransformLookupIndex", &DBM2RibbonData::textureTransformLookupIndex), + + foreign_key(&DBM2RibbonData::m2Id).references(&DBM2::m2Id), + unique(&DBM2RibbonData::m2Id, &DBM2RibbonData::ribbonIndex) + ), + make_table("M2RibbonMaterial", + make_column("m2Id", &DBM2RibbonMaterial::m2Id), + make_column("ribbonIndex", &DBM2RibbonMaterial::ribbonIndex), + make_column("materialIndex", &DBM2RibbonMaterial::materialIndex), + make_column("m2MaterialIndex", &DBM2RibbonMaterial::m2MaterialIndex), + + foreign_key(&DBM2RibbonMaterial::m2Id).references(&DBM2::m2Id), + unique(&DBM2RibbonMaterial::m2Id, &DBM2RibbonMaterial::ribbonIndex, &DBM2RibbonMaterial::materialIndex) ) ); }; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index ccf433e1d..44f1d1668 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -880,6 +880,14 @@ void FrontendUI::showQuickLinksDialog() { replacementTextureFDids = std::vector(17); openM2SceneByfdid(5099010, replacementTextureFDids); } + if (ImGui::Button("crystal song bush", ImVec2(-1, 0))) { + replacementTextureFDids = std::vector(17); + openM2SceneByfdid(194418, replacementTextureFDids); + } + if (ImGui::Button("bugged decal", ImVec2(-1, 0))) { + replacementTextureFDids = std::vector(17); + openM2SceneByfdid(946969, replacementTextureFDids); + } if (ImGui::Button("Some model", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 4952373; @@ -1755,8 +1763,6 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto wowSceneFrameInput = std::make_shared>(); wowSceneFrameInput->delta = deltaTime * (1000.0f); wowSceneFrameInput->viewPortDimensions = dimension; - wowSceneFrameInput->invertedZ = true; - wowSceneFrameInput->clearScreen = true; wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, canvWidth, canvHeight, m_api->getConfig()->doubleCameraDebug, @@ -1769,7 +1775,6 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto uiFrameInput = std::make_shared>(); uiFrameInput->delta = deltaTime * (1000.0f); uiFrameInput->viewPortDimensions = dimension; - uiFrameInput->invertedZ = false; uiFrameInput->frameParameters = std::make_shared( ImGui::GetDrawData()); auto clearColor = m_api->getConfig()->clearColor; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 8bd1d4bb6..25c367c88 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -99,6 +99,10 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptr(clip_min.x * uiScale), static_cast((clip_min.y) * uiScale)}; meshTemplate.scissorSize = {static_cast((clip_max.x - clip_min.x)* uiScale), static_cast((clip_max.y - clip_min.y)* uiScale)}; } + if (meshTemplate.scissorOffset[0] < 0) meshTemplate.scissorOffset[0] = 0; + if (meshTemplate.scissorOffset[1] < 0) meshTemplate.scissorOffset[1] = 0; + if (meshTemplate.scissorSize[0] < 0) meshTemplate.scissorSize[0] = 0; + if (meshTemplate.scissorSize[1] < 0) meshTemplate.scissorSize[1] = 0; meshTemplate.start = pcmd->IdxOffset * sizeof(ImDrawIdx); meshTemplate.end = pcmd->ElemCount; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 26dbd47b6..483f72d74 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -60,7 +60,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, l_imguiUbo->getSubBuffer()); + .ubo(1, *l_imguiUbo); }) .createDescriptorSet(1, [&hgtexture](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index b3df3d61d..0c4166a88 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -500,7 +500,6 @@ if (LINK_VULKAN) src/gapi/vulkan/meshes/GMeshVLK.cpp src/gapi/vulkan/textures/GTextureVLK.cpp src/gapi/vulkan/textures/GBlpTextureVLK.cpp - src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp src/gapi/vulkan/GPipelineVLK.cpp src/gapi/vulkan/GPipelineVLK.h src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index d32ef3b9c..dfb1a7532 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -243,7 +243,7 @@ out float finalOpacity, out bool discardThisFragment) canDiscard = true; break; } - case (36): { //unk shader combiner + case (36): { //Combiners_Mod_Mod_Depth matDiffuse = meshColor * tex.rgb * tex2.rgb; discardAlpha = tex.a * tex2.a; canDiscard = true; @@ -258,7 +258,7 @@ out float finalOpacity, out bool discardThisFragment) } else if (blendMode == 1) { finalOpacity = meshOpacity; if (canDiscard && discardAlpha < 0.501960814) - doDiscard = true; + doDiscard = true; } else if (blendMode == 0) { finalOpacity = meshOpacity; } else { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 16d8f0508..b302cec81 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -67,7 +67,7 @@ enum class M2PixelShader : int { Combiners_Mod_Depth = 33, Illum = 34, Combiners_Mod_Mod_Mod_Const = 35, - NewUnkCombiner = 36 + Combiners_Mod_Mod_Depth = 36 }; enum class M2VertexShader : int { @@ -149,42 +149,48 @@ static std::array M2ShaderTable = {{ { +M2PixelShader::Combiners_Opaque, +M2VertexShader::Diffuse_T1, 0, 0 }, { +M2PixelShader::Combiners_Mod_Mod2x, +M2VertexShader::Diffuse_EdgeFade_T1_T2, 1, 1 }, { +M2PixelShader::Combiners_Mod, +M2VertexShader::Diffuse_EdgeFade_T1, 1, 1 }, - { +M2PixelShader::NewUnkCombiner, +M2VertexShader::Diffuse_EdgeFade_T1_T2, 1, 1 }, + { +M2PixelShader::Combiners_Mod_Mod_Depth, +M2VertexShader::Diffuse_EdgeFade_T1_T2, 1, 1 }, }}; int getVertexShaderId(int textureCount, int16_t shaderId) { int result; - if ( shaderId < 0 ) - { - int vertexShaderId = shaderId & 0x7FFF; - if ( (unsigned int)vertexShaderId >= M2ShaderTable.size()) { - std::cout << "Wrong shaderId for vertex shader"; - assert(false); + if ( shaderId >= 0 ) { + if ( textureCount == 1 ) { + if ( (shaderId & 0x80u) == 0 ) { + return (shaderId & 0x4000) != 0 ? 10 : 0; + } else { + result = 1; + } } - result = (unsigned int)M2ShaderTable[(shaderId & 0x7FFF)].vertex; - } - else if ( textureCount == 1 ) - { - if ( (shaderId & 0x80u) != 0 ) + else if ( (shaderId & 0x80u) == 0 ) { - result = 1LL; + if ( (shaderId & 8) != 0 ) + { + return 3; + } + else + { + result = 7; + if ( (shaderId & 0x4000) != 0 ) + return 2; + } + } + else if ( (shaderId & 8) != 0 ) + { + return 5; } else { - result = 10LL; - if ( !(shaderId & 0x4000) ) - result = 0LL; + return 4; } - } - else if ( (shaderId & 0x80u) != 0 ) - { - result = ((shaderId & 8u) >> 3) | 4; - } - else + } else if ( shaderId < 0 ) { - result = 3LL; - if ( !(shaderId & 8) ) - result = 5 * (unsigned int)((shaderId & 0x4000) == 0) + 2; + int vertexShaderId = shaderId & 0x7FFF; + if ( (unsigned int)vertexShaderId >= M2ShaderTable.size()) { + std::cout << "Wrong shaderId for vertex shader"; + assert(false); + } + result = (unsigned int)M2ShaderTable[(shaderId & 0x7FFF)].vertex; } return result; } @@ -227,29 +233,28 @@ int getPixelShaderId(int textureCount, uint16_t shaderId) { } else { - - //For future reference. The arrays are these cases, with inbetween filled with default value -// result = array2[(shaderId) & 7]; -// if ( shaderId & 0x70 ) { -// result = array1[(shaderId) & 7]; -// } - - if ( shaderId & 0x70 ) { + if ( (shaderId & 0x70) != 0 ) { switch (shaderId & 7) { + case 0 : + result = +M2PixelShader::Combiners_Mod_Opaque; + break; + case 1 : + case 2 : + case 5 : + result = +M2PixelShader::Combiners_Mod_Mod; + break; case 3 : result = +M2PixelShader::Combiners_Mod_Add; break; case 4 : result = +M2PixelShader::Combiners_Mod_Mod2x; break; - case 6 : result = +M2PixelShader::Combiners_Mod_Mod2xNA; break; case 7 : result = +M2PixelShader::Combiners_Mod_AddNA; break; - default: result = +M2PixelShader::Combiners_Mod_Mod; break; @@ -259,6 +264,11 @@ int getPixelShaderId(int textureCount, uint16_t shaderId) { case 0 : result = +M2PixelShader::Combiners_Opaque_Opaque; break; + case 1: + case 2: + case 5: + result = +M2PixelShader::Combiners_Opaque_Mod; + break; case 3: case 7: result = +M2PixelShader::Combiners_Opaque_AddAlpha; @@ -1507,7 +1517,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { this->m_meshArray.emplace_back(hMesh, batchIndex); - if (getBlendMode(batchIndex) == EGxBlendEnum::GxBlend_Opaque) { + if (getBlendMode(batchIndex) == EGxBlendEnum::GxBlend_Opaque || getBlendMode(batchIndex) == EGxBlendEnum::GxBlend_AlphaKey) { EGxBlendEnum blendMode = EGxBlendEnum::GxBlend_Alpha; HGM2Mesh hMeshTrans = createSingleMesh(sceneRenderer, 0, bufferBindings, m_forcedTranspMaterialArray[batchIndex], skinSection, m2Batch); @@ -1602,6 +1612,8 @@ std::shared_ptr M2Object::createM2Material(const HMapSceneBufferCre pipelineTemplate.triCCW = true; if (overrideBlend) { pipelineTemplate.blendMode = blendMode; + if (blendMode > EGxBlendEnum::GxBlend_AlphaKey) + pipelineTemplate.depthWrite = false; } else { pipelineTemplate.blendMode = M2BlendingModeToEGxBlendEnum[renderFlag->blending_mode]; } @@ -1642,7 +1654,7 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector(this->m_meshArray[i]); - if (finalTransparency < 0.999 && i < this->m_meshForcedTranspArray.size() && + if (finalTransparency < 0.999f && i < this->m_meshForcedTranspArray.size() && std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { mesh = std::get<0>(this->m_meshForcedTranspArray[i]); } diff --git a/wowViewerLib/src/gapi/interface/sortLambda.h b/wowViewerLib/src/gapi/interface/sortLambda.h index eeb51d735..2cb704590 100644 --- a/wowViewerLib/src/gapi/interface/sortLambda.h +++ b/wowViewerLib/src/gapi/interface/sortLambda.h @@ -12,10 +12,10 @@ static const bool SortMeshes(const HGSortableMesh &indexA, const HGSortableMesh return pB->priorityPlane() > pA->priorityPlane(); } - if (pA->getSortDistance() < pB->getSortDistance()) { + if (pA->getSortDistance() > pB->getSortDistance()) { return true; } - if (pA->getSortDistance() > pB->getSortDistance()) { + if (pA->getSortDistance() < pB->getSortDistance()) { return false; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 13cf44235..296284d66 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1152,7 +1152,7 @@ void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, const std::vector &imageIndexes) { VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.pNext = NULL; + presentInfo.pNext = nullptr; presentInfo.waitSemaphoreCount = waitSemaphores.size(); presentInfo.pWaitSemaphores = waitSemaphores.data(); @@ -1185,7 +1185,7 @@ void GDeviceVLK::executeDeallocators() { } std::shared_ptr GDeviceVLK::getRenderPass( - std::vector textureAttachments, + const std::vector &textureAttachments, ITextureFormat depthAttachment, VkSampleCountFlagBits sampleCountFlagBits, bool invertZ, @@ -1213,16 +1213,11 @@ std::shared_ptr GDeviceVLK::getRenderPass( } } - std::vector attachmentFormats = {}; - GFrameBufferVLK::iterateOverAttachments(textureAttachments, [&](int i, VkFormat textureFormat) { - attachmentFormats.push_back(textureFormat); - }); - VkFormat fbDepthFormat = findDepthFormat(); - auto renderPass = std::make_shared(this->device, - attachmentFormats, - findDepthFormat(), + auto renderPass = std::make_shared(*this, + textureAttachments, + depthAttachment, sampleCountFlagBits, invertZ, false @@ -1382,8 +1377,8 @@ void GDeviceVLK::singleExecuteAndWait(std::function callb VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - beginInfo.pNext = NULL; - beginInfo.pInheritanceInfo = NULL; + beginInfo.pNext = nullptr; + beginInfo.pInheritanceInfo = nullptr; ERR_GUARD_VULKAN(vkBeginCommandBuffer(copyCmd, &beginInfo)); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 90d54012f..e9745a247 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -132,7 +132,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getRenderPass(std::vector textureAttachments, + std::shared_ptr getRenderPass(const std::vector &textureAttachments, ITextureFormat depthAttachment, VkSampleCountFlagBits sampleCountFlagBits, bool invertZ, diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index 458e2216c..b69691ed3 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -83,10 +83,11 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, // << std::endl; } - std::array attachments = { + std::vector attachments = { std::dynamic_pointer_cast(colorImage)->texture.view, - std::dynamic_pointer_cast(m_depthTexture)->texture.view }; + if (m_depthTexture != nullptr) + attachments.push_back(std::dynamic_pointer_cast(m_depthTexture)->texture.view); VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; fbufCreateInfo.pNext = nullptr; @@ -156,7 +157,9 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, }); //Depth attachment - { + if (depthAttachment != ITextureFormat::itNone) { + assert(depthAttachment == ITextureFormat::itDepth32); + // Find a suitable depth format VkFormat fbDepthFormat = mdevice.findDepthFormat(); diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index cda659cc6..6631ae34e 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -39,7 +39,7 @@ class GFrameBufferVLK : public IFrameBuffer { std::vector m_attachmentTextures; std::vector m_attachmentTexturesSampled; - HGTexture m_depthTexture; + HGTexture m_depthTexture = nullptr; //Used only in readRGBAPixels function std::vector m_attachmentFormats; diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp index 95c3f8687..2324a80e7 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp @@ -4,14 +4,53 @@ #include #include "GRenderPassVLK.h" +#include "../interface/textures/ITexture.h" +#include "GFrameBufferVLK.h" +GRenderPassVLK::GRenderPassVLK(IDevice &device, + const std::vector &textureAttachments, + ITextureFormat depthAttachmentFormat, + VkSampleCountFlagBits sampleCountBit, + bool invertZ, + bool isSwapChainPass) : m_invertZ(invertZ) { + + auto &deviceVlk = dynamic_cast(device); + + std::vector attachmentFormats = {}; + + GFrameBufferVLK::iterateOverAttachments(textureAttachments, [&](int i, VkFormat textureFormat) { + attachmentFormats.push_back(textureFormat); + }); + + VkFormat availableDepth = deviceVlk.findDepthFormat(); + + createRenderPass(depthAttachmentFormat, + sampleCountBit, isSwapChainPass, + deviceVlk.getVkDevice(), + attachmentFormats, + availableDepth); +} GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, - std::vector textureAttachments, - VkFormat depthAttachmentFormat, + const std::vector &textureAttachments, + VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, bool invertZ, bool isSwapChainPass) : m_invertZ(invertZ) { + createRenderPass(ITextureFormat::itDepth32, + sampleCountBit, isSwapChainPass, + vkDevice, + textureAttachments, + depthAttachment); +} + + +void GRenderPassVLK::createRenderPass(const ITextureFormat &depthAttachmentFormat, + const VkSampleCountFlagBits &sampleCountBit, bool isSwapChainPass, + VkDevice vkDevice, + const std::vector &attachmentFormats, + const VkFormat &availableDepth) { + m_sampleCountBit = sampleCountBit; std::vector attachments; @@ -21,9 +60,9 @@ GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, std::vector colorResolveReferences; int attachmentIndex = 0; - for (int i = 0; i < textureAttachments.size(); i++) { + for (int i = 0; i < attachmentFormats.size(); i++) { VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = textureAttachments[i]; + colorAttachment.format = attachmentFormats[i]; colorAttachment.samples = sampleCountBit; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -48,7 +87,7 @@ GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, //Add resolves if multisampling is on if (sampleCountBit != VK_SAMPLE_COUNT_1_BIT) { VkAttachmentDescription colorAttachmentResolve{}; - colorAttachmentResolve.format = textureAttachments[i]; + colorAttachmentResolve.format = attachmentFormats[i]; colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -67,29 +106,37 @@ GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, } } - VkAttachmentDescription depthAttachment = {}; - depthAttachment.format = depthAttachmentFormat; - depthAttachment.samples = sampleCountBit; - depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - attachments.push_back(depthAttachment); - attachmentTypes.push_back(AttachmentType::atDepth); - + bool hasDepth = false; VkAttachmentReference depthAttachmentRef = {}; - depthAttachmentRef.attachment = attachmentIndex++; - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (depthAttachmentFormat != ITextureFormat::itNone) { + assert(depthAttachmentFormat == ITextureFormat::itDepth32); + + hasDepth = true; + + VkAttachmentDescription depthAttachment = {}; + depthAttachment.format = availableDepth; + depthAttachment.samples = sampleCountBit; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + attachments.push_back(depthAttachment); + attachmentTypes.push_back(AttachmentType::atDepth); + + //Fill DepthAttachmentRef + depthAttachmentRef.attachment = attachmentIndex++; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = colorReferences.size(); subpass.pColorAttachments = colorReferences.data(); subpass.pResolveAttachments = colorResolveReferences.data(); - subpass.pDepthStencilAttachment = &depthAttachmentRef; + subpass.pDepthStencilAttachment = (hasDepth ? &depthAttachmentRef : nullptr); std::vector dependencies; if (isSwapChainPass) { diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h index 7a1a5d596..5fcbc92df 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h @@ -6,13 +6,22 @@ #define AWEBWOWVIEWERCPP_GRENDERPASSVLK_H #include "context/vulkan_context.h" +#include "../interface/textures/ITexture.h" +#include "../interface/IDevice.h" #include #include class GRenderPassVLK { public: + GRenderPassVLK(IDevice &device, + const std::vector &textureAttachments, + ITextureFormat depthAttachment, + VkSampleCountFlagBits sampleCountBit, + bool invertZ, + bool isSwapChainPass); + GRenderPassVLK(VkDevice vkDevice, - std::vector textureAttachments, + const std::vector &textureAttachments, VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, bool invertZ, @@ -41,6 +50,11 @@ class GRenderPassVLK { //Is used to fill proper clearColor vector std::vector attachmentTypes; + void createRenderPass(const ITextureFormat &depthAttachmentFormat, + const VkSampleCountFlagBits &sampleCountBit, bool isSwapChainPass, + VkDevice vkDevice, + const std::vector &attachmentFormats, + const VkFormat &availableDepth); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index 3e402d2fc..96e3a7afb 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -30,9 +30,7 @@ class CBufferChunkVLK : public IBufferChunk { pSubBuffer->save(m_realSize); }; - const std::shared_ptr getSubBuffer() { - return subBuffer; - } + operator const std::shared_ptr() const { return subBuffer; } private: int m_realSize = 0; void *ptr = nullptr; @@ -42,8 +40,8 @@ class CBufferChunkVLK : public IBufferChunk { namespace BufferChunkHelperVLK { template - static const inline std::shared_ptr> cast(const std::shared_ptr> &chunk) { - return std::dynamic_pointer_cast>(chunk); + static const inline std::shared_ptr cast(const std::shared_ptr> &chunk) { + return *std::dynamic_pointer_cast>(chunk); } template diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp deleted file mode 100644 index 90291e373..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// -// Created by deamon on 05.06.18. -// - -#include -#include -#include "GVertexBufferDynamicVLK.h" - -GVertexBufferDynamicVLK::GVertexBufferDynamicVLK(IDevice &device, size_t maxSize) : m_device(dynamic_cast(device)) { - m_size = maxSize; - createBuffer(); -} - -GVertexBufferDynamicVLK::~GVertexBufferDynamicVLK() { - destroyBuffer(); - -} - -void GVertexBufferDynamicVLK::createBuffer() { - //Create new buffer for VBO - VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - vbInfo.size = m_size; - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo ibAllocCreateInfo = {}; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, &stagingVertexBuffer, - &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo)); - - - - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ibAllocCreateInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device.getVMAAllocator(), &vbInfo, &ibAllocCreateInfo, &g_hVertexBuffer, - &g_hVertexBufferAlloc, nullptr)); -} - -void GVertexBufferDynamicVLK::destroyBuffer() { - auto *l_device = &m_device; - auto &l_stagingVertexBuffer = stagingVertexBuffer; - auto &l_stagingVertexBufferAlloc = stagingVertexBufferAlloc; - - auto &l_hVertexBuffer = g_hVertexBuffer; - auto &l_hVertexBufferAlloc = g_hVertexBufferAlloc; - - m_device.addDeallocationRecord( - [l_device, l_stagingVertexBuffer, l_stagingVertexBufferAlloc, l_hVertexBuffer, l_hVertexBufferAlloc]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_stagingVertexBuffer, l_stagingVertexBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_hVertexBuffer, l_hVertexBufferAlloc); - } - ); -} - -static int vbo_uploaded = 0; - -void GVertexBufferDynamicVLK::uploadData(const void *data, int length) { -} - -void *GVertexBufferDynamicVLK::getPointer() { - return stagingVertexBufferAllocInfo.pMappedData; -} - -/* -void GVertexBufferDynamicVLK::save(size_t sizeToSave) { - VkBufferCopy vbCopyRegion = {}; - vbCopyRegion.srcOffset = 0; - vbCopyRegion.dstOffset = 0; - vbCopyRegion.size = sizeToSave; - vkCmdCopyBuffer(m_device.getUploadCommandBuffer(), stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion); -} - -void GVertexBufferDynamicVLK::resize(size_t sizeToSave) { - if (sizeToSave > m_size) { - destroyBuffer(); - m_size = sizeToSave; - createBuffer(); - } -} - */ \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h deleted file mode 100644 index c5d505a73..000000000 --- a/wowViewerLib/src/gapi/vulkan/buffers/GVertexBufferDynamicVLK.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Created by deamon on 05.06.18. -// - -#ifndef WEBWOWVIEWERCPP_GVERTEXBUFFERDYNAMICVLK_H -#define WEBWOWVIEWERCPP_GVERTEXBUFFERDYNAMICVLK_H - -#include "../../interface/IDevice.h" -#include "../GDeviceVulkan.h" -#include - -class GVertexBufferDynamicVLK : public IBufferVLK { - friend class GDeviceVLK; - - explicit GVertexBufferDynamicVLK(IDevice &device, size_t maxSize); -public: - ~GVertexBufferDynamicVLK() override; - - void *getPointer() override; - -private: - void createBuffer(); - void destroyBuffer(); -public: - void uploadData(const void *, int length) override; - -private: - GDeviceVLK &m_device; - VkBuffer g_hVertexBuffer; - VmaAllocation g_hVertexBufferAlloc; - - VkBuffer stagingVertexBuffer = VK_NULL_HANDLE; - VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingVertexBufferAllocInfo; -private: - size_t m_size = 0; - bool m_buffCreated = false; - bool m_dataUploaded = false; -}; - -#endif //WEBWOWVIEWERCPP_GVERTEXBUFFERDYNAMICVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h index 4028740e7..3825d2340 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h @@ -16,4 +16,6 @@ class IBufferVLK : public IBuffer, public IDSBindable { virtual VkBuffer getGPUBuffer() = 0; virtual size_t getOffset() = 0; }; + + #endif //AWEBWOWVIEWERCPP_IBUFFERVLK_H diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 1d1d17886..742437d1e 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -22,8 +22,6 @@ struct FrameInputParams { //Parameters for framebuffer ViewPortDimensions viewPortDimensions = {{0,0}, {64, 64}}; - bool invertedZ = false; - bool clearScreen = false; }; #endif //AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 7b67cc4e0..c037b8a2c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -235,8 +235,8 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, vertexFragmentData->getSubBuffer()) - .ubo(2, fragmentData->getSubBuffer()); + .ubo(1, *vertexFragmentData) + .ubo(2, *fragmentData); }) .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -272,12 +272,12 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)->getSubBuffer()) - .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)->getSubBuffer()) - .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) - .ubo(7, vertexFragmentData->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)) + .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)) + .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)) + .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)) + .ubo(7, *vertexFragmentData); }) .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -312,10 +312,10 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) - .ubo(4, vertexData->getSubBuffer()) - .ubo(5, fragmentData->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)) + .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)) + .ubo(4, *vertexData) + .ubo(5, *fragmentData); }) .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -345,7 +345,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(4, *l_fragmentData); }) .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -372,8 +372,8 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater .createDescriptorSet(0, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)->getSubBuffer()) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ubo(4, *l_fragmentData); }) .createDescriptorSet(1, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -402,9 +402,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) - .ubo(2, l_vertexData->getSubBuffer()) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(1, BufferChunkHelperVLK::cast(modelWide)) + .ubo(2, *l_vertexData) + .ubo(4, *l_fragmentData); }) .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -437,8 +437,8 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(1, BufferChunkHelperVLK::cast(modelWide)) + .ubo(4, *l_fragmentData); }) .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -466,7 +466,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, skyColors->getSubBuffer()); + .ubo(1, *skyColors); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { instance->m_skyColors = skyColors; @@ -484,7 +484,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, materialPS->getSubBuffer()); + .ubo(1, *materialPS); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { instance->m_materialPS = materialPS; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 40f08132c..b53d7c91f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -18,7 +18,7 @@ FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &ubo { auto const dataFormat = {ITextureFormat::itRGBA}; - m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, VK_SAMPLE_COUNT_1_BIT, // sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), true, false); @@ -99,6 +99,7 @@ void FFXGlowPassVLK::drawMaterial (CmdBufRecorder& cmdBuf, const std::shared_ptr void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, const std::shared_ptr &finalRenderPass, ViewPortDimensions &viewPortDimensions) { + ZoneScoped; auto currentFrame = m_device->getDrawFrameNumber(); { @@ -168,7 +169,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { colorFrameBuffer = std::make_shared( *m_device, dataFormat, - ITextureFormat::itDepth32, + ITextureFormat::itNone, 1, targetWidth, targetHeight ); @@ -177,7 +178,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { colorFrameBuffer = std::make_shared( *m_device, dataFormat, - ITextureFormat::itDepth32, + ITextureFormat::itNone, 1, targetWidth, targetHeight ); @@ -203,8 +204,8 @@ FFXGlowPassVLK::createFFXGaussMat( .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelperVLK::cast(ffxGaussVs)->getSubBuffer()) - .ubo(4, BufferChunkHelperVLK::cast(ffxGaussPS)->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(ffxGaussVs)) + .ubo(4, BufferChunkHelperVLK::cast(ffxGaussPS)); }) .createDescriptorSet(1, [texture](std::shared_ptr &ds) { ds->beginUpdate() @@ -228,8 +229,8 @@ FFXGlowPassVLK::createFFXGlowMat( .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelperVLK::cast(ffxGlowVs)->getSubBuffer()) - .ubo(4, BufferChunkHelperVLK::cast(ffxGlowPS)->getSubBuffer()); + .ubo(2, BufferChunkHelperVLK::cast(ffxGlowVs)) + .ubo(4, BufferChunkHelperVLK::cast(ffxGlowPS)); }) .createDescriptorSet(1, [screenTex, blurTex](std::shared_ptr &ds) { ds->beginUpdate() From a6312203f288668866c762bee28da35528854c9b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Jul 2023 20:43:06 +0300 Subject: [PATCH 094/212] - More toggles in UI (render liquid, render invis meshes) - minimize getDescOffsets function call through messing with DescriptorSets - use data from EXP2 chunk in particle shader --- src/ui/FrontendUI.cpp | 61 +- wowViewerLib/CMakeLists.txt | 3 +- .../glsl/common/commonLightFunctions.glsl | 7 +- .../glsl/common/commonM2DescriptorSet.glsl | 33 + .../shaders/glsl/common/commonM2Material.glsl | 3 - .../glsl/forwardRendering/adtShader.frag | 22 +- .../glsl/forwardRendering/adtShader.vert | 2 +- .../forwardRendering/drawPortalShader.frag | 2 +- .../forwardRendering/drawPortalShader.vert | 2 +- .../glsl/forwardRendering/imguiShader.vert | 2 +- .../forwardRendering/m2ParticleShader.frag | 24 +- .../forwardRendering/m2ParticleShader.vert | 3 + .../glsl/forwardRendering/m2Shader.frag | 44 +- .../glsl/forwardRendering/m2Shader.vert | 25 +- .../glsl/forwardRendering/ribbonShader.frag | 8 +- .../glsl/forwardRendering/skyConus.frag | 8 + .../glsl/forwardRendering/skyConus.vert | 2 +- .../glsl/forwardRendering/waterShader.frag | 4 +- .../glsl/forwardRendering/waterShader.vert | 2 +- .../forwardRendering/waterfallShader.frag | 21 +- .../forwardRendering/waterfallShader.vert | 19 +- .../glsl/forwardRendering/wmoShader.frag | 20 +- .../glsl/forwardRendering/wmoShader.vert | 4 +- .../managers/particles/particleEmitter.cpp | 15 +- .../managers/particles/particleEmitter.h | 12 +- .../engine/objects/liquid/LiquidInstance.cpp | 4 +- .../src/engine/objects/m2/m2Object.cpp | 11 +- .../persistance/header/M2FileHeader.cpp | 4 +- .../engine/persistance/header/M2FileHeader.h | 6 +- .../src/engine/shader/ShaderDefinitions.h | 1151 +++++++++-------- .../src/gapi/UniformBufferStructures.h | 4 +- .../gapi/interface/buffers/IBufferVersioned.h | 16 + .../buffers/GBufferChunkDynamicVersionedVLK.h | 85 ++ .../vulkan/descriptorSets/GDescriptorSet.cpp | 6 - .../vulkan/shaders/GShaderPermutationVLK.cpp | 7 +- .../vulkan/shaders/GShaderPermutationVLK.h | 2 +- wowViewerLib/src/include/config.h | 2 + .../src/renderer/frame/FrameInputParams.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 6 +- .../src/renderer/mapScene/MapSceneRenderer.h | 4 +- .../mapScene/materials/IMaterialStructs.h | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 107 +- .../vulkan/MapSceneRenderForwardVLK.h | 11 +- 43 files changed, 1039 insertions(+), 737 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl create mode 100644 wowViewerLib/src/gapi/interface/buffers/IBufferVersioned.h create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 44f1d1668..5517c08d9 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -181,6 +181,24 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current blp vulkan textures loaded %d", l_blpTexturesVulkanLoaded); ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); + if (m_sceneRenderer && false) { + auto mapPlan = m_sceneRenderer->getLastCreatedPlan(); + if (mapPlan) { + auto &adtArray = mapPlan->adtArray; + auto &wmoArray = mapPlan->wmoArray; + auto &wmoGroupArray = mapPlan->wmoGroupArray; + auto &m2Array = mapPlan->m2Array; + + ImGui::Text("Candidates WMO %d", wmoArray.getCandidates().size()); + ImGui::Text("Candidates M2 objects %d", m2Array.getCandidates().size()); + + ImGui::Text("Rendered ADT files %d", adtArray.size()); + ImGui::Text("Rendered WMO %d", wmoArray.getToDrawn().size()); + ImGui::Text("Rendered WMO groups %d", wmoGroupArray.getToDraw().size()); + ImGui::Text("Rendered M2 objects %d", m2Array.getDrawn().size()); + } + } + ImGui::NewLine(); if (ImGui::CollapsingHeader("Elapsed times")) { @@ -485,9 +503,9 @@ void FrontendUI::showAdtSelectionMinimap() { void FrontendUI::showMapSelectionDialog() { if (!showSelectMap) { - for (int i = 0; i < 64; i++) - for (int j = 0; j < 64; j++) - adtSelectionMinimapMaterials[i][j] = nullptr; +// for (int i = 0; i < 64; i++) +// for (int j = 0; j < 64; j++) +// adtSelectionMinimapMaterials[i][j] = nullptr; return; } @@ -601,6 +619,7 @@ void FrontendUI::showMapSelectionDialog() { ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { if (mapRec.ID != prevMapId) { + minimapZoom = 0.1; mapCanBeOpened = true; adtMinimapFilled = false; prevMapRec = mapRec; @@ -1296,11 +1315,21 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->renderWMO = renderWMO; } + bool renderLiquid = m_api->getConfig()->renderLiquid; + if (ImGui::Checkbox("Render Liquid", &renderLiquid)) { + m_api->getConfig()->renderLiquid = renderLiquid; + } + bool drawM2BB = m_api->getConfig()->drawM2BB; if (ImGui::Checkbox("Render M2 Bounding Box", &drawM2BB)) { m_api->getConfig()->drawM2BB = drawM2BB; } + bool discardInvisibleMeshes = m_api->getConfig()->discardInvisibleMeshes; + if (ImGui::Checkbox("Discard invisible M2 meshes", &discardInvisibleMeshes)) { + m_api->getConfig()->discardInvisibleMeshes = discardInvisibleMeshes; + } + bool ignoreADTHoles = m_api->getConfig()->ignoreADTHoles; if (ImGui::Checkbox("Ignore ADT holes for rendering", &ignoreADTHoles)) { m_api->getConfig()->ignoreADTHoles = ignoreADTHoles; @@ -1769,6 +1798,26 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do m_api->getConfig()->swapMainAndDebug, m_currentScene); + if (needToMakeScreenshot) { + wowSceneFrameInput->screenShotParameters = createMapSceneParams(*m_api, + screenShotWidth, screenShotHeight, + false, + false, + m_currentScene); + } +// { +// HCullStage tempCullStage = nullptr; +// auto drawStage = createSceneDrawStage(sceneScenario, screenShotWidth, screenShotHeight, deltaTime, true, +// false, false, *m_api, +// currentScene,tempCullStage); +// if (drawStage != nullptr) { +// uiDependecies.push_back(drawStage); +// screenshotDS = drawStage; +// screenshotFrame = m_api->hDevice->getFrameNumber(); +// } +// needToMakeScreenshot = false; +// } + scenario->cullFunctions.push_back(m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput)); } @@ -1780,12 +1829,6 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto clearColor = m_api->getConfig()->clearColor; scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput)); - -// auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); -// auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); -// std::vector updateStages = {uiUpdateStage}; -// HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, -// true, dimension, clearOnUi, false, clearColor, nullptr); } diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 0c4166a88..d427c0195 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -357,7 +357,7 @@ set(SOURCE_FILES src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h - src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h) + src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h src/gapi/interface/buffers/IBufferVersioned.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -520,6 +520,7 @@ if (LINK_VULKAN) src/gapi/vulkan/materials/ISimpleMaterialVLK.h src/gapi/vulkan/buffers/CBufferChunkVLK.cpp src/gapi/vulkan/buffers/CBufferChunkVLK.h + src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h src/gapi/vulkan/commandBuffer/CommandBuffer.cpp diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index bfe996665..7551ecb6a 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -1,5 +1,11 @@ #ifndef COMMON_LIGHT_FUNCTIONS #define COMMON_LIGHT_FUNCTIONS +struct LocalLight +{ + vec4 color; + vec4 position; + vec4 attenuation; +}; struct SceneExteriorLight { vec4 uExteriorAmbientColor; @@ -10,7 +16,6 @@ struct SceneExteriorLight { vec4 adtSpecMult; }; - struct SceneWideParams { mat4 uLookAtMat; mat4 uPMatrix; diff --git a/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl new file mode 100644 index 000000000..f68c8b48c --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl @@ -0,0 +1,33 @@ +#include "../common/commonLightFunctions.glsl" + +#ifndef MAX_MATRIX_NUM +#define MAX_MATRIX_NUM 256 +#endif + +// Whole model +layout(std140, set=1, binding=1) uniform modelWideBlockVS { + mat4 uPlacementMat; +}; + +layout(std140, set=1, binding=2) uniform modelWideBlockPS { + InteriorLightParam intLight; + LocalLight pc_lights[4]; + ivec4 lightCountAndBcHack; + vec4 interiorExteriorBlend; +}; + +layout(std140, set=1, binding=3) uniform boneMats { + mat4 uBoneMatrixes[MAX_MATRIX_NUM]; +}; + +layout(std140, set=1, binding=4) uniform m2Colors { + vec4 colors[256]; +}; + +layout(std140, set=1, binding=5) uniform textureWeights { + vec4 textureWeight[16]; +}; + +layout(std140, set=1, binding=6) uniform textureMatrices { + mat4 textureMatrix[64]; +}; \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl index dfb1a7532..46b68da31 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2Material.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2Material.glsl @@ -1,8 +1,5 @@ #include "commonFunctions.glsl" -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 256 -#endif void calcM2FragMaterial(const in int uPixelShader, in sampler2D texSampler1, diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 72a306a19..edf2e250b 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -14,29 +14,29 @@ layout(location = 2) in vec4 vColor; layout(location = 3) in vec3 vNormal; layout(location = 4) in vec3 vVertexLighting; -layout(set=1, binding=5) uniform sampler2D uLayer0; -layout(set=1, binding=6) uniform sampler2D uLayer1; -layout(set=1, binding=7) uniform sampler2D uLayer2; -layout(set=1, binding=8) uniform sampler2D uLayer3; -layout(set=1, binding=9) uniform sampler2D uAlphaTexture; -layout(set=1, binding=10) uniform sampler2D uLayerHeight0; -layout(set=1, binding=11) uniform sampler2D uLayerHeight1; -layout(set=1, binding=12) uniform sampler2D uLayerHeight2; -layout(set=1, binding=13) uniform sampler2D uLayerHeight3; +layout(set=2, binding=5) uniform sampler2D uLayer0; +layout(set=2, binding=6) uniform sampler2D uLayer1; +layout(set=2, binding=7) uniform sampler2D uLayer2; +layout(set=2, binding=8) uniform sampler2D uLayer3; +layout(set=2, binding=9) uniform sampler2D uAlphaTexture; +layout(set=2, binding=10) uniform sampler2D uLayerHeight0; +layout(set=2, binding=11) uniform sampler2D uLayerHeight1; +layout(set=2, binding=12) uniform sampler2D uLayerHeight2; +layout(set=2, binding=13) uniform sampler2D uLayerHeight3; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, binding=1) uniform meshWideBlockVSPS { +layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { vec4 uPos; ivec4 uUseHeightMixFormula; vec4 uHeightScale; vec4 uHeightOffset; }; -layout(std140, binding=2) uniform meshWideBlockPS { +layout(std140, set=1, binding=2) uniform meshWideBlockPS { vec4 scaleFactorPerLayer; ivec4 animation_rotationPerLayer; ivec4 animation_speedPerLayer; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 3235df5b3..e91d3a528 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -19,7 +19,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, binding=1) uniform meshWideBlockVSPS { +layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { vec4 uPos; ivec4 uUseHeightMixFormula; vec4 uHeightScale; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag index 24312ecef..5bb45fe53 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag @@ -4,7 +4,7 @@ precision highp float; precision highp int; //Individual mesh -layout(std140, set=0, binding=1) uniform meshWideBlockPS { +layout(std140, set=1, binding=1) uniform meshWideBlockPS { vec4 uColor; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert index 048d311b8..59c022b47 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert @@ -12,7 +12,7 @@ precision highp int; layout(location = 0) in vec3 aPosition; //Whole scene -layout(std140, binding=0) uniform sceneWideBlockVSPS { +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert index 1daa3a78e..f2cdcdfe4 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert @@ -7,7 +7,7 @@ layout (location = 0) in vec2 Position; layout (location = 1) in vec2 UV; layout (location = 2) in vec4 Color; -layout(std140, binding=1) uniform modelWideBlockVS { +layout(std140, set=0, binding=1) uniform modelWideBlockVS { mat4 ProjMtx; vec4 uiScale; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index 8e4d74677..0cc4a5767 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -10,24 +10,25 @@ layout(location = 1) in vec4 vColor; layout(location = 2) in vec2 vTexcoord0; layout(location = 3) in vec2 vTexcoord1; layout(location = 4) in vec2 vTexcoord2; +layout(location = 5) in float alphaCutoff; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" -layout(std140, binding=0) uniform sceneWideBlockVSPS { +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; //Individual meshes -layout(std140, binding=4) uniform meshWideBlockPS { - vec4 uAlphaTestv; +layout(std140, set=1, binding=4) uniform meshWideBlockPS { + vec4 uAlphaTest_alphaMult_colorMult; ivec4 uPixelShaderBlendModev; }; -layout(set=1,binding=5) uniform sampler2D uTexture; -layout(set=1,binding=6) uniform sampler2D uTexture2; -layout(set=1,binding=7) uniform sampler2D uTexture3; +layout(set=2,binding=5) uniform sampler2D uTexture; +layout(set=2,binding=6) uniform sampler2D uTexture2; +layout(set=2,binding=7) uniform sampler2D uTexture3; layout(location = 0) out vec4 outputColor; @@ -36,7 +37,9 @@ void main() { vec4 tex2 = texture(uTexture2, vTexcoord1).rgba; vec4 tex3 = texture(uTexture3, vTexcoord2).rgba; - float uAlphaTest = uAlphaTestv.x; + float uAlphaTest = uAlphaTest_alphaMult_colorMult.x; + float alphaMult = uAlphaTest_alphaMult_colorMult.y; + float colorMult = uAlphaTest_alphaMult_colorMult.z; if(tex.a < uAlphaTest) discard; @@ -84,10 +87,15 @@ void main() { finalColor = vec4(height_995, 0.0, 0.0, alpha_997); } + finalColor = vec4(finalColor.rgb * colorMult, finalColor.a * alphaMult); + if(finalColor.a < uAlphaTest) discard; -// vec3 sunDir = + if(finalColor.a < alphaCutoff) + discard; + + // vec3 sunDir = // mix( // scene.uInteriorSunDir, // scene.extLight.uExteriorDirectColorDir, diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert index dc3f247aa..b4071ee4b 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert @@ -10,6 +10,7 @@ layout(location = 1) in vec4 aColor; layout(location = 2) in vec2 aTexcoord0; layout(location = 3) in vec2 aTexcoord1; layout(location = 4) in vec2 aTexcoord2; +layout(location = 5) in float aAlphaCutoff; layout(location = 0) out vec3 vPosition; @@ -17,6 +18,7 @@ layout(location = 1) out vec4 vColor; layout(location = 2) out vec2 vTexcoord0; layout(location = 3) out vec2 vTexcoord1; layout(location = 4) out vec2 vTexcoord2; +layout(location = 5) out float vAlphaCutoff; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" @@ -38,6 +40,7 @@ void main() { vec4 vertexViewSpace = (scene.uLookAtMat * aPositionVec4); vPosition = vertexViewSpace.xyz; + vAlphaCutoff = aAlphaCutoff; gl_Position = scene.uPMatrix * vertexViewSpace; } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 06a70e6a7..d3c2d9b1b 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -2,10 +2,6 @@ #extension GL_GOOGLE_include_directive: require -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 -#endif - precision highp float; precision highp int; @@ -13,13 +9,6 @@ precision highp int; #include "../common/commonFogFunctions.glsl" #include "../common/commonM2Material.glsl" -struct LocalLight -{ - vec4 color; - vec4 position; - vec4 attenuation; -}; - layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; layout(location=2) in vec2 vTexCoord3; @@ -33,42 +22,21 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=1) uniform placementMat { - mat4 uPlacementMat; -}; - //Whole model -layout(std140, set=0, binding=2) uniform modelWideBlockPS { - InteriorLightParam intLight; - LocalLight pc_lights[4]; - ivec4 lightCountAndBcHack; - vec4 interiorExteriorBlend; -}; - -layout(std140, set=0, binding=4) uniform m2Colors { - vec4 colors[256]; -}; - -layout(std140, set=0, binding=5) uniform textureWeights { - vec4 textureWeight[16]; -}; - -layout(std140, set=0, binding=6) uniform textureMatrices { - mat4 textureMatrix[64]; -}; +#include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=0, binding=7) uniform meshWideBlockVSPS { +layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; ivec4 PixelShader_UnFogged_blendMode; ivec4 textureWeightIndexes; ivec4 colorIndex_applyWeight; }; -layout(set=1,binding=6) uniform sampler2D uTexture; -layout(set=1,binding=7) uniform sampler2D uTexture2; -layout(set=1,binding=8) uniform sampler2D uTexture3; -layout(set=1,binding=9) uniform sampler2D uTexture4; +layout(set=3,binding=6) uniform sampler2D uTexture; +layout(set=3,binding=7) uniform sampler2D uTexture2; +layout(set=3,binding=8) uniform sampler2D uTexture3; +layout(set=3,binding=9) uniform sampler2D uTexture4; void main() { /* Animation support */ diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 04ad45ab5..473a714bb 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -25,30 +25,11 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -// Whole model -layout(std140, set=0, binding=1) uniform modelWideBlockVS { - mat4 uPlacementMat; -}; - -layout(std140, set=0, binding=3) uniform boneMats { - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; -}; - - -layout(std140, set=0, binding=4) uniform m2Colors { - vec4 colors[256]; -}; - -layout(std140, set=0, binding=5) uniform textureWeights { - vec4 textureWeight[16]; -}; - -layout(std140, set=0, binding=6) uniform textureMatrices { - mat4 textureMatrix[64]; -}; +//Whole model +#include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=0, binding=7) uniform meshWideBlockVSPS { +layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; ivec4 PixelShader_UnFogged_blendMode; ivec4 textureWeightIndexes; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index f814b4f13..3badb3882 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -13,19 +13,19 @@ layout(location = 0) in vec3 vPosition; layout(location = 1) in vec4 vColor; layout(location = 2) in vec2 vTexcoord0; -layout(std140, binding=0) uniform sceneWideBlockVSPS { +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, binding=3) uniform textureMatrices { +layout(std140, set=1, binding=3) uniform textureMatrices { mat4 textureMatrix[64]; }; -layout(std140, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=4) uniform meshWideBlockPS { ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; -layout(set=1, binding=5) uniform sampler2D uTexture; +layout(set=2, binding=5) uniform sampler2D uTexture; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag index 3cccdbefc..108b13df5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag @@ -5,6 +5,14 @@ precision highp float; precision highp int; +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + layout(location = 0) in vec4 vColor; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert index 90adf9c02..0a9c0d949 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert @@ -14,7 +14,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, set=0, binding=1) uniform meshWideBlockVS { +layout(std140, set=1, binding=1) uniform meshWideBlockVS { vec4 skyColor[6]; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 8cbbd31fe..3738004c1 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -14,7 +14,7 @@ layout(location=2) in vec3 vNormal; layout(location=0) out vec4 outputColor; -layout(set=1,binding=5) uniform sampler2D uTexture; +layout(set=2,binding=5) uniform sampler2D uTexture; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; @@ -22,7 +22,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { }; //Individual meshes -layout(std140, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=4) uniform meshWideBlockPS { ivec4 materialId; vec4 color; mat4 textureMatrix; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index 7d0816f68..63aa65aa3 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -17,7 +17,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index 34d1443af..b0d806222 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -2,10 +2,6 @@ #extension GL_GOOGLE_include_directive: require -#ifndef MAX_MATRIX_NUM -#define MAX_MATRIX_NUM 220 -#endif - precision highp float; precision highp int; @@ -19,10 +15,10 @@ layout(location=2) in vec2 vTexCoord2_animated; layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; -layout(set=1,binding=6) uniform sampler2D uMask; -layout(set=1,binding=7) uniform sampler2D uWhiteWater; -layout(set=1,binding=8) uniform sampler2D uNoise; -layout(set=1,binding=10) uniform sampler2D uNormalTex; +layout(set=3,binding=6) uniform sampler2D uMask; +layout(set=3,binding=7) uniform sampler2D uWhiteWater; +layout(set=3,binding=8) uniform sampler2D uNoise; +layout(set=3,binding=10) uniform sampler2D uNormalTex; layout(location=0) out vec4 outputColor; @@ -31,7 +27,10 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=5) uniform meshWideBlockPS { +//Whole model +#include "../common/commonM2DescriptorSet.glsl" + +layout(std140, set=2, binding=5) uniform meshWideBlockPS { vec4 values0; vec4 values1; vec4 values2; @@ -40,7 +39,7 @@ layout(std140, set=0, binding=5) uniform meshWideBlockPS { vec4 baseColor; }; -const InteriorLightParam intLight = { +const InteriorLightParam intLightWaterfall = { vec4(0,0,0,0), vec4(0,0,0,1) }; @@ -99,7 +98,7 @@ void main() { true, 0.0, scene, - intLight, + intLightWaterfall, vec3(0.0), /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index ae7f73be6..4b6edc366 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -27,23 +27,15 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { }; // Whole model -layout(std140, set=0, binding=1) uniform modelWideBlockVS { - mat4 uPlacementMat; -}; - -layout(std140, set=0, binding=2) uniform boneMats { - mat4 uBoneMatrixes[MAX_MATRIX_NUM]; -}; - -layout(std140, set=0, binding=3) uniform textureMatrices { - mat4 textureMatrix[64]; -}; +#include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=0, binding=4) uniform meshWideBlockVS { +layout(std140, set=2, binding=4) uniform meshWideBlockVS { vec4 bumpScaleTextIndexes; }; +layout(set=3,binding=9) uniform sampler2D uBumpTexture; + //Shader output layout(location=0) out vec2 vTexCoord; layout(location=1) out vec2 vTexCoord2; @@ -51,9 +43,6 @@ layout(location=2) out vec2 vTexCoord2_animated; layout(location=3) out vec3 vNormal; layout(location=4) out vec3 vPosition; - -layout(set=1,binding=9) uniform sampler2D uBumpTexture; - void main() { float bumpScale = bumpScaleTextIndexes.x; int textMatIndex1 = floatBitsToInt(bumpScaleTextIndexes.y); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index 342fff80e..c23ea6cc6 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -29,20 +29,20 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { PSFog fogData; }; -layout(std140, set=0, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=4) uniform meshWideBlockPS { ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; vec4 FogColor_AlphaTest; }; -layout(set=1, binding=5) uniform sampler2D uTexture; -layout(set=1, binding=6) uniform sampler2D uTexture2; -layout(set=1, binding=7) uniform sampler2D uTexture3; -layout(set=1, binding=8) uniform sampler2D uTexture4; -layout(set=1, binding=9) uniform sampler2D uTexture5; -layout(set=1, binding=10) uniform sampler2D uTexture6; -layout(set=1, binding=11) uniform sampler2D uTexture7; -layout(set=1, binding=12) uniform sampler2D uTexture8; -layout(set=1, binding=13) uniform sampler2D uTexture9; +layout(set=2, binding=5) uniform sampler2D uTexture; +layout(set=2, binding=6) uniform sampler2D uTexture2; +layout(set=2, binding=7) uniform sampler2D uTexture3; +layout(set=2, binding=8) uniform sampler2D uTexture4; +layout(set=2, binding=9) uniform sampler2D uTexture5; +layout(set=2, binding=10) uniform sampler2D uTexture6; +layout(set=2, binding=11) uniform sampler2D uTexture7; +layout(set=2, binding=12) uniform sampler2D uTexture8; +layout(set=2, binding=13) uniform sampler2D uTexture9; layout (location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index 275aa130a..89f25c022 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -26,11 +26,11 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; -layout(std140, set=0, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; }; -layout(std140, set=0, binding=2) uniform meshWideBlockVS { +layout(std140, set=1, binding=2) uniform meshWideBlockVS { ivec4 VertexShader_UseLitColor; }; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 1753a0062..141ef83ca 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -81,7 +81,7 @@ static const struct { }; -ParticleEmitter::ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw) : m_seed(rand()), m_api(api), m2Object(m2Object) { +ParticleEmitter::ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, Exp2Record *exp2, M2Object *m2Object, HM2Geom geom, int txac_val_raw) : m_seed(rand()), m_api(api), m2Object(m2Object) { if (!randTableInited) { for (int i = 0; i < 128; i++) { @@ -90,6 +90,7 @@ ParticleEmitter::ParticleEmitter(const HApiContainer &api, const HMapSceneBuffer randTableInited = true; } + m_exp2Data = exp2; m_data = particle; txac_particles_value.value = txac_val_raw; @@ -323,6 +324,8 @@ void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } else { blockPS.uAlphaTest = 0.0039215689f; } + blockPS.alphaMult = (m_exp2Data == nullptr) ? 1.0 : m_exp2Data->alphaMult; + blockPS.colorMult = (m_exp2Data == nullptr) ? 1.0 : m_exp2Data->colorMult; int uPixelShader = particleMaterialShader[this->shaderId].pixelShader; @@ -829,6 +832,7 @@ int ParticleEmitter::buildVertex1(CParticle2 &p, ParticlePreRenderData &particle particlePreRenderData.m_particleCenter, particlePreRenderData.m_ageDependentValues.m_timedColor, particlePreRenderData.m_ageDependentValues.m_alpha, + particlePreRenderData.m_ageDependentValues.alphaCutoff, texScaleVec.x, texScaleVec.y, p.texPos); return 0; @@ -883,6 +887,7 @@ int ParticleEmitter::buildVertex2(CParticle2 &p, ParticlePreRenderData &particle particlePreRenderData.m_particleCenter, particlePreRenderData.m_ageDependentValues.m_timedColor, particlePreRenderData.m_ageDependentValues.m_alpha, + particlePreRenderData.m_ageDependentValues.alphaCutoff, texScaleVec.x, texScaleVec.y, p.texPos); @@ -1040,6 +1045,12 @@ void ParticleEmitter::fillTimedParticleData(CParticle2 &p, defaultCell = 0; ageDependentValues.timedTailCell = animatePartTrack(percentTime, &m_data->old.tailCellTrack, defaultCell); + ageDependentValues.alphaCutoff = 0.0f; + if (m_exp2Data != nullptr) { + ageDependentValues.alphaCutoff = animatePartTrack(percentTime, &m_exp2Data->alphaCutoff, ageDependentValues.alphaCutoff); + } + + ageDependentValues.timedTailCell = (ageDependentValues.timedTailCell + m_randomizedTextureIndexMask) & textureIndexMask; float scaleMultiplier = 1.0f; @@ -1064,6 +1075,7 @@ void ParticleEmitter::BuildQuadT3( mathfu::vec3 &m0, mathfu::vec3 &m1, mathfu::vec3 &viewPos, mathfu::vec3 &color, float alpha, + float alphaCutoff, float texStartX, float texStartY, mathfu::vec2 *texPos) { static const float vxs[4] = {-1, -1, 1, 1}; @@ -1099,6 +1111,7 @@ ParticleEmitter::BuildQuadT3( txs[i] * paramXTransform(this->m_data->old.multiTextureParamX[1]) + texPos[1].x, tys[i] * paramXTransform(this->m_data->old.multiTextureParamX[1]) + texPos[1].y); + record.particle[i].alphaCutoff = alphaCutoff; } } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index da96c9d27..0d3914480 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -32,6 +32,7 @@ struct ParticleBuffStruct { C2Vector textCoord0; //28 C2Vector textCoord1; //36 C2Vector textCoord2; //44 + float alphaCutoff; }; struct ParticleBuffStructQuad { @@ -56,7 +57,7 @@ struct CParticleMaterialFlags { class ParticleEmitter { public: - ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, M2Object *m2Object, HM2Geom geom, int txac_val_raw); + ParticleEmitter(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, M2Particle *particle, Exp2Record *exp2, M2Object *m2Object, HM2Geom geom, int txac_val_raw); ~ParticleEmitter() { delete generator; } @@ -85,6 +86,7 @@ class ParticleEmitter { M2Particle *m_data; + Exp2Record *m_exp2Data = nullptr; M2Object *m2Object; CRndSeed m_seed; @@ -150,7 +152,7 @@ class ParticleEmitter { mathfu::vec2 m_particleScale; uint32_t timedHeadCell; uint32_t timedTailCell; - float exp2_unk3; + float alphaCutoff; } m_ageDependentValues; int field_24; int field_28; @@ -187,8 +189,10 @@ class ParticleEmitter { void BuildQuadT3( - mathfu::vec3 &m0, mathfu::vec3 &m1, mathfu::vec3 &viewPos, mathfu::vec3 &color, float alpha, float texStartX, - float texStartY, mathfu::vec2 *texPos); + mathfu::vec3 &m0, mathfu::vec3 &m1, mathfu::vec3 &viewPos, mathfu::vec3 &color, float alpha, + float alphaCutoff, + float texStartX, + float texStartY, mathfu::vec2 *texPos); struct particleFrame { HGVertexBufferDynamic m_bufferVBO = nullptr; diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 42fe26479..72a104599 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -330,7 +330,9 @@ void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDepen void LiquidInstance::collectMeshes(std::vector &transparentMeshes) { //TODO: Get time and right mesh instance for animation - transparentMeshes.push_back(m_liquidMeshes[0]); + if (m_api->getConfig()->renderLiquid) { + transparentMeshes.push_back(m_liquidMeshes[0]); + } } mathfu::mat4 LiquidInstance::GetTexScrollMtx(int time, mathfu::vec2 scrollVec) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index b302cec81..17510ee7e 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1650,11 +1650,12 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector maxBatch ) continue; float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); - if ((finalTransparency < 0.0001)) + bool meshIsInvisible = finalTransparency < 0.0001; + if (m_api->getConfig()->discardInvisibleMeshes && meshIsInvisible) continue; HGM2Mesh mesh = std::get<0>(this->m_meshArray[i]); - if (finalTransparency < 0.999f && i < this->m_meshForcedTranspArray.size() && + if (!meshIsInvisible && finalTransparency < 0.999f && i < this->m_meshForcedTranspArray.size() && std::get<0>(this->m_meshForcedTranspArray[i]) != nullptr) { mesh = std::get<0>(this->m_meshForcedTranspArray[i]); } @@ -1726,7 +1727,11 @@ void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) txacVal = m_m2Geom->txacMParticle[i].value; } - auto emitter = std::make_unique(m_api, sceneRenderer,m_m2Geom->getM2Data()->particle_emitters.getElement(i), this, m_m2Geom, txacVal); + Exp2Record *exp2 = nullptr; + if (m_m2Geom->exp2 != nullptr) { + exp2 = m_m2Geom->exp2->content.getElement(i); + } + auto emitter = std::make_unique(m_api, sceneRenderer,m_m2Geom->getM2Data()->particle_emitters.getElement(i), exp2, this, m_m2Geom, txacVal); if (m_m2Geom->exp2 != nullptr && emitter->getGenerator() != nullptr) { auto exp2Rec = m_m2Geom->exp2->content.getElement(i); emitter->getGenerator()->getAniProp()->zSource = exp2Rec->zSource; diff --git a/wowViewerLib/src/engine/persistance/header/M2FileHeader.cpp b/wowViewerLib/src/engine/persistance/header/M2FileHeader.cpp index 21349dea7..831200ae3 100644 --- a/wowViewerLib/src/engine/persistance/header/M2FileHeader.cpp +++ b/wowViewerLib/src/engine/persistance/header/M2FileHeader.cpp @@ -8,8 +8,8 @@ void initEXP2(EXP2 *exp2) { exp2->content.initM2Array(exp2); for (int i = 0; i < exp2->content.size; i++) { Exp2Record *exp2Record = exp2->content.getElement(i); - exp2Record->unk3.timestamps.initM2Array(exp2); - exp2Record->unk3.values.initM2Array(exp2); + exp2Record->alphaCutoff.timestamps.initM2Array(exp2); + exp2Record->alphaCutoff.values.initM2Array(exp2); } } diff --git a/wowViewerLib/src/engine/persistance/header/M2FileHeader.h b/wowViewerLib/src/engine/persistance/header/M2FileHeader.h index a6528e596..4d719ef18 100644 --- a/wowViewerLib/src/engine/persistance/header/M2FileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/M2FileHeader.h @@ -425,9 +425,9 @@ struct TXAC { struct Exp2Record { float zSource; - float unk1; - float unk2; - M2PartTrack unk3; + float colorMult; + float alphaMult; + M2PartTrack alphaCutoff; }; struct EXP2 diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a2f280a43..77e87f810 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,75 +65,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,9 +194,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -212,21 +244,19 @@ const std::unordered_map> attributesPe { "aTexcoord0", 2}, { "aTexcoord1", 3}, { "aTexcoord2", 4}, + { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -234,7 +264,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -244,16 +274,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -268,25 +288,6 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -294,12 +295,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,1,64}, + {1,1,64}, {0,0,368}, - {0,2,16}, + {1,2,16}, }, { { + {0,0,1}, {2,2,1}, {0,0,0}, {0,0,0}, @@ -307,7 +309,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -326,16 +327,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,20 +346,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, - {1,8, "uTexture4"}, - {1,9, "uTexture5"}, - {1,10, "uTexture6"}, - {1,11, "uTexture7"}, - {1,12, "uTexture8"}, - {1,13, "uTexture9"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -370,16 +361,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,96}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,12 +380,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -406,12 +395,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,5,96}, - {0,0,368}, + {0,0,84}, }, { { @@ -426,15 +414,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,10, "uNormalTex"}, - {1,8, "uNoise"}, - {1,7, "uWhiteWater"}, - {1,6, "uMask"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,16 +431,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,64}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -480,11 +465,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,1,112}, + {0,0,368}, }, { { @@ -514,20 +500,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,4,16}, - {0,3,4096}, - {0,2,16384}, + {1,4,32}, {0,0,368}, - {0,1,64}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -537,13 +520,21 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9, "uBumpTexture"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, - {9,9,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -553,16 +544,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -588,15 +578,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -607,10 +597,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,16 +613,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {1,2,48}, + {0,0,368}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,14 +634,21 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,16 +658,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,48}, {0,0,368}, - {0,1,64}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -675,24 +675,14 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { - {1,9, "uAlphaTexture"}, - {1,10, "uLayerHeight0"}, - {1,11, "uLayerHeight1"}, - {1,12, "uLayerHeight2"}, - {1,13, "uLayerHeight3"}, - {1,5, "uLayer0"}, - {1,6, "uLayer1"}, - {1,7, "uLayer2"}, - {1,8, "uLayer3"}, }, { { {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,16 +693,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,368}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -738,15 +727,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -772,15 +761,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -791,11 +780,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,15 +795,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -826,12 +815,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,16 +830,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {1,1,16}, }, { { - {1,1,1}, {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -877,15 +864,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -911,15 +898,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -945,14 +932,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,11 +951,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +967,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1012,15 +1001,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1020,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,17 +1037,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,368}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {3,3,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1065,14 +1063,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1115,17 +1116,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,368}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {6,6,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,15 +1157,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1183,16 +1191,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {1,4,96}, + {0,0,368}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1202,12 +1211,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,22 +1227,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,7,64}, - {0,5,256}, - {0,4,4096}, - {0,2,256}, + {1,4,32}, {0,0,368}, - {0,1,64}, - {0,6,4096}, }, { { - {6,6,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1242,16 +1247,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6, "uTexture"}, - {1,7, "uTexture2"}, - {1,8, "uTexture3"}, - {1,9, "uTexture4"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, - {6,9,4}, {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1266,10 +1270,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,368}, - {0,1,64}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1277,7 +1282,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -1296,7 +1300,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1330,15 +1334,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,10 +1353,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,16 +1370,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {0,1,96}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1403,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {1,4,16}, + {1,3,4096}, + {0,0,368}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,14 +1424,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {2,5, "uTexture"}, }, { { - {3,4,2}, {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,14 +1440,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "ribbonShader.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1468,17 +1474,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, {0,0,368}, + {1,1,96}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1488,14 +1494,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, - {1,6, "uTexture2"}, - {1,7, "uTexture3"}, }, { { {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1506,23 +1509,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,3,16384}, - {0,1,64}, + {2,5,96}, {0,0,368}, - {0,4,4096}, - {0,5,256}, - {0,6,4096}, - {0,7,64}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {7,7,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {6,6,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1531,13 +1535,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,19 +1554,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, - {0,3,4096}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, {0,0,368}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {5,5,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1567,14 +1580,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "uTexture"}, + {3,9, "uBumpTexture"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1586,10 +1599,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1613,21 +1637,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1985,13 +2013,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2007,29 +2049,21 @@ const std::unordered_map +class IBufferChunkVersioned { +public: + using structureType = T; + + virtual ~IBufferChunkVersioned() = default; + virtual T &getObject(int version) = 0; + virtual void saveVersion(int version) = 0; +}; +#endif //AWEBWOWVIEWERCPP_IBUFFERVERSIONED_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h new file mode 100644 index 000000000..cf498a63a --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -0,0 +1,85 @@ +// +// Created by Deamon on 7/2/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVERSIONEDVLK_H +#define AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVERSIONEDVLK_H + + +#include "../../interface/buffers/IBufferChunk.h" +#include "GBufferVLK.h" +#include "../../interface/buffers/IBufferVersioned.h" + +template +class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVersioned { +public: + GBufferChunkDynamicVersionedVLK(const HGDeviceVLK &device, int versionAmount, const std::shared_ptr &mainBuffer, int realSize = -1) : m_device(device) { + m_realSize = realSize; + + if (m_realSize < 0) + m_realSize = sizeof(T); + + subBufferVersions.resize(versionAmount); + for (auto &subBuffers : subBufferVersions) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + auto subBuffer = mainBuffer->getSubBuffer(m_realSize, sizeof(T)); + subBuffers[i] = subBuffer; + } + } + + iteratorUnique = subBufferVersions[0][0]->addOnHandleChange([&]() -> void { + this->executeOnChange(); + }); + } + + ~GBufferChunkDynamicVersionedVLK() final { + subBufferVersions[0][0]->eraseOnHandleChange(iteratorUnique); + } + void uploadData(const void *, int length) override { + }; + void *getPointer() override { + auto index = m_device->getUpdateFrameNumber(); + return subBufferVersions[m_currentVersion][index]->getPointer(); + }; + void save(int length) override{ + auto index = m_device->getUpdateFrameNumber(); + subBufferVersions[m_currentVersion][index]->save(m_realSize); + }; + VkBuffer getGPUBuffer() override { + auto index = m_device->getUpdateFrameNumber(); + return subBufferVersions[m_currentVersion][index]->getGPUBuffer(); + } + size_t getOffset() override { + auto index = m_device->getUpdateFrameNumber(); + return subBufferVersions[m_currentVersion][index]->getOffset(); + } + + size_t getSize() override { + return m_realSize; + } + void setCurrentVersion(int version) { + if (version > subBufferVersions.size()) throw "wrong version"; + m_currentVersion = version; + } + + T &getObject(int version) override { + if (version > subBufferVersions.size()) throw "wrong version"; + auto index = m_device->getUpdateFrameNumber(); + return *(T*)subBufferVersions[version][index]->getPointer(); + }; + void saveVersion(int version) { + auto index = m_device->getUpdateFrameNumber(); + subBufferVersions[version][index]->save(m_realSize); + } + +private: + HGDeviceVLK m_device; + int m_realSize = 0; + int m_currentVersion = 0; + void *ptr = nullptr; + std::vector, IDevice::MAX_FRAMES_IN_FLIGHT>> subBufferVersions; + std::unique_ptr iteratorUnique = nullptr; +}; + + +#endif //AWEBWOWVIEWERCPP_GBUFFERCHUNKDYNAMICVERSIONEDVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 414215f37..c560626c1 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -46,12 +46,6 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de m_firstUpdate = false; m_dynamicBufferIndexes = dynamicBufferIndexes; - -// m_updateBitSet |= updatedBindsBitSet; -// -// for (int i = 0; updatedBindsBitSet.size(); i++) { -// m_updatesLeft[i] = GDeviceVLK::MAX_FRAMES_IN_FLIGHT; -// } } void GDescriptorSet::getDynamicOffsets(std::vector &dynamicOffsets) { diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 153384a76..0b9b0637c 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -176,9 +176,10 @@ void GShaderPermutationVLK::createShaderLayout() { } void GShaderPermutationVLK::createPipelineLayout() { - std::array descLayouts = { - this->getDescriptorLayout(0)->getSetLayout(), - this->getDescriptorLayout(1)->getSetLayout() + std::vector descLayouts; + descLayouts.reserve(combinedShaderLayout.setLayouts.size()); + for (int i = 0; i < combinedShaderLayout.setLayouts.size(); i++) { + descLayouts.push_back(this->getDescriptorLayout(i)->getSetLayout()); }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index bfec13638..0e44441ba 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -65,7 +65,7 @@ class GShaderPermutationVLK : public IShaderPermutation { VkPipelineLayout pipelineLayout; - std::array, MAX_SHADER_DESC_SETS> descriptorSetLayouts; + std::array, MAX_SHADER_DESC_SETS> descriptorSetLayouts = {}; std::shared_ptr m_device; private: diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 2781ff896..63e643c94 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -44,11 +44,13 @@ class Config { bool renderAdt = true; bool renderWMO = true; bool renderM2 = true; + bool renderLiquid = true; bool renderBSP = false; bool renderPortals = false; bool renderAntiPortals = false; bool renderPortalsIgnoreDepth = false; bool usePortalCulling = true; + bool discardInvisibleMeshes = true; bool ignoreADTHoles = false; diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 742437d1e..54e3a7875 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -16,6 +16,7 @@ struct ViewPortDimensions{ template struct FrameInputParams { std::shared_ptr frameParameters; + std::shared_ptr screenShotParameters; //Time advance animTime_t delta = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index fddfe5a3a..bec1a587d 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -106,7 +106,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende m_config->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); } -void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, +void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, bool isVulkan, @@ -120,7 +120,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrgetObject(); + auto &blockPSVS = sceneWideChunk->getObject(0); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; if (isVulkan) { blockPSVS.uPMatrix = vulkanMatrixFix*renderingMatrices->perspectiveMat; @@ -177,5 +177,5 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrSunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); - sceneWideChunk->save(); + sceneWideChunk->saveVersion(0); } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index bbb8678e3..bed8f6782 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -12,6 +12,7 @@ #include "MapSceneParams.h" #include "MapScenePlan.h" +#include "../../gapi/interface/buffers/IBufferVersioned.h" #include "../../engine/shader/ShaderDefinitions.h" #include "../../engine/algorithms/FrameCounter.h" @@ -60,6 +61,7 @@ static const std::vector staticM2ParticleBindings = {{ {+m2ParticleShader::Attribute::aTexcoord0, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord0)}, {+m2ParticleShader::Attribute::aTexcoord1, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord1)}, {+m2ParticleShader::Attribute::aTexcoord2, 2, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, textCoord2)}, + {+m2ParticleShader::Attribute::aAlphaCutoff, 1, GBindingType::GFLOAT, false, sizeof(ParticleBuffStruct), offsetof(ParticleBuffStruct, alphaCutoff)}, }}; static std::vector staticM2RibbonBindings = {{ @@ -98,7 +100,7 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public const std::shared_ptr> &htransparentMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes); - void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, + void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const HCameraMatrices &renderingMatrices, const HFrameDependantData &fdd, bool isVulkan, diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index df875cf1e..a362f2c24 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -53,6 +53,7 @@ struct WaterMaterialTemplate { class IM2ModelData { public: + virtual ~IM2ModelData() = default; std::shared_ptr> m_placementMatrix = nullptr; std::shared_ptr> m_bonesData = nullptr; std::shared_ptr> m_colors = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index c037b8a2c..c7ef84eef 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -12,9 +12,17 @@ #include "materials/IMaterialInstance.h" #include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../../frame/FrameProfile.h" #include +static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; +static const ShaderConfig m2ForwardShaderConfig = { + { + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}, + {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} +}}; + MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer(1024*1024); @@ -78,7 +86,13 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C createFrameBuffers(); - sceneWideChunk = std::make_shared>(hDevice, uboBuffer); + sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + .createDescriptorSet(0, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, sceneWideChunk); + sceneWideDS = ds; + }); } // ------------------ @@ -218,11 +232,7 @@ HGIndexBuffer MapSceneRenderForwardVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; -static const ShaderConfig m2ForwardShaderConfig = {{ - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}, - {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} -}}; + std::shared_ptr MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { @@ -232,13 +242,13 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, *vertexFragmentData) .ubo(2, *fragmentData); }) - .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&adtMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, adtMaterialTemplate.textures[0]) .texture(6, adtMaterialTemplate.textures[1]) @@ -268,18 +278,13 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .createDescriptorSet(2, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)) - .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)) - .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)) - .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)) .ubo(7, *vertexFragmentData); }) - .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) .texture(7, m2MaterialTemplate.textures[1]) @@ -308,16 +313,14 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .createDescriptorSet(2, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)) .ubo(4, *vertexData) .ubo(5, *fragmentData); }) - .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) .texture(7, m2MaterialTemplate.textures[1]) @@ -342,12 +345,12 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, m2ParticleMatTemplate.textures[0]) .texture(6, m2ParticleMatTemplate.textures[1]) @@ -369,13 +372,13 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, m2RibbonMaterialTemplate.textures[0]); }) @@ -399,14 +402,14 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(modelWide)) .ubo(2, *l_vertexData) .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, wmoMaterialTemplate.textures[0]) .texture(6, wmoMaterialTemplate.textures[1]) @@ -434,13 +437,13 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, BufferChunkHelperVLK::cast(modelWide)) .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&waterMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, waterMaterialTemplate.texture); }) @@ -463,9 +466,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, *skyColors); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { @@ -481,9 +484,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) .ubo(1, *materialPS); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { @@ -494,7 +497,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( } std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { - auto result = std::make_shared(); + auto result = std::make_shared(); DynamicBufferChunkHelperVLK::create(m_device, uboBuffer, result->m_placementMatrix); BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); @@ -503,6 +506,18 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(result->m_placementMatrix)) + .ubo(2, BufferChunkHelperVLK::cast(result->m_modelFragmentData)) + .ubo(3, BufferChunkHelperVLK::cast(result->m_bonesData)) + .ubo(4, BufferChunkHelperVLK::cast(result->m_colors)) + .ubo(5, BufferChunkHelperVLK::cast(result->m_textureWeights)) + .ubo(6, BufferChunkHelperVLK::cast(result->m_textureMatrices)); + result->placementMatrixDS = ds; + }); + return result; } @@ -587,6 +602,8 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); + m_lastCreatedPlan = framePlan; + //The portal meshes are created here. Need to call doPostLoad before CollectMeshes mapScene->doPostLoad(l_this, framePlan); @@ -627,11 +644,6 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // Upload stuff // --------------------- { - { - std::string debugMess = "sceneWideChunk = " + std::to_string( - DynamicBufferChunkHelperVLK::cast(l_this->sceneWideChunk)->getOffset()); - auto debugLabel = uploadCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - } ZoneScopedN("submit buffers"); uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -656,6 +668,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // ---------------------- // Draw meshes // ---------------------- + l_this->sceneWideChunk->setCurrentVersion(0); { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, @@ -722,7 +735,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { - return nullptr; + return m_lastCreatedPlan; } HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 44340e3e0..3876e56bd 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -8,6 +8,7 @@ #include "../MapSceneRenderer.h" #include "../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" @@ -125,12 +126,14 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_drawQuadVao = nullptr; - std::shared_ptr> sceneWideChunk; + std::shared_ptr> sceneWideChunk; + std::shared_ptr sceneWideDS = nullptr; std::shared_ptr m_renderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + std::shared_ptr m_lastCreatedPlan = nullptr; HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptyADTVAO = nullptr; @@ -144,5 +147,11 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { void createFrameBuffers(); }; +class IM2ModelDataVLK : public IM2ModelData { +public: + ~IM2ModelDataVLK() override = default; + std::shared_ptr placementMatrixDS; +}; + #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H From b8b3b9f1badcbd09ef4486d59c9bc577f8e90fac Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Jul 2023 22:52:18 +0300 Subject: [PATCH 095/212] - small optimization for dynamic UBOs --- .../commandBufferRecorder/CommandBufferRecorder.cpp | 7 ++++--- .../src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp | 9 ++++++--- .../src/gapi/vulkan/descriptorSets/GDescriptorSet.h | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 15f189b1a..a246de4c0 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -90,14 +90,15 @@ void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t b constexpr uint32_t vkDescCnt = 1; - std::vector dynamicOffsets; - pDescriptorSet->getDynamicOffsets(dynamicOffsets); + std::array dynamicOffsets; + uint32_t dynamicOffsetsSize; + pDescriptorSet->getDynamicOffsets(dynamicOffsets, dynamicOffsetsSize); vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, m_currentPipeline->getLayout(), bindIndex, vkDescCnt, &vkDescSet, - dynamicOffsets.size(), dynamicOffsets.size() > 0 ? dynamicOffsets.data() : nullptr); + dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets.data() : nullptr); m_currentDescriptorSet[bindIndex] = pDescriptorSet; } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index c560626c1..3fe8929b9 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -48,13 +48,16 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de m_dynamicBufferIndexes = dynamicBufferIndexes; } -void GDescriptorSet::getDynamicOffsets(std::vector &dynamicOffsets) { - for (int i = 0; i < m_dynamicBufferIndexes.size(); i++) { +void GDescriptorSet::getDynamicOffsets(std::array &dynamicOffsets, uint32_t &dynamicOffsetsSize) { + dynamicOffsetsSize = m_dynamicBufferIndexes.size(); + + assert(dynamicOffsetsSize <= 16); + for (int i = 0; i < dynamicOffsetsSize; i++) { auto &descriptor = boundDescriptors[m_dynamicBufferIndexes[i]]; assert(descriptor->descType == DescriptorRecord::DescriptorRecordType::UBODynamic); - dynamicOffsets.push_back(descriptor->buffer->getOffset()); + dynamicOffsets[i] = (descriptor->buffer->getOffset()); } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index f4cfb0496..2212913ac 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -29,7 +29,7 @@ class GDescriptorSet : public std::enable_shared_from_this { const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} - void getDynamicOffsets(std::vector &dynamicOffsets); + void getDynamicOffsets(std::array &dynamicOffsets, uint32_t &dynamicOffsetsSize); From af8b75377213cd40d5b0c81f65abfe369de9a84e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 15 Aug 2023 22:28:04 +0300 Subject: [PATCH 096/212] - temp commit --- src/main.cpp | 1 + wowViewerLib/CMakeLists.txt | 1 + wowViewerLib/shaders/CMakeLists.txt | 9 +- .../engine/objects/liquid/LiquidInstance.cpp | 4 +- .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 1154 ++++++++--------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 6 +- .../descriptorSets/GDescriptorSetLayout.cpp | 15 +- .../descriptorSets/GDescriptorSetLayout.h | 3 +- .../src/gapi/vulkan/shaders/ShaderConfig.h | 5 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 18 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 241 ++-- .../vulkan/MapSceneRenderVisBufferVLK.h | 28 +- 13 files changed, 805 insertions(+), 684 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5ba8de361..06ac064b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -450,6 +450,7 @@ int main(){ std::cout << "corrected uiScale for monitor dimensions = " << uiScale << std::endl; } + uiScale = 1.0; frontendUI->setUIScale(uiScale); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index d427c0195..05221ab15 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -15,6 +15,7 @@ option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) set(LINK_TRACY 1) +set(COMPILE_SHADER_WITH_DEBUG 1) option(EMSCRIPTEN_SIMD "Enable SIMD for Emscripten " OFF) diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 13f2dffcd..632e492af 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -4,6 +4,13 @@ else() set(GLSL_TARGET_FOLDER ${CMAKE_BINARY_DIR}) endif() + +if (COMPILE_SHADER_WITH_DEBUG) + set(SHADER_DEBUG_FLAG "-g") +else() + set(SHADER_DEBUG_FLAG "") +endif() + set(APP_RUN_PREFIX "") if (EMSCRIPTEN) set(APP_RUN_PREFIX node --experimental-wasm-simd) @@ -99,7 +106,7 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) add_custom_command( OUTPUT ${SPIRV_NonOpt} COMMAND ${CMAKE_COMMAND} -E make_directory "${destDir}" - COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_GLSL_VALIDATOR} -V ${srcTemplatePath} -o ${SPIRV_NonOpt} + COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_GLSL_VALIDATOR} -V ${SHADER_DEBUG_FLAG} ${srcTemplatePath} -o ${SPIRV_NonOpt} DEPENDS ${srcTemplatePath} glslangValidator ${commonFiles}) if(SPIRV_OPT_APP) diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 72a104599..50fb10304 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -131,10 +131,8 @@ LiquidInstance::getInfoFromDatabase(int liquid_object_or_lvf, int liquid_type, b m_api->databaseHandler->getLiquidTypeData(liquid_type, m_liqMatAndType, m_liquidTextureData); m_liqMatAndType.matLVF = liquid_object_or_lvf; - //assert(liquid_object_or_lvf == liqMatAndType.matLVF); } -// assert(liquidVertexFormat == liqMatAndType.matLVF); -// liquidVertexFormat = liqMatAndType.matLVF; + generateTexCoordsFromPos = getLiquidSettings(liquid_object_or_lvf, liquid_type, m_liqMatAndType.materialID, diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 648b23d14..3138a2c35 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1302,9 +1302,7 @@ std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) if (shaderId >= MAX_WMO_SHADERS) { shaderId = 0; } -// if (shaderId == 23) { -// std::cout << "Hello" << std::endl; -// } + int pixelShader = wmoMaterialShader[shaderId].pixelShader; int vertexShader = wmoMaterialShader[shaderId].vertexShader; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 77e87f810..bfc25f63f 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -65,15 +65,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -89,51 +83,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -143,41 +143,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -194,41 +194,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -247,16 +215,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -264,7 +235,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -274,6 +245,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -288,6 +269,25 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { @@ -327,16 +327,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {1,4,32}, + {0,0,368}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,12 +347,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -361,16 +371,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "waterShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,96}, + {0,0,368}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -380,12 +391,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -395,17 +407,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {2,5,96}, + {0,0,368}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {6,6,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -414,15 +433,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -431,16 +452,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,368}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -465,12 +487,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,368}, + {0,0,144}, }, { { @@ -500,42 +521,40 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, {0,0,368}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { {0,0,1}, + {5,5,1}, {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -544,15 +563,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -578,15 +598,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -597,11 +617,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -613,18 +632,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "ffxglow.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,368}, - {1,1,64}, + {0,4,16}, }, { { - {0,0,1}, - {1,1,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -634,21 +651,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -658,10 +668,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,368}, {1,1,64}, }, @@ -678,12 +689,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -693,15 +713,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -727,15 +748,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -761,15 +782,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,12}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -780,10 +801,11 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,16 +817,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -815,10 +836,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -830,15 +853,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "drawPoints.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, + {0,1,12}, }, { { - {0,0,0}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -846,6 +868,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -864,15 +887,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -898,15 +921,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -932,15 +955,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "skyConus.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,0,368}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -951,12 +974,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -967,16 +989,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,0,368}, + {1,1,16}, }, { { - {0,0,1}, {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1001,15 +1023,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,128}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1020,13 +1042,11 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1037,24 +1057,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,368}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,4,32}, }, { { - {0,0,1}, - {3,3,1}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1063,17 +1076,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,24 +1126,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,368}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {6,6,1}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1157,15 +1160,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,2,16}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1191,17 +1194,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,368}, + {0,1,80}, }, { { - {0,0,1}, - {4,4,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1211,13 +1213,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1227,18 +1228,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,368}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { {0,0,1}, - {4,4,1}, - {0,0,0}, + {3,3,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1247,16 +1254,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1300,7 +1308,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "drawPortalShader.vert.spv", { ShaderStage::Vertex, { @@ -1334,15 +1342,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,12 +1361,10 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1370,15 +1376,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "skyConus.vert.spv", { ShaderStage::Vertex, { + {0,0,368}, + {1,1,96}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1403,18 +1411,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, - {0,0,368}, + {0,2,168}, }, { { - {0,0,1}, - {3,3,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,13 +1430,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,5, "uTexture"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1440,15 +1447,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1474,17 +1480,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,368}, - {1,1,96}, }, { { {0,0,1}, - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1494,12 +1500,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1509,24 +1518,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,5,96}, - {0,0,368}, + {1,3,16384}, {1,1,64}, + {0,0,368}, {1,2,256}, - {1,3,16384}, {1,4,4096}, {1,5,256}, {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, {6,6,1}, - {5,5,1}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,17 +1544,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1554,24 +1559,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, + {1,4,16}, + {1,3,4096}, {0,0,368}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { {0,0,1}, - {5,5,1}, - {4,4,1}, + {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1580,14 +1580,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {3,9, "uBumpTexture"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1599,21 +1599,35 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1637,6 +1651,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"waterfallShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 6, { + {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_1_4_colors[0]", true, 0, 1, 4, 256}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + 3, { + {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, } }, - }}, - {"drawDepthShader", { { 2, { - {"_0_2_drawDepth", false, 0, 1, 1, 0}, - {"_0_2_uFarPlane", true, 4, 1, 1, 0}, - {"_0_2_uNearPlane", true, 8, 1, 1, 0}, + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, } }, - }}, - {"adtShader", { { - 2, { - {"_1_2_scaleFactorPerLayer", true, 0, 1, 4, 0}, - {"_1_2_animation_rotationPerLayer", false, 16, 1, 4, 0}, - {"_1_2_animation_speedPerLayer", false, 32, 1, 4, 0}, + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -2088,25 +2083,29 @@ const std::unordered_map{}(rec.second) ^ hash{}(rec.first); + for (const auto &rec : k.shaderConfig.typeOverrides) + for (const auto &rec2 : rec.second) + mapHash ^= hash{}(rec2.second) << 4 ^ hash{}(rec2.first) << 4 ^ hash{}(rec.first) << 4; + return hash{}(k.name) ^ mapHash; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 31ac12c03..a6d83aec8 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -10,7 +10,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaDatas, int setIndex, - const std::unordered_map &typeOverrides) : m_device(device) { + const DescTypeOverride &typeOverrides) : m_device(device) { //Create Layout auto &shaderLayoutBindings = m_shaderLayoutBindings; @@ -36,10 +36,15 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr if (uboBinding.set != setIndex) continue; auto uniformType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - if (typeOverrides.find(uboBinding.binding) != typeOverrides.end()) { - auto overrideType = typeOverrides.at(uboBinding.binding); - assert(overrideType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); - uniformType = overrideType; + { + if (typeOverrides.find(uboBinding.set) != typeOverrides.end()) { + auto &setTypeOverrides = typeOverrides.at(uboBinding.set); + if (setTypeOverrides.find(uboBinding.binding) != setTypeOverrides.end()) { + auto overrideType = setTypeOverrides.at(uboBinding.binding); + assert(overrideType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); + uniformType = overrideType; + } + } } auto it = shaderLayoutBindings.find(uboBinding.binding); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index b671ff28f..084021aad 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -14,6 +14,7 @@ class IDeviceVulkan; #include "../context/vulkan_context.h" #include "../IDeviceVulkan.h" #include "../../../engine/shader/ShaderDefinitions.h" +#include "../shaders/ShaderConfig.h" class GDescriptorSetLayout { public: @@ -22,7 +23,7 @@ class GDescriptorSetLayout { GDescriptorSetLayout(const std::shared_ptr &device, const std::vector &metaData, int setIndex, - const std::unordered_map &typeOverrides); + const DescTypeOverride &typeOverrides); ~GDescriptorSetLayout(); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 6e1c44a82..11b0ebcaa 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -8,8 +8,11 @@ #include #include "../context/vulkan_context.h" +//Per DescSet -> per binding point +typedef std::unordered_map> DescTypeOverride; + struct ShaderConfig { - std::unordered_map typeOverrides; + DescTypeOverride typeOverrides; }; #endif //AWEBWOWVIEWERCPP_SHADERCONFIG_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index c7ef84eef..a61d07491 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -16,11 +16,21 @@ #include "../../frame/FrameProfile.h" #include -static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; +static const ShaderConfig forwardShaderConfig = { + { + {0, { + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }} + } +}; static const ShaderConfig m2ForwardShaderConfig = { { - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}, - {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {0, { + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }}, + {1, { + {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }} }}; MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : @@ -639,7 +649,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha renderSky, skyMesh, skyMesh0x4, + mapScene, framePlan, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + // --------------------- // Upload stuff // --------------------- diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index a6acd0cf8..abc621d16 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -12,9 +12,27 @@ #include "materials/IMaterialInstance.h" #include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../../frame/FrameProfile.h" #include +static const ShaderConfig forwardShaderConfig = { + { + {0, { + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }} + } +}; +static const ShaderConfig m2ForwardShaderConfig = { + { + {0, { + {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }}, + {1, { + {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + }} + }}; + MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer(1024*1024); @@ -22,6 +40,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic vboM2Buffer = m_device->createVertexBuffer(1024*1024); vboPortalBuffer = m_device->createVertexBuffer(1024*1024); vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer(1024*1024); vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); vboWMOBuffer = m_device->createVertexBuffer(1024*1024); vboWaterBuffer = m_device->createVertexBuffer(1024*1024); @@ -59,6 +78,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); + m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); @@ -69,14 +89,20 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, // VK_SAMPLE_COUNT_1_BIT, - sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), - true, false); + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + true, false); glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); createFrameBuffers(); - sceneWideChunk = std::make_shared>(hDevice, uboBuffer); + sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + .createDescriptorSet(0, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, sceneWideChunk); + sceneWideDS = ds; + }); } // ------------------ @@ -127,6 +153,15 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2ParticleVAO(HGVertexB return m2ParticleVAO; } +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2RibbonVAO = m_device->createVertexBufferBindings(); + m2RibbonVAO->addVertexBufferBinding(vertexBuffer, staticM2RibbonBindings); + m2RibbonVAO->setIndexBuffer(indexBuffer); + + return m2RibbonVAO; +}; + HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto waterVAO = m_device->createVertexBufferBindings(); @@ -168,6 +203,9 @@ HGVertexBuffer MapSceneRenderVisBufferVLK::createM2VertexBuffer(int sizeInBytes) HGVertexBuffer MapSceneRenderVisBufferVLK::createM2ParticleVertexBuffer(int sizeInBytes) { return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); } +HGVertexBuffer MapSceneRenderVisBufferVLK::createM2RibbonVertexBuffer(int sizeInBytes) { + return vboM2RibbonBuffer->getSubBuffer(sizeInBytes); +} HGIndexBuffer MapSceneRenderVisBufferVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); @@ -204,7 +242,7 @@ HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) return iboBuffer->getSubBuffer(sizeInBytes); } -static const ShaderConfig forwardShaderConfig = {{{0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}}}; + std::shared_ptr MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { @@ -214,13 +252,13 @@ MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTe auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, vertexFragmentData->getSubBuffer()) - .ubo(2, fragmentData->getSubBuffer()); + .ubo(1, *vertexFragmentData) + .ubo(2, *fragmentData); }) - .createDescriptorSet(1, [&adtMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&adtMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, adtMaterialTemplate.textures[0]) .texture(6, adtMaterialTemplate.textures[1]) @@ -248,20 +286,15 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .createDescriptorSet(2, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_modelFragmentData)->getSubBuffer()) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(4, BufferChunkHelperVLK::cast(m2ModelData->m_colors)->getSubBuffer()) - .ubo(5, BufferChunkHelperVLK::cast(m2ModelData->m_textureWeights)->getSubBuffer()) - .ubo(6, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) - .ubo(7, vertexFragmentData->getSubBuffer()); + .ubo(7, *vertexFragmentData); }) - .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) .texture(7, m2MaterialTemplate.textures[1]) @@ -282,24 +315,22 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr } std::shared_ptr MapSceneRenderVisBufferVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, - const PipelineTemplate &pipelineTemplate, - const M2WaterfallMaterialTemplate &m2MaterialTemplate) { + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto vertexData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .createDescriptorSet(2, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(m2ModelData->m_placementMatrix)->getSubBuffer()) - .ubo(2, BufferChunkHelperVLK::cast(m2ModelData->m_bonesData)->getSubBuffer()) - .ubo(3, BufferChunkHelperVLK::cast(m2ModelData->m_textureMatrices)->getSubBuffer()) - .ubo(4, vertexData->getSubBuffer()) - .ubo(5, fragmentData->getSubBuffer()); + .ubo(4, *vertexData) + .ubo(5, *fragmentData); }) - .createDescriptorSet(1, [&m2MaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) .texture(7, m2MaterialTemplate.textures[1]) @@ -324,12 +355,12 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Particl auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&m2ParticleMatTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, m2ParticleMatTemplate.textures[0]) .texture(6, m2ParticleMatTemplate.textures[1]) @@ -342,6 +373,32 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Particl return material; } +std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + auto &l_m2ModelData = m2ModelData; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) + .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ubo(4, *l_fragmentData); + }) + .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(5, m2RibbonMaterialTemplate.textures[0]); + }) + .toMaterial([l_fragmentData](IM2RibbonMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +}; + std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOWideChunk() { return std::make_shared>(uboBuffer); } @@ -355,14 +412,14 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(cons auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) - .ubo(2, l_vertexData->getSubBuffer()) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(1, BufferChunkHelperVLK::cast(modelWide)) + .ubo(2, *l_vertexData) + .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&wmoMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, wmoMaterialTemplate.textures[0]) .texture(6, wmoMaterialTemplate.textures[1]) @@ -383,20 +440,20 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(cons } std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial(const std::shared_ptr> &modelWide, - const PipelineTemplate &pipelineTemplate, - const WaterMaterialTemplate &waterMaterialTemplate) { + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) { auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, BufferChunkHelperVLK::cast(modelWide)->getSubBuffer()) - .ubo(4, l_fragmentData->getSubBuffer()); + .ubo(1, BufferChunkHelperVLK::cast(modelWide)) + .ubo(4, *l_fragmentData); }) - .createDescriptorSet(1, [&waterMaterialTemplate](std::shared_ptr &ds) { + .createDescriptorSet(2, [&waterMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(5, waterMaterialTemplate.texture); }) @@ -419,10 +476,10 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMater auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, skyColors->getSubBuffer()); + .ubo(1, *skyColors); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { instance->m_skyColors = skyColors; @@ -437,10 +494,10 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) - .createDescriptorSet(0, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, DynamicBufferChunkHelperVLK::cast(l_sceneWideChunk)) - .ubo(1, materialPS->getSubBuffer()); + .ubo(1, *materialPS); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { instance->m_materialPS = materialPS; @@ -450,15 +507,27 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria } std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { - auto result = std::make_shared(); + auto result = std::make_shared(); - BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); + DynamicBufferChunkHelperVLK::create(m_device, uboBuffer, result->m_placementMatrix); BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(result->m_placementMatrix)) + .ubo(2, BufferChunkHelperVLK::cast(result->m_modelFragmentData)) + .ubo(3, BufferChunkHelperVLK::cast(result->m_bonesData)) + .ubo(4, BufferChunkHelperVLK::cast(result->m_colors)) + .ubo(5, BufferChunkHelperVLK::cast(result->m_textureWeights)) + .ubo(6, BufferChunkHelperVLK::cast(result->m_textureMatrices)); + result->placementMatrixDS = ds; + }); + return result; } @@ -505,7 +574,7 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { } std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::shared_ptr> &frameInputParams, - const std::shared_ptr &framePlan) { + const std::shared_ptr &framePlan) { ZoneScoped; @@ -543,15 +612,19 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); + m_lastCreatedPlan = framePlan; + + //The portal meshes are created here. Need to call doPostLoad before CollectMeshes + mapScene->doPostLoad(l_this, framePlan); + // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { - collectMeshes(framePlan, opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes); + collectMeshes(framePlan, opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes); // } // ); - mapScene->doPostLoad(l_this, framePlan); mapScene->update(framePlan); mapScene->updateBuffers(framePlan); glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); @@ -572,20 +645,17 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; return createRenderFuncVLK([opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes, - renderSky, - skyMesh, - skyMesh0x4, - l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + mapScene, framePlan, + l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + // --------------------- // Upload stuff // --------------------- { - { - std::string debugMess = "sceneWideChunk = " + std::to_string( - DynamicBufferChunkHelperVLK::cast(l_this->sceneWideChunk)->getOffset()); - auto debugLabel = uploadCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - } ZoneScopedN("submit buffers"); uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -595,6 +665,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->vboM2Buffer); uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); @@ -609,6 +680,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // ---------------------- // Draw meshes // ---------------------- + l_this->sceneWideChunk->setCurrentVersion(0); { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, @@ -632,7 +704,9 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s for (auto const &mesh: *skyOpaqueMeshes) { MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } - for (auto const &mesh: *skyTransparentMeshes) { + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); + // std::string debugMess = // "Drawing mesh " // " meshType = " + std::to_string((int)mesh->getMeshType()) + @@ -641,7 +715,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } if (renderSky && skyMesh0x4) @@ -649,15 +723,16 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s } { ZoneScopedN("submit transparent"); - for (auto const &mesh: *transparentMeshes) { + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); +// +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); // -// std::string debugMess = -// "Drawing mesh " -// " meshType = " + std::to_string((int)mesh->getMeshType()) + -// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + -// " sortDistance = " + std::to_string(mesh->getSortDistance()) + -// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); - // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); @@ -666,13 +741,13 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s } l_this->glowPass->doPass(frameBufCmd, swapChainCmd, - l_this->m_device->getSwapChainRenderPass(), - frameInputParams->viewPortDimensions); + l_this->m_device->getSwapChainRenderPass(), + frameInputParams->viewPortDimensions); }); } std::shared_ptr MapSceneRenderVisBufferVLK::getLastCreatedPlan() { - return nullptr; + return m_lastCreatedPlan; } HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index dc7021aae..698bc2837 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -8,13 +8,14 @@ #include "../MapSceneRenderer.h" #include "../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { public: - explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); - ~MapSceneRenderVisBufferVLK() override = default; + explicit MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderForwardVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType); @@ -28,6 +29,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; + HGVertexBufferBindings createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; @@ -39,6 +41,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; + HGVertexBuffer createM2RibbonVertexBuffer(int sizeInBytes) override; HGVertexBuffer createADTVertexBuffer(int sizeInBytes) override; HGIndexBuffer createADTIndexBuffer(int sizeInBytes) override; @@ -62,12 +65,16 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) override; std::shared_ptr createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, - const PipelineTemplate &pipelineTemplate, - const M2WaterfallMaterialTemplate &m2MaterialTemplate) override; + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) override; std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) override; + std::shared_ptr> createWMOWideChunk() override; std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, @@ -99,6 +106,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; + HGBufferVLK vboM2RibbonBuffer; HGBufferVLK vboPortalBuffer; HGBufferVLK vboAdtBuffer; @@ -118,15 +126,19 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGVertexBufferBindings m_drawQuadVao = nullptr; - std::shared_ptr> sceneWideChunk; + std::shared_ptr> sceneWideChunk; + std::shared_ptr sceneWideDS = nullptr; std::shared_ptr m_renderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + std::shared_ptr m_lastCreatedPlan = nullptr; + HGVertexBufferBindings m_emptyM2VAO = nullptr; HGVertexBufferBindings m_emptyADTVAO = nullptr; HGVertexBufferBindings m_emptyM2ParticleVAO = nullptr; + HGVertexBufferBindings m_emptyM2RibbonVAO = nullptr; HGVertexBufferBindings m_emptyPortalVAO = nullptr; HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; @@ -135,5 +147,11 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { void createFrameBuffers(); }; +class IM2ModelDataVisVLK : public IM2ModelData { +public: + ~IM2ModelDataVisVLK() override = default; + std::shared_ptr placementMatrixDS; +}; + #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H From 03b65556d564ef64cad85bc43946aed8d6916ce5 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 20 Aug 2023 00:57:32 +0300 Subject: [PATCH 097/212] - temp commit for some shader stuff - VisBuffer in process --- src/ui/FrontendUI.cpp | 127 ++-- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- wowViewerLib/CMakeLists.txt | 2 + wowViewerLib/shaders/CMakeLists.txt | 150 ++--- .../glsl/common/commonLightFunctions.glsl | 5 +- .../common/commonM2IndirectDescriptorSet.glsl | 45 ++ .../glsl/common/commonWMOMaterial.glsl | 38 +- .../shaders/glsl/visBuffer/m2Shader.frag | 198 ++++++ .../shaders/glsl/visBuffer/m2Shader.vert | 84 +++ .../shaders/src/spirv/dumpShaderFields.h | 102 +++- .../shaders/src/spirv/spirv_refl_main.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 568 +++++++++++------- .../src/gapi/UniformBufferStructures.h | 27 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 7 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 5 +- .../src/gapi/vulkan/buffers/CBufferChunkVLK.h | 10 + .../vulkan/buffers/GBufferChunkDynamicVLK.h | 4 + .../buffers/GBufferChunkDynamicVersionedVLK.h | 5 + .../src/gapi/vulkan/buffers/GBufferVLK.h | 8 + .../src/gapi/vulkan/buffers/IBufferVLK.h | 1 + .../vulkan/descriptorSets/DescriptorRecord.h | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 39 +- .../descriptorSets/GDescriptorSetLayout.h | 1 + .../vulkan/materials/ISimpleMaterialVLK.h | 7 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 37 +- .../vulkan/materials/MaterialBuilderVLK.h | 20 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 11 +- .../src/gapi/vulkan/shaders/ShaderConfig.h | 1 + .../mapScene/materials/IMaterialStructs.h | 9 + .../vulkan/MapSceneRenderForwardVLK.cpp | 3 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 94 ++- .../vulkan/MapSceneRenderVisBufferVLK.h | 18 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 4 +- 33 files changed, 1195 insertions(+), 441 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 5517c08d9..3f4ea2f91 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -181,7 +181,7 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current blp vulkan textures loaded %d", l_blpTexturesVulkanLoaded); ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); - if (m_sceneRenderer && false) { + if (m_sceneRenderer) { auto mapPlan = m_sceneRenderer->getLastCreatedPlan(); if (mapPlan) { auto &adtArray = mapPlan->adtArray; @@ -196,6 +196,71 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Rendered WMO %d", wmoArray.getToDrawn().size()); ImGui::Text("Rendered WMO groups %d", wmoGroupArray.getToDraw().size()); ImGui::Text("Rendered M2 objects %d", m2Array.getDrawn().size()); + + + auto &cullStageData = mapPlan; + + if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { + int m2ObjectsBeforeCullingExterior = 0; + if (cullStageData->viewsHolder.getExterior() != nullptr) { + m2ObjectsBeforeCullingExterior = cullStageData->viewsHolder.getExterior()->m2List.getCandidates().size(); + } + + int wmoGroupsInExterior = 0; + if (cullStageData->viewsHolder.getExterior() != nullptr) { + wmoGroupsInExterior = cullStageData->viewsHolder.getExterior()->wmoGroupArray.getToDraw().size(); + } + + int m2ObjectsDrawn = cullStageData != nullptr ? cullStageData->m2Array.getDrawn().size() : 0; + int wmoObjectsBeforeCull = + cullStageData != nullptr ? cullStageData->wmoArray.getCandidates().size() : 0; + + ImGui::Text("M2 objects drawn: %s", std::to_string(m2ObjectsDrawn).c_str()); + ImGui::Text("WMO Groups in Exterior: %s", std::to_string(wmoGroupsInExterior).c_str()); + ImGui::Text("Interiors (aka group WMOs): %s", + std::to_string(cullStageData->viewsHolder.getInteriorViews().size()).c_str()); + ImGui::Text("M2 Objects Before Culling in Exterior: %s", + std::to_string(m2ObjectsBeforeCullingExterior).c_str()); + ImGui::Text("WMO objects before culling: %s", std::to_string(wmoObjectsBeforeCull).c_str()); + + ImGui::Separator(); + } + + if (ImGui::CollapsingHeader("Current fog params")) { + if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { + ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); + ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); + ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); + ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); + ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); + ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); + ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); + ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", + cullStageData->frameDependentData->FogColor.x, + cullStageData->frameDependentData->FogColor.y, + cullStageData->frameDependentData->FogColor.z); + ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", + cullStageData->frameDependentData->EndFogColor.x, + cullStageData->frameDependentData->EndFogColor.y, + cullStageData->frameDependentData->EndFogColor.z); + ImGui::Text("End Fog Color Distance: %.3f", + cullStageData->frameDependentData->EndFogColorDistance); + ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", + cullStageData->frameDependentData->SunFogColor.x, + cullStageData->frameDependentData->SunFogColor.y, + cullStageData->frameDependentData->SunFogColor.z); + ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); + ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", + cullStageData->frameDependentData->FogHeightColor.x, + cullStageData->frameDependentData->FogHeightColor.y, + cullStageData->frameDependentData->FogHeightColor.z); + ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", + cullStageData->frameDependentData->FogHeightCoefficients.x, + cullStageData->frameDependentData->FogHeightCoefficients.y, + cullStageData->frameDependentData->FogHeightCoefficients.z); + ImGui::Separator(); + } + } } } @@ -251,65 +316,7 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Separator(); } -// auto &cullStageData = m_cullstages[currentFrame]; -// -// if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { -// int m2ObjectsBeforeCullingExterior = 0; -// if (cullStageData->viewsHolder.getExterior() != nullptr) { -// m2ObjectsBeforeCullingExterior = cullStageData->viewsHolder.getExterior()->m2List.getCandidates().size(); -// } -// -// int wmoGroupsInExterior = 0; -// if (cullStageData->viewsHolder.getExterior() != nullptr) { -// wmoGroupsInExterior = cullStageData->viewsHolder.getExterior()->wmoGroupArray.getToDraw().size(); -// } -// -// int m2ObjectsDrawn = cullStageData!= nullptr ? cullStageData->m2Array.getDrawn().size() : 0; -// int wmoObjectsBeforeCull = cullStageData!= nullptr ? cullStageData->wmoArray.getCandidates().size() : 0; -// -// ImGui::Text("M2 objects drawn: %s", std::to_string(m2ObjectsDrawn).c_str()); -// ImGui::Text("WMO Groups in Exterior: %s", std::to_string(wmoGroupsInExterior).c_str()); -// ImGui::Text("Interiors (aka group WMOs): %s", std::to_string(cullStageData->viewsHolder.getInteriorViews().size()).c_str()); -// ImGui::Text("M2 Objects Before Culling in Exterior: %s", std::to_string(m2ObjectsBeforeCullingExterior).c_str()); -// ImGui::Text("WMO objects before culling: %s", std::to_string(wmoObjectsBeforeCull).c_str()); -// -// ImGui::Separator(); -// } -// -// if (ImGui::CollapsingHeader("Current fog params")) { -// if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { -// ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); -// ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); -// ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); -// ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); -// ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); -// ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); -// ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); -// ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogColor.x, -// cullStageData->frameDependentData->FogColor.y, -// cullStageData->frameDependentData->FogColor.z); -// ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->EndFogColor.x, -// cullStageData->frameDependentData->EndFogColor.y, -// cullStageData->frameDependentData->EndFogColor.z); -// ImGui::Text("End Fog Color Distance: %.3f", cullStageData->frameDependentData->EndFogColorDistance); -// ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->SunFogColor.x, -// cullStageData->frameDependentData->SunFogColor.y, -// cullStageData->frameDependentData->SunFogColor.z); -// ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); -// ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogHeightColor.x, -// cullStageData->frameDependentData->FogHeightColor.y, -// cullStageData->frameDependentData->FogHeightColor.z); -// ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogHeightCoefficients.x, -// cullStageData->frameDependentData->FogHeightCoefficients.y, -// cullStageData->frameDependentData->FogHeightCoefficients.z); -// ImGui::Separator(); -// } -// } + // if (ImGui::CollapsingHeader("Current light params")) { // if (cullStageData->frameDependentData != nullptr) { // ImGui::Text("Glow: %.3f", cullStageData->frameDependentData->currentGlow); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 483f72d74..9fb17cdad 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -56,7 +56,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}, {}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}, {"forwardRendering"}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 05221ab15..f5add3575 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -512,6 +512,8 @@ if (LINK_VULKAN) src/gapi/vulkan/GRenderPassVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h + src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp + src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 632e492af..6dfc79a86 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -74,12 +74,12 @@ endif() set (SPIRV_OPT_APP "") -macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) +macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring directory ${destDir}") set(spirvNonOptDir ${CMAKE_BINARY_DIR}/spriv_raw) - make_directory(${spirvNonOptDir}) - file(GLOB_RECURSE templateFiles RELATIVE ${srcDir} ${srcDir}/*.frag ${srcDir}/*.vert) + file(MAKE_DIRECTORY ${spirvNonOptDir}) + file(GLOB_RECURSE commonFilesRelative RELATIVE ${srcCommonDir} ${srcCommonDir}/*.glsl) foreach(commonFileRelative ${commonFilesRelative}) @@ -89,81 +89,88 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) endif() endforeach(commonFileRelative) - foreach(templateFile ${templateFiles}) - set(srcTemplatePath ${srcDir}/${templateFile}) - if(NOT IS_DIRECTORY ${srcTemplatePath}) - message(STATUS "Configuring file ${templateFile}") - get_filename_component(FILE_NAME_WO_EXT ${srcTemplatePath} NAME_WE) - get_filename_component(FILE_NAME ${srcTemplatePath} NAME) - if (NOT SPIRV_OPT_APP) - set(SPIRV_NonOpt "${destDir}/${FILE_NAME}.spv") - else() - set(SPIRV_NonOpt "${spirvNonOptDir}/${FILE_NAME}.spv") - set(SPIRVOpt "${destDir}/${FILE_NAME}.spv") - endif() - - - add_custom_command( - OUTPUT ${SPIRV_NonOpt} - COMMAND ${CMAKE_COMMAND} -E make_directory "${destDir}" - COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_GLSL_VALIDATOR} -V ${SHADER_DEBUG_FLAG} ${srcTemplatePath} -o ${SPIRV_NonOpt} - DEPENDS ${srcTemplatePath} glslangValidator ${commonFiles}) - - if(SPIRV_OPT_APP) - add_custom_command( - OUTPUT ${SPIRVOpt} - COMMAND ${SPIRV_OPT_APP} -O -o ${SPIRVOpt} ${SPIRV_NonOpt} - DEPENDS ${srcTemplatePath} ${SPIRV_NonOpt}) - endif() - - list(APPEND SPIRV_BINARY_FILES_NON_OPT ${SPIRV_NonOpt}) - list(APPEND SPIRV_BINARY_FILES_OPT ${SPIRVOpt}) - - #Generate GLSL for ogl33 and ogl20 from spirv - set(GLSL20_FILE ${destDirGL20}/${FILE_NAME}) - set(GLSL33_FILE ${destDirGL33}/${FILE_NAME}) + foreach(shaderDir ${shaderDirs}) + set(srcDir "${rootDir}/${shaderDir}") + file(GLOB_RECURSE templateFiles RELATIVE ${srcDir} ${srcDir}/*.frag ${srcDir}/*.vert) + file(MAKE_DIRECTORY ${spirvNonOptDir}/${shaderDir}) + file(MAKE_DIRECTORY ${destDir}/${shaderDir}) + + foreach(templateFile ${templateFiles}) + set(srcTemplatePath ${srcDir}/${templateFile}) + if(NOT IS_DIRECTORY ${srcTemplatePath}) + message(STATUS "Configuring file ${templateFile}") + get_filename_component(FILE_NAME_WO_EXT ${srcTemplatePath} NAME_WE) + get_filename_component(FILE_NAME ${srcTemplatePath} NAME) + if (NOT SPIRV_OPT_APP) + set(SPIRV_NonOpt "${destDir}/${shaderDir}/${FILE_NAME}.spv") + else() + set(SPIRV_NonOpt "${spirvNonOptDir}/${shaderDir}/${FILE_NAME}.spv") + set(SPIRVOpt "${destDir}/${shaderDir}/${FILE_NAME}.spv") + endif() - get_filename_component(GLSL20_FILE_FULLPATH "${GLSL20_FILE}" - REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") - SET(OGL3_GLSL_OPTION "") - if (ANDROID) - SET(OGL3_GLSL_OPTION "-glslEs310") - elseif(EMSCRIPTEN) - SET(OGL3_GLSL_OPTION "-glslEs300") - else() - SET(OGL3_GLSL_OPTION "-glsl330") - endif() - - SET(OGL2_GLSL_OPTION "") - if (ANDROID OR EMSCRIPTEN) - SET(OGL2_GLSL_OPTION "-glsl100") - else() - SET(OGL2_GLSL_OPTION "-glsl100") - endif() + add_custom_command( + OUTPUT ${SPIRV_NonOpt} + COMMAND ${CMAKE_COMMAND} -E make_directory "${destDir}" + COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_GLSL_VALIDATOR} -V ${SHADER_DEBUG_FLAG} ${srcTemplatePath} -o ${SPIRV_NonOpt} + DEPENDS ${srcTemplatePath} glslangValidator ${commonFiles}) + + if(SPIRV_OPT_APP) + add_custom_command( + OUTPUT ${SPIRVOpt} + COMMAND ${SPIRV_OPT_APP} -O -o ${SPIRVOpt} ${SPIRV_NonOpt} + DEPENDS ${srcTemplatePath} ${SPIRV_NonOpt}) + endif() + + list(APPEND SPIRV_BINARY_FILES_NON_OPT ${SPIRV_NonOpt}) + list(APPEND SPIRV_BINARY_FILES_OPT ${SPIRVOpt}) + + #Generate GLSL for ogl33 and ogl20 from spirv + set(GLSL20_FILE ${destDirGL20}/${shaderDir}/${FILE_NAME}) + set(GLSL33_FILE ${destDirGL33}/${shaderDir}/${FILE_NAME}) + + get_filename_component(GLSL20_FILE_FULLPATH "${GLSL20_FILE}" + REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") + + SET(OGL3_GLSL_OPTION "") + if (ANDROID) + SET(OGL3_GLSL_OPTION "-glslEs310") + elseif(EMSCRIPTEN) + SET(OGL3_GLSL_OPTION "-glslEs300") + else() + SET(OGL3_GLSL_OPTION "-glsl330") + endif() + + SET(OGL2_GLSL_OPTION "") + if (ANDROID OR EMSCRIPTEN) + SET(OGL2_GLSL_OPTION "-glsl100") + else() + SET(OGL2_GLSL_OPTION "-glsl100") + endif() - add_custom_command( - OUTPUT ${GLSL20_FILE} - COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL20}" - COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} ${OGL2_GLSL_OPTION} ${SPIRV_NonOpt} > ${GLSL20_FILE_FULLPATH} - DEPENDS ${SPIRV_NonOpt} spirv_reflection) + add_custom_command( + OUTPUT ${GLSL20_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL20}" + COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} ${OGL2_GLSL_OPTION} ${SPIRV_NonOpt} > ${GLSL20_FILE_FULLPATH} + DEPENDS ${SPIRV_NonOpt} spirv_reflection) - list(APPEND GLSL20Files ${GLSL20_FILE}) + list(APPEND GLSL20Files ${GLSL20_FILE}) - get_filename_component(GLSL30_FILE_FULLPATH "${GLSL33_FILE}" - REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") + get_filename_component(GLSL30_FILE_FULLPATH "${GLSL33_FILE}" + REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") - add_custom_command( - OUTPUT ${GLSL33_FILE} - COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL33}" - COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} ${OGL3_GLSL_OPTION} ${SPIRV_NonOpt} > ${GLSL30_FILE_FULLPATH} - DEPENDS spirv_reflection ${SPIRV_NonOpt}) + add_custom_command( + OUTPUT ${GLSL33_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory "${destDirGL33}" + COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} ${OGL3_GLSL_OPTION} ${SPIRV_NonOpt} > ${GLSL30_FILE_FULLPATH} + DEPENDS spirv_reflection ${SPIRV_NonOpt}) - list(APPEND GLSL30Files ${GLSL33_FILE}) + list(APPEND GLSL30Files ${GLSL33_FILE}) - endif(NOT IS_DIRECTORY ${srcTemplatePath}) - endforeach(templateFile) + endif(NOT IS_DIRECTORY ${srcTemplatePath}) + endforeach(templateFile) + endforeach(shaderDir) if (NOT SPIRV_OPT_APP) SET(SPIRV_BINARY_FILES ${SPIRV_BINARY_FILES_NON_OPT}) @@ -173,15 +180,16 @@ macro(configure_filesVLK srcDir srcCommonDir destDir destDirGL20 destDirGL33 ) endmacro(configure_filesVLK) configure_filesVLK( - ${PROJECT_SOURCE_DIR}/shaders/glsl/forwardRendering + ${PROJECT_SOURCE_DIR}/shaders/glsl/ ${PROJECT_SOURCE_DIR}/shaders/glsl/common + "forwardRendering;visBuffer" ${GLSL_TARGET_FOLDER}/spirv ${GLSL_TARGET_FOLDER}/glsl/glsl20/ ${GLSL_TARGET_FOLDER}/glsl/glsl3.3/) add_custom_command( OUTPUT ${SPIRV_META_FILE} - COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} -sf ${SPIRV_BINARY_FILES} > ${SPIRV_META_FILE} + COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} -sf ${GLSL_TARGET_FOLDER}/spirv ${SPIRV_BINARY_FILES} > ${SPIRV_META_FILE} DEPENDS ${SPIRV_BINARY_FILES} spirv_reflection glslangValidator ShadersVulkanNonOpt ) diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 7551ecb6a..55431840f 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -55,7 +55,6 @@ vec3 calcLight( const in vec3 accumLight, const in vec3 precomputedLight, const in vec3 specular, const in vec3 emissive) { - vec3 localDiffuse = accumLight; vec3 result = matDiffuse; if (applyLight) { vec3 currColor = vec3(0.0, 0.0, 0.0); @@ -84,7 +83,7 @@ vec3 calcLight( lDiffuse = (sceneParams.extLight.uExteriorDirectColor.xyz * nDotL); - currColor = mix(groundColor, skyColor, vec3(nDotL)); + currColor = mix(groundColor, skyColor, (0.5f + vec3(0.5f * nDotL))); } if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir.xyz)), 0.0, 1.0); @@ -101,7 +100,7 @@ vec3 calcLight( } vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse); - vec3 linearDiffTerm = (matDiffuse * matDiffuse) * localDiffuse; + vec3 linearDiffTerm = (matDiffuse * matDiffuse) * accumLight; // //Specular term // vec3 specTerm = specular; diff --git a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl new file mode 100644 index 000000000..0204a488f --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl @@ -0,0 +1,45 @@ +#include "../common/commonLightFunctions.glsl" + +#ifndef MAX_MATRIX_NUM +#define MAX_MATRIX_NUM 256 +#endif + +// Whole model +layout(std430, set=1, binding=1) buffer modelWideBlockVS { + mat4 uPlacementMats[]; +}; + +struct modelWideBlockPSStruct { + InteriorLightParam intLight; + LocalLight pc_lights[4]; + ivec4 lightCountAndBcHack; + vec4 interiorExteriorBlend; +}; + +layout(std430, set=1, binding=2) buffer modelWideBlockPS { + modelWideBlockPSStruct modelWides[]; +}; + +layout(std430, set=1, binding=3) buffer boneMats { + mat4 uBoneMatrixes[]; +}; + +layout(std430, set=1, binding=4) buffer m2Colors { + vec4 colors[]; +}; + +layout(std430, set=1, binding=5) buffer textureWeights { + vec4 textureWeight[]; +}; + +layout(std430, set=1, binding=6) buffer textureMatrices { + mat4 textureMatrix[]; +}; + +struct M2InstanceRecordBindless { + ivec4 placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd; + ivec4 textureMatricesInd_modelFragmentDatasInd; +}; +layout(std430, set=1, binding=7) buffer m2Instances { + M2InstanceRecordBindless instances[]; +}; \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl index 97e75319e..2aae42cd1 100644 --- a/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWMOMaterial.glsl @@ -195,31 +195,35 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, mat3 TBN = contangent_frame(normalInView, -vertexPosInView, vTexCoord2); float cosAlpha = dot(normalize(vertexPosInView.xyz), normalInView); - vec2 dotResult = (TBN * (normalize(-vertexPosInView.xyz) / cosAlpha)).xy; + vec3 viewTS = TBN * normalize(-vertexPosInView.xyz); + vec2 viewTSNorm = (viewTS.xy / viewTS.z); - vec4 tex_4 = texture(s_texture4, vTexCoord2 - (dotResult * tex_6.r * 0.25)).rgba; - vec4 tex_5 = texture(s_texture5, vTexCoord3 - (dotResult * tex_6.r * 0.25)).rgba; + float bumpOffset_backLayer = tex_6.r; + float bumpOffset_middleLayer = 0.5f * bumpOffset_backLayer; + vec4 tex_4 = texture(s_texture4, vTexCoord2 - (viewTSNorm * bumpOffset_middleLayer * 0.5)).rgba; + vec4 tex_5 = texture(s_texture5, vTexCoord3 - (viewTSNorm * bumpOffset_middleLayer * 0.5)).rgba; vec4 tex_3 = texture(s_texture3, vTexCoord2).rgba; - vec3 mix1 = tex_5.rgb + tex_4.rgb * tex_4.a; - vec3 mix2 = (tex_3.rgb - mix1) * tex_6.g + mix1; + vec3 diffuseResult = tex_5.rgb + tex_4.rgb * tex_4.a; + vec3 diffuseResult2 = (tex_3.rgb - diffuseResult) * tex_6.g + diffuseResult; vec3 mix3 = tex_3.rgb * tex_6.b + (tex_5.rgb * tex_5.a * (1.0 - tex3.b)); vec4 tex_2 = texture(s_texture3, vColorSecond.bg).rgba; vec3 tex_2_mult = tex_2.rgb * tex_2.a; - vec3 emissive_component; + vec3 fakeSpecularResult; if (vColor2.a> 0.0) { vec4 tex = texture(s_texture, vTexCoord).rgba; - matDiffuse = (tex.rgb - mix2 ) * vColor2.a + mix2; - emissive_component = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; + matDiffuse = mix(diffuseResult2, tex.rgb, vColor2.a); + fakeSpecularResult = ((tex.rgb * tex.a) - tex_2_mult.rgb) * vColor2.a + tex_2_mult.rgb; } else { - emissive_component = tex_2_mult; - matDiffuse = mix2; + fakeSpecularResult = tex_2_mult; + matDiffuse = diffuseResult2; } - emissive = (mix3 - (mix3 * vColor2.a)) + (emissive_component * tex_2.rgb); + vec3 envResult = fakeSpecularResult * tex_2.rgb; + emissive = (mix3 - (mix3 * vColor2.a)) + (envResult); break; } case (20): { //MapObjUnkShader @@ -235,9 +239,11 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, vec4 tex_9 = texture(s_texture9, vTexCoord4).rgba; float secondColorSum = dot(vColorSecond.bgr, vec3(1.0)); - vec4 alphaVec = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004) * vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); - float maxAlpha = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); - vec4 alphaVec2 = (1.0 - clamp(vec4(maxAlpha) - alphaVec, 0.0, 1.0)); + vec4 weights = vec4(vColorSecond.bgr, 1.0 - clamp(secondColorSum, 0.0, 1.0)); + vec4 heights = max(vec4(tex_6.a, tex_7.a, tex_8.a, tex_9.a), 0.004); + vec4 alphaVec = weights * heights; + float weightsMax = max(alphaVec.r, max(alphaVec.g, max(alphaVec.r, alphaVec.a))); + vec4 alphaVec2 = (1.0 - clamp(vec4(weightsMax) - alphaVec, 0.0, 1.0)); alphaVec2 = alphaVec2 * alphaVec; vec4 alphaVec2Normalized = alphaVec2 * (1.0 / dot(alphaVec2, vec4(1.0))); @@ -248,8 +254,8 @@ void caclWMOFragMat(in int pixelShader, bool enableAlpha, tex_5 * alphaVec2Normalized.a; emissive = (texMixed.w * tex_1.rgb) * texMixed.rgb; - vec3 diffuseColor = vec3(0,0,0); //<= it's unknown where this color comes from. But it's not MOMT chunk - matDiffuse = (diffuseColor - texMixed.rgb) * vColorSecond.a + texMixed.rgb; + vec3 ambientOcclusionColor = vec3(0,0,0); // TODO: when ambient occlusion is ready, add it here + matDiffuse = mix(texMixed.rgb, ambientOcclusionColor, vColorSecond.a); break; } } diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag new file mode 100644 index 000000000..b9b358876 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -0,0 +1,198 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonM2Material.glsl" + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec2 vTexCoord3; +layout(location=3) in vec3 vNormal; +layout(location=4) in vec4 vPosition_EdgeFade; +layout(location=5) in flat int meshIndex; + +layout(location=0) out vec4 outputColor; + +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +//Whole model +#include "../common/commonM2IndirectDescriptorSet.glsl" + +//Individual meshes +struct meshWideBlockVSPSBindless { + ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; + ivec4 PixelShader_UnFogged_blendMode; + ivec4 textureWeightIndexes; + ivec4 colorIndex_applyWeight_instanceIndex; + ivec4 textureIndicies; +}; + +layout(std430, set=2, binding=8) buffer meshWideBlockVSPS { + meshWideBlockVSPSBindless meshWides[]; +}; + +layout(set=3,binding=6) uniform sampler2D uTexture; +layout(set=3,binding=7) uniform sampler2D uTexture2; +layout(set=3,binding=8) uniform sampler2D uTexture3; +layout(set=3,binding=9) uniform sampler2D uTexture4; + +void main() { + /* Animation support */ + vec2 texCoord = vTexCoord.xy; + vec2 texCoord2 = vTexCoord2.xy; + vec2 texCoord3 = vTexCoord3.xy; + + vec4 finalColor = vec4(0); + + meshWideBlockVSPSBindless meshWide = meshWides[meshIndex]; + int instanceIndex = meshWide.colorIndex_applyWeight_instanceIndex.y; + + vec3 uTexSampleAlpha = vec3( + meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], + meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], + meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] + ); + + vec4 vMeshColorAlpha = vec4( + meshWide.colorIndex_applyWeight_instanceIndex.x < 0 ? + vec4(1.0,1.0,1.0,1.0) : + colors[meshWide.colorIndex_applyWeight_instanceIndex.x] + ); + if (meshWide.colorIndex_applyWeight_instanceIndex.y > 0) + vMeshColorAlpha.a *= + meshWide.textureWeightIndexes.x < 0 ? + 1.0 : + textureWeight[meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; + + vec3 l_Normal = vNormal; + + //Accumulate and apply lighting + + vec3 meshResColor = vMeshColorAlpha.rgb; + + vec3 accumLight = vec3(0.0); + modelWideBlockPSStruct modelWide = modelWides[instanceIndex]; + if ((meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { + mat4 placementMat = + uPlacementMats[instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x]; + + vec3 vPos3 = vPosition_EdgeFade.xyz; + vec3 vNormal3 = normalize(l_Normal.xyz); + vec3 lightColor = vec3(0.0); + int count = int(modelWide.pc_lights[0].attenuation.w); + + for (int index = 0; index < 4; index++) + { + if (index >= modelWide.lightCountAndBcHack.x) break; + + LocalLight lightRecord = modelWide.pc_lights[index]; + vec3 vectorToLight = ((scene.uLookAtMat * (placementMat * lightRecord.position)).xyz - vPos3); + float distanceToLightSqr = dot(vectorToLight, vectorToLight); + float distanceToLightInv = inversesqrt(distanceToLightSqr); + float distanceToLight = (distanceToLightSqr * distanceToLightInv); + float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); + vec4 attenuationRec = lightRecord.attenuation; + + float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); + + vec3 attenuatedColor = attenuation * lightRecord.color.xyz; + lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); + } + + meshResColor.rgb = clamp(lightColor , 0.0, 1.0); + accumLight = mix(lightColor.rgb, meshResColor.rgb, modelWide.lightCountAndBcHack.y); + //finalColor.rgb = finalColor.rgb * lightColor; + } + +//---------------------- +// Calc Diffuse and Specular +//--------------------- + int uVertexShader = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; + + mat4 textMat[2]; + int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; + int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; + + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + float edgeFade = 1.0; + + calcM2VertexMat(uVertexShader, + vPosition_EdgeFade.xyz, l_Normal, + vTexCoord, vTexCoord2, + textMat, edgeFade, + texCoord, texCoord2, texCoord3); + + vMeshColorAlpha *= edgeFade; + + float finalOpacity = 0.0; + vec3 matDiffuse; + vec3 specular; + + int uPixelShader = meshWide.PixelShader_UnFogged_blendMode.x; + int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; + + bool doDiscard = false; + + calcM2FragMaterial(uPixelShader, + uTexture, uTexture2, uTexture3, uTexture4, + texCoord, texCoord2, texCoord3, + vMeshColorAlpha.rgb, vMeshColorAlpha.a, + uTexSampleAlpha.rgb, + blendMode, + matDiffuse, specular, finalOpacity, doDiscard + ); + + if (doDiscard) + discard; + +// ------------------------------ +// Apply lighting +// ------------------------------ + +// specular *= vMeshColorAlpha.rgb; + + finalColor = vec4( + calcLight( + matDiffuse, + l_Normal, + meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, + modelWide.interiorExteriorBlend.x, + scene, + modelWide.intLight, + accumLight, + vec3(0.0), + specular, + vec3(0.0) + ) , + finalOpacity + ); + +// ------------------------------ +// Apply Fog +// ------------------------------ + + int uUnFogged = meshWide.PixelShader_UnFogged_blendMode.y; + if (uUnFogged == 0) { + vec3 sunDir = + mix( + scene.uInteriorSunDir, + scene.extLight.uExteriorDirectColorDir, + modelWide.interiorExteriorBlend.x + ) + .xyz; + + finalColor = makeFog(fogData, finalColor, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); + } + + //Forward rendering without lights + outputColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert new file mode 100644 index 000000000..4e628aee2 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -0,0 +1,84 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonM2Material.glsl" + +/* vertex shader code */ +layout(location=0) in vec3 aPosition; +layout(location=1) in vec3 aNormal; +layout(location=2) in uvec4 bones; +layout(location=3) in vec4 boneWeights; +layout(location=4) in vec2 aTexCoord; +layout(location=5) in vec2 aTexCoord2; + +//Whole scene +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +//Whole model +#include "../common/commonM2DescriptorSet.glsl" + +//Individual meshes +layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { + ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; + ivec4 PixelShader_UnFogged_blendMode; + ivec4 textureWeightIndexes; + ivec4 colorIndex_applyWeight; +}; + +//Shader output +layout(location=0) out vec2 vTexCoord; +layout(location=1) out vec2 vTexCoord2; +layout(location=2) out vec2 vTexCoord3; +layout(location=3) out vec3 vNormal; +layout(location=4) out vec4 vPosition_EdgeFade; +layout(location=5) out flat int instanceIndex; + + +void main() { + vec4 modelPoint = vec4(0,0,0,0); + + vec4 aPositionVec4 = vec4(aPosition, 1); + mat4 boneTransformMat = mat4(0.0); + + if (dot(boneWeights, boneWeights) > 0) { + // + boneTransformMat += (boneWeights.x) * uBoneMatrixes[bones.x]; + boneTransformMat += (boneWeights.y) * uBoneMatrixes[bones.y]; + boneTransformMat += (boneWeights.z) * uBoneMatrixes[bones.z]; + boneTransformMat += (boneWeights.w) * uBoneMatrixes[bones.w]; + } else { + boneTransformMat = mat4(1.0); + } + + mat4 placementMat; + placementMat = uPlacementMat; + + mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; + vec4 vertexPosInView = viewModelMat * aPositionVec4; + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + + vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); + vec3 minusNormal = normalize((viewModelMatForNormal * vec4(-aNormal, 0.0)).xyz); + + vTexCoord = aTexCoord; + vTexCoord2 = aTexCoord2; + vTexCoord3 = aTexCoord2; + + gl_Position = scene.uPMatrix * vertexPosInView; + vNormal = normal; + vPosition_EdgeFade = vec4(vertexPosInView.xyz, 0.0); + instanceIndex = gl_InstanceIndex; +} + + diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index 520cd82ee..146f5f766 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -9,8 +9,10 @@ #include #include #include +#include #include "fileHelpers.h" #include "webGLSLCompiler.h" +#include "../../../src/include/string_utils.h" constexpr const int MAX_SHADER_DESC_SETS = 8; @@ -50,6 +52,11 @@ struct uboBindingData { unsigned int binding; unsigned long long size; }; +struct ssboBindingData { + unsigned int set; + unsigned int binding; + unsigned long long size; +}; struct imageBindingData { unsigned int set; @@ -66,6 +73,7 @@ struct bindingAmountData { struct shaderMetaData { ShaderStage stage; std::vector uboBindings; + std::vector ssboBindingData; std::array uboBindingAmountsPerSet; std::vector imageBindings; @@ -133,7 +141,7 @@ void dumpMembers(spirv_cross::WebGLSLCompiler &glsl, std::vector &f } } -void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { +void dumpShaderUniformOffsets(const std::string &basePath, const std::vector &shaderFilePaths) { std::cout << "#ifndef WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H\n" "#define WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H\n" "\n" @@ -177,6 +185,11 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { unsigned int binding; unsigned long long size; }; + struct ssboBindingData { + unsigned int set; + unsigned int binding; + unsigned long long size; + }; struct imageBindingData { unsigned int set; unsigned int binding; @@ -195,6 +208,8 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::vector uboBindings; std::array uboBindingAmountsPerSet; + std::vector ssboBindingData; + std::vector imageBindings; std::array imageBindingAmountsPerSet; }; @@ -220,8 +235,16 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::vector spirv_binary = readFile(filePath); - std::string fileName = basename(filePath); - auto tokens = split(fileName, '.'); + + std::string fileName = startsWith(filePath, basePath) ? + filePath.substr(basePath.size()+1, filePath.size()-basePath.size()) : + basename(filePath); + + std::string shaderName = basename(filePath); + auto tokens = split(shaderName, '.'); + shaderName = tokens[0]; + + spirv_cross::WebGLSLCompiler glsl(std::move(spirv_binary)); @@ -234,9 +257,9 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { //Find or create new record for shader { - auto it = fieldDefMapPerShaderName.find(tokens[0]); + auto it = fieldDefMapPerShaderName.find(shaderName); if (it == fieldDefMapPerShaderName.end()) { - fieldDefMapPerShaderName[tokens[0]] = {}; + fieldDefMapPerShaderName[shaderName] = {}; } } @@ -246,7 +269,7 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { shaderMetaInfo[fileName] = {}; } } - auto &perSetMap = fieldDefMapPerShaderName.at(tokens[0]); + auto &perSetMap = fieldDefMapPerShaderName.at(shaderName); auto &metaInfo = shaderMetaInfo.at(fileName); @@ -277,11 +300,11 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { }(); if (glsl.get_entry_points_and_stages()[0].execution_model == spv::ExecutionModel::ExecutionModelVertex) { - auto it = attributesPerShaderName.find(tokens[0]); + auto it = attributesPerShaderName.find(shaderName); if (it == attributesPerShaderName.end()) { - attributesPerShaderName[tokens[0]] = {}; + attributesPerShaderName[shaderName] = {}; } - auto &shaderAttributeVector = attributesPerShaderName.at(tokens[0]); + auto &shaderAttributeVector = attributesPerShaderName.at(shaderName); auto inputAttributes = glsl.get_shader_resources(); @@ -297,6 +320,9 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { [](const attributeDefine &a, const attributeDefine &b) -> bool { return a.location < b.location; }); + shaderAttributeVector.erase(std::unique(shaderAttributeVector.begin(), shaderAttributeVector.end(), [](attributeDefine &a, attributeDefine &b) -> bool { + return a.name == b.name && a.location == b.location; + }), shaderAttributeVector.end()); } // The SPIR-V is now parsed, and we can perform reflection on it. @@ -315,9 +341,9 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { if (set >= 0) { metaInfo.uboBindingAmountsPerSet[set].start = - std::min(metaInfo.imageBindingAmountsPerSet[set].start, binding); + std::min(metaInfo.uboBindingAmountsPerSet[set].start, binding); metaInfo.uboBindingAmountsPerSet[set].end = - std::max(metaInfo.imageBindingAmountsPerSet[set].end, binding); + std::max(metaInfo.uboBindingAmountsPerSet[set].end, binding); } if (perSetMap.find(binding) != perSetMap.end()) { @@ -347,6 +373,44 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { } } + //Record data for SSBO + for (auto &resource : resources.storage_buffers) { + auto ssboType = glsl.get_type(resource.type_id); + + auto typeId_size = glsl.get_declared_struct_size(ssboType); + + unsigned set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet); + unsigned binding = glsl.get_decoration(resource.id, spv::DecorationBinding); + + metaInfo.ssboBindingData.push_back({set, binding, typeId_size}); + +// if (set >= 0) { +// metaInfo.uboBindingAmountsPerSet[set].start = +// std::min(metaInfo.uboBindingAmountsPerSet[set].start, binding); +// metaInfo.uboBindingAmountsPerSet[set].end = +// std::max(metaInfo.uboBindingAmountsPerSet[set].end, binding); +// } + + if (perSetMap.find(binding) != perSetMap.end()) { + perSetMap[binding] = {}; + } + + auto &fieldVectorDef = perSetMap[binding]; + + for (int j = 0; j < ssboType.member_types.size(); j++) { + + auto uboParentType = glsl.get_type(ssboType.parent_type); + auto memberSize = glsl.get_declared_struct_member_size(uboParentType, j); + auto offset = glsl.type_struct_member_offset(uboParentType, j); + auto memberName = glsl.get_member_name(ssboType.parent_type, j); + + + dumpMembers(glsl, fieldVectorDef, ssboType.member_types[j], +// "_" + std::to_string(resource.id) + "_" + memberName, offset, memberSize); + glsl.to_name(resource.id) + "_" + memberName, offset, memberSize); + } + } + //Record data for images for (auto &resource : resources.sampled_images) { unsigned int set = 255; @@ -387,7 +451,14 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { " enum class Attribute {" << std::endl; std::cout << " "; - for (auto &attributeInfo : it->second) { + auto array = it->second; + std::sort(array.begin(), array.end(), [](const attributeDefine &a, const attributeDefine &b) -> bool { + return a.location < b.location; + }); + array.erase(std::unique(array.begin(), array.end(), [](attributeDefine &a, attributeDefine &b) -> bool { + return a.name == b.name && a.location == b.location; + }), array.end()); + for (auto &attributeInfo : array) { std::cout << "" << attributeInfo.name << " = " << attributeInfo.location << ", "; } @@ -446,6 +517,13 @@ void dumpShaderUniformOffsets(std::vector &shaderFilePaths) { std::cout << " }\n"; std::cout << " },\n"; + //Dump SSBO Bindings per shader + std::cout << " {\n"; + for (auto subIt = it->second.ssboBindingData.begin(); subIt != it->second.ssboBindingData.end(); subIt++) { + std::cout << " {" << subIt->set << "," << subIt->binding << "," << subIt->size << "}," << std::endl; + } + std::cout << " },\n"; + //SSBO Bindings dump end std::cout << " {\n"; for (auto &binding : it->second.imageBindings) { diff --git a/wowViewerLib/shaders/src/spirv/spirv_refl_main.cpp b/wowViewerLib/shaders/src/spirv/spirv_refl_main.cpp index 1ce3d4547..5d2165344 100644 --- a/wowViewerLib/shaders/src/spirv/spirv_refl_main.cpp +++ b/wowViewerLib/shaders/src/spirv/spirv_refl_main.cpp @@ -71,7 +71,7 @@ int main(int argc, char **argv) if (mode == "-sf") { - dumpShaderUniformOffsets(filePaths); + dumpShaderUniformOffsets(filePaths[0], decltype(filePaths)(filePaths.begin()+1, filePaths.end())); } else if (mode == "-glsl100") { dumpGLSLText(filePaths, 100, false); } else if (mode == "-glsl120Es") { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index bfc25f63f..08928dfa6 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -35,6 +35,11 @@ struct attributeDefine { unsigned int binding; unsigned long long size; }; + struct ssboBindingData { + unsigned int set; + unsigned int binding; + unsigned long long size; + }; struct imageBindingData { unsigned int set; unsigned int binding; @@ -53,6 +58,8 @@ struct attributeDefine { std::vector uboBindings; std::array uboBindingAmountsPerSet; + std::vector ssboBindingData; + std::vector imageBindings; std::array imageBindingAmountsPerSet; }; @@ -291,19 +298,24 @@ const std::unordered_map> attributesPe }; const std::unordered_map shaderMetaInfo = { -{ "wmoShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,368}, - {1,2,16}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {2,2,1}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -313,6 +325,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -327,17 +341,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "wmoShader.frag.spv", +{ "forwardRendering/wmoShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, + {1,1,64}, {0,0,368}, + {1,2,16}, }, { { {0,0,1}, - {4,4,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -347,21 +362,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + }, + { }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -371,34 +379,42 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, {0,0,368}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { {0,0,1}, + {1,6,6}, {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { - {2,5, "uTexture"}, + }, + { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -407,24 +423,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,5,96}, {0,0,368}, {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {6,6,1}, - {5,5,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -433,17 +443,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, + }, + { }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -452,12 +460,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.vert.spv", +{ "forwardRendering/skyConus.vert.spv", { ShaderStage::Vertex, { {0,0,368}, - {1,1,64}, + {1,1,96}, }, { { @@ -473,6 +481,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -487,15 +497,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -507,6 +517,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -521,24 +533,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterfallShader.vert.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, {0,0,368}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { {0,0,1}, - {5,5,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -547,14 +552,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {3,9, "uBumpTexture"}, + }, + { }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -563,16 +569,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.vert.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { ShaderStage::Vertex, { {0,0,128}, - {0,1,64}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -584,6 +589,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -598,15 +605,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -618,10 +624,13 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {1,5, "Texture"}, + }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -632,15 +641,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxglow.frag.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,2,168}, }, { { - {4,4,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -651,13 +660,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + }, + { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, - {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -668,17 +679,61 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, + {2,5,96}, {0,0,368}, {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, + {1,6,6}, + {5,5,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {6,10,5}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/drawLinesShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,1,12}, + }, + { + { {1,1,1}, {0,0,0}, {0,0,0}, @@ -686,24 +741,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + }, + { }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -713,7 +762,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { @@ -722,7 +771,7 @@ const std::unordered_map shaderMetaInfo = { }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -734,6 +783,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -748,16 +799,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,1,16}, }, { { - {2,2,1}, {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -768,6 +819,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -782,7 +835,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawDepthShader.frag.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { @@ -801,11 +854,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "diffuse"}, + }, + { }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -817,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "adtLodShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -836,12 +890,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + }, + { }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -853,15 +907,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPoints.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,144}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -873,6 +927,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -887,16 +943,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawBBShader.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {1,2,48}, + {0,0,368}, + {1,1,64}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -907,11 +965,22 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, + }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -921,15 +990,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,368}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -940,13 +1009,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, + }, + { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -955,11 +1038,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,368}, + {0,0,128}, }, { { @@ -975,6 +1058,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -989,15 +1074,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, + {0,0,368}, + {1,1,64}, }, { { - {0,0,0}, + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1009,6 +1095,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1023,11 +1111,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawLinesShader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,0,84}, }, { { @@ -1043,9 +1131,13 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, + }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1057,14 +1149,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ffxgauss4.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,4,32}, + {0,0,368}, }, { { + {0,0,1}, {4,4,1}, {0,0,0}, {0,0,0}, @@ -1072,17 +1166,26 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { - {1,5, "texture0"}, + }, + { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1092,14 +1195,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1110,7 +1214,9 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,5, "Texture"}, + }, + { + {1,5, "texture0"}, }, { { @@ -1126,15 +1232,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1146,6 +1252,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1160,15 +1268,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawQuad.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,4,16}, }, { { - {2,2,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1180,10 +1288,14 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {1,5, "screenTex"}, + {1,6, "blurTex"}, + }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1194,16 +1306,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "imguiShader.vert.spv", +{ "forwardRendering/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {1,4,96}, + {0,0,368}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1214,11 +1327,14 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {2,5, "uTexture"}, + }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1228,7 +1344,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { @@ -1244,7 +1360,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,1}, - {3,3,1}, + {1,6,6}, {7,7,1}, {0,0,0}, {0,0,0}, @@ -1253,6 +1369,8 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, } }, + { + }, { {3,6, "uTexture"}, {3,7, "uTexture2"}, @@ -1273,17 +1391,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "waterShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,368}, - {1,1,64}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, - {1,1,1}, + {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1294,6 +1412,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1308,15 +1428,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,368}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1328,6 +1448,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1342,16 +1464,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,368}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1362,11 +1485,16 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1376,17 +1504,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "skyConus.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { {0,0,368}, - {1,1,96}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1397,6 +1524,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1411,15 +1540,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,0,368}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1430,12 +1559,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + }, + { }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1447,7 +1576,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "renderFrameBufferShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { @@ -1466,6 +1595,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1480,17 +1611,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2ParticleShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,368}, + {0,2,12}, }, { { - {0,0,1}, - {4,4,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1500,15 +1630,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + }, + { + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, - {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1518,7 +1648,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "m2Shader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -1534,7 +1664,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,1}, - {6,6,1}, + {1,6,6}, {7,7,1}, {0,0,0}, {0,0,0}, @@ -1545,6 +1675,8 @@ const std::unordered_map shaderMetaInfo = { }, { }, + { + }, { { {0,0,0}, @@ -1559,7 +1691,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "ribbonShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { @@ -1570,7 +1702,7 @@ const std::unordered_map shaderMetaInfo = { { { {0,0,1}, - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1579,6 +1711,8 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, } }, + { + }, { {2,5, "uTexture"}, }, @@ -1596,6 +1730,42 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "forwardRendering/ribbonShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,368}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { @@ -2318,19 +2488,23 @@ const std::unordered_mappMessage << std::endl << std::flush; - - return VK_FALSE; } @@ -1073,6 +1071,11 @@ HGBufferVLK GDeviceVLK::createUniformBuffer(size_t initialSize) { return h_uniformBuffer; } +HGBufferVLK GDeviceVLK::createSSBOBuffer(size_t initialSize, int recordSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); + return h_uniformBuffer; +} + HGBufferVLK GDeviceVLK::createVertexBuffer(size_t initialSize) { auto h_vertexBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 3677bed81..442ca502d 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -106,6 +106,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); HGBufferVLK createUniformBuffer(size_t size); + HGBufferVLK createSSBOBuffer(size_t size, int recordSize); HGBufferVLK createVertexBuffer(size_t size); HGBufferVLK createIndexBuffer(size_t size); HGVertexBufferBindings createVertexBufferBindings() override; @@ -320,6 +321,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.shaderConfig.shaderFolder); for (const auto &rec : k.shaderConfig.typeOverrides) for (const auto &rec2 : rec.second) mapHash ^= hash{}(rec2.second) << 4 ^ hash{}(rec2.first) << 4 ^ hash{}(rec.first) << 4; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index 96e3a7afb..3f72b4fca 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -30,6 +30,11 @@ class CBufferChunkVLK : public IBufferChunk { pSubBuffer->save(m_realSize); }; + size_t getIndex() { + return subBuffer->getIndex(); + } + + inline std::shared_ptr getSubBuffer() {return subBuffer;} operator const std::shared_ptr() const { return subBuffer; } private: int m_realSize = 0; @@ -44,6 +49,11 @@ namespace BufferChunkHelperVLK { return *std::dynamic_pointer_cast>(chunk); } + template + static inline std::shared_ptr> castToChunk(const std::shared_ptr> &chunk) { + return std::dynamic_pointer_cast>(chunk); + } + template static const inline void create(const HGBufferVLK &parentBuffer, std::shared_ptr> &chunk, int realSize = -1) { chunk = std::make_shared>(parentBuffer, realSize); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 17a042bfd..70be4d0b3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -51,6 +51,10 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { auto index = m_device->getUpdateFrameNumber(); return pSubBuffers[index]->getOffset(); } + size_t getIndex() override { + auto index = m_device->getUpdateFrameNumber(); + return pSubBuffers[index]->getIndex(); + } size_t getSize() override { return m_realSize; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h index cf498a63a..08b0f995c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -54,6 +54,11 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe return subBufferVersions[m_currentVersion][index]->getOffset(); } + size_t getIndex() override { + auto index = m_device->getUpdateFrameNumber(); + return subBufferVersions[m_currentVersion][index]->getIndex(); + } + size_t getSize() override { return m_realSize; } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index c11cc0038..fa197a025 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -49,6 +49,9 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords(); @@ -106,6 +109,11 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_thism_alignment > 0) ? + m_alloc.offset / m_parentBuffer->m_alignment : + m_alloc.offset; + }; private: void setParentDataPointer(void * ptr) { m_dataPointer = ((uint8_t *) ptr) + m_alloc.offset; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h index 3825d2340..231b6c29e 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/IBufferVLK.h @@ -15,6 +15,7 @@ class IBufferVLK : public IBuffer, public IDSBindable { virtual VkBuffer getGPUBuffer() = 0; virtual size_t getOffset() = 0; + virtual size_t getIndex() = 0; }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h index 482d47124..00b46d4c9 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -15,7 +15,7 @@ class DescriptorRecord { public: enum class DescriptorRecordType { - None, UBO, UBODynamic, Texture + None, UBO, UBODynamic, SSBO, Texture }; DescriptorRecord() = delete; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 3fe8929b9..9e802a412 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -202,7 +202,44 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr &buffer) { - throw "unimplemented"; + auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); + auto &uboSizes = m_set.m_hDescriptorSetLayout->getRequiredUBOSize(); + +#if (!defined(NDEBUG)) + if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + std::cerr << "descriptor mismatch for UBO" << std::endl; + throw std::runtime_error("descriptor mismatch for UBO"); + } + if (uboSizes.find(bindIndex) != uboSizes.end() && buffer->getSize() != uboSizes.at(bindIndex)) { + std::cout << "buffers missmatch! for" + << " binding = " << bindIndex + << " expected size " << uboSizes.at(bindIndex) + << ", provided size = " << (buffer->getSize()) + << std::endl; + } +#endif + + + assignBoundDescriptors(bindIndex, buffer, DescriptorRecord::DescriptorRecordType::SSBO); + m_updateBindPoints[bindIndex] = true; + + VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); + bufferInfo = {}; + bufferInfo.buffer = buffer->getGPUBuffer(); + bufferInfo.offset = buffer->getOffset(); + bufferInfo.range = buffer->getSize(); + + VkWriteDescriptorSet &writeDescriptor = updates.emplace_back(); + writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptor.dstSet = m_set.getDescSet(); + writeDescriptor.pNext = nullptr; + writeDescriptor.dstBinding = bindIndex; + writeDescriptor.dstArrayElement = 0; + writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeDescriptor.descriptorCount = 1; + writeDescriptor.pBufferInfo = &bufferInfo; + writeDescriptor.pImageInfo = nullptr; + writeDescriptor.pTexelBufferView = nullptr; return *this; } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 084021aad..35485785b 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -31,6 +31,7 @@ class GDescriptorSetLayout { const std::unordered_map& getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; const std::unordered_map& getRequiredUBOSize() const {return m_requiredUBOSize;} ; + const std::unordered_map& getRequiredSSBOSize() const {return m_requiredUBOSize;} ; int getTotalUbos() { return m_totalUbos; }; int getTotalDynUbos() { return m_totalDynUbos; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index a00cba5ba..2f19b364c 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -21,16 +21,19 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); ~ISimpleMaterialVLK() override = default; - HGShaderPermutation getShader() { + const HGShaderPermutation &getShader() const { return m_shader; } const std::array, MAX_SHADER_DESC_SETS> &getDescriptorSets() { return descriptors; } - HPipelineVLK getPipeline() { + const HPipelineVLK &getPipeline() const { return m_pipeline; } + const PipelineTemplate &getPipelineTemplate() const { + return m_pipelineTemplate; + } std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); EGxBlendEnum getBlendMode(); diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index 491f349c6..2e55935d2 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -15,6 +15,17 @@ MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &dev shaderFiles[1], shaderConfig); } +MaterialBuilderVLK::MaterialBuilderVLK( + const std::shared_ptr &device, + const HGShaderPermutation &shader, + const HPipelineVLK &pipeline, + const PipelineTemplate &pipelineTemplate, + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : + m_device(device), m_shader(shader), m_pipeline(pipeline), m_pipelineTemplate(pipelineTemplate), + m_descriptorSets(descriptorSets) { + +} + MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, const std::function &ds)> &callback) { @@ -23,35 +34,15 @@ MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, auto ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint)); callback(ds); - descriptorSets[bindPoint] = ds; + m_descriptorSets[bindPoint] = ds; return *this; } -//MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, -// const std::function &, GDescriptorSet::SetUpdateHelper &)> &callback) { -// auto shaderVLK = std::dynamic_pointer_cast(m_shader); -// -// auto ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint, {})); -// auto updater = ds->beginUpdate(); -// callback(ds, updater); -// auto &overrides = updater.getAccumulatedTypeOverrides(); -// if (!overrides.empty()) { -// updater.cancelUpdate(); -// ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint, overrides)); -// auto updater2 = ds->beginUpdate(); -// callback(ds, updater2); -// } -// -// descriptorSets[bindPoint] = ds; -// -// return *this; -//} - MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::shared_ptr &ds) { //TODO: check DS layout compatibility - descriptorSets[bindPoint] = ds; + m_descriptorSets[bindPoint] = ds; return *this; } @@ -81,6 +72,6 @@ std::shared_ptr MaterialBuilderVLK::toMaterial() { m_shader, m_pipelineTemplate, m_pipeline, - descriptorSets + m_descriptorSets ); } diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index be4f9e61f..4ab8e58d0 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -22,6 +22,16 @@ class MaterialBuilderVLK { return {device, shaderFiles, shaderConfig}; } + template + static MaterialBuilderVLK fromMaterial(const std::shared_ptr &device, + const std::shared_ptr &materialVlk) { + return {device, materialVlk->getShader(), + materialVlk->getPipeline(), + materialVlk->getPipelineTemplate(), + materialVlk->getDescriptorSets() + }; + } + MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); MaterialBuilderVLK& createDescriptorSet(int bindPoint, const std::function &ds)> &callback); MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, @@ -35,7 +45,7 @@ class MaterialBuilderVLK { m_shader, m_pipelineTemplate, m_pipeline, - descriptorSets); + m_descriptorSets); } ~MaterialBuilderVLK() = default; @@ -43,6 +53,12 @@ class MaterialBuilderVLK { MaterialBuilderVLK(const std::shared_ptr &device, const std::vector &shaderFiles, const ShaderConfig &shaderConfig); + MaterialBuilderVLK(const std::shared_ptr &device, + const HGShaderPermutation &shader, + const HPipelineVLK &pipeline, + const PipelineTemplate &pipelineTemplate, + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); + private: //States @@ -51,7 +67,7 @@ class MaterialBuilderVLK { HGShaderPermutation m_shader; HPipelineVLK m_pipeline; PipelineTemplate m_pipelineTemplate; - std::array, MAX_SHADER_DESC_SETS> descriptorSets; + std::array, MAX_SHADER_DESC_SETS> m_descriptorSets; }; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 0b9b0637c..0c32d132e 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -67,14 +67,17 @@ void GShaderPermutationVLK::createSetDescriptorLayouts() { } void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const std::string &fragExtraDef) { - auto vertShaderCode = readFile("spirv/" + m_shaderNameVert + ".vert.spv"); - auto fragShaderCode = readFile("spirv/" + m_shaderNameFrag + ".frag.spv"); + std::string vertShaderName = m_shaderConf.shaderFolder +"/" + m_shaderNameVert; + std::string vertShaderFrag = m_shaderConf.shaderFolder +"/" + m_shaderNameFrag; + + auto vertShaderCode = readFile("spirv/" + vertShaderName + ".vert.spv"); + auto fragShaderCode = readFile("spirv/" + vertShaderFrag + ".frag.spv"); vertShaderModule = createShaderModule(vertShaderCode); fragShaderModule = createShaderModule(fragShaderCode); - vertShaderMeta = &shaderMetaInfo.at(m_shaderNameVert + ".vert.spv"); - fragShaderMeta = &shaderMetaInfo.at(m_shaderNameFrag + ".frag.spv"); + vertShaderMeta = &shaderMetaInfo.at(vertShaderName + ".vert.spv"); + fragShaderMeta = &shaderMetaInfo.at(vertShaderFrag + ".frag.spv"); this->createShaderLayout(); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 11b0ebcaa..9ce03fff4 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -12,6 +12,7 @@ typedef std::unordered_map> DescTypeOverride; struct ShaderConfig { + std::string shaderFolder; DescTypeOverride typeOverrides; }; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index a362f2c24..413f6f119 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -60,6 +60,7 @@ class IM2ModelData { std::shared_ptr> m_textureWeights = nullptr; std::shared_ptr> m_textureMatrices = nullptr; std::shared_ptr> m_modelFragmentData = nullptr; + std::shared_ptr> m_instanceBindless = nullptr; }; class IM2Material : public IMaterial { @@ -68,9 +69,17 @@ class IM2Material : public IMaterial { int pixelShader; int batchIndex; EGxBlendEnum blendMode; + bool depthWrite; + bool depthCulling; + bool backFaceCulling; std::shared_ptr> m_vertexFragmentData = nullptr; }; +class IM2MaterialVis : public IM2Material { +public: + size_t instanceIndex; +}; + class IM2WaterFallMaterial : public IMaterial { public: int vertexShader; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index a61d07491..6410d9421 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -17,6 +17,7 @@ #include static const ShaderConfig forwardShaderConfig = { + "forwardRendering", { {0, { {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} @@ -24,6 +25,7 @@ static const ShaderConfig forwardShaderConfig = { } }; static const ShaderConfig m2ForwardShaderConfig = { + "forwardRendering", { {0, { {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} @@ -612,6 +614,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); + //Needs to be executed only after lock m_lastCreatedPlan = framePlan; //The portal meshes are created here. Need to call doPostLoad before CollectMeshes diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index abc621d16..cfb5a0023 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -17,13 +17,15 @@ #include static const ShaderConfig forwardShaderConfig = { + "forwardRendering", { {0, { {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} }} } }; -static const ShaderConfig m2ForwardShaderConfig = { +static const ShaderConfig m2VisShaderConfig = { + "visBuffer", { {0, { {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} @@ -70,6 +72,20 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m_drawQuadVao->save(); } + //Create m2 shaders + { + m2Buffers.placementMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(M2::PlacementMatrix)); + m2Buffers.boneMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); + m2Buffers.m2Colors = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureWeights = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureMatrices = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); + m2Buffers.modelVertexDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS)); + m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::modelWideBlockPS)); + + m2Buffers.m2InstanceData = m_device->createSSBOBuffer(1024*1024, sizeof(M2::M2InstanceRecordBindless)); + m2Buffers.meshWideBlocks = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); + } + uboBuffer = m_device->createUniformBuffer(1024*1024); uboStaticBuffer = m_device->createUniformBuffer(1024*1024); @@ -103,6 +119,25 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic .ubo_dynamic(0, sceneWideChunk); sceneWideDS = ds; }); + + //Create global m2Material + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, m2Buffers.placementMatrix) + .ssbo(2, m2Buffers.modelFragmentDatas) + .ssbo(3, m2Buffers.boneMatrix) + .ssbo(4, m2Buffers.m2Colors) + .ssbo(5, m2Buffers.textureWeights) + .ssbo(6, m2Buffers.textureMatrices) + .ssbo(7, m2Buffers.m2InstanceData) + .ssbo(8, m2Buffers.meshWideBlocks); + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(7, m2Buffers.modelVertexDatas); + }); } // ------------------ @@ -284,16 +319,11 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr const M2MaterialTemplate &m2MaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; - auto vertexFragmentData = std::make_shared>(uboStaticBuffer); + auto vertexFragmentData = std::make_shared>(m2Buffers.modelVertexDatas); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) - .bindDescriptorSet(0, sceneWideDS) - .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) - .createDescriptorSet(2, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo(7, *vertexFragmentData); - }) + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) @@ -301,14 +331,19 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr .texture(8, m2MaterialTemplate.textures[2]) .texture(9, m2MaterialTemplate.textures[3]); }) - .toMaterial([&vertexFragmentData](IM2Material *instance) -> void { + .toMaterial([&vertexFragmentData](IM2MaterialVis *instance) -> void { instance->m_vertexFragmentData = vertexFragmentData; }); material->blendMode = pipelineTemplate.blendMode; + material->depthWrite = pipelineTemplate.depthWrite; + material->depthCulling = pipelineTemplate.depthCulling; + material->backFaceCulling = pipelineTemplate.backFaceCulling; + material->batchIndex = m2MaterialTemplate.batchIndex; material->vertexShader = m2MaterialTemplate.vertexShader; material->pixelShader = m2MaterialTemplate.pixelShader; + material->instanceIndex = vertexFragmentData->getIndex(); return material; @@ -321,10 +356,10 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Waterf auto vertexData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2VisShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) .createDescriptorSet(2, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo(4, *vertexData) @@ -509,24 +544,23 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); - DynamicBufferChunkHelperVLK::create(m_device, uboBuffer, result->m_placementMatrix); - BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); - BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); - - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) - .createDescriptorSet(1, [&](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(result->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(result->m_modelFragmentData)) - .ubo(3, BufferChunkHelperVLK::cast(result->m_bonesData)) - .ubo(4, BufferChunkHelperVLK::cast(result->m_colors)) - .ubo(5, BufferChunkHelperVLK::cast(result->m_textureWeights)) - .ubo(6, BufferChunkHelperVLK::cast(result->m_textureMatrices)); - result->placementMatrixDS = ds; - }); + BufferChunkHelperVLK::create(m2Buffers.placementMatrix, result->m_placementMatrix); + BufferChunkHelperVLK::create(m2Buffers.boneMatrix, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(m2Buffers.m2Colors, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); + BufferChunkHelperVLK::create(m2Buffers.textureWeights, result->m_textureWeights, sizeof(float) * textureWeightsCount); + BufferChunkHelperVLK::create(m2Buffers.textureMatrices, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); + BufferChunkHelperVLK::create(m2Buffers.modelFragmentDatas, result->m_modelFragmentData); + + BufferChunkHelperVLK::create(m2Buffers.m2InstanceData, result->m_instanceBindless); + + auto &instanceData = result->m_instanceBindless->getObject(); + instanceData.placementMatrixInd = BufferChunkHelperVLK::castToChunk(result->m_placementMatrix)->getSubBuffer()->getIndex(); + instanceData.boneMatrixInd = BufferChunkHelperVLK::castToChunk(result->m_bonesData)->getSubBuffer()->getIndex(); + instanceData.m2ColorsInd = BufferChunkHelperVLK::castToChunk(result->m_colors)->getSubBuffer()->getIndex(); + instanceData.textureWeightsInd = BufferChunkHelperVLK::castToChunk(result->m_textureWeights)->getSubBuffer()->getIndex(); + instanceData.textureMatricesInd = BufferChunkHelperVLK::castToChunk(result->m_textureMatrices)->getSubBuffer()->getIndex(); + instanceData.modelFragmentDatasInd = BufferChunkHelperVLK::castToChunk(result->m_modelFragmentData)->getSubBuffer()->getIndex(); + result->m_instanceBindless->save(); return result; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 698bc2837..d9f925cc8 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -14,8 +14,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { public: - explicit MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config); - ~MapSceneRenderForwardVLK() override = default; + explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderVisBufferVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType); @@ -118,6 +118,19 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboStaticBuffer; + struct { + HGBufferVLK placementMatrix; + HGBufferVLK boneMatrix; + HGBufferVLK m2Colors; + HGBufferVLK textureWeights; + HGBufferVLK textureMatrices; + HGBufferVLK modelVertexDatas; + HGBufferVLK modelFragmentDatas; + + HGBufferVLK m2InstanceData; + HGBufferVLK meshWideBlocks; + } m2Buffers; + HGBufferVLK uboBuffer; HGBufferVLK uboM2BoneMatrixBuffer; @@ -154,4 +167,5 @@ class IM2ModelDataVisVLK : public IM2ModelData { }; + #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index b53d7c91f..5191a4ac3 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -200,7 +200,7 @@ FFXGlowPassVLK::createFFXGaussMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {"forwardRendering"}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() @@ -225,7 +225,7 @@ FFXGlowPassVLK::createFFXGlowMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {"forwardRendering"}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() From 1d77c7b7515cf7628fea7959b4d286f37cd9b2ce Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 20 Aug 2023 17:24:57 +0300 Subject: [PATCH 098/212] - support for bindless descriptorLayout --- src/ui/renderer/uiScene/FrontendUIRenderer.h | 6 +- .../shaders/glsl/visBuffer/m2Shader.frag | 11 ++-- .../src/engine/shader/ShaderDefinitions.h | 7 +-- .../src/gapi/interface/materials/IMaterial.h | 17 ++++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 53 +++++++++++++--- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 17 +++-- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 2 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 18 +++++- .../descriptorSets/GDescriptorPoolVLK.h | 3 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 7 ++- .../vulkan/descriptorSets/GDescriptorSet.h | 2 +- .../descriptorSets/GDescriptorSetLayout.cpp | 55 ++++++++++++++-- .../descriptorSets/GDescriptorSetLayout.h | 9 ++- .../vulkan/materials/MaterialBuilderVLK.h | 1 - .../src/gapi/vulkan/shaders/ShaderConfig.h | 15 ++++- .../vulkan/MapSceneRenderForwardVLK.cpp | 6 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 62 +++++++++++++++---- .../vulkan/MapSceneRenderVisBufferVLK.h | 20 ++++++ 18 files changed, 253 insertions(+), 58 deletions(-) diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 46e475779..f8be0c3a0 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -19,11 +19,11 @@ static const std::array imguiBindings = {{ static const PipelineTemplate s_imguiPipelineTemplate = { DrawElementMode::TRIANGLES, - true, - true, - false, false, + true, EGxBlendEnum::GxBlend_Alpha, + false, + true, 0xFF }; diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index b9b358876..857a13dd0 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require precision highp float; precision highp int; @@ -39,10 +40,8 @@ layout(std430, set=2, binding=8) buffer meshWideBlockVSPS { meshWideBlockVSPSBindless meshWides[]; }; -layout(set=3,binding=6) uniform sampler2D uTexture; -layout(set=3,binding=7) uniform sampler2D uTexture2; -layout(set=3,binding=8) uniform sampler2D uTexture3; -layout(set=3,binding=9) uniform sampler2D uTexture4; + +layout (set = 3, binding = 0) uniform sampler2D s_Textures[]; void main() { /* Animation support */ @@ -142,8 +141,10 @@ void main() { bool doDiscard = false; + calcM2FragMaterial(uPixelShader, - uTexture, uTexture2, uTexture3, uTexture4, + s_Textures[meshWide.textureIndicies.x], s_Textures[meshWide.textureIndicies.y], + s_Textures[meshWide.textureIndicies.z], s_Textures[meshWide.textureIndicies.w], texCoord, texCoord2, texCoord3, vMeshColorAlpha.rgb, vMeshColorAlpha.a, uTexSampleAlpha.rgb, diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 08928dfa6..c39f50d11 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1019,17 +1019,14 @@ const std::unordered_map shaderMetaInfo = { {1,3,0}, }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index 01aea4ffd..9fb9a4005 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -11,13 +11,24 @@ struct PipelineTemplate { DrawElementMode element; - bool triCCW = true; //counter-clockwise - bool depthWrite = true; - bool depthCulling = true; bool backFaceCulling = true; + bool triCCW = true; //counter-clockwise EGxBlendEnum blendMode; + bool depthCulling = true; + bool depthWrite = true; uint8_t colorMask = 0xFF; + + bool operator==(const PipelineTemplate &other) const { + return + (element == other.element) && + (backFaceCulling == other.backFaceCulling) && + (triCCW == other.triCCW) && + (blendMode == other.blendMode) && + (depthCulling == other.depthCulling) && + (depthWrite == other.depthWrite) && + (colorMask == other.colorMask); + }; }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 36e2a80d7..0adcb7e05 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -184,13 +184,21 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma throw std::runtime_error("validation layers requested, but not available!"); } + uint32_t apiVersion = VK_API_VERSION_1_0; + if (vkEnumerateInstanceVersion != nullptr) { + + vkEnumerateInstanceVersion(&apiVersion); + } + + if (apiVersion > VK_API_VERSION_1_2) apiVersion = VK_API_VERSION_1_2; + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "Hello Triangle"; + appInfo.pApplicationName = "WoW Map Viewer"; appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "No Engine"; + appInfo.pEngineName = "CustomMadeEngine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_0; + appInfo.apiVersion = apiVersion; VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; @@ -616,6 +624,21 @@ void GDeviceVLK::createLogicalDevice() { queueCreateInfos.push_back(queueCreateInfo); } + VkPhysicalDeviceDescriptorIndexingFeatures indexing_features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT, nullptr }; + bool bindless_supported = false; + bool hasDeviceFeatures2 = vkGetPhysicalDeviceFeatures2 != nullptr; + if (hasDeviceFeatures2) { + VkPhysicalDeviceFeatures2 device_features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &indexing_features}; + vkGetPhysicalDeviceFeatures2(physicalDevice, &device_features); + + bindless_supported = indexing_features.shaderSampledImageArrayNonUniformIndexing && + indexing_features.runtimeDescriptorArray && + indexing_features.descriptorBindingVariableDescriptorCount && + indexing_features.descriptorBindingPartiallyBound ; + } + + + VkPhysicalDeviceFeatures deviceFeatures = {}; deviceFeatures.samplerAnisotropy = true; @@ -639,6 +662,19 @@ void GDeviceVLK::createLogicalDevice() { createInfo.enabledLayerCount = 0; } + VkPhysicalDeviceFeatures2 physical_features2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + if ( bindless_supported ) { + // This should be already set to VK_TRUE, as we queried before. + indexing_features.descriptorBindingPartiallyBound = VK_TRUE; + indexing_features.runtimeDescriptorArray = VK_TRUE; + + vkGetPhysicalDeviceFeatures2( physicalDevice, &physical_features2 ); + physical_features2.pNext = &indexing_features; + + + createInfo.pNext = &physical_features2; + } + if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { throw std::runtime_error("failed to create logical device!"); } @@ -1289,9 +1325,12 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings VkDescriptorSet GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) { + bool isBindlessDS = hDescriptorSetLayout->getIsBindless(); + auto &dsPools = isBindlessDS ? m_bindlessDescriptorPools : m_descriptorPools; + //1. Try to allocate from existing sets - for (int i = m_descriptorPools.size() - 1; i >= 0 ; i--) { - desciptorPool = m_descriptorPools[i]; + for (int i = dsPools.size() - 1; i >= 0 ; i--) { + desciptorPool = dsPools[i]; auto result = desciptorPool->allocate(hDescriptorSetLayout); if (result != nullptr) { return result; @@ -1299,9 +1338,9 @@ GDeviceVLK::allocateDescriptorSetPrimitive(const std::shared_ptr(*this); + auto newPool = std::make_shared(*this, isBindlessDS); desciptorPool = newPool; - m_descriptorPools.push_back(newPool); + dsPools.push_back(newPool); return newPool->allocate(hDescriptorSetLayout); } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 442ca502d..a2232e364 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -158,7 +158,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &hDescriptorSetLayout, - std::shared_ptr &desciptorPool) override; + std::shared_ptr &out_desciptorPool) override; std::shared_ptr createDescriptorSet(std::shared_ptr &hDescriptorSetLayout); @@ -233,6 +233,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.depthCulling) << 8) ^ (hash{}(k.depthWrite) << 10) ^ (hash{}(k.blendMode) << 14) ^ - (hash{}(k.element) << 16); + (hash{}(k.element) << 16) ^ + (hash{}(k.colorMask) << 18); }; }; std::unordered_map, PipelineCacheRecordHasher> loadedPipeLines; @@ -309,6 +312,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> frameBufSemaphores; std::vector> m_descriptorPools; + std::vector> m_bindlessDescriptorPools; VmaAllocator vmaAllocator; @@ -355,7 +359,12 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.shaderConfig.shaderFolder); for (const auto &rec : k.shaderConfig.typeOverrides) for (const auto &rec2 : rec.second) - mapHash ^= hash{}(rec2.second) << 4 ^ hash{}(rec2.first) << 4 ^ hash{}(rec.first) << 4; + mapHash ^= + hash{}(rec2.second.type) << 4 ^ + hash{}(rec2.second.isBindless) << 8 ^ + hash{}(rec2.second.descriptorCount) << 10 ^ + hash{}(rec2.first) << 12 ^ + hash{}(rec.first) << 16; return hash{}(k.name) ^ mapHash; diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index 660419cd3..601be9c3e 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -32,7 +32,7 @@ class IDeviceVulkan { virtual VkDevice getVkDevice() = 0; virtual void addDeallocationRecord(std::function callback) = 0; virtual VkDescriptorSet allocateDescriptorSetPrimitive( - const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &desciptorPool) = 0; + const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &out_desciptorPool) = 0; virtual VmaAllocator getVMAAllocator() = 0; virtual VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index 385524b9c..745c7e3d4 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -6,9 +6,10 @@ #include #include "GDescriptorPoolVLK.h" -GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) { +GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device, bool isBindless) : m_device(device) { uniformsAvailable = 4*4096; - dynUniformsAvailable = 4*4096; + dynUniformsAvailable = 4*1024; + ssboAvailable = 4*1024; imageAvailable = 4096 * 4; setsAvailable = 4096 * 4; @@ -19,6 +20,8 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) poolSizes[1].descriptorCount = static_cast(imageAvailable); poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; poolSizes[2].descriptorCount = static_cast(dynUniformsAvailable); + poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + poolSizes[3].descriptorCount = static_cast(ssboAvailable); VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -27,6 +30,8 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device) : m_device(device) poolInfo.maxSets = setsAvailable; poolInfo.pNext = nullptr; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT ; + if (isBindless) + poolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; if (vkCreateDescriptorPool(m_device.getVkDevice(), &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); @@ -41,6 +46,7 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptr descLayouts = {hDescriptorSetLayout->getSetLayout()}; + VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.pNext = NULL; @@ -50,6 +56,14 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptrgetBindlessDescSizes(); + bool isBindless = !descSizes.empty(); + if (isBindless) { + count_info.descriptorSetCount = descSizes.size(); + count_info.pDescriptorCounts = descSizes.data(); + allocInfo.pNext = &count_info; + } VkDescriptorSet descriptorSet; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h index 86a156978..6fed11711 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h @@ -13,7 +13,7 @@ class GDescriptorPoolVLK; class GDescriptorPoolVLK : public std::enable_shared_from_this{ public: - explicit GDescriptorPoolVLK(IDeviceVulkan &device); + explicit GDescriptorPoolVLK(IDeviceVulkan &device, bool isBindless); VkDescriptorSet allocate(const std::shared_ptr &gDescriptorSetLayout); void deallocate(const std::shared_ptr &hDescriptorLayout, VkDescriptorSet descSet); @@ -24,6 +24,7 @@ class GDescriptorPoolVLK : public std::enable_shared_from_this &device, const std::shared_ptr &hDescriptorSetLayout) : m_device(device), m_hDescriptorSetLayout(hDescriptorSetLayout) { + //Gets DS and gets pool it was allocated from into m_parentPool m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); assert(m_descriptorSet != nullptr); } @@ -67,7 +68,7 @@ void GDescriptorSet::getDynamicOffsets(std::array &dynamicOffsets, // ------------------------------------- GDescriptorSet::SetUpdateHelper & -GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture &samplableTextureVlk) { +GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture &samplableTextureVlk, int index) { auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); #if (!defined(NDEBUG)) @@ -77,7 +78,7 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture } #endif - auto textureVlk = samplableTextureVlk!=nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getTexture()) : nullptr; + auto textureVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getTexture()) : nullptr; auto samplerVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getSampler()) : nullptr; assignBoundDescriptors(bindIndex, samplableTextureVlk, DescriptorRecord::DescriptorRecordType::Texture); @@ -102,7 +103,7 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture writeDescriptor.dstSet = m_set.getDescSet(); writeDescriptor.pNext = nullptr; writeDescriptor.dstBinding = bindIndex; - writeDescriptor.dstArrayElement = 0; + writeDescriptor.dstArrayElement = index; writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptor.descriptorCount = 1; writeDescriptor.pBufferInfo = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 2212913ac..6521f8bb6 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -55,7 +55,7 @@ class GDescriptorSet : public std::enable_shared_from_this { SetUpdateHelper& ssbo(int bindIndex, const std::shared_ptr &buffer); //TODO: add version of this array texture case (aka bindless) - SetUpdateHelper& texture(int bindIndex, const HGSamplableTexture &textureVlk); + SetUpdateHelper& texture(int bindIndex, const HGSamplableTexture &textureVlk, int index = 0); void cancelUpdate(); template diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index a6d83aec8..5da452b3c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -13,6 +13,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr const DescTypeOverride &typeOverrides) : m_device(device) { //Create Layout auto &shaderLayoutBindings = m_shaderLayoutBindings; + std::unordered_set bindlessBindPoints; for (const auto p_metaData : metaDatas) { auto const &metaData = *p_metaData; @@ -40,9 +41,9 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr if (typeOverrides.find(uboBinding.set) != typeOverrides.end()) { auto &setTypeOverrides = typeOverrides.at(uboBinding.set); if (setTypeOverrides.find(uboBinding.binding) != setTypeOverrides.end()) { - auto overrideType = setTypeOverrides.at(uboBinding.binding); - assert(overrideType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); - uniformType = overrideType; + auto const &overrideStruct = setTypeOverrides.at(uboBinding.binding); + assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); + uniformType = overrideStruct.type; } } } @@ -103,8 +104,23 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr imageLayoutBinding.pImmutableSamplers = nullptr; imageLayoutBinding.stageFlags = vkStageFlag; + { + if (typeOverrides.find(imageBinding.set) != typeOverrides.end()) { + auto &setTypeOverrides = typeOverrides.at(imageBinding.set); + if (setTypeOverrides.find(imageBinding.binding) != setTypeOverrides.end()) { + auto const &overrideStruct = setTypeOverrides.at(imageBinding.binding); + assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + if (overrideStruct.isBindless) { + m_isBindless = true; + imageLayoutBinding.descriptorCount = overrideStruct.descriptorCount; + bindlessBindPoints.insert(imageBinding.binding); + } + } + } + } + shaderLayoutBindings.insert({imageBinding.binding, imageLayoutBinding}); - m_totalImages++; + m_totalImages += imageLayoutBinding.descriptorCount; m_requiredBindPoints[imageBinding.binding] = true; } @@ -113,13 +129,42 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr std::vector layouts(shaderLayoutBindings.size()); std::transform(shaderLayoutBindings.begin(), shaderLayoutBindings.end(), layouts.begin(), [](auto &pair){return pair.second;}); - + std::sort(layouts.begin(), layouts.end(), [](VkDescriptorSetLayoutBinding &a, VkDescriptorSetLayoutBinding &b) -> bool { + return a.binding < b.binding; + }); + + VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags{}; + binding_flags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + std::vector flags; + + if (m_isBindless) { + m_bindlessDescSizes.resize(layouts.size()); + flags.resize(layouts.size()); + binding_flags.bindingCount = layouts.size(); + binding_flags.pBindingFlags = flags.data(); + + for (int i = 0; i < layouts.size(); i++) { + auto const &layout = layouts[i]; + if (bindlessBindPoints.find(layout.binding) != bindlessBindPoints.end()) { + m_bindlessDescSizes[i] = layout.descriptorCount; + flags[i] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + } else { + m_bindlessDescSizes[i] = 0; + flags[i] = 0; + } + } + } //Create VK descriptor layout VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.bindingCount = layouts.size(); layoutInfo.pBindings = (!layouts.empty()) ? layouts.data() : nullptr; + layoutInfo.pNext = nullptr; + if (m_isBindless) { + layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + layoutInfo.pNext = &binding_flags; + } if (vkCreateDescriptorSetLayout(m_device->getVkDevice(), &layoutInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 35485785b..d1b78f5a9 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -31,15 +31,20 @@ class GDescriptorSetLayout { const std::unordered_map& getShaderLayoutBindings() const {return m_shaderLayoutBindings;} ; const std::unordered_map& getRequiredUBOSize() const {return m_requiredUBOSize;} ; - const std::unordered_map& getRequiredSSBOSize() const {return m_requiredUBOSize;} ; + const std::unordered_map& getRequiredSSBOSize() const {return m_requiredSSBOSize;} ; + const std::vector& getBindlessDescSizes() const {return m_bindlessDescSizes;} ; int getTotalUbos() { return m_totalUbos; }; int getTotalDynUbos() { return m_totalDynUbos; }; int getTotalImages() { return m_totalImages; }; + bool getIsBindless() { return m_isBindless; }; std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; private: std::unordered_map m_shaderLayoutBindings; std::unordered_map m_requiredUBOSize; + std::unordered_map m_requiredSSBOSize; + + std::vector m_bindlessDescSizes; std::bitset m_requiredBindPoints = 0; VkDescriptorSetLayout m_descriptorSetLayout; @@ -47,6 +52,8 @@ class GDescriptorSetLayout { int m_totalUbos = 0; int m_totalDynUbos = 0; + bool m_isBindless = false; + std::shared_ptr m_device; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 4ab8e58d0..52f10f716 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -22,7 +22,6 @@ class MaterialBuilderVLK { return {device, shaderFiles, shaderConfig}; } - template static MaterialBuilderVLK fromMaterial(const std::shared_ptr &device, const std::shared_ptr &materialVlk) { return {device, materialVlk->getShader(), diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 9ce03fff4..7b156727f 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -9,7 +9,20 @@ #include "../context/vulkan_context.h" //Per DescSet -> per binding point -typedef std::unordered_map> DescTypeOverride; +struct DescTypeConfig { + VkDescriptorType type; + bool isBindless = false; + int descriptorCount = 1; + + bool operator==(const DescTypeConfig &other) const { + return + (type == other.type) && + (isBindless == other.isBindless) && + (descriptorCount == other.descriptorCount); + }; +}; + +typedef std::unordered_map> DescTypeOverride; struct ShaderConfig { std::string shaderFolder; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 6410d9421..94380cc96 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -20,7 +20,7 @@ static const ShaderConfig forwardShaderConfig = { "forwardRendering", { {0, { - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }} } }; @@ -28,10 +28,10 @@ static const ShaderConfig m2ForwardShaderConfig = { "forwardRendering", { {0, { - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }}, {1, { - {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }} }}; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index cfb5a0023..72fbca5a2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -20,18 +20,22 @@ static const ShaderConfig forwardShaderConfig = { "forwardRendering", { {0, { - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }} } }; +const int m2TexturesBindlessCount = 2048; static const ShaderConfig m2VisShaderConfig = { "visBuffer", { {0, { - {0, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }}, {1, { - {1, VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC} + {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + }}, + {3, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; @@ -120,9 +124,8 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic sceneWideDS = ds; }); - //Create global m2Material + //Create global m2 descriptor for bindless textures MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) - .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() .ssbo(1, m2Buffers.placementMatrix) @@ -133,14 +136,46 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic .ssbo(6, m2Buffers.textureMatrices) .ssbo(7, m2Buffers.m2InstanceData) .ssbo(8, m2Buffers.meshWideBlocks); + + m2BufferOneDS = ds; }) .createDescriptorSet(2, [&](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(7, m2Buffers.modelVertexDatas); + .ssbo(7, m2Buffers.modelVertexDatas); + + m2BufferTwoDS = ds; + }) + .createDescriptorSet(3, [&](std::shared_ptr &ds) { + m2TextureDS = ds; }); } // ------------------ + + +std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { + auto i = m_m2StaticMaterials.find(pipelineTemplate); + if (i != m_m2StaticMaterials.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + m_m2StaticMaterials.erase(i); + } + } + + auto staticMaterial = + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, m2BufferOneDS) + .bindDescriptorSet(2, m2BufferTwoDS) + .bindDescriptorSet(3, m2TextureDS) + .toMaterial(); + + m_m2StaticMaterials[pipelineTemplate] = staticMaterial; + + return staticMaterial; +} // Buffer creation // ------------------ @@ -321,19 +356,22 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(m2Buffers.modelVertexDatas); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + auto staticMaterial = getM2StaticMaterial(pipelineTemplate); - .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { + auto material = MaterialBuilderVLK::fromMaterial(m_device, staticMaterial) + .toMaterial([&vertexFragmentData](IM2MaterialVis *instance) -> void { + instance->m_vertexFragmentData = vertexFragmentData; + }); + + /* + .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() .texture(6, m2MaterialTemplate.textures[0]) .texture(7, m2MaterialTemplate.textures[1]) .texture(8, m2MaterialTemplate.textures[2]) .texture(9, m2MaterialTemplate.textures[3]); }) - .toMaterial([&vertexFragmentData](IM2MaterialVis *instance) -> void { - instance->m_vertexFragmentData = vertexFragmentData; - }); + */ material->blendMode = pipelineTemplate.blendMode; material->depthWrite = pipelineTemplate.depthWrite; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index d9f925cc8..04ab22641 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -11,6 +11,7 @@ #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" +#include "../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { public: @@ -96,6 +97,22 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; +private: + std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); + + struct PipelineTemplateHasher { + std::size_t operator()(const PipelineTemplate& k) const { + using std::hash; + return (hash{}(k.backFaceCulling) << 2) ^ + (hash{}(k.triCCW) << 4) ^ + (hash{}(k.depthCulling) << 8) ^ + (hash{}(k.depthWrite) << 10) ^ + (hash{}(k.blendMode) << 14) ^ + (hash{}(k.element) << 16) ^ + (hash{}(k.colorMask) << 18); + }; + }; + std::unordered_map, PipelineTemplateHasher> m_m2StaticMaterials; private: HGDeviceVLK m_device; @@ -142,6 +159,9 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr> sceneWideChunk; std::shared_ptr sceneWideDS = nullptr; + std::shared_ptr m2TextureDS = nullptr; + std::shared_ptr m2BufferOneDS = nullptr; + std::shared_ptr m2BufferTwoDS = nullptr; std::shared_ptr m_renderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; From 8a1f2fa73160b2ebff6da7c8422bf2c6a5dbaad4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 27 Aug 2023 02:51:32 +0300 Subject: [PATCH 099/212] - small progress with fog --- src/database/CEmptySqliteDB.h | 4 +- src/database/CSqliteDB.cpp | 163 +++++++++++++++--- src/database/CSqliteDB.h | 36 +++- .../glsl/common/commonFogFunctions.glsl | 14 +- .../src/engine/objects/scenes/map.cpp | 5 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 7 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 69 ++++---- .../descriptorSets/GDescriptorSetLayout.cpp | 4 +- wowViewerLib/src/include/database/dbStructs.h | 1 + wowViewerLib/src/include/databaseHandler.h | 4 +- .../renderer/mapScene/MapSceneRenderer.cpp | 25 ++- 12 files changed, 237 insertions(+), 97 deletions(-) diff --git a/src/database/CEmptySqliteDB.h b/src/database/CEmptySqliteDB.h index b9f12b6a2..71b2f127d 100644 --- a/src/database/CEmptySqliteDB.h +++ b/src/database/CEmptySqliteDB.h @@ -14,8 +14,8 @@ class CEmptySqliteDB : public IClientDatabase { bool getMapById(int mapId, MapRecord &mapRecord) override {return false;}; AreaRecord getArea(int areaId) override { return {}; }; AreaRecord getWmoArea(int wmoId, int nameId, int groupId) override { return {}; }; - void getLightById(int lightId, int time, LightResult &lightResult) override {}; - void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) override {}; + void getLightById(int lightId, int time, LightResult &lightResult, float zFar) override {}; + void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float zFar) override {}; void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; void getZoneLightsForMap(int mapId, std::vector &zoneLights) override {}; diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 60d0cf6c4..f7e931921 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -140,7 +140,10 @@ CSqliteDB::CSqliteDB(std::string dbFileName) : getLightStatement(m_sqliteDatabase, getLightSQL), getLightByIdStatement(m_sqliteDatabase, getLightByIdSQL), - getLightData(m_sqliteDatabase, lightDataSQL), +// getLightData(m_sqliteDatabase, lightDataSQL), + getLightData(m_sqliteDatabase, generateSimpleSelectSQL("LightData", + {"LightParamID", "ID"}, + " where LightParamID = ? ORDER BY Time ASC")), getLiquidObjectInfo(m_sqliteDatabase,liquidObjectInfoSQL), getLiquidTypeInfo(m_sqliteDatabase, liquidTypeSQL), getLiquidTextureFileDataIds(m_sqliteDatabase, getHasLiquidTypeXTexture(m_sqliteDatabase) ? liquidTextureFileDataIdsSQL : "select 1 from Map;"), @@ -311,7 +314,7 @@ inline void addOnlyOne(std::array &colorF, int currLdRes, float innerA inline void addOnlyOne(float &colorF, float currLdRes, float innerAlpha) { colorF += currLdRes * innerAlpha; } -void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult) { +void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, float farClip) { getLightByIdStatement.setInputs( lightId ); std::vector innerResults; @@ -331,13 +334,13 @@ void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult) { ilr.blendAlpha = 1.0f; } std::vector lightResults; - convertInnerResultsToPublic(time, lightResults, innerResults); + convertInnerResultsToPublic(time, lightResults, innerResults, farClip); if (lightResults.size() > 0) { lightResult = lightResults[0]; } }; -void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std::vector &lightResults) { +void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std::vector &lightResults, float farClip) { getLightStatement.setInputs( mapId, x, y, z ); std::vector innerResults; @@ -378,7 +381,7 @@ void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std: ilr.isDefault = true; } } - convertInnerResultsToPublic(ptime, lightResults, innerResults); + convertInnerResultsToPublic(ptime, lightResults, innerResults, farClip); } void CSqliteDB::addOnlyOne(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &currLdRes, @@ -488,7 +491,8 @@ void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerL } void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector &lightResults, - std::vector &innerResults) { + std::vector &innerResults, + float farClip) { //From lowest to highest std::sort(innerResults.begin(), innerResults.end(), [](const InnerLightResult &a, const InnerLightResult &b) { @@ -558,14 +562,36 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector lightResult.lightSkyboxId = innerResult.lightSkyboxId; lightResult.glow = innerResult.glow; + bool hasHorizonAmbientColor = getLightData.getFieldIndex("HorizonAmbientColor") >= 0; + bool hasGroundAmbientColor = getLightData.getFieldIndex("GroundAmbientColor") >= 0; + bool hasFogDensity = getLightData.getFieldIndex("FogDensity") >= 0; + bool hasFogHeight = getLightData.getFieldIndex("FogHeight") >= 0; + bool hasFogHeightScaler = getLightData.getFieldIndex("FogHeightScaler") >= 0; + bool hasFogHeightDensity = getLightData.getFieldIndex("FogHeightDensity") >= 0; + bool hasSunFogAngle = getLightData.getFieldIndex("SunFogAngle") >= 0; + bool hasEndFogColor = getLightData.getFieldIndex("EndFogColor") >= 0; + bool hasEndFogColorDistance = getLightData.getFieldIndex("EndFogColorDistance") >= 0; + bool hasSunFogColor = getLightData.getFieldIndex("SunFogColor") >= 0; + bool hasSunFogStrength = getLightData.getFieldIndex("SunFogStrength") >= 0; + bool hasFogHeightColor = getLightData.getFieldIndex("FogHeightColor") >= 0; + bool hasFogHeightCoefficients = getLightData.getFieldIndex("HeightDensityFogCoeff") >= 0; + bool hasFogZScalar = getLightData.getFieldIndex("FogZScalar") >= 0; + bool hasMainFogStartDist = getLightData.getFieldIndex("MainFogStartDist") >= 0; + bool hasMainFogEndDist = getLightData.getFieldIndex("MainFogEndDist") >= 0; + bool hasFogStartOffset = getLightData.getFieldIndex("FogStartOffset") >= 0; + bool hasEndFogHeightColor = getLightData.getFieldIndex("EndFogHeightColor") >= 0; + bool hasMainFogCoefficients = getLightData.getFieldIndex("MainFogCoefficients_0") >= 0; + bool hasHeightDensityFogCoeff = getLightData.getFieldIndex("HeightDensityFogCoeff_0") >= 0; + while (getLightData.execute()) { InnerLightDataRes currLdRes; currLdRes.ambientLight = getLightData.getField("AmbientColor"); - currLdRes.horizontAmbientColor = getLightData.getField("HorizonAmbientColor"); + currLdRes.horizontAmbientColor = hasHorizonAmbientColor ? getLightData.getField("HorizonAmbientColor") : 0; + if (currLdRes.horizontAmbientColor == 0) { currLdRes.horizontAmbientColor = currLdRes.ambientLight; } - currLdRes.groundAmbientColor = getLightData.getField("GroundAmbientColor"); + currLdRes.groundAmbientColor = hasGroundAmbientColor ? getLightData.getField("GroundAmbientColor") : 0; if (currLdRes.groundAmbientColor == 0) { currLdRes.groundAmbientColor = currLdRes.ambientLight; } @@ -586,44 +612,109 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector currLdRes.FogEnd = getLightData.getField("FogEnd").getDouble(); currLdRes.FogScaler = getLightData.getField("FogScaler").getDouble(); - currLdRes.FogDensity = getLightData.getField("FogDensity").getDouble(); - currLdRes.FogHeight = getLightData.getField("FogHeight").getDouble(); - currLdRes.FogHeightScaler = getLightData.getField("FogHeightScaler").getDouble(); - currLdRes.FogHeightDensity = getLightData.getField("FogHeightDensity").getDouble(); - currLdRes.SunFogAngle = getLightData.getField("SunFogAngle").getDouble(); - currLdRes.EndFogColor = getLightData.getField("EndFogColor").getInt(); - currLdRes.EndFogColorDistance = getLightData.getField("EndFogColorDistance").getDouble(); - currLdRes.SunFogColor = getLightData.getField("SunFogColor").getInt(); - currLdRes.SunFogStrength = getLightData.getField("SunFogStrength").getDouble(); - currLdRes.FogHeightColor = getLightData.getField("FogHeightColor").getInt(); - currLdRes.FogHeightCoefficients[0] = getLightData.getField("FogHeightCoefficients_0").getDouble(); - currLdRes.FogHeightCoefficients[1] = getLightData.getField("FogHeightCoefficients_1").getDouble(); - currLdRes.FogHeightCoefficients[2] = getLightData.getField("FogHeightCoefficients_2").getDouble(); - currLdRes.FogHeightCoefficients[3] = getLightData.getField("FogHeightCoefficients_3").getDouble(); + currLdRes.FogDensity = hasFogDensity ? getLightData.getField("FogDensity").getDouble() : 0.000001f; + currLdRes.FogHeight = hasFogHeight ? getLightData.getField("FogHeight").getDouble() : -10000.0; + currLdRes.FogHeightScaler = hasFogHeightScaler ? getLightData.getField("FogHeightScaler").getDouble() : -1.0f; + currLdRes.FogHeightDensity = hasFogHeightDensity ? getLightData.getField("FogHeightDensity").getDouble() : 0.0f; + currLdRes.FogZScalar = hasFogZScalar ? getLightData.getField("FogZScalar").getDouble() : 0.0f; + currLdRes.MainFogStartDist = hasMainFogStartDist ? getLightData.getField("MainFogStartDist").getDouble() : 0.0f; + currLdRes.MainFogStartDist = hasMainFogEndDist ? getLightData.getField("MainFogEndDist").getDouble() : 0.0f; + currLdRes.SunFogAngle = hasSunFogAngle ? getLightData.getField("SunFogAngle").getDouble() : 0.f; + currLdRes.EndFogColor = hasEndFogColor ? getLightData.getField("EndFogColor").getInt() : 0; + currLdRes.EndFogColorDistance = hasEndFogColorDistance ? getLightData.getField("EndFogColorDistance").getDouble() : 0; + currLdRes.FogStartOffset = hasFogStartOffset ? getLightData.getField("FogStartOffset").getDouble() : 0; + currLdRes.SunFogColor = hasSunFogColor ? getLightData.getField("SunFogColor").getInt() : 0; + currLdRes.SunFogStrength = hasSunFogStrength ? getLightData.getField("SunFogStrength").getDouble() : 0.0f; + currLdRes.FogHeightColor = hasFogHeightColor ? getLightData.getField("FogHeightColor").getInt() : 0.0f; + currLdRes.EndFogHeightColor = hasEndFogHeightColor ? getLightData.getField("EndFogHeightColor").getInt() : 0; + currLdRes.FogHeightCoefficients[0] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_0").getDouble() : 0.0f; + currLdRes.FogHeightCoefficients[1] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_1").getDouble(): 0.0f; + currLdRes.FogHeightCoefficients[2] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_2").getDouble(): 0.0f; + currLdRes.FogHeightCoefficients[3] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_3").getDouble(): 0.0f; + currLdRes.MainFogCoefficients[0] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_0").getDouble() : 0.0f; + currLdRes.MainFogCoefficients[1] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_1").getDouble(): 0.0f; + currLdRes.MainFogCoefficients[2] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_2").getDouble(): 0.0f; + currLdRes.MainFogCoefficients[3] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_3").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[0] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_0").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[1] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_1").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[2] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_2").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[3] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_3").getDouble(): 0.0f; currLdRes.time = getLightData.getField("Time").getInt(); + //Hacks for loading of fog information if (!currLdRes.EndFogColor) { currLdRes.EndFogColor = currLdRes.SkyFogColor; } if (!currLdRes.FogHeightColor) { currLdRes.FogHeightColor = currLdRes.SkyFogColor; } + if (!currLdRes.EndFogHeightColor) { + currLdRes.FogHeightColor = currLdRes.EndFogColor; + } + currLdRes.FogScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); + currLdRes.FogEnd = std::max(currLdRes.FogEnd, 10.0f); + currLdRes.FogHeight = std::max(currLdRes.FogEnd, -10000.0f); + currLdRes.FogHeightScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); + if (!currLdRes.SunFogColor) + currLdRes.SunFogAngle = 1.0f; + if (currLdRes.FogHeightScaler == 0.0) { currLdRes.FogHeightDensity = currLdRes.FogDensity; } + if (currLdRes.FogHeight > 10000.0f) + currLdRes.FogHeight = 0.0f; + + if (currLdRes.FogDensity <= 0.0f) { + float a = std::min(farClip, 700.0) - 200.0; + float b = currLdRes.FogEnd - (float)(currLdRes.FogEnd * lastLdRes.FogScaler); + if ( b > a || a <= 0.0 ) + currLdRes.FogDensity = 1.5; + else + currLdRes.FogDensity = (float)((float)(1.0 - (float)(b / a)) * 5.5) + 1.5; + } if (currLdRes.time > ptime) { assigned = true; + //Blend using time as alpha + float timeAlphaBlend = 1.0f - (((float) currLdRes.time - (float) ptime) / + ((float) currLdRes.time - (float) lastLdRes.time)); + + + //Hack for SunFogAngle + { + auto SunFogAngle2 = currLdRes.SunFogAngle; + auto SunFogAngle1 = lastLdRes.SunFogAngle; + if (SunFogAngle2 >= 1.0f && SunFogAngle1 >= 1.0f) { + lightResult.SunAngleBlend = 0.0f; + lightResult.SunFogStrength = 0.0f; + lightResult.SunFogAngle = 1.0f; + } else + if (SunFogAngle1 < 1.0 && SunFogAngle2 < 1.0) { + lightResult.SunAngleBlend = 1.0f; + ::blendTwoAndAdd(lightResult.SunFogStrength, + currLdRes.SunFogStrength, lastLdRes.SunFogStrength, + timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.SunFogAngle, + currLdRes.SunFogAngle, lastLdRes.SunFogAngle, + timeAlphaBlend, innerAlpha); + lightResult.SunFogAngle = 1.0f; + } else + if ((SunFogAngle2 >= 1.0f and SunFogAngle2 >= 1.0) || (SunFogAngle1 < 1.0 and SunFogAngle2 >= 1.0)) + { + lightResult.SunAngleBlend = 1.0f - timeAlphaBlend; + lightResult.SunFogStrength = lastLdRes.SunFogStrength; + lightResult.SunFogAngle = lastLdRes.SunFogAngle; + } else { + lightResult.SunAngleBlend = timeAlphaBlend; + lightResult.SunFogAngle = SunFogAngle2; + lightResult.SunFogStrength = currLdRes.SunFogStrength; + } + } if (lastLdRes.time == -1) { addOnlyOne(lightResult, currLdRes, innerAlpha); - } else { - //Blend using time as alpha - float timeAlphaBlend = 1.0f - (((float) currLdRes.time - (float) ptime) / - ((float) currLdRes.time - (float) lastLdRes.time)); - blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend, innerAlpha); } break; @@ -752,3 +843,21 @@ void CSqliteDB::getZoneLightsForMap(int mapId, std::vector &zoneLight } } } + +std::string +CSqliteDB::generateSimpleSelectSQL(const std::string &tableName, const std::vector &skipColumnNames, + const std::string &whereClause) { + std::string query = "SELECT "; + std::vector fieldList = getTableFields(m_sqliteDatabase, tableName); + + bool fieldWasAdded = false; + for (auto const &fieldName : fieldList) { + if (std::find(skipColumnNames.begin(), skipColumnNames.end(), fieldName) == std::end(skipColumnNames)) { + query += fieldName + ", "; + fieldWasAdded = true; + } + } + query = query.substr(0, query.size()-2); + query += " FROM "+tableName+" "+whereClause; + return query; +} diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index d540ef88e..0dcaff72d 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -21,14 +21,18 @@ class CSqliteDB : public IClientDatabase { AreaRecord getArea(int areaId) override; AreaRecord getWmoArea(int wmoId, int nameId, int groupId) override; - void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) override; - void getLightById(int lightId, int time, LightResult &lightResult) override; + void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) override; + void getLightById(int lightId, int time, LightResult &lightResult, float farClip) override; void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; void getLiquidTexture(int liquidTypeId, std::vector &textures); void getZoneLightsForMap(int mapId, std::vector &zoneLights) override; private: + std::string generateSimpleSelectSQL(const std::string &tableName, + const std::vector &skipColumnNames, + const std::string &whereClause); + class StatementFieldHolder { public: StatementFieldHolder(SQLite::Database &database, const std::string &query); @@ -110,6 +114,20 @@ class CSqliteDB : public IClientDatabase { return m_hasWdtId; } + std::vector getTableFields(SQLite::Database &sqliteDatabase, const std::string &tableName) { + std::vector result; + SQLite::Statement statement(sqliteDatabase, "PRAGMA table_info('"+tableName+"') "); + try { + while (statement.executeStep()) { + result.push_back(statement.getColumn("name").getString()); + } + } catch (...) { + + } + + return result; + } + struct InnerLightResult { float pos[3]; float fallbackStart; @@ -125,8 +143,8 @@ class CSqliteDB : public IClientDatabase { struct InnerLightDataRes { int ambientLight; - int horizontAmbientColor; - int groundAmbientColor; + int horizontAmbientColor = 0; + int groundAmbientColor = 0; int directLight; int closeRiverColor; @@ -147,18 +165,26 @@ class CSqliteDB : public IClientDatabase { float FogHeight; float FogHeightScaler; float FogHeightDensity; + float FogZScalar; + float MainFogStartDist; + float MainFogEndDist; float SunFogAngle; int EndFogColor; float EndFogColorDistance; + float FogStartOffset; int SunFogColor; float SunFogStrength; int FogHeightColor; + int EndFogHeightColor; float FogHeightCoefficients[4]; + float MainFogCoefficients[4]; + float HeightDensityFogCoeff[4]; int time; }; - void convertInnerResultsToPublic(int ptime, std::vector &lightResults, std::vector &innerResults); + void convertInnerResultsToPublic(int ptime, std::vector &lightResults, + std::vector &innerResults, float farClip); void addOnlyOne(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &currLdRes, diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index b0a104986..5ba775a1a 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -62,12 +62,12 @@ vec4 makeFog(const in PSFog fogData, in vec4 final, in vec3 vertexInViewSpace, i float vLength = length(vertexInViewSpace); float z = (vLength - bias); float expMax = max(0.0, (z - start)); - float expFog = 1 / (exp((expMax * density))); - float expFogHeight = 1 / (exp((expMax * l_heightDensity_and_endColor.x))); + float expFog = 1.0 / (exp((expMax * density))); + float expFogHeight = 1.0 / (exp((expMax * l_heightDensity_and_endColor.x))); float height = (dot(l_heightPlane.xyz, vertexInViewSpace) + l_heightPlane.w); - float heightFog = clamp((height * l_color_and_heightRate.w), 0, 1); + float heightFog = clamp((height * l_color_and_heightRate.w), 0.0, 1.0); float finalFog = mix(expFog, expFogHeight, heightFog); - float endFadeFog = clamp((1.42857146 * (1.0 - (vLength / end))), 0, 1); + float endFadeFog = clamp((1.42857146 * (1.0 - (vLength / end))), 0.0, 1.0); float alpha = 1.0; if (blendMode == 13) { @@ -79,13 +79,13 @@ vec4 makeFog(const in PSFog fogData, in vec4 final, in vec3 vertexInViewSpace, i float end2 = (vLength / l_heightColor_and_endFogDistance.w); float end2_cube = (end2 * (end2 * end2)); - vec3 heightColor = mix(validateFogColor(l_heightColor_and_endFogDistance.xyz, blendMode), endColor, vec3(clamp(end2, 0, 1))); - vec3 fogFinal = mix(validateFogColor(l_color_and_heightRate.xyz, blendMode), endColor, vec3(clamp(end2_cube, 0, 1))); + vec3 heightColor = mix(validateFogColor(l_heightColor_and_endFogDistance.xyz, blendMode), endColor, vec3(clamp(end2, 0.0, 1.0))); + vec3 fogFinal = mix(validateFogColor(l_color_and_heightRate.xyz, blendMode), endColor, vec3(clamp(end2_cube, 0.0, 1.0))); fogFinal = mix(fogFinal, heightColor, vec3(heightFog)); float nDotSun = dot(normalize(vertexInViewSpace), sunDirInViewSpace.xyz); vec3 sunColor = mix(fogFinal, validateFogColor(fogData.sunAngle_and_sunColor.yzw, blendMode), vec3(fogData.sunPercentage.x)); - nDotSun = clamp((nDotSun - fogData.sunAngle_and_sunColor.x), 0, 1); + nDotSun = clamp((nDotSun - fogData.sunAngle_and_sunColor.x), 0.0, 1.0); if ((nDotSun > 0.0)) { nDotSun = ((nDotSun * nDotSun) * nDotSun); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 337634110..3ae553a5a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -934,7 +934,7 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } if (zoneLightFound) { - m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult); + m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult, config->farPlane); if (stateForConditions != nullptr) { stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId); } @@ -945,7 +945,8 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, cameraVec3.y, cameraVec3.z, config->currentTime, - lightResults + lightResults, + config->farPlane ); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 0adcb7e05..297e2fb9a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -185,12 +185,11 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma } uint32_t apiVersion = VK_API_VERSION_1_0; - if (vkEnumerateInstanceVersion != nullptr) { - + if (vkEnumerateInstanceVersion != nullptr) vkEnumerateInstanceVersion(&apiVersion); - } - if (apiVersion > VK_API_VERSION_1_2) apiVersion = VK_API_VERSION_1_2; + if (apiVersion > VK_API_VERSION_1_2) + apiVersion = VK_API_VERSION_1_2; VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index 745c7e3d4..8806b74ec 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -31,7 +31,7 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device, bool isBindless) : poolInfo.pNext = nullptr; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT ; if (isBindless) - poolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + poolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; if (vkCreateDescriptorPool(m_device.getVkDevice(), &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 1394010ff..1c46167bd 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -20,15 +20,17 @@ GDescriptorSet::~GDescriptorSet() { }; GDescriptorSet::SetUpdateHelper GDescriptorSet::beginUpdate() { - if (!m_firstUpdate) { - //In this implementation of descriptor set, the descriptor set is getting free'd on update - //and new one is created - - //This deallocate already have deallocate queue queue submission inside - m_parentPool->deallocate(m_hDescriptorSetLayout, m_descriptorSet); - - m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); - assert(m_descriptorSet != nullptr); + if (!m_hDescriptorSetLayout->getIsBindless()) { + if (!m_firstUpdate) { + //For normal (non-bindless) implementation of descriptor set, the descriptor set is getting free'd on update + //and new one is created + + //This deallocate already have deallocate queue queue submission inside + m_parentPool->deallocate(m_hDescriptorSetLayout, m_descriptorSet); + + m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); + assert(m_descriptorSet != nullptr); + } } return SetUpdateHelper(*this, boundDescriptors, m_device->getDescriptorSetUpdater()); } @@ -262,35 +264,36 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { } //FOR DEBUG AND STABILITY - - //Fill the rest of Descriptor with already bound values - //This is needed, cause In this implementation of descriptor set, the descriptor set is getting free'd on update - //and new one is created - for (int bindPoint = 0; bindPoint < m_updateBindPoints.size(); bindPoint++) { - if(m_updateBindPoints[bindPoint] || m_boundDescriptors[bindPoint] == nullptr) continue; - - if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBO) { - ubo(bindPoint, m_boundDescriptors[bindPoint]->buffer); - } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBODynamic) { - ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint]->buffer); - } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::Texture) { - texture(bindPoint, m_boundDescriptors[bindPoint]->texture); + if (!m_set.m_hDescriptorSetLayout->getIsBindless()) { + //Fill the rest of Descriptor with already bound values + //This is needed, cause In this implementation of descriptor set, the descriptor set is getting free'd on update + //and new one is created + for (int bindPoint = 0; bindPoint < m_updateBindPoints.size(); bindPoint++) { + if (m_updateBindPoints[bindPoint] || m_boundDescriptors[bindPoint] == nullptr) continue; + + if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBO) { + ubo(bindPoint, m_boundDescriptors[bindPoint]->buffer); + } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBODynamic) { + ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint]->buffer); + } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::Texture) { + texture(bindPoint, m_boundDescriptors[bindPoint]->texture); + } } - } - auto noSetBitSet = - m_set.getDescSetLayout()->getRequiredBindPoints() & (~m_updateBindPoints); + auto noSetBitSet = + m_set.getDescSetLayout()->getRequiredBindPoints() & (~m_updateBindPoints); - if (!noSetBitSet.none()) { - std::string notSetBits; - for (int i = 0; i < noSetBitSet.size(); i++) { - if(noSetBitSet[i]) { - notSetBits += " " + std::to_string(i); + if (!noSetBitSet.none()) { + std::string notSetBits; + for (int i = 0; i < noSetBitSet.size(); i++) { + if (noSetBitSet[i]) { + notSetBits += " " + std::to_string(i); + } } - } - std::cerr << "required descriptors " << notSetBits << " were not set during update" << std::endl; - throw std::runtime_error("required descriptors were not set"); + std::cerr << "required descriptors " << notSetBits << " were not set during update" << std::endl; + throw std::runtime_error("required descriptors were not set"); + } } std::sort(dynamicBufferIndexes.begin(), dynamicBufferIndexes.end()); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 5da452b3c..e174c2d90 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -147,7 +147,9 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr auto const &layout = layouts[i]; if (bindlessBindPoints.find(layout.binding) != bindlessBindPoints.end()) { m_bindlessDescSizes[i] = layout.descriptorCount; - flags[i] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + flags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT ; } else { m_bindlessDescSizes[i] = 0; flags[i] = 0; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index eccdcdc9e..8cc0d49c1 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -40,6 +40,7 @@ struct LightResult { float FogHeightScaler; float FogHeightDensity; float SunFogAngle; + float SunAngleBlend = 0.0f; std::array EndFogColor; float EndFogColorDistance; diff --git a/wowViewerLib/src/include/databaseHandler.h b/wowViewerLib/src/include/databaseHandler.h index f66f6b838..2089e14c5 100644 --- a/wowViewerLib/src/include/databaseHandler.h +++ b/wowViewerLib/src/include/databaseHandler.h @@ -15,8 +15,8 @@ class IClientDatabase { virtual bool getMapById(int mapId, MapRecord &mapRecord) = 0; virtual AreaRecord getArea(int areaId) = 0; virtual AreaRecord getWmoArea(int wmoId, int nameId, int groupId) = 0; - virtual void getLightById(int lightId, int time, LightResult &lightResult) = 0; - virtual void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults) = 0; + virtual void getLightById(int lightId, int time, LightResult &lightResult, float farClip) = 0; + virtual void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) = 0; virtual void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; virtual void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; virtual void getZoneLightsForMap(int mapId, std::vector &zoneLights) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index bec1a587d..302da4b52 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -137,24 +137,23 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorDirectColorDir, 1.0); blockPSVS.extLight.uAdtSpecMult = mathfu::vec4(m_config->adtSpecMult, 0, 0, 1.0); -// float fogEnd = std::min(config->getFarPlane(), config->getFogEnd()); - float fogEnd = m_config->farPlane; + float fogEnd = std::min(std::max(m_config->farPlane, 277.5), m_config->farPlane); if (m_config->disableFog || !fdd->FogDataFound) { fogEnd = 100000000.0f; fdd->FogScaler = 0; fdd->FogDensity = 0; } - float fogStart = std::max(m_config->farPlane - 250, 0); - fogStart = std::max(fogEnd - fdd->FogScaler * (fogEnd - fogStart), 0); - + float fogScaler = fdd->FogScaler; + if (fogScaler <= 0.00000001f) fogScaler = 0.5f; + float fogStart = 300;//std::min(m_config->farPlane, 3000) * fogScaler; blockPSVS.fogData.densityParams = mathfu::vec4( fogStart, fogEnd, - fdd->FogDensity / 1000, + fdd->FogDensity , 0); - blockPSVS.fogData.heightPlane = mathfu::vec4(0, 0, 0, 0); + blockPSVS.fogData.heightPlane = mathfu::vec4(0, 0, 0, 10000); blockPSVS.fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); blockPSVS.fogData.heightDensity_and_endColor = mathfu::vec4( fdd->FogHeightDensity, @@ -164,18 +163,18 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrSunFogAngle, - fdd->SunFogColor.x * fdd->SunFogStrength, - fdd->SunFogColor.y * fdd->SunFogStrength, - fdd->SunFogColor.z * fdd->SunFogStrength + fdd->SunFogColor.x, + fdd->SunFogColor.y, + fdd->SunFogColor.z ); blockPSVS.fogData.heightColor_and_endFogDistance = mathfu::vec4( fdd->FogHeightColor, (fdd->EndFogColorDistance > 0) ? - fdd->EndFogColorDistance : - 1000.0f + fdd->EndFogColorDistance : + 1000.0f ); blockPSVS.fogData.sunPercentage = mathfu::vec4( - (fdd->SunFogColor.Length() > 0) ? 0.5f : 0.0f, 0, 0, 0); + fdd->SunFogAngle * fdd->SunFogStrength, 0, 0, 0); sceneWideChunk->saveVersion(0); } From a06fee80eda2a4cbd5cf7b8fdc6e94b79af96822 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 27 Aug 2023 22:26:57 +0300 Subject: [PATCH 100/212] - small progress with fog 2.0, but formulas just do not work --- src/database/CSqliteDB.cpp | 87 +++- .../glsl/common/commonFogFunctions.glsl | 197 +++++++++ .../glsl/forwardRendering/adtShader.frag | 3 +- .../forwardRendering/m2ParticleShader.frag | 2 +- .../glsl/forwardRendering/m2Shader.frag | 2 +- .../glsl/forwardRendering/ribbonShader.frag | 2 +- .../glsl/forwardRendering/waterShader.frag | 2 +- .../forwardRendering/waterfallShader.frag | 2 +- .../glsl/forwardRendering/wmoShader.frag | 3 +- .../shaders/glsl/visBuffer/m2Shader.frag | 2 +- .../src/engine/camera/firstPersonCamera.cpp | 5 - .../src/engine/objects/scenes/map.cpp | 42 +- .../src/engine/shader/ShaderDefinitions.h | 382 ++++++++++++------ .../src/gapi/UniformBufferStructures.h | 22 +- wowViewerLib/src/include/database/dbStructs.h | 17 +- .../renderer/mapScene/FrameDependentData.h | 9 + .../renderer/mapScene/MapSceneRenderer.cpp | 46 ++- 17 files changed, 649 insertions(+), 176 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index f7e931921..5dbb58d19 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -272,6 +272,12 @@ void initWithZeros(std::array &colorF) { colorF[1] = 0; colorF[2] = 0; } +void initWithZeros(std::array &colorF) { + colorF[0] = 0; + colorF[1] = 0; + colorF[2] = 0; + colorF[3] = 0; +} void blendTwoAndAdd(float *colorF, int currLdRes, int lastLdRes, float timeAlphaBlend, float innerAlpha) { colorF[0] += (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + getFloatFromInt<0>(lastLdRes) * @@ -410,16 +416,32 @@ void CSqliteDB::addOnlyOne(LightResult &lightResult, ::addOnlyOne(lightResult.FogHeight, currLdRes.FogHeight, innerAlpha); ::addOnlyOne(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, innerAlpha); ::addOnlyOne(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, innerAlpha); - ::addOnlyOne(lightResult.SunFogAngle, currLdRes.SunFogAngle, innerAlpha); + ::addOnlyOne(lightResult.EndFogColor, currLdRes.EndFogColor, innerAlpha); ::addOnlyOne(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, innerAlpha); ::addOnlyOne(lightResult.SunFogColor, currLdRes.SunFogColor, innerAlpha); - ::addOnlyOne(lightResult.SunFogStrength, currLdRes.SunFogStrength, innerAlpha); + ::addOnlyOne(lightResult.FogHeightColor, currLdRes.FogHeightColor, innerAlpha); ::addOnlyOne(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0], innerAlpha); ::addOnlyOne(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], innerAlpha); ::addOnlyOne(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], innerAlpha); ::addOnlyOne(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], innerAlpha); + + ::addOnlyOne(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], innerAlpha); + ::addOnlyOne(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], innerAlpha); + ::addOnlyOne(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], innerAlpha); + ::addOnlyOne(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], innerAlpha); + + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], innerAlpha); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], innerAlpha); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], innerAlpha); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], innerAlpha); + + ::addOnlyOne(lightResult.FogZScalar, currLdRes.FogZScalar, innerAlpha); + ::addOnlyOne(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, innerAlpha); + ::addOnlyOne(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, innerAlpha); + ::addOnlyOne(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor, innerAlpha); + ::addOnlyOne(lightResult.FogStartOffset, currLdRes.FogStartOffset, innerAlpha); } void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &lastLdRes, @@ -488,6 +510,31 @@ void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerL ::blendTwoAndAdd(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], lastLdRes.FogHeightCoefficients[1], timeAlphaBlend, innerAlpha); ::blendTwoAndAdd(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], lastLdRes.FogHeightCoefficients[2], timeAlphaBlend, innerAlpha); ::blendTwoAndAdd(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], lastLdRes.FogHeightCoefficients[3], timeAlphaBlend, innerAlpha); + + + ::blendTwoAndAdd(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], lastLdRes.MainFogCoefficients[0], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], lastLdRes.MainFogCoefficients[1], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], lastLdRes.MainFogCoefficients[2], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], lastLdRes.MainFogCoefficients[3], timeAlphaBlend, innerAlpha); + + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], lastLdRes.HeightDensityFogCoeff[0], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], lastLdRes.HeightDensityFogCoeff[1], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], lastLdRes.HeightDensityFogCoeff[2], timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], lastLdRes.HeightDensityFogCoeff[3], timeAlphaBlend, innerAlpha); + + ::blendTwoAndAdd(lightResult.FogZScalar, currLdRes.FogZScalar, lastLdRes.FogZScalar, timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, lastLdRes.MainFogStartDist, timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, lastLdRes.MainFogEndDist, timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor,lastLdRes.EndFogHeightColor, timeAlphaBlend, innerAlpha); + ::blendTwoAndAdd(lightResult.FogStartOffset, currLdRes.FogStartOffset, lastLdRes.FogStartOffset, timeAlphaBlend, innerAlpha); +} + +float arr4SqrLength(const std::array &arr) { + return + arr[0] * arr[0] + + arr[1] * arr[1] + + arr[2] * arr[2] + + arr[3] * arr[3]; } void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector &lightResults, @@ -523,7 +570,10 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector initWithZeros(lightResult.SunFogColor); initWithZeros(lightResult.FogHeightColor); initWithZeros(lightResult.FogHeightCoefficients); - lightResult.FogHeightCoefficients[3] = 0; + initWithZeros(lightResult.MainFogCoefficients); + initWithZeros(lightResult.HeightDensityFogCoefficients); + initWithZeros(lightResult.HeightEndFogColor); + lightResult.skyBoxFdid = 0; lightResult.lightSkyboxId = 0; @@ -538,6 +588,12 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector lightResult.SunFogAngle = 0.0; lightResult.EndFogColorDistance = 0.0; lightResult.SunFogStrength = 0.0; + lightResult.FogZScalar = 0.0; + lightResult.LegacyFogScalar = 0.0; + lightResult.MainFogStartDist = 0.0; + lightResult.MainFogEndDist = 0.0; + lightResult.FogBlendAlpha = 0.0; + lightResult.FogStartOffset = 0.0; @@ -574,7 +630,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector bool hasSunFogColor = getLightData.getFieldIndex("SunFogColor") >= 0; bool hasSunFogStrength = getLightData.getFieldIndex("SunFogStrength") >= 0; bool hasFogHeightColor = getLightData.getFieldIndex("FogHeightColor") >= 0; - bool hasFogHeightCoefficients = getLightData.getFieldIndex("HeightDensityFogCoeff") >= 0; + bool hasFogHeightCoefficients = getLightData.getFieldIndex("FogHeightCoefficients_0") >= 0; bool hasFogZScalar = getLightData.getFieldIndex("FogZScalar") >= 0; bool hasMainFogStartDist = getLightData.getFieldIndex("MainFogStartDist") >= 0; bool hasMainFogEndDist = getLightData.getFieldIndex("MainFogEndDist") >= 0; @@ -618,7 +674,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector currLdRes.FogHeightDensity = hasFogHeightDensity ? getLightData.getField("FogHeightDensity").getDouble() : 0.0f; currLdRes.FogZScalar = hasFogZScalar ? getLightData.getField("FogZScalar").getDouble() : 0.0f; currLdRes.MainFogStartDist = hasMainFogStartDist ? getLightData.getField("MainFogStartDist").getDouble() : 0.0f; - currLdRes.MainFogStartDist = hasMainFogEndDist ? getLightData.getField("MainFogEndDist").getDouble() : 0.0f; + currLdRes.MainFogEndDist = hasMainFogEndDist ? getLightData.getField("MainFogEndDist").getDouble() : 0.0f; currLdRes.SunFogAngle = hasSunFogAngle ? getLightData.getField("SunFogAngle").getDouble() : 0.f; currLdRes.EndFogColor = hasEndFogColor ? getLightData.getField("EndFogColor").getInt() : 0; currLdRes.EndFogColorDistance = hasEndFogColorDistance ? getLightData.getField("EndFogColorDistance").getDouble() : 0; @@ -635,10 +691,10 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector currLdRes.MainFogCoefficients[1] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_1").getDouble(): 0.0f; currLdRes.MainFogCoefficients[2] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_2").getDouble(): 0.0f; currLdRes.MainFogCoefficients[3] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_3").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[0] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_0").getDouble() : 0.0f; - currLdRes.HeightDensityFogCoeff[1] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_1").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[2] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_2").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[3] = hasFogHeightCoefficients ? getLightData.getField("HeightDensityFogCoeff_3").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[0] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_0").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[1] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_1").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[2] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_2").getDouble(): 0.0f; + currLdRes.HeightDensityFogCoeff[3] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_3").getDouble(): 0.0f; currLdRes.time = getLightData.getField("Time").getInt(); @@ -650,7 +706,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector currLdRes.FogHeightColor = currLdRes.SkyFogColor; } if (!currLdRes.EndFogHeightColor) { - currLdRes.FogHeightColor = currLdRes.EndFogColor; + currLdRes.EndFogHeightColor = currLdRes.EndFogColor; } currLdRes.FogScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); currLdRes.FogEnd = std::max(currLdRes.FogEnd, 10.0f); @@ -680,7 +736,6 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector float timeAlphaBlend = 1.0f - (((float) currLdRes.time - (float) ptime) / ((float) currLdRes.time - (float) lastLdRes.time)); - //Hack for SunFogAngle { auto SunFogAngle2 = currLdRes.SunFogAngle; @@ -711,7 +766,6 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector lightResult.SunFogStrength = currLdRes.SunFogStrength; } } - if (lastLdRes.time == -1) { addOnlyOne(lightResult, currLdRes, innerAlpha); } else { @@ -726,6 +780,15 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector addOnlyOne(lightResult, lastLdRes, innerAlpha); } + //Hack for LegacyFogScaler + if ( + arr4SqrLength(lightResult.MainFogCoefficients) > 0.00000011920929f || + arr4SqrLength(lightResult.MainFogCoefficients) > 0.00000011920929f + ) { + lightResult.LegacyFogScalar = 0.0f; + } else { + lightResult.LegacyFogScalar = 1.0f; + } lightResults.push_back(lightResult); diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index 5ba775a1a..0a83e0876 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -1,12 +1,19 @@ struct PSFog { vec4 densityParams; + vec4 classicFogParams; vec4 heightPlane; vec4 color_and_heightRate; vec4 heightDensity_and_endColor; vec4 sunAngle_and_sunColor; vec4 heightColor_and_endFogDistance; vec4 sunPercentage; + vec4 sunDirection_and_fogZScalar; + vec4 heightFogCoeff; + vec4 mainFogCoeff; + vec4 heightDensityFogCoeff; + vec4 mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; + vec4 heightFogEndColor_fogStartOffset; }; const vec3 fogColors[14] = vec3[14]( @@ -97,3 +104,193 @@ vec4 makeFog(const in PSFog fogData, in vec4 final, in vec3 vertexInViewSpace, i return vec4(fogFinal, final.a * alpha); } +float saturatef(float x) { + return clamp(x, 0.0f, 1.0f); +} + +vec4 makeFog2(const in PSFog mainFogData, const in PSFog fogDataSecond, in vec4 final, in vec3 uViewUp, in vec3 vertexInViewSpaceMy, in vec3 sunDirInViewSpace, in int blendMode) { + float fogRateScalar = 1.0f; //Unk stuff atm. + bool t138 = false; //some strange parameter from materials + vec3 vertexInViewSpace = vertexInViewSpaceMy; + float vLength = length(vertexInViewSpace); + float _retVal_739; + bool _ret0_738; + float _retVal_715 = 0.0f; + float _retVal_913 = 0.0f; + float heightFog_912 = 0.0f; + + + vec4 classicFogParams = fogDataSecond.classicFogParams; + float classicFogEnabled = classicFogParams.x; + float classicEnd = classicFogParams.y; + float classicEndMinusStartInv = classicFogParams.z; + float classicRate = classicFogParams.w; + if (bool(classicFogEnabled)) + { + // Block 726 + float t_729 = max(0.0f, ((classicEnd - vLength) * classicEndMinusStartInv)); + float pow_730 = pow(t_729, classicRate); + float _retVal_731 = saturatef(pow_730); + _retVal_739 = _retVal_731; + _ret0_738 = true; + } + else + { + // Block 734 + _retVal_739 = _retVal_715; + _ret0_738 = false; + } + // Block 737 + float _retVal_742 = _retVal_739; + bool _ret0_741 = _ret0_738; + if (!(_ret0_741)) + { + // Block 743 + vec4 densityParams = fogDataSecond.densityParams; + float start = densityParams.x; + float end = densityParams.y; + float density = densityParams.z; + float bias = densityParams.w; + float heightRate = fogDataSecond.color_and_heightRate.w; + float heightDensity = fogDataSecond.heightDensity_and_endColor.x; + float fogZScalar = fogDataSecond.sunDirection_and_fogZScalar.w; + vec4 t755 = fogDataSecond.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; + float mainFogCurveEndDist = t755.x; + float mainFogCurveStartDist = t755.y; + float legacyFogBlend = t755.z; + vec3 viewSpaceUp = uViewUp; + float dotVal_763 = dot(viewSpaceUp, vertexInViewSpace); + vec3 adjustedVpos_777; + if (dotVal_763 > 0.0f) + { + // Block 765 + float clamp_766 = clamp(fogZScalar, 0.0f, dotVal_763); + vec3 adjustedVpos_768 = (vertexInViewSpace - (viewSpaceUp * clamp_766)); + adjustedVpos_777 = adjustedVpos_768; + } + else + { + // Block 770 + float clamp_772 = clamp(-(fogZScalar), dotVal_763, 0.0f); + vec3 adjustedVpos_774 = (vertexInViewSpace - (viewSpaceUp * clamp_772)); + adjustedVpos_777 = adjustedVpos_774; + } + // Block 776 + vec3 adjustedVpos_905 = adjustedVpos_777; + float vLength_778 = length(adjustedVpos_905); + float z_779 = (vLength_778 - bias); + float expMax_781 = max(0.0f, (z_779 - start)); + float exp_783 = exp((expMax_781 * heightDensity)); + float legacyExpFogHeight_784 = (1.0 / exp_783); + vec4 t785 = fogDataSecond.heightPlane; + float dot_787 = dot(t785.xyz, vertexInViewSpace); + float height_789 = (dot_787 + t785.w); + float saturate_791 = saturatef((height_789 * heightRate)); + float heightFog_792 = (1.0f - saturate_791); + vec4 t793 = fogDataSecond.heightFogCoeff; + float xSqrd_794 = (heightFog_792 * heightFog_792); + float xCubed_795 = (xSqrd_794 * heightFog_792); + float saturate_806 = saturatef(((((t793.x * xCubed_795) + (t793.y * xSqrd_794)) + (t793.z * heightFog_792)) + t793.w)); + float heightFog_807 = (1.0f - saturate_806); + float normalizedDistance_808 = (vLength_778 / end); + float exp_810 = exp((expMax_781 * density)); + float legacyFogResult_811 = (1.0 / exp_810); + float lerp_812 = mix(legacyFogResult_811, legacyExpFogHeight_784, heightFog_807); + float finalLegacyFog_815 = (1.0f - ((1.0f - lerp_812) * fogRateScalar)); + float endFadeFog_818 = saturatef((1.42857146f * (1.0f - normalizedDistance_808))); + float finalLegacyFog_819 = min(finalLegacyFog_815, endFadeFog_818); + float artFogNormalizedDistance_823 = saturatef(((vLength_778 - mainFogCurveStartDist) / (mainFogCurveEndDist - mainFogCurveStartDist))); + float engineFogNormalizedDistance_825 = saturatef((vLength_778 / mainFogCurveEndDist)); + vec4 t826 = fogDataSecond.mainFogCoeff; + float xSqrd_827 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); + float xCubed_828 = (xSqrd_827 * artFogNormalizedDistance_823); + float saturate_839 = saturatef(((((t826.x * xCubed_828) + (t826.y * xSqrd_827)) + (t826.z * artFogNormalizedDistance_823)) + t826.w)); + float fogResult_841 = saturatef((1.0f - saturate_839)); + vec4 t842 = fogDataSecond.heightDensityFogCoeff; + float xSqrd_843 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); + float xCubed_844 = (xSqrd_843 * artFogNormalizedDistance_823); + float saturate_855 = saturatef(((((t842.x * xCubed_844) + (t842.y * xSqrd_843)) + (t842.z * artFogNormalizedDistance_823)) + t842.w)); + float heightFogResult_857 = saturatef((1.0f - saturate_855)); + float lerp_858 = mix(fogResult_841, heightFogResult_857, heightFog_807); + float finalFog_861 = (1.0f - ((1.0f - lerp_858) * fogRateScalar)); + float endPct_863 = saturatef((end / mainFogCurveEndDist)); + float finalFogBeginPct_864 = (endPct_863 - 0.300000012f); + float xSqrd_865 = (finalFogBeginPct_864 * finalFogBeginPct_864); + float xCubed_866 = (xSqrd_865 * finalFogBeginPct_864); + float saturate_877 = saturatef(((((t826.x * xCubed_866) + (t826.y * xSqrd_865)) + (t826.z * finalFogBeginPct_864)) + t826.w)); + float mainFogValueAtBlendStart_878 = saturatef(saturate_877); + float xSqrd_879 = (finalFogBeginPct_864 * finalFogBeginPct_864); + float xCubed_880 = (xSqrd_879 * finalFogBeginPct_864); + float saturate_891 = saturatef(((((t842.x * xCubed_880) + (t842.y * xSqrd_879)) + (t842.z * finalFogBeginPct_864)) + t842.w)); + float heightFogValueAtBlendStart_892 = saturatef(saturate_891); + float fogValueAtBlendStart_893 = mix(mainFogValueAtBlendStart_878, heightFogValueAtBlendStart_892, heightFog_807); + float blendValue_896 = saturatef(((engineFogNormalizedDistance_825 - finalFogBeginPct_864) / 0.300000012f)); + float endFogValue_898 = (blendValue_896 * (1.0f - fogValueAtBlendStart_893)); + float endFogValue_899 = (endFogValue_898 + fogValueAtBlendStart_893); + float endFogValue_901 = saturatef((1.0f - endFogValue_899)); + float lerp_902 = mix(finalFog_861, endFogValue_901, blendValue_896); + float finalFog_903 = min(finalFog_861, lerp_902); + float _retVal_904 = mix(finalFog_903, finalLegacyFog_819, legacyFogBlend); + _retVal_913 = _retVal_904; + heightFog_912 = heightFog_807; + } + else + { + // Block 908 + _retVal_913 = _retVal_742; + heightFog_912 = 0.0f; + } + // Block 911 + float _retVal_956 = _retVal_913; + float heightFog_955 = heightFog_912; + vec3 normalize_918 = normalize(vertexInViewSpace); + float t924 = fogDataSecond.sunAngle_and_sunColor.x; + float alpha_935 = final.w; + float end2_938 = saturatef(((vLength - fogDataSecond.heightFogEndColor_fogStartOffset.w) / fogDataSecond.heightColor_and_endFogDistance.w)); + float end_940 = (end2_938 * (end2_938 * end2_938)); + vec3 heightColor_942 = mix(mainFogData.heightColor_and_endFogDistance.xyz, mainFogData.heightFogEndColor_fogStartOffset.xyz, vec3(end2_938)); + float saturate_943 = saturatef(end_940); + vec3 fogFinal_945 = mix(mainFogData.color_and_heightRate.xyz, mainFogData.heightDensity_and_endColor.yzw, vec3(saturate_943)); + vec3 fogFinal_947 = mix(fogFinal_945, heightColor_942, vec3(heightFog_955)); + float dot_948 = dot(normalize_918, fogDataSecond.sunDirection_and_fogZScalar.xyz); + float nDotSun_949 = saturatef(dot_948); + vec3 sunColor_951 = mix(fogFinal_947, mainFogData.sunAngle_and_sunColor.yzw, vec3(fogDataSecond.sunPercentage.x)); + float nDotSun_953 = saturatef((nDotSun_949 - t924)); + vec3 fogFinal_969; + if (nDotSun_953 > 0.0f) + { + // Block 957 + float nDotSun_960 = ((1.0f / (1.0f - t924)) * nDotSun_953); + float nDotSun_962 = ((nDotSun_960 * nDotSun_960) * nDotSun_960); + vec3 fogFinal_964 = mix(fogFinal_947, sunColor_951, vec3(nDotSun_962)); + fogFinal_969 = fogFinal_964; + } + else + { + // Block 966 + fogFinal_969 = fogFinal_947; + } + // Block 968 + vec3 fogFinal_971 = fogFinal_969; + float alpha_978; + if (bool(t138)) + { + // Block 972 + float alpha_973 = (alpha_935 * _retVal_956); + alpha_978 = alpha_973; + } + else + { + // Block 975 + alpha_978 = alpha_935; + } + // Block 977 + float alpha_988 = alpha_978; + vec3 lerp_981 = mix(fogFinal_971, final.xyz, vec3(_retVal_956)); + vec4 t982 = vec4(lerp_981, alpha_988); + vec4 outColor_713 = vec4(0.0); //accumulator + vec4 outColor_986 = (outColor_713 + (t982 * fogDataSecond.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); + + return outColor_986; +} + diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index edf2e250b..5aefc42b0 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -162,7 +162,8 @@ void main() { vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult.x; finalColor.rgb += specTerm; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); finalColor.a = 1.0; outColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index 0cc4a5767..6deaaba4d 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -104,7 +104,7 @@ void main() { // .xyz; vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); outputColor.rgba = finalColor ; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index d3c2d9b1b..3c8282555 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -173,7 +173,7 @@ void main() { ) .xyz; - finalColor = makeFog(fogData, finalColor, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index 3badb3882..e50d01405 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -46,7 +46,7 @@ void main() { vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); outputColor = finalColor; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 3738004c1..275225793 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -75,7 +75,7 @@ void main() { } //BlendMode is always GxBlend_Alpha - finalColor.rgb = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, 2).rgb; + finalColor.rgb = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; outputColor = vec4(finalColor.rgb, 0.7); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index b0d806222..eaa010acb 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -115,7 +115,7 @@ void main() { ); vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog(fogData, finalColor, vPosition.xyz, sunDir.xyz, 0); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); outputColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index c23ea6cc6..fb2f604d3 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -89,7 +89,8 @@ void main() { finalOpacity ); - finalColor = makeFog(fogData, finalColor, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); finalColor.a = 1.0; outputColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index 857a13dd0..bfa6ab5cf 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -191,7 +191,7 @@ void main() { ) .xyz; - finalColor = makeFog(fogData, finalColor, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 920f889af..9d9e26d54 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -137,7 +137,6 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { this->lookAt = camera + dir; -// cameraRotationMat = cameraRotationMat * MathHelper::RotationX(90*M_PI/180); lookAtMat = mathfu::mat4( right_move.x, up.x, -dir.x, 0.0f, right_move.y, up.y, -dir.y, 0.0f, @@ -149,10 +148,6 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { this->camera = mathfu::vec4(camera, 1.0);//(lookAtMat.Inverse() * mathfu::vec4(0,0,0,1.0)).xyz(); - //std::cout<<"camera " << camera[0] <<" "< combinedResults = {}; float totalSummator = 0.0; @@ -875,8 +883,18 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp SunFogColor += mathfu::vec3(_light.SunFogColor.data()) * _light.blendCoef; SunFogStrength += _light.SunFogStrength * _light.blendCoef; FogHeightColor += mathfu::vec3(_light.FogHeightColor.data()) * _light.blendCoef; - FogHeightCoefficients += mathfu::vec4(_light.FogHeightCoefficients) * _light.blendCoef; + FogHeightCoefficients += mathfu::vec4(_light.FogHeightCoefficients.data()) * _light.blendCoef; + MainFogCoefficients += mathfu::vec4(_light.MainFogCoefficients.data()) * _light.blendCoef; + HeightDensityFogCoefficients += mathfu::vec4(_light.HeightDensityFogCoefficients.data()) * _light.blendCoef; + FogZScalar += _light.FogZScalar * _light.blendCoef; + LegacyFogScalar += _light.LegacyFogScalar * _light.blendCoef; + MainFogStartDist += _light.MainFogStartDist * _light.blendCoef; + MainFogEndDist += _light.MainFogEndDist * _light.blendCoef; + FogBlendAlpha += _light.FogBlendAlpha * _light.blendCoef; + HeightEndFogColor += mathfu::vec3(_light.HeightEndFogColor.data()) * _light.blendCoef; + FogStartOffset += _light.FogStartOffset * _light.blendCoef; } + FogBlendAlpha = 1.0f; //In case of no data -> disable the fog { @@ -903,6 +921,18 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp fdd->FogHeightColor = mathfu::vec3(FogHeightColor[2], FogHeightColor[1], FogHeightColor[0]); fdd->FogHeightCoefficients = mathfu::vec4(FogHeightCoefficients[0], FogHeightCoefficients[1], FogHeightCoefficients[2], FogHeightCoefficients[3]); + fdd->MainFogCoefficients = mathfu::vec4(MainFogCoefficients[0], MainFogCoefficients[1], + MainFogCoefficients[2], MainFogCoefficients[3]); + fdd->HeightDensityFogCoefficients = mathfu::vec4(HeightDensityFogCoefficients[0], HeightDensityFogCoefficients[1], + HeightDensityFogCoefficients[2], HeightDensityFogCoefficients[3]); + + fdd->FogZScalar = FogZScalar; + fdd->LegacyFogScalar = LegacyFogScalar; + fdd->MainFogStartDist = MainFogStartDist; + fdd->MainFogEndDist = MainFogEndDist; + fdd->FogBlendAlpha = FogBlendAlpha; + fdd->HeightEndFogColor = mathfu::vec3(HeightEndFogColor[2], HeightEndFogColor[1], HeightEndFogColor[0]); + fdd->FogStartOffset = FogStartOffset; } } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index c39f50d11..b864af07d 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -304,7 +304,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,368}, + {0,0,480}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -346,7 +346,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,1,64}, - {0,0,368}, + {0,0,480}, {1,2,16}, }, { @@ -386,7 +386,7 @@ const std::unordered_map shaderMetaInfo = { {2,4,16}, {1,6,4096}, {1,3,16384}, - {0,0,368}, + {0,0,480}, {1,1,64}, {1,2,256}, {1,4,4096}, @@ -427,7 +427,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, {1,1,64}, }, { @@ -464,7 +464,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, {1,1,96}, }, { @@ -537,7 +537,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, }, { { @@ -684,7 +684,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {2,5,96}, - {0,0,368}, + {0,0,480}, {1,1,64}, {1,2,256}, {1,3,16384}, @@ -767,7 +767,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,1,112}, - {0,0,368}, + {0,0,480}, }, { { @@ -948,7 +948,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,2,48}, - {0,0,368}, + {0,0,480}, {1,1,64}, }, { @@ -994,7 +994,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,368}, + {0,0,480}, }, { { @@ -1075,7 +1075,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, {1,1,64}, }, { @@ -1151,7 +1151,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,368}, + {0,0,480}, }, { { @@ -1308,7 +1308,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,96}, - {0,0,368}, + {0,0,480}, }, { { @@ -1349,7 +1349,7 @@ const std::unordered_map shaderMetaInfo = { {1,5,256}, {1,4,4096}, {1,2,256}, - {0,0,368}, + {0,0,480}, {1,1,64}, {1,6,4096}, {1,3,16384}, @@ -1466,7 +1466,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,368}, + {0,0,480}, }, { { @@ -1505,7 +1505,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, }, { { @@ -1541,7 +1541,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,368}, + {0,0,480}, }, { { @@ -1651,7 +1651,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,368}, + {0,0,480}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -1694,7 +1694,7 @@ const std::unordered_map shaderMetaInfo = { { {1,4,16}, {1,3,4096}, - {0,0,368}, + {0,0,480}, }, { { @@ -1731,7 +1731,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,368}, + {0,0,480}, }, { { @@ -1810,12 +1810,19 @@ const std::unordered_map EndFogColor; float EndFogColorDistance; std::array SunFogColor; - float SunFogStrength; + float SunFogStrength; //Blended Separately std::array FogHeightColor; - float FogHeightCoefficients[4]; + std::array FogHeightCoefficients; + std::array MainFogCoefficients; + std::array HeightDensityFogCoefficients; + float FogZScalar = 0; + float LegacyFogScalar = 0; //calculated separately + float MainFogStartDist = 0; + float MainFogEndDist = 0; + float FogBlendAlpha = 0.0f; //Set manually in map.cpp //TODO BTW + std::array HeightEndFogColor; + float FogStartOffset = 0; std::string skyBoxName; diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 9469b8b20..3f2d33cdd 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -49,6 +49,15 @@ struct FrameDependantData { float SunFogStrength = 0; mathfu::vec3 FogHeightColor = mathfu::vec3(0,0,0); mathfu::vec4 FogHeightCoefficients = mathfu::vec4(0,0,0,0); + mathfu::vec4 MainFogCoefficients = mathfu::vec4(0,0,0,0); + mathfu::vec4 HeightDensityFogCoefficients = mathfu::vec4(0,0,0,0); + float FogZScalar = 0.00001; + float LegacyFogScalar = 0.00001; + float MainFogStartDist = 0.00001; + float MainFogEndDist = 0.00001; + float FogBlendAlpha = 0.00001; + mathfu::vec3 HeightEndFogColor = mathfu::vec3(0,0,0); + float FogStartOffset = 0.00001; //Water params bool useMinimapWaterColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 302da4b52..8702596da 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -119,6 +119,19 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrlookAtMat * mathfu::vec4((zUp * fdd->FogHeight).xyz(), 1.0f)).xyz(); + mathfu::vec4 heightPlaneVec = + renderingMatrices->invTranspViewMat * mathfu::vec4((zUp * fdd->FogHeight).xyz(), 0.0); + mathfu::vec3 heightPlaneVecNorm = heightPlaneVec.xyz().LengthSquared() > 0 ? + heightPlaneVec.Normalized().xyz() : + mathfu::vec3(0,0,0); + mathfu::vec4 heightPlane = mathfu::vec4( + heightPlaneVecNorm, + -(mathfu::vec3::DotProduct(heightPlaneVecNorm, zUpPointInView)) + ); auto &blockPSVS = sceneWideChunk->getObject(0); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; @@ -144,19 +157,21 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrFogDensity = 0; } + const float densityMultFix = 1.0/1000; ; float fogScaler = fdd->FogScaler; if (fogScaler <= 0.00000001f) fogScaler = 0.5f; - float fogStart = 300;//std::min(m_config->farPlane, 3000) * fogScaler; + float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; blockPSVS.fogData.densityParams = mathfu::vec4( fogStart, fogEnd, - fdd->FogDensity , + fdd->FogDensity * densityMultFix, 0); - blockPSVS.fogData.heightPlane = mathfu::vec4(0, 0, 0, 10000); + blockPSVS.fogData.classicFogParams = mathfu::vec4(0, 0, 0, 0); + blockPSVS.fogData.heightPlane = heightPlane; blockPSVS.fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); blockPSVS.fogData.heightDensity_and_endColor = mathfu::vec4( - fdd->FogHeightDensity, + fdd->FogHeightDensity * densityMultFix, fdd->EndFogColor.x, fdd->EndFogColor.y, fdd->EndFogColor.z @@ -174,7 +189,26 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrSunFogAngle * fdd->SunFogStrength, 0, 0, 0); - + 0.0f, //fdd->SunFogAngle * fdd->SunFogStrength, + 0, 1.0, 1.0); + blockPSVS.fogData.sunDirection_and_fogZScalar = mathfu::vec4( + fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position + fdd->FogZScalar + ); + blockPSVS.fogData.heightFogCoeff = fdd->FogHeightCoefficients; + blockPSVS.fogData.mainFogCoeff = fdd->MainFogCoefficients; + blockPSVS.fogData.heightDensityFogCoeff = fdd->HeightDensityFogCoefficients; + + bool mainFogOk = (fdd->MainFogStartDist + 0.001 <= fdd->MainFogEndDist); + blockPSVS.fogData.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( + mainFogOk ? fdd->MainFogEndDist : fdd->MainFogStartDist + 0.001, + fdd->MainFogStartDist >= 0.0 ? fdd->MainFogStartDist : 0.0f, + fdd->LegacyFogScalar, + fdd->FogBlendAlpha + ); + blockPSVS.fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( + fdd->HeightEndFogColor, + fdd->FogStartOffset + ); sceneWideChunk->saveVersion(0); } From 7210b7f49c6a6a8ab19b101798001c5b16d0bed0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 28 Aug 2023 14:38:56 +0300 Subject: [PATCH 101/212] Consider fog being mostly done. The picture is in reverse atm though --- src/database/CSqliteDB.cpp | 11 +- src/ui/FrontendUI.cpp | 72 +- .../glsl/common/commonFogFunctions.glsl | 340 +-- .../glsl/common/commonLightFunctions.glsl | 2 +- .../glsl/forwardRendering/adtShader.frag | 6 +- .../glsl/forwardRendering/adtShader.vert | 2 +- .../glsl/forwardRendering/drawBBShader.vert | 2 +- .../forwardRendering/drawPortalShader.vert | 2 +- .../forwardRendering/m2ParticleShader.frag | 4 +- .../forwardRendering/m2ParticleShader.vert | 2 +- .../glsl/forwardRendering/m2Shader.frag | 4 +- .../glsl/forwardRendering/m2Shader.vert | 2 +- .../glsl/forwardRendering/ribbonShader.frag | 4 +- .../glsl/forwardRendering/ribbonShader.vert | 2 +- .../glsl/forwardRendering/skyConus.frag | 2 +- .../glsl/forwardRendering/skyConus.vert | 2 +- .../glsl/forwardRendering/waterShader.frag | 4 +- .../glsl/forwardRendering/waterShader.vert | 2 +- .../forwardRendering/waterfallShader.frag | 4 +- .../forwardRendering/waterfallShader.vert | 2 +- .../glsl/forwardRendering/wmoShader.frag | 4 +- .../glsl/forwardRendering/wmoShader.vert | 2 +- .../shaders/glsl/visBuffer/m2Shader.frag | 4 +- .../shaders/glsl/visBuffer/m2Shader.vert | 2 +- .../src/engine/camera/firstPersonCamera.cpp | 12 +- .../src/engine/objects/adt/adtObject.cpp | 1 - .../src/engine/objects/m2/m2Object.cpp | 2 - .../src/engine/objects/scenes/map.cpp | 119 +- .../src/engine/shader/ShaderDefinitions.h | 2344 +++++++++++++++-- .../src/gapi/UniformBufferStructures.h | 5 +- .../src/gapi/interface/materials/IMaterial.h | 2 +- .../renderer/mapScene/FrameDependentData.h | 50 +- .../src/renderer/mapScene/MapScenePlan.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 142 +- 34 files changed, 2471 insertions(+), 690 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 5dbb58d19..8accc8087 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -710,14 +710,11 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector } currLdRes.FogScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); currLdRes.FogEnd = std::max(currLdRes.FogEnd, 10.0f); - currLdRes.FogHeight = std::max(currLdRes.FogEnd, -10000.0f); + currLdRes.FogHeight = std::max(currLdRes.FogHeight, -10000.0f); currLdRes.FogHeightScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); if (!currLdRes.SunFogColor) currLdRes.SunFogAngle = 1.0f; - if (currLdRes.FogHeightScaler == 0.0) { - currLdRes.FogHeightDensity = currLdRes.FogDensity; - } if (currLdRes.FogHeight > 10000.0f) currLdRes.FogHeight = 0.0f; @@ -727,9 +724,13 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector if ( b > a || a <= 0.0 ) currLdRes.FogDensity = 1.5; else - currLdRes.FogDensity = (float)((float)(1.0 - (float)(b / a)) * 5.5) + 1.5; + currLdRes.FogDensity = (float)((float)(1.0f - (float)(b / a)) * 5.5f) + 1.5f; } +// if (currLdRes.FogHeightScaler == 0.0) { +// currLdRes.FogHeightDensity = currLdRes.FogDensity; +// } + if (currLdRes.time > ptime) { assigned = true; //Blend using time as alpha diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 3f4ea2f91..92ec8ee0b 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -225,42 +225,42 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Separator(); } - - if (ImGui::CollapsingHeader("Current fog params")) { - if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { - ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); - ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); - ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); - ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); - ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); - ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); - ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); - ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogColor.x, - cullStageData->frameDependentData->FogColor.y, - cullStageData->frameDependentData->FogColor.z); - ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->EndFogColor.x, - cullStageData->frameDependentData->EndFogColor.y, - cullStageData->frameDependentData->EndFogColor.z); - ImGui::Text("End Fog Color Distance: %.3f", - cullStageData->frameDependentData->EndFogColorDistance); - ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->SunFogColor.x, - cullStageData->frameDependentData->SunFogColor.y, - cullStageData->frameDependentData->SunFogColor.z); - ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); - ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogHeightColor.x, - cullStageData->frameDependentData->FogHeightColor.y, - cullStageData->frameDependentData->FogHeightColor.z); - ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", - cullStageData->frameDependentData->FogHeightCoefficients.x, - cullStageData->frameDependentData->FogHeightCoefficients.y, - cullStageData->frameDependentData->FogHeightCoefficients.z); - ImGui::Separator(); - } - } +// +// if (ImGui::CollapsingHeader("Current fog params")) { +// if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { +// ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); +// ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); +// ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); +// ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); +// ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); +// ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); +// ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); +// ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogColor.x, +// cullStageData->frameDependentData->FogColor.y, +// cullStageData->frameDependentData->FogColor.z); +// ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->EndFogColor.x, +// cullStageData->frameDependentData->EndFogColor.y, +// cullStageData->frameDependentData->EndFogColor.z); +// ImGui::Text("End Fog Color Distance: %.3f", +// cullStageData->frameDependentData->EndFogColorDistance); +// ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->SunFogColor.x, +// cullStageData->frameDependentData->SunFogColor.y, +// cullStageData->frameDependentData->SunFogColor.z); +// ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); +// ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogHeightColor.x, +// cullStageData->frameDependentData->FogHeightColor.y, +// cullStageData->frameDependentData->FogHeightColor.z); +// ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", +// cullStageData->frameDependentData->FogHeightCoefficients.x, +// cullStageData->frameDependentData->FogHeightCoefficients.y, +// cullStageData->frameDependentData->FogHeightCoefficients.z); +// ImGui::Separator(); +// } +// } } } diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index 0a83e0876..39afa59ea 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -108,7 +108,7 @@ float saturatef(float x) { return clamp(x, 0.0f, 1.0f); } -vec4 makeFog2(const in PSFog mainFogData, const in PSFog fogDataSecond, in vec4 final, in vec3 uViewUp, in vec3 vertexInViewSpaceMy, in vec3 sunDirInViewSpace, in int blendMode) { +vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec3 uViewUp, in vec3 vertexInViewSpaceMy, in vec3 sunDirInViewSpace, in int blendMode) { float fogRateScalar = 1.0f; //Unk stuff atm. bool t138 = false; //some strange parameter from materials vec3 vertexInViewSpace = vertexInViewSpaceMy; @@ -119,178 +119,184 @@ vec4 makeFog2(const in PSFog mainFogData, const in PSFog fogDataSecond, in vec4 float _retVal_913 = 0.0f; float heightFog_912 = 0.0f; + vec4 outColor_713 = vec4(0.0); //accumulator - vec4 classicFogParams = fogDataSecond.classicFogParams; - float classicFogEnabled = classicFogParams.x; - float classicEnd = classicFogParams.y; - float classicEndMinusStartInv = classicFogParams.z; - float classicRate = classicFogParams.w; - if (bool(classicFogEnabled)) - { - // Block 726 - float t_729 = max(0.0f, ((classicEnd - vLength) * classicEndMinusStartInv)); - float pow_730 = pow(t_729, classicRate); - float _retVal_731 = saturatef(pow_730); - _retVal_739 = _retVal_731; - _ret0_738 = true; - } - else - { - // Block 734 - _retVal_739 = _retVal_715; - _ret0_738 = false; - } - // Block 737 - float _retVal_742 = _retVal_739; - bool _ret0_741 = _ret0_738; - if (!(_ret0_741)) - { - // Block 743 - vec4 densityParams = fogDataSecond.densityParams; - float start = densityParams.x; - float end = densityParams.y; - float density = densityParams.z; - float bias = densityParams.w; - float heightRate = fogDataSecond.color_and_heightRate.w; - float heightDensity = fogDataSecond.heightDensity_and_endColor.x; - float fogZScalar = fogDataSecond.sunDirection_and_fogZScalar.w; - vec4 t755 = fogDataSecond.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; - float mainFogCurveEndDist = t755.x; - float mainFogCurveStartDist = t755.y; - float legacyFogBlend = t755.z; - vec3 viewSpaceUp = uViewUp; - float dotVal_763 = dot(viewSpaceUp, vertexInViewSpace); - vec3 adjustedVpos_777; - if (dotVal_763 > 0.0f) + + for (int i = 0; i < fogCount; i++) { + vec4 classicFogParams = mainFogData[i].classicFogParams; + float classicFogEnabled = classicFogParams.x; + float classicEnd = classicFogParams.y; + float classicEndMinusStartInv = classicFogParams.z; + float classicRate = classicFogParams.w; + if (bool(classicFogEnabled)) { - // Block 765 - float clamp_766 = clamp(fogZScalar, 0.0f, dotVal_763); - vec3 adjustedVpos_768 = (vertexInViewSpace - (viewSpaceUp * clamp_766)); - adjustedVpos_777 = adjustedVpos_768; + // Block 726 + float t_729 = max(0.0f, ((classicEnd - vLength) * classicEndMinusStartInv)); + float pow_730 = pow(t_729, classicRate); + float _retVal_731 = saturatef(pow_730); + _retVal_739 = _retVal_731; + _ret0_738 = true; } else { - // Block 770 - float clamp_772 = clamp(-(fogZScalar), dotVal_763, 0.0f); - vec3 adjustedVpos_774 = (vertexInViewSpace - (viewSpaceUp * clamp_772)); - adjustedVpos_777 = adjustedVpos_774; + // Block 734 + _retVal_739 = _retVal_715; + _ret0_738 = false; } - // Block 776 - vec3 adjustedVpos_905 = adjustedVpos_777; - float vLength_778 = length(adjustedVpos_905); - float z_779 = (vLength_778 - bias); - float expMax_781 = max(0.0f, (z_779 - start)); - float exp_783 = exp((expMax_781 * heightDensity)); - float legacyExpFogHeight_784 = (1.0 / exp_783); - vec4 t785 = fogDataSecond.heightPlane; - float dot_787 = dot(t785.xyz, vertexInViewSpace); - float height_789 = (dot_787 + t785.w); - float saturate_791 = saturatef((height_789 * heightRate)); - float heightFog_792 = (1.0f - saturate_791); - vec4 t793 = fogDataSecond.heightFogCoeff; - float xSqrd_794 = (heightFog_792 * heightFog_792); - float xCubed_795 = (xSqrd_794 * heightFog_792); - float saturate_806 = saturatef(((((t793.x * xCubed_795) + (t793.y * xSqrd_794)) + (t793.z * heightFog_792)) + t793.w)); - float heightFog_807 = (1.0f - saturate_806); - float normalizedDistance_808 = (vLength_778 / end); - float exp_810 = exp((expMax_781 * density)); - float legacyFogResult_811 = (1.0 / exp_810); - float lerp_812 = mix(legacyFogResult_811, legacyExpFogHeight_784, heightFog_807); - float finalLegacyFog_815 = (1.0f - ((1.0f - lerp_812) * fogRateScalar)); - float endFadeFog_818 = saturatef((1.42857146f * (1.0f - normalizedDistance_808))); - float finalLegacyFog_819 = min(finalLegacyFog_815, endFadeFog_818); - float artFogNormalizedDistance_823 = saturatef(((vLength_778 - mainFogCurveStartDist) / (mainFogCurveEndDist - mainFogCurveStartDist))); - float engineFogNormalizedDistance_825 = saturatef((vLength_778 / mainFogCurveEndDist)); - vec4 t826 = fogDataSecond.mainFogCoeff; - float xSqrd_827 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); - float xCubed_828 = (xSqrd_827 * artFogNormalizedDistance_823); - float saturate_839 = saturatef(((((t826.x * xCubed_828) + (t826.y * xSqrd_827)) + (t826.z * artFogNormalizedDistance_823)) + t826.w)); - float fogResult_841 = saturatef((1.0f - saturate_839)); - vec4 t842 = fogDataSecond.heightDensityFogCoeff; - float xSqrd_843 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); - float xCubed_844 = (xSqrd_843 * artFogNormalizedDistance_823); - float saturate_855 = saturatef(((((t842.x * xCubed_844) + (t842.y * xSqrd_843)) + (t842.z * artFogNormalizedDistance_823)) + t842.w)); - float heightFogResult_857 = saturatef((1.0f - saturate_855)); - float lerp_858 = mix(fogResult_841, heightFogResult_857, heightFog_807); - float finalFog_861 = (1.0f - ((1.0f - lerp_858) * fogRateScalar)); - float endPct_863 = saturatef((end / mainFogCurveEndDist)); - float finalFogBeginPct_864 = (endPct_863 - 0.300000012f); - float xSqrd_865 = (finalFogBeginPct_864 * finalFogBeginPct_864); - float xCubed_866 = (xSqrd_865 * finalFogBeginPct_864); - float saturate_877 = saturatef(((((t826.x * xCubed_866) + (t826.y * xSqrd_865)) + (t826.z * finalFogBeginPct_864)) + t826.w)); - float mainFogValueAtBlendStart_878 = saturatef(saturate_877); - float xSqrd_879 = (finalFogBeginPct_864 * finalFogBeginPct_864); - float xCubed_880 = (xSqrd_879 * finalFogBeginPct_864); - float saturate_891 = saturatef(((((t842.x * xCubed_880) + (t842.y * xSqrd_879)) + (t842.z * finalFogBeginPct_864)) + t842.w)); - float heightFogValueAtBlendStart_892 = saturatef(saturate_891); - float fogValueAtBlendStart_893 = mix(mainFogValueAtBlendStart_878, heightFogValueAtBlendStart_892, heightFog_807); - float blendValue_896 = saturatef(((engineFogNormalizedDistance_825 - finalFogBeginPct_864) / 0.300000012f)); - float endFogValue_898 = (blendValue_896 * (1.0f - fogValueAtBlendStart_893)); - float endFogValue_899 = (endFogValue_898 + fogValueAtBlendStart_893); - float endFogValue_901 = saturatef((1.0f - endFogValue_899)); - float lerp_902 = mix(finalFog_861, endFogValue_901, blendValue_896); - float finalFog_903 = min(finalFog_861, lerp_902); - float _retVal_904 = mix(finalFog_903, finalLegacyFog_819, legacyFogBlend); - _retVal_913 = _retVal_904; - heightFog_912 = heightFog_807; - } - else - { - // Block 908 - _retVal_913 = _retVal_742; - heightFog_912 = 0.0f; - } - // Block 911 - float _retVal_956 = _retVal_913; - float heightFog_955 = heightFog_912; - vec3 normalize_918 = normalize(vertexInViewSpace); - float t924 = fogDataSecond.sunAngle_and_sunColor.x; - float alpha_935 = final.w; - float end2_938 = saturatef(((vLength - fogDataSecond.heightFogEndColor_fogStartOffset.w) / fogDataSecond.heightColor_and_endFogDistance.w)); - float end_940 = (end2_938 * (end2_938 * end2_938)); - vec3 heightColor_942 = mix(mainFogData.heightColor_and_endFogDistance.xyz, mainFogData.heightFogEndColor_fogStartOffset.xyz, vec3(end2_938)); - float saturate_943 = saturatef(end_940); - vec3 fogFinal_945 = mix(mainFogData.color_and_heightRate.xyz, mainFogData.heightDensity_and_endColor.yzw, vec3(saturate_943)); - vec3 fogFinal_947 = mix(fogFinal_945, heightColor_942, vec3(heightFog_955)); - float dot_948 = dot(normalize_918, fogDataSecond.sunDirection_and_fogZScalar.xyz); - float nDotSun_949 = saturatef(dot_948); - vec3 sunColor_951 = mix(fogFinal_947, mainFogData.sunAngle_and_sunColor.yzw, vec3(fogDataSecond.sunPercentage.x)); - float nDotSun_953 = saturatef((nDotSun_949 - t924)); - vec3 fogFinal_969; - if (nDotSun_953 > 0.0f) - { - // Block 957 - float nDotSun_960 = ((1.0f / (1.0f - t924)) * nDotSun_953); - float nDotSun_962 = ((nDotSun_960 * nDotSun_960) * nDotSun_960); - vec3 fogFinal_964 = mix(fogFinal_947, sunColor_951, vec3(nDotSun_962)); - fogFinal_969 = fogFinal_964; - } - else - { - // Block 966 - fogFinal_969 = fogFinal_947; - } - // Block 968 - vec3 fogFinal_971 = fogFinal_969; - float alpha_978; - if (bool(t138)) - { - // Block 972 - float alpha_973 = (alpha_935 * _retVal_956); - alpha_978 = alpha_973; - } - else - { - // Block 975 - alpha_978 = alpha_935; - } - // Block 977 - float alpha_988 = alpha_978; - vec3 lerp_981 = mix(fogFinal_971, final.xyz, vec3(_retVal_956)); - vec4 t982 = vec4(lerp_981, alpha_988); - vec4 outColor_713 = vec4(0.0); //accumulator - vec4 outColor_986 = (outColor_713 + (t982 * fogDataSecond.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); + // Block 737 + float _retVal_742 = _retVal_739; + bool _ret0_741 = _ret0_738; + if (!(_ret0_741)) + { + // Block 743 + vec4 densityParams = mainFogData[i].densityParams; + float start = densityParams.x; + float end = densityParams.y; + float density = densityParams.z; + float bias = densityParams.w; + float heightRate = mainFogData[i].color_and_heightRate.w; + float heightDensity = mainFogData[i].heightDensity_and_endColor.x; + float fogZScalar = mainFogData[i].sunDirection_and_fogZScalar.w; + vec4 t755 = mainFogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; + float mainFogCurveEndDist = t755.x; + float mainFogCurveStartDist = t755.y; + float legacyFogBlend = t755.z; + vec3 viewSpaceUp = uViewUp; + float dotVal_763 = dot(viewSpaceUp, vertexInViewSpace); + vec3 adjustedVpos_777; + if (dotVal_763 > 0.0f) + { + // Block 765 + float clamp_766 = clamp(fogZScalar, 0.0f, dotVal_763); + vec3 adjustedVpos_768 = (vertexInViewSpace - (viewSpaceUp * clamp_766)); + adjustedVpos_777 = adjustedVpos_768; + } + else + { + // Block 770 + float clamp_772 = clamp(-(fogZScalar), dotVal_763, 0.0f); + vec3 adjustedVpos_774 = (vertexInViewSpace - (viewSpaceUp * clamp_772)); + adjustedVpos_777 = adjustedVpos_774; + } + // Block 776 + vec3 adjustedVpos_905 = adjustedVpos_777; + float vLength_778 = length(adjustedVpos_905); + float z_779 = (vLength_778 - bias); + float expMax_781 = max(0.0f, (z_779 - start)); + float exp_783 = exp((expMax_781 * heightDensity)); + float legacyExpFogHeight_784 = (1.0 / exp_783); + vec4 t785 = mainFogData[i].heightPlane; + float dot_787 = dot(t785.xyz, vertexInViewSpace); + float height_789 = (dot_787 + t785.w); + float saturate_791 = saturatef((height_789 * heightRate)); + float heightFog_792 = (1.0f - saturate_791); + vec4 t793 = mainFogData[i].heightFogCoeff; + float xSqrd_794 = (heightFog_792 * heightFog_792); + float xCubed_795 = (xSqrd_794 * heightFog_792); + float saturate_806 = saturatef(((((t793.x * xCubed_795) + (t793.y * xSqrd_794)) + (t793.z * heightFog_792)) + t793.w)); + float heightFog_807 = (1.0f - saturate_806); + float normalizedDistance_808 = (vLength_778 / end); + float exp_810 = exp((expMax_781 * density)); + float legacyFogResult_811 = (1.0 / exp_810); + float lerp_812 = mix(legacyFogResult_811, legacyExpFogHeight_784, heightFog_807); + float finalLegacyFog_815 = (1.0f - ((1.0f - lerp_812) * fogRateScalar)); + float endFadeFog_818 = saturatef((1.42857146f * (1.0f - normalizedDistance_808))); + float finalLegacyFog_819 = min(finalLegacyFog_815, endFadeFog_818); + float artFogNormalizedDistance_823 = saturatef(((vLength_778 - mainFogCurveStartDist) / (mainFogCurveEndDist - mainFogCurveStartDist))); + float engineFogNormalizedDistance_825 = saturatef((vLength_778 / mainFogCurveEndDist)); + vec4 t826 = mainFogData[i].mainFogCoeff; + float xSqrd_827 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); + float xCubed_828 = (xSqrd_827 * artFogNormalizedDistance_823); + float saturate_839 = saturatef(((((t826.x * xCubed_828) + (t826.y * xSqrd_827)) + (t826.z * artFogNormalizedDistance_823)) + t826.w)); + float fogResult_841 = saturatef((1.0f - saturate_839)); + vec4 t842 = mainFogData[i].heightDensityFogCoeff; + float xSqrd_843 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); + float xCubed_844 = (xSqrd_843 * artFogNormalizedDistance_823); + float saturate_855 = saturatef(((((t842.x * xCubed_844) + (t842.y * xSqrd_843)) + (t842.z * artFogNormalizedDistance_823)) + t842.w)); + float heightFogResult_857 = saturatef((1.0f - saturate_855)); + float lerp_858 = mix(fogResult_841, heightFogResult_857, heightFog_807); + float finalFog_861 = (1.0f - ((1.0f - lerp_858) * fogRateScalar)); + float endPct_863 = saturatef((end / mainFogCurveEndDist)); + float finalFogBeginPct_864 = (endPct_863 - 0.300000012f); + float xSqrd_865 = (finalFogBeginPct_864 * finalFogBeginPct_864); + float xCubed_866 = (xSqrd_865 * finalFogBeginPct_864); + float saturate_877 = saturatef(((((t826.x * xCubed_866) + (t826.y * xSqrd_865)) + (t826.z * finalFogBeginPct_864)) + t826.w)); + float mainFogValueAtBlendStart_878 = saturatef(saturate_877); + float xSqrd_879 = (finalFogBeginPct_864 * finalFogBeginPct_864); + float xCubed_880 = (xSqrd_879 * finalFogBeginPct_864); + float saturate_891 = saturatef(((((t842.x * xCubed_880) + (t842.y * xSqrd_879)) + (t842.z * finalFogBeginPct_864)) + t842.w)); + float heightFogValueAtBlendStart_892 = saturatef(saturate_891); + float fogValueAtBlendStart_893 = mix(mainFogValueAtBlendStart_878, heightFogValueAtBlendStart_892, heightFog_807); + float blendValue_896 = saturatef(((engineFogNormalizedDistance_825 - finalFogBeginPct_864) / 0.300000012f)); + float endFogValue_898 = (blendValue_896 * (1.0f - fogValueAtBlendStart_893)); + float endFogValue_899 = (endFogValue_898 + fogValueAtBlendStart_893); + float endFogValue_901 = saturatef((1.0f - endFogValue_899)); + float lerp_902 = mix(finalFog_861, endFogValue_901, blendValue_896); + float finalFog_903 = min(finalFog_861, lerp_902); + float _retVal_904 = mix(finalFog_903, finalLegacyFog_819, legacyFogBlend); + _retVal_913 = _retVal_904; + heightFog_912 = heightFog_807; + } + else + { + // Block 908 + _retVal_913 = _retVal_742; + heightFog_912 = 0.0f; + } + // Block 911 + float _retVal_956 = _retVal_913; + float heightFog_955 = heightFog_912; + vec3 normalize_918 = normalize(vertexInViewSpace); + float t924 = mainFogData[i].sunAngle_and_sunColor.x; + float alpha_935 = final.w; + float end2_938 = saturatef(((vLength - mainFogData[i].heightFogEndColor_fogStartOffset.w) / mainFogData[i].heightColor_and_endFogDistance.w)); + float end_940 = (end2_938 * (end2_938 * end2_938)); + vec3 heightColor_942 = mix(validateFogColor(mainFogData[0].heightColor_and_endFogDistance.xyz, blendMode), + validateFogColor(mainFogData[0].heightFogEndColor_fogStartOffset.xyz, blendMode), vec3(end2_938)); + float saturate_943 = saturatef(end_940); + vec3 fogFinal_945 = mix(validateFogColor(mainFogData[0].color_and_heightRate.xyz, blendMode), + validateFogColor(mainFogData[0].heightDensity_and_endColor.yzw, blendMode), vec3(saturate_943)); + vec3 fogFinal_947 = mix(fogFinal_945, heightColor_942, vec3(heightFog_955)); + float dot_948 = dot(normalize_918, mainFogData[i].sunDirection_and_fogZScalar.xyz); + float nDotSun_949 = saturatef(dot_948); + vec3 sunColor_951 = mix(fogFinal_947, validateFogColor(mainFogData[0].sunAngle_and_sunColor.yzw, blendMode), vec3(mainFogData[i].sunPercentage.x)); + float nDotSun_953 = saturatef((nDotSun_949 - t924)); + vec3 fogFinal_969; + if (nDotSun_953 > 0.0f) + { + // Block 957 + float nDotSun_960 = ((1.0f / (1.0f - t924)) * nDotSun_953); + float nDotSun_962 = ((nDotSun_960 * nDotSun_960) * nDotSun_960); + vec3 fogFinal_964 = mix(fogFinal_947, sunColor_951, vec3(nDotSun_962)); + fogFinal_969 = fogFinal_964; + } + else + { + // Block 966 + fogFinal_969 = fogFinal_947; + } + // Block 968 + vec3 fogFinal_971 = fogFinal_969; + float alpha_978; + if (bool(t138)) + { + // Block 972 + float alpha_973 = (alpha_935 * _retVal_956); + alpha_978 = alpha_973; + } + else + { + // Block 975 + alpha_978 = alpha_935; + } + // Block 977 + float alpha_988 = alpha_978; + vec3 lerp_981 = mix(fogFinal_971, final.xyz, vec3(_retVal_956)); + vec4 t982 = vec4(lerp_981, alpha_988); - return outColor_986; + vec4 outColor_986 = (outColor_713 + (t982 * mainFogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); + outColor_713 = outColor_986; + } + return outColor_713; } diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 55431840f..d0e4c91f5 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -13,7 +13,7 @@ struct SceneExteriorLight { vec4 uExteriorGroundAmbientColor; vec4 uExteriorDirectColor; vec4 uExteriorDirectColorDir; - vec4 adtSpecMult; + vec4 adtSpecMult_fogCount; }; struct SceneWideParams { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 5aefc42b0..8f45c42af 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -26,7 +26,7 @@ layout(set=2, binding=13) uniform sampler2D uLayerHeight3; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { @@ -159,10 +159,10 @@ void main() { float specBlend = final.a; vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); - vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult.x; + vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; finalColor.rgb += specTerm; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); finalColor.a = 1.0; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index e91d3a528..ec8901094 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -16,7 +16,7 @@ layout(location = 3) in vec3 aNormal; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert index 0e8498491..7cdeee1d5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert @@ -13,7 +13,7 @@ layout(location = 0) in vec3 aPosition; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; // Whole model diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert index 59c022b47..0ea8bef19 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert @@ -14,7 +14,7 @@ layout(location = 0) in vec3 aPosition; //Whole scene layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; void main() { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index 6deaaba4d..4b3998a8f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -17,7 +17,7 @@ layout(location = 5) in float alphaCutoff; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Individual meshes @@ -104,7 +104,7 @@ void main() { // .xyz; vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); outputColor.rgba = finalColor ; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert index b4071ee4b..89d9e9192 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert @@ -26,7 +26,7 @@ layout(location = 5) out float vAlphaCutoff; layout(std140, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; void main() { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 3c8282555..6fcd351ea 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -19,7 +19,7 @@ layout(location=0) out vec4 outputColor; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Whole model @@ -173,7 +173,7 @@ void main() { ) .xyz; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 473a714bb..16d25d038 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -22,7 +22,7 @@ layout(location=5) in vec2 aTexCoord2; //Whole scene layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Whole model diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index e50d01405..47489acec 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -15,7 +15,7 @@ layout(location = 2) in vec2 vTexcoord0; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=3) uniform textureMatrices { @@ -46,7 +46,7 @@ void main() { vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); outputColor = finalColor; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert index 532197da7..9ed58bcca 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert @@ -15,7 +15,7 @@ layout(location = 2) in vec2 aTexcoord0; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(location = 0) out vec3 vPosition; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag index 108b13df5..2f8197d5e 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag @@ -10,7 +10,7 @@ precision highp int; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(location = 0) in vec4 vColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert index 0a9c0d949..1dd573d93 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert @@ -12,7 +12,7 @@ precision highp float; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=1) uniform meshWideBlockVS { vec4 skyColor[6]; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 275225793..873edd213 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -18,7 +18,7 @@ layout(set=2,binding=5) uniform sampler2D uTexture; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Individual meshes @@ -75,7 +75,7 @@ void main() { } //BlendMode is always GxBlend_Alpha - finalColor.rgb = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; + finalColor.rgb = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; outputColor = vec4(finalColor.rgb, 0.7); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index 63aa65aa3..f9df7ca2e 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -14,7 +14,7 @@ layout(location=1) in vec2 aTexCoord; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=1) uniform modelWideBlockVS { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index eaa010acb..3a3c7d065 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -24,7 +24,7 @@ layout(location=0) out vec4 outputColor; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Whole model @@ -115,7 +115,7 @@ void main() { ); vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); + finalColor = makeFog2(fogData,int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); outputColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index 4b6edc366..fb5ee0406 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -23,7 +23,7 @@ layout(location=5) in vec2 aTexCoord2; //Whole scene layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; // Whole model diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index fb2f604d3..6f150cca1 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -26,7 +26,7 @@ layout(location=9) in vec4 vWmoAmbient; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=4) uniform meshWideBlockPS { @@ -89,7 +89,7 @@ void main() { finalOpacity ); - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); finalColor.a = 1.0; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index 89f25c022..f4e0c9ebe 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -24,7 +24,7 @@ layout (location = 9) in vec4 wmoAmbient; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; layout(std140, set=1, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index bfa6ab5cf..a4fd6c428 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -21,7 +21,7 @@ layout(location=0) out vec4 outputColor; layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Whole model @@ -191,7 +191,7 @@ void main() { ) .xyz; - finalColor = makeFog2(fogData, fogData, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert index 4e628aee2..e590da293 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -22,7 +22,7 @@ layout(location=5) in vec2 aTexCoord2; //Whole scene layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; - PSFog fogData; + PSFog fogData[8]; }; //Whole model diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 9d9e26d54..372773669 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -106,8 +106,8 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { /* Calc look at position */ - dir = mathfu::mat3::RotationY((float) (this->av * M_PI / 180.0f)) * dir; - dir = mathfu::mat3::RotationZ((float) (-this->ah * M_PI / 180.0f)) * dir; + dir = mathfu::mat3::RotationY((float) (-this->av * M_PI / 180.0f)) * dir; + dir = mathfu::mat3::RotationZ((float) (this->ah * M_PI / 180.0f)) * dir; dir = mathfu::normalize(dir); @@ -129,7 +129,7 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { mathfu::vec3 movDir = mathfu::vec3(dir); movDir = movDir * depthDiff; - camera = camera + movDir; + camera = camera - movDir; } if (verticalDiff != 0) { camera[2] = camera[2] + verticalDiff; @@ -138,9 +138,9 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { this->lookAt = camera + dir; lookAtMat = mathfu::mat4( - right_move.x, up.x, -dir.x, 0.0f, - right_move.y, up.y, -dir.y, 0.0f, - right_move.z, up.z, -dir.z, 0.0f, + right_move.x, up.x, dir.x, 0.0f, + right_move.y, up.y, dir.y, 0.0f, + right_move.z, up.z, dir.z, 0.0f, 0,0,0,1.0f //translation ); lookAtMat *= mathfu::mat4::FromTranslationVector(-camera) ; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index a252fb648..e87ee10bd 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -345,7 +345,6 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.triCCW = true; pipelineTemplate.depthWrite = true; pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = true; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 17510ee7e..163c18aad 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1401,7 +1401,6 @@ HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRendere pipelineTemplate.depthWrite = false; pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; - pipelineTemplate.triCCW = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16)) * 2; @@ -1609,7 +1608,6 @@ std::shared_ptr M2Object::createM2Material(const HMapSceneBufferCre pipelineTemplate.depthWrite = !(renderFlag->flags & 0x10); pipelineTemplate.depthCulling = !(renderFlag->flags & 0x8); pipelineTemplate.backFaceCulling = !(renderFlag->flags & 0x4); - pipelineTemplate.triCCW = true; if (overrideBlend) { pipelineTemplate.blendMode = blendMode; if (blendMode > EGxBlendEnum::GxBlend_AlphaKey) diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 11bf831b8..050b1205c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -869,32 +869,32 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } } - for (auto &_light : combinedResults) { - FogEnd += _light.FogEnd * _light.blendCoef; - FogScaler += _light.FogScaler * _light.blendCoef; - FogDensity += _light.FogDensity * _light.blendCoef; - FogHeight += _light.FogHeight * _light.blendCoef; - FogHeightScaler += _light.FogHeightScaler * _light.blendCoef; - FogHeightDensity += _light.FogHeightDensity * _light.blendCoef; - SunFogAngle += _light.SunFogAngle * _light.blendCoef; - - EndFogColor += mathfu::vec3(_light.EndFogColor.data()) * _light.blendCoef; - EndFogColorDistance += _light.EndFogColorDistance * _light.blendCoef; - SunFogColor += mathfu::vec3(_light.SunFogColor.data()) * _light.blendCoef; - SunFogStrength += _light.SunFogStrength * _light.blendCoef; - FogHeightColor += mathfu::vec3(_light.FogHeightColor.data()) * _light.blendCoef; - FogHeightCoefficients += mathfu::vec4(_light.FogHeightCoefficients.data()) * _light.blendCoef; - MainFogCoefficients += mathfu::vec4(_light.MainFogCoefficients.data()) * _light.blendCoef; - HeightDensityFogCoefficients += mathfu::vec4(_light.HeightDensityFogCoefficients.data()) * _light.blendCoef; - FogZScalar += _light.FogZScalar * _light.blendCoef; - LegacyFogScalar += _light.LegacyFogScalar * _light.blendCoef; - MainFogStartDist += _light.MainFogStartDist * _light.blendCoef; - MainFogEndDist += _light.MainFogEndDist * _light.blendCoef; - FogBlendAlpha += _light.FogBlendAlpha * _light.blendCoef; - HeightEndFogColor += mathfu::vec3(_light.HeightEndFogColor.data()) * _light.blendCoef; - FogStartOffset += _light.FogStartOffset * _light.blendCoef; - } - FogBlendAlpha = 1.0f; +// for (auto &_light : combinedResults) { +// FogEnd += _light.FogEnd * _light.blendCoef; +// FogScaler += _light.FogScaler * _light.blendCoef; +// FogDensity += _light.FogDensity * _light.blendCoef; +// FogHeight += _light.FogHeight * _light.blendCoef; +// FogHeightScaler += _light.FogHeightScaler * _light.blendCoef; +// FogHeightDensity += _light.FogHeightDensity * _light.blendCoef; +// SunFogAngle += _light.SunFogAngle * _light.blendCoef; +// +// EndFogColor += mathfu::vec3(_light.EndFogColor.data()) * _light.blendCoef; +// EndFogColorDistance += _light.EndFogColorDistance * _light.blendCoef; +// SunFogColor += mathfu::vec3(_light.SunFogColor.data()) * _light.blendCoef; +// SunFogStrength += _light.SunFogStrength * _light.blendCoef; +// FogHeightColor += mathfu::vec3(_light.FogHeightColor.data()) * _light.blendCoef; +// FogHeightCoefficients += mathfu::vec4(_light.FogHeightCoefficients.data()) * _light.blendCoef; +// MainFogCoefficients += mathfu::vec4(_light.MainFogCoefficients.data()) * _light.blendCoef; +// HeightDensityFogCoefficients += mathfu::vec4(_light.HeightDensityFogCoefficients.data()) * _light.blendCoef; +// FogZScalar += _light.FogZScalar * _light.blendCoef; +// LegacyFogScalar += _light.LegacyFogScalar * _light.blendCoef; +// MainFogStartDist += _light.MainFogStartDist * _light.blendCoef; +// MainFogEndDist += _light.MainFogEndDist * _light.blendCoef; +// FogBlendAlpha += _light.FogBlendAlpha * _light.blendCoef; +// HeightEndFogColor += mathfu::vec3(_light.HeightEndFogColor.data()) * _light.blendCoef; +// FogStartOffset += _light.FogStartOffset * _light.blendCoef; +// } +// FogBlendAlpha = 1.0f; //In case of no data -> disable the fog { @@ -902,37 +902,44 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp fdd->FogDataFound = !combinedResults.empty(); // std::cout << "combinedResults.empty() = " << combinedResults.empty() << std::endl; // std::cout << "combinedResults.size() = " << combinedResults.size() << std::endl; - fdd->FogEnd = FogEnd; - fdd->FogScaler = FogScaler; - fdd->FogDensity = FogDensity; - fdd->FogHeight = FogHeight; - fdd->FogHeightScaler = FogHeightScaler; - fdd->FogHeightDensity = FogHeightDensity; - fdd->SunFogAngle = SunFogAngle; - if (fdd->overrideValuesWithFinalFog) { - fdd->FogColor = mathfu::vec3(EndFogColor[2], EndFogColor[1], EndFogColor[0]); - } else { - fdd->FogColor = fdd->SkyFogColor.xyz(); + fdd->EndFogColor = mathfu::vec3(0.0f, 0, 0); + for (auto &_light : lightResults) { + auto &fogResult = fdd->fogResults.emplace_back(); + fogResult.FogEnd = _light.FogEnd; + fogResult.FogScaler = _light.FogScaler; + fogResult.FogDensity = _light.FogDensity; + fogResult.FogHeight = _light.FogHeight; + fogResult.FogHeightScaler = _light.FogHeightScaler; + fogResult.FogHeightDensity = _light.FogHeightDensity; + fogResult.SunFogAngle = _light.SunFogAngle; + if (fdd->overrideValuesWithFinalFog) { + fogResult.FogColor = mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]); + } else { + fogResult.FogColor = mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]); + } + fogResult.EndFogColor = mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]); + fdd->EndFogColor += fogResult.EndFogColor * _light.blendCoef; + fogResult.EndFogColorDistance = _light.EndFogColorDistance; + fogResult.SunFogColor = mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]); + fogResult.SunFogStrength = _light.SunFogStrength; + fogResult.FogHeightColor = mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]); + fogResult.FogHeightCoefficients = mathfu::vec4(_light.FogHeightCoefficients[0], _light.FogHeightCoefficients[1], + _light.FogHeightCoefficients[2], _light.FogHeightCoefficients[3]); + fogResult.MainFogCoefficients = mathfu::vec4(_light.MainFogCoefficients[0], _light.MainFogCoefficients[1], + _light.MainFogCoefficients[2], _light.MainFogCoefficients[3]); + fogResult.HeightDensityFogCoefficients = mathfu::vec4(_light.HeightDensityFogCoefficients[0], + _light.HeightDensityFogCoefficients[1], + _light.HeightDensityFogCoefficients[2], + _light.HeightDensityFogCoefficients[3]); + + fogResult.FogZScalar = _light.FogZScalar; + fogResult.LegacyFogScalar = _light.LegacyFogScalar; + fogResult.MainFogStartDist = _light.MainFogStartDist; + fogResult.MainFogEndDist = _light.MainFogEndDist; + fogResult.FogBlendAlpha = _light.blendCoef; + fogResult.HeightEndFogColor = mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]); + fogResult.FogStartOffset = _light.FogStartOffset; } - fdd->EndFogColor = mathfu::vec3(EndFogColor[2], EndFogColor[1], EndFogColor[0]); - fdd->EndFogColorDistance = EndFogColorDistance; - fdd->SunFogColor = mathfu::vec3(SunFogColor[2], SunFogColor[1], SunFogColor[0]); - fdd->SunFogStrength = SunFogStrength; - fdd->FogHeightColor = mathfu::vec3(FogHeightColor[2], FogHeightColor[1], FogHeightColor[0]); - fdd->FogHeightCoefficients = mathfu::vec4(FogHeightCoefficients[0], FogHeightCoefficients[1], - FogHeightCoefficients[2], FogHeightCoefficients[3]); - fdd->MainFogCoefficients = mathfu::vec4(MainFogCoefficients[0], MainFogCoefficients[1], - MainFogCoefficients[2], MainFogCoefficients[3]); - fdd->HeightDensityFogCoefficients = mathfu::vec4(HeightDensityFogCoefficients[0], HeightDensityFogCoefficients[1], - HeightDensityFogCoefficients[2], HeightDensityFogCoefficients[3]); - - fdd->FogZScalar = FogZScalar; - fdd->LegacyFogScalar = LegacyFogScalar; - fdd->MainFogStartDist = MainFogStartDist; - fdd->MainFogEndDist = MainFogEndDist; - fdd->FogBlendAlpha = FogBlendAlpha; - fdd->HeightEndFogColor = mathfu::vec3(HeightEndFogColor[2], HeightEndFogColor[1], HeightEndFogColor[0]); - fdd->FogStartOffset = FogStartOffset; } } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b864af07d..714fdeb14 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -304,7 +304,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,480}, + {0,0,2048}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -346,7 +346,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,1,64}, - {0,0,480}, + {0,0,2048}, {1,2,16}, }, { @@ -386,7 +386,7 @@ const std::unordered_map shaderMetaInfo = { {2,4,16}, {1,6,4096}, {1,3,16384}, - {0,0,480}, + {0,0,2048}, {1,1,64}, {1,2,256}, {1,4,4096}, @@ -427,7 +427,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, {1,1,64}, }, { @@ -464,7 +464,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, {1,1,96}, }, { @@ -537,7 +537,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, }, { { @@ -684,7 +684,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {2,5,96}, - {0,0,480}, + {0,0,2048}, {1,1,64}, {1,2,256}, {1,3,16384}, @@ -767,7 +767,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,1,112}, - {0,0,480}, + {0,0,2048}, }, { { @@ -948,7 +948,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,2,48}, - {0,0,480}, + {0,0,2048}, {1,1,64}, }, { @@ -994,7 +994,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,2048}, }, { { @@ -1075,7 +1075,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, {1,1,64}, }, { @@ -1151,7 +1151,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,480}, + {0,0,2048}, }, { { @@ -1308,7 +1308,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,96}, - {0,0,480}, + {0,0,2048}, }, { { @@ -1349,7 +1349,7 @@ const std::unordered_map shaderMetaInfo = { {1,5,256}, {1,4,4096}, {1,2,256}, - {0,0,480}, + {0,0,2048}, {1,1,64}, {1,6,4096}, {1,3,16384}, @@ -1466,7 +1466,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,480}, + {0,0,2048}, }, { { @@ -1505,7 +1505,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, }, { { @@ -1541,7 +1541,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,2048}, }, { { @@ -1651,7 +1651,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,480}, + {0,0,2048}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -1694,7 +1694,7 @@ const std::unordered_map shaderMetaInfo = { { {1,4,16}, {1,3,4096}, - {0,0,480}, + {0,0,2048}, }, { { @@ -1731,7 +1731,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,2048}, }, { { @@ -1808,21 +1808,119 @@ const std::unordered_map fogResults; + mathfu::vec3 EndFogColor = mathfu::vec3(0, 0, 0); //Water params bool useMinimapWaterColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index f9bf69cd4..8f00a9b7a 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -33,6 +33,7 @@ struct MapRenderPlan { HFrameDependantData frameDependentData = std::make_shared(); + //Objects for update and rendering std::vector> adtArray = {}; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 8702596da..29839d96e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -121,17 +121,6 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrlookAtMat * mathfu::vec4((zUp * fdd->FogHeight).xyz(), 1.0f)).xyz(); - mathfu::vec4 heightPlaneVec = - renderingMatrices->invTranspViewMat * mathfu::vec4((zUp * fdd->FogHeight).xyz(), 0.0); - mathfu::vec3 heightPlaneVecNorm = heightPlaneVec.xyz().LengthSquared() > 0 ? - heightPlaneVec.Normalized().xyz() : - mathfu::vec3(0,0,0); - mathfu::vec4 heightPlane = mathfu::vec4( - heightPlaneVecNorm, - -(mathfu::vec3::DotProduct(heightPlaneVecNorm, zUpPointInView)) - ); auto &blockPSVS = sceneWideChunk->getObject(0); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; @@ -148,67 +137,78 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorGroundAmbientColor; blockPSVS.extLight.uExteriorDirectColor = fdd->exteriorDirectColor; blockPSVS.extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); - blockPSVS.extLight.uAdtSpecMult = mathfu::vec4(m_config->adtSpecMult, 0, 0, 1.0); + blockPSVS.extLight.uAdtSpecMult_FogCount = mathfu::vec4(m_config->adtSpecMult, fdd->fogResults.size(), 0, 1.0); - float fogEnd = std::min(std::max(m_config->farPlane, 277.5), m_config->farPlane); - if (m_config->disableFog || !fdd->FogDataFound) { - fogEnd = 100000000.0f; - fdd->FogScaler = 0; - fdd->FogDensity = 0; - } + for (int i = 0; i < std::min(fdd->fogResults.size(), FOG_MAX_SHADER_COUNT); i++) + { + auto &fogResult = fdd->fogResults[i]; + + mathfu::vec4 heightPlane = mathfu::vec4( + zUp.xyz(), + -(mathfu::vec3::DotProduct(zUp.xyz(), (zUp * fogResult.FogHeight).xyz())) + ); + heightPlane = renderingMatrices->invTranspViewMat * heightPlane; + + float fogEnd = std::min(std::max(m_config->farPlane, 277.5), m_config->farPlane); + if (m_config->disableFog || !fdd->FogDataFound) { + fogEnd = 100000000.0f; + fogResult.FogScaler = 0; + fogResult.FogDensity = 0; + } - const float densityMultFix = 1.0/1000; ; - float fogScaler = fdd->FogScaler; - if (fogScaler <= 0.00000001f) fogScaler = 0.5f; - float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; - - blockPSVS.fogData.densityParams = mathfu::vec4( - fogStart, - fogEnd, - fdd->FogDensity * densityMultFix, - 0); - blockPSVS.fogData.classicFogParams = mathfu::vec4(0, 0, 0, 0); - blockPSVS.fogData.heightPlane = heightPlane; - blockPSVS.fogData.color_and_heightRate = mathfu::vec4(fdd->FogColor, fdd->FogHeightScaler); - blockPSVS.fogData.heightDensity_and_endColor = mathfu::vec4( - fdd->FogHeightDensity * densityMultFix, - fdd->EndFogColor.x, - fdd->EndFogColor.y, - fdd->EndFogColor.z - ); - blockPSVS.fogData.sunAngle_and_sunColor = mathfu::vec4( - fdd->SunFogAngle, - fdd->SunFogColor.x, - fdd->SunFogColor.y, - fdd->SunFogColor.z - ); - blockPSVS.fogData.heightColor_and_endFogDistance = mathfu::vec4( - fdd->FogHeightColor, - (fdd->EndFogColorDistance > 0) ? - fdd->EndFogColorDistance : - 1000.0f - ); - blockPSVS.fogData.sunPercentage = mathfu::vec4( - 0.0f, //fdd->SunFogAngle * fdd->SunFogStrength, - 0, 1.0, 1.0); - blockPSVS.fogData.sunDirection_and_fogZScalar = mathfu::vec4( - fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position - fdd->FogZScalar - ); - blockPSVS.fogData.heightFogCoeff = fdd->FogHeightCoefficients; - blockPSVS.fogData.mainFogCoeff = fdd->MainFogCoefficients; - blockPSVS.fogData.heightDensityFogCoeff = fdd->HeightDensityFogCoefficients; - - bool mainFogOk = (fdd->MainFogStartDist + 0.001 <= fdd->MainFogEndDist); - blockPSVS.fogData.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( - mainFogOk ? fdd->MainFogEndDist : fdd->MainFogStartDist + 0.001, - fdd->MainFogStartDist >= 0.0 ? fdd->MainFogStartDist : 0.0f, - fdd->LegacyFogScalar, - fdd->FogBlendAlpha - ); - blockPSVS.fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( - fdd->HeightEndFogColor, - fdd->FogStartOffset - ); + const float densityMultFix = 0.00050000002; + float fogScaler = fogResult.FogScaler; + if (fogScaler <= 0.00000001f) fogScaler = 0.5f; + float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; + + blockPSVS.fogData[i].densityParams = mathfu::vec4( + fogStart, + fogEnd, + fogResult.FogDensity * densityMultFix, + 0); + blockPSVS.fogData[i].classicFogParams = mathfu::vec4(0, 0, 0, 0); + blockPSVS.fogData[i].heightPlane = heightPlane; + blockPSVS.fogData[i].color_and_heightRate = mathfu::vec4(fogResult.FogColor, fogResult.FogHeightScaler); + blockPSVS.fogData[i].heightDensity_and_endColor = mathfu::vec4( + fogResult.FogHeightDensity * densityMultFix, + fogResult.EndFogColor.x, + fogResult.EndFogColor.y, + fogResult.EndFogColor.z + ); + blockPSVS.fogData[i].sunAngle_and_sunColor = mathfu::vec4( + fogResult.SunFogAngle, + fogResult.SunFogColor.x, + fogResult.SunFogColor.y, + fogResult.SunFogColor.z + ); + blockPSVS.fogData[i].heightColor_and_endFogDistance = mathfu::vec4( + fogResult.FogHeightColor, + (fogResult.EndFogColorDistance > 0) ? + fogResult.EndFogColorDistance : + 1000.0f + ); + blockPSVS.fogData[i].sunPercentage = mathfu::vec4( + 0.0f, //fdd->SunFogAngle * fdd->SunFogStrength, + 0, 1.0, 1.0); + blockPSVS.fogData[i].sunDirection_and_fogZScalar = mathfu::vec4( + fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position + fogResult.FogZScalar + ); + blockPSVS.fogData[i].heightFogCoeff = fogResult.FogHeightCoefficients; + blockPSVS.fogData[i].mainFogCoeff = fogResult.MainFogCoefficients; + blockPSVS.fogData[i].heightDensityFogCoeff = fogResult.HeightDensityFogCoefficients; + + bool mainFogOk = (fogResult.MainFogStartDist + 0.001 <= fogResult.MainFogEndDist); + blockPSVS.fogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( + mainFogOk ? fogResult.MainFogEndDist : fogResult.MainFogStartDist + 0.001, + fogResult.MainFogStartDist >= 0.0 ? fogResult.MainFogStartDist : 0.0f, + fogResult.LegacyFogScalar, + fogResult.FogBlendAlpha + ); + blockPSVS.fogData[i].heightFogEndColor_fogStartOffset = mathfu::vec4( + fogResult.HeightEndFogColor, + fogResult.FogStartOffset + ); + } sceneWideChunk->saveVersion(0); } From 0cd3ea8f5267e4e538bc5925300bfa8839019d58 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 5 Sep 2023 21:09:55 +0300 Subject: [PATCH 102/212] - refactor file loading - do some work on Fog - Add tracy vulkan zones --- src/database/CSqliteDB.cpp | 352 +++++++++--------- src/database/CSqliteDB.h | 6 +- .../dataExporter/DataExporterClass.cpp | 14 +- .../dataExporter/DataExporterClass.h | 46 ++- src/main.cpp | 8 - src/persistance/CascRequestProcessor.cpp | 2 +- src/persistance/CascRequestProcessor.h | 2 +- src/persistance/HttpRequestProcessor.cpp | 2 +- src/persistance/HttpRequestProcessor.h | 2 +- src/persistance/RequestProcessor.cpp | 47 +-- src/persistance/RequestProcessor.h | 42 +-- src/ui/FrontendUI.cpp | 24 +- src/ui/FrontendUI.h | 5 - .../MinimapGenerationWindow.h | 3 +- wowViewerLib/shaders/CMakeLists.txt | 2 +- .../glsl/common/commonFogFunctions.glsl | 39 +- wowViewerLib/src/engine/ApiContainer.h | 2 + .../src/engine/WowFilesCacheStorage.cpp | 55 --- .../src/engine/WowFilesCacheStorage.h | 3 - wowViewerLib/src/engine/cache/cache.h | 63 ---- .../src/engine/camera/firstPersonCamera.cpp | 12 +- .../src/engine/geometry/wmoGroupGeom.cpp | 15 +- .../src/engine/geometry/wmoGroupGeom.h | 6 +- .../src/engine/objects/scenes/map.cpp | 167 +++++---- .../src/engine/objects/wmo/wmoGroupObject.cpp | 5 +- .../src/engine/objects/wmo/wmoObject.cpp | 2 +- .../src/gapi/interface/materials/IMaterial.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 6 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 1 + .../vulkan/commandBuffer/CommandBuffer.cpp | 20 +- .../gapi/vulkan/commandBuffer/CommandBuffer.h | 8 +- .../CommandBufferRecorder.cpp | 5 + .../CommandBufferRecorder.h | 12 + wowViewerLib/src/include/config.h | 3 +- wowViewerLib/src/include/database/dbStructs.h | 2 + .../src/renderer/frame/FrameProfile.h | 7 +- .../src/renderer/frame/SceneComposer.cpp | 34 +- .../src/renderer/frame/SceneComposer.h | 1 - .../ProdConsumerIOConnector.h | 34 +- .../renderer/mapScene/MapSceneRenderer.cpp | 9 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 13 +- 42 files changed, 550 insertions(+), 535 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 8accc8087..2042ff19e 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -74,18 +74,20 @@ const std::string getLightSQL = R"===( select l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, l.LightParamsID_0, IFNULL(ls.SkyboxFileDataID, 0) as SkyboxFileDataID, IFNULL(lp.LightSkyboxID, 0) as LightSkyboxID, - lp.Glow, IFNULL(ls.Flags, 0) as SkyboxFlags - from Light l - left join LightParams lp on lp.ID = l.LightParamsID_0 - left join LightSkybox ls on ls.ID = lp.LightSkyboxID - where - ((l.ContinentID = ?) and (( - abs(l.GameCoords_0 - ?) < l.GameFalloffEnd and - abs(l.GameCoords_1 - ?) < l.GameFalloffEnd and - abs(l.GameCoords_2 - ?) < l.GameFalloffEnd - ) or (l.GameCoords_0 = 0 and l.GameCoords_1 = 0 and l.GameCoords_2 = 0))) - or (l.GameCoords_0 = 0 and l.GameCoords_1 = 0 and l.GameCoords_2 = 0 and l.ContinentID = 0) - ORDER BY l.ID desc + lp.Glow, IFNULL(ls.Flags, 0) as SkyboxFlags, l.ContinentID, + (abs(l.GameCoords_0 - ?1) * abs(l.GameCoords_0 - ?1) + + abs(l.GameCoords_1 - ?2) * abs(l.GameCoords_1 - ?2) + + abs(l.GameCoords_2 - ?3) * abs(l.GameCoords_2 - ?3)) as lightDistSQR + from Light l + left join LightParams lp on lp.ID = l.LightParamsID_0 + left join LightSkybox ls on ls.ID = lp.LightSkyboxID + where + ((l.ContinentID = ?4) and + ( + (lightDistSQR < (l.GameFalloffEnd * l.GameFalloffEnd)) or + (l.GameCoords_0 = 0 and l.GameCoords_1 = 0 and l.GameCoords_2 = 0) + )) or (l.GameCoords_0 = 0 and l.GameCoords_1 = 0 and l.GameCoords_2 = 0 and l.ContinentID = 0) + ORDER BY l.ID desc )==="; const std::string lightDataSQL = R"===( @@ -278,47 +280,47 @@ void initWithZeros(std::array &colorF) { colorF[2] = 0; colorF[3] = 0; } -void blendTwoAndAdd(float *colorF, int currLdRes, int lastLdRes, float timeAlphaBlend, float innerAlpha) { +void blendTwoAndAdd(float *colorF, int currLdRes, int lastLdRes, float timeAlphaBlend) { colorF[0] += (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + getFloatFromInt<0>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); colorF[1] += (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + getFloatFromInt<1>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); colorF[2] += (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + getFloatFromInt<2>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); } -inline void blendTwoAndAdd(std::array &colorF, int currLdRes, int lastLdRes, float timeAlphaBlend, float innerAlpha) { +inline void blendTwoAndAdd(std::array &colorF, int currLdRes, int lastLdRes, float timeAlphaBlend) { colorF[0] += (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + getFloatFromInt<0>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); colorF[1] += (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + getFloatFromInt<1>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); colorF[2] += (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + getFloatFromInt<2>(lastLdRes) * - (1.0f - timeAlphaBlend)) * innerAlpha; + (1.0f - timeAlphaBlend)); } -inline void blendTwoAndAdd(float &colorF, float currLdRes, float lastLdRes, float timeAlphaBlend, float innerAlpha) { - colorF += (currLdRes * timeAlphaBlend + lastLdRes * (1.0f - timeAlphaBlend)) * innerAlpha; +inline void blendTwoAndAdd(float &colorF, float currLdRes, float lastLdRes, float timeAlphaBlend) { + colorF += (currLdRes * timeAlphaBlend + lastLdRes * (1.0f - timeAlphaBlend)); } -inline void addOnlyOne(float *colorF, int currLdRes, float innerAlpha) { - colorF[0] += getFloatFromInt<0>(currLdRes) * innerAlpha; - colorF[1] += getFloatFromInt<1>(currLdRes) * innerAlpha; - colorF[2] += getFloatFromInt<2>(currLdRes) * innerAlpha; +inline void addOnlyOne(float *colorF, int currLdRes) { + colorF[0] += getFloatFromInt<0>(currLdRes); + colorF[1] += getFloatFromInt<1>(currLdRes); + colorF[2] += getFloatFromInt<2>(currLdRes); } -inline void addOnlyOne(std::array &colorF, int currLdRes, float innerAlpha) { - colorF[0] += getFloatFromInt<0>(currLdRes) * innerAlpha; - colorF[1] += getFloatFromInt<1>(currLdRes) * innerAlpha; - colorF[2] += getFloatFromInt<2>(currLdRes) * innerAlpha; +inline void addOnlyOne(std::array &colorF, int currLdRes) { + colorF[0] += getFloatFromInt<0>(currLdRes); + colorF[1] += getFloatFromInt<1>(currLdRes); + colorF[2] += getFloatFromInt<2>(currLdRes); } -inline void addOnlyOne(float &colorF, float currLdRes, float innerAlpha) { - colorF += currLdRes * innerAlpha; +inline void addOnlyOne(float &colorF, float currLdRes) { + colorF += currLdRes; } void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, float farClip) { getLightByIdStatement.setInputs( lightId ); @@ -336,8 +338,6 @@ void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, fl ilr.lightSkyboxId = getLightByIdStatement.getField("LightSkyboxID").getInt(); ilr.glow = getLightByIdStatement.getField("Glow").getDouble(); ilr.skyBoxFlags = getLightByIdStatement.getField("SkyboxFlags").getInt(); - - ilr.blendAlpha = 1.0f; } std::vector lightResults; convertInnerResultsToPublic(time, lightResults, innerResults, farClip); @@ -347,9 +347,11 @@ void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, fl }; void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std::vector &lightResults, float farClip) { - getLightStatement.setInputs( mapId, x, y, z ); + getLightStatement.setInputs(x, y, z, mapId ); std::vector innerResults; + bool defaultRecordSet = false; + InnerLightResult defaultRecord; float totalBlend = 0; while (getLightStatement.execute()) { @@ -365,168 +367,163 @@ void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std: ilr.glow = getLightStatement.getField("Glow").getDouble(); ilr.skyBoxFlags = getLightStatement.getField("SkyboxFlags").getInt(); - bool defaultRec = false; - if (ilr.pos[0] == 0 && ilr.pos[1] == 0 && ilr.pos[2] == 0 ) { - if (totalBlend > 1) continue; - defaultRec = true; - } + ilr.lightDistSQR = getLightStatement.getField("lightDistSQR").getDouble(); - if (!defaultRec) { - float distanceToLight = - std::sqrt( - (ilr.pos[0] - x) * (ilr.pos[0] - x) + - (ilr.pos[1] - y) * (ilr.pos[1] - y) + - (ilr.pos[2] - z) * (ilr.pos[2] - z)); + ilr.blendAlpha = + sqrtf(ilr.lightDistSQR) > ilr.fallbackStart ? + std::max( ((ilr.fallbackStart - sqrtf(ilr.lightDistSQR)) / (ilr.fallbackEnd - ilr.fallbackStart)) + 1.0f, 0.0f) : + 1.0f; - ilr.blendAlpha = 1.0f - (distanceToLight - ilr.fallbackStart) / (ilr.fallbackEnd - ilr.fallbackStart); - if (ilr.blendAlpha <= 0) continue; - - totalBlend += ilr.blendAlpha; - } else { - ilr.blendAlpha = 1.0f - totalBlend; - ilr.isDefault = true; + if (ilr.pos[0] == 0 && ilr.pos[1] == 0 && ilr.pos[2] == 0 ) { + if (!defaultRecordSet || mapId == getLightStatement.getField("ContinentID").getInt()){ + defaultRecord = ilr; + defaultRecord.isDefault = true; + defaultRecord.blendAlpha = 1.0f; + defaultRecordSet = true; + } + innerResults.resize(std::max(innerResults.size() - 1, 0)); } } + if (defaultRecordSet) innerResults.push_back(defaultRecord); + convertInnerResultsToPublic(ptime, lightResults, innerResults, farClip); } void CSqliteDB::addOnlyOne(LightResult &lightResult, - const CSqliteDB::InnerLightDataRes &currLdRes, - float innerAlpha) const {//Set as is - ::addOnlyOne(lightResult.ambientColor, currLdRes.ambientLight, innerAlpha); - ::addOnlyOne(lightResult.horizontAmbientColor, currLdRes.horizontAmbientColor, innerAlpha); - ::addOnlyOne(lightResult.groundAmbientColor, currLdRes.groundAmbientColor, innerAlpha); - - ::addOnlyOne(lightResult.directColor, currLdRes.directLight, innerAlpha); - - ::addOnlyOne(lightResult.closeRiverColor, currLdRes.closeRiverColor, innerAlpha); - ::addOnlyOne(lightResult.farRiverColor, currLdRes.farRiverColor, innerAlpha); - ::addOnlyOne(lightResult.closeOceanColor, currLdRes.closeOceanColor, innerAlpha); - ::addOnlyOne(lightResult.farOceanColor, currLdRes.farOceanColor, innerAlpha); - - ::addOnlyOne(lightResult.SkyTopColor, currLdRes.SkyTopColor, innerAlpha); - ::addOnlyOne(lightResult.SkyMiddleColor, currLdRes.SkyMiddleColor, innerAlpha); - ::addOnlyOne(lightResult.SkyBand1Color, currLdRes.SkyBand1Color, innerAlpha); - ::addOnlyOne(lightResult.SkyBand2Color, currLdRes.SkyBand2Color, innerAlpha); - ::addOnlyOne(lightResult.SkySmogColor, currLdRes.SkySmogColor, innerAlpha); - ::addOnlyOne(lightResult.SkyFogColor, currLdRes.SkyFogColor, innerAlpha); - - ::addOnlyOne(lightResult.FogEnd, currLdRes.FogEnd, innerAlpha); - ::addOnlyOne(lightResult.FogScaler, currLdRes.FogScaler, innerAlpha); - ::addOnlyOne(lightResult.FogDensity, currLdRes.FogDensity, innerAlpha); - ::addOnlyOne(lightResult.FogHeight, currLdRes.FogHeight, innerAlpha); - ::addOnlyOne(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, innerAlpha); - ::addOnlyOne(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, innerAlpha); - - ::addOnlyOne(lightResult.EndFogColor, currLdRes.EndFogColor, innerAlpha); - ::addOnlyOne(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, innerAlpha); - ::addOnlyOne(lightResult.SunFogColor, currLdRes.SunFogColor, innerAlpha); - - ::addOnlyOne(lightResult.FogHeightColor, currLdRes.FogHeightColor, innerAlpha); - ::addOnlyOne(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0], innerAlpha); - ::addOnlyOne(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], innerAlpha); - ::addOnlyOne(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], innerAlpha); - ::addOnlyOne(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], innerAlpha); - - ::addOnlyOne(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], innerAlpha); - ::addOnlyOne(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], innerAlpha); - ::addOnlyOne(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], innerAlpha); - ::addOnlyOne(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], innerAlpha); - - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], innerAlpha); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], innerAlpha); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], innerAlpha); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], innerAlpha); - - ::addOnlyOne(lightResult.FogZScalar, currLdRes.FogZScalar, innerAlpha); - ::addOnlyOne(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, innerAlpha); - ::addOnlyOne(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, innerAlpha); - ::addOnlyOne(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor, innerAlpha); - ::addOnlyOne(lightResult.FogStartOffset, currLdRes.FogStartOffset, innerAlpha); + const CSqliteDB::InnerLightDataRes &currLdRes) const {//Set as is + ::addOnlyOne(lightResult.ambientColor, currLdRes.ambientLight); + ::addOnlyOne(lightResult.horizontAmbientColor, currLdRes.horizontAmbientColor); + ::addOnlyOne(lightResult.groundAmbientColor, currLdRes.groundAmbientColor); + + ::addOnlyOne(lightResult.directColor, currLdRes.directLight); + + ::addOnlyOne(lightResult.closeRiverColor, currLdRes.closeRiverColor); + ::addOnlyOne(lightResult.farRiverColor, currLdRes.farRiverColor); + ::addOnlyOne(lightResult.closeOceanColor, currLdRes.closeOceanColor); + ::addOnlyOne(lightResult.farOceanColor, currLdRes.farOceanColor); + + ::addOnlyOne(lightResult.SkyTopColor, currLdRes.SkyTopColor); + ::addOnlyOne(lightResult.SkyMiddleColor, currLdRes.SkyMiddleColor); + ::addOnlyOne(lightResult.SkyBand1Color, currLdRes.SkyBand1Color); + ::addOnlyOne(lightResult.SkyBand2Color, currLdRes.SkyBand2Color); + ::addOnlyOne(lightResult.SkySmogColor, currLdRes.SkySmogColor); + ::addOnlyOne(lightResult.SkyFogColor, currLdRes.SkyFogColor); + + ::addOnlyOne(lightResult.FogEnd, currLdRes.FogEnd); + ::addOnlyOne(lightResult.FogScaler, currLdRes.FogScaler); + ::addOnlyOne(lightResult.FogDensity, currLdRes.FogDensity); + ::addOnlyOne(lightResult.FogHeight, currLdRes.FogHeight); + ::addOnlyOne(lightResult.FogHeightScaler, currLdRes.FogHeightScaler); + ::addOnlyOne(lightResult.FogHeightDensity, currLdRes.FogHeightDensity); + + ::addOnlyOne(lightResult.EndFogColor, currLdRes.EndFogColor); + ::addOnlyOne(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance); + ::addOnlyOne(lightResult.SunFogColor, currLdRes.SunFogColor); + + ::addOnlyOne(lightResult.FogHeightColor, currLdRes.FogHeightColor); + ::addOnlyOne(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0]); + ::addOnlyOne(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1]); + ::addOnlyOne(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2]); + ::addOnlyOne(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3]); + + ::addOnlyOne(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0]); + ::addOnlyOne(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1]); + ::addOnlyOne(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2]); + ::addOnlyOne(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3]); + + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0]); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1]); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2]); + ::addOnlyOne(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3]); + + ::addOnlyOne(lightResult.FogZScalar, currLdRes.FogZScalar); + ::addOnlyOne(lightResult.MainFogStartDist, currLdRes.MainFogStartDist); + ::addOnlyOne(lightResult.MainFogEndDist, currLdRes.MainFogEndDist); + ::addOnlyOne(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor); + ::addOnlyOne(lightResult.FogStartOffset, currLdRes.FogStartOffset); } void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &lastLdRes, - const CSqliteDB::InnerLightDataRes &currLdRes, float timeAlphaBlend, - float innerAlpha) const { + const CSqliteDB::InnerLightDataRes &currLdRes, float timeAlphaBlend) const { ::blendTwoAndAdd(lightResult.ambientColor, currLdRes.ambientLight, lastLdRes.ambientLight, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.horizontAmbientColor, currLdRes.horizontAmbientColor, lastLdRes.horizontAmbientColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.groundAmbientColor, currLdRes.groundAmbientColor, lastLdRes.groundAmbientColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.directColor, currLdRes.directLight, lastLdRes.directLight, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.closeRiverColor, currLdRes.closeRiverColor, lastLdRes.closeRiverColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.farRiverColor, currLdRes.farRiverColor, lastLdRes.farRiverColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.closeOceanColor, currLdRes.closeOceanColor, lastLdRes.closeOceanColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.farOceanColor, currLdRes.farOceanColor, lastLdRes.farOceanColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkyTopColor, currLdRes.SkyTopColor, lastLdRes.SkyTopColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkyMiddleColor, currLdRes.SkyMiddleColor, lastLdRes.SkyMiddleColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkyBand1Color, currLdRes.SkyBand1Color, lastLdRes.SkyBand1Color, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkyBand2Color, currLdRes.SkyBand2Color, lastLdRes.SkyBand2Color, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkySmogColor, currLdRes.SkySmogColor, lastLdRes.SkySmogColor, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SkyFogColor, currLdRes.SkyFogColor, lastLdRes.SkyFogColor, - timeAlphaBlend, innerAlpha); - - ::blendTwoAndAdd(lightResult.FogEnd, currLdRes.FogEnd, lastLdRes.FogEnd, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogScaler, currLdRes.FogScaler, lastLdRes.FogScaler, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogDensity, currLdRes.FogDensity, lastLdRes.FogDensity, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeight, currLdRes.FogHeight, lastLdRes.FogHeight, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, lastLdRes.FogHeightScaler, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, lastLdRes.FogHeightDensity, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.EndFogColor, currLdRes.EndFogColor, lastLdRes.EndFogColor, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, lastLdRes.EndFogColorDistance, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.SunFogColor, currLdRes.SunFogColor, lastLdRes.SunFogColor, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.SunFogStrength, currLdRes.SunFogStrength, lastLdRes.SunFogStrength, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightColor, currLdRes.FogHeightColor, lastLdRes.FogHeightColor, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0], lastLdRes.FogHeightCoefficients[0], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], lastLdRes.FogHeightCoefficients[1], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], lastLdRes.FogHeightCoefficients[2], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], lastLdRes.FogHeightCoefficients[3], timeAlphaBlend, innerAlpha); - - - ::blendTwoAndAdd(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], lastLdRes.MainFogCoefficients[0], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], lastLdRes.MainFogCoefficients[1], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], lastLdRes.MainFogCoefficients[2], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], lastLdRes.MainFogCoefficients[3], timeAlphaBlend, innerAlpha); - - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], lastLdRes.HeightDensityFogCoeff[0], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], lastLdRes.HeightDensityFogCoeff[1], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], lastLdRes.HeightDensityFogCoeff[2], timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], lastLdRes.HeightDensityFogCoeff[3], timeAlphaBlend, innerAlpha); - - ::blendTwoAndAdd(lightResult.FogZScalar, currLdRes.FogZScalar, lastLdRes.FogZScalar, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, lastLdRes.MainFogStartDist, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, lastLdRes.MainFogEndDist, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor,lastLdRes.EndFogHeightColor, timeAlphaBlend, innerAlpha); - ::blendTwoAndAdd(lightResult.FogStartOffset, currLdRes.FogStartOffset, lastLdRes.FogStartOffset, timeAlphaBlend, innerAlpha); + timeAlphaBlend); + + ::blendTwoAndAdd(lightResult.FogEnd, currLdRes.FogEnd, lastLdRes.FogEnd, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogScaler, currLdRes.FogScaler, lastLdRes.FogScaler, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogDensity, currLdRes.FogDensity, lastLdRes.FogDensity, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeight, currLdRes.FogHeight, lastLdRes.FogHeight, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, lastLdRes.FogHeightScaler, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, lastLdRes.FogHeightDensity, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.EndFogColor, currLdRes.EndFogColor, lastLdRes.EndFogColor, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, lastLdRes.EndFogColorDistance, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.SunFogColor, currLdRes.SunFogColor, lastLdRes.SunFogColor, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.SunFogStrength, currLdRes.SunFogStrength, lastLdRes.SunFogStrength, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightColor, currLdRes.FogHeightColor, lastLdRes.FogHeightColor, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0], lastLdRes.FogHeightCoefficients[0], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], lastLdRes.FogHeightCoefficients[1], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], lastLdRes.FogHeightCoefficients[2], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], lastLdRes.FogHeightCoefficients[3], timeAlphaBlend); + + + ::blendTwoAndAdd(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], lastLdRes.MainFogCoefficients[0], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], lastLdRes.MainFogCoefficients[1], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], lastLdRes.MainFogCoefficients[2], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], lastLdRes.MainFogCoefficients[3], timeAlphaBlend); + + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], lastLdRes.HeightDensityFogCoeff[0], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], lastLdRes.HeightDensityFogCoeff[1], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], lastLdRes.HeightDensityFogCoeff[2], timeAlphaBlend); + ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], lastLdRes.HeightDensityFogCoeff[3], timeAlphaBlend); + + ::blendTwoAndAdd(lightResult.FogZScalar, currLdRes.FogZScalar, lastLdRes.FogZScalar, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, lastLdRes.MainFogStartDist, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, lastLdRes.MainFogEndDist, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor,lastLdRes.EndFogHeightColor, timeAlphaBlend); + ::blendTwoAndAdd(lightResult.FogStartOffset, currLdRes.FogStartOffset, lastLdRes.FogStartOffset, timeAlphaBlend); } float arr4SqrLength(const std::array &arr) { @@ -542,13 +539,26 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector float farClip) { //From lowest to highest - std::sort(innerResults.begin(), innerResults.end(), [](const InnerLightResult &a, const InnerLightResult &b) { - return a.blendAlpha > b.blendAlpha; - }); + std::sort(innerResults.begin(), innerResults.end(), +[](const InnerLightResult &a, const InnerLightResult &b) -> bool { + if (a.isDefault) return true; + if (b.isDefault) return false; + + float distanceSqr = + (a.pos[0] - b.pos[0]) * (a.pos[0] - b.pos[0]) + + (a.pos[1] - b.pos[1]) * (a.pos[1] - b.pos[1]) + + (a.pos[2] - b.pos[2]) * (a.pos[2] - b.pos[2]); + + static const float tolerance = 0.33333334f; + if (sqrtf(distanceSqr) < tolerance) { + return a.fallbackStart < b.fallbackStart; + } else { + return a.lightDistSQR < b.lightDistSQR; + } + return false; + }); - float totalSummator = 0.0f; - for (int i = 0; i < innerResults.size() && totalSummator < 1.0f; i++) { + for (int i = 0; i < innerResults.size(); i++) { LightResult lightResult; initWithZeros(lightResult.ambientColor); initWithZeros(lightResult.horizontAmbientColor); @@ -607,11 +617,9 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector InnerLightDataRes lastLdRes = {0, 0, -1}; bool assigned = false; - float innerAlpha = innerResult.blendAlpha < 1.0 ? innerResult.blendAlpha : 1.0; - if (totalSummator + innerAlpha > 1.0f) { - innerAlpha = 1.0f - totalSummator; - } - lightResult.blendCoef = innerAlpha; + + lightResult.blendCoef = innerResult.blendAlpha; + lightResult.skyBoxFdid = innerResult.skyBoxFileId; lightResult.skyBoxFlags = innerResult.skyBoxFlags; @@ -750,13 +758,13 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector lightResult.SunAngleBlend = 1.0f; ::blendTwoAndAdd(lightResult.SunFogStrength, currLdRes.SunFogStrength, lastLdRes.SunFogStrength, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, - timeAlphaBlend, innerAlpha); + timeAlphaBlend); lightResult.SunFogAngle = 1.0f; } else - if ((SunFogAngle2 >= 1.0f and SunFogAngle2 >= 1.0) || (SunFogAngle1 < 1.0 and SunFogAngle2 >= 1.0)) + if ((SunFogAngle2 >= 1.0f && SunFogAngle2 >= 1.0) || (SunFogAngle1 < 1.0 && SunFogAngle2 >= 1.0)) { lightResult.SunAngleBlend = 1.0f - timeAlphaBlend; lightResult.SunFogStrength = lastLdRes.SunFogStrength; @@ -768,9 +776,9 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector } } if (lastLdRes.time == -1) { - addOnlyOne(lightResult, currLdRes, innerAlpha); + addOnlyOne(lightResult, currLdRes); } else { - blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend, innerAlpha); + blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend); } break; } @@ -778,7 +786,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector } if (!assigned) { - addOnlyOne(lightResult, lastLdRes, innerAlpha); + addOnlyOne(lightResult, lastLdRes); } //Hack for LegacyFogScaler @@ -792,8 +800,6 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector } lightResults.push_back(lightResult); - - totalSummator += innerResult.blendAlpha; } } diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index 0dcaff72d..fa3bf1aac 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -132,6 +132,7 @@ class CSqliteDB : public IClientDatabase { float pos[3]; float fallbackStart; float fallbackEnd; + float lightDistSQR = 0; float blendAlpha = 0; int paramId; int skyBoxFileId; @@ -187,13 +188,12 @@ class CSqliteDB : public IClientDatabase { std::vector &innerResults, float farClip); void - addOnlyOne(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &currLdRes, - float innerAlpha) const; + addOnlyOne(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &currLdRes) const; void blendTwoAndAdd(LightResult &lightResult, const InnerLightDataRes &lastLdRes, const InnerLightDataRes &currLdRes, - float timeAlphaBlend, float innerAlpha) const; + float timeAlphaBlend) const; }; diff --git a/src/exporters/dataExporter/DataExporterClass.cpp b/src/exporters/dataExporter/DataExporterClass.cpp index 755c5ff46..7bab29bb7 100644 --- a/src/exporters/dataExporter/DataExporterClass.cpp +++ b/src/exporters/dataExporter/DataExporterClass.cpp @@ -222,11 +222,23 @@ void DataExporter::DataExporterClass::exportDBSkin(int id) { auto const batch = skinProfile->batches.getElement(batchIndex); DataExporter::DBM2Batch dbm2Batch; - *dynamic_cast(&dbm2Batch) = *batch; + *dynamic_cast(&dbm2Batch) = *batch; dbm2Batch.m2Id = id; dbm2Batch.batchIndex = batchIndex; m_storage.insert(dbm2Batch); } + + M2Array &skinSections = skinProfile->skinSections; + for (int skinSectionIndex = 0; skinSectionIndex < skinSections.size; skinSectionIndex++) { + auto const skinSection = skinProfile->skinSections.getElement(skinSectionIndex); + + DataExporter::DBSkinSection dbm2SkinSection; + *dynamic_cast(&dbm2SkinSection) = *skinSection; + dbm2SkinSection.m2Id = id; + dbm2SkinSection.skinSectionIndex = skinSectionIndex; + + m_storage.insert(dbm2SkinSection); + } } diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index e67320004..39bcbeaec 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -22,9 +22,25 @@ namespace DataExporter { int batchIndex = -1; }; - struct DBSkinSection { + struct DBSkinSection : public M2SkinSection{ int m2Id = -1; - M2SkinSection skinSection; + int skinSectionIndex = -1; + + float getCenterPositionX() const {return this->centerPosition.x;}; + float getCenterPositionY() const {return this->centerPosition.y;}; + float getCenterPositionZ() const {return this->centerPosition.z;}; + + float getSortCenterPositionX() const {return this->sortCenterPosition.x;}; + float getSortCenterPositionY() const {return this->sortCenterPosition.y;}; + float getSortCenterPositionZ() const {return this->sortCenterPosition.z;}; + + void setCenterPositionX(float value) {this->sortCenterPosition.x = value;}; + void setCenterPositionY(float value) {this->sortCenterPosition.y = value;}; + void setCenterPositionZ(float value) {this->sortCenterPosition.z = value;}; + + void setSortCenterPositionX(float value) {this->sortCenterPosition.x = value;}; + void setSortCenterPositionY(float value) {this->sortCenterPosition.y = value;}; + void setSortCenterPositionZ(float value) {this->sortCenterPosition.z = value;}; }; struct DBM2Material : M2Material{ @@ -148,6 +164,32 @@ namespace DataExporter { foreign_key(&DBM2Batch::m2Id).references(&DBM2::m2Id), unique(&DBM2Batch::m2Id, &DBM2Batch::batchIndex) ), + make_table("M2SkinSection", + make_column("m2Id", &DBSkinSection::m2Id), + make_column("skinSectionIndex", &DBSkinSection::skinSectionIndex), +#ifdef _MSC_VER + make_column("skinSectionId", &DBSkinSection::skinSectionId), + make_column("Level", &DBSkinSection::Level), + make_column("vertexStart", &DBSkinSection::vertexStart), + make_column("vertexCount", &DBSkinSection::vertexCount), + make_column("indexStart", &DBSkinSection::indexStart), + make_column("indexCount", &DBSkinSection::indexCount), + make_column("boneCount", &DBSkinSection::boneCount), + make_column("boneComboIndex", &DBSkinSection::boneComboIndex), + make_column("boneInfluences", &DBSkinSection::boneInfluences), + make_column("centerBoneIndex", &DBSkinSection::centerBoneIndex), + + make_column("centerPosition_0", &DBSkinSection::getCenterPositionX, &DBSkinSection::setCenterPositionX), + make_column("centerPosition_1", &DBSkinSection::getCenterPositionY, &DBSkinSection::setCenterPositionY), + make_column("centerPosition_2", &DBSkinSection::getCenterPositionZ, &DBSkinSection::setCenterPositionZ), + make_column("sortCenterPosition_0", &DBSkinSection::getSortCenterPositionX, &DBSkinSection::setSortCenterPositionX), + make_column("sortCenterPosition_1", &DBSkinSection::getSortCenterPositionY, &DBSkinSection::setSortCenterPositionY), + make_column("sortCenterPosition_2", &DBSkinSection::getSortCenterPositionZ, &DBSkinSection::setSortCenterPositionZ), +#endif + make_column("sortRadius", &DBSkinSection::sortRadius), + foreign_key(&DBSkinSection::m2Id).references(&DBM2::m2Id), + unique(&DBSkinSection::m2Id, &DBSkinSection::skinSectionIndex) + ), make_table("M2Material", make_column("m2Id", &DBM2Material::m2Id), make_column("materialIndex", &DBM2Material::materialIndex), diff --git a/src/main.cpp b/src/main.cpp index 06ac064b0..a1bbbe3f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -481,14 +481,6 @@ int main(){ // Render scene currentFrame = glfwGetTime(); // seconds double deltaTime = currentFrame - lastFrame; - { - auto processor = frontendUI->getProcessor(); - if (frontendUI->getProcessor()) { - if (!processor->getThreaded()) { - processor->processRequests(false); - } - } - } apiContainer->camera->tick(deltaTime*(1000.0f)); if (apiContainer->debugCamera != nullptr) { diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 09951541d..573eb1506 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -133,7 +133,7 @@ HFileContent CascRequestProcessor::tryGetFile(void *cascStorage, void *fileNameT return fileContent; } -void CascRequestProcessor::processFileRequest(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) { +void CascRequestProcessor::processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) { auto perstFile = s_file.lock(); uint32_t fileDataId = 0; if (fileName.find("File") == 0) { diff --git a/src/persistance/CascRequestProcessor.h b/src/persistance/CascRequestProcessor.h index 88475496a..7fd2b6017 100644 --- a/src/persistance/CascRequestProcessor.h +++ b/src/persistance/CascRequestProcessor.h @@ -24,7 +24,7 @@ class CascRequestProcessor : public RequestProcessor { void* m_storage = nullptr; void* m_storageOnline = nullptr; protected: - void processFileRequest(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) override; + void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) override; private: HFileContent tryGetFile(void *cascStorage, void *fileNameToPass, uint32_t openFlags); }; diff --git a/src/persistance/HttpRequestProcessor.cpp b/src/persistance/HttpRequestProcessor.cpp index eb7f8df92..1370aa2af 100644 --- a/src/persistance/HttpRequestProcessor.cpp +++ b/src/persistance/HttpRequestProcessor.cpp @@ -40,7 +40,7 @@ std::string ReplaceAll(std::string str, const std::string& from, const std::stri return str; } -void HttpRequestProcessor::processFileRequest(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) { +void HttpRequestProcessor::processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) { auto perstFile = s_file.lock(); if (perstFile == nullptr){ toBeProcessed--; diff --git a/src/persistance/HttpRequestProcessor.h b/src/persistance/HttpRequestProcessor.h index b7a0eeef1..e58e0cf09 100644 --- a/src/persistance/HttpRequestProcessor.h +++ b/src/persistance/HttpRequestProcessor.h @@ -17,7 +17,7 @@ class HttpRequestProcessor : public RequestProcessor { std::string m_urlBase; std::string m_urlBaseFileId; protected: - void processFileRequest(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) override; + void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) override; }; diff --git a/src/persistance/RequestProcessor.cpp b/src/persistance/RequestProcessor.cpp index b402eee03..926976bf6 100644 --- a/src/persistance/RequestProcessor.cpp +++ b/src/persistance/RequestProcessor.cpp @@ -4,9 +4,6 @@ #include #include "RequestProcessor.h" -std::mutex requestMtx; // mutex for critical section -std::mutex resultMtx; // mutex for critical section - std::mutex setProcessingMtx; // mutex for critical section //1. Add request to FIFO @@ -35,59 +32,36 @@ RequestProcessor::requestFile(std::string &fileName, CacheHolderType holderType, currentlyProcessingFnames.insert(fileName); setLck.unlock(); - std::unique_lock lck (requestMtx,std::defer_lock); - // critical section (exclusive access to std::cout signaled by locking lck): - lck.lock(); - - m_requestQueue.push_back({fileName, holderType, s_file}); + m_requestQueue->pushInput({fileName, holderType, s_file}); toBeProcessed++; - lck.unlock(); } -void RequestProcessor::processRequests (bool calledFromThread) { +void RequestProcessor::processRequests (int limit) { using namespace std::chrono_literals; // critical section (exclusive access to std::cout signaled by locking lck): - std::unique_lock lck (requestMtx,std::defer_lock); - - if (calledFromThread){ - while (!this->isTerminating) { - if (m_requestQueue.empty()) { - std::this_thread::sleep_for(1ms); - continue; - } - - lck.lock(); - auto it = m_requestQueue.front(); - m_requestQueue.pop_front(); - lck.unlock(); + std::unique_lock setLck (setProcessingMtx,std::defer_lock); + if (m_threaded) { + m_requestQueue->waitAndProcess([&](const RequestStruct &it) { this->processFileRequest(it.fileName, it.holderType, it.s_file); - std::unique_lock setLck (setProcessingMtx,std::defer_lock); setLck.lock(); currentlyProcessingFnames.erase(it.fileName); setLck.unlock(); - } - } else if (!m_threaded) { - while (!m_requestQueue.empty()) { - lck.lock(); - auto it = m_requestQueue.front(); - m_requestQueue.pop_front(); - lck.unlock(); - + }); + } else { + m_requestQueue->blockProcessWithoutWait(limit, [&](const RequestStruct &it) { this->processFileRequest(it.fileName, it.holderType, it.s_file); - std::unique_lock setLck (setProcessingMtx,std::defer_lock); setLck.lock(); currentlyProcessingFnames.erase(it.fileName); setLck.unlock(); - } + }); } - } void -RequestProcessor::processResult(std::shared_ptr s_file, HFileContent content, const std::string &fileName) { +RequestProcessor::processResult(const std::shared_ptr &s_file, const HFileContent &content, const std::string &fileName) { if (s_file->getStatus() == FileStatus::FSLoaded) { std::cout << "sharedPtr->getStatus == FileStatus::FSLoaded " << fileName << std::endl; } if (s_file->getStatus() == FileStatus::FSRejected) { @@ -95,5 +69,4 @@ RequestProcessor::processResult(std::shared_ptr s_file, HFileCon } else { s_file->process(content, fileName); } - } diff --git a/src/persistance/RequestProcessor.h b/src/persistance/RequestProcessor.h index 5a3145452..13b90b862 100644 --- a/src/persistance/RequestProcessor.h +++ b/src/persistance/RequestProcessor.h @@ -7,6 +7,7 @@ #include "../../wowViewerLib/src/include/sharedFile.h" #include "../../wowViewerLib/src/include/iostuff.h" +#include "../../wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h" #include #include #include @@ -17,25 +18,25 @@ class RequestProcessor : public IFileRequest { protected: RequestProcessor() : toBeProcessed(0){ - + m_requestQueue = std::make_unique(dumb_boolean_always_false); } virtual ~RequestProcessor() { - if (loaderThread != nullptr) { - isTerminating = true; - loaderThread->join(); - loaderThread = nullptr; - } }; protected: IFileRequester *m_fileRequester = nullptr; - virtual void processFileRequest(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) = 0; + virtual void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) = 0; public: void setFileRequester(IFileRequester *fileRequester) { m_fileRequester = fileRequester; } + void initThreadQueue(bool &isTerminating) { + m_threaded = true; + m_requestQueue = std::make_unique(isTerminating); + } + void requestFile(std::string &fileName, CacheHolderType holderType, std::weak_ptr s_file) override; private: class RequestStruct { @@ -58,38 +59,21 @@ class RequestProcessor : public IFileRequest { HFileContent buffer = nullptr; }; - bool isTerminating = false; - std::shared_ptr loaderThread = nullptr; - - std::list m_requestQueue; + std::unique_ptr> m_requestQueue; std::list m_resultQueue; std::unordered_set currentlyProcessingFnames; bool m_threaded = false; - - int currentlyProcessing = 0; + bool dumb_boolean_always_false = false; public: - void processRequests(bool calledFromThread); + void processRequests(int limit); bool completedAllJobs() { - return (m_requestQueue.empty()) && (m_resultQueue.empty()) && (toBeProcessed == 0); + return (m_requestQueue->empty()) && (m_resultQueue.empty()) && (toBeProcessed == 0); }; - - bool getThreaded() { - return m_threaded; - } - void setThreaded(bool value) { - m_threaded = value; - if (value) { - loaderThread = std::make_shared(([&](){ - this->processRequests(true); - })); - } - } - protected: std::atomic toBeProcessed; - void processResult( std::shared_ptr s_file, HFileContent content, const std::string &fileName); + void processResult(const std::shared_ptr &s_file, const HFileContent &content, const std::string &fileName); }; typedef std::shared_ptr HRequestProcessor; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 92ec8ee0b..980d0795b 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -39,7 +39,6 @@ FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { m_api = api; - m_processor = processor; this->createDatabaseHandler(); m_uiRenderer = FrontendUIRendererFactory::createForwardRenderer(m_api->hDevice); @@ -48,6 +47,7 @@ FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { } void FrontendUI::composeUI() { + if (m_dataExporter != nullptr) { m_dataExporter->process(); if (m_dataExporter->isDone()) @@ -270,7 +270,6 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Elapsed time on consumeUpdate : %.3f ms", m_api->getConfig()->consumeUpdate); ImGui::Text("Elapsed time on consumeDraw : %.3f ms", m_api->getConfig()->consumeDraw); ImGui::Text("Elapsed time on composerDrawTimePerFrame : %.3f ms", m_api->getConfig()->composerDrawTimePerFrame); - ImGui::Text("Elapsed time on culling : %.3f ms", m_api->getConfig()->cullingTimePerFrame); ImGui::Text("- Elapsed time on cullCreateVarsCounter: %.3f ms", m_api->getConfig()->cullCreateVarsCounter); ImGui::Text("- Elapsed time on cullGetCurrentWMOCounter: %.3f ms", m_api->getConfig()->cullGetCurrentWMOCounter); ImGui::Text("- Elapsed time on cullGetCurrentZoneCounter: %.3f ms", m_api->getConfig()->cullGetCurrentZoneCounter); @@ -722,8 +721,8 @@ void FrontendUI::showMainMenu() { } if (ImGui::MenuItem("Update keys", "", false)) { m_keyUpdateWorkFlow = std::make_shared( - std::dynamic_pointer_cast(m_processor) - ); + std::dynamic_pointer_cast(m_api->requestProcessor) + ); } ImGui::EndMenu(); } @@ -1412,6 +1411,10 @@ void FrontendUI::showSettingsDialog() { if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { m_api->camera->setMovementSpeed(movementSpeed); } + auto fogDensityIncreaser = m_api->getConfig()->fogDensityIncreaser; + if (ImGui::SliderFloat("Fog Density", &fogDensityIncreaser, -4, 4)) { + m_api->getConfig()->fogDensityIncreaser = fogDensityIncreaser; + } switch(m_api->getConfig()->globalLighting) { case EParameterSource::eDatabase: { @@ -1910,14 +1913,13 @@ bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { try { newProcessor = std::make_shared(cascPath, buildDef); newStorage = std::make_shared(newProcessor.get()); - newProcessor->setThreaded(true); newProcessor->setFileRequester(newStorage.get()); } catch (...){ return false; }; m_api->cacheStorage = newStorage; - m_processor = newProcessor; + m_api->requestProcessor = newProcessor; return true; } @@ -2058,13 +2060,12 @@ void FrontendUI::createDefaultprocessor() { // processor = new HttpZipRequestProcessor(url); //// processor = new ZipRequestProcessor(filePath); //// processor = new MpqRequestProcessor(filePath); - m_processor = std::make_shared(url, urlFileId); + m_api->requestProcessor = std::make_shared(url, urlFileId); // m_processor = std::make_shared("e:\\games\\wow beta\\World of Warcraft Beta\\:wowt"); //// processor->setThreaded(false); //// - m_processor->setThreaded(true); - m_api->cacheStorage = std::make_shared(m_processor.get()); - m_processor->setFileRequester(m_api->cacheStorage.get()); + m_api->cacheStorage = std::make_shared(m_api->requestProcessor.get()); + m_api->requestProcessor->setFileRequester(m_api->cacheStorage.get()); overrideCascOpened(true); } @@ -2073,8 +2074,7 @@ void FrontendUI::showMinimapGenerationSettingsDialog() { if (m_minimapGenerationWindow == nullptr) m_minimapGenerationWindow = std::make_shared(m_api, m_uiRenderer, - m_processor, - showMinimapGeneratorSettings); + showMinimapGeneratorSettings); m_minimapGenerationWindow->render(); } else { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 50acf50cb..b301dcc60 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -45,10 +45,6 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &renderer, HRequestProcessor processor, bool &showMinimapGeneratorSettings) : + MinimapGenerationWindow(HApiContainer api, const std::shared_ptr &renderer, bool &showMinimapGeneratorSettings) : m_showMinimapGeneratorSettings(showMinimapGeneratorSettings), m_renderer(renderer) { m_api = api; - m_processor = processor; m_minimapDB = std::make_shared("minimapdb.sqlite"); m_minimapDB->getScenarios(sceneDefList); diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 6dfc79a86..3ba1fa4ee 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -7,11 +7,11 @@ endif() if (COMPILE_SHADER_WITH_DEBUG) set(SHADER_DEBUG_FLAG "-g") + set(APP_RUN_PREFIX "") else() set(SHADER_DEBUG_FLAG "") endif() -set(APP_RUN_PREFIX "") if (EMSCRIPTEN) set(APP_RUN_PREFIX node --experimental-wasm-simd) endif() diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index 39afa59ea..9c0b18336 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -249,17 +249,37 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec vec3 normalize_918 = normalize(vertexInViewSpace); float t924 = mainFogData[i].sunAngle_and_sunColor.x; float alpha_935 = final.w; - float end2_938 = saturatef(((vLength - mainFogData[i].heightFogEndColor_fogStartOffset.w) / mainFogData[i].heightColor_and_endFogDistance.w)); + float end2_938 = saturatef( + (vLength - mainFogData[i].heightFogEndColor_fogStartOffset.w) / + mainFogData[i].heightColor_and_endFogDistance.w + ); + + //Height fog color calculation float end_940 = (end2_938 * (end2_938 * end2_938)); - vec3 heightColor_942 = mix(validateFogColor(mainFogData[0].heightColor_and_endFogDistance.xyz, blendMode), - validateFogColor(mainFogData[0].heightFogEndColor_fogStartOffset.xyz, blendMode), vec3(end2_938)); + vec3 heightColor_942 = mix( + validateFogColor(mainFogData[0].heightColor_and_endFogDistance.xyz, blendMode), + validateFogColor(mainFogData[0].heightFogEndColor_fogStartOffset.xyz, blendMode), + vec3(end2_938) + ); + + //Usual fog color calculation float saturate_943 = saturatef(end_940); - vec3 fogFinal_945 = mix(validateFogColor(mainFogData[0].color_and_heightRate.xyz, blendMode), - validateFogColor(mainFogData[0].heightDensity_and_endColor.yzw, blendMode), vec3(saturate_943)); + vec3 fogFinal_945 = mix( + validateFogColor(mainFogData[0].color_and_heightRate.xyz, blendMode), + validateFogColor(mainFogData[0].heightDensity_and_endColor.yzw, blendMode), + vec3(saturate_943) + ); + + //Mix fog colors above together vec3 fogFinal_947 = mix(fogFinal_945, heightColor_942, vec3(heightFog_955)); float dot_948 = dot(normalize_918, mainFogData[i].sunDirection_and_fogZScalar.xyz); float nDotSun_949 = saturatef(dot_948); - vec3 sunColor_951 = mix(fogFinal_947, validateFogColor(mainFogData[0].sunAngle_and_sunColor.yzw, blendMode), vec3(mainFogData[i].sunPercentage.x)); + vec3 sunColor_951 = mix( + fogFinal_947, + validateFogColor(mainFogData[0].sunAngle_and_sunColor.yzw, blendMode), + vec3(mainFogData[i].sunPercentage.x) + ); + float nDotSun_953 = saturatef((nDotSun_949 - t924)); vec3 fogFinal_969; if (nDotSun_953 > 0.0f) @@ -291,7 +311,12 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec } // Block 977 float alpha_988 = alpha_978; - vec3 lerp_981 = mix(fogFinal_971, final.xyz, vec3(_retVal_956)); + vec3 lerp_981 = mix( + fogFinal_971, + final.xyz, + vec3(_retVal_956) + ); + vec4 t982 = vec4(lerp_981, alpha_988); vec4 outColor_986 = (outColor_713 + (t982 * mainFogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); diff --git a/wowViewerLib/src/engine/ApiContainer.h b/wowViewerLib/src/engine/ApiContainer.h index d95fa3127..637de70b3 100644 --- a/wowViewerLib/src/engine/ApiContainer.h +++ b/wowViewerLib/src/engine/ApiContainer.h @@ -14,6 +14,7 @@ typedef std::shared_ptr HApiContainer; #include "camera/CameraInterface.h" #include "../include/config.h" #include "../include/databaseHandler.h" +#include "../../../src/persistance/RequestProcessor.h" class ApiContainer { @@ -21,6 +22,7 @@ class ApiContainer { Config config; public: HWoWFilesCacheStorage cacheStorage = nullptr; + HRequestProcessor requestProcessor = nullptr; HGDevice hDevice = nullptr; std::shared_ptr databaseHandler = nullptr; std::shared_ptr camera = nullptr; diff --git a/wowViewerLib/src/engine/WowFilesCacheStorage.cpp b/wowViewerLib/src/engine/WowFilesCacheStorage.cpp index 25fd2b447..053f3f630 100644 --- a/wowViewerLib/src/engine/WowFilesCacheStorage.cpp +++ b/wowViewerLib/src/engine/WowFilesCacheStorage.cpp @@ -4,61 +4,6 @@ #include "WowFilesCacheStorage.h" -void WoWFilesCacheStorage::provideFile(CacheHolderType holderType, const char *fileName, const HFileContent &data) { -// std::cout << "data.use_count() = " << data.use_count() << std::endl << std::flush; - std::string s_fileName(fileName); - - switch (holderType) { - case CacheHolderType::CACHE_M2: - m2GeomCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_SKIN: - skinGeomCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_MAIN_WMO: - wmoMainCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_GROUP_WMO: - wmoGeomCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_ADT: - adtObjectCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_WDT: - wdtCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_WDL: - wdlCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_BLP: - textureCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_ANIM: - animCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_SKEL: - skelCache.provideFile(s_fileName, data); - break; - case CacheHolderType::CACHE_DB2: - db2Cache.provideFile(s_fileName, data); - break; - } -} - -void WoWFilesCacheStorage::processCaches(int limit) { - this->adtObjectCache.processCacheQueue(limit); - this->wdtCache.processCacheQueue(limit); - this->wdlCache.processCacheQueue(limit); - this->wmoGeomCache.processCacheQueue(limit); - this->wmoMainCache.processCacheQueue(limit); - this->skinGeomCache.processCacheQueue(limit); - this->animCache.processCacheQueue(limit); - this->skelCache.processCacheQueue(limit); - this->m2GeomCache.processCacheQueue(limit); - this->textureCache.processCacheQueue(limit); - this->db2Cache.processCacheQueue(limit); -} - void WoWFilesCacheStorage::rejectFile(CacheHolderType holderType, const char* fileName) { std::string s_fileName(fileName); diff --git a/wowViewerLib/src/engine/WowFilesCacheStorage.h b/wowViewerLib/src/engine/WowFilesCacheStorage.h index 0808fc60e..58dc9d61b 100644 --- a/wowViewerLib/src/engine/WowFilesCacheStorage.h +++ b/wowViewerLib/src/engine/WowFilesCacheStorage.h @@ -41,13 +41,10 @@ class WoWFilesCacheStorage : public IFileRequester { Cache db2Cache; public: WoWFilesCacheStorage(IFileRequest * requestProcessor); - void provideFile(CacheHolderType holderType, const char *fileName, const HFileContent &data) ; void rejectFile(CacheHolderType holderType, const char* fileName) override ; void actuallDropCache(); - void processCaches(int limit); - Cache *getAdtGeomCache(); Cache *getM2GeomCache(); Cache* getSkinGeomCache(); diff --git a/wowViewerLib/src/engine/cache/cache.h b/wowViewerLib/src/engine/cache/cache.h index 2dff22464..8be8b8645 100644 --- a/wowViewerLib/src/engine/cache/cache.h +++ b/wowViewerLib/src/engine/cache/cache.h @@ -34,70 +34,12 @@ class Cache { public: std::mutex cacheMapMutex; std::mutex getFileMutex; - std::mutex objectsToBeProcessedMutex; std::unordered_map> m_cache; std::unordered_map> m_cacheFdid; - std::forward_list m_objectsToBeProcessed; public: Cache(IFileRequest *fileRequestProcessor, CacheHolderType holderType) : m_fileRequestProcessor(fileRequestProcessor), holderType(holderType){ } - void processCacheQueue(int limit) { - int objectsProcessed = 0; - - auto const &m_cache_const = m_cache; - while (!m_objectsToBeProcessed.empty()) - { - std::unique_lock lck (objectsToBeProcessedMutex,std::defer_lock); - std::unique_lock cacheLck (cacheMapMutex,std::defer_lock); - - lck.lock(); - auto const it = m_objectsToBeProcessed.front(); - m_objectsToBeProcessed.pop_front(); - lck.unlock(); - - - cacheLck.lock(); - std::weak_ptr weakPtr = m_cache_const.at(it.fileName); - cacheLck.unlock(); - -// std::cout << "Processing file " << it.fileName << std::endl << std::flush; - if (!weakPtr.expired()) { - std::shared_ptr sharedPtr = weakPtr.lock(); - if (sharedPtr->getStatus() == FileStatus::FSLoaded) { - std::cout << "sharedPtr->getStatus == FileStatus::FSLoaded" << std::endl; - } else { - sharedPtr->process(it.fileContent, it.fileName); - } - } -// std::cout << "Processed file " << it.fileName << std::endl << std::flush; - - objectsProcessed++; - if (objectsProcessed > limit) { - break; - } - } - - } - void provideFile(std::string &fileName, HFileContent fileContent) { - trim(fileName); -// std::cout << "called provideFile with fileName = " << fileName << std::endl; -// std::cout << "m_cache.size() == " << m_cache.size() << " " << __PRETTY_FUNCTION__ << std::endl; - -// std::cout << "filename:" << fileName << " hex: " << string_to_hex(fileName) << std::endl; -// std::cout << "first in storage:" << m_cache.begin()->first << " hex: " << string_to_hex(m_cache.begin()->first) << std::endl << std::flush; - auto const &m_cache_const = m_cache; - - std::unique_lock cacheLck(cacheMapMutex, std::defer_lock); - cacheLck.lock(); - auto it = m_cache_const.find(fileName); - bool found = it != m_cache_const.end(); - cacheLck.unlock(); - if (found) { - std::lock_guard guard(objectsToBeProcessedMutex); - m_objectsToBeProcessed.push_front({fileName, fileContent}); - } - } /* * Queue load functions @@ -192,11 +134,6 @@ class Cache { cacheLck.lock(); m_cache.clear(); cacheLck.unlock(); - - std::unique_lock lck(objectsToBeProcessedMutex, std::defer_lock); - lck.lock(); - m_objectsToBeProcessed.clear(); - lck.unlock(); } private: /* diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 372773669..9d9e26d54 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -106,8 +106,8 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { /* Calc look at position */ - dir = mathfu::mat3::RotationY((float) (-this->av * M_PI / 180.0f)) * dir; - dir = mathfu::mat3::RotationZ((float) (this->ah * M_PI / 180.0f)) * dir; + dir = mathfu::mat3::RotationY((float) (this->av * M_PI / 180.0f)) * dir; + dir = mathfu::mat3::RotationZ((float) (-this->ah * M_PI / 180.0f)) * dir; dir = mathfu::normalize(dir); @@ -129,7 +129,7 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { mathfu::vec3 movDir = mathfu::vec3(dir); movDir = movDir * depthDiff; - camera = camera - movDir; + camera = camera + movDir; } if (verticalDiff != 0) { camera[2] = camera[2] + verticalDiff; @@ -138,9 +138,9 @@ void FirstPersonCamera::tick (animTime_t timeDelta) { this->lookAt = camera + dir; lookAtMat = mathfu::mat4( - right_move.x, up.x, dir.x, 0.0f, - right_move.y, up.y, dir.y, 0.0f, - right_move.z, up.z, dir.z, 0.0f, + right_move.x, up.x, -dir.x, 0.0f, + right_move.y, up.y, -dir.y, 0.0f, + right_move.z, up.z, -dir.z, 0.0f, 0,0,0,1.0f //translation ); lookAtMat *= mathfu::mat4::FromTranslationVector(-camera) ; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 7163ad2df..15942474e 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -225,11 +225,6 @@ void WmoGroupGeom::process(HFileContent wmoGroupFile, const std::string &fileNam CChunkFileReader reader(*m_wmoGroupFile.get()); reader.processFile(*this, &WmoGroupGeom::wmoGroupTable); - fixColorVertexAlpha(mohd); - if (!mohd->flags.flag_attenuate_vertices_based_on_distance_to_portal) { - this->m_attenuateFunc(*this); - } - fsStatus = FileStatus::FSLoaded; } @@ -385,9 +380,15 @@ HGIndexBuffer WmoGroupGeom::getIBO(const HMapSceneBufferCreate &sceneRenderer) { return indexVBO; } -HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient) { +HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, mathfu::vec4 localAmbient) { if (vertexBufferBindings == nullptr) { - + //Do postLoading stuff here + if (mohd) { + fixColorVertexAlpha(mohd); + if (!mohd->flags.flag_attenuate_vertices_based_on_distance_to_portal) { + this->m_attenuateFunc(*this); + } + } vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer), localAmbient); } diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index 64e64850f..0bbe42f3c 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -38,12 +38,10 @@ class WmoGroupGeom : public PersistentFile { static chunkDef wmoGroupTable; - void setMOHD(SMOHeader *mohd) {this->mohd = mohd; }; void setAttenuateFunction(std::function attenuateFunc) {this->m_attenuateFunc = attenuateFunc; }; bool hasWater() const {return m_mliq != nullptr; }; - - HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, mathfu::vec4 localAmbient); + HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, mathfu::vec4 localAmbient); HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type, CAaBox &waterAaBB); int getFileDataId() const {return m_fileDataId;} @@ -60,8 +58,6 @@ class WmoGroupGeom : public PersistentFile { HFileContent m_wmoGroupFile; - SMOHeader *mohd = nullptr; - MOGP *mogp = nullptr; PointerChecker indicies = PointerChecker(indicesLen); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 050b1205c..6a1ceb8ad 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -564,9 +564,16 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams // } } -mathfu::vec3 blendV3(mathfu::vec3 a, mathfu::vec3 b, float alpha) { - return (a - b) * alpha + a; +static inline mathfu::vec4 mix(const mathfu::vec4 &a, const mathfu::vec4 &b, float alpha) { + return (b - a) * alpha + a; } +static inline mathfu::vec3 mix(const mathfu::vec3 &a, const mathfu::vec3 &b, float alpha) { + return (b - a) * alpha + a; +} +static inline float mix(const float &a, const float &b, float alpha) { + return (b - a) * alpha + a; +} + void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) { @@ -662,24 +669,24 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp float currentGlow = 0; for (auto &_light : lightResults) { - currentGlow += _light.glow * _light.blendCoef; - - ambientColor += mathfu::vec3(_light.ambientColor) * _light.blendCoef; - horizontAmbientColor += mathfu::vec3(_light.horizontAmbientColor) * _light.blendCoef; - groundAmbientColor += mathfu::vec3(_light.groundAmbientColor) * _light.blendCoef; - directColor += mathfu::vec3(_light.directColor) * _light.blendCoef; - - closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; - farRiverColor += mathfu::vec3(_light.farRiverColor) * _light.blendCoef; - closeOceanColor += mathfu::vec3(_light.closeOceanColor) * _light.blendCoef; - farOceanColor += mathfu::vec3(_light.farOceanColor) * _light.blendCoef; - - SkyTopColor += mathfu::vec3(_light.SkyTopColor.data()) * _light.blendCoef; - SkyMiddleColor += mathfu::vec3(_light.SkyMiddleColor) * _light.blendCoef; - SkyBand1Color += mathfu::vec3(_light.SkyBand1Color) * _light.blendCoef; - SkyBand2Color += mathfu::vec3(_light.SkyBand2Color) * _light.blendCoef; - SkySmogColor += mathfu::vec3(_light.SkySmogColor) * _light.blendCoef; - SkyFogColor += mathfu::vec3(_light.SkyFogColor.data()) * _light.blendCoef; + currentGlow = mix(currentGlow, _light.glow, _light.blendCoef); + + ambientColor = mix(ambientColor, mathfu::vec3(_light.ambientColor), _light.blendCoef); + horizontAmbientColor = mix(horizontAmbientColor, mathfu::vec3(_light.horizontAmbientColor), _light.blendCoef); + groundAmbientColor = mix(groundAmbientColor, mathfu::vec3(_light.groundAmbientColor), _light.blendCoef); + directColor = mix(directColor, mathfu::vec3(_light.directColor), _light.blendCoef); + + closeRiverColor = mix(closeRiverColor, mathfu::vec3(_light.closeRiverColor), _light.blendCoef); + farRiverColor = mix(farRiverColor, mathfu::vec3(_light.farRiverColor), _light.blendCoef); + closeOceanColor = mix(closeOceanColor, mathfu::vec3(_light.closeOceanColor), _light.blendCoef); + farOceanColor = mix(farOceanColor, mathfu::vec3(_light.farOceanColor), _light.blendCoef); + + SkyTopColor = mix(SkyTopColor, mathfu::vec3(_light.SkyTopColor.data()), _light.blendCoef); + SkyMiddleColor = mix(SkyMiddleColor, mathfu::vec3(_light.SkyMiddleColor), _light.blendCoef); + SkyBand1Color = mix(SkyBand1Color, mathfu::vec3(_light.SkyBand1Color), _light.blendCoef); + SkyBand2Color = mix(SkyBand2Color, mathfu::vec3(_light.SkyBand2Color), _light.blendCoef); + SkySmogColor = mix(SkySmogColor, mathfu::vec3(_light.SkySmogColor), _light.blendCoef); + SkyFogColor = mix(SkyFogColor, mathfu::vec3(_light.SkyFogColor.data()), _light.blendCoef); } //Database is in BGRA @@ -903,47 +910,50 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp // std::cout << "combinedResults.empty() = " << combinedResults.empty() << std::endl; // std::cout << "combinedResults.size() = " << combinedResults.size() << std::endl; fdd->EndFogColor = mathfu::vec3(0.0f, 0, 0); + auto &fogResult = fdd->fogResults.emplace_back(); for (auto &_light : lightResults) { - auto &fogResult = fdd->fogResults.emplace_back(); - fogResult.FogEnd = _light.FogEnd; - fogResult.FogScaler = _light.FogScaler; - fogResult.FogDensity = _light.FogDensity; - fogResult.FogHeight = _light.FogHeight; - fogResult.FogHeightScaler = _light.FogHeightScaler; - fogResult.FogHeightDensity = _light.FogHeightDensity; - fogResult.SunFogAngle = _light.SunFogAngle; + fogResult.FogEnd = mix(fogResult.FogEnd, _light.FogEnd, _light.blendCoef); + fogResult.FogScaler = mix(fogResult.FogScaler, _light.FogScaler, _light.blendCoef); + fogResult.FogDensity = mix(fogResult.FogDensity, _light.FogDensity, _light.blendCoef); + fogResult.FogHeight = mix(fogResult.FogHeight, _light.FogHeight, _light.blendCoef); + fogResult.FogHeightScaler = mix(fogResult.FogHeightScaler, _light.FogHeightScaler, _light.blendCoef); + fogResult.FogHeightDensity = mix(fogResult.FogHeightDensity, _light.FogHeightDensity, _light.blendCoef); + fogResult.SunFogAngle = mix(fogResult.SunFogAngle, _light.SunFogAngle, _light.blendCoef); if (fdd->overrideValuesWithFinalFog) { - fogResult.FogColor = mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]); + fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); } else { - fogResult.FogColor = mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]); + fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]), _light.blendCoef); } - fogResult.EndFogColor = mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]); - fdd->EndFogColor += fogResult.EndFogColor * _light.blendCoef; - fogResult.EndFogColorDistance = _light.EndFogColorDistance; - fogResult.SunFogColor = mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]); - fogResult.SunFogStrength = _light.SunFogStrength; - fogResult.FogHeightColor = mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]); - fogResult.FogHeightCoefficients = mathfu::vec4(_light.FogHeightCoefficients[0], _light.FogHeightCoefficients[1], - _light.FogHeightCoefficients[2], _light.FogHeightCoefficients[3]); - fogResult.MainFogCoefficients = mathfu::vec4(_light.MainFogCoefficients[0], _light.MainFogCoefficients[1], - _light.MainFogCoefficients[2], _light.MainFogCoefficients[3]); - fogResult.HeightDensityFogCoefficients = mathfu::vec4(_light.HeightDensityFogCoefficients[0], - _light.HeightDensityFogCoefficients[1], - _light.HeightDensityFogCoefficients[2], - _light.HeightDensityFogCoefficients[3]); - - fogResult.FogZScalar = _light.FogZScalar; - fogResult.LegacyFogScalar = _light.LegacyFogScalar; - fogResult.MainFogStartDist = _light.MainFogStartDist; - fogResult.MainFogEndDist = _light.MainFogEndDist; - fogResult.FogBlendAlpha = _light.blendCoef; - fogResult.HeightEndFogColor = mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]); - fogResult.FogStartOffset = _light.FogStartOffset; + fogResult.EndFogColor = mix(fogResult.EndFogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); + fogResult.EndFogColorDistance = mix(fogResult.EndFogColorDistance, _light.EndFogColorDistance, _light.blendCoef); + fogResult.SunFogColor = mix(fogResult.SunFogColor, mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]), _light.blendCoef); + fogResult.SunFogStrength = mix(fogResult.SunFogStrength, _light.SunFogStrength, _light.blendCoef); + fogResult.FogHeightColor = mix(fogResult.FogHeightColor, mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]), _light.blendCoef); + fogResult.FogHeightCoefficients = mix( + fogResult.FogHeightCoefficients, + mathfu::vec4(_light.FogHeightCoefficients[3], _light.FogHeightCoefficients[2], + _light.FogHeightCoefficients[1], _light.FogHeightCoefficients[0]), _light.blendCoef); + fogResult.MainFogCoefficients = mix( + fogResult.MainFogCoefficients, + mathfu::vec4(_light.MainFogCoefficients[3], _light.MainFogCoefficients[2], + _light.MainFogCoefficients[1], _light.MainFogCoefficients[0]), _light.blendCoef); + fogResult.HeightDensityFogCoefficients = mix( + fogResult.HeightDensityFogCoefficients, + mathfu::vec4(_light.HeightDensityFogCoefficients[3], + _light.HeightDensityFogCoefficients[2], + _light.HeightDensityFogCoefficients[1], + _light.HeightDensityFogCoefficients[0]), _light.blendCoef); + + fogResult.FogZScalar = mix(fogResult.FogZScalar, _light.FogZScalar, _light.blendCoef); + fogResult.LegacyFogScalar = mix(fogResult.LegacyFogScalar, _light.LegacyFogScalar, _light.blendCoef); + fogResult.MainFogStartDist = mix(fogResult.MainFogStartDist, _light.MainFogStartDist, _light.blendCoef); + fogResult.MainFogEndDist = mix(fogResult.MainFogEndDist, _light.MainFogEndDist, _light.blendCoef); + fogResult.FogBlendAlpha = mix(fogResult.FogBlendAlpha, _light.blendCoef, _light.blendCoef); + fogResult.HeightEndFogColor = mix(fogResult.HeightEndFogColor, mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]), _light.blendCoef); + fogResult.FogStartOffset = mix(fogResult.FogStartOffset, _light.FogStartOffset, _light.blendCoef); } } } - -// this->m_api->getConfig()->setClearColor(0,0,0,0); } void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) { @@ -1355,15 +1365,21 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende int wmoProcessedThisFrame = 0; int wmoGroupsProcessedThisFrame = 0; - for (auto &m2Object : renderPlan->m2Array.getToLoadMain()) { - if (m2Object == nullptr) continue; - m2Object->doLoadMainFile(); + { + ZoneScopedN("Load m2 main"); + for (auto &m2Object: renderPlan->m2Array.getToLoadMain()) { + if (m2Object == nullptr) continue; + m2Object->doLoadMainFile(); + } } - for (auto &m2Object : renderPlan->m2Array.getToLoadGeom()) { - if (m2Object == nullptr) continue; - m2Object->doLoadGeom(sceneRenderer); - m2ProcessedThisFrame++; + { + ZoneScopedN("Load m2 geom"); + for (auto &m2Object: renderPlan->m2Array.getToLoadGeom()) { + if (m2Object == nullptr) continue; + m2Object->doLoadGeom(sceneRenderer); + m2ProcessedThisFrame++; // if (m2ProcessedThisFrame > 100) break; + } } if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { @@ -1378,19 +1394,28 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende } // } - for (auto &wmoObject : renderPlan->wmoArray.getToLoad()) { - if (wmoObject == nullptr) continue; - wmoObject->doPostLoad(sceneRenderer); + { + ZoneScopedN("Load wmoObject"); + for (auto &wmoObject: renderPlan->wmoArray.getToLoad()) { + if (wmoObject == nullptr) continue; + wmoObject->doPostLoad(sceneRenderer); + } } - for (auto &wmoGroupObject : renderPlan->wmoGroupArray.getToLoad()) { - if (wmoGroupObject == nullptr) continue; - wmoGroupObject->doPostLoad(sceneRenderer); - wmoGroupsProcessedThisFrame++; - if (wmoGroupsProcessedThisFrame > 20) break; + { + ZoneScopedN("Load wmo group"); + for (auto &wmoGroupObject: renderPlan->wmoGroupArray.getToLoad()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->doPostLoad(sceneRenderer); + wmoGroupsProcessedThisFrame++; + if (wmoGroupsProcessedThisFrame > 20) break; + } } - for (auto &adtObject : renderPlan->adtArray) { - adtObject->adtObject->doPostLoad(sceneRenderer); + { + ZoneScopedN("Load adt"); + for (auto &adtObject: renderPlan->adtArray) { + adtObject->adtObject->doPostLoad(sceneRenderer); + } } if (quadBindings == nullptr) diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 1b8b2d170..7c522b780 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -101,7 +101,7 @@ void WmoGroupObject::startLoading() { } else { m_geom = m_api->cacheStorage->getWmoGroupGeomCache()->get(m_fileName); } - m_geom->setMOHD(this->m_wmoApi->getWmoHeader()); + m_geom->setAttenuateFunction(this->m_wmoApi->getAttenFunction()); } } @@ -130,7 +130,8 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer, mathfu::vec4( + HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer, this->m_wmoApi->getWmoHeader(), + mathfu::vec4( this->getAmbientColor().xyz(), ((this->m_geom->mogp->flags.INTERIOR > 0) && (!this->m_geom->mogp->flags.EXTERIOR_LIT)) ? 1.0f : 0.0f )); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 3138a2c35..a6775d69b 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1261,7 +1261,7 @@ void WmoObject::checkFog(mathfu::vec3 &cameraPos, std::vector &fogR 1.0f); wmoFog.isDefault = false; } - std::array fogColor = {fogRecord.fog.color.b/255.0f, fogRecord.fog.color.g/255.0f, fogRecord.fog.color.r/255.0f}; + std::array fogColor = {fogRecord.fog.color.r/255.0f, fogRecord.fog.color.g/255.0f, fogRecord.fog.color.b/255.0f}; wmoFog.EndFogColor = fogColor; wmoFog.SunFogColor = fogColor; wmoFog.FogHeightColor = fogColor; diff --git a/wowViewerLib/src/gapi/interface/materials/IMaterial.h b/wowViewerLib/src/gapi/interface/materials/IMaterial.h index c74852fc1..9fb9a4005 100644 --- a/wowViewerLib/src/gapi/interface/materials/IMaterial.h +++ b/wowViewerLib/src/gapi/interface/materials/IMaterial.h @@ -12,7 +12,7 @@ struct PipelineTemplate { DrawElementMode element; bool backFaceCulling = true; - bool triCCW = false; //counter-clockwise + bool triCCW = true; //counter-clockwise EGxBlendEnum blendMode; bool depthCulling = true; bool depthWrite = true; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 297e2fb9a..936a99fb1 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -776,14 +776,14 @@ void GDeviceVLK::createCommandPoolForUpload(){ void GDeviceVLK::createCommandBuffers() { for (auto & commandBuffer : fbCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily.value()); + commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true, indices.graphicsFamily.value()); } for (auto & commandBuffer : swapChainCommandBuffers) { - commandBuffer = std::make_shared(*this, commandPool, true, indices.graphicsFamily.value()); + commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true, indices.graphicsFamily.value()); } for (auto & commandBuffer : uploadCommandBuffers) { - commandBuffer = std::make_shared(*this, uploadCommandPool, true, indices.transferFamily.value()); + commandBuffer = std::make_shared(*this, uploadQueue, uploadCommandPool, true, indices.transferFamily.value()); } } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index a2232e364..3f7b89c2d 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -165,7 +165,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback) = 0; virtual VkDescriptorSet allocateDescriptorSetPrimitive( const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &out_desciptorPool) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index c23df65d2..8be926295 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -4,13 +4,16 @@ #include "CommandBuffer.h" + GCommandBuffer::GCommandBuffer(IDeviceVulkan &deviceVlk, + VkQueue vkQueue, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex) : m_device(deviceVlk), m_isPrimary(isPrimary), m_queueFamilyIndex(queueFamilyIndex), - m_commandPool(commandPool) + m_commandPool(commandPool), + m_vkQueue(vkQueue) { } @@ -31,11 +34,19 @@ void GCommandBuffer::createCommandBufVLK() { if (m_cmdBufWasCreated) { //Dispose of previous buffer auto l_cmdBuf = m_cmdBuffer; + auto l_deviceVlk = m_device.getVkDevice(); auto l_commandPool = m_commandPool; - m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_commandPool]() -> void { + auto l_tracyContext = tracyContext; + + m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_tracyContext, l_commandPool]() -> void { +#ifdef LINK_TRACY + TracyVkCollect(l_tracyContext, l_cmdBuf); +#endif vkFreeCommandBuffers(l_deviceVlk, l_commandPool, 1, &l_cmdBuf); }); + + } VkCommandBufferAllocateInfo allocInfo = {}; @@ -48,5 +59,10 @@ void GCommandBuffer::createCommandBufVLK() { throw std::runtime_error("failed to allocate command buffers!"); } + if (!m_cmdBufWasCreated) { +#ifdef LINK_TRACY + tracyContext = TracyVkContext(m_device.getVkPhysicalDevice(), m_device.getVkDevice(), m_vkQueue, m_cmdBuffer); +#endif LINK_TRACY + } m_cmdBufWasCreated = true; } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index 23f040658..49bfdcf9d 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -10,6 +10,7 @@ #include "../GDeviceVulkan.h" #include "../GFrameBufferVLK.h" #include "commandBufferRecorder/CommandBufferRecorder.h" +#include "../../../renderer/frame/FrameProfile.h" class GCommandBuffer { public: @@ -19,7 +20,7 @@ class GCommandBuffer { friend class IDeviceVulkan; public: - GCommandBuffer(IDeviceVulkan &deviceVlk, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); + GCommandBuffer(IDeviceVulkan &deviceVlk, VkQueue vkQueue, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); VkCommandBuffer getNativeCmdBuffer() const { @@ -31,12 +32,17 @@ class GCommandBuffer { private: IDeviceVulkan &m_device; VkCommandBuffer m_cmdBuffer; + VkQueue m_vkQueue; bool m_isPrimary = true; const uint32_t m_queueFamilyIndex; VkCommandPool m_commandPool; bool m_cmdBufWasCreated = false; bool m_hasData = false; + +#ifdef LINK_TRACY + TracyVkCtx tracyContext; +#endif }; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index a246de4c0..35e689b55 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -300,3 +300,8 @@ void CmdBufRecorder::createDefaultScissors(const std::array &areaOff static_cast(areaSize[1]) }; } + +#ifdef LINK_TRACY +VkCommandBuffer CmdBufRecorder::getNativeCmdBuffer() { return m_gCmdBuffer.getNativeCmdBuffer(); } +TracyVkCtx const &CmdBufRecorder::getTracyContext() { return m_gCmdBuffer.tracyContext; } +#endif diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index eaa33757b..0453d854d 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -8,6 +8,7 @@ #include #include "../../GRenderPassVLK.h" #include "../../GFrameBufferVLK.h" +#include "../../../../renderer/frame/FrameProfile.h" @@ -20,6 +21,11 @@ class CommandBufferDebugLabel; #include "RenderPassHelper.h" #include "CommandBufferDebugLabel.h" #include "../../descriptorSets/GDescriptorSet.h" + +#ifdef LINK_TRACY +#define VkZone(buffRecorder,a) TracyVkZone(buffRecorder.getTracyContext(), buffRecorder.getNativeCmdBuffer(), a) +#endif + class CmdBufRecorder { public: enum class ViewportType: int {vp_none = -1, vp_usual = 0, vp_mapArea = 1, vp_skyBox = 2, vp_MAX = 3}; @@ -60,6 +66,12 @@ class CmdBufRecorder { friend class RenderPassHelper; void setViewPort(ViewportType viewportType); + +#ifdef LINK_TRACY + //Those should only be used for initialization of tracy zone + TracyVkCtx const &getTracyContext();; + VkCommandBuffer getNativeCmdBuffer();; +#endif private: const GCommandBuffer &m_gCmdBuffer; diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 63e643c94..1526ee457 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -90,6 +90,8 @@ class Config { float farPlane = 1000; float farPlaneForCulling = 400; + float fogDensityIncreaser = 0; + bool disableGlow = false; bool pauseAnimation = false; @@ -156,7 +158,6 @@ class Config { //Stuff to display in UI - double cullingTimePerFrame = 0; double composerDrawTimePerFrame = 0; double consumeDraw = 0; double consumeUpdate = 0; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 0098f77fa..623ae51ae 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -3,6 +3,8 @@ // #include +#include +#include #ifndef AWEBWOWVIEWERCPP_DBSTRUCTS_H #define AWEBWOWVIEWERCPP_DBSTRUCTS_H diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h index 25d230fa4..78a6e2eae 100644 --- a/wowViewerLib/src/renderer/frame/FrameProfile.h +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -7,7 +7,12 @@ #ifdef LINK_TRACY #include "Tracy.hpp" -//#include "tracy/TracyVulkan.hpp" + +#ifdef LINK_VULKAN + #include "../../gapi/vulkan/context/vulkan_context.h" + #include "tracy/TracyVulkan.hpp" +#endif + #define setThreadName(a) tracy::SetThreadName(a); #else #define setThreadName(a) diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 78edf94e1..d1fbc8e78 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -11,14 +11,6 @@ #include #endif - - -void SceneComposer::processCaches(int limit) { - if (m_apiContainer->cacheStorage) { - m_apiContainer->cacheStorage->processCaches(limit); - } -} - SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiContainer) { #ifdef __EMSCRIPTEN__ m_supportThreads = false; @@ -29,16 +21,26 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon loadingResourcesThread = std::thread([&]() { setThreadName("ResourceLoader"); using namespace std::chrono_literals; + + HRequestProcessor currentProcessor = nullptr; + while (!this->m_isTerminating) { - std::this_thread::sleep_for(1ms); - processCaches(1000); + if (currentProcessor != m_apiContainer->requestProcessor) { + currentProcessor = m_apiContainer->requestProcessor; + if (currentProcessor != nullptr) + currentProcessor->initThreadQueue(this->m_isTerminating); + } + + if (currentProcessor != nullptr) { + m_apiContainer->requestProcessor->processRequests(INT_MAX); + } else { + std::this_thread::sleep_for(1ms); + } } }); - cullingThread = std::thread(([&]() { using namespace std::chrono_literals; - FrameCounter frameCounter; setThreadName("Culling"); while (!this->m_isTerminating) { @@ -46,9 +48,6 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon if (m_isTerminating) continue; - - frameCounter.beginMeasurement(); - //Do the culling and make function for further pipeline if (frameScenario != nullptr) { consumeCulling(frameScenario); @@ -56,9 +55,6 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon //Pass the culling result down the pipeline updateInput.pushInput(frameScenario); - - frameCounter.endMeasurement(); - m_apiContainer->getConfig()->cullingTimePerFrame = frameCounter.getTimePerFrame(); } })); @@ -142,9 +138,9 @@ void SceneComposer::draw(HFrameScenario frameScenario) { composerDrawTimePerFrame.beginMeasurement(); if (!m_supportThreads) { - processCaches(10); consumeCulling(frameScenario); std::vector> renderFuncs = {}; + m_apiContainer->requestProcessor->processRequests(10); consumeUpdate(frameScenario,renderFuncs); consumeDraw(renderFuncs); diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 3c92975f5..46317cb06 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -34,7 +34,6 @@ class SceneComposer { void consumeCulling(HFrameScenario &frameScenario); void consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions); void consumeDraw(const std::vector> &renderFuncs); - void processCaches(int limit); //Flip-flop delta promises int frameMod = 0; diff --git a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h index 9726693e7..8a5c19d28 100644 --- a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h +++ b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h @@ -8,13 +8,14 @@ #include #include #include +#include +#include "../FrameProfile.h" template class ProdConsumerIOConnector { public: typedef T value_type; - ProdConsumerIOConnector(bool &terminating) : m_terminating(terminating) { } @@ -36,7 +37,36 @@ class ProdConsumerIOConnector { lock.unlock(); return std::move(result); - } + }; + + void blockProcessWithoutWait(int limit, const std::function &callback) { + ZoneScoped; + int processed; + while ((processed < limit) && (!m_queue.empty())) { + auto result = std::move(m_queue.front()); + m_queue.pop(); + callback(result); + processed++; + } + }; + + void waitAndProcess(const std::function &callback) { + std::unique_lock lock{m_queueMutex}; + auto &l_queue = m_queue; + auto &l_terminated = this->m_terminating; + { + using namespace std::chrono_literals; + m_condVar.wait_for(lock, 20ms, [&l_queue, &l_terminated]() + { + return !l_queue.empty() || l_terminated; + }); + } + + blockProcessWithoutWait(INT_MAX, callback); + lock.unlock(); + }; + + bool empty() {return m_queue.empty(); } void pushInput(const T &newInput) { { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 29839d96e..b744b4960 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -154,9 +154,10 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrfogDensityIncreaser); float fogScaler = fogResult.FogScaler; if (fogScaler <= 0.00000001f) fogScaler = 0.5f; float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; @@ -168,13 +169,15 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrSunFogAngle * fdd->SunFogStrength, + fogResult.SunFogAngle * fogResult.SunFogStrength, 0, 1.0, 1.0); blockPSVS.fogData[i].sunDirection_and_fogZScalar = mathfu::vec4( fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 94380cc96..92095bfd7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -660,6 +660,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // --------------------- { ZoneScopedN("submit buffers"); + VkZone(uploadCmd, "submit buffers") uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -696,6 +697,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") for (auto const &mesh: *opaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } @@ -725,6 +727,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } { + VkZone(frameBufCmd, "render transparent") ZoneScopedN("submit transparent"); for (int i = 0; i < transparentMeshes->size(); i++) { auto const &mesh = transparentMeshes->at(i); @@ -743,9 +746,13 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } } - l_this->glowPass->doPass(frameBufCmd, swapChainCmd, - l_this->m_device->getSwapChainRenderPass(), - frameInputParams->viewPortDimensions); + { +// VkZone(frameBufCmd, "glowPassFrameBuf"); +// VkZone(swapChainCmd, "glowPassSwapBuf"); + l_this->glowPass->doPass(frameBufCmd, swapChainCmd, + l_this->m_device->getSwapChainRenderPass(), + frameInputParams->viewPortDimensions); + } }); } From d7d2e21ff06e107be1f57ec88aa474058b1ceed4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 6 Sep 2023 03:03:35 +0300 Subject: [PATCH 103/212] - stupid error in fog --- src/database/CSqliteDB.cpp | 2 +- wowViewerLib/CMakeLists.txt | 4 ++++ wowViewerLib/shaders/CMakeLists.txt | 3 ++- wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 2042ff19e..fc380d8a0 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -719,7 +719,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector currLdRes.FogScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); currLdRes.FogEnd = std::max(currLdRes.FogEnd, 10.0f); currLdRes.FogHeight = std::max(currLdRes.FogHeight, -10000.0f); - currLdRes.FogHeightScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); + currLdRes.FogHeightScaler = std::clamp(currLdRes.FogHeightScaler, -1.0f, 1.0f); if (!currLdRes.SunFogColor) currLdRes.SunFogAngle = 1.0f; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index f5add3575..20e2d5a03 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -16,6 +16,10 @@ set(LINK_OPENMP 0) set(ENABLE_SIMD 1) set(LINK_TRACY 1) set(COMPILE_SHADER_WITH_DEBUG 1) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(COMPILE_SHADER_WITH_DEBUG 1) +endif () + option(EMSCRIPTEN_SIMD "Enable SIMD for Emscripten " OFF) diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 3ba1fa4ee..d593308e9 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -8,6 +8,7 @@ endif() if (COMPILE_SHADER_WITH_DEBUG) set(SHADER_DEBUG_FLAG "-g") set(APP_RUN_PREFIX "") + set (SPIRV_OPT_APP "") else() set(SHADER_DEBUG_FLAG "") endif() @@ -72,7 +73,7 @@ else() add_custom_target(spirv_reflection) endif() -set (SPIRV_OPT_APP "") + macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring directory ${destDir}") diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index b744b4960..522231943 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -169,7 +169,9 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr Date: Fri, 8 Sep 2023 18:41:36 +0300 Subject: [PATCH 104/212] - update casc lib - lighting works - more data is shown in UI --- 3rdparty/casclib | 2 +- src/database/CSqliteDB.cpp | 40 +- src/database/CSqliteDB.h | 1 + src/minimapGenerator/minimapGenerator.cpp | 8 +- src/ui/FrontendUI.cpp | 601 +++++++++--------- src/ui/FrontendUI.h | 5 - .../MinimapGenerationWindow.cpp | 8 +- wowViewerLib/CMakeLists.txt | 2 +- .../glsl/common/commonFogFunctions.glsl | 6 +- .../managers/particles/particleEmitter.cpp | 3 +- .../src/engine/objects/scenes/m2Scene.cpp | 8 +- .../src/engine/objects/scenes/map.cpp | 203 ++---- wowViewerLib/src/engine/objects/scenes/map.h | 24 - .../src/engine/objects/scenes/wmoScene.cpp | 8 +- wowViewerLib/src/include/config.h | 82 +-- wowViewerLib/src/include/database/dbStructs.h | 14 +- .../src/renderer/frame/SceneComposer.cpp | 11 - .../src/renderer/frame/SceneComposer.h | 4 - .../renderer/mapScene/FrameDependentData.h | 84 +-- .../renderer/mapScene/MapSceneRenderer.cpp | 30 +- .../src/renderer/mapScene/MapSceneRenderer.h | 8 - 21 files changed, 465 insertions(+), 687 deletions(-) diff --git a/3rdparty/casclib b/3rdparty/casclib index 136c6e055..5c6005077 160000 --- a/3rdparty/casclib +++ b/3rdparty/casclib @@ -1 +1 @@ -Subproject commit 136c6e05537bd7123620ddb28671d1f2cf060e0b +Subproject commit 5c60050770767f2e606f6fec0c35beb8b9b00c60 diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index fc380d8a0..8a9e5d18c 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -72,7 +72,7 @@ const std::string getLightByIdSQL = R"===( const std::string getLightSQL = R"===( select - l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, l.LightParamsID_0, + l.id as LightId, l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, l.LightParamsID_0, IFNULL(ls.SkyboxFileDataID, 0) as SkyboxFileDataID, IFNULL(lp.LightSkyboxID, 0) as LightSkyboxID, lp.Glow, IFNULL(ls.Flags, 0) as SkyboxFlags, l.ContinentID, (abs(l.GameCoords_0 - ?1) * abs(l.GameCoords_0 - ?1) + @@ -281,24 +281,24 @@ void initWithZeros(std::array &colorF) { colorF[3] = 0; } void blendTwoAndAdd(float *colorF, int currLdRes, int lastLdRes, float timeAlphaBlend) { - colorF[0] += (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + + colorF[0] = (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + getFloatFromInt<0>(lastLdRes) * (1.0f - timeAlphaBlend)); - colorF[1] += (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + + colorF[1] = (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + getFloatFromInt<1>(lastLdRes) * (1.0f - timeAlphaBlend)); - colorF[2] += (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + + colorF[2] = (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + getFloatFromInt<2>(lastLdRes) * (1.0f - timeAlphaBlend)); } inline void blendTwoAndAdd(std::array &colorF, int currLdRes, int lastLdRes, float timeAlphaBlend) { - colorF[0] += (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + + colorF[0] = (getFloatFromInt<0>(currLdRes) * timeAlphaBlend + getFloatFromInt<0>(lastLdRes) * (1.0f - timeAlphaBlend)); - colorF[1] += (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + + colorF[1] = (getFloatFromInt<1>(currLdRes) * timeAlphaBlend + getFloatFromInt<1>(lastLdRes) * (1.0f - timeAlphaBlend)); - colorF[2] += (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + + colorF[2] = (getFloatFromInt<2>(currLdRes) * timeAlphaBlend + getFloatFromInt<2>(lastLdRes) * (1.0f - timeAlphaBlend)); } @@ -308,19 +308,19 @@ inline void blendTwoAndAdd(float &colorF, float currLdRes, float lastLdRes, floa } inline void addOnlyOne(float *colorF, int currLdRes) { - colorF[0] += getFloatFromInt<0>(currLdRes); - colorF[1] += getFloatFromInt<1>(currLdRes); - colorF[2] += getFloatFromInt<2>(currLdRes); + colorF[0] = getFloatFromInt<0>(currLdRes); + colorF[1] = getFloatFromInt<1>(currLdRes); + colorF[2] = getFloatFromInt<2>(currLdRes); } inline void addOnlyOne(std::array &colorF, int currLdRes) { - colorF[0] += getFloatFromInt<0>(currLdRes); - colorF[1] += getFloatFromInt<1>(currLdRes); - colorF[2] += getFloatFromInt<2>(currLdRes); + colorF[0] = getFloatFromInt<0>(currLdRes); + colorF[1] = getFloatFromInt<1>(currLdRes); + colorF[2] = getFloatFromInt<2>(currLdRes); } inline void addOnlyOne(float &colorF, float currLdRes) { - colorF += currLdRes; + colorF = currLdRes; } void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, float farClip) { getLightByIdStatement.setInputs( lightId ); @@ -338,6 +338,7 @@ void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, fl ilr.lightSkyboxId = getLightByIdStatement.getField("LightSkyboxID").getInt(); ilr.glow = getLightByIdStatement.getField("Glow").getDouble(); ilr.skyBoxFlags = getLightByIdStatement.getField("SkyboxFlags").getInt(); + ilr.id = lightId; } std::vector lightResults; convertInnerResultsToPublic(time, lightResults, innerResults, farClip); @@ -356,6 +357,7 @@ void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std: float totalBlend = 0; while (getLightStatement.execute()) { InnerLightResult &ilr = innerResults.emplace_back(); + ilr.id = getLightStatement.getField("LightId").getInt(); ilr.pos[0] = getLightStatement.getField("GameCoords_0").getDouble(); ilr.pos[1] = getLightStatement.getField("GameCoords_1").getDouble(); ilr.pos[2] = getLightStatement.getField("GameCoords_2").getDouble(); @@ -497,7 +499,7 @@ void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerL ::blendTwoAndAdd(lightResult.FogHeight, currLdRes.FogHeight, lastLdRes.FogHeight, timeAlphaBlend); ::blendTwoAndAdd(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, lastLdRes.FogHeightScaler, timeAlphaBlend); ::blendTwoAndAdd(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, lastLdRes.FogHeightDensity, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, timeAlphaBlend); +// ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, timeAlphaBlend); ::blendTwoAndAdd(lightResult.EndFogColor, currLdRes.EndFogColor, lastLdRes.EndFogColor, timeAlphaBlend); ::blendTwoAndAdd(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, lastLdRes.EndFogColorDistance, timeAlphaBlend); ::blendTwoAndAdd(lightResult.SunFogColor, currLdRes.SunFogColor, lastLdRes.SunFogColor, timeAlphaBlend); @@ -610,6 +612,7 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector auto &innerResult = innerResults[i]; lightResult.isDefault = innerResult.isDefault; lightResult.lightParamId = innerResult.paramId; + lightResult.id = innerResult.id; getLightData.setInputs( innerResult.paramId ); @@ -775,11 +778,8 @@ void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector lightResult.SunFogStrength = currLdRes.SunFogStrength; } } - if (lastLdRes.time == -1) { - addOnlyOne(lightResult, currLdRes); - } else { - blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend); - } + blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend); + break; } lastLdRes = currLdRes; diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index fa3bf1aac..79ab3be8a 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -129,6 +129,7 @@ class CSqliteDB : public IClientDatabase { } struct InnerLightResult { + int id; float pos[3]; float fallbackStart; float fallbackEnd; diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index ef1ad315c..6d40ffe26 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -35,10 +35,10 @@ MinimapGenerator::MinimapGenerator(HWoWFilesCacheStorage cacheStorage, const HGD // config->adtTTLWithoutUpdate = 500; //0.5 sec config->adtFreeStrategy = EFreeStrategy::eFrameBase; // - config->exteriorAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0);; - config->exteriorHorizontAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); - config->exteriorGroundAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); - config->exteriorDirectColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); + config->exteriorColors.exteriorAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0);; + config->exteriorColors.exteriorHorizontAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); + config->exteriorColors.exteriorGroundAmbientColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); + config->exteriorColors.exteriorDirectColor = mathfu::vec4(0.5f,0.5f,0.5f,1.0); config->adtSpecMult = 0.0; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 980d0795b..9dcc313a6 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -138,6 +138,40 @@ void FrontendUI::composeUI() { ImGui::Render(); } +inline void drawColumnF(const std::string &text, const float &value) { + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::Text(text.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%.3f", value); +} +inline void drawColumnVec4(const std::string &text, const mathfu::vec4 &value) { + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::Text(text.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%.3f, %.3f, %.3f, %.3f", value.x, value.y, value.z, value.w); +} + +inline void drawColumnColorVec3(const std::string &text, const std::string &name, const mathfu::vec3 &value) { + ImGui::TableNextRow(); + + const std::string message = "(%.3f, %.3f, %.3f)"; + const std::string varName = name + "##b"; + ImGui::TableNextColumn(); + ImGui::Text(text.c_str()); + + ImGui::TableNextColumn(); + ImGui::Text(message.c_str(), + value.x, + value.y, + value.z); + ImGui::SameLine(); + ImGui::ColorButton(varName.c_str(), ImVec4(value.x, value.y, value.z, 0)); +} + void FrontendUI::showCurrentStatsDialog() { static float f = 0.0f; static int counter = 0; @@ -162,45 +196,48 @@ void FrontendUI::showCurrentStatsDialog() { } ImGui::Separator(); } - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, - ImGui::GetIO().Framerate); + if (ImGui::CollapsingHeader("General statistics")) { + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, + ImGui::GetIO().Framerate); // if(getCurrentAreaName) { - ImGui::Text("Current area name: %s", getCurrentAreaName().c_str()); + ImGui::Text("Current area name: %s", getCurrentAreaName().c_str()); - ImGui::Text("Uniform data for GPU: %.3f MB", m_api->hDevice->getUploadSize() / (1024.0f * 1024.0f)); + ImGui::Text("Uniform data for GPU: %.3f MB", m_api->hDevice->getUploadSize() / (1024.0f * 1024.0f)); - float m2s = m2SizeLoaded / 1024.0f / 1024.f; - ImGui::Text("Total size of m2 files loaded %f MB", m2s); - int l_blpTexturesLoaded = blpTexturesLoaded; - float l_blpTexturesSizeLoaded = blpTexturesSizeLoaded / 1024.0f / 1024.f; - ImGui::Text("Current blp files loaded %d", l_blpTexturesLoaded); - ImGui::Text("Current blp files size %f MB", l_blpTexturesSizeLoaded); + float m2s = m2SizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Total size of m2 files loaded %f MB", m2s); + int l_blpTexturesLoaded = blpTexturesLoaded; + float l_blpTexturesSizeLoaded = blpTexturesSizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Current blp files loaded %d", l_blpTexturesLoaded); + ImGui::Text("Current blp files size %f MB", l_blpTexturesSizeLoaded); - int l_blpTexturesVulkanLoaded = blpTexturesVulkanLoaded; - float l_blpTexturesVulkanSizeLoaded = blpTexturesVulkanSizeLoaded / 1024.0f / 1024.f; - ImGui::Text("Current blp vulkan textures loaded %d", l_blpTexturesVulkanLoaded); - ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); + int l_blpTexturesVulkanLoaded = blpTexturesVulkanLoaded; + float l_blpTexturesVulkanSizeLoaded = blpTexturesVulkanSizeLoaded / 1024.0f / 1024.f; + ImGui::Text("Current blp vulkan textures loaded %d", l_blpTexturesVulkanLoaded); + ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); + } if (m_sceneRenderer) { auto mapPlan = m_sceneRenderer->getLastCreatedPlan(); if (mapPlan) { - auto &adtArray = mapPlan->adtArray; - auto &wmoArray = mapPlan->wmoArray; - auto &wmoGroupArray = mapPlan->wmoGroupArray; - auto &m2Array = mapPlan->m2Array; + auto &cullStageData = mapPlan; - ImGui::Text("Candidates WMO %d", wmoArray.getCandidates().size()); - ImGui::Text("Candidates M2 objects %d", m2Array.getCandidates().size()); + if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { + auto &adtArray = mapPlan->adtArray; + auto &wmoArray = mapPlan->wmoArray; + auto &wmoGroupArray = mapPlan->wmoGroupArray; + auto &m2Array = mapPlan->m2Array; - ImGui::Text("Rendered ADT files %d", adtArray.size()); - ImGui::Text("Rendered WMO %d", wmoArray.getToDrawn().size()); - ImGui::Text("Rendered WMO groups %d", wmoGroupArray.getToDraw().size()); - ImGui::Text("Rendered M2 objects %d", m2Array.getDrawn().size()); + ImGui::Text("Candidates WMO %d", wmoArray.getCandidates().size()); + ImGui::Text("Candidates M2 objects %d", m2Array.getCandidates().size()); + ImGui::Text("Rendered ADT files %d", adtArray.size()); + ImGui::Text("Rendered WMO %d", wmoArray.getToDrawn().size()); + ImGui::Text("Rendered WMO groups %d", wmoGroupArray.getToDraw().size()); + ImGui::Text("Rendered M2 objects %d", m2Array.getDrawn().size()); - auto &cullStageData = mapPlan; + ImGui::Separator(); - if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { int m2ObjectsBeforeCullingExterior = 0; if (cullStageData->viewsHolder.getExterior() != nullptr) { m2ObjectsBeforeCullingExterior = cullStageData->viewsHolder.getExterior()->m2List.getCandidates().size(); @@ -225,103 +262,90 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Separator(); } -// -// if (ImGui::CollapsingHeader("Current fog params")) { -// if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr) { -// ImGui::Text("Fog end: %.3f", cullStageData->frameDependentData->FogEnd); -// ImGui::Text("Fog Scalar: %.3f", cullStageData->frameDependentData->FogScaler); -// ImGui::Text("Fog Density: %.3f", cullStageData->frameDependentData->FogDensity); -// ImGui::Text("Fog Height: %.3f", cullStageData->frameDependentData->FogHeight); -// ImGui::Text("Fog Height Scaler: %.3f", cullStageData->frameDependentData->FogHeightScaler); -// ImGui::Text("Fog Height Density: %.3f", cullStageData->frameDependentData->FogHeightDensity); -// ImGui::Text("Sun Fog Angle: %.3f", cullStageData->frameDependentData->SunFogAngle); -// ImGui::Text("Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogColor.x, -// cullStageData->frameDependentData->FogColor.y, -// cullStageData->frameDependentData->FogColor.z); -// ImGui::Text("End Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->EndFogColor.x, -// cullStageData->frameDependentData->EndFogColor.y, -// cullStageData->frameDependentData->EndFogColor.z); -// ImGui::Text("End Fog Color Distance: %.3f", -// cullStageData->frameDependentData->EndFogColorDistance); -// ImGui::Text("Sun Fog Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->SunFogColor.x, -// cullStageData->frameDependentData->SunFogColor.y, -// cullStageData->frameDependentData->SunFogColor.z); -// ImGui::Text("Sun Fog Strength: %.3f", cullStageData->frameDependentData->SunFogStrength); -// ImGui::Text("Fog Height Color: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogHeightColor.x, -// cullStageData->frameDependentData->FogHeightColor.y, -// cullStageData->frameDependentData->FogHeightColor.z); -// ImGui::Text("Fog Height Coefficients: (%.3f, %.3f, %.3f)", -// cullStageData->frameDependentData->FogHeightCoefficients.x, -// cullStageData->frameDependentData->FogHeightCoefficients.y, -// cullStageData->frameDependentData->FogHeightCoefficients.z); -// ImGui::Separator(); -// } -// } - } - } - - ImGui::NewLine(); - if (ImGui::CollapsingHeader("Elapsed times")) { - ImGui::Text("Elapsed time on consumeUpdate : %.3f ms", m_api->getConfig()->consumeUpdate); - ImGui::Text("Elapsed time on consumeDraw : %.3f ms", m_api->getConfig()->consumeDraw); - ImGui::Text("Elapsed time on composerDrawTimePerFrame : %.3f ms", m_api->getConfig()->composerDrawTimePerFrame); - ImGui::Text("- Elapsed time on cullCreateVarsCounter: %.3f ms", m_api->getConfig()->cullCreateVarsCounter); - ImGui::Text("- Elapsed time on cullGetCurrentWMOCounter: %.3f ms", m_api->getConfig()->cullGetCurrentWMOCounter); - ImGui::Text("- Elapsed time on cullGetCurrentZoneCounter: %.3f ms", m_api->getConfig()->cullGetCurrentZoneCounter); - ImGui::Text("- Elapsed time on cullUpdateLightsFromDBCounter: %.3f ms", m_api->getConfig()->cullUpdateLightsFromDBCounter); - ImGui::Text("- Elapsed time on cullExterior: %.3f ms", m_api->getConfig()->cullExterior); - ImGui::Text("-- Elapsed time on cullExteriorWDLCull: %.3f ms", m_api->getConfig()->cullExteriorWDLCull); - ImGui::Text("-- Elapsed time on cullExteriorGetCands: %.3f ms", m_api->getConfig()->cullExteriorGetCands); - ImGui::Text("-- Elapsed time on cullExterioFrustumWMO: %.3f ms", m_api->getConfig()->cullExterioFrustumWMO); - ImGui::Text("-- Elapsed time on cullExterioFrustumM2: %.3f ms", m_api->getConfig()->cullExterioFrustumM2); - ImGui::Text("- Elapsed time on cullSkyDoms: %.3f ms", m_api->getConfig()->cullSkyDoms); - ImGui::Text("- Elapsed time on cullCombineAllObjects: %.3f ms", m_api->getConfig()->cullCombineAllObjects); - - ImGui::Text("Elapsed time on drawStageAndDepsCNT: %.3f ms", m_api->getConfig()->drawStageAndDepsCNT); - - ImGui::Text("Elapsed time on update : %.3f ms", m_api->getConfig()->updateTimePerFrame); - ImGui::Text("- Elapsed time on startUpdateForNexFrame: %.3f ms", m_api->getConfig()->startUpdateForNexFrame); - ImGui::Text("- Elapsed time on singleUpdateCNT: %.3f ms", m_api->getConfig()->singleUpdateCNT); - ImGui::Text("-- Elapsed time on mapProduceUpdateTime : %.3f ms", m_api->getConfig()->mapProduceUpdateTime); - ImGui::Text("--- Elapsed time on map update : %.3f ms", m_api->getConfig()->mapUpdateTime); - ImGui::Text("---- Elapsed time on m2 update : %.3f ms", m_api->getConfig()->m2UpdateTime); - ImGui::Text("---- Elapsed time on wmo group update : %.3f ms", m_api->getConfig()->wmoGroupUpdateTime); - ImGui::Text("---- Elapsed time on adtUpdate update : %.3f ms", m_api->getConfig()->adtUpdateTime); - ImGui::Text("---- Elapsed time on m2 calc distance : %.3f ms", m_api->getConfig()->m2calcDistanceTime); - ImGui::Text("---- Elapsed time on adt cleanup : %.3f ms", m_api->getConfig()->adtCleanupTime); - ImGui::Text("--- Elapsed time on interiorViewCollectMeshTime : %.3f ms", m_api->getConfig()->interiorViewCollectMeshTime); - ImGui::Text("--- Elapsed time on exteriorViewCollectMeshTime : %.3f ms", m_api->getConfig()->exteriorViewCollectMeshTime); - ImGui::Text("--- Elapsed time on m2CollectMeshTime : %.3f ms", m_api->getConfig()->m2CollectMeshTime); - ImGui::Text("--- Elapsed time on sortMeshTime : %.3f ms", m_api->getConfig()->sortMeshTime); - ImGui::Text("--- Elapsed time on collectBuffersTime : %.3f ms", m_api->getConfig()->collectBuffersTime); - ImGui::Text("--- Elapsed time on sortBuffersTime : %.3f ms", m_api->getConfig()->sortBuffersTime); - - ImGui::Text("- Elapsed time on produceDrawStage: %.3f ms", m_api->getConfig()->produceDrawStage); - ImGui::Text("- Elapsed time on meshesCollectCNT: %.3f ms", m_api->getConfig()->meshesCollectCNT); - ImGui::Text("- Elapsed time on updateBuffersCNT: %.3f ms", m_api->getConfig()->updateBuffersCNT); - ImGui::Text("- Elapsed time on updateBuffersDeviceCNT: %.3f ms", m_api->getConfig()->updateBuffersDeviceCNT); - ImGui::Text("- Elapsed time on postLoadCNT: %.3f ms", m_api->getConfig()->postLoadCNT); - ImGui::Text("- Elapsed time on textureUploadCNT: %.3f ms", m_api->getConfig()->textureUploadCNT); - ImGui::Text("- Elapsed time on endUpdateCNT: %.3f ms", m_api->getConfig()->endUpdateCNT); - - ImGui::Text("Elapsed time on wait for begin update: %.3f ms", m_api->hDevice->getWaitForUpdate()); + if (ImGui::CollapsingHeader("Active db2 lights")) { + if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr ) { + ImGui::Text("List of current Light.db2 ids:"); + for (auto lightId : cullStageData->frameDependentData->currentLightIds) { + ImGui::Text("%d", lightId); + } - ImGui::Separator(); - } - + ImGui::Separator(); -// if (ImGui::CollapsingHeader("Current light params")) { -// if (cullStageData->frameDependentData != nullptr) { -// ImGui::Text("Glow: %.3f", cullStageData->frameDependentData->currentGlow); -// } -// } + ImGui::Text("List of current LightParams.db2 ids:"); + for (auto lightParamId : cullStageData->frameDependentData->currentLightParamIds) { + ImGui::Text("%d", lightParamId); + } + } + } + if (ImGui::CollapsingHeader("Current fog params")) { + if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr && + !cullStageData->frameDependentData->fogResults.empty() ) + { + ImGui::BeginTable("CurrentFogParams", 2); + + + const auto &fogData = cullStageData->frameDependentData->fogResults[0]; + drawColumnF("Fog End:", fogData.FogEnd); + drawColumnF("Fog Scalar:", fogData.FogScaler); + drawColumnF("Fog Density:", fogData.FogDensity); + drawColumnF("Fog Height:", fogData.FogHeight); + drawColumnF("Fog Height Scaler:", fogData.FogHeightScaler); + drawColumnF("Fog Height Density:", fogData.FogHeightDensity); + drawColumnF("Sun Fog Angle:", fogData.SunFogAngle); + drawColumnF("End Fog Color Distance:", fogData.EndFogColorDistance); + drawColumnF("Sun Fog Strength:", fogData.SunFogStrength); + drawColumnVec4("Fog Height Coefficients:", fogData.FogHeightCoefficients); + drawColumnVec4("Main Fog Coefficients:", fogData.MainFogCoefficients); + drawColumnVec4("Height Density Fog Coefficients:", fogData.HeightDensityFogCoefficients); + drawColumnF("Fog Z Scalar:", fogData.FogZScalar); + drawColumnF("Legacy Fog Scalar:", fogData.LegacyFogScalar); + drawColumnF("Main Fog Start Dist:", fogData.MainFogStartDist); + drawColumnF("Main Fog End Dist:", fogData.MainFogEndDist); + drawColumnF("Fog Blend Alpha:", fogData.FogBlendAlpha); + drawColumnF("Fog Start Offset:", fogData.FogStartOffset); + drawColumnColorVec3("Sun Fog Color:", "SunFogColor", fogData.SunFogColor); + drawColumnColorVec3("Fog Color:", "FogColor", fogData.FogColor); + drawColumnColorVec3("End Fog Color:", "EndFogColor", fogData.EndFogColor); + drawColumnColorVec3("Fog Height Color:", "FogHeightColor", fogData.FogHeightColor); + drawColumnColorVec3("Height End Fog Color:", "HeightEndFogColor", fogData.HeightEndFogColor); + ImGui::EndTable(); + + ImGui::Separator(); + } + } + if (ImGui::CollapsingHeader("Current Sky colors")) { + if (cullStageData->frameDependentData != nullptr) { + auto frameDependentData = cullStageData->frameDependentData; + + ImGui::BeginTable("CurrentSkyColors", 2); + drawColumnColorVec3("Sky Top:", "SkyTopColor", frameDependentData->skyColors.SkyTopColor.xyz()); + drawColumnColorVec3("Sky Middle:", "SkyMiddleColor", frameDependentData->skyColors.SkyMiddleColor.xyz()); + drawColumnColorVec3("Sky Band1:", "SkyBand1Color", frameDependentData->skyColors.SkyBand1Color.xyz()); + drawColumnColorVec3("Sky Band2:", "SkyBand2Color", frameDependentData->skyColors.SkyBand2Color.xyz()); + drawColumnColorVec3("Sky Smog:", "SkySmogColor", frameDependentData->skyColors.SkySmogColor.xyz()); + drawColumnColorVec3("Sky Fog:", "SkyFogColor", frameDependentData->skyColors.SkyFogColor.xyz()); + ImGui::EndTable(); + } + } + if (ImGui::CollapsingHeader("Current global light")) { + if (cullStageData->frameDependentData != nullptr) { + auto frameDependentData = cullStageData->frameDependentData; + + ImGui::BeginTable("CurrentLightParams", 2); + + drawColumnColorVec3("Exterior Ambient:", "ExteriorAmbient", frameDependentData->colors.exteriorAmbientColor.xyz()); + drawColumnColorVec3("Exterior Horizon Ambient:", "ExteriorHorizonAmbient", frameDependentData->colors.exteriorAmbientColor.xyz()); + drawColumnColorVec3("Exterior Ground Ambient:", "ExteriorGroundAmbient", frameDependentData->colors.exteriorGroundAmbientColor.xyz()); + drawColumnColorVec3("Exterior Direct Color:", "ExteriorDirectColor", frameDependentData->colors.exteriorGroundAmbientColor.xyz()); + drawColumnF("Glow:", cullStageData->frameDependentData->currentGlow); + ImGui::EndTable(); + } + } + } + } ImGui::End(); } } @@ -1297,249 +1321,206 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->farPlaneForCulling = farPlane+50; } - if (ImGui::Checkbox("Disable glow", &disableGlow)) { - m_api->getConfig()->disableGlow = disableGlow; - } + ImGui::Text("Time: %02d:%02d", (int)(currentTime/120), (int)((currentTime/2) % 60)); - bool disableFog = m_api->getConfig()->disableFog; - if (ImGui::Checkbox("Disable fog", &disableFog)) { - m_api->getConfig()->disableFog = disableFog; + if (ImGui::SliderInt("Current time", ¤tTime, 0, 2880)) { + m_api->getConfig()->currentTime = currentTime; } - bool renderADT = m_api->getConfig()->renderAdt; - if (ImGui::Checkbox("Render ADT", &renderADT)) { - m_api->getConfig()->renderAdt = renderADT; + if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { + m_api->camera->setMovementSpeed(movementSpeed); } - - bool renderM2 = m_api->getConfig()->renderM2; - if (ImGui::Checkbox("Render M2", &renderM2)) { - m_api->getConfig()->renderM2 = renderM2; + auto fogDensityIncreaser = m_api->getConfig()->fogDensityIncreaser; + if (ImGui::SliderFloat("Fog Density", &fogDensityIncreaser, -4, 4)) { + m_api->getConfig()->fogDensityIncreaser = fogDensityIncreaser; } - bool renderWMO = m_api->getConfig()->renderWMO; - if (ImGui::Checkbox("Render WMO", &renderWMO)) { - m_api->getConfig()->renderWMO = renderWMO; - } + if (ImGui::CollapsingHeader("Option toogles")) { - bool renderLiquid = m_api->getConfig()->renderLiquid; - if (ImGui::Checkbox("Render Liquid", &renderLiquid)) { - m_api->getConfig()->renderLiquid = renderLiquid; - } - bool drawM2BB = m_api->getConfig()->drawM2BB; - if (ImGui::Checkbox("Render M2 Bounding Box", &drawM2BB)) { - m_api->getConfig()->drawM2BB = drawM2BB; - } + if (ImGui::Checkbox("Disable glow", &disableGlow)) { + m_api->getConfig()->disableGlow = disableGlow; + } - bool discardInvisibleMeshes = m_api->getConfig()->discardInvisibleMeshes; - if (ImGui::Checkbox("Discard invisible M2 meshes", &discardInvisibleMeshes)) { - m_api->getConfig()->discardInvisibleMeshes = discardInvisibleMeshes; - } + bool disableFog = m_api->getConfig()->disableFog; + if (ImGui::Checkbox("Disable fog", &disableFog)) { + m_api->getConfig()->disableFog = disableFog; + } - bool ignoreADTHoles = m_api->getConfig()->ignoreADTHoles; - if (ImGui::Checkbox("Ignore ADT holes for rendering", &ignoreADTHoles)) { - m_api->getConfig()->ignoreADTHoles = ignoreADTHoles; - } + bool renderADT = m_api->getConfig()->renderAdt; + if (ImGui::Checkbox("Render ADT", &renderADT)) { + m_api->getConfig()->renderAdt = renderADT; + } + bool renderM2 = m_api->getConfig()->renderM2; + if (ImGui::Checkbox("Render M2", &renderM2)) { + m_api->getConfig()->renderM2 = renderM2; + } - bool disablePortalCulling = !m_api->getConfig()->usePortalCulling; - if (ImGui::Checkbox("Disable portal culling", &disablePortalCulling)) { - m_api->getConfig()->usePortalCulling = !disablePortalCulling; - } + bool renderWMO = m_api->getConfig()->renderWMO; + if (ImGui::Checkbox("Render WMO", &renderWMO)) { + m_api->getConfig()->renderWMO = renderWMO; + } - bool renderPortals = m_api->getConfig()->renderPortals; - if (ImGui::Checkbox("Render portals", &renderPortals)) { - m_api->getConfig()->renderPortals = renderPortals; - } - bool renderAntiPortals = m_api->getConfig()->renderAntiPortals; - if (ImGui::Checkbox("Render anti portals", &renderAntiPortals)) { - m_api->getConfig()->renderAntiPortals = renderAntiPortals; - } + bool renderLiquid = m_api->getConfig()->renderLiquid; + if (ImGui::Checkbox("Render Liquid", &renderLiquid)) { + m_api->getConfig()->renderLiquid = renderLiquid; + } - if (renderPortals || renderAntiPortals) { - bool renderPortalsIgnoreDepth = m_api->getConfig()->renderPortalsIgnoreDepth; - if (ImGui::Checkbox("Ignore depth test for rendering portals", &renderPortalsIgnoreDepth)) { - m_api->getConfig()->renderPortalsIgnoreDepth = renderPortalsIgnoreDepth; + bool drawM2BB = m_api->getConfig()->drawM2BB; + if (ImGui::Checkbox("Render M2 Bounding Box", &drawM2BB)) { + m_api->getConfig()->drawM2BB = drawM2BB; } - } - bool useDoubleCameraDebug = m_api->getConfig()->doubleCameraDebug; - if (ImGui::Checkbox("Enable second camera(for debug)", &useDoubleCameraDebug)) { - m_api->getConfig()->doubleCameraDebug = useDoubleCameraDebug; - } + bool discardInvisibleMeshes = m_api->getConfig()->discardInvisibleMeshes; + if (ImGui::Checkbox("Discard invisible M2 meshes", &discardInvisibleMeshes)) { + m_api->getConfig()->discardInvisibleMeshes = discardInvisibleMeshes; + } - if (useDoubleCameraDebug) { - if (m_api->debugCamera == nullptr) { - m_api->debugCamera = std::make_shared(); - m_api->debugCamera->setMovementSpeed(movementSpeed); - float currentCameraPos[4] = {0, 0, 0, 0}; - m_api->camera->getCameraPosition(¤tCameraPos[0]); + bool ignoreADTHoles = m_api->getConfig()->ignoreADTHoles; + if (ImGui::Checkbox("Ignore ADT holes for rendering", &ignoreADTHoles)) { + m_api->getConfig()->ignoreADTHoles = ignoreADTHoles; + } - m_api->debugCamera->setCameraPos(currentCameraPos[0], - currentCameraPos[1], - currentCameraPos[2]); + bool disablePortalCulling = !m_api->getConfig()->usePortalCulling; + if (ImGui::Checkbox("Disable portal culling", &disablePortalCulling)) { + m_api->getConfig()->usePortalCulling = !disablePortalCulling; } - bool controlSecondCamera = m_api->getConfig()->controlSecondCamera; - if (ImGui::Checkbox("Control debug camera", &controlSecondCamera)) { - m_api->getConfig()->controlSecondCamera = controlSecondCamera; + bool renderPortals = m_api->getConfig()->renderPortals; + if (ImGui::Checkbox("Render portals", &renderPortals)) { + m_api->getConfig()->renderPortals = renderPortals; + } + bool renderAntiPortals = m_api->getConfig()->renderAntiPortals; + if (ImGui::Checkbox("Render anti portals", &renderAntiPortals)) { + m_api->getConfig()->renderAntiPortals = renderAntiPortals; } - bool swapMainAndDebug = m_api->getConfig()->swapMainAndDebug; - if (ImGui::Checkbox("Swap main and debug cameras", &swapMainAndDebug)) { - m_api->getConfig()->swapMainAndDebug = swapMainAndDebug; + if (renderPortals || renderAntiPortals) { + bool renderPortalsIgnoreDepth = m_api->getConfig()->renderPortalsIgnoreDepth; + if (ImGui::Checkbox("Ignore depth test for rendering portals", &renderPortalsIgnoreDepth)) { + m_api->getConfig()->renderPortalsIgnoreDepth = renderPortalsIgnoreDepth; + } } - } else { - m_api->debugCamera = nullptr; - } - pauseAnimation = m_api->getConfig()->pauseAnimation; - if (ImGui::Checkbox("Pause animation", &pauseAnimation)) { - m_api->getConfig()->pauseAnimation = pauseAnimation; - } + bool useDoubleCameraDebug = m_api->getConfig()->doubleCameraDebug; + if (ImGui::Checkbox("Enable second camera(for debug)", &useDoubleCameraDebug)) { + m_api->getConfig()->doubleCameraDebug = useDoubleCameraDebug; + } - if (ImGui::Button("Reset Animation")) { - resetAnimationCallback(); - } + if (useDoubleCameraDebug) { + if (m_api->debugCamera == nullptr) { + m_api->debugCamera = std::make_shared(); + m_api->debugCamera->setMovementSpeed(movementSpeed); + float currentCameraPos[4] = {0, 0, 0, 0}; + m_api->camera->getCameraPosition(¤tCameraPos[0]); - ImGui::Text("Time: %02d:%02d", (int)(currentTime/120), (int)((currentTime/2) % 60)); - if (ImGui::SliderInt("Current time", ¤tTime, 0, 2880)) { - m_api->getConfig()->currentTime = currentTime; - } - if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { - m_api->camera->setMovementSpeed(movementSpeed); - } - auto fogDensityIncreaser = m_api->getConfig()->fogDensityIncreaser; - if (ImGui::SliderFloat("Fog Density", &fogDensityIncreaser, -4, 4)) { - m_api->getConfig()->fogDensityIncreaser = fogDensityIncreaser; - } + m_api->debugCamera->setCameraPos(currentCameraPos[0], + currentCameraPos[1], + currentCameraPos[2]); + } + + bool controlSecondCamera = m_api->getConfig()->controlSecondCamera; + if (ImGui::Checkbox("Control debug camera", &controlSecondCamera)) { + m_api->getConfig()->controlSecondCamera = controlSecondCamera; + } - switch(m_api->getConfig()->globalLighting) { - case EParameterSource::eDatabase: { - lightSource = 0; - break; + bool swapMainAndDebug = m_api->getConfig()->swapMainAndDebug; + if (ImGui::Checkbox("Swap main and debug cameras", &swapMainAndDebug)) { + m_api->getConfig()->swapMainAndDebug = swapMainAndDebug; + } + } else { + m_api->debugCamera = nullptr; } - case EParameterSource::eM2: { - lightSource = 1; - break; + + pauseAnimation = m_api->getConfig()->pauseAnimation; + if (ImGui::Checkbox("Pause animation", &pauseAnimation)) { + m_api->getConfig()->pauseAnimation = pauseAnimation; } - case EParameterSource::eConfig: { - lightSource = 2; - break; + + if (ImGui::Button("Reset Animation")) { + resetAnimationCallback(); } } - if (ImGui::RadioButton("Use global timed light", &lightSource, 0)) { - m_api->getConfig()->globalLighting = EParameterSource::eDatabase; - } - if (ImGui::RadioButton("Use ambient light from M2 (only for M2 scenes)", &lightSource, 1)) { - m_api->getConfig()->globalLighting = EParameterSource::eM2; - } - if (ImGui::RadioButton("Manual light", &lightSource, 2)) { - m_api->getConfig()->globalLighting = EParameterSource::eConfig; - } + if (ImGui::CollapsingHeader("Light options")) { + auto mapPlan = (m_sceneRenderer != nullptr) ? + m_sceneRenderer->getLastCreatedPlan() : + nullptr; - if (m_api->getConfig()->globalLighting == EParameterSource::eConfig) { - { - auto ambient = m_api->getConfig()->exteriorAmbientColor; - exteriorAmbientColor = {ambient.x, ambient.y, ambient.z}; - ImVec4 col = ImVec4(ambient.x, ambient.y, ambient.z, 1.0); - if (ImGui::ColorButton("ExteriorAmbientColor##3b", col)) { - ImGui::OpenPopup("Exterior Ambient picker"); + switch(m_api->getConfig()->globalLighting) { + case EParameterSource::eDatabase: { + lightSource = 0; + break; } - ImGui::SameLine(); - ImGui::Text("Exterior Ambient"); - - if (ImGui::BeginPopup("Exterior Ambient picker")) { - if (ImGui::ColorPicker3("Exterior Ambient", exteriorAmbientColor.data())) { - m_api->getConfig()->exteriorAmbientColor = mathfu::vec4( - exteriorAmbientColor[0], exteriorAmbientColor[1], exteriorAmbientColor[2], 1.0); - } - ImGui::EndPopup(); + case EParameterSource::eM2: { + lightSource = 1; + break; + } + case EParameterSource::eConfig: { + lightSource = 2; + break; } } - { - auto horizontAmbient = m_api->getConfig()->exteriorHorizontAmbientColor; - exteriorHorizontAmbientColor = {horizontAmbient.x, horizontAmbient.y, horizontAmbient.z}; - ImVec4 col = ImVec4(horizontAmbient.x, horizontAmbient.y, horizontAmbient.z, 1.0); - if (ImGui::ColorButton("ExteriorHorizontAmbientColor##3b", col)) { - ImGui::OpenPopup("Exterior Horizont Ambient picker"); - } - ImGui::SameLine(); - ImGui::Text("Exterior Horizont Ambient"); - - if (ImGui::BeginPopup("Exterior Horizont Ambient picker")) { - if (ImGui::ColorPicker3("Exterior Horizont Ambient", exteriorHorizontAmbientColor.data())) { - m_api->getConfig()->exteriorHorizontAmbientColor = mathfu::vec4 ( - exteriorHorizontAmbientColor[0], - exteriorHorizontAmbientColor[1], exteriorHorizontAmbientColor[2], 1.0); - } - ImGui::EndPopup(); - } + if (ImGui::RadioButton("Use global timed light", &lightSource, 0)) { + m_api->getConfig()->globalLighting = EParameterSource::eDatabase; } + ImGui::SameLine(); + if (mapPlan != nullptr && mapPlan->frameDependentData != nullptr && + ImGui::Button("Edit current colors")) { - auto groundAmbient = m_api->getConfig()->exteriorGroundAmbientColor; - exteriorGroundAmbientColor = {groundAmbient.x, groundAmbient.y, groundAmbient.z}; - ImVec4 col = ImVec4(groundAmbient.x, groundAmbient.y, groundAmbient.z, 1.0); - - if (ImGui::ColorButton("ExteriorGroundAmbientColor##3b", col)) { - ImGui::OpenPopup("Exterior Ground Ambient picker"); - } - ImGui::SameLine(); - ImGui::Text("Exterior Ground Ambient"); - - if (ImGui::BeginPopup("Exterior Ground Ambient picker")) { - if (ImGui::ColorPicker3("Exterior Ground Ambient", exteriorGroundAmbientColor.data())) { - m_api->getConfig()->exteriorGroundAmbientColor = mathfu::vec4( - exteriorGroundAmbientColor[0], - exteriorGroundAmbientColor[1], exteriorGroundAmbientColor[2], 1.0); - } - ImGui::EndPopup(); - } + m_api->getConfig()->exteriorColors = mapPlan->frameDependentData->colors; + m_api->getConfig()->globalLighting = EParameterSource::eConfig; } - } - //Glow source - switch(m_api->getConfig()->glowSource) { - case EParameterSource::eDatabase: { - glowSource = 0; - break; + if (ImGui::RadioButton("Use ambient light from M2 (only for M2 scenes)", &lightSource, 1)) { + m_api->getConfig()->globalLighting = EParameterSource::eM2; } - case EParameterSource::eConfig: { - glowSource = 1; - break; + if (ImGui::RadioButton("Manual light", &lightSource, 2)) { + m_api->getConfig()->globalLighting = EParameterSource::eConfig; } - default: - glowSource = 1; - } - if (ImGui::RadioButton("Use glow from database", &glowSource, 0)) { - m_api->getConfig()->glowSource = EParameterSource::eDatabase; - } - if (ImGui::RadioButton("Manual glow", &glowSource, 1)) { - m_api->getConfig()->glowSource = EParameterSource::eConfig; - } + if (m_api->getConfig()->globalLighting == EParameterSource::eConfig) { + auto config = m_api->getConfig(); - if (m_api->getConfig()->glowSource == EParameterSource::eConfig) { - if (ImGui::SliderFloat("Custom glow", &customGlow, 0.0, 10)) { - m_api->getConfig()->currentGlow = customGlow; + ImGui::CompactColorPicker("Exterior Ambient", config->exteriorColors.exteriorAmbientColor); + ImGui::CompactColorPicker("Exterior Horizon Ambient", + config->exteriorColors.exteriorHorizontAmbientColor); + ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor); + ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor); } - } + //Glow source + switch (m_api->getConfig()->glowSource) { + case EParameterSource::eDatabase: { + glowSource = 0; + break; + } + case EParameterSource::eConfig: { + glowSource = 1; + break; + } + default: + glowSource = 1; + } + ImGui::Separator(); - if (ImGui::SliderInt("Thread Count", &threadCount, 2, 16)) { - m_api->getConfig()->threadCount = threadCount; - } -// if (ImGui::SliderInt("QuickSort cutoff", &quickSortCutoff, 1, 1000)) { -// if (setQuicksortCutoff){ -// setQuicksortCutoff(quickSortCutoff); -// } -// } - + if (ImGui::RadioButton("Use glow from database", &glowSource, 0)) { + m_api->getConfig()->glowSource = EParameterSource::eDatabase; + } + if (ImGui::RadioButton("Manual glow", &glowSource, 1)) { + m_api->getConfig()->glowSource = EParameterSource::eConfig; + } + if (m_api->getConfig()->glowSource == EParameterSource::eConfig) { + if (ImGui::SliderFloat("Custom glow", &customGlow, 0.0, 10)) { + m_api->getConfig()->currentGlow = customGlow; + } + } + } ImGui::End(); diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index b301dcc60..44404bbbd 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -157,11 +157,6 @@ class FrontendUI : public IScene, public std::enable_shared_from_this exteriorAmbientColor = {1, 1, 1}; - std::array exteriorHorizontAmbientColor = {1, 1, 1}; - std::array exteriorGroundAmbientColor= {1, 1, 1}; - std::array exteriorDirectColor = {0, 0, 0}; - MapRecord prevMapRec; float worldPosX = 0; diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 9a3401401..213ead5e0 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -154,10 +154,10 @@ void MinimapGenerationWindow::editComponentsForConfig(Config * config) { ImGui::BeginGroupPanel("Exterior Lighting"); { - ImGui::CompactColorPicker("Exterior Ambient", config->exteriorAmbientColor); - ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorHorizontAmbientColor); - ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorGroundAmbientColor); - ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorDirectColor); + ImGui::CompactColorPicker("Exterior Ambient", config->exteriorColors.exteriorAmbientColor); + ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorColors.exteriorHorizontAmbientColor); + ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor); + ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor); } ImGui::EndGroupPanel(); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 20e2d5a03..9537679c1 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -15,7 +15,7 @@ option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) set(LINK_TRACY 1) -set(COMPILE_SHADER_WITH_DEBUG 1) +set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) endif () diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index 9c0b18336..d91581d66 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -121,7 +121,6 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec vec4 outColor_713 = vec4(0.0); //accumulator - for (int i = 0; i < fogCount; i++) { vec4 classicFogParams = mainFogData[i].classicFogParams; float classicFogEnabled = classicFogParams.x; @@ -185,11 +184,13 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float expMax_781 = max(0.0f, (z_779 - start)); float exp_783 = exp((expMax_781 * heightDensity)); float legacyExpFogHeight_784 = (1.0 / exp_783); + vec4 t785 = mainFogData[i].heightPlane; float dot_787 = dot(t785.xyz, vertexInViewSpace); float height_789 = (dot_787 + t785.w); float saturate_791 = saturatef((height_789 * heightRate)); float heightFog_792 = (1.0f - saturate_791); + vec4 t793 = mainFogData[i].heightFogCoeff; float xSqrd_794 = (heightFog_792 * heightFog_792); float xCubed_795 = (xSqrd_794 * heightFog_792); @@ -199,11 +200,13 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float exp_810 = exp((expMax_781 * density)); float legacyFogResult_811 = (1.0 / exp_810); float lerp_812 = mix(legacyFogResult_811, legacyExpFogHeight_784, heightFog_807); + float finalLegacyFog_815 = (1.0f - ((1.0f - lerp_812) * fogRateScalar)); float endFadeFog_818 = saturatef((1.42857146f * (1.0f - normalizedDistance_808))); float finalLegacyFog_819 = min(finalLegacyFog_815, endFadeFog_818); float artFogNormalizedDistance_823 = saturatef(((vLength_778 - mainFogCurveStartDist) / (mainFogCurveEndDist - mainFogCurveStartDist))); float engineFogNormalizedDistance_825 = saturatef((vLength_778 / mainFogCurveEndDist)); + vec4 t826 = mainFogData[i].mainFogCoeff; float xSqrd_827 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); float xCubed_828 = (xSqrd_827 * artFogNormalizedDistance_823); @@ -215,6 +218,7 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float saturate_855 = saturatef(((((t842.x * xCubed_844) + (t842.y * xSqrd_843)) + (t842.z * artFogNormalizedDistance_823)) + t842.w)); float heightFogResult_857 = saturatef((1.0f - saturate_855)); float lerp_858 = mix(fogResult_841, heightFogResult_857, heightFog_807); + float finalFog_861 = (1.0f - ((1.0f - lerp_858) * fogRateScalar)); float endPct_863 = saturatef((end / mainFogCurveEndDist)); float finalFogBeginPct_864 = (endPct_863 - 0.300000012f); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 141ef83ca..adb7923b4 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -493,8 +493,7 @@ void ParticleEmitter::StepUpdate(animTime_t delta) { std::list listForDeletion; - int numThreads = m_api->getConfig()->threadCount; - + int numThreads = 10; #pragma omp parallel for schedule(dynamic, 200) default(none) shared(delta, forces) num_threads(numThreads) for (int i = 0; i < this->particles.size(); i++) { auto &p = this->particles[i]; diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 337f50076..4cd931e4a 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -38,10 +38,10 @@ void M2Scene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, auto frameDepedantData = mapRenderPlan->frameDependentData; - frameDepedantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->exteriorDirectColor = mathfu::vec4(0.0,0.0,0.0,0.0); + frameDepedantData->colors.exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDepedantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDepedantData->colors.exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDepedantData->colors.exteriorDirectColor = mathfu::vec4(0.0,0.0,0.0,0.0); frameDepedantData->exteriorDirectColorDir = mathfu::vec3(0.0,0.0,0.0); } auto frameDepedantData = mapRenderPlan->frameDependentData; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 6a1ceb8ad..5fa7c2416 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -324,7 +324,6 @@ std::tuple> createSkyMesh(const HMapSc void Map::makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { ZoneScoped ; - cullCreateVarsCounter.beginMeasurement(); Config* config = this->m_api->getConfig(); mathfu::vec4 cameraPos = frameInputParams.frameParameters->matricesForCulling->cameraPos; @@ -374,11 +373,8 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams WMOListContainer potentialWmo; M2ObjectListContainer potentialM2; - cullCreateVarsCounter.endMeasurement(); - { ZoneScopedN("cullGetCurrentWMOCounter"); - cullGetCurrentWMOCounter.beginMeasurement(); //Hack that is needed to get the current WMO the camera is in. Basically it does frustum culling over current ADT getPotentialEntities(frustumData, cameraPos, mapRenderPlan, potentialM2, potentialWmo); @@ -402,10 +398,8 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams break; } } - cullGetCurrentWMOCounter.endMeasurement(); } - cullGetCurrentZoneCounter.beginMeasurement(); //7. Get AreaId and Area Name StateForConditions stateForConditions; @@ -435,12 +429,9 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->areaId = areaRecord.areaId; mapRenderPlan->parentAreaId = areaRecord.parentAreaId; - cullGetCurrentZoneCounter.endMeasurement(); //Get lights from DB - cullUpdateLightsFromDBCounter.beginMeasurement(); updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); - cullUpdateLightsFromDBCounter.endMeasurement(); ///----------------------------------- @@ -460,7 +451,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->wmoArray.addToDrawn(mapRenderPlan->m_currentWMO); } - cullExterior.beginMeasurement(); auto exterior = mapRenderPlan->viewsHolder.getExterior(); if ( exterior != nullptr ) { //Fix FrustumData for exterior was created after WMO traversal. So we need to fix it @@ -470,16 +460,12 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams checkExterior(cameraPos, exterior->frustumData, m_viewRenderOrder, mapRenderPlan); } - cullExterior.endMeasurement(); } else { //Cull exterior - cullExterior.beginMeasurement(); auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); checkExterior(cameraPos, exteriorView->frustumData, m_viewRenderOrder, mapRenderPlan); - cullExterior.endMeasurement(); } - cullSkyDoms.beginMeasurement(); if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { @@ -501,9 +487,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams } } } - cullSkyDoms.endMeasurement(); - cullCombineAllObjects.beginMeasurement(); { auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); if (exteriorView != nullptr) { @@ -529,8 +513,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams } } - cullCombineAllObjects.endMeasurement(); - mapRenderPlan->renderSky = m_api->getConfig()->renderSkyDom && (!m_suppressDrawingSky && (mapRenderPlan->viewsHolder.getExterior() || mapRenderPlan->currentWmoGroupIsExtLit)); @@ -541,18 +523,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->skyMesh0x4 = skyMesh0x4Sky; } - m_api->getConfig()->cullCreateVarsCounter = cullCreateVarsCounter.getTimePerFrame(); - m_api->getConfig()->cullGetCurrentWMOCounter = cullGetCurrentWMOCounter.getTimePerFrame(); - m_api->getConfig()->cullGetCurrentZoneCounter = cullGetCurrentZoneCounter.getTimePerFrame(); - m_api->getConfig()->cullUpdateLightsFromDBCounter = cullUpdateLightsFromDBCounter.getTimePerFrame(); - m_api->getConfig()->cullExterior = cullExterior.getTimePerFrame(); - m_api->getConfig()->cullExteriorSetDecl = cullExteriorSetDecl.getTimePerFrame(); - m_api->getConfig()->cullExteriorWDLCull = cullExteriorWDLCull.getTimePerFrame(); - m_api->getConfig()->cullExteriorGetCands = cullExteriorGetCands.getTimePerFrame(); - m_api->getConfig()->cullExterioFrustumWMO = cullExterioFrustumWMO.getTimePerFrame(); - m_api->getConfig()->cullExterioFrustumM2 = cullExterioFrustumM2.getTimePerFrame(); - m_api->getConfig()->cullSkyDoms = cullSkyDoms.getTimePerFrame(); - m_api->getConfig()->cullCombineAllObjects = cullCombineAllObjects.getTimePerFrame(); // //Limit M2 count based on distance/m2 height // for (auto it = this->m2RenderedThisFrameArr.begin(); // it != this->m2RenderedThisFrameArr.end();) { @@ -594,6 +564,15 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp //Check zoneLight getLightResultsFromDB(frustumData.cameraPos, config, lightResults, &stateForConditions); + { + auto &fdd = mapRenderPlan->frameDependentData; + //Fill current light ids + for (auto &light : lightResults) { + fdd->currentLightIds.push_back(light.id); + fdd->currentLightParamIds.push_back(light.lightParamId); + } + } + //Delete skyboxes that are not in light array std::unordered_map> perFdidMap; auto modelIt = m_exteriorSkyBoxes.begin(); @@ -707,12 +686,12 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp if (config->globalLighting == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->exteriorAmbientColor = mathfu::vec4(ambientColor[2], ambientColor[1], ambientColor[0], 0); - fdd->exteriorGroundAmbientColor = mathfu::vec4(groundAmbientColor[2], groundAmbientColor[1], groundAmbientColor[0], + fdd->colors.exteriorAmbientColor = mathfu::vec4(ambientColor[2], ambientColor[1], ambientColor[0], 0); + fdd->colors.exteriorGroundAmbientColor = mathfu::vec4(groundAmbientColor[2], groundAmbientColor[1], groundAmbientColor[0], 0); - fdd->exteriorHorizontAmbientColor = mathfu::vec4(horizontAmbientColor[2], horizontAmbientColor[1], + fdd->colors.exteriorHorizontAmbientColor = mathfu::vec4(horizontAmbientColor[2], horizontAmbientColor[1], horizontAmbientColor[0], 0); - fdd->exteriorDirectColor = mathfu::vec4(directColor[2], directColor[1], directColor[0], 0); + fdd->colors.exteriorDirectColor = mathfu::vec4(directColor[2], directColor[1], directColor[0], 0); auto extDir = MathHelper::calcExteriorColorDir( frustumData.viewMat, m_api->getConfig()->currentTime @@ -721,10 +700,10 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } else if (config->globalLighting == EParameterSource::eConfig) { auto fdd = mapRenderPlan->frameDependentData; - fdd->exteriorAmbientColor = config->exteriorAmbientColor; - fdd->exteriorGroundAmbientColor = config->exteriorGroundAmbientColor; - fdd->exteriorHorizontAmbientColor = config->exteriorHorizontAmbientColor; - fdd->exteriorDirectColor = config->exteriorDirectColor; + fdd->colors.exteriorAmbientColor = config->exteriorColors.exteriorAmbientColor; + fdd->colors.exteriorGroundAmbientColor = config->exteriorColors.exteriorGroundAmbientColor; + fdd->colors.exteriorHorizontAmbientColor = config->exteriorColors.exteriorHorizontAmbientColor; + fdd->colors.exteriorDirectColor = config->exteriorColors.exteriorDirectColor; auto extDir = MathHelper::calcExteriorColorDir( frustumData.viewMat, m_api->getConfig()->currentTime @@ -753,12 +732,12 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } if (config->skyParams == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->SkyTopColor = mathfu::vec4(SkyTopColor[2], SkyTopColor[1], SkyTopColor[0], 1.0); - fdd->SkyMiddleColor = mathfu::vec4(SkyMiddleColor[2], SkyMiddleColor[1], SkyMiddleColor[0], 1.0); - fdd->SkyBand1Color = mathfu::vec4(SkyBand1Color[2], SkyBand1Color[1], SkyBand1Color[0], 1.0); - fdd->SkyBand2Color = mathfu::vec4(SkyBand2Color[2], SkyBand2Color[1], SkyBand2Color[0], 1.0); - fdd->SkySmogColor = mathfu::vec4(SkySmogColor[2], SkySmogColor[1], SkySmogColor[0], 1.0); - fdd->SkyFogColor = mathfu::vec4(SkyFogColor[2], SkyFogColor[1], SkyFogColor[0], 1.0); + fdd->skyColors.SkyTopColor = mathfu::vec4(SkyTopColor[2], SkyTopColor[1], SkyTopColor[0], 1.0); + fdd->skyColors.SkyMiddleColor = mathfu::vec4(SkyMiddleColor[2], SkyMiddleColor[1], SkyMiddleColor[0], 1.0); + fdd->skyColors.SkyBand1Color = mathfu::vec4(SkyBand1Color[2], SkyBand1Color[1], SkyBand1Color[0], 1.0); + fdd->skyColors.SkyBand2Color = mathfu::vec4(SkyBand2Color[2], SkyBand2Color[1], SkyBand2Color[0], 1.0); + fdd->skyColors.SkySmogColor = mathfu::vec4(SkySmogColor[2], SkySmogColor[1], SkySmogColor[0], 1.0); + fdd->skyColors.SkyFogColor = mathfu::vec4(SkyFogColor[2], SkyFogColor[1], SkyFogColor[0], 1.0); } } @@ -845,24 +824,24 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } } else if (config->globalFog == EParameterSource::eConfig) { LightResult globalFog; - globalFog.FogScaler = config->FogScaler; - globalFog.FogEnd = config->FogEnd; - globalFog.FogDensity = config->FogDensity; + globalFog.FogScaler = config->fogResult.FogScaler; + globalFog.FogEnd = config->fogResult.FogEnd; + globalFog.FogDensity = config->fogResult.FogDensity; - globalFog.FogHeightScaler = config->FogHeightScaler; - globalFog.FogHeightDensity = config->FogHeightDensity; - globalFog.SunFogAngle = config->SunFogAngle; - globalFog.EndFogColorDistance = config->EndFogColorDistance; - globalFog.SunFogStrength = config->SunFogStrength; + globalFog.FogHeightScaler = config->fogResult.FogHeightScaler; + globalFog.FogHeightDensity = config->fogResult.FogHeightDensity; + globalFog.SunFogAngle = config->fogResult.SunFogAngle; + globalFog.EndFogColorDistance = config->fogResult.EndFogColorDistance; + globalFog.SunFogStrength = config->fogResult.SunFogStrength; globalFog.blendCoef = 1.0 - totalSummator; globalFog.isDefault = true; - globalFog.EndFogColor = {config->EndFogColor.z, config->EndFogColor.y, config->EndFogColor.x}; - globalFog.SunFogColor = {config->SunFogColor.z, config->SunFogColor.y, config->SunFogColor.x}; - globalFog.FogHeightColor = {config->FogHeightColor.z, config->FogHeightColor.y, config->FogHeightColor.x}; + globalFog.EndFogColor = {config->fogResult.EndFogColor.z, config->fogResult.EndFogColor.y, config->fogResult.EndFogColor.x}; + globalFog.SunFogColor = {config->fogResult.SunFogColor.z, config->fogResult.SunFogColor.y, config->fogResult.SunFogColor.x}; + globalFog.FogHeightColor = {config->fogResult.FogHeightColor.z, config->fogResult.FogHeightColor.y, config->fogResult.FogHeightColor.x}; - combinedResults.push_back(globalFog); + combinedResults = {globalFog}; } } std::sort(combinedResults.begin(), combinedResults.end(), [](const LightResult &a, const LightResult &b) -> bool { @@ -876,40 +855,11 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } } -// for (auto &_light : combinedResults) { -// FogEnd += _light.FogEnd * _light.blendCoef; -// FogScaler += _light.FogScaler * _light.blendCoef; -// FogDensity += _light.FogDensity * _light.blendCoef; -// FogHeight += _light.FogHeight * _light.blendCoef; -// FogHeightScaler += _light.FogHeightScaler * _light.blendCoef; -// FogHeightDensity += _light.FogHeightDensity * _light.blendCoef; -// SunFogAngle += _light.SunFogAngle * _light.blendCoef; -// -// EndFogColor += mathfu::vec3(_light.EndFogColor.data()) * _light.blendCoef; -// EndFogColorDistance += _light.EndFogColorDistance * _light.blendCoef; -// SunFogColor += mathfu::vec3(_light.SunFogColor.data()) * _light.blendCoef; -// SunFogStrength += _light.SunFogStrength * _light.blendCoef; -// FogHeightColor += mathfu::vec3(_light.FogHeightColor.data()) * _light.blendCoef; -// FogHeightCoefficients += mathfu::vec4(_light.FogHeightCoefficients.data()) * _light.blendCoef; -// MainFogCoefficients += mathfu::vec4(_light.MainFogCoefficients.data()) * _light.blendCoef; -// HeightDensityFogCoefficients += mathfu::vec4(_light.HeightDensityFogCoefficients.data()) * _light.blendCoef; -// FogZScalar += _light.FogZScalar * _light.blendCoef; -// LegacyFogScalar += _light.LegacyFogScalar * _light.blendCoef; -// MainFogStartDist += _light.MainFogStartDist * _light.blendCoef; -// MainFogEndDist += _light.MainFogEndDist * _light.blendCoef; -// FogBlendAlpha += _light.FogBlendAlpha * _light.blendCoef; -// HeightEndFogColor += mathfu::vec3(_light.HeightEndFogColor.data()) * _light.blendCoef; -// FogStartOffset += _light.FogStartOffset * _light.blendCoef; -// } -// FogBlendAlpha = 1.0f; - //In case of no data -> disable the fog { auto fdd = mapRenderPlan->frameDependentData; fdd->FogDataFound = !combinedResults.empty(); -// std::cout << "combinedResults.empty() = " << combinedResults.empty() << std::endl; -// std::cout << "combinedResults.size() = " << combinedResults.size() << std::endl; - fdd->EndFogColor = mathfu::vec3(0.0f, 0, 0); + auto &fogResult = fdd->fogResults.emplace_back(); for (auto &_light : lightResults) { fogResult.FogEnd = mix(fogResult.FogEnd, _light.FogEnd, _light.blendCoef); @@ -1007,24 +957,21 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, if (zoneLightFound) { float blendCoef = 1.0; + //Replace default light with ZoneLight + //TODO: make a blend coef to zonelight border based on the least distance to border and replace default only if that coef is 1.0 + bool hasDefault = false; + zoneLightResult.blendCoef = 1.0f; for (auto &_light : lightResults) { - if (!_light.isDefault) { - blendCoef -= _light.blendCoef; + if (_light.isDefault) { + hasDefault = true; + _light = zoneLightResult; } } - if (blendCoef > 0) { - zoneLightResult.blendCoef = blendCoef; + if (!hasDefault) { lightResults.push_back(zoneLightResult); - //Delete default from results; - auto it = lightResults.begin(); - while (it != lightResults.end()) { - if (it->isDefault) { - lightResults.erase(it); - break; - } else - it++; - } } + std::sort(lightResults.begin(), lightResults.end(), [](auto const &a, auto const &b) {return a.blendCoef > b.blendCoef; }); + } } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, @@ -1119,17 +1066,12 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); //Should not be null, since we called checkExterior - cullExteriorWDLCull.beginMeasurement(); if (m_wdlObject != nullptr) { m_wdlObject->checkFrustumCulling(frustumData, cameraPos, exteriorView->m2List, mapRenderPlan->wmoArray); } - cullExteriorWDLCull.endMeasurement(); - cullExteriorGetCands.beginMeasurement(); getCandidatesEntities(frustumData, cameraPos, mapRenderPlan, exteriorView->m2List, mapRenderPlan->wmoArray); - cullExteriorGetCands.endMeasurement(); - cullExterioFrustumWMO.beginMeasurement(); //Frustum cull for (auto &wmoCandidate : mapRenderPlan->wmoArray.getCandidates()) { if (!wmoCandidate->isLoaded()) continue; @@ -1146,12 +1088,9 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, mapRenderPlan->wmoArray.addToDrawn(wmoCandidate); } } - cullExterioFrustumWMO.endMeasurement(); - cullExterioFrustumM2.beginMeasurement(); //3.2 Iterate over all global WMOs and M2s (they have uniqueIds) { - int numThreads = m_api->getConfig()->threadCount; auto results = std::vector(); auto &candidates = exteriorView->m2List.getCandidates(); @@ -1185,7 +1124,6 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, exteriorView->m2List.addToDraw(m2ObjectCandidate); } } - cullExterioFrustumM2.endMeasurement(); } } @@ -1497,7 +1435,6 @@ void Map::update(const HMapRenderPlan &renderPlan) { auto &m2ToDraw = renderPlan->m2Array.getDrawn(); { ZoneScopedN("m2UpdateframeCounter"); - m2UpdateframeCounter.beginMeasurement(); auto threadsAvailable = m_api->getConfig()->hardwareThreadCount(); @@ -1519,33 +1456,27 @@ void Map::update(const HMapRenderPlan &renderPlan) { m2Object->update(deltaTime, cameraVec3, lookAtMat); } } - - m2UpdateframeCounter.endMeasurement(); } { ZoneScopedN("wmoUpdate"); - wmoUpdate.beginMeasurement(); + for (const auto &wmoObject: renderPlan->wmoArray.getToDrawn()) { if (wmoObject == nullptr) continue; wmoObject->update(); } - wmoUpdate.endMeasurement(); } { ZoneScopedN("wmoGroupUpdate"); - wmoGroupUpdate.beginMeasurement(); for (const auto &wmoGroupObject: renderPlan->wmoGroupArray.getToDraw()) { if (wmoGroupObject == nullptr) continue; wmoGroupObject->update(); } - wmoGroupUpdate.endMeasurement(); } { ZoneScopedN("adtUpdate"); - adtUpdate.beginMeasurement(); { std::unordered_set> processedADT; for (const auto &adtObjectRes: renderPlan->adtArray) { @@ -1555,12 +1486,10 @@ void Map::update(const HMapRenderPlan &renderPlan) { } } } - adtUpdate.endMeasurement(); } //2. Calc distance every 100 ms - m2calcDistanceCounter.beginMeasurement(); tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { @@ -1570,11 +1499,9 @@ void Map::update(const HMapRenderPlan &renderPlan) { } }, tbb::auto_partitioner() ); - m2calcDistanceCounter.endMeasurement(); //Cleanup ADT every 10 seconds - adtCleanupCounter.beginMeasurement(); - if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { + if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { auto adtObj = mapTiles[i][j]; @@ -1589,23 +1516,25 @@ void Map::update(const HMapRenderPlan &renderPlan) { adtFreeLambda(false, true, this->m_currentTime + deltaTime); } - adtCleanupCounter.endMeasurement(); - this->m_currentTime += deltaTime; - m_api->getConfig()->m2UpdateTime = m2UpdateframeCounter.getTimePerFrame(); - m_api->getConfig()->wmoGroupUpdateTime = wmoGroupUpdate.getTimePerFrame(); - m_api->getConfig()->adtUpdateTime = adtUpdate.getTimePerFrame(); - m_api->getConfig()->m2calcDistanceTime = m2calcDistanceCounter.getTimePerFrame(); - m_api->getConfig()->adtCleanupTime = adtCleanupCounter.getTimePerFrame(); - //Collect meshes + this->m_currentTime += deltaTime; } void Map::updateBuffers(const HMapRenderPlan &renderPlan) { ZoneScoped; { auto &meshblockVS = skyMeshMat0x4->m_skyColors->getObject(); - auto EndFogColorV4_1 = mathfu::vec4(renderPlan->frameDependentData->EndFogColor, 0.0); - auto EndFogColorV4_2 = mathfu::vec4(renderPlan->frameDependentData->EndFogColor, 1.0); + auto EndFogColor = !renderPlan->frameDependentData->fogResults.empty() ? + renderPlan->frameDependentData->fogResults[0].EndFogColor: + mathfu::vec3(0,0,0); + + if (EndFogColor.Length() < 0.0001) { + EndFogColor = renderPlan->frameDependentData->skyColors.SkyFogColor.xyz(); + } + + + auto EndFogColorV4_1 = mathfu::vec4(EndFogColor, 0.0); + auto EndFogColorV4_2 = mathfu::vec4(EndFogColor, 1.0); meshblockVS.skyColor[0] = EndFogColorV4_1; meshblockVS.skyColor[1] = EndFogColorV4_1; meshblockVS.skyColor[2] = EndFogColorV4_1; @@ -1616,12 +1545,12 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { } { auto &meshblockVS = skyMeshMat->m_skyColors->getObject(); - meshblockVS.skyColor[0] = renderPlan->frameDependentData->SkyTopColor; - meshblockVS.skyColor[1] = renderPlan->frameDependentData->SkyMiddleColor; - meshblockVS.skyColor[2] = renderPlan->frameDependentData->SkyBand1Color; - meshblockVS.skyColor[3] = renderPlan->frameDependentData->SkyBand2Color; - meshblockVS.skyColor[4] = renderPlan->frameDependentData->SkySmogColor; - meshblockVS.skyColor[5] = renderPlan->frameDependentData->SkyFogColor; + meshblockVS.skyColor[0] = renderPlan->frameDependentData->skyColors.SkyTopColor; + meshblockVS.skyColor[1] = renderPlan->frameDependentData->skyColors.SkyMiddleColor; + meshblockVS.skyColor[2] = renderPlan->frameDependentData->skyColors.SkyBand1Color; + meshblockVS.skyColor[3] = renderPlan->frameDependentData->skyColors.SkyBand2Color; + meshblockVS.skyColor[4] = renderPlan->frameDependentData->skyColors.SkySmogColor; + meshblockVS.skyColor[5] = renderPlan->frameDependentData->skyColors.SkyFogColor; skyMeshMat->m_skyColors->save(); } diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 02731812c..cb571e150 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -36,30 +36,6 @@ class Map : public IScene, public IMapApi { } } protected: - - - FrameCounter mapUpdateCounter; - FrameCounter m2UpdateframeCounter; - FrameCounter m2calcDistanceCounter; - FrameCounter adtCleanupCounter; - FrameCounter wmoUpdate; - FrameCounter wmoGroupUpdate; - FrameCounter adtUpdate; - - - FrameCounter cullCreateVarsCounter; - FrameCounter cullGetCurrentWMOCounter; - FrameCounter cullGetCurrentZoneCounter; - FrameCounter cullUpdateLightsFromDBCounter; - FrameCounter cullExterior; - FrameCounter cullExteriorSetDecl; - FrameCounter cullExteriorWDLCull; - FrameCounter cullExteriorGetCands; - FrameCounter cullExterioFrustumWMO; - FrameCounter cullExterioFrustumM2; - FrameCounter cullSkyDoms; - FrameCounter cullCombineAllObjects; - HApiContainer m_api = nullptr; std::array, 64>, 64> mapTiles={}; std::vector> m_mandatoryADT; diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index 956be8327..8648c0837 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -36,10 +36,10 @@ void WmoScene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, Mat auto frameDependantData = mapRenderPlan->frameDependentData; - frameDependantData->exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->exteriorDirectColor = mathfu::vec4(0.3, 0.30, 0.3, 0.3); + frameDependantData->colors.exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorDirectColor = mathfu::vec4(0.3, 0.30, 0.3, 0.3); frameDependantData->exteriorDirectColorDir = MathHelper::calcExteriorColorDir( mapRenderPlan->renderingMatrices->lookAtMat, m_api->getConfig()->currentTime diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 1526ee457..1f3e79910 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -10,6 +10,7 @@ #include #include #include +#include "../renderer/mapScene/FrameDependentData.h" struct RiverColorOverride { int liquidObjectId; @@ -35,7 +36,6 @@ enum class EFreeStrategy : char { class Config { public: Config() { - threadCount = std::max((int)std::thread::hardware_concurrency()-2, 1); m_hardwareThreadCount = std::max((int)std::thread::hardware_concurrency()-2, 1); } @@ -79,9 +79,6 @@ class Config { int minParticle = 0; int maxParticle = 9999; - int threadCount = 4; - int quickSortCutoff = 100; - int currentTime = 0; bool useWotlkLogic = false; @@ -99,18 +96,11 @@ class Config { mathfu::vec4 clearColor = {0.117647, 0.207843, 0.392157, 0}; EParameterSource globalLighting = EParameterSource::eDatabase; - mathfu::vec4 exteriorAmbientColor = {1, 1, 1, 1}; - mathfu::vec4 exteriorHorizontAmbientColor = {1, 1, 1, 1}; - mathfu::vec4 exteriorGroundAmbientColor = {1, 1, 1, 1}; - mathfu::vec4 exteriorDirectColor = {0.3,0.3,0.3, 0.3}; + ExteriorColors exteriorColors; mathfu::vec3 exteriorDirectColorDir; float adtSpecMult = 1.0; - mathfu::vec4 interiorAmbientColor; - mathfu::vec4 interiorSunColor; - mathfu::vec3 interiorSunDir; - bool useMinimapWaterColor = false; bool useCloseRiverColorForDB = false; EParameterSource waterColorParams = EParameterSource::eDatabase; @@ -120,29 +110,10 @@ class Config { mathfu::vec4 farOceanColor = {1,1,1,1}; EParameterSource skyParams = EParameterSource::eDatabase; - mathfu::vec4 SkyTopColor; - mathfu::vec4 SkyMiddleColor; - mathfu::vec4 SkyBand1Color; - mathfu::vec4 SkyBand2Color; - mathfu::vec4 SkySmogColor; - mathfu::vec4 SkyFogColor; + SkyColors skyColors; EParameterSource globalFog = EParameterSource::eDatabase; - mathfu::vec4 actualFogColor = mathfu::vec4(1,1,1, 1); - float FogEnd = 0; - float FogScaler = 0; - float FogDensity = 0; - float FogHeight = 0; - float FogHeightScaler = 0; - float FogHeightDensity = 0; - float SunFogAngle = 0; - mathfu::vec3 FogColor = mathfu::vec3(0,0,0); - mathfu::vec3 EndFogColor = mathfu::vec3(0,0,0); - float EndFogColorDistance = 0; - mathfu::vec3 SunFogColor = mathfu::vec3(0,0,0); - float SunFogStrength = 0; - mathfu::vec3 FogHeightColor = mathfu::vec3(0,0,0); - mathfu::vec4 FogHeightCoefficients = mathfu::vec4(0,0,0,0); + FogResult fogResult; std::string areaName; @@ -156,51 +127,6 @@ class Config { double adtFTLWithoutUpdate = 6; //25 frames by default EFreeStrategy adtFreeStrategy = EFreeStrategy::eTimeBased; - - //Stuff to display in UI - double composerDrawTimePerFrame = 0; - double consumeDraw = 0; - double consumeUpdate = 0; - double updateTimePerFrame = 0; - double mapUpdateTime = 0; - double m2UpdateTime = 0; - double wmoGroupUpdateTime = 0; - double adtUpdateTime = 0; - double m2calcDistanceTime = 0; - double adtCleanupTime = 0; - - double mapProduceUpdateTime = 0; - double interiorViewCollectMeshTime = 0; - double exteriorViewCollectMeshTime = 0; - double m2CollectMeshTime = 0; - double sortMeshTime = 0; - double collectBuffersTime = 0; - double sortBuffersTime = 0; - - double startUpdateForNexFrame = 0; - double singleUpdateCNT = 0; - double produceDrawStage = 0; - double meshesCollectCNT = 0; - double updateBuffersCNT = 0; - double updateBuffersDeviceCNT = 0; - double postLoadCNT = 0; - double textureUploadCNT = 0; - double drawStageAndDepsCNT = 0; - double endUpdateCNT = 0; - - double cullCreateVarsCounter = 0; - double cullGetCurrentWMOCounter = 0; - double cullGetCurrentZoneCounter = 0; - double cullUpdateLightsFromDBCounter = 0; - double cullExterior = 0; - double cullExteriorSetDecl = 0; - double cullExteriorWDLCull = 0; - double cullExteriorGetCands = 0; - double cullExterioFrustumWMO = 0; - double cullExterioFrustumM2 = 0; - double cullSkyDoms = 0; - double cullCombineAllObjects = 0; - HRiverColorOverrideHolder colorOverrideHolder = nullptr; private: int m_hardwareThreadCount; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 623ae51ae..ad179c30f 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -35,13 +35,13 @@ struct LightResult { std::array SkyFogColor; //Fog - float FogEnd; - float FogScaler; - float FogDensity; - float FogHeight; - float FogHeightScaler; - float FogHeightDensity; - float SunFogAngle; //Blended Separately + float FogEnd = 0.0; + float FogScaler = 0.0; + float FogDensity = 100000; + float FogHeight = 0.0; + float FogHeightScaler = 0.0; + float FogHeightDensity = 100000; + float SunFogAngle = 0.0; //Blended Separately float SunAngleBlend = 0.0f; //Blended Separately std::array EndFogColor; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index d1fbc8e78..2249d8ab5 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -108,22 +108,14 @@ void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vectordrawUpdateFunction.size(); i++) { renderFunctions.push_back(std::move(frameScenario->drawUpdateFunction[i]())); } - drawFuncGeneration.endMeasurement(); - m_apiContainer->getConfig()->consumeUpdate = drawFuncGeneration.getTimePerFrame(); } void SceneComposer::consumeDraw(const std::vector> &renderFuncs) { ZoneScoped ; - deviceDrawFrame.beginMeasurement(); m_apiContainer->hDevice->drawFrame(renderFuncs); - deviceDrawFrame.endMeasurement(); - - m_apiContainer->getConfig()->consumeDraw = deviceDrawFrame.getTimePerFrame(); } @@ -135,7 +127,6 @@ void SceneComposer::consumeDraw(const std::vectorhDevice->submitDrawCommands(); m_apiContainer->hDevice->increaseFrameNumber(); - composerDrawTimePerFrame.endMeasurement(); - m_apiContainer->getConfig()->composerDrawTimePerFrame = composerDrawTimePerFrame.getTimePerFrame(); } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 46317cb06..4a5f18c07 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -27,10 +27,6 @@ class SceneComposer { bool m_isTerminating = false; bool m_firstFrame = true; - FrameCounter composerDrawTimePerFrame; - FrameCounter deviceDrawFrame; - FrameCounter drawFuncGeneration; - void consumeCulling(HFrameScenario &frameScenario); void consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions); void consumeDraw(const std::vector> &renderFuncs); diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index b3c2c3655..3dab76531 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -11,57 +11,67 @@ #endif #include "mathfu/glsl_mappings.h" -struct FrameDependantData { - //Glow - float currentGlow; +struct FogResult { + float FogEnd = 0; + float FogScaler = 0; + float FogDensity = 0; + float FogHeight = 0; + float FogHeightScaler = 0; + float FogHeightDensity = 0; + float SunFogAngle = 0; + mathfu::vec3 FogColor = mathfu::vec3(0, 0, 0); + mathfu::vec3 EndFogColor = mathfu::vec3(0, 0, 0); + float EndFogColorDistance = 0; + mathfu::vec3 SunFogColor = mathfu::vec3(0, 0, 0); + float SunFogStrength = 0; + mathfu::vec3 FogHeightColor = mathfu::vec3(0, 0, 0); + mathfu::vec4 FogHeightCoefficients = mathfu::vec4(0, 0, 0, 0); + mathfu::vec4 MainFogCoefficients = mathfu::vec4(0, 0, 0, 0); + mathfu::vec4 HeightDensityFogCoefficients = mathfu::vec4(0, 0, 0, 0); + float FogZScalar = 0.00001; + float LegacyFogScalar = 0.00001; + float MainFogStartDist = 0.00001; + float MainFogEndDist = 0.00001; + float FogBlendAlpha = 0.00001; + mathfu::vec3 HeightEndFogColor = mathfu::vec3(0, 0, 0); + float FogStartOffset = 0.00001; +}; - //Ambient +struct SkyColors { + mathfu::vec4 SkyTopColor; + mathfu::vec4 SkyMiddleColor; + mathfu::vec4 SkyBand1Color; + mathfu::vec4 SkyBand2Color; + mathfu::vec4 SkySmogColor; + mathfu::vec4 SkyFogColor; +}; + +struct ExteriorColors { mathfu::vec4 exteriorAmbientColor = {1, 1, 1, 1}; mathfu::vec4 exteriorHorizontAmbientColor = {1, 1, 1, 1}; mathfu::vec4 exteriorGroundAmbientColor = {1, 1, 1, 1}; mathfu::vec4 exteriorDirectColor = {0.3,0.3,0.3, 0.3}; +}; + +struct FrameDependantData { + //Glow + float currentGlow; + + //Ambient + ExteriorColors colors; mathfu::vec3 exteriorDirectColorDir; + std::vector currentLightIds; + std::vector currentLightParamIds; + //Sky params bool overrideValuesWithFinalFog = false; + SkyColors skyColors; - mathfu::vec4 SkyTopColor; - mathfu::vec4 SkyMiddleColor; - mathfu::vec4 SkyBand1Color; - mathfu::vec4 SkyBand2Color; - mathfu::vec4 SkySmogColor; - mathfu::vec4 SkyFogColor; //Fog params bool FogDataFound = false; - - struct FogResult { - float FogEnd = 0; - float FogScaler = 0; - float FogDensity = 0; - float FogHeight = 0; - float FogHeightScaler = 0; - float FogHeightDensity = 0; - float SunFogAngle = 0; - mathfu::vec3 FogColor = mathfu::vec3(0, 0, 0); - mathfu::vec3 EndFogColor = mathfu::vec3(0, 0, 0); - float EndFogColorDistance = 0; - mathfu::vec3 SunFogColor = mathfu::vec3(0, 0, 0); - float SunFogStrength = 0; - mathfu::vec3 FogHeightColor = mathfu::vec3(0, 0, 0); - mathfu::vec4 FogHeightCoefficients = mathfu::vec4(0, 0, 0, 0); - mathfu::vec4 MainFogCoefficients = mathfu::vec4(0, 0, 0, 0); - mathfu::vec4 HeightDensityFogCoefficients = mathfu::vec4(0, 0, 0, 0); - float FogZScalar = 0.00001; - float LegacyFogScalar = 0.00001; - float MainFogStartDist = 0.00001; - float MainFogEndDist = 0.00001; - float FogBlendAlpha = 0.00001; - mathfu::vec3 HeightEndFogColor = mathfu::vec3(0, 0, 0); - float FogStartOffset = 0.00001; - }; std::vector fogResults; - mathfu::vec3 EndFogColor = mathfu::vec3(0, 0, 0); //Water params bool useMinimapWaterColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 522231943..70e5dd802 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -26,7 +26,6 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes) { ZoneScoped; - mapProduceUpdateCounter.beginMeasurement(); auto &opaqueMeshes = *hopaqueMeshes; auto &transparentMeshes = *htransparentMeshes; @@ -46,7 +45,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende int m_viewRenderOrder = 0; // Put everything into one array and sort - interiorViewCollectMeshCounter.beginMeasurement(); + bool renderPortals = m_config->renderPortals; bool renderADT = m_config->renderAdt; bool renderWMO = m_config->renderWMO; @@ -54,18 +53,14 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende for (auto &view : cullStage->viewsHolder.getInteriorViews()) { view->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); } - interiorViewCollectMeshCounter.endMeasurement(); - exteriorViewCollectMeshCounter.beginMeasurement(); { auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); } } - exteriorViewCollectMeshCounter.endMeasurement(); - m2CollectMeshCounter.beginMeasurement(); if (m_config->renderM2) { for (auto &m2Object : cullStage->m2Array.getDrawn()) { if (m2Object == nullptr) continue; @@ -82,28 +77,14 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende } } } - m2CollectMeshCounter.endMeasurement(); //No need to sort array which has only one element - sortMeshCounter.beginMeasurement(); if (transparentMeshes.size() > 1) { std::sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); } if (skyTransparentMeshes.size() > 1) { std::sort(skyTransparentMeshes.begin(), skyTransparentMeshes.end(), SortMeshes); } - sortMeshCounter.endMeasurement(); - - mapProduceUpdateCounter.endMeasurement(); - - - m_config->mapProduceUpdateTime = mapProduceUpdateCounter.getTimePerFrame(); - m_config->interiorViewCollectMeshTime = interiorViewCollectMeshCounter.getTimePerFrame(); - m_config->exteriorViewCollectMeshTime = exteriorViewCollectMeshCounter.getTimePerFrame(); - m_config->m2CollectMeshTime = m2CollectMeshCounter.getTimePerFrame(); - m_config->sortMeshTime = sortMeshCounter.getTimePerFrame(); - m_config->collectBuffersTime = collectBuffersCounter.getTimePerFrame(); - m_config->sortBuffersTime = sortBuffersCounter.getTimePerFrame(); } void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, @@ -132,10 +113,10 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrinteriorDirectLightDir; blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); - blockPSVS.extLight.uExteriorAmbientColor = fdd->exteriorAmbientColor; - blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->exteriorHorizontAmbientColor; - blockPSVS.extLight.uExteriorGroundAmbientColor = fdd->exteriorGroundAmbientColor; - blockPSVS.extLight.uExteriorDirectColor = fdd->exteriorDirectColor; + blockPSVS.extLight.uExteriorAmbientColor = fdd->colors.exteriorAmbientColor; + blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->colors.exteriorHorizontAmbientColor; + blockPSVS.extLight.uExteriorGroundAmbientColor = fdd->colors.exteriorGroundAmbientColor; + blockPSVS.extLight.uExteriorDirectColor = fdd->colors.exteriorDirectColor; blockPSVS.extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); blockPSVS.extLight.uAdtSpecMult_FogCount = mathfu::vec4(m_config->adtSpecMult, fdd->fogResults.size(), 0, 1.0); @@ -179,7 +160,6 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr Date: Fri, 8 Sep 2023 18:59:01 +0300 Subject: [PATCH 105/212] - update casc lib - lighting works - more data is shown in UI --- 3rdparty/DBImporter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index dfb3aef49..089e18ce4 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit dfb3aef491c3cc0cc2d21d385b71727e5b2d25e2 +Subproject commit 089e18ce4159b6fed9b11a6771e5b3ced6a2738c From 50a975c6a0d4e4bcb66373a7764b882aac83084f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 8 Sep 2023 19:00:12 +0300 Subject: [PATCH 106/212] - fix assert error --- 3rdparty/DBImporter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index 089e18ce4..279e61a78 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit 089e18ce4159b6fed9b11a6771e5b3ced6a2738c +Subproject commit 279e61a789d34446b44033b5d63dfa3c1c5292d4 From f5dc6fe026f6f0415adfeca424b712c47e7d0600 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 14 Sep 2023 00:57:04 +0300 Subject: [PATCH 107/212] - add more controls on UI --- src/persistance/CascRequestProcessor.cpp | 38 +++- src/persistance/CascRequestProcessor.h | 1 + src/ui/FrontendUI.cpp | 205 +++--------------- src/ui/FrontendUI.h | 1 + .../MinimapGenerationWindow.cpp | 12 +- .../compactColorPicker/compactColorPicker.cpp | 17 +- .../compactColorPicker/compactColorPicker.h | 2 +- 7 files changed, 89 insertions(+), 187 deletions(-) diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 573eb1506..29a9617fd 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "CascRequestProcessor.h" #include "../../3rdparty/casclib/src/CascLib.h" #include "../../3rdparty/filesystem_impl/include/ghc/filesystem.hpp" @@ -133,6 +134,37 @@ HFileContent CascRequestProcessor::tryGetFile(void *cascStorage, void *fileNameT return fileContent; } +static const std::string cacheDirectory = "./file_edits/"; +HFileContent CascRequestProcessor::tryGetFileFromOverrides(int fileDataId) { + + std::string inputFileName = cacheDirectory + std::to_string(fileDataId); + std::ifstream cache_file(inputFileName, std::ios::in |std::ios::binary); + if (cache_file.good()) { + cache_file.unsetf(std::ios::skipws); + + // get its size: + std::streampos fileSize; + + cache_file.seekg(0, std::ios::end); + fileSize = cache_file.tellg(); + cache_file.seekg(0, std::ios::beg); + + + HFileContent vec = std::make_shared(fileSize); + cache_file.read((char *) vec->data(), fileSize); + + // read the data: + std::copy(std::istream_iterator(cache_file), + std::istream_iterator(), + std::back_inserter(*vec.get())); + + std::cout << "Loaded fdid = " << fileDataId << " from " << inputFileName << std::endl; + + return vec; + } + return nullptr; +} + void CascRequestProcessor::processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) { auto perstFile = s_file.lock(); uint32_t fileDataId = 0; @@ -166,8 +198,10 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache openFlags |= CASC_OVERCOME_ENCRYPTED; - HFileContent fileContent; - if (this->m_storage != nullptr) { + HFileContent fileContent = nullptr; + + fileContent = this->tryGetFileFromOverrides(fileDataId); + if (this->m_storage != nullptr && fileContent == nullptr) { fileContent = this->tryGetFile(this->m_storage, fileNameToPass, openFlags); if (fileContent == nullptr) { if (fileDataId > 0) { diff --git a/src/persistance/CascRequestProcessor.h b/src/persistance/CascRequestProcessor.h index 7fd2b6017..8f8b03cbb 100644 --- a/src/persistance/CascRequestProcessor.h +++ b/src/persistance/CascRequestProcessor.h @@ -27,6 +27,7 @@ class CascRequestProcessor : public RequestProcessor { void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) override; private: HFileContent tryGetFile(void *cascStorage, void *fileNameToPass, uint32_t openFlags); + HFileContent tryGetFileFromOverrides(int fileDataId); }; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 9dcc313a6..284c9adf9 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -47,6 +47,7 @@ FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { } void FrontendUI::composeUI() { + ZoneScoped; if (m_dataExporter != nullptr) { m_dataExporter->process(); @@ -286,7 +287,6 @@ void FrontendUI::showCurrentStatsDialog() { { ImGui::BeginTable("CurrentFogParams", 2); - const auto &fogData = cullStageData->frameDependentData->fogResults[0]; drawColumnF("Fog End:", fogData.FogEnd); drawColumnF("Fog Scalar:", fogData.FogScaler); @@ -337,9 +337,9 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::BeginTable("CurrentLightParams", 2); drawColumnColorVec3("Exterior Ambient:", "ExteriorAmbient", frameDependentData->colors.exteriorAmbientColor.xyz()); - drawColumnColorVec3("Exterior Horizon Ambient:", "ExteriorHorizonAmbient", frameDependentData->colors.exteriorAmbientColor.xyz()); + drawColumnColorVec3("Exterior Horizon Ambient:", "ExteriorHorizonAmbient", frameDependentData->colors.exteriorHorizontAmbientColor.xyz()); drawColumnColorVec3("Exterior Ground Ambient:", "ExteriorGroundAmbient", frameDependentData->colors.exteriorGroundAmbientColor.xyz()); - drawColumnColorVec3("Exterior Direct Color:", "ExteriorDirectColor", frameDependentData->colors.exteriorGroundAmbientColor.xyz()); + drawColumnColorVec3("Exterior Direct Color:", "ExteriorDirectColor", frameDependentData->colors.exteriorDirectColor.xyz()); drawColumnF("Glow:", cullStageData->frameDependentData->currentGlow); ImGui::EndTable(); } @@ -1315,6 +1315,8 @@ void FrontendUI::showSettingsDialog() { // ImGui::EndCombo(); // } // } + if (ImGui::SliderFloat("fov", &fov, 10, 150)) { + } if (ImGui::SliderFloat("Far plane", &farPlane, 200, 2000)) { m_api->getConfig()->farPlane = farPlane; @@ -1468,12 +1470,15 @@ void FrontendUI::showSettingsDialog() { if (ImGui::RadioButton("Use global timed light", &lightSource, 0)) { m_api->getConfig()->globalLighting = EParameterSource::eDatabase; } - ImGui::SameLine(); - if (mapPlan != nullptr && mapPlan->frameDependentData != nullptr && - ImGui::Button("Edit current colors")) - { - m_api->getConfig()->exteriorColors = mapPlan->frameDependentData->colors; - m_api->getConfig()->globalLighting = EParameterSource::eConfig; + if (mapPlan != nullptr && + mapPlan->frameDependentData != nullptr && + m_api->getConfig()->globalLighting == EParameterSource::eDatabase) { + + ImGui::SameLine(); + if (ImGui::Button("Edit current colors")) { + m_api->getConfig()->exteriorColors = mapPlan->frameDependentData->colors; + m_api->getConfig()->globalLighting = EParameterSource::eConfig; + } } if (ImGui::RadioButton("Use ambient light from M2 (only for M2 scenes)", &lightSource, 1)) { @@ -1486,11 +1491,15 @@ void FrontendUI::showSettingsDialog() { if (m_api->getConfig()->globalLighting == EParameterSource::eConfig) { auto config = m_api->getConfig(); - ImGui::CompactColorPicker("Exterior Ambient", config->exteriorColors.exteriorAmbientColor); + ImGui::BeginTable("CurrentFogParams", 2); + + ImGui::CompactColorPicker("Exterior Ambient", config->exteriorColors.exteriorAmbientColor,true); ImGui::CompactColorPicker("Exterior Horizon Ambient", - config->exteriorColors.exteriorHorizontAmbientColor); - ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor); - ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor); + config->exteriorColors.exteriorHorizontAmbientColor,true); + ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor,true); + ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor,true); + + ImGui::EndTable(); } //Glow source @@ -1626,104 +1635,9 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { 0.0f, 0.0f, 1, 0.0f); } -//HDrawStage createSceneDrawStage(HFrameScenario sceneScenario, int width, int height, double deltaTime, bool isScreenshot, -// bool produceDoubleCamera, bool swapDebugCamera, -// ApiContainer &apiContainer, std::shared_ptr ¤tScene, HCullStage &cullStage) { -// -// -// static const mathfu::mat4 vulkanMatrixFix2 = mathfu::mat4(1, 0, 0, 0, -// 0, -1, 0, 0, -// 0, 0, 1.0/2.0, 1.0/2.0, -// 0, 0, 0, 1).Transpose(); -// -// float farPlaneRendering = apiContainer.getConfig()->farPlane; -// float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; -// -// float nearPlane = 1.0; -// float fov = toRadian(45.0); -// -// float canvasAspect = (float)width / (float)height; -// -// HCameraMatrices cameraMatricesCulling = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); -// HCameraMatrices cameraMatricesUpdate = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); -// HCameraMatrices cameraMatricesRendering = cameraMatricesUpdate; -// HCameraMatrices cameraMatricesRenderingDebug = nullptr; -// -// if (produceDoubleCamera && apiContainer.debugCamera != nullptr) -// cameraMatricesRenderingDebug = apiContainer.debugCamera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); -// -// -// //Frustum matrix with reversed Z -// bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); -// if (isInfZSupported) -// { -// float f = 1.0f / tan(fov / 2.0f); -// cameraMatricesRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); -// if (cameraMatricesRenderingDebug != nullptr) { -// cameraMatricesRenderingDebug->perspectiveMat = cameraMatricesRendering->perspectiveMat; -// } -// } -// -// if (apiContainer.hDevice->getIsVulkanAxisSystem() ) { -// auto &perspectiveMatrix = cameraMatricesRendering->perspectiveMat; -// -// perspectiveMatrix = vulkanMatrixFix2 * perspectiveMatrix; -// } -// -// auto clearColor = apiContainer.getConfig()->clearColor; -// -// if (cameraMatricesRenderingDebug && swapDebugCamera) { -// std::swap(cameraMatricesRendering, cameraMatricesRenderingDebug); -// } -// -// if (currentScene != nullptr) { -// ViewPortDimensions dimensions = {{0, 0}, {width, height}}; -// -// HFrameBuffer fb = nullptr; -// if (isScreenshot) { -// fb = apiContainer.hDevice->createFrameBuffer(width, height, -// {ITextureFormat::itRGBA}, -// ITextureFormat::itDepth32, -// apiContainer.hDevice->getMaxSamplesCnt(), 4); -// } -// -// cullStage = sceneScenario->addCullStage(cameraMatricesCulling, currentScene); -// auto updateStage = sceneScenario->addUpdateStage(cullStage, deltaTime*(1000.0f), cameraMatricesUpdate); -// std::vector updateStages = {updateStage}; -// -// std::vector drawStageDependencies = {}; -// if (produceDoubleCamera) { -// std::vector drawStageDependencies__ = {}; -// -// HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRenderingDebug, drawStageDependencies__, -// true, -// dimensions, -// true, isInfZSupported, clearColor, fb); -// drawStageDependencies.push_back(sceneDrawStage); -// -// int newWidth = floor(dimensions.maxs[0]*0.25f); -// int newHeight = floor((float)newWidth / canvasAspect); -// -// int newX = dimensions.maxs[0] - newWidth; -// int newY = dimensions.maxs[1] - newHeight; -// -// dimensions = {{newX, newY}, {newWidth, newHeight}}; -// } -// -// HDrawStage sceneDrawStage = sceneScenario->addDrawStage(updateStages, currentScene, cameraMatricesRendering, drawStageDependencies, -// true, -// dimensions, -// true, isInfZSupported, clearColor, fb); -// -// -// return sceneDrawStage; -// } -// -// return nullptr; -//} - HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, int width, int height, + float fov, bool produceDoubleCamera, bool swapDebugCamera, const std::shared_ptr ¤tScene) { @@ -1735,23 +1649,23 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; float nearPlane = 1.0; - float fov = toRadian(45.0); + float fovR = toRadian(fov); float canvasAspect = (float)width / (float)height; - result->matricesForCulling = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); - result->cameraMatricesForRendering = apiContainer.camera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneCulling); + result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); + result->cameraMatricesForRendering = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); result->cameraMatricesForDebugCamera = nullptr; if (produceDoubleCamera && apiContainer.debugCamera != nullptr) - result->cameraMatricesForDebugCamera = apiContainer.debugCamera->getCameraMatrices(fov, canvasAspect, nearPlane, farPlaneRendering); + result->cameraMatricesForDebugCamera = apiContainer.debugCamera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneRendering); //Frustum matrix with reversed Z bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); if (isInfZSupported) { - float f = 1.0f / tan(fov / 2.0f); + float f = 1.0f / tan(fovR / 2.0f); result->cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); if (result->cameraMatricesForDebugCamera != nullptr) { result->cameraMatricesForDebugCamera->perspectiveMat = result->cameraMatricesForRendering->perspectiveMat; @@ -1785,6 +1699,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do wowSceneFrameInput->viewPortDimensions = dimension; wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, canvWidth, canvHeight, + fov, m_api->getConfig()->doubleCameraDebug, m_api->getConfig()->swapMainAndDebug, m_currentScene); @@ -1792,6 +1707,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do if (needToMakeScreenshot) { wowSceneFrameInput->screenShotParameters = createMapSceneParams(*m_api, screenShotWidth, screenShotHeight, + fov, false, false, m_currentScene); @@ -1824,67 +1740,6 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do return scenario; -// -// HFrameScenario sceneScenario = std::make_shared(); -// std::vector uiDependecies = {}; -// -// if (needToMakeScreenshot) -// { -// HCullStage tempCullStage = nullptr; -// auto drawStage = createSceneDrawStage(sceneScenario, screenShotWidth, screenShotHeight, deltaTime, true, -// false, false, *m_api, -// currentScene,tempCullStage); -// if (drawStage != nullptr) { -// uiDependecies.push_back(drawStage); -// screenshotDS = drawStage; -// screenshotFrame = m_api->hDevice->getFrameNumber(); -// } -// needToMakeScreenshot = false; -// } -// if (m_minimapGenerationWindow != nullptr) { -// auto drawStage = m_minimapGenerationWindow->getDrawStage(sceneScenario); -// if (drawStage != nullptr) { -// uiDependecies.push_back(drawStage); -// } -// } -// -// //DrawStage for current frame -// bool clearOnUi = true; -// if (currentScene != nullptr && m_api->camera != nullptr) -// { -// int currentFrame = m_api->hDevice->getDrawFrameNumber(); -// auto &cullStageData = m_cullstages[currentFrame]; -// cullStageData = nullptr; -// -// -// -// auto drawStage = createSceneDrawStage(sceneScenario, canvWidth, canvHeight, deltaTime, -// false, -// m_api->getConfig()->doubleCameraDebug, -// m_api->getConfig()->swapMainAndDebug, -// *m_api, -// currentScene, cullStageData); -// if (drawStage != nullptr) { -// uiDependecies.push_back(drawStage); -// clearOnUi = false; -// } -// } -// //DrawStage for UI -// { -// ViewPortDimensions dimension = { -// {0, 0}, -// {canvWidth, canvHeight} -// }; -// auto clearColor = m_api->getConfig()->clearColor; -// -// auto uiCullStage = sceneScenario->addCullStage(nullptr, getShared()); -// auto uiUpdateStage = sceneScenario->addUpdateStage(uiCullStage, deltaTime * (1000.0f), nullptr); -// std::vector updateStages = {uiUpdateStage}; -// HDrawStage frontUIDrawStage = sceneScenario->addDrawStage(updateStages, getShared(), nullptr, uiDependecies, -// true, dimension, clearOnUi, false, clearColor, nullptr); -// } -// -// return sceneScenario; } bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 44404bbbd..b431147e1 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -136,6 +136,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_thisexteriorColors.exteriorAmbientColor); - ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorColors.exteriorHorizontAmbientColor); - ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor); - ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor); + ImGui::CompactColorPicker("Exterior Ambient", config->exteriorColors.exteriorAmbientColor, false); + ImGui::CompactColorPicker("Exterior Horizon Ambient", config->exteriorColors.exteriorHorizontAmbientColor, false); + ImGui::CompactColorPicker("Exterior Ground Ambient", config->exteriorColors.exteriorGroundAmbientColor, false); + ImGui::CompactColorPicker("Exterior Direct Color", config->exteriorColors.exteriorDirectColor, false); } ImGui::EndGroupPanel(); @@ -407,7 +407,7 @@ void MinimapGenerationWindow::renderEditTab() { } ImGui::BeginGroupPanel("Ocean color override"); { - ImGui::CompactColorPicker("Close Ocean Color", sceneDef->closeOceanColor); + ImGui::CompactColorPicker("Close Ocean Color", sceneDef->closeOceanColor, false); ImGui::EndGroupPanel(); } ImGui::BeginGroupPanel("Image settings"); @@ -465,7 +465,7 @@ void MinimapGenerationWindow::renderEditTab() { minimapGenerator->getCurrentFDData(areaId, parentAreaId, riverColor); ImGui::Text("Current areaId %d", areaId); ImGui::Text("Current parent areaId %d", parentAreaId); - ImGui::CompactColorPicker("Current River Color", riverColor); + ImGui::CompactColorPicker("Current River Color", riverColor, false); ImGui::EndGroupPanel(); } diff --git a/src/ui/imguiLib/compactColorPicker/compactColorPicker.cpp b/src/ui/imguiLib/compactColorPicker/compactColorPicker.cpp index 00c127be0..697b8af0a 100644 --- a/src/ui/imguiLib/compactColorPicker/compactColorPicker.cpp +++ b/src/ui/imguiLib/compactColorPicker/compactColorPicker.cpp @@ -4,13 +4,24 @@ #include "compactColorPicker.h" -void ImGui::CompactColorPicker(const std::string colorName, mathfu::vec4 &color) { +void ImGui::CompactColorPicker(const std::string colorName, mathfu::vec4 &color, bool columnMode) { + if (columnMode) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + } + + ImGui::Text("%s", colorName.c_str()); + + if (columnMode) { + ImGui::TableNextColumn(); + } else { + ImGui::SameLine(); + } + ImVec4 col = ImVec4(color.x, color.y, color.z, 1.0); if (ImGui::ColorButton((colorName+"##3b").c_str(), col)) { ImGui::OpenPopup((colorName+"picker").c_str()); } - ImGui::SameLine(); - ImGui::Text("%s", colorName.c_str()); if (ImGui::BeginPopup((colorName + "picker").c_str())) { if (ImGui::ColorPicker3(colorName.c_str(), color.data_)) { diff --git a/src/ui/imguiLib/compactColorPicker/compactColorPicker.h b/src/ui/imguiLib/compactColorPicker/compactColorPicker.h index 4dce40dc5..2dbcf79bc 100644 --- a/src/ui/imguiLib/compactColorPicker/compactColorPicker.h +++ b/src/ui/imguiLib/compactColorPicker/compactColorPicker.h @@ -7,7 +7,7 @@ #include namespace ImGui { - void CompactColorPicker(const std::string colorName, mathfu::vec4 &color); + void CompactColorPicker(const std::string colorName, mathfu::vec4 &color, bool columnMode); } From 18546367d6381be2921ff5e2855acc938848d242 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 14 Sep 2023 23:38:16 +0300 Subject: [PATCH 108/212] - more debugging stuff, ring buffer --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 6 +- wowViewerLib/CMakeLists.txt | 8 +- .../src/engine/objects/scenes/map.cpp | 36 +- .../src/engine/shader/ShaderDefinitions.h | 1232 ++++++++--------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 69 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 10 +- .../src/gapi/vulkan/buffers/CBufferChunkVLK.h | 9 +- .../vulkan/buffers/GBufferChunkDynamicVLK.h | 1 - .../buffers/GBufferChunkDynamicVersionedVLK.h | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 238 ++-- .../src/gapi/vulkan/buffers/GBufferVLK.h | 73 +- .../vulkan/buffers/GStagingRingBuffer.cpp | 59 + .../gapi/vulkan/buffers/GStagingRingBuffer.h | 36 + .../gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp | 36 + .../gapi/vulkan/buffers/gpu/BufferGpuVLK.h | 36 + .../vulkan/buffers/gpu/BufferStagingVLK.cpp | 38 + .../vulkan/buffers/gpu/BufferStagingVLK.h | 26 + .../CommandBufferRecorder.cpp | 12 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 32 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 72 +- 20 files changed, 1122 insertions(+), 909 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 9fb17cdad..d955b8471 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -20,9 +20,9 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic } void FrontendUIRenderForwardVLK::createBuffers() { - iboBuffer = m_device->createIndexBuffer(1024*1024); - vboBuffer = m_device->createVertexBuffer(1024*1024); - uboBuffer = m_device->createUniformBuffer(sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); + iboBuffer = m_device->createIndexBuffer("UI_Ibo_Buffer", 1024*1024); + vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024); + uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_imguiUbo = std::make_shared>(uboBuffer); } diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 9537679c1..35939bc7e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -562,7 +562,13 @@ if (LINK_VULKAN) src/gapi/vulkan/context/vulkan_context.h src/gapi/vulkan/shaders/ShaderConfig.h src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp - src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp src/gapi/vulkan/commandBuffer/CommandBufferThread.h) + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp src/gapi/vulkan/commandBuffer/CommandBufferThread.h + src/gapi/vulkan/buffers/GStagingRingBuffer.cpp + src/gapi/vulkan/buffers/GStagingRingBuffer.h + src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp + src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h + src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp + src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 5fa7c2416..e68fb7f24 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1568,25 +1568,25 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { } } - if (granSize > 0) { - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } - } - }, tbb::simple_partitioner()); - } - -// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { -// if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, -// renderPlan->frameDependentData); -// } +// if (granSize > 0) { +// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), +// [&](tbb::blocked_range r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { +// auto &m2Object = m2ToDraw[i]; +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } +// }, tbb::simple_partitioner()); // } + + for (auto &m2Object: renderPlan->m2Array.getDrawn()) { + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 714fdeb14..03da57150 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,11 +201,43 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", { { "aPosition", 0}, } }, +{ "m2Shader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, { "waterShader", { { "aPositionTransp", 0}, @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,46 +295,20 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,0,84}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -326,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -341,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,2048}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,24 +372,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,2048}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, + {0,2,12}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -407,14 +393,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -423,17 +409,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,2048}, {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -460,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, - {1,1,96}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -477,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -497,14 +492,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,2048}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -512,7 +509,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -533,15 +529,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -569,15 +565,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -605,14 +601,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -625,12 +622,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,15 +637,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,112}, + {0,0,2048}, }, { { - {2,2,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -662,12 +659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,24 +674,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,2048}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, + {0,1,12}, }, { { - {0,0,1}, - {1,6,6}, - {5,5,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -707,17 +695,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +710,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -762,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,2048}, + {0,0,128}, + {0,1,64}, }, { { @@ -835,15 +819,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,2048}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -871,15 +855,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -892,10 +876,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -907,15 +893,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -943,18 +929,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,2048}, - {1,1,64}, + {0,4,32}, }, { { - {0,0,1}, - {1,2,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,21 +950,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -990,15 +966,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,2048}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1009,24 +985,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,15 +1004,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1056,11 +1024,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1071,16 +1040,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,0,2048}, - {1,1,64}, + {0,1,80}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1088,6 +1055,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -1108,16 +1076,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,4,32}, + {0,0,2048}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1129,14 +1098,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1146,17 +1116,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,2048}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1168,21 +1137,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1192,16 +1152,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,2048}, + {1,1,96}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1213,12 +1174,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,17 +1189,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,2048}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1250,13 +1217,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1265,17 +1236,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {1,3,16384}, + {1,1,64}, + {0,0,2048}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,13 +1264,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1303,17 +1279,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,2048}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1325,13 +1299,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1341,24 +1314,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,16}, + {1,3,4096}, {0,0,2048}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1369,17 +1337,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1388,16 +1353,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,2048}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,15 +1389,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,0,2048}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1461,11 +1425,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {1,4,96}, {0,0,2048}, }, { @@ -1484,14 +1448,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1501,16 +1463,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,2048}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1537,17 +1500,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,5,96}, {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1558,13 +1528,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,16 +1547,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1593,13 +1575,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1608,16 +1591,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,32}, + {0,0,2048}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1629,13 +1613,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,24 +1637,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, {1,1,64}, {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {1,2,16}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1688,18 +1675,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, {0,0,2048}, }, { { {0,0,1}, - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1709,16 +1694,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {2,5, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1727,17 +1720,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,2048}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1766,35 +1766,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 5, { - {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, + {"drawFrustumShader", { { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1923,21 +1909,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"drawFrustumShader", { { - 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, + }}, + {"drawBBShader", { { - 4, { - {"_1_4_colors[0]", true, 0, 1, 4, 256}, + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, + }}, + {"adtLodShader", { { - 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, + 0, { + {"_0_0_uViewUp", true, 0, 1, 4, 0}, + {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, + {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, + {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, + {"_0_0_FogColor", true, 64, 1, 4, 0}, + {"_0_0_uNewFormula", false, 80, 1, 1, 0}, } }, + }}, + {"drawDepthShader", { { 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + {"_0_2_drawDepth", false, 0, 1, 1, 0}, + {"_0_2_uFarPlane", true, 4, 1, 1, 0}, + {"_0_2_uNearPlane", true, 8, 1, 1, 0}, } }, + }}, + {"adtShader", { { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + 2, { + {"_1_2_scaleFactorPerLayer", true, 0, 1, 4, 0}, + {"_1_2_animation_rotationPerLayer", false, 16, 1, 4, 0}, + {"_1_2_animation_speedPerLayer", false, 32, 1, 4, 0}, } }, { @@ -3405,29 +3410,25 @@ const std::unordered_map get_supported_extensions() { + VkResult result = VK_NOT_READY; + + /* + * From the link above: + * If `pProperties` is NULL, then the number of extensions properties + * available is returned in `pPropertyCount`. + * + * Basically, gets the number of extensions. + */ + uint32_t count = 0; + result = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); + if (result != VK_SUCCESS) { + return {}; + } + + std::vector extensionProperties(count); + + // Get the extensions + result = vkEnumerateInstanceExtensionProperties(nullptr, &count, extensionProperties.data()); + if (result != VK_SUCCESS) { + // Throw an exception or log the error + return {}; + } + + std::set extensions; + for (auto & extension : extensionProperties) { + extensions.insert(extension.extensionName); + } + + return extensions; +} + GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ enableValidationLayers = false; @@ -204,15 +237,26 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma createInfo.pNext = NULL; createInfo.pApplicationInfo = &appInfo; + { + auto supportedExtensions = get_supported_extensions(); + std::cout << "available instance extensions: " << std::endl; + for (auto &ext: supportedExtensions) { + std::cout << " " << ext << std::endl; + } + std::cout << std::endl; + } + char** extensions; int extensionCnt = 0; callback->getRequiredExtensions(extensions, extensionCnt); std::vector extensionsVec(extensions, extensions+extensionCnt); if (enableValidationLayers) { extensionsVec.push_back("VK_EXT_debug_report"); - extensionsVec.push_back("VK_EXT_debug_utils"); } + //TODO: disable in general case + extensionsVec.push_back("VK_EXT_debug_utils"); + createInfo.enabledExtensionCount = extensionsVec.size(); createInfo.ppEnabledExtensionNames = extensionsVec.data(); @@ -321,6 +365,10 @@ void GDeviceVLK::initialize() { //--------------- m_textureManager->initialize(); +//--------------- + + stagingRingBuffer = std::make_shared(this->shared_from_this()); + //--------------- createSwapChainAndFramebuffer(); @@ -341,6 +389,7 @@ void GDeviceVLK::initialize() { m_whitePixelTexture = createTexture(false, false); unsigned int ff = 0xffffffff; m_whitePixelTexture->getTexture()->loadData(1,1,&ff, ITextureFormat::itRGBA); + } void GDeviceVLK::setObjectName(uint64_t object, VkObjectType objectType, const char *name) @@ -837,6 +886,8 @@ float GDeviceVLK::getAnisLevel() { void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { ZoneScoped; + stagingRingBuffer->flushBuffers(); + this->waitInDrawStageAndDeps.beginMeasurement(); int currentDrawFrame = getDrawFrameNumber(); @@ -1101,24 +1152,24 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName return sharedPtr; } -HGBufferVLK GDeviceVLK::createUniformBuffer(size_t initialSize) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); +HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createSSBOBuffer(size_t initialSize, int recordSize) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); +HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createVertexBuffer(size_t initialSize) { - auto h_vertexBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize) { + auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); return h_vertexBuffer; } -HGBufferVLK GDeviceVLK::createIndexBuffer(size_t initialSize) { - auto h_indexBuffer = std::make_shared(this->shared_from_this(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize) { + auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); return h_indexBuffer; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 3f7b89c2d..139c741ff 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -105,10 +105,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); - HGBufferVLK createUniformBuffer(size_t size); - HGBufferVLK createSSBOBuffer(size_t size, int recordSize); - HGBufferVLK createVertexBuffer(size_t size); - HGBufferVLK createIndexBuffer(size_t size); + HGBufferVLK createUniformBuffer(const char * objName, size_t size); + HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize); + HGBufferVLK createVertexBuffer(const char * objName, size_t size); + HGBufferVLK createIndexBuffer(const char * objName, size_t size); HGVertexBufferBindings createVertexBufferBindings() override; HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) override; @@ -333,6 +333,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this stagingRingBuffer; + HGSamplableTexture m_blackPixelTexture = nullptr; HGSamplableTexture m_whitePixelTexture = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index 3f72b4fca..ab4492483 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -8,6 +8,7 @@ #include "../../interface/buffers/IBufferChunk.h" #include "GBufferVLK.h" +#include template class CBufferChunkVLK : public IBufferChunk { @@ -24,21 +25,23 @@ class CBufferChunkVLK : public IBufferChunk { ~CBufferChunkVLK() final = default; T &getObject() override { - return *(T*)pSubBuffer->getPointer(); + using SubBuffer = std::invoke_result_t::element_type; + + return *static_cast(((SubBuffer *)pSubBuffer)->getPointer()); }; void save() override { pSubBuffer->save(m_realSize); }; size_t getIndex() { - return subBuffer->getIndex(); + return pSubBuffer->getIndex(); } inline std::shared_ptr getSubBuffer() {return subBuffer;} operator const std::shared_ptr() const { return subBuffer; } private: int m_realSize = 0; - void *ptr = nullptr; + std::shared_ptr subBuffer = nullptr; IBufferVLK *pSubBuffer = nullptr; }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 70be4d0b3..51851678a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -71,7 +71,6 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { private: HGDeviceVLK m_device; int m_realSize = 0; - void *ptr = nullptr; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> subBuffers = {nullptr}; std::array pSubBuffers = {nullptr}; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h index 08b0f995c..c9e0e0d8e 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -81,7 +81,7 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe HGDeviceVLK m_device; int m_realSize = 0; int m_currentVersion = 0; - void *ptr = nullptr; + std::vector, IDevice::MAX_FRAMES_IN_FLIGHT>> subBufferVersions; std::unique_ptr iteratorUnique = nullptr; }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 6552e1c6b..d05754583 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -5,69 +5,31 @@ #include "GBufferVLK.h" #include "../vk_mem_alloc.h" -GBufferVLK::GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment) : m_device(device) { +GBufferVLK::GBufferVLK(const HGDeviceVLK &device, const char *objName, + const std::shared_ptr &ringBuff, + VkBufferUsageFlags usageFlags, int maxSize, int alignment) : m_device(device) { m_usageFlags = usageFlags; m_bufferSize = maxSize; m_alignment = alignment; + m_ringBuff = ringBuff; + + m_objName = objName; + //Create virtual buffer off this native buffer auto allocator = OffsetAllocator::Allocator(m_bufferSize); offsetAllocator = std::move(allocator); - createBuffer(currentBuffer); + m_gpuBuffer = std::make_shared(m_device, maxSize, m_usageFlags, m_objName.c_str()); } GBufferVLK::~GBufferVLK() { - destroyBuffer(currentBuffer); -} - -void GBufferVLK::createBuffer(BufferInternal &buffer) { - //Create new buffer - { - VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - vbInfo.size = m_bufferSize; - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo stagingAllocInfo = {}; - stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; - stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - stagingAllocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, - &buffer.stagingBuffer, - &buffer.stagingBufferAlloc, - &buffer.stagingBufferAllocInfo)); - } - { - // No need to flush stagingBuffer memory because CPU_ONLY memory is always HOST_COHERENT. - VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - vbInfo.size = m_bufferSize; - vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | m_usageFlags; - vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VmaAllocationCreateInfo stagingAllocInfo = {}; - stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO; - stagingAllocInfo.flags = 0; - ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, - &buffer.g_hBuffer, - &buffer.g_hBufferAlloc, nullptr)); - } } -void GBufferVLK::destroyBuffer(BufferInternal &buffer) { - auto l_device = m_device; - auto l_buffer = buffer; - m_device->addDeallocationRecord( - [l_buffer, l_device]() { - vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.stagingBuffer, l_buffer.stagingBufferAlloc); - vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer.g_hBuffer, l_buffer.g_hBufferAlloc); - } - ); -} -VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, int fakeSize, OffsetAllocator::Allocation &alloc) { + +VkResult GBufferVLK::allocateSubBuffer(int sizeInBytes, int fakeSize, OffsetAllocator::Allocation &alloc) { std::unique_lock lock(m_mutex, std::defer_lock); bool minAddressStrategy = sizeInBytes < fakeSize && fakeSize > 0; @@ -105,7 +67,7 @@ VkResult GBufferVLK::allocateSubBuffer(BufferInternal &buffer, int sizeInBytes, return result; } -void GBufferVLK::deallocateSubBuffer(BufferInternal &buffer, const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc) { +void GBufferVLK::deallocateSubBuffer(const OffsetAllocator::Allocation &alloc, const OffsetAllocator::Allocation &uiaAlloc) { //Destruction of this virtualBlock happens only in deallocation queue. //So it's safe to assume that even if the buffer's handle been changed by the time VirtualFree happens, //the virtualBlock was still not been free'd @@ -134,9 +96,24 @@ void GBufferVLK::uploadData(const void *data, int length) { resize(length); } - memcpy(currentBuffer.stagingBufferAllocInfo.pMappedData, data, length); + void * ptr = allocatePtr(0, length); - uploadFromStaging(0, 0, length); + memcpy(ptr, data, length); +} + +void *GBufferVLK::allocatePtr(int offset, int length) { +// std::unique_lock lock(m_mutex); + + VkBuffer staging; + int stage_offset; + auto *ptr = m_ringBuff->allocateNext(length, staging, stage_offset); + uploadRegionsPerStaging[staging].push_back({ + .srcOffset = static_cast(stage_offset), + .dstOffset = static_cast(offset), + .size = static_cast(length) + }); + + return ptr; } void GBufferVLK::resize(int newLength) { @@ -144,29 +121,12 @@ void GBufferVLK::resize(int newLength) { lock.lock(); auto oldSize = m_bufferSize; offsetAllocator.growSize(newLength - oldSize); - m_bufferSize = newLength; + lock.unlock(); +} - BufferInternal newBuffer; - createBuffer(newBuffer); - - //Reallocate subBuffers and copy their data - for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ - auto subBuffer = it->lock(); - if (subBuffer != nullptr) { - subBuffer->setParentDataPointer(newBuffer.stagingBufferAllocInfo.pMappedData); - } - } - memcpy((uint8_t *)newBuffer.stagingBufferAllocInfo.pMappedData, - (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData, - oldSize - ); - - destroyBuffer(currentBuffer); - currentBuffer = newBuffer; - - +void GBufferVLK::executeOnChangeForBufAndSubBuf() { for (std::list>::const_iterator it = currentSubBuffers.begin(); it != currentSubBuffers.end(); ++it){ auto subBuffer = it->lock(); if (subBuffer != nullptr) { @@ -175,7 +135,6 @@ void GBufferVLK::resize(int newLength) { } executeOnChange(); - lock.unlock(); } static inline uint8_t BitScanMSB(uint32_t mask) @@ -208,7 +167,7 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy VkResult res = VK_ERROR_OUT_OF_DEVICE_MEMORY; if (sizeInBytes < m_bufferSize) { - res = allocateSubBuffer(currentBuffer, sizeInBytes, fakeSize, alloc); + res = allocateSubBuffer(sizeInBytes, fakeSize, alloc); } if(res == VK_SUCCESS) @@ -219,18 +178,15 @@ std::shared_ptr GBufferVLK::getSubBuffer(int sizeInBy uiaAlloc = uiaAllocator.allocate(1); if (uiaAlloc.offset == OffsetAllocator::Allocation::NO_SPACE) { this->uiaAllocator.growSize(1000); - uploadIntervalActivatable.resize(uploadIntervalActivatable.size() + 1000); uiaAlloc = this->uiaAllocator.allocate(1); } } - uploadIntervalActivatable[uiaAlloc.offset] = {alloc.offset, static_cast(sizeInBytes), false}; auto subBuffer = std::make_shared( shared_from_this(), alloc, sizeInBytes, fakeSize, - uiaAlloc, - (uint8_t *)currentBuffer.stagingBufferAllocInfo.pMappedData+alloc.offset); + uiaAlloc); { @@ -255,93 +211,73 @@ void GBufferVLK::deleteSubBuffer(std::list>::const_ std::unique_lock lock(m_mutex); if (subBuffersize > 0) { - deallocateSubBuffer(currentBuffer, alloc, uiaAlloc); + deallocateSubBuffer(alloc, uiaAlloc); } currentSubBuffers.erase(it); } -void GBufferVLK::uploadFromStaging(int offset, int destOffset, int length) { - std::lock_guard lock(dataToBeUploadedMtx); - - VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); - vbCopyRegion.srcOffset = offset; - vbCopyRegion.dstOffset = destOffset; - vbCopyRegion.size = length; -} - void GBufferVLK::save(int length) { - uploadFromStaging(0, 0, length); -} -void GBufferVLK::addIntervalIndexForUpload(int index) { - this->uploadIntervalActivatable[index].requiresUpdate = true; } -MutexLockedVector GBufferVLK::getSubmitRecords() { +MutexLockedVector GBufferVLK::getSubmitRecords() { { std::lock_guard lock(dataToBeUploadedMtx); - std::vector intervals; - for (auto &interval : uploadIntervalActivatable) { - if (!interval.requiresUpdate) continue; - interval.requiresUpdate = false; + dataToBeUploaded.clear(); + if (m_gpuBuffer->size() != m_bufferSize) { + auto newGpuBuf = std::make_shared(m_device, m_bufferSize, m_usageFlags, m_objName.c_str()); - auto &newInterval = intervals.emplace_back(); - newInterval = interval; - } + auto ©Cmd = dataToBeUploaded.emplace_back(); + copyCmd.src = m_gpuBuffer->getBuffer(); + copyCmd.dst = newGpuBuf->getBuffer(); - if (lastSubmittedBufferSize != m_bufferSize) { - if (lastSubmittedBufferSize > 0) { - auto& newInterval = intervals.emplace_back(); - newInterval = { .start = 0, .size = lastSubmittedBufferSize }; - } + auto ®ion = copyCmd.copyRegions.emplace_back(); + region.size = m_gpuBuffer->size(); + region.srcOffset = 0; + region.dstOffset = 0; - lastSubmittedBufferSize = m_bufferSize; + m_gpuBuffer = newGpuBuf; + + executeOnChangeForBufAndSubBuf(); } - std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b ) -> bool { - return - a.start != b.start - ? a.start < b.start - : a.size < b.size; - }); - - if (!intervals.empty()) { - auto currInterval = intervals[0]; - const static auto calcIntervalEnd = [](decltype(currInterval) interval, int aligment) -> size_t { - return aligment > 0 ? - ((interval.start + interval.size + aligment - 1) / aligment) * aligment: - interval.start + interval.size; - }; - - size_t currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); - - for (int i = 1; i < intervals.size(); i++) { - auto &nextInterval = intervals[i]; - if (currIntervalEnd < nextInterval.start) { - VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); - vbCopyRegion.srcOffset = currInterval.start; - vbCopyRegion.dstOffset = currInterval.start; - vbCopyRegion.size = currInterval.size; - - currInterval = intervals[i]; - currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); - } else { - assert(nextInterval.start - currInterval.start >= 0); - currInterval.size = std::max(currInterval.size, (nextInterval.start - currInterval.start) + nextInterval.size); - currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); - } - } + for (auto &stagingRecord : uploadRegionsPerStaging) { + auto &intervals = stagingRecord.second; + std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) -> bool { + return + a.srcOffset != b.srcOffset + ? a.srcOffset < b.srcOffset + : a.size < b.size; + }); + + if (!intervals.empty()) { + auto currInterval = intervals[0]; + const static auto calcIntervalEnd = [](decltype(currInterval) interval, int aligment) -> size_t { +// return aligment > 0 ? +// ((interval.srcOffset + interval.size + aligment - 1) / aligment) * aligment : +// interval.srcOffset + interval.size; + return interval.srcOffset + interval.size; + }; + + size_t currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); + + auto &uploadData = dataToBeUploaded.emplace_back(); + uploadData.src = stagingRecord.first; + uploadData.dst = m_gpuBuffer->getBuffer(); - VkBufferCopy &vbCopyRegion = dataToBeUploaded.emplace_back(); - vbCopyRegion.srcOffset = currInterval.start; - vbCopyRegion.dstOffset = currInterval.start; - vbCopyRegion.size = currInterval.size; + uploadData.copyRegions = intervals; + } } + uploadRegionsPerStaging.clear(); } - return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); + return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); +} + +VkBuffer GBufferVLK::getGPUBuffer() { + return m_gpuBuffer->getBuffer(); } //---------------------------------------------------------------- @@ -351,13 +287,11 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { GBufferVLK::GSubBufferVLK::GSubBufferVLK(HGBufferVLK parent, OffsetAllocator::Allocation alloc, int size, int fakeSize, - OffsetAllocator::Allocation uiaAlloc, - uint8_t *dataPointer) : m_parentBuffer(parent) { + OffsetAllocator::Allocation uiaAlloc) : m_parentBuffer(parent) { m_alloc = alloc; m_uiaAlloc = uiaAlloc; m_size = size; m_fakeSize = fakeSize > 0 ? fakeSize : m_size; - m_dataPointer = dataPointer; } GBufferVLK::GSubBufferVLK::~GSubBufferVLK() { @@ -369,16 +303,15 @@ void GBufferVLK::GSubBufferVLK::uploadData(const void *data, int length) { std::cerr << "invalid dataSize" << std::endl; } - memcpy(m_dataPointer, data, length); - - m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); -// m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); + void * dataPointer = m_parentBuffer->allocatePtr(m_alloc.offset, m_size); + memcpy(dataPointer, data, length); } void *GBufferVLK::GSubBufferVLK::getPointer() { if (m_size <= 0) return nullptr; - return m_dataPointer; + void * dataPointer = m_parentBuffer->allocatePtr(m_alloc.offset, m_size); + return dataPointer; } void GBufferVLK::GSubBufferVLK::save(int length) { @@ -386,9 +319,6 @@ void GBufferVLK::GSubBufferVLK::save(int length) { std::cerr << "invalid dataSize" << std::endl; } if (m_size <= 0) return; - - m_parentBuffer->addIntervalIndexForUpload(m_uiaAlloc.offset); -// m_parentBuffer->uploadFromStaging(m_offset, m_offset, length); } size_t GBufferVLK::GSubBufferVLK::getSize() { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index fa197a025..800ca1962 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -12,6 +12,8 @@ class GDeviceVLK; typedef std::shared_ptr HGDeviceVLK; class GBufferVLK; +class BufferGpuVLK; +class GStagingRingBuffer; typedef std::shared_ptr HGBufferVLK; #include "../GDeviceVulkan.h" @@ -20,32 +22,33 @@ typedef std::shared_ptr HGBufferVLK; #include "../bindable/DSBindable.h" #include "../../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" +#include "gpu/BufferGpuVLK.h" +#include "GStagingRingBuffer.h" + +struct VulkanCopyCommands { + VkBuffer src; + VkBuffer dst; + std::vector copyRegions; +}; class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { friend class GDeviceVLK; class GSubBufferVLK; public: - GBufferVLK(const HGDeviceVLK &device, VkBufferUsageFlags usageFlags, int maxSize, int alignment = -1); + GBufferVLK(const HGDeviceVLK &device, const char *objName, const std::shared_ptr &ringBuff, + VkBufferUsageFlags usageFlags, int maxSize, int alignment = -1); ~GBufferVLK() override; //Doesn't make actual upload, only queues it. void uploadData(const void *, int length) override; - void uploadFromStaging(int offset, int destOffset, int length); - void addIntervalIndexForUpload(int index); - void *getPointer() override { return currentBuffer.stagingBufferAllocInfo.pMappedData;}; + void *getPointer() override { return allocatePtr(0, m_bufferSize);} //Submits data edited with Pointer void save(int length) override; - size_t getSize() override { return m_bufferSize;}; - VkBuffer getGPUBuffer() override { - return currentBuffer.g_hBuffer; - } - VkBuffer getCPUBuffer() { - return currentBuffer.stagingBuffer; - } + VkBuffer getGPUBuffer() override; size_t getOffset() override { return 0; }; @@ -53,34 +56,26 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords(); + MutexLockedVector getSubmitRecords(); void resize(int newLength); struct uploadInterval {size_t start; size_t size;}; - struct uploadIntervalActivatable : uploadInterval { - bool requiresUpdate = false; - }; + private: HGDeviceVLK m_device; + std::shared_ptr m_ringBuff; + + std::string m_objName; VkBufferUsageFlags m_usageFlags; int m_bufferSize; int m_alignment; - //Buffers - struct BufferInternal { - VkBuffer g_hBuffer = VK_NULL_HANDLE; - VmaAllocation g_hBufferAlloc = VK_NULL_HANDLE; - - VkBuffer stagingBuffer = VK_NULL_HANDLE; - VmaAllocation stagingBufferAlloc = VK_NULL_HANDLE; - VmaAllocationInfo stagingBufferAllocInfo; - - //Virtual block for suballocations - } currentBuffer; + //Buffers + std::unordered_map> uploadRegionsPerStaging; std::mutex dataToBeUploadedMtx; - std::vector dataToBeUploaded; + std::vector dataToBeUploaded; OffsetAllocator::Allocator offsetAllocator = OffsetAllocator::Allocator(1000); @@ -95,11 +90,10 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_thism_alignment : m_alloc.offset; }; - private: - void setParentDataPointer(void * ptr) { - m_dataPointer = ((uint8_t *) ptr) + m_alloc.offset; - } private: HGBufferVLK m_parentBuffer; @@ -125,17 +115,15 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this>::const_iterator m_iterator; }; - + std::shared_ptr m_gpuBuffer; std::list> currentSubBuffers; - std::vector uploadIntervals; OffsetAllocator::Allocator uiaAllocator = OffsetAllocator::Allocator(0); - std::vector uploadIntervalActivatable; // uploadCache = {}; public: @@ -145,11 +133,12 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_thisgetDrawFrameNumber(); + auto &vec = m_stagingBuffers[frame]; + + int startOffset = 0; + int bufferIndex = 0; + + { +// std::unique_lock l(m_mutex); + int currentIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; + int currentIndexAfter = (currentOffset + size) / STAGE_BUFFER_SIZE; + + if (currentIndex != currentIndexAfter) + currentOffset = currentIndexAfter * STAGE_BUFFER_SIZE; + + startOffset = currentOffset % STAGE_BUFFER_SIZE; + bufferIndex = currentIndexAfter; + + if (currentIndexAfter >= vec.size()) { + vec.emplace_back().staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); + } + + currentOffset += size; + } + + auto &staging = vec[bufferIndex]; + auto allocatedPtr = ((uint8_t *)staging.cpuBuffer.data()) + startOffset; + o_staging = staging.staging->getBuffer(); + o_offset = startOffset; + + return allocatedPtr; +} + +void GStagingRingBuffer::flushBuffers() { + auto frame = m_device->getDrawFrameNumber(); + auto &vec = m_stagingBuffers[frame]; + + int maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; + + for (int i = 0; i < maxIndex; i++) { + auto &stagingRec = vec[i]; + memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), STAGE_BUFFER_SIZE); + } + if (currentOffset > 0) { + auto &stagingRec = vec[maxIndex]; + memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); + } + + int prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; + currentOffset = 0; + + vec.resize(std::min(prevMaxIndex, vec.size())); +} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h new file mode 100644 index 000000000..e16e975c4 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -0,0 +1,36 @@ +// +// Created by Deamon on 9/8/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GSTAGINGRINGBUFFER_H +#define AWEBWOWVIEWERCPP_GSTAGINGRINGBUFFER_H + +class BufferStagingVLK; + +#include +#include "../GDeviceVulkan.h" +#include "gpu/BufferStagingVLK.h" + +class GStagingRingBuffer { + static constexpr int STAGE_BUFFER_SIZE = 20*1024*1024; +public: + GStagingRingBuffer(const HGDeviceVLK &device) : m_device(device) {}; + + void* allocateNext(int size, VkBuffer &o_staging, int &o_offset); + + void flushBuffers(); +private: + HGDeviceVLK m_device; + + std::mutex m_mutex; + uint32_t currentOffset = 0; + struct BufferAndCPU { + std::shared_ptr staging; + std::array cpuBuffer; + }; + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_stagingBuffers; +}; + + +#endif //AWEBWOWVIEWERCPP_GSTAGINGRINGBUFFER_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp new file mode 100644 index 000000000..147164133 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp @@ -0,0 +1,36 @@ +// +// Created by Deamon on 9/12/2023. +// + +#include "BufferGpuVLK.h" + +BufferGpuVLK::BufferGpuVLK(const HGDeviceVLK &device, int size, VkBufferUsageFlags usageFlags, const char *obj_name) : m_device(device) { + m_size = size; + + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = m_size; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | usageFlags; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo stagingAllocInfo = {}; + stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + stagingAllocInfo.flags = 0; + ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, + &m_hBuffer, + &m_hBufferAlloc, nullptr)); + + device->setObjectName((uint64_t) m_hBuffer, VK_OBJECT_TYPE_BUFFER, obj_name); + +} + +BufferGpuVLK::~BufferGpuVLK() { + //This thing MUST ONLY ALLOCATE FUTURE DEALLOC + auto l_device = m_device; + auto l_buffer = m_hBuffer; + auto l_bufferAlloc = m_hBufferAlloc; + m_device->addDeallocationRecord( + [l_buffer, l_device, l_bufferAlloc]() { + vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer, l_bufferAlloc); + } + ); +} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h new file mode 100644 index 000000000..04057f154 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h @@ -0,0 +1,36 @@ +// +// Created by Deamon on 9/12/2023. +// + +#ifndef AWEBWOWVIEWERCPP_BUFFERGPUVLK_H +#define AWEBWOWVIEWERCPP_BUFFERGPUVLK_H + +#include + +class GDeviceVLK; +typedef std::shared_ptr HGDeviceVLK; + +#include "../../GDeviceVulkan.h" + +class BufferGpuVLK { +public: + BufferGpuVLK(const HGDeviceVLK &device, int size, VkBufferUsageFlags usageFlags, const char *obj_name); + ~BufferGpuVLK(); + + uint32_t size() { + return m_size; + } + + VkBuffer getBuffer() { + return m_hBuffer; + } +private: + HGDeviceVLK m_device; + + VkBuffer m_hBuffer = VK_NULL_HANDLE; + VmaAllocation m_hBufferAlloc = VK_NULL_HANDLE; + uint32_t m_size; +}; + + +#endif //AWEBWOWVIEWERCPP_BUFFERGPUVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp new file mode 100644 index 000000000..038381ef6 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp @@ -0,0 +1,38 @@ +// +// Created by Deamon on 9/12/2023. +// + +#include "BufferStagingVLK.h" + +BufferStagingVLK::BufferStagingVLK(const HGDeviceVLK &device, int size) : m_device(device) { + { + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + vbInfo.size = size; + vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo stagingAllocInfo = {}; + stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; //TODO: + + ERR_GUARD_VULKAN(vmaCreateBuffer(device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, + &m_stagingBuffer, + &m_stagingBufferAlloc, + &m_stagingBufferAllocInfo)); + } +} + +BufferStagingVLK::~BufferStagingVLK() { + auto l_device = m_device; + auto l_buffer = m_stagingBuffer; + auto l_bufferAlloc = m_stagingBufferAlloc; + m_device->addDeallocationRecord( + [l_buffer, l_device, l_bufferAlloc]() { + vmaDestroyBuffer(l_device->getVMAAllocator(), l_buffer, l_bufferAlloc); + } + ); +} + +void *BufferStagingVLK::getPointer() { + return m_stagingBufferAllocInfo.pMappedData; +} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h new file mode 100644 index 000000000..772f5a94c --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h @@ -0,0 +1,26 @@ +// +// Created by Deamon on 9/12/2023. +// + +#ifndef AWEBWOWVIEWERCPP_BUFFERSTAGINGVLK_H +#define AWEBWOWVIEWERCPP_BUFFERSTAGINGVLK_H + +#include "../../GDeviceVulkan.h" + +class BufferStagingVLK { +public: + BufferStagingVLK(const HGDeviceVLK &device, int size); + ~BufferStagingVLK(); +private: + HGDeviceVLK m_device; + + VkBuffer m_stagingBuffer = VK_NULL_HANDLE; + VmaAllocation m_stagingBufferAlloc = VK_NULL_HANDLE; + VmaAllocationInfo m_stagingBufferAllocInfo; +public: + void *getPointer(); + VkBuffer getBuffer() {return m_stagingBuffer;}; +}; + + +#endif //AWEBWOWVIEWERCPP_BUFFERSTAGINGVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 35e689b55..50eb46ab0 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -204,11 +204,13 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff if (submitRecords.get().empty()) return; - vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, - bufferVLK->getCPUBuffer(), - bufferVLK->getGPUBuffer(), - submitRecords.get().size(), - submitRecords.get().data()); + for (auto &submitRecord : submitRecords.get()) { + vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, + submitRecord.src, + submitRecord.dst, + submitRecord.copyRegions.size(), + submitRecord.copyRegions.data()); + } } void CmdBufRecorder::setViewPort(ViewportType viewportType) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 92095bfd7..31bf6ed36 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -37,17 +37,17 @@ static const ShaderConfig m2ForwardShaderConfig = { MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { - iboBuffer = m_device->createIndexBuffer(1024*1024); - - vboM2Buffer = m_device->createVertexBuffer(1024*1024); - vboPortalBuffer = m_device->createVertexBuffer(1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); - vboM2RibbonBuffer = m_device->createVertexBuffer(1024*1024); - vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); - vboWMOBuffer = m_device->createVertexBuffer(1024*1024); - vboWaterBuffer = m_device->createVertexBuffer(1024*1024); - vboSkyBuffer = m_device->createVertexBuffer(1024*1024); - vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); + + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); + vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); + vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200); { const float epsilon = 0.f; @@ -61,8 +61,8 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C 0, 1, 2, 2, 1, 3 }; - m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); - m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); @@ -72,10 +72,10 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_drawQuadVao->save(); } - uboBuffer = m_device->createUniformBuffer(1024*1024); - uboStaticBuffer = m_device->createUniformBuffer(1024*1024); + uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024); + uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024); - uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); + uboM2BoneMatrixBuffer = m_device->createUniformBuffer("Scene_UBO_M2BoneMats", 5000*64); m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 72fbca5a2..1d4575509 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -41,17 +41,17 @@ static const ShaderConfig m2VisShaderConfig = { MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { - iboBuffer = m_device->createIndexBuffer(1024*1024); - - vboM2Buffer = m_device->createVertexBuffer(1024*1024); - vboPortalBuffer = m_device->createVertexBuffer(1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer(1024*1024); - vboM2RibbonBuffer = m_device->createVertexBuffer(1024*1024); - vboAdtBuffer = m_device->createVertexBuffer(3*1024*1024); - vboWMOBuffer = m_device->createVertexBuffer(1024*1024); - vboWaterBuffer = m_device->createVertexBuffer(1024*1024); - vboSkyBuffer = m_device->createVertexBuffer(1024*1024); - vboWMOGroupAmbient = m_device->createVertexBuffer(16*200); + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); + + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); + vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); + vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200); { const float epsilon = 0.f; @@ -65,35 +65,35 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic 0, 1, 2, 2, 1, 3 }; - m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); - m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); - m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); - m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); - - m_drawQuadVao = m_device->createVertexBufferBindings(); - m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); - m_drawQuadVao->setIndexBuffer(m_iboQuad); - m_drawQuadVao->save(); +// m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); +// m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); +// m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); +// m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); +// +// m_drawQuadVao = m_device->createVertexBufferBindings(); +// m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); +// m_drawQuadVao->setIndexBuffer(m_iboQuad); +// m_drawQuadVao->save(); } //Create m2 shaders - { - m2Buffers.placementMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(M2::PlacementMatrix)); - m2Buffers.boneMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); - m2Buffers.m2Colors = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); - m2Buffers.textureWeights = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); - m2Buffers.textureMatrices = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); - m2Buffers.modelVertexDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS)); - m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::modelWideBlockPS)); - - m2Buffers.m2InstanceData = m_device->createSSBOBuffer(1024*1024, sizeof(M2::M2InstanceRecordBindless)); - m2Buffers.meshWideBlocks = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); - } - - uboBuffer = m_device->createUniformBuffer(1024*1024); - uboStaticBuffer = m_device->createUniformBuffer(1024*1024); +// { +// m2Buffers.placementMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(M2::PlacementMatrix)); +// m2Buffers.boneMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); +// m2Buffers.m2Colors = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); +// m2Buffers.textureWeights = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); +// m2Buffers.textureMatrices = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); +// m2Buffers.modelVertexDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS)); +// m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::modelWideBlockPS)); +// +// m2Buffers.m2InstanceData = m_device->createSSBOBuffer(1024*1024, sizeof(M2::M2InstanceRecordBindless)); +// m2Buffers.meshWideBlocks = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); +// } - uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); +// uboBuffer = m_device->createUniformBuffer(1024*1024); +// uboStaticBuffer = m_device->createUniformBuffer(1024*1024); +// +// uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); From 8186611e76ac0e5262a0fac077e9de78acf8709d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 31 Jul 2023 03:49:11 +0300 Subject: [PATCH 109/212] - update in separate thread part 1 --- src/ui/FrontendUI.cpp | 9 ++- .../src/engine/managers/CRibbonEmitter.cpp | 6 +- .../managers/particles/particleEmitter.cpp | 12 ++-- .../src/engine/objects/ViewsObjects.cpp | 10 ++-- .../src/engine/objects/ViewsObjects.h | 1 + .../src/engine/objects/m2/m2Object.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 40 +++++++------ wowViewerLib/src/gapi/interface/IDevice.cpp | 9 +++ wowViewerLib/src/gapi/interface/IDevice.h | 5 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 25 ++++---- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 5 +- .../vulkan/buffers/GBufferChunkDynamicVLK.h | 14 ++--- .../buffers/GBufferChunkDynamicVersionedVLK.h | 14 ++--- .../vulkan/buffers/GStagingRingBuffer.cpp | 4 +- wowViewerLib/src/renderer/IRenderParameters.h | 22 +++++-- .../src/renderer/frame/SceneComposer.cpp | 58 +++++++++---------- .../src/renderer/frame/SceneComposer.h | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 15 ++++- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 2 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 2 +- .../src/renderer/vulkan/IRenderFunctionVLK.h | 8 ++- 21 files changed, 154 insertions(+), 112 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 284c9adf9..326901f6a 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1685,6 +1685,10 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do if (m_minimapGenerationWindow != nullptr) { m_minimapGenerationWindow->process(); } + auto l_device = m_api->hDevice; + auto processingFrame = l_device->getProcessingFrameNumber(); + auto updateFrameNumberLambda = [l_device](unsigned int frame) -> void {l_device->setCurrentProcessingFrameNumber(frame);}; + HFrameScenario scenario = std::make_shared(); { @@ -1725,7 +1729,8 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do // needToMakeScreenshot = false; // } - scenario->cullFunctions.push_back(m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput)); + scenario->cullFunctions.push_back( + m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput, processingFrame, updateFrameNumberLambda)); } auto uiFrameInput = std::make_shared>(); @@ -1735,7 +1740,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto clearColor = m_api->getConfig()->clearColor; - scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput)); + scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput, processingFrame, updateFrameNumberLambda)); } diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index fea97daa5..e25c29e18 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -840,7 +840,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV } void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { - auto &currFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; if (currFrame.isDead) return; for (int i = 0; i < currFrame.m_meshes.size(); i++) { @@ -861,7 +861,7 @@ void CRibbonEmitter::fitBuffersToSize() { size_t sizeInd = m_gxIndices.size() * sizeof(uint16_t); size_t sizeVert = m_gxVertices.size() * sizeof(CRibbonVertex); - int frameNum = m_api->hDevice->getDrawFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; auto iboBufferDynamic = frame[frameNum].m_indexVBO; @@ -875,7 +875,7 @@ void CRibbonEmitter::fitBuffersToSize() { } void CRibbonEmitter::updateBuffers() { - auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; currentFrame.isDead = this->IsDead(); if (currentFrame.isDead) return; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index adb7923b4..47da2031f 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -471,7 +471,7 @@ void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathf this->InternalUpdate(delta); } - const HGParticleMesh &mesh = frame[m_api->hDevice->getDrawFrameNumber()].m_mesh; + const HGParticleMesh &mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber()].m_mesh; mesh->setSortDistance(m_currentBonePos); } @@ -653,7 +653,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { this->calculateQuadToViewEtc(nullptr, viewMatrix); // FrameOfRerefence mat is null since it's not used - int frameNum = m_api->hDevice->getDrawFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); @@ -681,7 +681,7 @@ void ParticleEmitter::fitBuffersToSize() { if ((m_data->old.flags & 0x60000) == 0x60000) { maxFutureSize *= 2; } - int frameNum = m_api->hDevice->getDrawFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; if (maxFutureSize > vboBufferDynamic->getSize()) { @@ -1118,11 +1118,11 @@ ParticleEmitter::BuildQuadT3( void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; if (!currentFrame.active) return; - HGParticleMesh mesh = frame[m_api->hDevice->getDrawFrameNumber()].m_mesh; + HGParticleMesh mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber()].m_mesh; if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { @@ -1133,7 +1133,7 @@ void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vect void ParticleEmitter::updateBuffers() { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getDrawFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; currentFrame.active = szVertexCnt > 0; if (!currentFrame.active) diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index dac070328..4d2e9b168 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -34,10 +34,6 @@ void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool rende wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); } } - - for (auto const &mesh : m_portalMeshes) { - transparentMeshes.push_back(mesh); - } } void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos) { @@ -161,6 +157,12 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc } } +void GeneralView::collectPortalMeshes(std::vector &transparentMeshes) { + for (auto const &mesh : m_portalMeshes) { + transparentMeshes.push_back(mesh); + } +} + void InteriorView::setM2Lights(std::shared_ptr &m2Object) { if (ownerGroupWMO == nullptr || !ownerGroupWMO->getIsLoaded()) return; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 4f271d13a..af78fa7b1 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -53,6 +53,7 @@ class GeneralView { std::vector portals; virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes); + void collectPortalMeshes(std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 163c18aad..2c1f7eb4b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1666,7 +1666,7 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorhDevice->getDrawFrameNumber(); + int frame = m_api->hDevice->getCurrentProcessingFrameNumber(); auto const &dynMeshFrame = dynMesh[frame]; @@ -1988,7 +1988,7 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) void M2Object::updateDynamicMeshes() { auto rootMatInverse = bonesMatrices[0].Inverse(); - auto frameNum = m_api->hDevice->getDrawFrameNumber(); + auto frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); for (auto &dynamicMesh: dynamicMeshes) { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index e68fb7f24..625efe0e4 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1522,6 +1522,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { void Map::updateBuffers(const HMapRenderPlan &renderPlan) { ZoneScoped; + if (skyMeshMat0x4) { auto &meshblockVS = skyMeshMat0x4->m_skyColors->getObject(); auto EndFogColor = !renderPlan->frameDependentData->fogResults.empty() ? @@ -1543,6 +1544,7 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { meshblockVS.skyColor[5] = EndFogColorV4_2; skyMeshMat0x4->m_skyColors->save(); } + if (skyMeshMat) { auto &meshblockVS = skyMeshMat->m_skyColors->getObject(); meshblockVS.skyColor[0] = renderPlan->frameDependentData->skyColors.SkyTopColor; @@ -1568,25 +1570,29 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { } } -// if (granSize > 0) { -// tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), -// [&](tbb::blocked_range r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto &m2Object = m2ToDraw[i]; -// if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, -// renderPlan->frameDependentData); -// } -// } -// }, tbb::simple_partitioner()); -// } - for (auto &m2Object: renderPlan->m2Array.getDrawn()) { - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } + if (granSize > 0) { + auto l_device = m_api->hDevice; + auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + l_device->setCurrentProcessingFrameNumber(processingFrame); + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } + }, tbb::simple_partitioner()); } + +// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/gapi/interface/IDevice.cpp b/wowViewerLib/src/gapi/interface/IDevice.cpp index 44c78e170..4aa306083 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.cpp +++ b/wowViewerLib/src/gapi/interface/IDevice.cpp @@ -65,4 +65,13 @@ std::string IDevice::insertAfterVersion(std::string &glslShaderString, std::stri } } +thread_local unsigned int processingFrame = 0; +unsigned int IDevice::getCurrentProcessingFrameNumber() { + return processingFrame; +} + +void IDevice::setCurrentProcessingFrameNumber(unsigned int frameNumber) { + processingFrame = frameNumber; +} + diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 4feca653d..91181beda 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -164,9 +164,12 @@ class IDevice { virtual int getUploadSize() {return 0;}; virtual unsigned int getFrameNumber() = 0; - virtual unsigned int getDrawFrameNumber() = 0; + virtual unsigned int getProcessingFrameNumber() = 0; virtual void increaseFrameNumber() = 0; + unsigned int getCurrentProcessingFrameNumber(); + void setCurrentProcessingFrameNumber(unsigned int frameNumber); + virtual void submitDrawCommands() {}; virtual void startUpdateForNextFrame() {}; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index da9fa01cb..27c73f922 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -855,20 +855,10 @@ void GDeviceVLK::createSyncObjects() { } -unsigned int GDeviceVLK::getDrawFrameNumber() { +unsigned int GDeviceVLK::getProcessingFrameNumber() { return m_frameNumber % MAX_FRAMES_IN_FLIGHT; } -unsigned int GDeviceVLK::getUpdateFrameNumber() { - return (m_frameNumber + 1) % MAX_FRAMES_IN_FLIGHT; -} -unsigned int GDeviceVLK::getOcclusionFrameNumber() { - return (m_frameNumber + 2) % MAX_FRAMES_IN_FLIGHT; -} -unsigned int GDeviceVLK::getCullingFrameNumber() { - return (m_frameNumber + 3) % MAX_FRAMES_IN_FLIGHT; -} - void GDeviceVLK::increaseFrameNumber() { m_frameNumber++; } @@ -889,7 +879,12 @@ void GDeviceVLK::drawFrame(const std::vector> & stagingRingBuffer->flushBuffers(); this->waitInDrawStageAndDeps.beginMeasurement(); - int currentDrawFrame = getDrawFrameNumber(); + + int currentDrawFrame = getCurrentProcessingFrameNumber(); + if (renderFuncs.size() > 0) { + currentDrawFrame = renderFuncs[0]->getProcessingFrame(); + setCurrentProcessingFrameNumber(currentDrawFrame); + } auto &uploadCmdBuf = uploadCommandBuffers[currentDrawFrame]; auto &swapChainCmdBuf = swapChainCommandBuffers[currentDrawFrame]; @@ -943,7 +938,7 @@ void GDeviceVLK::drawFrame(const std::vector> & auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->execute(uploadCmd, frameBufCmd, swapChainCmd); + dynamic_cast(renderFuncs[i].get())->execute(*this, uploadCmd, frameBufCmd, swapChainCmd); } } } @@ -993,7 +988,7 @@ void GDeviceVLK::drawFrame(const std::vector> & } RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd) { - int currentDrawFrame = getDrawFrameNumber(); + int currentDrawFrame = getCurrentProcessingFrameNumber(); //Begin render pass for swap CMD buffer. //It used to execute secondary command buffer, but now this is altered @@ -1009,7 +1004,7 @@ RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBu } void GDeviceVLK::getNextSwapImageIndex(uint32_t &imageIndex) { - int currentDrawFrame = getDrawFrameNumber(); + int currentDrawFrame = getCurrentProcessingFrameNumber(); VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 139c741ff..79bf7d541 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -66,10 +66,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this get_enabled_extensions(); unsigned int getFrameNumber() override { return m_frameNumber; }; - unsigned int getUpdateFrameNumber() ; - unsigned int getCullingFrameNumber() ; - unsigned int getOcclusionFrameNumber() ; - unsigned int getDrawFrameNumber() override; + unsigned int getProcessingFrameNumber() override; bool getIsRenderbufferSupported() override {return true;} diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 51851678a..86df7918b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -36,23 +36,23 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { }; void *getPointer() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return pSubBuffers[index]->getPointer(); }; void save(int length) override{ - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); pSubBuffers[index]->save(m_realSize); }; VkBuffer getGPUBuffer() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return pSubBuffers[index]->getGPUBuffer(); } size_t getOffset() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return pSubBuffers[index]->getOffset(); } size_t getIndex() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return pSubBuffers[index]->getIndex(); } @@ -60,11 +60,11 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { return m_realSize; } T &getObject() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return *(T*)pSubBuffers[index]->getPointer(); }; void save() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); pSubBuffers[index]->save(m_realSize); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h index c9e0e0d8e..8a40992fb 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -38,24 +38,24 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe void uploadData(const void *, int length) override { }; void *getPointer() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return subBufferVersions[m_currentVersion][index]->getPointer(); }; void save(int length) override{ - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); subBufferVersions[m_currentVersion][index]->save(m_realSize); }; VkBuffer getGPUBuffer() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return subBufferVersions[m_currentVersion][index]->getGPUBuffer(); } size_t getOffset() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return subBufferVersions[m_currentVersion][index]->getOffset(); } size_t getIndex() override { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return subBufferVersions[m_currentVersion][index]->getIndex(); } @@ -69,11 +69,11 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe T &getObject(int version) override { if (version > subBufferVersions.size()) throw "wrong version"; - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); return *(T*)subBufferVersions[version][index]->getPointer(); }; void saveVersion(int version) { - auto index = m_device->getUpdateFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber(); subBufferVersions[version][index]->save(m_realSize); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index 3cd3db6bd..81521feef 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -5,7 +5,7 @@ #include "GStagingRingBuffer.h" void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_offset) { - auto frame = m_device->getDrawFrameNumber(); + auto frame = m_device->getCurrentProcessingFrameNumber(); auto &vec = m_stagingBuffers[frame]; int startOffset = 0; @@ -38,7 +38,7 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of } void GStagingRingBuffer::flushBuffers() { - auto frame = m_device->getDrawFrameNumber(); + auto frame = m_device->getCurrentProcessingFrameNumber(); auto &vec = m_stagingBuffers[frame]; int maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index 7381e6a97..95e1de2a3 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -7,11 +7,17 @@ #include #include +#include #include "frame/FrameInputParams.h" class IRenderFunction { public: virtual ~IRenderFunction() = default; + + void setProcessingFrame(unsigned int frame) { currentProcessingFrame = frame; }; + unsigned int getProcessingFrame() const { return currentProcessingFrame; } +private: + unsigned int currentProcessingFrame = 0; }; typedef std::function()> SceneUpdateLambda; typedef std::function CullLambda; @@ -27,14 +33,22 @@ class IRendererParameters : public std::enable_shared_from_this getLastCreatedPlan() = 0; - CullLambda createCullUpdateRenderChain(const std::shared_ptr> &frameInputParams) { + CullLambda createCullUpdateRenderChain(const std::shared_ptr> &frameInputParams, + int currentFrame, std::function updateProcessingFrame) { auto this_s = this->shared_from_this(); + auto l_currentFrame = currentFrame; + auto l_updateProcessingFrame = std::move(updateProcessingFrame); - return [frameInputParams, this_s]() -> SceneUpdateLambda { + return [frameInputParams, this_s, l_currentFrame, l_updateProcessingFrame]() -> SceneUpdateLambda { + l_updateProcessingFrame(l_currentFrame); std::shared_ptr framePlan = this_s->processCulling(frameInputParams); - return [framePlan, frameInputParams, this_s]() -> std::unique_ptr { - return this_s->update(frameInputParams, framePlan); + return [framePlan, frameInputParams, this_s, l_currentFrame, l_updateProcessingFrame]() -> std::unique_ptr { + l_updateProcessingFrame(l_currentFrame); + + auto renderFunc = this_s->update(frameInputParams, framePlan); + renderFunc->setProcessingFrame(l_currentFrame); + return renderFunc; }; }; } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 2249d8ab5..a40a98f18 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -58,36 +58,31 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon } })); -// updateThread = std::thread(([&]() { -// using namespace std::chrono_literals; -// FrameCounter frameCounter; -// -// while (!this->m_isTerminating) { -// auto frameScenario = updateInput.waitForNewInput(); -// if (m_isTerminating) -// continue; -// -// frameCounter.beginMeasurement(); -// -// //Do the culling and make function for further pipeline -// std::shared_ptr>> renderFuncs = std::make_shared(); -// if (frameScenario != nullptr) { -// consumeUpdate(frameScenario, *renderFuncs); -// } -// -// //Pass the culling result down the pipeline -// drawInput.pushInput(renderFuncs); -// -// frameCounter.endMeasurement(); -//// m_apiContainer->getConfig()->cullingTimePerFrame = frameCounter.getTimePerFrame(); -// } -// })); + updateThread = std::thread(([&]() { + using namespace std::chrono_literals; + setThreadName("Update"); + + while (!this->m_isTerminating) { + auto frameScenario = updateInput.waitForNewInput(); + if (m_isTerminating) + continue; + + //Do the culling and make function for further pipeline + std::shared_ptr>> renderFuncs = std::make_shared(); + if (frameScenario != nullptr) { + consumeUpdate(frameScenario, *renderFuncs); + } + + //Pass the culling result down the pipeline + drawInput.pushInput(renderFuncs); + } + })); } //Insert one temp element for balancing updateInput.pushInput(nullptr); - drawInput.pushInput(nullptr); +// drawInput.pushInput(nullptr); drawInput.pushInput(nullptr); } @@ -134,17 +129,16 @@ void SceneComposer::draw(HFrameScenario frameScenario) { m_apiContainer->requestProcessor->processRequests(10); consumeUpdate(frameScenario,renderFuncs); consumeDraw(renderFuncs); - } else { cullingInput.pushInput(frameScenario); { // if (!m_firstFrame) { - auto frameScenario = updateInput.waitForNewInput(); -// auto renderFuncs = drawInput.waitForNewInput(); - std::shared_ptr>> renderFuncs = std::make_shared(); - if (frameScenario != nullptr) { - consumeUpdate(frameScenario, *renderFuncs); - } +// auto frameScenario = updateInput.waitForNewInput(); + auto renderFuncs = drawInput.waitForNewInput(); +// std::shared_ptr>> renderFuncs = std::make_shared(); +// if (frameScenario != nullptr) { +// consumeUpdate(frameScenario, *renderFuncs); +// } if (renderFuncs != nullptr) { consumeDraw(*renderFuncs); } diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 4a5f18c07..2d06191da 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -50,6 +50,7 @@ class SceneComposer { drawInput.pushInput(nullParam); } cullingThread.join(); + updateThread.join(); loadingResourcesThread.join(); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 31bf6ed36..853601612 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -654,6 +654,19 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha skyMesh0x4, mapScene, framePlan, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { +// //Do postLoad here. So creation of stuff is done from main thread +// mapScene->doPostLoad(l_this, framePlan); +// //And add portal meshes +// for (auto &view : framePlan->viewsHolder.getInteriorViews()) { +// view->collectPortalMeshes(*transparentMeshes); +// } +// { +// auto exteriorView = framePlan->viewsHolder.getExterior(); +// if (exteriorView != nullptr) { +// exteriorView->collectPortalMeshes(*transparentMeshes); +// } +// } + // --------------------- // Upload stuff @@ -688,7 +701,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getDrawFrameNumber()], + l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber()], frameInputParams->viewPortDimensions.mins, frameInputParams->viewPortDimensions.maxs, vec4ToArr3(frameInputParams->frameParameters->clearColor), diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 1d4575509..e94856115 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -756,7 +756,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getDrawFrameNumber()], + l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber()], frameInputParams->viewPortDimensions.mins, frameInputParams->viewPortDimensions.maxs, vec4ToArr3(frameInputParams->frameParameters->clearColor), diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 5191a4ac3..d116b6f5d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -100,7 +100,7 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapCha const std::shared_ptr &finalRenderPass, ViewPortDimensions &viewPortDimensions) { ZoneScoped; - auto currentFrame = m_device->getDrawFrameNumber(); + auto currentFrame = m_device->getCurrentProcessingFrameNumber(); { for (int i = 0; i < GAUSS_PASS_COUNT; i++) { diff --git a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h index 503983aa6..32986dd36 100644 --- a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h +++ b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h @@ -11,8 +11,8 @@ class IRenderFunctionVLK : public IRenderFunction { public: ~IRenderFunctionVLK() override = default; - - virtual void execute(CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) = 0; +public: + virtual void execute(IDevice &device, CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) = 0; }; template @@ -21,7 +21,9 @@ class TemplateIRenderFunctionVLK : public IRenderFunctionVLK { TemplateIRenderFunctionVLK(T a) : m_a(std::move(a)){ }; - void execute(CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) override { + void execute(IDevice &device, CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) override { + //Hack through currently processing frame + device.setCurrentProcessingFrameNumber(getProcessingFrame()); m_a(uploadCmd, frameBufCmd, swapChainCmd); }; private: From 564e9da78226d8975659c5272d6910939ed2ffd0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 11 Aug 2023 18:44:06 +0300 Subject: [PATCH 110/212] - update in the thread, temp commit --- wowViewerLib/src/gapi/interface/IDevice.h | 3 ++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 21 ++++++++++++------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 14 +++++++++++-- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 1 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 91181beda..fea2ad980 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -151,7 +151,7 @@ enum class GDeviceType { class IDevice { public: - static const constexpr uint8_t MAX_FRAMES_IN_FLIGHT = 2; + static const constexpr uint8_t MAX_FRAMES_IN_FLIGHT = 3; virtual ~IDevice() {}; @@ -205,6 +205,7 @@ class IDevice { static std::string insertAfterVersion(std::string &glslShaderString, std::string stringToPaste); virtual void addDeallocationRecord(std::function callback) {}; + virtual void addBufferDeallocationRecord(std::function callback) {}; virtual int getCurrentTextureAllocated() {return 0;} }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 27c73f922..37640b7c0 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -880,11 +880,7 @@ void GDeviceVLK::drawFrame(const std::vector> & this->waitInDrawStageAndDeps.beginMeasurement(); - int currentDrawFrame = getCurrentProcessingFrameNumber(); - if (renderFuncs.size() > 0) { - currentDrawFrame = renderFuncs[0]->getProcessingFrame(); - setCurrentProcessingFrameNumber(currentDrawFrame); - } + int currentDrawFrame = getProcessingFrameNumber(); auto &uploadCmdBuf = uploadCommandBuffers[currentDrawFrame]; auto &swapChainCmdBuf = swapChainCommandBuffers[currentDrawFrame]; @@ -988,7 +984,7 @@ void GDeviceVLK::drawFrame(const std::vector> & } RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd) { - int currentDrawFrame = getCurrentProcessingFrameNumber(); + int currentDrawFrame = getProcessingFrameNumber(); //Begin render pass for swap CMD buffer. //It used to execute secondary command buffer, but now this is altered @@ -1004,7 +1000,7 @@ RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBu } void GDeviceVLK::getNextSwapImageIndex(uint32_t &imageIndex) { - int currentDrawFrame = getCurrentProcessingFrameNumber(); + int currentDrawFrame = getProcessingFrameNumber(); VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); @@ -1267,6 +1263,17 @@ void GDeviceVLK::executeDeallocators() { listOfDeallocators.pop_front(); } } +void GDeviceVLK::executeBufferDeallocators() { + std::lock_guard lock(m_listOfBufferDeallocatorsAccessMtx); + while ((!listOfBufferDeallocators.empty()) && (listOfBufferDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { + auto stuff = listOfBufferDeallocators.front(); + if (stuff.callback != nullptr) { + stuff.callback(); + } + + listOfBufferDeallocators.pop_front(); + } +} std::shared_ptr GDeviceVLK::getRenderPass( const std::vector &textureAttachments, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 79bf7d541..327b22410 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -181,8 +181,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback; }; - std::mutex m_listOfDeallocatorsAccessMtx; - void addDeallocationRecord(std::function callback) override { std::lock_guard lock(m_listOfDeallocatorsAccessMtx); DeallocationRecord dr; @@ -190,6 +188,14 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback) override { + std::lock_guard lock(m_listOfDeallocatorsAccessMtx); + DeallocationRecord dr; + dr.frameNumberToDoAt = m_frameNumber+MAX_FRAMES_IN_FLIGHT; + dr.callback = callback; + listOfDeallocators.push_back(dr); + }; + void executeBufferDeallocators(); VkFormat findDepthFormat(); @@ -374,8 +380,12 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this aggregationBufferForUpload = std::vector(1024*1024); + std::mutex m_listOfDeallocatorsAccessMtx; std::list listOfDeallocators; + std::mutex m_listOfBufferDeallocatorsAccessMtx; + std::list listOfBufferDeallocators; + std::vector m_createdFrameBuffers; struct RenderPassAvalabilityStruct { diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index f4c3db9ab..4331734cf 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -32,6 +32,7 @@ class IDeviceVulkan { virtual VkDevice getVkDevice() = 0; virtual VkPhysicalDevice getVkPhysicalDevice() = 0; virtual void addDeallocationRecord(std::function callback) = 0; + virtual void addBufferDeallocationRecord(std::function callback) = 0; virtual VkDescriptorSet allocateDescriptorSetPrimitive( const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &out_desciptorPool) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index d05754583..a73e8c3d6 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -213,7 +213,7 @@ void GBufferVLK::deleteSubBuffer(std::list>::const_ if (subBuffersize > 0) { deallocateSubBuffer(alloc, uiaAlloc); } - + currentSubBuffers.erase(it); } From a2b71949d1a1ec47a396718c47b4f54fe1262713 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 12 Aug 2023 20:36:13 +0300 Subject: [PATCH 111/212] - update in thread rehalted test --- src/ui/FrontendUI.cpp | 3 ++- .../uiScene/vulkan/FrontendUIRenderForwardVLK.h | 2 ++ wowViewerLib/src/engine/managers/CRibbonEmitter.cpp | 6 +++--- .../engine/managers/particles/particleEmitter.cpp | 12 ++++++------ wowViewerLib/src/engine/objects/m2/m2Object.cpp | 4 ++-- wowViewerLib/src/engine/objects/scenes/map.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h | 12 ++++++------ .../vulkan/buffers/GBufferChunkDynamicVersionedVLK.h | 12 ++++++------ wowViewerLib/src/renderer/frame/FrameProfile.h | 3 +++ .../mapScene/vulkan/MapSceneRenderForwardVLK.cpp | 5 ++++- .../mapScene/vulkan/MapSceneRenderForwardVLK.h | 2 ++ .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 2 +- 12 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 326901f6a..e67cecf6f 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1682,11 +1682,12 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, } HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, double deltaTime) { + ZoneScoped ; if (m_minimapGenerationWindow != nullptr) { m_minimapGenerationWindow->process(); } auto l_device = m_api->hDevice; - auto processingFrame = l_device->getProcessingFrameNumber(); + auto processingFrame = l_device->getFrameNumber(); auto updateFrameNumberLambda = [l_device](unsigned int frame) -> void {l_device->setCurrentProcessingFrameNumber(frame);}; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 8e841b9e1..5138b8a0f 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -42,6 +42,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; + std::vector allBuffers; + void createBuffers(); std::shared_ptr m_lastRenderPass; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index e25c29e18..af2c0a888 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -840,7 +840,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV } void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { - auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; + auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; if (currFrame.isDead) return; for (int i = 0; i < currFrame.m_meshes.size(); i++) { @@ -861,7 +861,7 @@ void CRibbonEmitter::fitBuffersToSize() { size_t sizeInd = m_gxIndices.size() * sizeof(uint16_t); size_t sizeVert = m_gxVertices.size() * sizeof(CRibbonVertex); - int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto vboBufferDynamic = frame[frameNum].m_bufferVBO; auto iboBufferDynamic = frame[frameNum].m_indexVBO; @@ -875,7 +875,7 @@ void CRibbonEmitter::fitBuffersToSize() { } void CRibbonEmitter::updateBuffers() { - auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; currentFrame.isDead = this->IsDead(); if (currentFrame.isDead) return; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 47da2031f..33465eb76 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -471,7 +471,7 @@ void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathf this->InternalUpdate(delta); } - const HGParticleMesh &mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber()].m_mesh; + const HGParticleMesh &mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT].m_mesh; mesh->setSortDistance(m_currentBonePos); } @@ -653,7 +653,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { this->calculateQuadToViewEtc(nullptr, viewMatrix); // FrameOfRerefence mat is null since it's not used - int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto vboBufferDynamic = frame[frameNum].m_bufferVBO; szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); @@ -681,7 +681,7 @@ void ParticleEmitter::fitBuffersToSize() { if ((m_data->old.flags & 0x60000) == 0x60000) { maxFutureSize *= 2; } - int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto vboBufferDynamic = frame[frameNum].m_bufferVBO; if (maxFutureSize > vboBufferDynamic->getSize()) { @@ -1118,11 +1118,11 @@ ParticleEmitter::BuildQuadT3( void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; if (!currentFrame.active) return; - HGParticleMesh mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber()].m_mesh; + HGParticleMesh mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT].m_mesh; if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { @@ -1133,7 +1133,7 @@ void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vect void ParticleEmitter::updateBuffers() { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber()]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; currentFrame.active = szVertexCnt > 0; if (!currentFrame.active) diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 2c1f7eb4b..5874a463f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1666,7 +1666,7 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorhDevice->getCurrentProcessingFrameNumber(); + int frame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto const &dynMeshFrame = dynMesh[frame]; @@ -1988,7 +1988,7 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) void M2Object::updateDynamicMeshes() { auto rootMatInverse = bonesMatrices[0].Inverse(); - auto frameNum = m_api->hDevice->getCurrentProcessingFrameNumber(); + auto frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; for (auto &dynamicMesh: dynamicMeshes) { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 625efe0e4..5fee40d18 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1573,7 +1573,7 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { if (granSize > 0) { auto l_device = m_api->hDevice; - auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); + auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), [&](tbb::blocked_range r) { l_device->setCurrentProcessingFrameNumber(processingFrame); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 86df7918b..89e7c5809 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -36,19 +36,19 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { }; void *getPointer() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return pSubBuffers[index]->getPointer(); }; void save(int length) override{ - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; pSubBuffers[index]->save(m_realSize); }; VkBuffer getGPUBuffer() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return pSubBuffers[index]->getGPUBuffer(); } size_t getOffset() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return pSubBuffers[index]->getOffset(); } size_t getIndex() override { @@ -60,11 +60,11 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { return m_realSize; } T &getObject() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return *(T*)pSubBuffers[index]->getPointer(); }; void save() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; pSubBuffers[index]->save(m_realSize); }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h index 8a40992fb..9c1d84082 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -38,19 +38,19 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe void uploadData(const void *, int length) override { }; void *getPointer() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return subBufferVersions[m_currentVersion][index]->getPointer(); }; void save(int length) override{ - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; subBufferVersions[m_currentVersion][index]->save(m_realSize); }; VkBuffer getGPUBuffer() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return subBufferVersions[m_currentVersion][index]->getGPUBuffer(); } size_t getOffset() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return subBufferVersions[m_currentVersion][index]->getOffset(); } @@ -69,11 +69,11 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe T &getObject(int version) override { if (version > subBufferVersions.size()) throw "wrong version"; - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return *(T*)subBufferVersions[version][index]->getPointer(); }; void saveVersion(int version) { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; subBufferVersions[version][index]->save(m_realSize); } diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h index 78a6e2eae..9bd3c63ce 100644 --- a/wowViewerLib/src/renderer/frame/FrameProfile.h +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -14,11 +14,14 @@ #endif #define setThreadName(a) tracy::SetThreadName(a); +#define TracyMessageStr(a) TracyMessage(a.c_str(), a.size()); #else #define setThreadName(a) +#define setThreadName(a) #define ZoneScoped #define ZoneScopedN(a) #define TracyVkContext(x,y,z,w) +#define TracyMessageStr(a) #endif diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 853601612..85b85e048 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -577,9 +577,9 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + TracyMessageStr(("Update stage frame = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); ZoneScoped; - auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); @@ -654,6 +654,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha skyMesh0x4, mapScene, framePlan, l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + + TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); + // //Do postLoad here. So creation of stuff is done from main thread // mapScene->doPostLoad(l_this, framePlan); // //And add portal meshes diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 3876e56bd..d4b18a181 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -123,6 +123,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; + + std::vector allBuffers; HGVertexBufferBindings m_drawQuadVao = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index d116b6f5d..b801454e7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -100,7 +100,7 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapCha const std::shared_ptr &finalRenderPass, ViewPortDimensions &viewPortDimensions) { ZoneScoped; - auto currentFrame = m_device->getCurrentProcessingFrameNumber(); + auto currentFrame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; { for (int i = 0; i < GAUSS_PASS_COUNT; i++) { From 862cd8b97b6baba8458747cdc441e4cc22660e82 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 15 Sep 2023 05:41:17 +0300 Subject: [PATCH 112/212] - another attempt into multithreading --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 114 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- wowViewerLib/CMakeLists.txt | 4 +- .../src/engine/geometry/wmoGroupGeom.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 42 +- .../src/engine/shader/ShaderDefinitions.h | 1298 ++++++++--------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 34 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 10 +- .../vulkan/buffers/GBufferChunkDynamicVLK.h | 2 +- .../buffers/GBufferChunkDynamicVersionedVLK.h | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 9 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 2 +- .../vulkan/buffers/GStagingRingBuffer.cpp | 6 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 8 +- .../src/renderer/frame/SceneComposer.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 139 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 2 +- .../src/renderer/vulkan/IRenderFunctionVLK.h | 25 +- 19 files changed, 871 insertions(+), 834 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index d955b8471..c9f6955e3 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -20,9 +20,11 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic } void FrontendUIRenderForwardVLK::createBuffers() { - iboBuffer = m_device->createIndexBuffer("UI_Ibo_Buffer", 1024*1024); - vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024); - uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); + m_ringBuffer = std::make_shared(m_device); + + iboBuffer = m_device->createIndexBuffer("UI_Ibo_Buffer", 1024*1024, m_ringBuffer); + vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024, m_ringBuffer); + uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT, m_ringBuffer); m_imguiUbo = std::make_shared>(uboBuffer); } @@ -82,6 +84,9 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + TracyMessageStr(("Update UI buffers = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); + ZoneScopedN("Update UI buffers"); + auto meshes = std::make_shared>(); this->consumeFrameInput(frameInputParams, *meshes); @@ -92,52 +97,61 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( //Record commands to update buffer and draw auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); - return createRenderFuncVLK(std::move([meshes, l_this](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) { - // --------------------- - // Upload stuff - // --------------------- - uploadCmd.submitBufferUploads(l_this->uboBuffer); - uploadCmd.submitBufferUploads(l_this->vboBuffer); - uploadCmd.submitBufferUploads(l_this->iboBuffer); - - // ---------------------- - // Draw meshes - // ---------------------- - - for (auto const &mesh : *meshes) { - const auto &meshVlk = std::dynamic_pointer_cast(mesh); - auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); - - //1. Bind VBOs - swapChainCmd.bindVertexBuffers(vulkanBindings->getVertexBuffers()); - - //2. Bind IBOs - swapChainCmd.bindIndexBuffer(vulkanBindings->getIndexBuffer()); - - //3. Bind pipeline - auto material = meshVlk->material(); - swapChainCmd.bindPipeline(material->getPipeline()); - - //4. Bind Descriptor sets - auto const &descSets = material->getDescriptorSets(); - for (int i = 0; i < descSets.size(); i++) { - if (descSets[i] != nullptr) { - swapChainCmd.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); + return createRenderFuncVLK( + std::move([meshes, l_this](CmdBufRecorder &uploadCmd) { + TracyMessageStr(("Upload stuff stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); + ZoneScopedN("Upload UI buffs"); + // --------------------- + // Upload stuff + // --------------------- + l_this->m_ringBuffer->flushBuffers(); + + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->vboBuffer); + uploadCmd.submitBufferUploads(l_this->iboBuffer); + }), + std::move([meshes, l_this](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) { + TracyMessageStr(("Render stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); + ZoneScopedN("Render UI"); + // ---------------------- + // Draw meshes + // ---------------------- + + for (auto const &mesh : *meshes) { + const auto &meshVlk = std::dynamic_pointer_cast(mesh); + auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); + + //1. Bind VBOs + swapChainCmd.bindVertexBuffers(vulkanBindings->getVertexBuffers()); + + //2. Bind IBOs + swapChainCmd.bindIndexBuffer(vulkanBindings->getIndexBuffer()); + + //3. Bind pipeline + auto material = meshVlk->material(); + swapChainCmd.bindPipeline(material->getPipeline()); + + //4. Bind Descriptor sets + auto const &descSets = material->getDescriptorSets(); + for (int i = 0; i < descSets.size(); i++) { + if (descSets[i] != nullptr) { + swapChainCmd.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); + } + } + + //5. Set view port + swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + + //6. Set scissors + if (meshVlk->scissorEnabled()) { + swapChainCmd.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); + } else { + swapChainCmd.setDefaultScissors(); + } + + //7. Draw the mesh + swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } - } - - //5. Set view port - swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); - - //6. Set scissors - if (meshVlk->scissorEnabled()) { - swapChainCmd.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); - } else { - swapChainCmd.setDefaultScissors(); - } - - //7. Draw the mesh - swapChainCmd.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); - } - })); + }) + ); } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 5138b8a0f..d0d31daad 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -42,7 +42,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; - std::vector allBuffers; + std::shared_ptr m_ringBuffer; void createBuffers(); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 35939bc7e..ce92600ef 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -516,8 +516,8 @@ if (LINK_VULKAN) src/gapi/vulkan/GRenderPassVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h - src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp - src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +# src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +# src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 15942474e..2da75e19c 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -363,7 +363,7 @@ HGVertexBuffer WmoGroupGeom::getVBO(const HMapSceneBufferCreate &sceneRenderer) } } - combinedVBO->uploadData(&buffer[0], (int)(verticesLen * sizeof(WMOVertex))); + //combinedVBO->uploadData(&buffer[0], (int)(verticesLen * sizeof(WMOVertex))); } return combinedVBO; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 5fee40d18..9963a11c3 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1571,28 +1571,28 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { } - if (granSize > 0) { - auto l_device = m_api->hDevice; - auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - l_device->setCurrentProcessingFrameNumber(processingFrame); - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } - } - }, tbb::simple_partitioner()); - } + //if (granSize > 0) { + // auto l_device = m_api->hDevice; + // auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + // tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + // [&](tbb::blocked_range r) { + // l_device->setCurrentProcessingFrameNumber(processingFrame); + // for (size_t i = r.begin(); i != r.end(); ++i) { + // auto &m2Object = m2ToDraw[i]; + // if (m2Object != nullptr) { + // m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + // renderPlan->frameDependentData); + // } + // } + // }, tbb::simple_partitioner()); + //} -// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { -// if (m2Object != nullptr) { -// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, -// renderPlan->frameDependentData); -// } -// } + for (auto &m2Object: renderPlan->m2Array.getDrawn()) { + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 03da57150..714fdeb14 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,20 +276,46 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {1,3,16384}, + {1,1,64}, + {0,0,2048}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -319,12 +326,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +341,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,2048}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,17 +379,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -393,14 +407,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {3,9, "uBumpTexture"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,18 +423,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, {0,0,2048}, {1,1,64}, }, { { {0,0,1}, - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,21 +445,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +460,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,2048}, + {1,1,96}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +477,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,16 +497,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, - {1,1,64}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -509,6 +512,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -529,15 +533,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,2048}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -565,15 +569,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -601,15 +605,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,11 +625,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -637,16 +641,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,2048}, + {0,2,168}, }, { { - {0,1,2}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -659,10 +662,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -674,17 +679,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {2,5,96}, + {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {1,1,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -695,13 +707,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -710,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +762,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,1,112}, + {0,0,2048}, }, { { @@ -819,15 +835,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -855,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -876,12 +892,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -893,15 +907,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,0,144}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,16 +943,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,2,48}, + {0,0,2048}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,13 +966,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,15 +990,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,0,2048}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -985,17 +1009,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,14 +1035,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,12 +1056,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,14 +1071,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,0,2048}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1055,7 +1088,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -1076,17 +1108,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,2048}, + {0,0,84}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1129,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, {0,0,0}, - {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,16 +1146,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,2048}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1137,12 +1168,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,17 +1192,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, - {1,1,96}, + {0,4,32}, }, { { - {0,0,1}, - {1,1,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,11 +1213,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1189,24 +1229,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,2048}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,2,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,17 +1250,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,24 +1265,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,4,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1264,11 +1286,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1279,15 +1303,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,96}, + {0,0,2048}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1299,12 +1325,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1314,19 +1341,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,2048}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { {0,0,1}, - {3,4,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1337,14 +1369,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,15 +1388,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,15 +1425,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,0,2048}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,11 +1461,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, + {1,4,32}, {0,0,2048}, }, { @@ -1448,12 +1484,14 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1463,17 +1501,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { {0,0,2048}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1500,24 +1537,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, {0,0,2048}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {5,5,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1528,17 +1558,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1547,24 +1573,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,2048}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1575,14 +1593,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1591,17 +1608,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,2048}, + {0,2,12}, }, { { - {0,0,1}, - {4,4,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1613,21 +1629,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1637,19 +1645,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,2048}, - {1,2,16}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {1,2,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1675,16 +1688,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, + {1,3,4096}, {0,0,2048}, }, { { {0,0,1}, - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1694,24 +1709,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1720,24 +1727,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1766,21 +1766,35 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1909,6 +1923,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"waterfallShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 6, { + {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 4, { + {"_1_4_colors[0]", true, 0, 1, 4, 256}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + 3, { + {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, } }, - }}, - {"drawDepthShader", { { 2, { - {"_0_2_drawDepth", false, 0, 1, 1, 0}, - {"_0_2_uFarPlane", true, 4, 1, 1, 0}, - {"_0_2_uNearPlane", true, 8, 1, 1, 0}, + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, } }, - }}, - {"adtShader", { { - 2, { - {"_1_2_scaleFactorPerLayer", true, 0, 1, 4, 0}, - {"_1_2_animation_rotationPerLayer", false, 16, 1, 4, 0}, - {"_1_2_animation_speedPerLayer", false, 32, 1, 4, 0}, + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -3410,25 +3405,29 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -365,10 +365,6 @@ void GDeviceVLK::initialize() { //--------------- m_textureManager->initialize(); -//--------------- - - stagingRingBuffer = std::make_shared(this->shared_from_this()); - //--------------- createSwapChainAndFramebuffer(); @@ -774,6 +770,8 @@ void GDeviceVLK::findQueueFamilies(VkPhysicalDevice device) { if (dedicatedTransferQueue > -1) { indices.transferFamily = dedicatedTransferQueue; } + + indices.transferFamily = indices.graphicsFamily; } void GDeviceVLK::createCommandPool() { @@ -876,8 +874,6 @@ float GDeviceVLK::getAnisLevel() { void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { ZoneScoped; - stagingRingBuffer->flushBuffers(); - this->waitInDrawStageAndDeps.beginMeasurement(); int currentDrawFrame = getProcessingFrameNumber(); @@ -899,6 +895,12 @@ void GDeviceVLK::drawFrame(const std::vector> & } auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); + { + for (int i = 0; i < renderFuncs.size(); i++) { + dynamic_cast(renderFuncs[i].get())->executeUpload(*this, uploadCmd); + } + } + auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); //Do Texture update @@ -934,7 +936,7 @@ void GDeviceVLK::drawFrame(const std::vector> & auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->execute(*this, uploadCmd, frameBufCmd, swapChainCmd); + dynamic_cast(renderFuncs[i].get())->executeRender(*this, frameBufCmd, swapChainCmd); } } } @@ -1143,24 +1145,24 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName return sharedPtr; } -HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); +HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); +HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize, const std::shared_ptr &ringBuff) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize) { - auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { + auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); return h_vertexBuffer; } -HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize) { - auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, stagingRingBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { + auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); return h_indexBuffer; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 327b22410..a15c00ab5 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -102,10 +102,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); - HGBufferVLK createUniformBuffer(const char * objName, size_t size); - HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize); - HGBufferVLK createVertexBuffer(const char * objName, size_t size); - HGBufferVLK createIndexBuffer(const char * objName, size_t size); + HGBufferVLK createUniformBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); + HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize, const std::shared_ptr &ringBuff); + HGBufferVLK createVertexBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); + HGBufferVLK createIndexBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); HGVertexBufferBindings createVertexBufferBindings() override; HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) override; @@ -336,7 +336,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this stagingRingBuffer; + HGSamplableTexture m_blackPixelTexture = nullptr; HGSamplableTexture m_whitePixelTexture = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h index 89e7c5809..034b5d043 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h @@ -52,7 +52,7 @@ class GBufferChunkDynamicVLK : public IBufferChunk, public IBufferVLK { return pSubBuffers[index]->getOffset(); } size_t getIndex() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return pSubBuffers[index]->getIndex(); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h index 9c1d84082..1dd5216d7 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h @@ -55,7 +55,7 @@ class GBufferChunkDynamicVersionedVLK : public IBufferVLK, public IBufferChunkVe } size_t getIndex() override { - auto index = m_device->getCurrentProcessingFrameNumber(); + auto index = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; return subBufferVersions[m_currentVersion][index]->getIndex(); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index a73e8c3d6..914c2e276 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -107,7 +107,9 @@ void *GBufferVLK::allocatePtr(int offset, int length) { VkBuffer staging; int stage_offset; auto *ptr = m_ringBuff->allocateNext(length, staging, stage_offset); - uploadRegionsPerStaging[staging].push_back({ + + auto frameIndex = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + uploadRegionsPerStaging[frameIndex][staging].push_back({ .srcOffset = static_cast(stage_offset), .dstOffset = static_cast(offset), .size = static_cast(length) @@ -243,7 +245,8 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { executeOnChangeForBufAndSubBuf(); } - for (auto &stagingRecord : uploadRegionsPerStaging) { + auto& stagingRecords = uploadRegionsPerStaging[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + for (auto &stagingRecord : stagingRecords) { auto &intervals = stagingRecord.second; std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) -> bool { return @@ -270,7 +273,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { uploadData.copyRegions = intervals; } } - uploadRegionsPerStaging.clear(); + stagingRecords.clear(); } return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 800ca1962..f13ca5cf2 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -73,7 +73,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this> uploadRegionsPerStaging; + std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> uploadRegionsPerStaging; std::mutex dataToBeUploadedMtx; std::vector dataToBeUploaded; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index 81521feef..fde689192 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -5,7 +5,7 @@ #include "GStagingRingBuffer.h" void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_offset) { - auto frame = m_device->getCurrentProcessingFrameNumber(); + auto frame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &vec = m_stagingBuffers[frame]; int startOffset = 0; @@ -38,7 +38,7 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of } void GStagingRingBuffer::flushBuffers() { - auto frame = m_device->getCurrentProcessingFrameNumber(); + auto frame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &vec = m_stagingBuffers[frame]; int maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; @@ -55,5 +55,5 @@ void GStagingRingBuffer::flushBuffers() { int prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; currentOffset = 0; - vec.resize(std::min(prevMaxIndex, vec.size())); + vec.resize(std::min(prevMaxIndex+1, vec.size())); } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 45a5fcf39..54fce2320 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -216,18 +216,24 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = numSamples; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; // Set initial layout of the image to undefined imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.extent = {static_cast(m_width), static_cast(m_height), 1}; imageCreateInfo.usage = imageUsageFlags; + imageCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; imageCreateInfo.queueFamilyIndexCount = 2; + auto &indicies = m_device.getQueueFamilyIndices(); std::array families = {indicies.graphicsFamily.value(), indicies.transferFamily.value()}; imageCreateInfo.pQueueFamilyIndices = families.data(); + if (indicies.graphicsFamily.value() == indicies.transferFamily.value()) { + imageCreateInfo.queueFamilyIndexCount = 1; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + } + VmaAllocationCreateInfo allocImageCreateInfo = {}; allocImageCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; // allocImageCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; //this bit forces to create per one texture per memory diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index a40a98f18..472cb0049 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -83,7 +83,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon //Insert one temp element for balancing updateInput.pushInput(nullptr); // drawInput.pushInput(nullptr); - drawInput.pushInput(nullptr); +// drawInput.pushInput(nullptr); } void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 85b85e048..17671af1c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -37,17 +37,19 @@ static const ShaderConfig m2ForwardShaderConfig = { MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { - iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); - - vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); - vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); - vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); - vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024); - vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); - vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); - vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); - vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200); + m_stagingRingBuffer = std::make_shared(m_device); + + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024, m_stagingRingBuffer); + + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, m_stagingRingBuffer); + vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024, m_stagingRingBuffer); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024, m_stagingRingBuffer); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024, m_stagingRingBuffer); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, m_stagingRingBuffer); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, m_stagingRingBuffer); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, m_stagingRingBuffer); + vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024, m_stagingRingBuffer); + vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200, m_stagingRingBuffer); { const float epsilon = 0.f; @@ -61,8 +63,8 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C 0, 1, 2, 2, 1, 3 }; - m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); - m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed), m_stagingRingBuffer); + m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t), m_stagingRingBuffer); m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); @@ -72,10 +74,10 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_drawQuadVao->save(); } - uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024); - uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024); + uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024, m_stagingRingBuffer); + uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024, m_stagingRingBuffer); - uboM2BoneMatrixBuffer = m_device->createUniformBuffer("Scene_UBO_M2BoneMats", 5000*64); + uboM2BoneMatrixBuffer = m_device->createUniformBuffer("Scene_UBO_M2BoneMats", 5000*64, m_stagingRingBuffer); m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); @@ -614,11 +616,8 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - //Needs to be executed only after lock - m_lastCreatedPlan = framePlan; - //The portal meshes are created here. Need to call doPostLoad before CollectMeshes - mapScene->doPostLoad(l_this, framePlan); +// mapScene->doPostLoad(l_this, framePlan); // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, @@ -647,55 +646,59 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha bool renderSky = framePlan->renderSky; auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; - return createRenderFuncVLK([opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes, - renderSky, - skyMesh, - skyMesh0x4, - mapScene, framePlan, - l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes](CmdBufRecorder &uploadCmd) -> void { + //Do postLoad here. So creation of stuff is done from main thread + mapScene->doPostLoad(l_this, framePlan); + //And add portal meshes + for (auto &view : framePlan->viewsHolder.getInteriorViews()) { + view->collectPortalMeshes(*transparentMeshes); + } + { + auto exteriorView = framePlan->viewsHolder.getExterior(); + if (exteriorView != nullptr) { + exteriorView->collectPortalMeshes(*transparentMeshes); + } + } - TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); + //Needs to be executed only after lock + l_this->m_lastCreatedPlan = framePlan; -// //Do postLoad here. So creation of stuff is done from main thread -// mapScene->doPostLoad(l_this, framePlan); -// //And add portal meshes -// for (auto &view : framePlan->viewsHolder.getInteriorViews()) { -// view->collectPortalMeshes(*transparentMeshes); -// } -// { -// auto exteriorView = framePlan->viewsHolder.getExterior(); -// if (exteriorView != nullptr) { -// exteriorView->collectPortalMeshes(*transparentMeshes); -// } -// } - - - // --------------------- - // Upload stuff - // --------------------- - { - ZoneScopedN("submit buffers"); - VkZone(uploadCmd, "submit buffers") - uploadCmd.submitBufferUploads(l_this->uboBuffer); - uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); - - uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); - - uploadCmd.submitBufferUploads(l_this->vboM2Buffer); - uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); - uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); - uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); - uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); - - uploadCmd.submitBufferUploads(l_this->iboBuffer); - uploadCmd.submitBufferUploads(l_this->m_vboQuad); - uploadCmd.submitBufferUploads(l_this->m_iboQuad); - } + l_this->m_stagingRingBuffer->flushBuffers(); + + // --------------------- + // Upload stuff + // --------------------- + { + ZoneScopedN("submit buffers"); + VkZone(uploadCmd, "submit buffers") + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + + uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); + } + }, [opaqueMeshes, transparentMeshes, + skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + mapScene, framePlan, + l_this, frameInputParams](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + + TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); // ---------------------- // Draw meshes @@ -704,7 +707,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber()], + l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], frameInputParams->viewPortDimensions.mins, frameInputParams->viewPortDimensions.maxs, vec4ToArr3(frameInputParams->frameParameters->clearColor), diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index d4b18a181..00884f7d1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -146,6 +146,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; + std::shared_ptr m_stagingRingBuffer; + void createFrameBuffers(); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index e94856115..cdd07b6ad 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -756,7 +756,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s { auto passHelper = frameBufCmd.beginRenderPass(false, l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber()], + l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], frameInputParams->viewPortDimensions.mins, frameInputParams->viewPortDimensions.maxs, vec4ToArr3(frameInputParams->frameParameters->clearColor), diff --git a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h index 32986dd36..c86a8a64c 100644 --- a/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h +++ b/wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h @@ -12,27 +12,34 @@ class IRenderFunctionVLK : public IRenderFunction { public: ~IRenderFunctionVLK() override = default; public: - virtual void execute(IDevice &device, CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) = 0; + virtual void executeUpload(IDevice &device, CmdBufRecorder &uploadCmd) = 0; + virtual void executeRender(IDevice &device, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) = 0; }; -template +template class TemplateIRenderFunctionVLK : public IRenderFunctionVLK { public: - TemplateIRenderFunctionVLK(T a) : m_a(std::move(a)){ + TemplateIRenderFunctionVLK(UP a, REND b) : m_render(std::move(b)), m_upload(std::move(a)) { }; - void execute(IDevice &device, CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) override { + void executeUpload(IDevice &device, CmdBufRecorder &uploadCmd) override { //Hack through currently processing frame device.setCurrentProcessingFrameNumber(getProcessingFrame()); - m_a(uploadCmd, frameBufCmd, swapChainCmd); + m_upload(uploadCmd); + }; + void executeRender(IDevice &device, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) override { + //Hack through currently processing frame + device.setCurrentProcessingFrameNumber(getProcessingFrame()); + m_render(frameBufCmd, swapChainCmd); }; private: - T m_a; + REND m_render; + UP m_upload; }; -template -std::unique_ptr createRenderFuncVLK(T a) { - return std::make_unique>(std::move(a)); +template +std::unique_ptr createRenderFuncVLK(UP a, REND b) { + return std::make_unique>(std::move(a), std::move(b)); } From ab14a1fdd682e02541378e8dade31c0a2efa6340 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 15 Sep 2023 06:23:03 +0300 Subject: [PATCH 113/212] - update in separate thread works? --- .../src/engine/shader/ShaderDefinitions.h | 324 +----------------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../vulkan/buffers/GStagingRingBuffer.cpp | 7 +- .../gapi/vulkan/buffers/GStagingRingBuffer.h | 5 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 2 + 5 files changed, 30 insertions(+), 310 deletions(-) diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 714fdeb14..fc5fcfcf1 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -305,17 +305,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -388,9 +383,6 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,2048}, {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { @@ -663,11 +655,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -685,17 +676,11 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,2048}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, + {0,0,0}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -730,11 +715,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -839,11 +823,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1016,7 +999,6 @@ const std::unordered_map shaderMetaInfo = { {1,1,0}, {1,7,0}, {1,6,0}, - {1,3,0}, }, { {3,0, "s_Textures"}, @@ -1076,12 +1058,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,2048}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1129,12 +1110,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1352,7 +1331,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,2048}, {1,1,64}, {1,6,4096}, - {1,3,16384}, }, { { @@ -1541,11 +1519,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,2048}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1652,17 +1629,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,2048}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1693,13 +1665,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,16}, - {1,3,4096}, {0,0,2048}, }, { { {0,0,1}, - {3,4,2}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1767,31 +1738,6 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { - { - 5, { - {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, { 1, { {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, @@ -1935,7 +1881,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, - } - }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -3406,7 +3261,12 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index fde689192..0537609e5 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -10,6 +10,7 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of int startOffset = 0; int bufferIndex = 0; + uint32_t ¤tOffset = offsets[frame]; { // std::unique_lock l(m_mutex); @@ -41,7 +42,9 @@ void GStagingRingBuffer::flushBuffers() { auto frame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &vec = m_stagingBuffers[frame]; - int maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; + uint32_t ¤tOffset = offsets[frame]; + + uint32_t maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; for (int i = 0; i < maxIndex; i++) { auto &stagingRec = vec[i]; @@ -52,7 +55,7 @@ void GStagingRingBuffer::flushBuffers() { memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); } - int prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; + uint32_t prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; currentOffset = 0; vec.resize(std::min(prevMaxIndex+1, vec.size())); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h index e16e975c4..3d8633f41 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -12,7 +12,7 @@ class BufferStagingVLK; #include "gpu/BufferStagingVLK.h" class GStagingRingBuffer { - static constexpr int STAGE_BUFFER_SIZE = 20*1024*1024; + static constexpr uint32_t STAGE_BUFFER_SIZE = 20*1024*1024; public: GStagingRingBuffer(const HGDeviceVLK &device) : m_device(device) {}; @@ -23,7 +23,8 @@ class GStagingRingBuffer { HGDeviceVLK m_device; std::mutex m_mutex; - uint32_t currentOffset = 0; + + std::array offsets = {0,0,0}; struct BufferAndCPU { std::shared_ptr staging; std::array cpuBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 0c32d132e..3022a8327 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -40,6 +40,8 @@ VkShaderModule GShaderPermutationVLK::createShaderModule(const std::vector throw std::runtime_error("failed to create shader module!"); } + m_device->setObjectName((uint64_t) shaderModule, VK_OBJECT_TYPE_SHADER_MODULE, m_combinedName.c_str()); + return shaderModule; } From 0405d69ce2d016c7c240b9304b9b11ba446d720d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 17 Sep 2023 04:50:45 +0300 Subject: [PATCH 114/212] - resolve mutex deadlock - resolve circular dependency in shared_ptrs --- .../src/engine/managers/CRibbonEmitter.cpp | 6 +- .../src/engine/managers/CRibbonEmitter.h | 3 +- .../src/engine/managers/animationManager.cpp | 4 +- .../src/engine/managers/animationManager.h | 4 +- .../managers/particles/particleEmitter.cpp | 7 +- .../managers/particles/particleEmitter.h | 4 +- wowViewerLib/src/engine/objects/iWmoApi.h | 2 +- .../engine/objects/liquid/LiquidInstance.cpp | 4 +- .../engine/objects/liquid/LiquidInstance.h | 1 - .../src/engine/objects/m2/m2Object.cpp | 17 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/m2Scene.h | 4 +- .../src/engine/objects/scenes/map.cpp | 14 +- wowViewerLib/src/engine/objects/scenes/map.h | 12 +- .../src/engine/objects/scenes/wmoScene.cpp | 4 +- .../src/engine/objects/scenes/wmoScene.h | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 6 +- .../src/engine/objects/wmo/wmoObject.h | 4 +- .../src/engine/shader/ShaderDefinitions.h | 1316 ++++++++++------- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 10 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 1 + wowViewerLib/src/renderer/IRenderParameters.h | 3 + .../src/renderer/frame/SceneComposer.cpp | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 2 - .../vulkan/MapSceneRenderForwardVLK.cpp | 28 +- 27 files changed, 883 insertions(+), 588 deletions(-) diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index af2c0a888..cb02f4ebd 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -12,7 +12,7 @@ CRibbonEmitter::CRibbonEmitter(const HApiContainer &api, const HMapSceneBufferCr const std::shared_ptr &m2ModelData, M2Object *object, std::vector &materials, - std::vector &textureIndicies, int textureTransformLookup) : m_api(api), m_sceneRenderer(sceneRenderer) + std::vector &textureIndicies, int textureTransformLookup) : m_api(api) { this->textureTransformLookup = textureTransformLookup; this->m_refCount = 1; @@ -853,7 +853,7 @@ void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vecto } } -void CRibbonEmitter::fitBuffersToSize() { +void CRibbonEmitter::fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer) { if (this->IsDead()) { return; } @@ -870,7 +870,7 @@ void CRibbonEmitter::fitBuffersToSize() { sizeInd > iboBufferDynamic->getSize() || sizeVert > vboBufferDynamic->getSize() ) { - createMesh(m_sceneRenderer, frame[frameNum]); + createMesh(sceneRenderer, frame[frameNum]); } } diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index c414d96a1..229c53499 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -74,7 +74,6 @@ class CRibbonEmitter { private: HApiContainer m_api; - HMapSceneBufferCreate m_sceneRenderer; struct RibbonFrame { HGIndexBuffer m_indexVBO; @@ -126,7 +125,7 @@ class CRibbonEmitter { void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); - void fitBuffersToSize(); + void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); }; diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index 19ac1ee81..485362067 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -722,7 +722,7 @@ void AnimationManager::update( std::vector &transparencies, std::vector &lights, std::vector> &particleEmitters, - std::vector &ribbonEmitters) { + std::vector> &ribbonEmitters) { auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; @@ -1313,7 +1313,7 @@ void AnimationManager::calcParticleEmitters(const std::vector &ribbonEmitters){ +void AnimationManager::calcRibbonEmitters(std::vector> &ribbonEmitters){ auto &ribbonRecords = boneMasterData->getM2Geom()->getM2Data()->ribbon_emitters; if (ribbonRecords.size <= 0) return; diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index ee3e22dde..9e898a623 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -63,7 +63,7 @@ class AnimationManager { std::vector &transparencies, std::vector &lights, std::vector> &particleEmitters, - std::vector &ribbonEmitters + std::vector> &ribbonEmitters /*cameraDetails, particleEmitters*/); @@ -87,7 +87,7 @@ class AnimationManager { const std::vector> &particleEmitters, std::vector &bonesMatrices); - void calcRibbonEmitters(std::vector &ribbonEmitters); + void calcRibbonEmitters(std::vector> &ribbonEmitters); void calcCamera(M2CameraResult &camera, int cameraId, mathfu::mat4 &placementMatrix); }; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 33465eb76..82263b380 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -260,7 +260,6 @@ static const std::array ParticleBlendingModeToEGxBlendEnum = void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; - m_sceneRenderer = sceneRenderer; if (m_indexVBO == nullptr) { //TODO: @@ -342,7 +341,7 @@ void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { //Create Buffers for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { //Create mesh - createMesh(m_sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); + createMesh(sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); } } void ParticleEmitter::createMesh(const HMapSceneBufferCreate &sceneRenderer, particleFrame &currFrame, int size) { @@ -672,7 +671,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { } } -void ParticleEmitter::fitBuffersToSize() { +void ParticleEmitter::fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer) { if (particles.size() == 0) { return; } @@ -685,7 +684,7 @@ void ParticleEmitter::fitBuffersToSize() { auto vboBufferDynamic = frame[frameNum].m_bufferVBO; if (maxFutureSize > vboBufferDynamic->getSize()) { - createMesh(m_sceneRenderer, frame[frameNum], maxFutureSize); + createMesh(sceneRenderer, frame[frameNum], maxFutureSize); } } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 0d3914480..93dd870d7 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -71,7 +71,7 @@ class ParticleEmitter { void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); - void fitBuffersToSize(); + void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); int flags = 6; CParticleMaterialFlags materialFlags; @@ -82,8 +82,6 @@ class ParticleEmitter { static bool randTableInited; private: HApiContainer m_api; - HMapSceneBufferCreate m_sceneRenderer; - M2Particle *m_data; Exp2Record *m_exp2Data = nullptr; diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index 06c9e3b2e..8a642f140 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -311,7 +311,7 @@ class IWmoApi { virtual SMOHeader *getWmoHeader() = 0; virtual mathfu::vec3 getAmbientColor() = 0; virtual PointerChecker &getMaterials() = 0; - virtual std::shared_ptr getMaterialInstance(int index) = 0; + virtual std::shared_ptr getMaterialInstance(int index, const HMapSceneBufferCreate &sceneRenderer) = 0; virtual bool isLoaded() = 0; virtual std::function getAttenFunction() = 0; virtual PointerChecker &getLightArray() = 0; diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 50fb10304..8c6fdf3eb 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -13,7 +13,7 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, const std::shared_ptr> &waterPlacementChunk, const mathfu::vec3 &liquidBasePos, const PointerChecker &mH2OBlob, CAaBox &waterAaBB) : - m_api(api), m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), + m_api(api), m_waterPlacementChunk(waterPlacementChunk), m_waterBBox(waterAaBB){ //Creating liquid instance from ADT data @@ -45,7 +45,7 @@ LiquidInstance::LiquidInstance(const HApiContainer &api, int indexBufferSize, const std::shared_ptr> &waterPlacementChunk, CAaBox &waterAaBB): m_api(api), - m_sceneRenderer(sceneRenderer), m_waterPlacementChunk(waterPlacementChunk), m_waterBBox(waterAaBB){ + m_waterPlacementChunk(waterPlacementChunk), m_waterBBox(waterAaBB){ bool generateTexCoordsFromPos; getInfoFromDatabase(0, liquidType, diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index 40f2699e1..a5a978cd8 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -30,7 +30,6 @@ class LiquidInstance { void collectMeshes(std::vector &transparentMeshes); private: const HApiContainer &m_api; - const HMapSceneBufferCreate &m_sceneRenderer; const std::shared_ptr> m_waterPlacementChunk; std::vector> m_liquidMaterials; std::vector m_liquidMeshes; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 5874a463f..81166c3df 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -468,9 +468,7 @@ int getShaderNames(M2Batch *m2Batch, std::string &vertexShader, std::string &pix } M2Object::~M2Object() { - for (auto obj: ribbonEmitters) { - delete obj; - } +// std::cout << "M2Object destroyed" << std::endl; } @@ -1024,15 +1022,15 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v } } -void M2Object::fitParticleAndRibbonBuffersToSize() { +void M2Object::fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer) { int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); for (int i = minParticle; i < maxParticle; i++) { - particleEmitters[i]->fitBuffersToSize(); + particleEmitters[i]->fitBuffersToSize(sceneRenderer); } for (int i = 0; i < ribbonEmitters.size(); i++) { - ribbonEmitters[i]->fitBuffersToSize(); + ribbonEmitters[i]->fitBuffersToSize(sceneRenderer); } } @@ -1740,7 +1738,7 @@ void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) } void M2Object::initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer) { - ribbonEmitters = std::vector(); + ribbonEmitters = std::vector>(); // ribbonEmitters.reserve(m_m2Geom->getM2Data()->ribbon_emitters.size); auto m2Data = m_m2Geom->getM2Data(); for (int i = 0; i < m2Data->ribbon_emitters.size; i++) { @@ -1758,9 +1756,8 @@ void M2Object::initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer) { int textureTransformLookup = (m2Data->global_flags.flag_unk_0x20000 != 0) ? m2Ribbon->textureTransformLookupIndex : -1; - auto emitter = new CRibbonEmitter(m_api, sceneRenderer, m_modelWideDataBuff, + auto emitter = std::make_unique(m_api, sceneRenderer, m_modelWideDataBuff, this, materials, textureIndicies, textureTransformLookup); - ribbonEmitters.push_back(emitter); CImVector color; color.r = 255; @@ -1777,6 +1774,8 @@ void M2Object::initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer) { emitter->SetGravity(m2Ribbon->gravity); emitter->SetPriority(m2Ribbon->priorityPlane); emitter->SetDataEnabled(0); + + ribbonEmitters.push_back(std::move(emitter)); } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 7b8e436eb..6c5b50d75 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -129,7 +129,7 @@ class M2Object { std::vector transparencies; std::vector lights; std::vector> particleEmitters; - std::vector ribbonEmitters; + std::vector> ribbonEmitters; std::unordered_map loadedTextures; @@ -266,7 +266,7 @@ class M2Object { void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); - void fitParticleAndRibbonBuffersToSize(); + void fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); void drawDebugLight(); diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 4cd931e4a..1994473c2 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -11,7 +11,7 @@ void M2Scene::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { potentialM2.addCandidate(m_m2Object); @@ -19,7 +19,7 @@ void M2Scene::getPotentialEntities(const MathHelper::FrustumCullingData &frustum void M2Scene::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { m2ObjectsCandidates.addCandidate(m_m2Object); diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index 3152d1c77..c5be386e4 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -17,13 +17,13 @@ class M2Scene : public Map { void getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) override; void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) override; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 9963a11c3..aab068783 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -321,7 +321,7 @@ std::tuple> createSkyMesh(const HMapSc return {hmesh, material}; } -void Map::makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan) { +void Map::makeFramePlan(const FrameInputParams &frameInputParams, const HMapRenderPlan &mapRenderPlan) { ZoneScoped ; Config* config = this->m_api->getConfig(); @@ -976,7 +976,7 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { @@ -1053,7 +1053,7 @@ void Map::getAdtAreaId(const mathfu::vec4 &cameraPos, int &areaId, int &parentAr void Map::checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, int viewRenderOrder, - HMapRenderPlan &mapRenderPlan + const HMapRenderPlan &mapRenderPlan ) { ZoneScoped ; // std::cout << "Map::checkExterior finished called" << std::endl; @@ -1129,7 +1129,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { if (m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { @@ -1193,7 +1193,7 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat void Map::checkADTCulling(int i, int j, const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { if ((i < 0) || (i > 64)) return; @@ -1520,7 +1520,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { this->m_currentTime += deltaTime; } -void Map::updateBuffers(const HMapRenderPlan &renderPlan) { +void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan) { ZoneScoped; if (skyMeshMat0x4) { @@ -1566,7 +1566,7 @@ void Map::updateBuffers(const HMapRenderPlan &renderPlan) { //Can't be paralleled? for (auto &m2Object: renderPlan->m2Array.getDrawn()) { if (m2Object != nullptr) { - m2Object->fitParticleAndRibbonBuffersToSize(); + m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); } } diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index cb571e150..4ad3a049a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -94,20 +94,20 @@ class Map : public IScene, public IMapApi { virtual void getPotentialEntities( const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo); virtual void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates); void checkADTCulling(int i, int j, const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates); @@ -177,7 +177,7 @@ class Map : public IScene, public IMapApi { }; animTime_t getCurrentSceneTime() override; - void makeFramePlan(const FrameInputParams &frameInputParams, HMapRenderPlan &mapRenderPlan); + void makeFramePlan(const FrameInputParams &frameInputParams, const HMapRenderPlan &mapRenderPlan); void setMandatoryADTs(std::vector> &mandatoryADTs) { m_mandatoryADT = mandatoryADTs; @@ -191,12 +191,12 @@ class Map : public IScene, public IMapApi { void doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan); void update(const HMapRenderPlan &renderPlan); - void updateBuffers(const HMapRenderPlan &renderPlan); + void updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan); private: void checkExterior(mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData, int viewRenderOrder, - HMapRenderPlan &mapRenderPlan); + const HMapRenderPlan &mapRenderPlan); // HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index 8648c0837..cc03ac842 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -10,7 +10,7 @@ void WmoScene::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) { potentialWmo.addCand(this->m_wmoObject); @@ -18,7 +18,7 @@ void WmoScene::getPotentialEntities(const MathHelper::FrustumCullingData &frustu void WmoScene::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.h b/wowViewerLib/src/engine/objects/scenes/wmoScene.h index b592d1c2a..05b3f3900 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.h +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.h @@ -17,13 +17,13 @@ class WmoScene : public Map { void getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &potentialM2, WMOListContainer &potentialWmo) override; void getCandidatesEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, - HMapRenderPlan &mapRenderPlan, + const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) override; public: diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 7c522b780..9a8a6ca38 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -148,7 +148,7 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { materialIndex = renderBatch.material_id; } - auto materialInstance = m_wmoApi->getMaterialInstance(materialIndex); + auto materialInstance = m_wmoApi->getMaterialInstance(materialIndex, sceneRenderer); gMeshTemplate meshTemplate(binding); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index a6775d69b..ab5941135 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -297,7 +297,7 @@ void WmoObject::createWorldPortals() { bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (mainGeom != nullptr && mainGeom->getStatus() == FileStatus::FSLoaded){ - m_sceneRenderer = sceneRenderer; + this->createMaterialCache(); this->createGroupObjects(); this->createWorldPortals(); @@ -1287,7 +1287,7 @@ PointerChecker &WmoObject::getMaterials() { return mainGeom->materials; } -std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) { +std::shared_ptr WmoObject::getMaterialInstance(int materialIndex, const HMapSceneBufferCreate &sceneRenderer) { assert(materialIndex < m_materialCache.size()); auto materialInstance = m_materialCache[materialIndex].lock(); @@ -1341,7 +1341,7 @@ std::shared_ptr WmoObject::getMaterialInstance(int materialIndex) materialTemplate.textures[8] = getTexture(material.runTimeData[3], false); } - auto wmoMaterialInstance = m_sceneRenderer->createWMOMaterial(m_modelWideChunk, + auto wmoMaterialInstance = sceneRenderer->createWMOMaterial(m_modelWideChunk, pipelineTemplate, materialTemplate); m_materialCache[materialIndex] = wmoMaterialInstance; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index b8c066311..b03e4c465 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -49,7 +49,7 @@ class WmoObject : public IWmoApi { HApiContainer m_api; HWmoMainGeom mainGeom = nullptr; - HMapSceneBufferCreate m_sceneRenderer; + bool m_loading = false; bool m_loaded = false; CAaBox m_bbox; @@ -119,7 +119,7 @@ class WmoObject : public IWmoApi { mathfu::vec3 getAmbientColor() override; PointerChecker &getMaterials() override; - std::shared_ptr getMaterialInstance(int index) override; + std::shared_ptr getMaterialInstance(int index, const HMapSceneBufferCreate &sceneRenderer) override; PointerChecker &getLightArray() override; std::vector &getPortalInfos() override { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index fc5fcfcf1..03da57150 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,40 +295,19 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,2048}, + {0,0,84}, }, { { {0,0,1}, - {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -321,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,2048}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -374,21 +372,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,2048}, - {1,1,64}, + {0,2,12}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -399,14 +393,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -415,17 +409,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,2048}, {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -437,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -452,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, - {1,1,96}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -469,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -489,14 +492,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,2048}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -504,7 +509,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -525,15 +529,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,2048}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -561,15 +565,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -597,14 +601,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -617,12 +622,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,15 +637,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,112}, + {0,0,2048}, }, { { - {2,2,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -654,11 +659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -670,18 +674,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,2048}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,17 +695,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -711,14 +710,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,2048}, + {0,0,128}, + {0,1,64}, }, { { @@ -819,14 +819,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,2048}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -854,15 +855,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -875,10 +876,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -890,15 +893,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -926,18 +929,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,2048}, - {1,1,64}, + {0,4,32}, }, { { - {0,0,1}, - {1,2,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -949,21 +950,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -973,15 +966,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,2048}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -992,23 +985,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, }, { - {3,0, "s_Textures"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1017,15 +1004,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1038,11 +1024,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1053,15 +1040,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,0,2048}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,16 +1076,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,4,32}, + {0,0,2048}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1110,12 +1098,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1125,17 +1116,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,2048}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1147,21 +1137,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1171,16 +1152,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,2048}, + {1,1,96}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1192,12 +1174,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1208,17 +1189,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,2048}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,13 +1217,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1244,17 +1236,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {1,3,16384}, + {1,1,64}, + {0,0,2048}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1265,13 +1264,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1282,17 +1279,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,2048}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1304,13 +1299,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1320,23 +1314,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,16}, + {1,3,4096}, {0,0,2048}, - {1,1,64}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1347,17 +1337,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,16 +1353,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,2048}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1403,15 +1389,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,0,2048}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1439,11 +1425,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {1,4,96}, {0,0,2048}, }, { @@ -1462,14 +1448,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1479,16 +1463,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,2048}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1515,16 +1500,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,5,96}, + {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,13 +1528,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1550,16 +1547,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,2048}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1570,13 +1575,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,16 +1591,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,32}, + {0,0,2048}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1606,13 +1613,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1622,18 +1637,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, {1,1,64}, {0,0,2048}, + {1,2,16}, }, { { {0,0,1}, - {1,3,3}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1660,17 +1675,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, {0,0,2048}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1680,16 +1694,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {2,5, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1698,15 +1720,37 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,2048}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, + {1,6,6}, + {7,7,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { {0,0,0}, {0,0,0}, {0,0,0}, @@ -1714,35 +1758,168 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + } + } + } +}, +}; + +const std::unordered_map>> fieldDefMapPerShaderNameVert = { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, + } + }, + { + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 240, 1, 4, 0}, + {"_0_0_fogData[0].densityParams", true, 256, 1, 4, 0}, + {"_0_0_fogData[0].classicFogParams", true, 272, 1, 4, 0}, + {"_0_0_fogData[0].heightPlane", true, 288, 1, 4, 0}, + {"_0_0_fogData[0].color_and_heightRate", true, 304, 1, 4, 0}, + {"_0_0_fogData[0].heightDensity_and_endColor", true, 320, 1, 4, 0}, + {"_0_0_fogData[0].sunAngle_and_sunColor", true, 336, 1, 4, 0}, + {"_0_0_fogData[0].heightColor_and_endFogDistance", true, 352, 1, 4, 0}, + {"_0_0_fogData[0].sunPercentage", true, 368, 1, 4, 0}, + {"_0_0_fogData[0].sunDirection_and_fogZScalar", true, 384, 1, 4, 0}, + {"_0_0_fogData[0].heightFogCoeff", true, 400, 1, 4, 0}, + {"_0_0_fogData[0].mainFogCoeff", true, 416, 1, 4, 0}, + {"_0_0_fogData[0].heightDensityFogCoeff", true, 432, 1, 4, 0}, + {"_0_0_fogData[0].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 448, 1, 4, 0}, + {"_0_0_fogData[0].heightFogEndColor_fogStartOffset", true, 464, 1, 4, 0}, + {"_0_0_fogData[1].densityParams", true, 480, 1, 4, 0}, + {"_0_0_fogData[1].classicFogParams", true, 496, 1, 4, 0}, + {"_0_0_fogData[1].heightPlane", true, 512, 1, 4, 0}, + {"_0_0_fogData[1].color_and_heightRate", true, 528, 1, 4, 0}, + {"_0_0_fogData[1].heightDensity_and_endColor", true, 544, 1, 4, 0}, + {"_0_0_fogData[1].sunAngle_and_sunColor", true, 560, 1, 4, 0}, + {"_0_0_fogData[1].heightColor_and_endFogDistance", true, 576, 1, 4, 0}, + {"_0_0_fogData[1].sunPercentage", true, 592, 1, 4, 0}, + {"_0_0_fogData[1].sunDirection_and_fogZScalar", true, 608, 1, 4, 0}, + {"_0_0_fogData[1].heightFogCoeff", true, 624, 1, 4, 0}, + {"_0_0_fogData[1].mainFogCoeff", true, 640, 1, 4, 0}, + {"_0_0_fogData[1].heightDensityFogCoeff", true, 656, 1, 4, 0}, + {"_0_0_fogData[1].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 672, 1, 4, 0}, + {"_0_0_fogData[1].heightFogEndColor_fogStartOffset", true, 688, 1, 4, 0}, + {"_0_0_fogData[2].densityParams", true, 704, 1, 4, 0}, + {"_0_0_fogData[2].classicFogParams", true, 720, 1, 4, 0}, + {"_0_0_fogData[2].heightPlane", true, 736, 1, 4, 0}, + {"_0_0_fogData[2].color_and_heightRate", true, 752, 1, 4, 0}, + {"_0_0_fogData[2].heightDensity_and_endColor", true, 768, 1, 4, 0}, + {"_0_0_fogData[2].sunAngle_and_sunColor", true, 784, 1, 4, 0}, + {"_0_0_fogData[2].heightColor_and_endFogDistance", true, 800, 1, 4, 0}, + {"_0_0_fogData[2].sunPercentage", true, 816, 1, 4, 0}, + {"_0_0_fogData[2].sunDirection_and_fogZScalar", true, 832, 1, 4, 0}, + {"_0_0_fogData[2].heightFogCoeff", true, 848, 1, 4, 0}, + {"_0_0_fogData[2].mainFogCoeff", true, 864, 1, 4, 0}, + {"_0_0_fogData[2].heightDensityFogCoeff", true, 880, 1, 4, 0}, + {"_0_0_fogData[2].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 896, 1, 4, 0}, + {"_0_0_fogData[2].heightFogEndColor_fogStartOffset", true, 912, 1, 4, 0}, + {"_0_0_fogData[3].densityParams", true, 928, 1, 4, 0}, + {"_0_0_fogData[3].classicFogParams", true, 944, 1, 4, 0}, + {"_0_0_fogData[3].heightPlane", true, 960, 1, 4, 0}, + {"_0_0_fogData[3].color_and_heightRate", true, 976, 1, 4, 0}, + {"_0_0_fogData[3].heightDensity_and_endColor", true, 992, 1, 4, 0}, + {"_0_0_fogData[3].sunAngle_and_sunColor", true, 1008, 1, 4, 0}, + {"_0_0_fogData[3].heightColor_and_endFogDistance", true, 1024, 1, 4, 0}, + {"_0_0_fogData[3].sunPercentage", true, 1040, 1, 4, 0}, + {"_0_0_fogData[3].sunDirection_and_fogZScalar", true, 1056, 1, 4, 0}, + {"_0_0_fogData[3].heightFogCoeff", true, 1072, 1, 4, 0}, + {"_0_0_fogData[3].mainFogCoeff", true, 1088, 1, 4, 0}, + {"_0_0_fogData[3].heightDensityFogCoeff", true, 1104, 1, 4, 0}, + {"_0_0_fogData[3].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 1120, 1, 4, 0}, + {"_0_0_fogData[3].heightFogEndColor_fogStartOffset", true, 1136, 1, 4, 0}, + {"_0_0_fogData[4].densityParams", true, 1152, 1, 4, 0}, + {"_0_0_fogData[4].classicFogParams", true, 1168, 1, 4, 0}, + {"_0_0_fogData[4].heightPlane", true, 1184, 1, 4, 0}, + {"_0_0_fogData[4].color_and_heightRate", true, 1200, 1, 4, 0}, + {"_0_0_fogData[4].heightDensity_and_endColor", true, 1216, 1, 4, 0}, + {"_0_0_fogData[4].sunAngle_and_sunColor", true, 1232, 1, 4, 0}, + {"_0_0_fogData[4].heightColor_and_endFogDistance", true, 1248, 1, 4, 0}, + {"_0_0_fogData[4].sunPercentage", true, 1264, 1, 4, 0}, + {"_0_0_fogData[4].sunDirection_and_fogZScalar", true, 1280, 1, 4, 0}, + {"_0_0_fogData[4].heightFogCoeff", true, 1296, 1, 4, 0}, + {"_0_0_fogData[4].mainFogCoeff", true, 1312, 1, 4, 0}, + {"_0_0_fogData[4].heightDensityFogCoeff", true, 1328, 1, 4, 0}, + {"_0_0_fogData[4].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 1344, 1, 4, 0}, + {"_0_0_fogData[4].heightFogEndColor_fogStartOffset", true, 1360, 1, 4, 0}, + {"_0_0_fogData[5].densityParams", true, 1376, 1, 4, 0}, + {"_0_0_fogData[5].classicFogParams", true, 1392, 1, 4, 0}, + {"_0_0_fogData[5].heightPlane", true, 1408, 1, 4, 0}, + {"_0_0_fogData[5].color_and_heightRate", true, 1424, 1, 4, 0}, + {"_0_0_fogData[5].heightDensity_and_endColor", true, 1440, 1, 4, 0}, + {"_0_0_fogData[5].sunAngle_and_sunColor", true, 1456, 1, 4, 0}, + {"_0_0_fogData[5].heightColor_and_endFogDistance", true, 1472, 1, 4, 0}, + {"_0_0_fogData[5].sunPercentage", true, 1488, 1, 4, 0}, + {"_0_0_fogData[5].sunDirection_and_fogZScalar", true, 1504, 1, 4, 0}, + {"_0_0_fogData[5].heightFogCoeff", true, 1520, 1, 4, 0}, + {"_0_0_fogData[5].mainFogCoeff", true, 1536, 1, 4, 0}, + {"_0_0_fogData[5].heightDensityFogCoeff", true, 1552, 1, 4, 0}, + {"_0_0_fogData[5].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 1568, 1, 4, 0}, + {"_0_0_fogData[5].heightFogEndColor_fogStartOffset", true, 1584, 1, 4, 0}, + {"_0_0_fogData[6].densityParams", true, 1600, 1, 4, 0}, + {"_0_0_fogData[6].classicFogParams", true, 1616, 1, 4, 0}, + {"_0_0_fogData[6].heightPlane", true, 1632, 1, 4, 0}, + {"_0_0_fogData[6].color_and_heightRate", true, 1648, 1, 4, 0}, + {"_0_0_fogData[6].heightDensity_and_endColor", true, 1664, 1, 4, 0}, + {"_0_0_fogData[6].sunAngle_and_sunColor", true, 1680, 1, 4, 0}, + {"_0_0_fogData[6].heightColor_and_endFogDistance", true, 1696, 1, 4, 0}, + {"_0_0_fogData[6].sunPercentage", true, 1712, 1, 4, 0}, + {"_0_0_fogData[6].sunDirection_and_fogZScalar", true, 1728, 1, 4, 0}, + {"_0_0_fogData[6].heightFogCoeff", true, 1744, 1, 4, 0}, + {"_0_0_fogData[6].mainFogCoeff", true, 1760, 1, 4, 0}, + {"_0_0_fogData[6].heightDensityFogCoeff", true, 1776, 1, 4, 0}, + {"_0_0_fogData[6].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 1792, 1, 4, 0}, + {"_0_0_fogData[6].heightFogEndColor_fogStartOffset", true, 1808, 1, 4, 0}, + {"_0_0_fogData[7].densityParams", true, 1824, 1, 4, 0}, + {"_0_0_fogData[7].classicFogParams", true, 1840, 1, 4, 0}, + {"_0_0_fogData[7].heightPlane", true, 1856, 1, 4, 0}, + {"_0_0_fogData[7].color_and_heightRate", true, 1872, 1, 4, 0}, + {"_0_0_fogData[7].heightDensity_and_endColor", true, 1888, 1, 4, 0}, + {"_0_0_fogData[7].sunAngle_and_sunColor", true, 1904, 1, 4, 0}, + {"_0_0_fogData[7].heightColor_and_endFogDistance", true, 1920, 1, 4, 0}, + {"_0_0_fogData[7].sunPercentage", true, 1936, 1, 4, 0}, + {"_0_0_fogData[7].sunDirection_and_fogZScalar", true, 1952, 1, 4, 0}, + {"_0_0_fogData[7].heightFogCoeff", true, 1968, 1, 4, 0}, + {"_0_0_fogData[7].mainFogCoeff", true, 1984, 1, 4, 0}, + {"_0_0_fogData[7].heightDensityFogCoeff", true, 2000, 1, 4, 0}, + {"_0_0_fogData[7].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 2016, 1, 4, 0}, + {"_0_0_fogData[7].heightFogEndColor_fogStartOffset", true, 2032, 1, 4, 0}, } }, + }}, + {"adtLodShader", { { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + 0, { + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, } }, + }}, + {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -1870,31 +2047,43 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, - {"imguiShader", { + {"adtLodShader", { { - 1, { - {"_0_1_ProjMtx", true, 0, 4, 4, 0}, - {"_0_1_uiScale", true, 64, 1, 4, 0}, + 0, { + {"_0_0_uViewUp", true, 0, 1, 4, 0}, + {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, + {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, + {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, + {"_0_0_FogColor", true, 64, 1, 4, 0}, + {"_0_0_uNewFormula", false, 80, 1, 1, 0}, } }, }}, - {"drawLinesShader", { + {"drawDepthShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 2, { + {"_0_2_drawDepth", false, 0, 1, 1, 0}, + {"_0_2_uFarPlane", true, 4, 1, 1, 0}, + {"_0_2_uNearPlane", true, 8, 1, 1, 0}, } }, }}, - {"ribbonShader", { + {"adtShader", { + { + 2, { + {"_1_2_scaleFactorPerLayer", true, 0, 1, 4, 0}, + {"_1_2_animation_rotationPerLayer", false, 16, 1, 4, 0}, + {"_1_2_animation_speedPerLayer", false, 32, 1, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -3129,10 +3409,52 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"drawLinesShader", { + { + 1, { + {"_0_1_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawPoints", { + { + 1, { + {"_0_1_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawPortalShader", { + { + 1, { + {"_1_1_uColor", true, 0, 1, 4, 0}, + } + }, + }}, + {"ffxgauss4", { + { + 4, { + {"_0_4_texOffsetX", true, 0, 1, 4, 0}, + {"_0_4_texOffsetY", true, 16, 1, 4, 0}, + } + }, + }}, + {"ffxglow", { + { + 4, { + {"_0_4_blurAmount", true, 0, 1, 4, 0}, + } + }, + }}, + {"skyConus", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -3259,52 +3581,26 @@ const std::unordered_map GBufferVLK::getSubBuffer(int sizeInBy { - std::unique_lock lock(m_mutex); + std::unique_lock lock(m_subBufferMutex); currentSubBuffers.push_back(subBuffer); subBuffer->m_iterator = std::prev(currentSubBuffers.end()); } @@ -211,12 +211,14 @@ void GBufferVLK::deleteSubBuffer(std::list>::const_ const OffsetAllocator::Allocation &uiaAlloc, int subBuffersize) { - std::unique_lock lock(m_mutex); + if (subBuffersize > 0) { deallocateSubBuffer(alloc, uiaAlloc); } - - currentSubBuffers.erase(it); + { + std::unique_lock lock(m_subBufferMutex); + currentSubBuffers.erase(it); + } } void GBufferVLK::save(int length) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index f13ca5cf2..827dcc173 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -80,6 +80,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this whole buffer needs to be submitted size_t lastSubmittedBufferSize = 0; diff --git a/wowViewerLib/src/renderer/IRenderParameters.h b/wowViewerLib/src/renderer/IRenderParameters.h index 95e1de2a3..8dd5bccd4 100644 --- a/wowViewerLib/src/renderer/IRenderParameters.h +++ b/wowViewerLib/src/renderer/IRenderParameters.h @@ -9,6 +9,7 @@ #include #include #include "frame/FrameInputParams.h" +#include "frame/FrameProfile.h" class IRenderFunction { public: @@ -41,6 +42,8 @@ class IRendererParameters : public std::enable_shared_from_this SceneUpdateLambda { l_updateProcessingFrame(l_currentFrame); + TracyMessageStr(("Culling stage frame = " + std::to_string(l_currentFrame))); + std::shared_ptr framePlan = this_s->processCulling(frameInputParams); return [framePlan, frameInputParams, this_s, l_currentFrame, l_updateProcessingFrame]() -> std::unique_ptr { diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 472cb0049..9b177d255 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -88,6 +88,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { ZoneScoped ; + if (frameScenario == nullptr) return; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 70e5dd802..ce09916ae 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -9,8 +9,6 @@ std::shared_ptr MapSceneRenderer::processCulling(const std::shared_ptr> &frameInputParams) { -// auto &scenes = frameInputParams->frameParameters->scene; - // for (auto &scene : scenes) { auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); auto mapPlan = std::make_shared(); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 17671af1c..e9d1662f5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -628,7 +628,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // ); mapScene->update(framePlan); - mapScene->updateBuffers(framePlan); + mapScene->updateBuffers(l_this, framePlan); glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); updateSceneWideChunk(sceneWideChunk, @@ -647,23 +647,33 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes](CmdBufRecorder &uploadCmd) -> void { + { + ZoneScopedN("Post Load"); //Do postLoad here. So creation of stuff is done from main thread mapScene->doPostLoad(l_this, framePlan); + } + { + ZoneScopedN("Collect Portal Meshes"); //And add portal meshes - for (auto &view : framePlan->viewsHolder.getInteriorViews()) { - view->collectPortalMeshes(*transparentMeshes); + for (auto const &view: framePlan->viewsHolder.getInteriorViews()) { + view->collectPortalMeshes(*transparentMeshes); } { - auto exteriorView = framePlan->viewsHolder.getExterior(); - if (exteriorView != nullptr) { - exteriorView->collectPortalMeshes(*transparentMeshes); - } + auto const &exteriorView = framePlan->viewsHolder.getExterior(); + if (exteriorView != nullptr) { + exteriorView->collectPortalMeshes(*transparentMeshes); + } } - + } + { + ZoneScopedN("Set Last Created Plan"); //Needs to be executed only after lock l_this->m_lastCreatedPlan = framePlan; - + } + { + ZoneScopedN("Flush Staging Buffer"); l_this->m_stagingRingBuffer->flushBuffers(); + } // --------------------- // Upload stuff From 1a015eb2ae143a27617e1bbb78a7bd2819d57237 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 19 Sep 2023 01:25:58 +0300 Subject: [PATCH 115/212] - Pipeline barrier for buffer copy command makes app work on AMD properly --- .../glsl/common/commonFogFunctions.glsl | 55 +- .../glsl/common/commonLightFunctions.glsl | 2 + .../glsl/common/commonUboSceneData.glsl | 12 + .../glsl/forwardRendering/adtShader.frag | 7 +- .../glsl/forwardRendering/adtShader.vert | 5 +- .../glsl/forwardRendering/drawBBShader.vert | 6 +- .../forwardRendering/drawPortalShader.vert | 5 +- .../forwardRendering/m2ParticleShader.frag | 8 +- .../forwardRendering/m2ParticleShader.vert | 5 +- .../glsl/forwardRendering/m2Shader.frag | 15 +- .../glsl/forwardRendering/m2Shader.vert | 12 +- .../glsl/forwardRendering/ribbonShader.frag | 8 +- .../glsl/forwardRendering/ribbonShader.vert | 6 +- .../glsl/forwardRendering/skyConus.frag | 6 +- .../glsl/forwardRendering/skyConus.vert | 6 +- .../glsl/forwardRendering/waterShader.frag | 7 +- .../glsl/forwardRendering/waterShader.vert | 6 +- .../forwardRendering/waterfallShader.frag | 8 +- .../forwardRendering/waterfallShader.vert | 6 +- .../glsl/forwardRendering/wmoShader.frag | 8 +- .../glsl/forwardRendering/wmoShader.vert | 6 +- .../shaders/glsl/visBuffer/m2Shader.frag | 7 +- .../shaders/glsl/visBuffer/m2Shader.vert | 6 +- .../src/engine/shader/ShaderDefinitions.h | 2308 ++--------------- .../src/gapi/UniformBufferStructures.h | 5 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 141 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 13 +- wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h | 1 - .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 1 + .../src/gapi/vulkan/buffers/GBufferVLK.h | 1 + .../vulkan/buffers/GStagingRingBuffer.cpp | 3 + .../gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp | 8 +- .../vulkan/buffers/gpu/BufferStagingVLK.cpp | 4 + .../CommandBufferRecorder.cpp | 67 +- .../TextureUploadHelper.cpp | 2 +- .../TextureUploadHelper.h | 1 - .../src/gapi/vulkan/textures/GTextureVLK.cpp | 5 +- .../renderer/mapScene/MapSceneRenderer.cpp | 30 +- 38 files changed, 563 insertions(+), 2239 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl diff --git a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl index d91581d66..c756d2a6b 100644 --- a/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonFogFunctions.glsl @@ -1,3 +1,6 @@ +#ifndef COMMON_FOG_FUNCTIONS +#define COMMON_FOG_FUNCTIONS + struct PSFog { vec4 densityParams; @@ -108,7 +111,7 @@ float saturatef(float x) { return clamp(x, 0.0f, 1.0f); } -vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec3 uViewUp, in vec3 vertexInViewSpaceMy, in vec3 sunDirInViewSpace, in int blendMode) { +vec4 makeFog2(const in PSFog mainFogData, in vec4 final, in vec3 uViewUp, in vec3 vertexInViewSpaceMy, in vec3 sunDirInViewSpace, in int blendMode) { float fogRateScalar = 1.0f; //Unk stuff atm. bool t138 = false; //some strange parameter from materials vec3 vertexInViewSpace = vertexInViewSpaceMy; @@ -121,8 +124,11 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec vec4 outColor_713 = vec4(0.0); //accumulator - for (int i = 0; i < fogCount; i++) { - vec4 classicFogParams = mainFogData[i].classicFogParams; + const PSFog mainFogData1 = mainFogData; + const PSFog mainFogData2 = mainFogData; + +// for (int i = 0; i < fogCount; i++) { + vec4 classicFogParams = mainFogData1.classicFogParams; float classicFogEnabled = classicFogParams.x; float classicEnd = classicFogParams.y; float classicEndMinusStartInv = classicFogParams.z; @@ -148,15 +154,15 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec if (!(_ret0_741)) { // Block 743 - vec4 densityParams = mainFogData[i].densityParams; + vec4 densityParams = mainFogData1.densityParams; float start = densityParams.x; float end = densityParams.y; float density = densityParams.z; float bias = densityParams.w; - float heightRate = mainFogData[i].color_and_heightRate.w; - float heightDensity = mainFogData[i].heightDensity_and_endColor.x; - float fogZScalar = mainFogData[i].sunDirection_and_fogZScalar.w; - vec4 t755 = mainFogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; + float heightRate = mainFogData1.color_and_heightRate.w; + float heightDensity = mainFogData1.heightDensity_and_endColor.x; + float fogZScalar = mainFogData1.sunDirection_and_fogZScalar.w; + vec4 t755 = mainFogData1.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha; float mainFogCurveEndDist = t755.x; float mainFogCurveStartDist = t755.y; float legacyFogBlend = t755.z; @@ -185,13 +191,13 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float exp_783 = exp((expMax_781 * heightDensity)); float legacyExpFogHeight_784 = (1.0 / exp_783); - vec4 t785 = mainFogData[i].heightPlane; + vec4 t785 = mainFogData1.heightPlane; float dot_787 = dot(t785.xyz, vertexInViewSpace); float height_789 = (dot_787 + t785.w); float saturate_791 = saturatef((height_789 * heightRate)); float heightFog_792 = (1.0f - saturate_791); - vec4 t793 = mainFogData[i].heightFogCoeff; + vec4 t793 = mainFogData1.heightFogCoeff; float xSqrd_794 = (heightFog_792 * heightFog_792); float xCubed_795 = (xSqrd_794 * heightFog_792); float saturate_806 = saturatef(((((t793.x * xCubed_795) + (t793.y * xSqrd_794)) + (t793.z * heightFog_792)) + t793.w)); @@ -207,12 +213,12 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float artFogNormalizedDistance_823 = saturatef(((vLength_778 - mainFogCurveStartDist) / (mainFogCurveEndDist - mainFogCurveStartDist))); float engineFogNormalizedDistance_825 = saturatef((vLength_778 / mainFogCurveEndDist)); - vec4 t826 = mainFogData[i].mainFogCoeff; + vec4 t826 = mainFogData1.mainFogCoeff; float xSqrd_827 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); float xCubed_828 = (xSqrd_827 * artFogNormalizedDistance_823); float saturate_839 = saturatef(((((t826.x * xCubed_828) + (t826.y * xSqrd_827)) + (t826.z * artFogNormalizedDistance_823)) + t826.w)); float fogResult_841 = saturatef((1.0f - saturate_839)); - vec4 t842 = mainFogData[i].heightDensityFogCoeff; + vec4 t842 = mainFogData1.heightDensityFogCoeff; float xSqrd_843 = (artFogNormalizedDistance_823 * artFogNormalizedDistance_823); float xCubed_844 = (xSqrd_843 * artFogNormalizedDistance_823); float saturate_855 = saturatef(((((t842.x * xCubed_844) + (t842.y * xSqrd_843)) + (t842.z * artFogNormalizedDistance_823)) + t842.w)); @@ -251,37 +257,37 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec float _retVal_956 = _retVal_913; float heightFog_955 = heightFog_912; vec3 normalize_918 = normalize(vertexInViewSpace); - float t924 = mainFogData[i].sunAngle_and_sunColor.x; + float t924 = mainFogData1.sunAngle_and_sunColor.x; float alpha_935 = final.w; float end2_938 = saturatef( - (vLength - mainFogData[i].heightFogEndColor_fogStartOffset.w) / - mainFogData[i].heightColor_and_endFogDistance.w + (vLength - mainFogData1.heightFogEndColor_fogStartOffset.w) / + mainFogData1.heightColor_and_endFogDistance.w ); //Height fog color calculation float end_940 = (end2_938 * (end2_938 * end2_938)); vec3 heightColor_942 = mix( - validateFogColor(mainFogData[0].heightColor_and_endFogDistance.xyz, blendMode), - validateFogColor(mainFogData[0].heightFogEndColor_fogStartOffset.xyz, blendMode), + validateFogColor(mainFogData2.heightColor_and_endFogDistance.xyz, blendMode), + validateFogColor(mainFogData2.heightFogEndColor_fogStartOffset.xyz, blendMode), vec3(end2_938) ); //Usual fog color calculation float saturate_943 = saturatef(end_940); vec3 fogFinal_945 = mix( - validateFogColor(mainFogData[0].color_and_heightRate.xyz, blendMode), - validateFogColor(mainFogData[0].heightDensity_and_endColor.yzw, blendMode), + validateFogColor(mainFogData2.color_and_heightRate.xyz, blendMode), + validateFogColor(mainFogData2.heightDensity_and_endColor.yzw, blendMode), vec3(saturate_943) ); //Mix fog colors above together vec3 fogFinal_947 = mix(fogFinal_945, heightColor_942, vec3(heightFog_955)); - float dot_948 = dot(normalize_918, mainFogData[i].sunDirection_and_fogZScalar.xyz); + float dot_948 = dot(normalize_918, mainFogData1.sunDirection_and_fogZScalar.xyz); float nDotSun_949 = saturatef(dot_948); vec3 sunColor_951 = mix( fogFinal_947, - validateFogColor(mainFogData[0].sunAngle_and_sunColor.yzw, blendMode), - vec3(mainFogData[i].sunPercentage.x) + validateFogColor(mainFogData2.sunAngle_and_sunColor.yzw, blendMode), + vec3(mainFogData1.sunPercentage.x) ); float nDotSun_953 = saturatef((nDotSun_949 - t924)); @@ -323,9 +329,10 @@ vec4 makeFog2(const in PSFog mainFogData[8], int fogCount, in vec4 final, in vec vec4 t982 = vec4(lerp_981, alpha_988); - vec4 outColor_986 = (outColor_713 + (t982 * mainFogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); + vec4 outColor_986 = (outColor_713 + (t982 * mainFogData1.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha.w)); outColor_713 = outColor_986; - } +// } return outColor_713; } +#endif diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index d0e4c91f5..d7643ffc8 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -112,6 +112,8 @@ vec3 calcLight( return result + specular; } + + vec3 calcSpec(const in float texAlpha) { return vec3(0.0f); } diff --git a/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl b/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl new file mode 100644 index 000000000..f47434e03 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl @@ -0,0 +1,12 @@ +#ifndef COMMON_SCENE_DATA +#define COMMON_SCENE_DATA + +#include "commonFogFunctions.glsl" +#include "commonLightFunctions.glsl" + +layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { + SceneWideParams scene; + PSFog fogData; +}; + +#endif \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 8f45c42af..1b2d87e96 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -24,10 +24,7 @@ layout(set=2, binding=11) uniform sampler2D uLayerHeight1; layout(set=2, binding=12) uniform sampler2D uLayerHeight2; layout(set=2, binding=13) uniform sampler2D uLayerHeight3; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { vec4 uPos; @@ -162,7 +159,7 @@ void main() { vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; finalColor.rgb += specTerm; - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); finalColor.a = 1.0; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index ec8901094..7c8299a08 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -14,10 +14,7 @@ layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { vec4 uPos; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert index 7cdeee1d5..ac8b96a50 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawBBShader.vert @@ -7,14 +7,12 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" /* vertex shader code */ layout(location = 0) in vec3 aPosition; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + // Whole model layout(std140, set=0, binding=1) uniform modelWideBlockVS { diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert index 0ea8bef19..116fab222 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.vert @@ -12,10 +12,7 @@ precision highp int; layout(location = 0) in vec3 aPosition; //Whole scene -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" void main() { vec4 worldPoint = vec4(aPosition.xyz, 1); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index 4b3998a8f..2aed8930f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -14,11 +14,9 @@ layout(location = 5) in float alphaCutoff; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; //Individual meshes layout(std140, set=1, binding=4) uniform meshWideBlockPS { @@ -104,7 +102,7 @@ void main() { // .xyz; vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); outputColor.rgba = finalColor ; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert index 89d9e9192..9b7b1155a 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.vert @@ -23,11 +23,8 @@ layout(location = 5) out float vAlphaCutoff; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" -layout(std140, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; void main() { vec4 aPositionVec4 = vec4(aPosition, 1); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 6fcd351ea..61d22fd8e 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -8,19 +8,16 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" #include "../common/commonM2Material.glsl" +#include "../common/commonUboSceneData.glsl" layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec2 vTexCoord3; -layout(location=3) in vec3 vNormal; -layout(location=4) in vec4 vPosition_EdgeFade; +layout(location=2) in vec3 vNormal; +layout(location=3) in vec4 vPosition_EdgeFade; layout(location=0) out vec4 outputColor; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + //Whole model #include "../common/commonM2DescriptorSet.glsl" @@ -42,7 +39,7 @@ void main() { /* Animation support */ vec2 texCoord = vTexCoord.xy; vec2 texCoord2 = vTexCoord2.xy; - vec2 texCoord3 = vTexCoord3.xy; + vec2 texCoord3 = vTexCoord2.xy; vec4 finalColor = vec4(0); @@ -173,7 +170,7 @@ void main() { ) .xyz; - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index 16d25d038..ca68f773f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -10,6 +10,7 @@ precision highp int; #include "../common/commonFogFunctions.glsl" #include "../common/commonFunctions.glsl" #include "../common/commonM2Material.glsl" +#include "../common/commonUboSceneData.glsl" /* vertex shader code */ layout(location=0) in vec3 aPosition; @@ -20,10 +21,7 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; //Whole scene -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + //Whole model #include "../common/commonM2DescriptorSet.glsl" @@ -39,9 +37,8 @@ layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { //Shader output layout(location=0) out vec2 vTexCoord; layout(location=1) out vec2 vTexCoord2; -layout(location=2) out vec2 vTexCoord3; -layout(location=3) out vec3 vNormal; -layout(location=4) out vec4 vPosition_EdgeFade; +layout(location=2) out vec3 vNormal; +layout(location=3) out vec4 vPosition_EdgeFade; void main() { @@ -72,7 +69,6 @@ void main() { vTexCoord = aTexCoord; vTexCoord2 = aTexCoord2; - vTexCoord3 = aTexCoord2; gl_Position = scene.uPMatrix * vertexPosInView; vNormal = normal; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index 47489acec..b5ada8be1 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -7,16 +7,14 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" precision highp float; layout(location = 0) in vec3 vPosition; layout(location = 1) in vec4 vColor; layout(location = 2) in vec2 vTexcoord0; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + layout(std140, set=1, binding=3) uniform textureMatrices { mat4 textureMatrix[64]; @@ -46,7 +44,7 @@ void main() { vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); outputColor = finalColor; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert index 9ed58bcca..e07baea34 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.vert @@ -7,16 +7,14 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" precision highp float; layout(location = 0) in vec3 aPosition; layout(location = 1) in vec4 aColor; layout(location = 2) in vec2 aTexcoord0; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + layout(location = 0) out vec3 vPosition; layout(location = 1) out vec4 vColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag index 2f8197d5e..20e2b17e9 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag @@ -7,11 +7,9 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; layout(location = 0) in vec4 vColor; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert index 1dd573d93..fdbc53b11 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert @@ -7,13 +7,11 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" precision highp float; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + layout(std140, set=1, binding=1) uniform meshWideBlockVS { vec4 skyColor[6]; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 873edd213..183c9cc4f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -16,10 +16,7 @@ layout(location=0) out vec4 outputColor; layout(set=2,binding=5) uniform sampler2D uTexture; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" //Individual meshes layout(std140, set=1, binding=4) uniform meshWideBlockPS { @@ -75,7 +72,7 @@ void main() { } //BlendMode is always GxBlend_Alpha - finalColor.rgb = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; + finalColor.rgb = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; outputColor = vec4(finalColor.rgb, 0.7); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index f9df7ca2e..ac9658f93 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -7,15 +7,13 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" layout(location=0) in vec4 aPositionTransp; layout(location=1) in vec2 aTexCoord; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + layout(std140, set=1, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index 3a3c7d065..edb9cd181 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -8,6 +8,7 @@ precision highp int; #include "../common/commonFunctions.glsl" #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; @@ -22,10 +23,7 @@ layout(set=3,binding=10) uniform sampler2D uNormalTex; layout(location=0) out vec4 outputColor; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + //Whole model #include "../common/commonM2DescriptorSet.glsl" @@ -115,7 +113,7 @@ void main() { ); vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - finalColor = makeFog2(fogData,int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); + finalColor = makeFog2(fogData,/*int(scene.extLight.adtSpecMult_fogCount.y),*/ finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); outputColor = finalColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index fb5ee0406..4cd0ee86f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -9,6 +9,7 @@ precision highp int; #include "../common/commonM2Material.glsl" #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" precision highp float; @@ -21,10 +22,7 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; //Whole scene -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + // Whole model #include "../common/commonM2DescriptorSet.glsl" diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index 6f150cca1..3c0db6be6 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -10,6 +10,7 @@ precision highp int; #include "../common/commonFogFunctions.glsl" #include "../common/commonFunctions.glsl" #include "../common/commonWMOMaterial.glsl" +#include "../common/commonUboSceneData.glsl" @@ -24,10 +25,7 @@ layout(location=7) in vec4 vPosition; layout(location=8) in vec3 vNormal; layout(location=9) in vec4 vWmoAmbient; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + layout(std140, set=1, binding=4) uniform meshWideBlockPS { ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; @@ -89,7 +87,7 @@ void main() { finalOpacity ); - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, UseLitColor_EnableAlpha_PixelShader_BlendMode.w); finalColor.a = 1.0; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index f4e0c9ebe..8c9436e1c 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -22,10 +22,8 @@ layout (location = 7) in vec4 aColor2; layout (location = 8) in vec4 aColorSecond; layout (location = 9) in vec4 wmoAmbient; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" + layout(std140, set=1, binding=1) uniform modelWideBlockVS { mat4 uPlacementMat; }; diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index a4fd6c428..8834aa30c 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -19,10 +19,7 @@ layout(location=5) in flat int meshIndex; layout(location=0) out vec4 outputColor; -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; +#include "../common/commonUboSceneData.glsl" //Whole model #include "../common/commonM2IndirectDescriptorSet.glsl" @@ -191,7 +188,7 @@ void main() { ) .xyz; - finalColor = makeFog2(fogData, int(scene.extLight.adtSpecMult_fogCount.y), finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert index e590da293..54f85f5b6 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -10,6 +10,7 @@ precision highp int; #include "../common/commonFogFunctions.glsl" #include "../common/commonFunctions.glsl" #include "../common/commonM2Material.glsl" +#include "../common/commonUboSceneData.glsl" /* vertex shader code */ layout(location=0) in vec3 aPosition; @@ -20,10 +21,7 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; //Whole scene -layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { - SceneWideParams scene; - PSFog fogData[8]; -}; + //Whole model #include "../common/commonM2DescriptorSet.glsl" diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 03da57150..c0b684ee3 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -414,7 +414,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,2,48}, - {0,0,2048}, + {0,0,480}, {1,1,64}, }, { @@ -496,7 +496,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, {1,1,64}, }, { @@ -642,7 +642,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,1,112}, - {0,0,2048}, + {0,0,480}, }, { { @@ -823,7 +823,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, }, { { @@ -1081,7 +1081,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,2048}, + {0,0,480}, }, { { @@ -1120,7 +1120,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, }, { { @@ -1156,7 +1156,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, {1,1,96}, }, { @@ -1197,7 +1197,7 @@ const std::unordered_map shaderMetaInfo = { {1,5,256}, {1,4,4096}, {1,2,256}, - {0,0,2048}, + {0,0,480}, {1,1,64}, {1,6,4096}, {1,3,16384}, @@ -1242,7 +1242,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,2048}, + {0,0,480}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -1320,7 +1320,7 @@ const std::unordered_map shaderMetaInfo = { { {1,4,16}, {1,3,4096}, - {0,0,2048}, + {0,0,480}, }, { { @@ -1357,7 +1357,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, }, { { @@ -1393,7 +1393,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,2048}, + {0,0,480}, }, { { @@ -1430,7 +1430,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,96}, - {0,0,2048}, + {0,0,480}, }, { { @@ -1467,7 +1467,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,2048}, + {0,0,480}, {1,1,64}, }, { @@ -1505,7 +1505,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {2,5,96}, - {0,0,2048}, + {0,0,480}, {1,1,64}, {1,2,256}, {1,3,16384}, @@ -1554,7 +1554,7 @@ const std::unordered_map shaderMetaInfo = { {2,4,16}, {1,6,4096}, {1,3,16384}, - {0,0,2048}, + {0,0,480}, {1,1,64}, {1,2,256}, {1,4,4096}, @@ -1596,7 +1596,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,32}, - {0,0,2048}, + {0,0,480}, }, { { @@ -1642,7 +1642,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,1,64}, - {0,0,2048}, + {0,0,480}, {1,2,16}, }, { @@ -1679,7 +1679,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,2048}, + {0,0,480}, }, { { @@ -1726,7 +1726,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,16384}, {1,1,64}, - {0,0,2048}, + {0,0,480}, {1,2,256}, {1,4,4096}, {1,5,256}, @@ -1795,118 +1795,20 @@ const std::unordered_map &swapChainTextures } } +std::string VkMemoryPropertyFlagBitsGetString(VkMemoryPropertyFlags value) { + std::string strings = ""; + if (value == 0) { strings += "None"; return strings; } + if (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT & value) strings += " MEMORY_PROPERTY_DEVICE_LOCAL_BIT"; + if (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT & value) strings += " MEMORY_PROPERTY_HOST_VISIBLE_BIT"; + if (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT & value) strings += " MEMORY_PROPERTY_HOST_COHERENT_BIT"; + if (VK_MEMORY_PROPERTY_HOST_CACHED_BIT & value) strings += " MEMORY_PROPERTY_HOST_CACHED_BIT"; + if (VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT & value) strings += " MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT"; + if (VK_MEMORY_PROPERTY_PROTECTED_BIT & value) strings += " MEMORY_PROPERTY_PROTECTED_BIT"; + if (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD & value) strings += " MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD"; + if (VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD & value) strings += " MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD"; + if (VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV & value) strings += " MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV"; + return strings; +} + +std::string VkMemoryHeapFlagBitsGetStrings(VkMemoryHeapFlags value) { + std::string string; + if (value == 0) { string += "None"; return string; } + if (VK_MEMORY_HEAP_DEVICE_LOCAL_BIT & value) string += " MEMORY_HEAP_DEVICE_LOCAL_BIT"; + if (VK_MEMORY_HEAP_MULTI_INSTANCE_BIT & value) string += " MEMORY_HEAP_MULTI_INSTANCE_BIT"; + return string; +} void GDeviceVLK::pickPhysicalDevice() { uint32_t deviceCount = 0; @@ -650,6 +670,29 @@ void GDeviceVLK::pickPhysicalDevice() { if (physicalDevice == VK_NULL_HANDLE) { throw std::runtime_error("failed to find a suitable GPU!"); } + + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures); + + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + + std::cout << "deviceMemoryProperties.memoryHeapCount = " << deviceMemoryProperties.memoryHeapCount << std::endl; + for (int i = 0; i < deviceMemoryProperties.memoryHeapCount; i++) { + std::cout << "memoryHeaps["<(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.pEnabledFeatures = &deviceFeatures; - std::vector enabledDeviceExtensions = deviceExtensions; createInfo.enabledExtensionCount = enabledDeviceExtensions.size(); createInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data(); @@ -714,9 +754,12 @@ void GDeviceVLK::createLogicalDevice() { vkGetPhysicalDeviceFeatures2( physicalDevice, &physical_features2 ); physical_features2.pNext = &indexing_features; + physical_features2.features = deviceFeatures; - + createInfo.pEnabledFeatures = nullptr; createInfo.pNext = &physical_features2; + } else { + createInfo.pEnabledFeatures = &deviceFeatures; } if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { @@ -842,6 +885,7 @@ void GDeviceVLK::createSyncObjects() { renderFinishedSemaphores[i] = std::make_shared(this->shared_from_this()); uploadSemaphores[i] = std::make_shared(this->shared_from_this()); + uploadSequenceSemaphores[i] = std::make_shared(this->shared_from_this()); frameBufSemaphores[i] = std::make_shared(this->shared_from_this()); } @@ -894,28 +938,52 @@ void GDeviceVLK::drawFrame(const std::vector> & } - auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); { - for (int i = 0; i < renderFuncs.size(); i++) { - dynamic_cast(renderFuncs[i].get())->executeUpload(*this, uploadCmd); + auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); + { + for (int i = 0; i < renderFuncs.size(); i++) { + dynamic_cast(renderFuncs[i].get())->executeUpload(*this, uploadCmd); + } } - } - - auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); - //Do Texture update - { - ZoneScopedN("Texture update"); - m_textureManager->processBLPTextures(); - auto textureVector = m_textureManager->getReadyToUploadTextures(); - textureUploadStrategy(textureVector.get(), frameBufCmd, uploadCmd); - //The next loop updates DescriptorSets - for(auto &wtexture : textureVector.get()) { - if( auto texture = wtexture.lock()) { - texture->executeOnChange(); + //Do Texture update + { + ZoneScopedN("Texture update"); + m_textureManager->processBLPTextures(); + auto textureVector = m_textureManager->getReadyToUploadTextures(); + textureUploadStrategy(textureVector.get(), uploadCmd); + //The next loop updates DescriptorSets + for (auto &wtexture: textureVector.get()) { + if (auto texture = wtexture.lock()) { + texture->executeOnChange(); + } } } } + { + std::vector uploadConseqWaitSemaphores = {}; + std::vector uploadWaitStages = {}; + if (m_frameNumber > IDevice::MAX_FRAMES_IN_FLIGHT) { + uploadConseqWaitSemaphores = { + uploadSequenceSemaphores[(currentDrawFrame + IDevice::MAX_FRAMES_IN_FLIGHT - 1) % + MAX_FRAMES_IN_FLIGHT]->getNativeSemaphore() + }; + uploadWaitStages = {VK_PIPELINE_STAGE_TRANSFER_BIT}; + } + + + submitQueue( + uploadQueue, + uploadConseqWaitSemaphores, + uploadWaitStages, + {uploadCmdBuf->getNativeCmdBuffer()}, + {uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), + uploadSequenceSemaphores[currentDrawFrame]->getNativeSemaphore()}, + uploadFences[currentDrawFrame]->getNativeFence() + ); + } + + { ZoneScopedN("DescriptorSet update"); m_descriptorSetUpdater->updateDescriptorSets(); @@ -931,6 +999,8 @@ void GDeviceVLK::drawFrame(const std::vector> & auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); { + auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); + //Begin render pass for Swap chain this->getNextSwapImageIndex(imageIndex); auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); @@ -941,16 +1011,6 @@ void GDeviceVLK::drawFrame(const std::vector> & } } - - submitQueue( - uploadQueue, - {}, - {}, - {uploadCmdBuf->getNativeCmdBuffer()}, - {uploadSemaphores[currentDrawFrame]->getNativeSemaphore()}, - uploadFences[currentDrawFrame]->getNativeFence() - ); - submitQueue( graphicsQueue, { @@ -1240,7 +1300,7 @@ void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, presentInfo.pWaitSemaphores = waitSemaphores.data(); presentInfo.swapchainCount = waitSemaphores.size(); - presentInfo.pSwapchains = swapchains.data(); + presentInfo.pSwapchains = swapchains.data(); presentInfo.pImageIndices = imageIndexes.data(); auto result = vkQueuePresentKHR(graphicsQueue, &presentInfo); @@ -1265,17 +1325,6 @@ void GDeviceVLK::executeDeallocators() { listOfDeallocators.pop_front(); } } -void GDeviceVLK::executeBufferDeallocators() { - std::lock_guard lock(m_listOfBufferDeallocatorsAccessMtx); - while ((!listOfBufferDeallocators.empty()) && (listOfBufferDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { - auto stuff = listOfBufferDeallocators.front(); - if (stuff.callback != nullptr) { - stuff.callback(); - } - - listOfBufferDeallocators.pop_front(); - } -} std::shared_ptr GDeviceVLK::getRenderPass( const std::vector &textureAttachments, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index a15c00ab5..48cbbeb18 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -188,14 +188,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this callback) override { - std::lock_guard lock(m_listOfDeallocatorsAccessMtx); - DeallocationRecord dr; - dr.frameNumberToDoAt = m_frameNumber+MAX_FRAMES_IN_FLIGHT; - dr.callback = callback; - listOfDeallocators.push_back(dr); - }; - void executeBufferDeallocators(); + VkFormat findDepthFormat(); @@ -312,6 +305,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> renderFinishedSemaphores; std::array, MAX_FRAMES_IN_FLIGHT> uploadSemaphores; + std::array, MAX_FRAMES_IN_FLIGHT> uploadSequenceSemaphores; std::array, MAX_FRAMES_IN_FLIGHT> frameBufSemaphores; std::vector> m_descriptorPools; @@ -383,9 +377,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this listOfDeallocators; - std::mutex m_listOfBufferDeallocatorsAccessMtx; - std::list listOfBufferDeallocators; - std::vector m_createdFrameBuffers; struct RenderPassAvalabilityStruct { diff --git a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h index 4331734cf..f4c3db9ab 100644 --- a/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/IDeviceVulkan.h @@ -32,7 +32,6 @@ class IDeviceVulkan { virtual VkDevice getVkDevice() = 0; virtual VkPhysicalDevice getVkPhysicalDevice() = 0; virtual void addDeallocationRecord(std::function callback) = 0; - virtual void addBufferDeallocationRecord(std::function callback) = 0; virtual VkDescriptorSet allocateDescriptorSetPrimitive( const std::shared_ptr &hDescriptorSetLayout, std::shared_ptr &out_desciptorPool) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index cbd1477b0..dbda39eeb 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -236,6 +236,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { auto ©Cmd = dataToBeUploaded.emplace_back(); copyCmd.src = m_gpuBuffer->getBuffer(); copyCmd.dst = newGpuBuf->getBuffer(); + copyCmd.needsBarrier = true; auto ®ion = copyCmd.copyRegions.emplace_back(); region.size = m_gpuBuffer->size(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 827dcc173..87cafaba8 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -29,6 +29,7 @@ struct VulkanCopyCommands { VkBuffer src; VkBuffer dst; std::vector copyRegions; + bool needsBarrier = false; }; class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index 0537609e5..9447c3064 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -12,6 +12,9 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of int bufferIndex = 0; uint32_t ¤tOffset = offsets[frame]; + if (size > STAGE_BUFFER_SIZE) + throw std::runtime_error(("size > STAGE_BUFFER_SIZE; size = " + std::to_string(size))); + { // std::unique_lock l(m_mutex); int currentIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp index 147164133..7978a0ba3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp @@ -7,6 +7,8 @@ BufferGpuVLK::BufferGpuVLK(const HGDeviceVLK &device, int size, VkBufferUsageFlags usageFlags, const char *obj_name) : m_device(device) { m_size = size; + VmaAllocationInfo allocationInfo; + VkBufferCreateInfo vbInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; vbInfo.size = m_size; vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | usageFlags; @@ -17,10 +19,14 @@ BufferGpuVLK::BufferGpuVLK(const HGDeviceVLK &device, int size, VkBufferUsageFla stagingAllocInfo.flags = 0; ERR_GUARD_VULKAN(vmaCreateBuffer(m_device->getVMAAllocator(), &vbInfo, &stagingAllocInfo, &m_hBuffer, - &m_hBufferAlloc, nullptr)); + &m_hBufferAlloc, &allocationInfo)); device->setObjectName((uint64_t) m_hBuffer, VK_OBJECT_TYPE_BUFFER, obj_name); +#ifdef DUMP_SELECTION_OF_MEMTYPE + std::cout << "GPU Buff "<< obj_name <<", memtype = " << allocationInfo.memoryType << std::endl; +#endif + } BufferGpuVLK::~BufferGpuVLK() { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp index 038381ef6..e90f65790 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp @@ -19,6 +19,10 @@ BufferStagingVLK::BufferStagingVLK(const HGDeviceVLK &device, int size) : m_devi &m_stagingBuffer, &m_stagingBufferAlloc, &m_stagingBufferAllocInfo)); + +#ifdef DUMP_SELECTION_OF_MEMTYPE + std::cout << "Staging CPU Buff, memtype = " << m_stagingBufferAllocInfo.memoryType << std::endl; +#endif } } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 50eb46ab0..31c7fb2cb 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -204,12 +204,69 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff if (submitRecords.get().empty()) return; - for (auto &submitRecord : submitRecords.get()) { + auto &submits = submitRecords.get(); + for (int i = 0; i < submits.size(); i++) { + auto &submit = submits[i]; + if (submit.needsBarrier && !submit.copyRegions.empty()) { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + submit.src, + submit.copyRegions[0].srcOffset, + submit.copyRegions[0].size + }; + + vkCmdPipelineBarrier( + m_gCmdBuffer.m_cmdBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + nullptr, + 1, + &buffer_barrier, + 0, + nullptr + ); + } vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, - submitRecord.src, - submitRecord.dst, - submitRecord.copyRegions.size(), - submitRecord.copyRegions.data()); + submit.src, + submit.dst, + submit.copyRegions.size(), + submit.copyRegions.data()); + + if (submit.needsBarrier && !submit.copyRegions.empty()) { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + submit.dst, + submit.copyRegions[0].dstOffset, + submit.copyRegions[0].size + }; + + vkCmdPipelineBarrier( + m_gCmdBuffer.m_cmdBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + nullptr, + 1, + &buffer_barrier, + 0, + nullptr + ); + } } } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index a8e419320..3ec7ff5e3 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -51,7 +51,7 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, ); } -void textureUploadStrategy(const std::vector> &textures, CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder) { +void textureUploadStrategy(const std::vector> &textures, CmdBufRecorder &uploadCmdBufRecorder) { ZoneScoped; if (textures.empty()) return; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h index 3fd22755f..897629aab 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.h @@ -26,7 +26,6 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, const TransitionParams &transitionParams); void textureUploadStrategy(const std::vector> &textures, - CmdBufRecorder &renderCmdBufRecorder, CmdBufRecorder &uploadCmdBufRecorder); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 54fce2320..bcee73304 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -235,7 +235,7 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te } VmaAllocationCreateInfo allocImageCreateInfo = {}; - allocImageCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocImageCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; // allocImageCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; //this bit forces to create per one texture per memory @@ -244,6 +244,9 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te if (!m_debugName.empty()) { m_device.setObjectName((uint64_t) texture.image, VK_OBJECT_TYPE_IMAGE, m_debugName.c_str()); } +#ifdef DUMP_SELECTION_OF_MEMTYPE + std::cout << "Texture "<< m_debugName <<", memtype = " << imageAllocationInfo.memoryType << std::endl; +#endif // Create image view // Textures are not directly accessed by the shaders and diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index ce09916ae..7151d13d3 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -122,6 +122,8 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrfogResults[i]; + auto &fogData = blockPSVS.fogData; + mathfu::vec4 heightPlane = mathfu::vec4( zUp.xyz(), -(mathfu::vec3::DotProduct(zUp.xyz(), (zUp * fogResult.FogHeight).xyz())) @@ -141,54 +143,54 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr(m_config->farPlane, 3000) * fogScaler; - blockPSVS.fogData[i].densityParams = mathfu::vec4( + fogData.densityParams = mathfu::vec4( fogStart, fogEnd, fogResult.FogDensity * densityMultFix, 0); - blockPSVS.fogData[i].classicFogParams = mathfu::vec4(0, 0, 0, 0); - blockPSVS.fogData[i].heightPlane = heightPlane; - blockPSVS.fogData[i].color_and_heightRate = mathfu::vec4(fogResult.FogColor, fogResult.FogHeightScaler + fogData.classicFogParams = mathfu::vec4(0, 0, 0, 0); + fogData.heightPlane = heightPlane; + fogData.color_and_heightRate = mathfu::vec4(fogResult.FogColor, fogResult.FogHeightScaler // * 0.01 ); - blockPSVS.fogData[i].heightDensity_and_endColor = mathfu::vec4( + fogData.heightDensity_and_endColor = mathfu::vec4( fogResult.FogHeightDensity * densityMultFix, fogResult.EndFogColor.x, fogResult.EndFogColor.y, fogResult.EndFogColor.z ); - blockPSVS.fogData[i].sunAngle_and_sunColor = mathfu::vec4( + fogData.sunAngle_and_sunColor = mathfu::vec4( fogResult.SunFogAngle, fogResult.SunFogColor.x, fogResult.SunFogColor.y, fogResult.SunFogColor.z ); - blockPSVS.fogData[i].heightColor_and_endFogDistance = mathfu::vec4( + fogData.heightColor_and_endFogDistance = mathfu::vec4( fogResult.FogHeightColor, (fogResult.EndFogColorDistance > 0) ? fogResult.EndFogColorDistance : 1000.0f ); - blockPSVS.fogData[i].sunPercentage = mathfu::vec4( + fogData.sunPercentage = mathfu::vec4( fogResult.SunFogAngle * fogResult.SunFogStrength, 0, 1.0, 1.0); - blockPSVS.fogData[i].sunDirection_and_fogZScalar = mathfu::vec4( + fogData.sunDirection_and_fogZScalar = mathfu::vec4( fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position fogResult.FogZScalar ); - blockPSVS.fogData[i].heightFogCoeff = fogResult.FogHeightCoefficients; - blockPSVS.fogData[i].mainFogCoeff = fogResult.MainFogCoefficients; - blockPSVS.fogData[i].heightDensityFogCoeff = fogResult.HeightDensityFogCoefficients; + fogData.heightFogCoeff = fogResult.FogHeightCoefficients; + fogData.mainFogCoeff = fogResult.MainFogCoefficients; + fogData.heightDensityFogCoeff = fogResult.HeightDensityFogCoefficients; bool mainFogOk = (fogResult.MainFogStartDist + 0.001 <= fogResult.MainFogEndDist); - blockPSVS.fogData[i].mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( + fogData.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( mainFogOk ? fogResult.MainFogEndDist : fogResult.MainFogStartDist + 0.001, fogResult.MainFogStartDist >= 0.0 ? fogResult.MainFogStartDist : 0.0f, fogResult.LegacyFogScalar, fogResult.FogBlendAlpha ); - blockPSVS.fogData[i].heightFogEndColor_fogStartOffset = mathfu::vec4( + fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( fogResult.HeightEndFogColor, fogResult.FogStartOffset ); From 98d852318300d94acf738d3c688778a7a708184d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 20 Sep 2023 08:02:25 +0300 Subject: [PATCH 116/212] - Liquid meshes write to Z-Buffer now - App continues to work correctly when minimized (swapchain changes) - First step for RenderView abstraction --- src/main.cpp | 3 +- .../src/engine/objects/ViewsObjects.cpp | 12 +- .../src/engine/objects/ViewsObjects.h | 8 +- .../engine/objects/liquid/LiquidInstance.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 4 +- .../src/engine/objects/wmo/wmoGroupObject.h | 2 +- wowViewerLib/src/gapi/interface/IDevice.h | 12 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 192 ++++++++---------- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 10 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 4 +- .../src/gapi/vulkan/GFrameBufferVLK.h | 2 +- .../CommandBufferRecorder.cpp | 53 ++--- .../CommandBufferRecorder.h | 3 +- .../TextureUploadHelper.cpp | 2 +- .../src/renderer/frame/SceneComposer.cpp | 14 +- .../src/renderer/frame/SceneComposer.h | 10 +- .../renderer/mapScene/MapSceneRenderer.cpp | 6 +- .../src/renderer/mapScene/MapSceneRenderer.h | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 119 +++++++---- .../vulkan/MapSceneRenderForwardVLK.h | 33 ++- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 75 ++++--- .../mapScene/vulkan/passes/FFXGlowPassVLK.h | 9 +- 23 files changed, 298 insertions(+), 280 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a1bbbe3f6..335237af2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -494,7 +494,8 @@ int main(){ frontendUI->composeUI(); auto sceneScenario = frontendUI->createFrameScenario(canvWidth, canvHeight, deltaTime); - sceneComposer.draw(sceneScenario); + sceneComposer.draw(sceneScenario, windowSizeChanged); + windowSizeChanged = false; double currentDeltaAfterDraw = (glfwGetTime() - lastFrame)*(1000.0f); lastFrame = currentFrame; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 4d2e9b168..0216efd3e 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -13,25 +13,25 @@ #include "../algorithms/mathHelper_culling.h" #include "../../gapi/interface/materials/IMaterial.h" -void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) { +void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) { if (renderADT) { auto inserter = std::back_inserter(opaqueMeshes); std::copy(this->m_adtOpaqueMeshes.begin(), this->m_adtOpaqueMeshes.end(), inserter); } if (renderAdtLiquid) { - auto inserter = std::back_inserter(transparentMeshes); - std::copy(this->m_adtLiquidTransparentMeshes.begin(), this->m_adtLiquidTransparentMeshes.end(), inserter); + auto inserter = std::back_inserter(liquidMeshes); + std::copy(this->liquidMeshes.begin(), this->liquidMeshes.end(), inserter); } - GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshes, transparentMeshes); + GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); } -void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) { +void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) { if (renderWMO) { for (auto &wmoGroup: wmoGroupArray.getToDraw()) { - wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); + wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, liquidMeshes, renderOrder); } } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index af78fa7b1..f5a3c877b 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -52,7 +52,9 @@ class GeneralView { std::vector portals; - virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes); + std::vector liquidMeshes = {}; + + virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes); void collectPortalMeshes(std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); @@ -72,10 +74,8 @@ class ExteriorView : public GeneralView { public: std::vector> drawnADTs = {}; std::vector m_adtOpaqueMeshes = {}; - std::vector m_adtLiquidTransparentMeshes = {}; - public: - void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes) override; + void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) override; }; class FrameViewsHolder { diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 8c6fdf3eb..0d969d240 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -71,7 +71,7 @@ void LiquidInstance::createMaterialAndMesh(const HMapSceneBufferCreate &sceneRen PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; - pipelineTemplate.depthWrite = false; + pipelineTemplate.depthWrite = true; pipelineTemplate.depthCulling = true; pipelineTemplate.backFaceCulling = false; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index aab068783..9e8ddc9b9 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -494,7 +494,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams exteriorView->addM2FromGroups(frustumData, cameraPos); for (auto &adtRes: exteriorView->drawnADTs) { adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_adtOpaqueMeshes, - exteriorView->m_adtLiquidTransparentMeshes, + exteriorView->liquidMeshes, exteriorView->renderOrder); } mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 9a8a6ca38..7a493301f 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -740,7 +740,7 @@ void WmoGroupObject::setModelFileId(int fileId) { m_modelFileId = fileId; } -void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes, int renderOrder) { if (!m_loaded) return; for (auto &i : this->m_meshArray) { opaqueMeshes.push_back(i); @@ -754,7 +754,7 @@ void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vecto } for (auto const &liquidInstance : m_liquidInstances) { - liquidInstance->collectMeshes(transparentMeshes); + liquidInstance->collectMeshes(liquidMeshes); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 2c528eb65..49ec04388 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -45,7 +45,7 @@ class WmoGroupObject { void setModelFileName(std::string modelName); void setModelFileId(int fileId); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes, int renderOrder); bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index fea2ad980..3e3675bb4 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -137,14 +137,6 @@ struct vkCallInitCallback { }; #endif -struct FramebufAvalabilityStruct { - int width; int height; - std::vector attachments; - ITextureFormat depthAttachment; - HFrameBuffer frameBuffer; - int frame; -}; - enum class GDeviceType { GOpenGL2, GOpenGL3, GVulkan, }; @@ -178,7 +170,7 @@ class IDevice { // virtual void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData)= 0; virtual void uploadTextureForMeshes(std::vector &meshes) = 0; - virtual void drawFrame(const std::vector> &renderFuncs) = 0; + virtual void drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) = 0; // virtual void drawStageAndDeps(HDrawStage drawStage) = 0; virtual bool getIsAnisFiltrationSupported(); @@ -192,8 +184,6 @@ class IDevice { public: virtual HGPUFence createFence() = 0; virtual HGVertexBufferBindings createVertexBufferBindings() = 0; - //Creates or receives framebuffer and tells it would be occupied for frameNumber frames - virtual HFrameBuffer createFrameBuffer(int width, int height, std::vector attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) = 0; virtual HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) = 0; virtual HGSamplableTexture createTexture(bool xWrapTex, bool yWrapTex) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index ea6feaf11..424388ad7 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -466,14 +466,18 @@ void GDeviceVLK::createSwapChainAndFramebuffer() { createSwapChain(swapChainSupport, surfaceFormat, extent); - uint32_t imageCount; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + uint32_t imageCount = 0; + if (swapChain != VK_NULL_HANDLE) { + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + } //Create swapchainImages and framebuffer std::vector swapChainImages = {}; swapChainImages.resize(imageCount); - ERR_GUARD_VULKAN(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data())); + if (swapChain != VK_NULL_HANDLE) { + ERR_GUARD_VULKAN(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data())); + } swapChainExtent = extent; @@ -481,6 +485,7 @@ void GDeviceVLK::createSwapChainAndFramebuffer() { std::vector swapChainImageViews; createSwapChainImageViews(swapChainImages, swapChainImageViews, surfaceFormat.format); + //Create swapchain renderPass createSwapChainRenderPass(surfaceFormat.format); @@ -488,7 +493,8 @@ void GDeviceVLK::createSwapChainAndFramebuffer() { std::vector swapChainTextures; swapChainTextures.resize(swapChainImages.size()); for (int i = 0; i < swapChainImages.size(); i++) { - swapChainTextures[i] = std::make_shared(*this, swapChainImages[i], swapChainImageViews[i], false); + swapChainTextures[i] = std::make_shared(*this, swapChainImages[i], swapChainImageViews[i], + false); } createFramebuffers(swapChainTextures, extent); @@ -518,40 +524,54 @@ void GDeviceVLK::createSwapChain(SwapChainSupportDetails &swapChainSupport, VkSu // imageCount = swapChainSupport.capabilities.maxImageCount; // } - VkSwapchainCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.pNext = nullptr; - createInfo.surface = vkSurface; - createInfo.flags = 0; + auto oldSwapChain = swapChain; - createInfo.minImageCount = imageCount; - createInfo.imageFormat = surfaceFormat.format; - createInfo.imageColorSpace = surfaceFormat.colorSpace; - createInfo.imageExtent = extent; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (extent.width > 0 && extent.height > 0) { + VkSwapchainCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.pNext = nullptr; + createInfo.surface = vkSurface; + createInfo.flags = 0; + + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()}; + + // if (indices.graphicsFamily != indices.presentFamily) { + // createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + // createInfo.queueFamilyIndexCount = 2; + // createInfo.pQueueFamilyIndices = queueFamilyIndices; + // } else { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + // } - uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()}; + createInfo.preTransform = swapChainSupport.capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; -// if (indices.graphicsFamily != indices.presentFamily) { -// createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; -// createInfo.queueFamilyIndexCount = 2; -// createInfo.pQueueFamilyIndices = queueFamilyIndices; -// } else { - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; -// } - createInfo.preTransform = swapChainSupport.capabilities.currentTransform; - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - createInfo.presentMode = presentMode; - createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = oldSwapChain; - createInfo.oldSwapchain = swapChain; + auto error = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain); + if (error != VK_SUCCESS) { + std::cout << "error = " << error << std::endl << std::flush; + throw std::runtime_error("failed to create swap chain!"); + } + } else { + swapChain = VK_NULL_HANDLE; + } - auto error = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain); - if ( error != VK_SUCCESS) { - std::cout << "error = " << error << std::endl << std::flush; - throw std::runtime_error("failed to create swap chain!"); + if (oldSwapChain != VK_NULL_HANDLE) { + auto vkDevice = this->getVkDevice(); + addDeallocationRecord([oldSwapChain, vkDevice]() { + vkDestroySwapchainKHR(vkDevice, oldSwapChain, nullptr); + }); } } @@ -885,7 +905,6 @@ void GDeviceVLK::createSyncObjects() { renderFinishedSemaphores[i] = std::make_shared(this->shared_from_this()); uploadSemaphores[i] = std::make_shared(this->shared_from_this()); - uploadSequenceSemaphores[i] = std::make_shared(this->shared_from_this()); frameBufSemaphores[i] = std::make_shared(this->shared_from_this()); } @@ -916,7 +935,7 @@ float GDeviceVLK::getAnisLevel() { return deviceProperties.limits.maxSamplerAnisotropy; } -void GDeviceVLK::drawFrame(const std::vector> &renderFuncs) { +void GDeviceVLK::drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) { ZoneScoped; this->waitInDrawStageAndDeps.beginMeasurement(); @@ -926,6 +945,10 @@ void GDeviceVLK::drawFrame(const std::vector> & auto &swapChainCmdBuf = swapChainCommandBuffers[currentDrawFrame]; auto &frameBufCmdBuf = fbCommandBuffers[currentDrawFrame]; + if (windowSizeChanged) { + createSwapChainAndFramebuffer(); + } + uint32_t imageIndex = -1; { { @@ -961,24 +984,12 @@ void GDeviceVLK::drawFrame(const std::vector> & } } { - std::vector uploadConseqWaitSemaphores = {}; - std::vector uploadWaitStages = {}; - if (m_frameNumber > IDevice::MAX_FRAMES_IN_FLIGHT) { - uploadConseqWaitSemaphores = { - uploadSequenceSemaphores[(currentDrawFrame + IDevice::MAX_FRAMES_IN_FLIGHT - 1) % - MAX_FRAMES_IN_FLIGHT]->getNativeSemaphore() - }; - uploadWaitStages = {VK_PIPELINE_STAGE_TRANSFER_BIT}; - } - - submitQueue( uploadQueue, - uploadConseqWaitSemaphores, - uploadWaitStages, + {}, + {}, {uploadCmdBuf->getNativeCmdBuffer()}, - {uploadSemaphores[currentDrawFrame]->getNativeSemaphore(), - uploadSequenceSemaphores[currentDrawFrame]->getNativeSemaphore()}, + {uploadSemaphores[currentDrawFrame]->getNativeSemaphore()}, uploadFences[currentDrawFrame]->getNativeFence() ); } @@ -997,10 +1008,10 @@ void GDeviceVLK::drawFrame(const std::vector> & } auto swapChainCmd = swapChainCmdBuf->beginRecord(nullptr); + auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); + if (swapChain != VK_NULL_HANDLE) { - auto frameBufCmd = frameBufCmdBuf->beginRecord(nullptr); - //Begin render pass for Swap chain this->getNextSwapImageIndex(imageIndex); auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); @@ -1022,24 +1033,29 @@ void GDeviceVLK::drawFrame(const std::vector> & frameBufFences[currentDrawFrame]->getNativeFence() ); + std::vector waitSemaphores = { frameBufSemaphores[currentDrawFrame]->getNativeSemaphore() }; + if (swapChain != VK_NULL_HANDLE) waitSemaphores.push_back(imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore()); + + std::vector signalSemaphores = {}; + if (swapChain != VK_NULL_HANDLE) signalSemaphores = {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}; + submitQueue( graphicsQueue, - { - frameBufSemaphores[currentDrawFrame]->getNativeSemaphore(), - imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore() - }, + waitSemaphores, {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, {swapChainCmdBuf->getNativeCmdBuffer()}, - {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + signalSemaphores, inFlightFences[currentDrawFrame]->getNativeFence() ); - presentQueue( - {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, - {swapChain}, - {imageIndex} - ); + if (swapChain != VK_NULL_HANDLE) { + presentQueue( + {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, + {swapChain}, + {imageIndex} + ); + } executeDeallocators(); this->waitInDrawStageAndDeps.endMeasurement(); @@ -1064,6 +1080,11 @@ RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBu void GDeviceVLK::getNextSwapImageIndex(uint32_t &imageIndex) { int currentDrawFrame = getProcessingFrameNumber(); + if (swapChain == VK_NULL_HANDLE) { + imageIndex = 0xFFFFFFFF; + return; + } + VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits::max(), imageAvailableSemaphores[currentDrawFrame]->getNativeSemaphore(), VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { @@ -1305,8 +1326,7 @@ void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, auto result = vkQueuePresentKHR(graphicsQueue, &presentInfo); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { - framebufferResized = false; + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { createSwapChainAndFramebuffer(); return; } else if (result != VK_SUCCESS) { @@ -1459,52 +1479,6 @@ GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescript void GDeviceVLK::initUploadThread() { } - - -HFrameBuffer GDeviceVLK::createFrameBuffer(int width, int height, std::vector attachments, - ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) { - - if (frameNumber > -1) { - for (auto &framebufAvalability : m_createdFrameBuffers) { - if ((framebufAvalability.frame < m_frameNumber) && - framebufAvalability.attachments.size() == attachments.size() && - framebufAvalability.depthAttachment == depthAttachment && - framebufAvalability.width == width && - framebufAvalability.height == height - ) { - //Check frame definition - bool notEqual = false; - for (int i = 0; i < attachments.size(); i++) { - if (attachments[i] != framebufAvalability.attachments[i]) { - notEqual = true; - break; - } - } - if (!notEqual) { - framebufAvalability.frame = m_frameNumber + frameNumber+3; - return framebufAvalability.frameBuffer; - } - } - } - } - - HFrameBuffer h_frameBuffer = std::make_shared(*this, attachments, depthAttachment, multiSampleCnt, width, height); - - if (frameNumber > -1) { - FramebufAvalabilityStruct avalabilityStruct; - avalabilityStruct.frameBuffer = h_frameBuffer; - avalabilityStruct.height = height; - avalabilityStruct.width = width; - avalabilityStruct.frame = m_frameNumber + frameNumber+3; - avalabilityStruct.attachments = attachments; - avalabilityStruct.depthAttachment = depthAttachment; - - m_createdFrameBuffers.push_back(avalabilityStruct); - } - - return h_frameBuffer; -} - void GDeviceVLK::singleExecuteAndWait(std::function callback) { //Allocate temporary command buffer VkCommandBufferAllocateInfo allocInfo = {}; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 48cbbeb18..3e7ff54f3 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -84,7 +84,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> &renderFuncs) override; + void drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) override; void updateBuffers(/*std::vector*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; @@ -118,7 +118,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this attachments, ITextureFormat depthAttachment, int multiSampleCnt, int frameNumber) override ; + HPipelineVLK createPipeline(const HGVertexBufferBindings &m_bindings, const HGShaderPermutation &shader, @@ -169,9 +169,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this, MAX_FRAMES_IN_FLIGHT> renderFinishedSemaphores; std::array, MAX_FRAMES_IN_FLIGHT> uploadSemaphores; - std::array, MAX_FRAMES_IN_FLIGHT> uploadSequenceSemaphores; std::array, MAX_FRAMES_IN_FLIGHT> frameBufSemaphores; std::vector> m_descriptorPools; @@ -377,8 +373,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this listOfDeallocators; - std::vector m_createdFrameBuffers; - struct RenderPassAvalabilityStruct { std::vector attachments; ITextureFormat depthAttachment; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index b69691ed3..2895e3e3e 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -108,6 +108,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, + bool invertZ, int width, int height) : mdevice(dynamic_cast(device)), m_height(height), m_width(width), m_multiSampleCnt(multiSampleCnt){ @@ -190,7 +191,6 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, attachments.push_back(h_depthTexture->texture.view); } - bool invertZ = true; m_renderPass = mdevice.getRenderPass(textureAttachments, depthAttachment, sampleCountToVkSampleCountFlagBits(multiSampleCnt), invertZ, false); VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; @@ -326,7 +326,7 @@ void GFrameBufferVLK::readRGBAPixels(int x, int y, int width, int height, void * 1, &imageMemoryBarrier); } - // If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB) + // If source and destination support blit we'll blit as this also does automatic formt conversion (e.g. from BGR to RGB)a if (supportsBlit) { // Define the region to blit (we will blit the whole swapchain image) diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index 6631ae34e..1c35408df 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -12,7 +12,7 @@ class GFrameBufferVLK : public IFrameBuffer { public: - GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, int width, int height); + GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, bool invertZ, int width, int height); GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, int width, int height, const std::shared_ptr &renderPass); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 31c7fb2cb..db7b3ab20 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -176,8 +176,8 @@ void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, ui firstInstance); } -void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - const std::vector &imageBarrierData) { +void CmdBufRecorder::recordPipelineImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + const std::vector &imageBarrierData) { vkCmdPipelineBarrier( m_gCmdBuffer.m_cmdBuffer, srcStageMask, @@ -188,6 +188,18 @@ void CmdBufRecorder::recordPipelineBarrier(VkPipelineStageFlags srcStageMask, Vk imageBarrierData.size(), imageBarrierData.data()); } +void CmdBufRecorder::recordPipelineBufferBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + const std::vector &bufferBarrierData) { + vkCmdPipelineBarrier( + m_gCmdBuffer.m_cmdBuffer, + srcStageMask, + dstStageMask, + 0, + 0, nullptr, + bufferBarrierData.size(), bufferBarrierData.data(), + 0, nullptr); +} + void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions) { vkCmdCopyBufferToImage( m_gCmdBuffer.m_cmdBuffer, @@ -208,7 +220,7 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff for (int i = 0; i < submits.size(); i++) { auto &submit = submits[i]; if (submit.needsBarrier && !submit.copyRegions.empty()) { - VkBufferMemoryBarrier buffer_barrier = + this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, { { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, nullptr, @@ -219,21 +231,10 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff submit.src, submit.copyRegions[0].srcOffset, submit.copyRegions[0].size - }; - - vkCmdPipelineBarrier( - m_gCmdBuffer.m_cmdBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, - nullptr, - 1, - &buffer_barrier, - 0, - nullptr - ); + } + }); } + vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, submit.src, submit.dst, @@ -241,7 +242,7 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff submit.copyRegions.data()); if (submit.needsBarrier && !submit.copyRegions.empty()) { - VkBufferMemoryBarrier buffer_barrier = + this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, { { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, nullptr, @@ -252,20 +253,8 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff submit.dst, submit.copyRegions[0].dstOffset, submit.copyRegions[0].size - }; - - vkCmdPipelineBarrier( - m_gCmdBuffer.m_cmdBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, - nullptr, - 1, - &buffer_barrier, - 0, - nullptr - ); + } + }); } } } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 0453d854d..1efa3b182 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -59,7 +59,8 @@ class CmdBufRecorder { const std::array &areaSize); void setDefaultScissors(); - void recordPipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); + void recordPipelineImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); + void recordPipelineBufferBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData); void copyBufferToImage(VkBuffer buffer, VkImage image, const std::vector ®ions); void submitBufferUploads(const std::shared_ptr &bufferVLK); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp index 3ec7ff5e3..1896d290c 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/TextureUploadHelper.cpp @@ -44,7 +44,7 @@ void transitionLayoutAndOwnageTextures(CmdBufRecorder &uploadCmdBufRecorder, // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - uploadCmdBufRecorder.recordPipelineBarrier( + uploadCmdBufRecorder.recordPipelineImageBarrier( transitionParams.srcStageMask, transitionParams.dstStageMask, imageMemoryBarriers diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 9b177d255..ea9384d83 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -86,7 +86,7 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon // drawInput.pushInput(nullptr); } -void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { +void SceneComposer::consumeCulling(const HFrameScenario &frameScenario) { ZoneScoped ; if (frameScenario == nullptr) @@ -98,7 +98,7 @@ void SceneComposer::consumeCulling(HFrameScenario &frameScenario) { } -void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions) { +void SceneComposer::consumeUpdate(const HFrameScenario &frameScenario, std::vector> &renderFunctions) { ZoneScoped ; if (frameScenario == nullptr) @@ -109,9 +109,9 @@ void SceneComposer::consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFuncs) { +void SceneComposer::consumeDraw(const std::vector> &renderFuncs, bool windowSizeChanged) { ZoneScoped ; - m_apiContainer->hDevice->drawFrame(renderFuncs); + m_apiContainer->hDevice->drawFrame(renderFuncs, windowSizeChanged); } @@ -121,7 +121,7 @@ void SceneComposer::consumeDraw(const std::vector> renderFuncs = {}; m_apiContainer->requestProcessor->processRequests(10); consumeUpdate(frameScenario,renderFuncs); - consumeDraw(renderFuncs); + consumeDraw(renderFuncs, windowSizeChanged); } else { cullingInput.pushInput(frameScenario); { @@ -141,7 +141,7 @@ void SceneComposer::draw(HFrameScenario frameScenario) { // consumeUpdate(frameScenario, *renderFuncs); // } if (renderFuncs != nullptr) { - consumeDraw(*renderFuncs); + consumeDraw(*renderFuncs, windowSizeChanged); } } m_firstFrame = false; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index 2d06191da..d8927f0aa 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -27,9 +27,9 @@ class SceneComposer { bool m_isTerminating = false; bool m_firstFrame = true; - void consumeCulling(HFrameScenario &frameScenario); - void consumeUpdate(HFrameScenario &frameScenario, std::vector> &renderFunctions); - void consumeDraw(const std::vector> &renderFuncs); + void consumeCulling(const HFrameScenario &frameScenario); + void consumeUpdate(const HFrameScenario &frameScenario, std::vector> &renderFunctions); + void consumeDraw(const std::vector> &renderFuncs, bool windowSizeChanged); //Flip-flop delta promises int frameMod = 0; @@ -54,9 +54,7 @@ class SceneComposer { loadingResourcesThread.join(); } - void draw(HFrameScenario frameScenario); - - void addInputParams(HFrameScenario rendererAndInput){}; + void draw(const HFrameScenario &frameScenario, bool windowSizeChanged); }; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 7151d13d3..3575650a8 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -21,6 +21,7 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hliquidMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes) { ZoneScoped; @@ -30,6 +31,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende auto &skyOpaqueMeshes = *hSkyOpaqueMeshes; auto &skyTransparentMeshes = *hSkyTransparentMeshes; + auto &liquidMeshes = *hliquidMeshes; opaqueMeshes.reserve(30000); transparentMeshes.reserve(30000); @@ -49,13 +51,13 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende bool renderWMO = m_config->renderWMO; for (auto &view : cullStage->viewsHolder.getInteriorViews()) { - view->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); + view->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); } { auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { - exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes); + exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); } } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 7b21aba60..7bf1b6042 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -98,6 +98,7 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public void collectMeshes(const std::shared_ptr &renderPlan, const std::shared_ptr> &hopaqueMeshes, const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hliquidMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index e9d1662f5..032981ffc 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -96,9 +96,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), true, false); - glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); - - createFrameBuffers(); + defaultView = std::make_unique(m_device, uboBuffer, m_drawQuadVao); sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) @@ -585,30 +583,16 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - if (frameInputParams->viewPortDimensions.maxs[0] != m_width || - frameInputParams->viewPortDimensions.maxs[1] != m_height) { - m_width = frameInputParams->viewPortDimensions.maxs[0]; - m_height = frameInputParams->viewPortDimensions.maxs[1]; - - createFrameBuffers(); - - { - std::vector> inputColorTextures; - for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); - } - - glowPass->updateDimensions(m_width, m_height, - inputColorTextures, - m_device->getSwapChainRenderPass()); - } - - } - + defaultView->update( + frameInputParams->viewPortDimensions.maxs[0], + frameInputParams->viewPortDimensions.maxs[1], + framePlan->frameDependentData->currentGlow + ); //Create meshes auto opaqueMeshes = std::make_shared>(); auto transparentMeshes = std::make_shared>(); + auto liquidMeshes = std::make_shared>(); auto skyOpaqueMeshes = std::make_shared>(); auto skyTransparentMeshes = std::make_shared>(); @@ -623,13 +607,12 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { collectMeshes(framePlan, opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes); + liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); // } // ); mapScene->update(framePlan); mapScene->updateBuffers(l_this, framePlan); - glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); updateSceneWideChunk(sceneWideChunk, framePlan->renderingMatrices, @@ -700,7 +683,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); } - }, [opaqueMeshes, transparentMeshes, + }, [opaqueMeshes, transparentMeshes, liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes, renderSky, skyMesh, @@ -715,14 +698,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // ---------------------- l_this->sceneWideChunk->setCurrentVersion(0); { - auto passHelper = frameBufCmd.beginRenderPass(false, - l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], - frameInputParams->viewPortDimensions.mins, - frameInputParams->viewPortDimensions.maxs, - vec4ToArr3(frameInputParams->frameParameters->clearColor), - true - ); + auto passHelper = l_this->defaultView->beginPass(frameBufCmd, l_this->m_renderPass, + false, + frameInputParams->frameParameters->clearColor); { ZoneScopedN("submit opaque"); @@ -731,13 +709,17 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); } } - if (true) { + { + //Sky opaque if (renderSky && skyMesh) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); for (auto const &mesh: *skyOpaqueMeshes) { MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } + } + { + //Sky transparent for (int i = 0; i < skyTransparentMeshes->size(); i++) { auto const &mesh = skyTransparentMeshes->at(i); @@ -755,6 +737,12 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha if (renderSky && skyMesh0x4) MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); } + { + //Render liquids + for (auto const &mesh: *liquidMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + } + } { VkZone(frameBufCmd, "render transparent") ZoneScopedN("submit transparent"); @@ -778,9 +766,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { // VkZone(frameBufCmd, "glowPassFrameBuf"); // VkZone(swapChainCmd, "glowPassSwapBuf"); - l_this->glowPass->doPass(frameBufCmd, swapChainCmd, - l_this->m_device->getSwapChainRenderPass(), - frameInputParams->viewPortDimensions); + + l_this->defaultView->doPostGlow(frameBufCmd); + l_this->defaultView->doPostFinal(swapChainCmd); } }); } @@ -811,7 +799,18 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemp auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } -void MapSceneRenderForwardVLK::createFrameBuffers() { + +/* + * RenderView + */ + +MapSceneRenderForwardVLK::RenderView::RenderView(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device) { + glowPass = std::make_unique(m_device, uboBuffer, quadVAO); + + createFrameBuffers(); +} + +void MapSceneRenderForwardVLK::RenderView::createFrameBuffers() { { auto const dataFormat = {ITextureFormat::itRGBA}; @@ -821,9 +820,51 @@ void MapSceneRenderForwardVLK::createFrameBuffers() { dataFormat, ITextureFormat::itDepth32, m_device->getMaxSamplesCnt(), + true, m_width, m_height ); } } +} + +void MapSceneRenderForwardVLK::RenderView::update(int width, int height, float glow) { + if (width != m_width || height != m_height) { + m_width = width; + m_height = height; + + this->createFrameBuffers(); + + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + m_device->getSwapChainRenderPass()); + } + } + glowPass->assignFFXGlowUBOConsts(glow); +} + +RenderPassHelper MapSceneRenderForwardVLK::RenderView::beginPass(CmdBufRecorder &frameBufCmd, + const std::shared_ptr &renderPass, + bool willExecuteSecondaryBuffs, + mathfu::vec4 &clearColor) { + return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, + renderPass, + m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + {0,0}, + {m_width, m_height}, + vec4ToArr3(clearColor), + true); +} + +void MapSceneRenderForwardVLK::RenderView::doPostGlow(CmdBufRecorder &frameBufCmd) { + glowPass->doPass(frameBufCmd); +} +void MapSceneRenderForwardVLK::RenderView::doPostFinal(CmdBufRecorder &bufCmd) { + glowPass->doFinalPass(bufCmd); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 00884f7d1..54cf69eb7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -99,11 +99,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; - int m_width = 640; - int m_height = 480; - - std::unique_ptr glowPass; - HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboM2RibbonBuffer; @@ -124,8 +119,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; - std::vector allBuffers; - HGVertexBufferBindings m_drawQuadVao = nullptr; std::shared_ptr> sceneWideChunk; @@ -133,7 +126,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr m_renderPass; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; std::shared_ptr m_lastCreatedPlan = nullptr; @@ -148,7 +140,30 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr m_stagingRingBuffer; - void createFrameBuffers(); +private: + class RenderView { + public: + RenderView(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); + void update(int width, int height, float glow); + + RenderPassHelper beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, + bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + + void doPostGlow(CmdBufRecorder &frameBufCmd); + void doPostFinal(CmdBufRecorder &bufCmd); + private: + uint32_t m_width = 640; + uint32_t m_height = 480; + + HGDeviceVLK m_device; + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + std::unique_ptr glowPass; + + void createFrameBuffers(); + }; + + std::unique_ptr defaultView; }; class IM2ModelDataVLK : public IM2ModelData { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index b801454e7..ba7ffebad 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -24,14 +24,45 @@ FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &ubo true, false); } + { + //Set constant values + auto &ffxGlowVs = m_ffxGlowVs->getObject(); + ffxGlowVs = {1, 1, 0, 0}; + m_ffxGlowVs->save(); + + static const std::array, 6> texOffsets = {{ + //X & Y + {{-1, 0, 0, -1}}, + {{2, 2, -1, -1}}, + //X & Y + {{-6, -1, 1, 6}}, + {{0, 0, 0, 0}}, + //X & Y + {{0, 0, 0, 0}}, + {{10, 2, -2, -10}}, + }}; + + for (int i = 0; i < GAUSS_PASS_COUNT; i++) { + auto &ffxGlowPs1 = m_ffxGaussPSs[i]->getObject(); + std::copy(std::begin(texOffsets[i * 2]), std::end(texOffsets[i * 2]), std::begin(ffxGlowPs1.texOffsetX)); + std::copy(std::begin(texOffsets[i * 2 + 1]), std::end(texOffsets[i * 2 + 1]), + std::begin(ffxGlowPs1.texOffsetY)); + m_ffxGaussPSs[i]->save(); + } + } } void FFXGlowPassVLK::updateDimensions(int width, int height, const std::vector &inputColorTextures, const std::shared_ptr &finalRenderPass) { + if (m_width == width && m_height == height) return; + + m_width = width; + m_height = height; + createFrameBuffers(width, height); assert(inputColorTextures.size() == IDevice::MAX_FRAMES_IN_FLIGHT); @@ -96,9 +127,7 @@ void FFXGlowPassVLK::drawMaterial (CmdBufRecorder& cmdBuf, const std::shared_ptr cmdBuf.drawIndexed(6, 1, 0, 0); } -void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, - const std::shared_ptr &finalRenderPass, - ViewPortDimensions &viewPortDimensions) { +void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd) { ZoneScoped; auto currentFrame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; { @@ -108,8 +137,8 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapCha false, m_renderPass, getTargetFrameBuffer(i, currentFrame), - viewPortDimensions.mins, - {viewPortDimensions.maxs[0] >> 2, viewPortDimensions.maxs[1] >> 2}, + {0,0}, + {m_width >> 2, m_height >> 2}, {0, 0, 0},//todo true ); @@ -118,42 +147,20 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapCha drawMaterial(frameBufCmd, ffxGaussMat[currentFrame][i]); } } +} +void FFXGlowPassVLK::doFinalPass(CmdBufRecorder &finalBufCmd) { + auto currentFrame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; { - swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); - swapChainCmd.setDefaultScissors(); - drawMaterial(swapChainCmd, ffxGlowMat[currentFrame]); + finalBufCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); + finalBufCmd.setDefaultScissors(); + drawMaterial(finalBufCmd, ffxGlowMat[currentFrame]); } } void FFXGlowPassVLK::assignFFXGlowUBOConsts(float glow) { ZoneScoped; - auto &ffxGlowVs = m_ffxGlowVs->getObject(); - ffxGlowVs = {1,1,0,0}; - m_ffxGlowVs->save(); - - static const std::array, 6> texOffsets = {{ - //X & Y - {{-1, 0, 0, -1}}, - {{2, 2, -1, -1}}, - - //X & Y - {{-6, -1, 1, 6}}, - {{0, 0, 0, 0}}, - - //X & Y - {{0, 0, 0, 0}}, - {{10, 2, -2, -10}}, - }}; - - for (int i = 0; i < GAUSS_PASS_COUNT; i++) { - auto &ffxGlowPs1 = m_ffxGaussPSs[i]->getObject(); - std::copy(std::begin(texOffsets[i*2]), std::end(texOffsets[i*2]), std::begin(ffxGlowPs1.texOffsetX)); - std::copy(std::begin(texOffsets[i*2+1]), std::end(texOffsets[i*2+1]), std::begin(ffxGlowPs1.texOffsetY)); - m_ffxGaussPSs[i]->save(); - } - auto &ffxGlowPS = m_ffxGlowPS->getObject(); ffxGlowPS = {1,1,0,glow}; m_ffxGlowPS->save(); @@ -171,6 +178,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { dataFormat, ITextureFormat::itNone, 1, + false, targetWidth, targetHeight ); } @@ -180,6 +188,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { dataFormat, ITextureFormat::itNone, 1, + false, targetWidth, targetHeight ); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h index c56c236df..9e72a2347 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h @@ -20,14 +20,17 @@ class FFXGlowPassVLK { const std::vector &inputColorTextures, const std::shared_ptr &finalRenderPass); - void doPass(CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd, - const std::shared_ptr &finalRenderPass, - ViewPortDimensions &viewPortDimensions); + void doPass(CmdBufRecorder &frameBufCmd); + + void doFinalPass(CmdBufRecorder &finalBufCmds); private: static constexpr int GAUSS_PASS_COUNT = 3; HGDeviceVLK m_device; + unsigned int m_width = 0; + unsigned int m_height = 0; + std::shared_ptr m_renderPass; HGVertexBufferBindings m_drawQuadVao = nullptr; From 049c0686c8ddf45d008f692b73c95248212c7261 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 25 Sep 2023 09:34:23 +0300 Subject: [PATCH 117/212] - screenshots part 1 --- src/main.cpp | 4 + src/ui/FrontendUI.cpp | 118 +- src/ui/FrontendUI.h | 4 + src/ui/renderer/uiScene/ImGUIPlan.h | 4 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- wowViewerLib/CMakeLists.txt | 17 +- .../src/engine/objects/ViewsObjects.cpp | 24 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 + .../src/engine/objects/scenes/map.cpp | 125 +- .../src/engine/shader/ShaderDefinitions.h | 1226 ++++++++--------- .../src/gapi/interface/meshes/IM2Mesh.h | 2 +- .../src/gapi/interface/meshes/ISortableMesh.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 4 +- wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp | 7 +- .../src/gapi/vulkan/buffers/CBufferChunkVLK.h | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 17 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 3 +- .../vulkan/buffers/GStagingRingBuffer.cpp | 39 +- .../gapi/vulkan/buffers/GStagingRingBuffer.h | 2 +- .../vulkan/commandBuffer/CommandBuffer.cpp | 46 +- .../CommandBufferRecorder.cpp | 36 +- .../CommandBufferRecorder.h | 10 +- .../CommandBufferRecorder_inline.h | 51 + .../vulkan/descriptorSets/GDescriptorSet.cpp | 16 +- .../vulkan/descriptorSets/GDescriptorSet.h | 22 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 7 - .../src/gapi/vulkan/meshes/GM2MeshVLK.h | 5 - .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 5 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 8 +- .../gapi/vulkan/meshes/GSortableMeshVLK.cpp | 4 - .../src/gapi/vulkan/meshes/GSortableMeshVLK.h | 10 - .../vulkan/shaders/GShaderPermutationVLK.cpp | 3 + wowViewerLib/src/include/config.h | 2 +- .../src/renderer/frame/FrameInputParams.h | 4 - .../src/renderer/frame/FrameProfile.h | 1 + .../src/renderer/frame/SceneComposer.cpp | 7 + .../src/renderer/mapScene/MapSceneParams.h | 15 +- .../src/renderer/mapScene/MapSceneRenderer.h | 2 + .../vulkan/MapSceneRenderForwardVLK.cpp | 55 +- .../vulkan/MapSceneRenderForwardVLK.h | 15 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 1 + 41 files changed, 1027 insertions(+), 904 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h diff --git a/src/main.cpp b/src/main.cpp index 335237af2..c0fecaf59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -453,6 +453,8 @@ int main(){ uiScale = 1.0; frontendUI->setUIScale(uiScale); +// auto native_me = std::this_thread::get_id().native_handle(); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); //This has to be called after setting all callbacks specific to this app. //ImGUI takes care of previous callbacks and calls them before applying it's own logic over data @@ -466,6 +468,8 @@ int main(){ glfwGetFramebufferSize(window, &canvWidth, &canvHeight); } glfwSwapInterval(0); + tbb::global_control global_limit(oneapi::tbb::global_control::max_allowed_parallelism, + 2*apiContainer->getConfig()->hardwareThreadCount()); //try { while (!glfwWindowShouldClose(window)) { diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index e67cecf6f..01a167e88 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1635,11 +1635,15 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { 0.0f, 0.0f, 1, 0.0f); } +struct RenderTargetParameters { + std::shared_ptr camera; + ViewPortDimensions dimensions; + std::shared_ptr target; +}; + HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, - int width, int height, float fov, - bool produceDoubleCamera, - bool swapDebugCamera, + const std::vector &renderTargetParams, const std::shared_ptr ¤tScene) { auto result = std::make_shared(); @@ -1651,33 +1655,29 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, float nearPlane = 1.0; float fovR = toRadian(fov); + auto width = renderTargetParams[0].dimensions.maxs[0]; + auto height = renderTargetParams[0].dimensions.maxs[1]; float canvasAspect = (float)width / (float)height; result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); - result->cameraMatricesForRendering = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); - result->cameraMatricesForDebugCamera = nullptr; - if (produceDoubleCamera && apiContainer.debugCamera != nullptr) - result->cameraMatricesForDebugCamera = apiContainer.debugCamera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneRendering); - - //Frustum matrix with reversed Z bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); - if (isInfZSupported) - { + auto assignInfiniteZ = [&](auto renderTarget) { float f = 1.0f / tan(fovR / 2.0f); - result->cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); - if (result->cameraMatricesForDebugCamera != nullptr) { - result->cameraMatricesForDebugCamera->perspectiveMat = result->cameraMatricesForRendering->perspectiveMat; - } + renderTarget.cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); + }; + + for (auto &targetParam : renderTargetParams) { + auto &renderTarget = result->renderTargets.emplace_back(); + renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling);; + renderTarget.viewPortDimensions = targetParam.dimensions; + renderTarget.target = targetParam.target; + if (isInfZSupported) assignInfiniteZ(renderTarget); } result->clearColor = apiContainer.getConfig()->clearColor; - if (result->cameraMatricesForDebugCamera && swapDebugCamera) { - std::swap(result->cameraMatricesForDebugCamera, result->cameraMatricesForRendering); - } - return result; } @@ -1701,50 +1701,74 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do if (m_sceneRenderer != nullptr) { auto wowSceneFrameInput = std::make_shared>(); wowSceneFrameInput->delta = deltaTime * (1000.0f); - wowSceneFrameInput->viewPortDimensions = dimension; + + std::shared_ptr target = nullptr; + std::shared_ptr debugTarget = nullptr; + if (m_api->debugCamera && m_api->getConfig()->doubleCameraDebug) { + if (!m_debugRenderView) m_debugRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight); + debugTarget = m_debugRenderView; + + if (m_api->getConfig()->swapMainAndDebug) { + std::swap(target, debugTarget); + } + } + + std::vector renderTargetParams = { + { + .camera = m_api->camera, + .dimensions = dimension, + .target = target + } + }; + if (m_api->getConfig()->doubleCameraDebug) { + auto &debugParams = renderTargetParams.emplace_back(); + debugParams.camera = m_api->debugCamera; + debugParams.dimensions = dimension; + debugParams.target = debugTarget; + } + wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, - canvWidth, canvHeight, fov, - m_api->getConfig()->doubleCameraDebug, - m_api->getConfig()->swapMainAndDebug, + renderTargetParams, m_currentScene); + scenario->cullFunctions.push_back( + m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput, processingFrame, updateFrameNumberLambda)); + + //---------------------- + // Screenshot part + //---------------------- if (needToMakeScreenshot) { - wowSceneFrameInput->screenShotParameters = createMapSceneParams(*m_api, - screenShotWidth, screenShotHeight, - fov, - false, - false, - m_currentScene); + auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight); + auto wowSceneScreenshotFrameInput = std::make_shared>(); + wowSceneScreenshotFrameInput->delta = 0; + + wowSceneScreenshotFrameInput->frameParameters = createMapSceneParams( + *m_api, + fov, + {{ + .camera = m_api->camera, + .dimensions = { + {0, 0}, + {static_cast(screenShotWidth), static_cast(screenShotHeight)} + }, + .target = screenShotRenderView + }}, + m_currentScene + ); + needToMakeScreenshot = false; } -// { -// HCullStage tempCullStage = nullptr; -// auto drawStage = createSceneDrawStage(sceneScenario, screenShotWidth, screenShotHeight, deltaTime, true, -// false, false, *m_api, -// currentScene,tempCullStage); -// if (drawStage != nullptr) { -// uiDependecies.push_back(drawStage); -// screenshotDS = drawStage; -// screenshotFrame = m_api->hDevice->getFrameNumber(); -// } -// needToMakeScreenshot = false; -// } - - scenario->cullFunctions.push_back( - m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput, processingFrame, updateFrameNumberLambda)); } auto uiFrameInput = std::make_shared>(); uiFrameInput->delta = deltaTime * (1000.0f); - uiFrameInput->viewPortDimensions = dimension; - uiFrameInput->frameParameters = std::make_shared( ImGui::GetDrawData()); + uiFrameInput->frameParameters = std::make_shared( ImGui::GetDrawData(), dimension); auto clearColor = m_api->getConfig()->clearColor; scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput, processingFrame, updateFrameNumberLambda)); } - return scenario; } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index b431147e1..a82a794b9 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -176,6 +176,10 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_screenShotRenderView = nullptr; + std::shared_ptr m_debugRenderView = nullptr; + + std::string screenshotFilename = ""; HFrameBuffer screenshotFramebuffer = nullptr; int screenShotWidth = 100; diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index fe266c1c7..00e788552 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -13,7 +13,7 @@ namespace ImGuiFramePlan { class ImGUIParam { public: - explicit ImGUIParam(ImDrawData *imData) { + explicit ImGUIParam(ImDrawData *imData, const ViewPortDimensions &dimensions) : m_dimensions(dimensions) { //Do copy of imData into local copy if (imData != nullptr) { m_imData = *imData; @@ -38,8 +38,10 @@ namespace ImGuiFramePlan { } const ImDrawData * const getImData() { return &m_imData; }; + const ViewPortDimensions & getDimensions() const { return m_dimensions; }; private: ImDrawData m_imData; + ViewPortDimensions m_dimensions; }; } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index c9f6955e3..46caafe14 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -8,8 +8,10 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h" + FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( hDevice), m_device(hDevice) { @@ -77,7 +79,7 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture } HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } std::unique_ptr FrontendUIRenderForwardVLK::update( diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index ce92600ef..c9cc530e6 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -87,12 +87,6 @@ if (EMSCRIPTEN) endif () add_subdirectory(${PROJECT_SOURCE_DIR}/3rdparty/oneTbb EXCLUDE_FROM_ALL) -option(BUILD_WITHOUT_CULLED_PORTAL_DRAWING "Build without drawing culled portals" ON) - -if (BUILD_WITHOUT_CULLED_PORTAL_DRAWING MATCHES ON) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DCULLED_NO_PORTAL_DRAWING") -endif(BUILD_WITHOUT_CULLED_PORTAL_DRAWING MATCHES ON) - #set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDODEBUGTHREADS" ) #set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDODEBUGTHREADS") @@ -562,13 +556,18 @@ if (LINK_VULKAN) src/gapi/vulkan/context/vulkan_context.h src/gapi/vulkan/shaders/ShaderConfig.h src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.cpp - src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h src/gapi/vulkan/GDescriptorSetUpdater.cpp src/gapi/vulkan/GDescriptorSetUpdater.h src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp src/gapi/vulkan/commandBuffer/CommandBufferThread.h + src/gapi/vulkan/buffers/GBufferChunkDynamicVLK.h + src/gapi/vulkan/GDescriptorSetUpdater.cpp + src/gapi/vulkan/GDescriptorSetUpdater.h + src/gapi/vulkan/commandBuffer/CommandBufferThread.cpp + src/gapi/vulkan/commandBuffer/CommandBufferThread.h src/gapi/vulkan/buffers/GStagingRingBuffer.cpp src/gapi/vulkan/buffers/GStagingRingBuffer.h src/gapi/vulkan/buffers/gpu/BufferStagingVLK.cpp src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp - src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h) + src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) @@ -612,7 +611,7 @@ if (LINK_VULKAN) # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() #Add volk loader - set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c ) + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c) endif() diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 0216efd3e..2ed5d7133 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -47,19 +47,23 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD auto candidatesArr = this->m2List.getCandidates(); auto candCullRes = std::vector(candidatesArr.size(), 0xFFFFFFFF); - oneapi::tbb::parallel_for(tbb::blocked_range(0, candCullRes.size(), 1000), - [&](tbb::blocked_range r) { -//for (int i = 0; i < candidatesArr.size(); i++) { + oneapi::tbb::task_arena arena(oneapi::tbb::task_arena::automatic, 3); + arena.execute([&] { + + oneapi::tbb::parallel_for(tbb::blocked_range(0, candCullRes.size(), 1000), + [&](tbb::blocked_range r) { + //for (int i = 0; i < candidatesArr.size(); i++) { #if (__AVX__ && __SSE2__) - ObjectCullingSEE>::cull(this->frustumData, r.begin(), - r.end(), candidatesArr, - candCullRes); + ObjectCullingSEE>::cull(this->frustumData, r.begin(), + r.end(), candidatesArr, + candCullRes); #else - ObjectCulling>::cull(this->frustumData, - r.begin(), r.end(), candidatesArr, - candCullRes); + ObjectCulling>::cull(this->frustumData, + r.begin(), r.end(), candidatesArr, + candCullRes); #endif - }, tbb::auto_partitioner()); + }, tbb::auto_partitioner()); + }); for (int i = 0; i < candCullRes.size(); i++) { if (!candCullRes[i]) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 6c5b50d75..5dd52e45b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -439,6 +439,8 @@ class M2ObjectListContainer { void lock() { + drawnCanHaveDuplicates = true; + getCandidates(); getToLoadGeom(); getToLoadMain(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 9e8ddc9b9..c40c75709 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -331,7 +331,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mathfu::mat4 &frustumMat = frameInputParams.frameParameters->matricesForCulling->perspectiveMat; mathfu::mat4 &lookAtMat4 = frameInputParams.frameParameters->matricesForCulling->lookAtMat; - mapRenderPlan->renderingMatrices = frameInputParams.frameParameters->cameraMatricesForRendering; + mapRenderPlan->renderingMatrices = frameInputParams.frameParameters->renderTargets[0].cameraMatricesForRendering; mapRenderPlan->deltaTime = frameInputParams.delta; size_t adtRenderedThisFramePrev = mapRenderPlan->adtArray.size(); @@ -1097,25 +1097,29 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, if (candidates.size() > 0) { results = std::vector(candidates.size(), 0xFFFFFFFF); - oneapi::tbb::parallel_for(tbb::blocked_range(0, candidates.size(), 2000), - [&](tbb::blocked_range &r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { -// auto &m2ObjectCandidate = tmpVector[i]; -// if(m2ObjectCandidate->checkFrustumCulling(cameraPos, frustumData)) { -// exteriorView->drawnM2s.insert(m2ObjectCandidate); -// cullStage->m2Array.insert(m2ObjectCandidate); -// } + oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); + arena.execute([&] { + + oneapi::tbb::parallel_for(tbb::blocked_range(0, candidates.size(), 2000), + [&](tbb::blocked_range &r) { + // for (size_t i = r.begin(); i != r.end(); ++i) { + // auto &m2ObjectCandidate = tmpVector[i]; + // if(m2ObjectCandidate->checkFrustumCulling(cameraPos, frustumData)) { + // exteriorView->drawnM2s.insert(m2ObjectCandidate); + // cullStage->m2Array.insert(m2ObjectCandidate); + // } #if (__AVX__ && __SSE2__) - ObjectCullingSEE>::cull(frustumData, - r.begin(), r.end(), candidates, - results); + ObjectCullingSEE>::cull(frustumData, + r.begin(), r.end(), candidates, + results); #else - ObjectCulling>::cull(frustumData, - r.begin(), r.end(), candidates, - results); + ObjectCulling>::cull(frustumData, + r.begin(), r.end(), candidates, + results); #endif -// } - }, tbb::auto_partitioner()); + // } + }, tbb::auto_partitioner()); + }); } for (int i = 0; i < candidates.size(); i++) { @@ -1442,13 +1446,17 @@ void Map::update(const HMapRenderPlan &renderPlan) { if (granSize == 0) granSize = m2ToDraw.size(); if (granSize > 0) { - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - m2Object->update(deltaTime, cameraVec3, lookAtMat); - } - }, tbb::simple_partitioner()); + oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); + arena.execute([&] { + tbb::affinity_partitioner ap; + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + m2Object->update(deltaTime, cameraVec3, lookAtMat); + } + }, ap); + }); } if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { @@ -1490,15 +1498,20 @@ void Map::update(const HMapRenderPlan &renderPlan) { //2. Calc distance every 100 ms - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; - if (m2Object == nullptr) continue; - m2Object->calcDistance(cameraVec3); - } - }, tbb::auto_partitioner() - ); + { + oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); + arena.execute([&] { + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object == nullptr) continue; + m2Object->calcDistance(cameraVec3); + } + }, tbb::auto_partitioner() + ); + }); + } //Cleanup ADT every 10 seconds if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { @@ -1571,28 +1584,32 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe } - //if (granSize > 0) { - // auto l_device = m_api->hDevice; - // auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - // tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - // [&](tbb::blocked_range r) { - // l_device->setCurrentProcessingFrameNumber(processingFrame); - // for (size_t i = r.begin(); i != r.end(); ++i) { - // auto &m2Object = m2ToDraw[i]; - // if (m2Object != nullptr) { - // m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - // renderPlan->frameDependentData); - // } - // } - // }, tbb::simple_partitioner()); - //} - - for (auto &m2Object: renderPlan->m2Array.getDrawn()) { - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } + if (granSize > 0) { + auto l_device = m_api->hDevice; + auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); + arena.execute([&] { + tbb::affinity_partitioner ap; + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + l_device->setCurrentProcessingFrameNumber(processingFrame); + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object != nullptr) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + } + } + }, ap); + }); } + +// for (auto &m2Object: renderPlan->m2Array.getDrawn()) { +// if (m2Object != nullptr) { +// m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, +// renderPlan->frameDependentData); +// } +// } } { ZoneScopedN("m2SkyboxBuffersUpdate"); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index c0b684ee3..ed1f84b25 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,20 +276,46 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -319,12 +326,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +341,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,17 +379,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -393,14 +407,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {3,9, "uBumpTexture"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,18 +423,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,21 +445,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +460,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,96}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +477,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,16 +497,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,64}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -509,6 +512,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -529,15 +533,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -565,15 +569,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -601,15 +605,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,11 +625,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -637,16 +641,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,480}, + {0,2,168}, }, { { - {0,1,2}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -659,10 +662,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -674,17 +679,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {2,5,96}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {1,1,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -695,13 +707,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -710,15 +726,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +762,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,1,112}, + {0,0,480}, }, { { @@ -819,15 +835,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -855,15 +871,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -876,12 +892,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -893,15 +907,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,0,144}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,16 +943,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,2,48}, + {0,0,480}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,13 +966,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,15 +990,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,0,480}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -985,17 +1009,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,14 +1035,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,12 +1056,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,14 +1071,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1055,7 +1088,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -1076,17 +1108,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,0,84}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1129,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, {0,0,0}, - {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,16 +1146,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1137,12 +1168,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,17 +1192,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,4,32}, }, { { - {0,0,1}, - {1,1,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,11 +1213,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1189,24 +1229,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,2,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,17 +1250,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,24 +1265,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,4,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1264,11 +1286,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1279,15 +1303,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,96}, + {0,0,480}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1299,12 +1325,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1314,19 +1341,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { {0,0,1}, - {3,4,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1337,14 +1369,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,15 +1388,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,15 +1425,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,11 +1461,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, + {1,4,32}, {0,0,480}, }, { @@ -1448,12 +1484,14 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1463,17 +1501,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1500,24 +1537,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {5,5,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1528,17 +1558,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1547,24 +1573,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1575,14 +1593,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1591,17 +1608,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, - {4,4,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1613,21 +1629,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1637,19 +1645,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,16}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {1,2,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1675,16 +1688,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, + {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1694,24 +1709,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1720,24 +1727,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1766,21 +1766,35 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, } }, - }}, - {"drawBBShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1811,6 +1825,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + 6, { + {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, + } + }, + { + 4, { + {"_1_4_colors[0]", true, 0, 1, 4, 256}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, } }, { @@ -2209,13 +2293,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, } }, }}, @@ -2286,51 +2344,23 @@ const std::unordered_map dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + static const std::array dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo dynamicState = {}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.pNext = NULL; dynamicState.pDynamicStates = dynamicStateEnables.data(); - dynamicState.dynamicStateCount = 2; + dynamicState.dynamicStateCount = dynamicStateEnables.size(); VkGraphicsPipelineCreateInfo pipelineInfo = {}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -245,4 +245,7 @@ void GPipelineVLK::createPipeline( &graphicsPipeline) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics pipeline!"); } + + auto combinedName = shaderVLK->getShaderCombinedName(); + m_device.setObjectName(reinterpret_cast(graphicsPipeline), VK_OBJECT_TYPE_PIPELINE, combinedName.c_str()); } \ No newline at end of file diff --git a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h index ab4492483..64d2a22bf 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h @@ -30,7 +30,7 @@ class CBufferChunkVLK : public IBufferChunk { return *static_cast(((SubBuffer *)pSubBuffer)->getPointer()); }; void save() override { - pSubBuffer->save(m_realSize); +// pSubBuffer->save(m_realSize); }; size_t getIndex() { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index dbda39eeb..63e138a9b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -102,18 +102,19 @@ void GBufferVLK::uploadData(const void *data, int length) { } void *GBufferVLK::allocatePtr(int offset, int length) { -// std::unique_lock lock(m_mutex); - VkBuffer staging; int stage_offset; auto *ptr = m_ringBuff->allocateNext(length, staging, stage_offset); auto frameIndex = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - uploadRegionsPerStaging[frameIndex][staging].push_back({ - .srcOffset = static_cast(stage_offset), - .dstOffset = static_cast(offset), - .size = static_cast(length) - }); + { +// std::unique_lock lock(m_mutex); + uploadRegionsPerStaging[frameIndex][staging].push_back({ + .srcOffset = static_cast(stage_offset), + .dstOffset = static_cast(offset), + .size = static_cast(length) + }); + } return ptr; } @@ -273,7 +274,7 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { uploadData.src = stagingRecord.first; uploadData.dst = m_gpuBuffer->getBuffer(); - uploadData.copyRegions = intervals; + uploadData.copyRegions = std::vector(intervals.begin(), intervals.end()); } } stagingRecords.clear(); diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 87cafaba8..3250060c3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -7,6 +7,7 @@ #include #include +#include "tbb/tbb.h" class GDeviceVLK; typedef std::shared_ptr HGDeviceVLK; @@ -74,7 +75,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this>, IDevice::MAX_FRAMES_IN_FLIGHT> uploadRegionsPerStaging; + std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> uploadRegionsPerStaging; std::mutex dataToBeUploadedMtx; std::vector dataToBeUploaded; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index 9447c3064..850ff9ef3 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -10,31 +10,38 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of int startOffset = 0; int bufferIndex = 0; - uint32_t ¤tOffset = offsets[frame]; + auto ¤tOffset = offsets[frame]; if (size > STAGE_BUFFER_SIZE) throw std::runtime_error(("size > STAGE_BUFFER_SIZE; size = " + std::to_string(size))); - { -// std::unique_lock l(m_mutex); - int currentIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; - int currentIndexAfter = (currentOffset + size) / STAGE_BUFFER_SIZE; - if (currentIndex != currentIndexAfter) - currentOffset = currentIndexAfter * STAGE_BUFFER_SIZE; + int currentIndex = 0; + int currentIndexAfter = 0; + uint64_t offset = 0; + do { + offset = atomic_fetch_add(¤tOffset, size); - startOffset = currentOffset % STAGE_BUFFER_SIZE; - bufferIndex = currentIndexAfter; + currentIndex = ( offset ) / STAGE_BUFFER_SIZE; + currentIndexAfter = (offset + size) / STAGE_BUFFER_SIZE; - if (currentIndexAfter >= vec.size()) { - vec.emplace_back().staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); - } + if (currentIndexAfter >= vec.size()) { + std::unique_lock l(m_mutex); + while (currentIndexAfter >= vec.size()) { + vec.emplace_back().staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); + } + } - currentOffset += size; - } + } while(currentIndex != currentIndexAfter); + + bufferIndex = currentIndex; + startOffset = offset % STAGE_BUFFER_SIZE; auto &staging = vec[bufferIndex]; auto allocatedPtr = ((uint8_t *)staging.cpuBuffer.data()) + startOffset; + if ((startOffset + size) > staging.cpuBuffer.size()) { + size++; + } o_staging = staging.staging->getBuffer(); o_offset = startOffset; @@ -45,7 +52,7 @@ void GStagingRingBuffer::flushBuffers() { auto frame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &vec = m_stagingBuffers[frame]; - uint32_t ¤tOffset = offsets[frame]; + uint64_t currentOffset = offsets[frame]; uint32_t maxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; @@ -59,7 +66,7 @@ void GStagingRingBuffer::flushBuffers() { } uint32_t prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; - currentOffset = 0; + offsets[frame] = 0; vec.resize(std::min(prevMaxIndex+1, vec.size())); } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h index 3d8633f41..6b4ac1dd4 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -24,7 +24,7 @@ class GStagingRingBuffer { std::mutex m_mutex; - std::array offsets = {0,0,0}; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> offsets = {0,0,0}; struct BufferAndCPU { std::shared_ptr staging; std::array cpuBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index 8be926295..a21b4a3a8 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -32,31 +32,31 @@ CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr void GCommandBuffer::createCommandBufVLK() { if (m_cmdBufWasCreated) { - //Dispose of previous buffer - auto l_cmdBuf = m_cmdBuffer; - - auto l_deviceVlk = m_device.getVkDevice(); - auto l_commandPool = m_commandPool; - auto l_tracyContext = tracyContext; - - m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_tracyContext, l_commandPool]() -> void { -#ifdef LINK_TRACY - TracyVkCollect(l_tracyContext, l_cmdBuf); -#endif - vkFreeCommandBuffers(l_deviceVlk, l_commandPool, 1, &l_cmdBuf); - }); - - - } +// //Dispose of previous buffer +// auto l_cmdBuf = m_cmdBuffer; +// +// auto l_deviceVlk = m_device.getVkDevice(); +// auto l_commandPool = m_commandPool; +// auto l_tracyContext = tracyContext; +// +// m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_tracyContext, l_commandPool]() -> void { +//#ifdef LINK_TRACY +// TracyVkCollect(l_tracyContext, l_cmdBuf); +//#endif +// vkFreeCommandBuffers(l_deviceVlk, l_commandPool, 1, &l_cmdBuf); +// }); + vkResetCommandBuffer(m_cmdBuffer, 0); + } else { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = m_commandPool; - allocInfo.level = m_isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocInfo.commandBufferCount = 1; + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_commandPool; + allocInfo.level = m_isPrimary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocInfo.commandBufferCount = 1; - if (vkAllocateCommandBuffers(m_device.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); + if (vkAllocateCommandBuffers(m_device.getVkDevice(), &allocInfo, &m_cmdBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } } if (!m_cmdBufWasCreated) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index db7b3ab20..d5e88038c 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -75,34 +75,6 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( ); } -void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet) { - //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others - //Which leads to three separate states for: - // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR - // Also, implement "Pipeline Layout Compatibility" thing from spec - -// if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; - - auto pDescriptorSet = descriptorSet.get(); - - if (m_currentDescriptorSet[bindIndex] != pDescriptorSet) { - auto vkDescSet = pDescriptorSet->getDescSet(); - constexpr uint32_t vkDescCnt = 1; - - - std::array dynamicOffsets; - uint32_t dynamicOffsetsSize; - pDescriptorSet->getDynamicOffsets(dynamicOffsets, dynamicOffsetsSize); - - vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, - m_currentPipeline->getLayout(), - bindIndex, - vkDescCnt, &vkDescSet, - dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets.data() : nullptr); - - m_currentDescriptorSet[bindIndex] = pDescriptorSet; - } -} CommandBufferDebugLabel CmdBufRecorder::beginDebugLabel(const std::string &labelName, const std::array &colors) { return CommandBufferDebugLabel( @@ -159,13 +131,7 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector &pipeline) { - if (m_currentPipeline == pipeline) return; - vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline()); - - m_currentPipeline = pipeline; -} void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance) { vkCmdDrawIndexed(m_gCmdBuffer.m_cmdBuffer, @@ -216,7 +182,7 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff if (submitRecords.get().empty()) return; - auto &submits = submitRecords.get(); + const auto &submits = submitRecords.get(); for (int i = 0; i < submits.size(); i++) { auto &submit = submits[i]; if (submit.needsBarrier && !submit.copyRegions.empty()) { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 1efa3b182..d96304871 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -21,6 +21,7 @@ class CommandBufferDebugLabel; #include "RenderPassHelper.h" #include "CommandBufferDebugLabel.h" #include "../../descriptorSets/GDescriptorSet.h" +#include "../../GPipelineVLK.h" #ifdef LINK_TRACY #define VkZone(buffRecorder,a) TracyVkZone(buffRecorder.getTracyContext(), buffRecorder.getNativeCmdBuffer(), a) @@ -51,8 +52,10 @@ class CmdBufRecorder { void bindIndexBuffer(const std::shared_ptr &bufferVlk); void bindVertexBuffers(const std::vector> &bufferVlk); - void bindPipeline(const std::shared_ptr &pipeline); - void bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet); + + inline void bindPipeline(const std::shared_ptr &pipeline); + inline void bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet); + void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); void setScissors(const std::array &areaOffset, @@ -80,7 +83,8 @@ class CmdBufRecorder { //States std::shared_ptr m_currentRenderPass = nullptr; - std::shared_ptr m_currentPipeline = nullptr; + GPipelineVLK *m_currentPipeline = nullptr; + VkPipelineLayout m_currentPipelineLayout = nullptr; std::shared_ptr m_currentIndexBuffer = nullptr; std::array, MAX_VERTEX_BUFFERS_PER_DRAWCALL> m_currentVertexBuffers; std::array m_currentDescriptorSet = {nullptr}; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h new file mode 100644 index 000000000..e55d84347 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h @@ -0,0 +1,51 @@ +// +// Created by Deamon on 9/21/2023. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_INLINE_H +#define AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_INLINE_H + +#include "CommandBufferRecorder.h" + +inline void CmdBufRecorder::bindPipeline(const std::shared_ptr &pipeline) { + auto *pPipelineVlk = pipeline.get(); + if (m_currentPipeline == pPipelineVlk) return; + + vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pPipelineVlk->getPipeline()); + + m_currentPipeline = pPipelineVlk; + m_currentPipelineLayout = pipeline->getLayout(); +} + +inline void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet) { + { + //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others + //Which leads to three separate states for: + // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR + // Also, implement "Pipeline Layout Compatibility" thing from spec + +// if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; + + auto pDescriptorSet = descriptorSet.get(); + + if (m_currentDescriptorSet[bindIndex] != pDescriptorSet) { + auto vkDescSet = pDescriptorSet->getDescSet(); + constexpr uint32_t vkDescCnt = 1; + + + uint32_t dynamicOffsets[16]; + uint32_t dynamicOffsetsSize; + pDescriptorSet->getDynamicOffsets(dynamicOffsets, dynamicOffsetsSize); + + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, + m_currentPipelineLayout, + bindIndex, + vkDescCnt, &vkDescSet, + dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets : nullptr); + + m_currentDescriptorSet[bindIndex] = pDescriptorSet; + } + } +} + +#endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_INLINE_H diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 1c46167bd..f2e0594eb 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -49,22 +49,14 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de m_firstUpdate = false; m_dynamicBufferIndexes = dynamicBufferIndexes; -} - -void GDescriptorSet::getDynamicOffsets(std::array &dynamicOffsets, uint32_t &dynamicOffsetsSize) { - dynamicOffsetsSize = m_dynamicBufferIndexes.size(); - - assert(dynamicOffsetsSize <= 16); - for (int i = 0; i < dynamicOffsetsSize; i++) { - - auto &descriptor = boundDescriptors[m_dynamicBufferIndexes[i]]; - assert(descriptor->descType == DescriptorRecord::DescriptorRecordType::UBODynamic); - - dynamicOffsets[i] = (descriptor->buffer->getOffset()); + m_dynamicBuffers.resize(m_dynamicBufferIndexes.size()); + for (int i = 0; i < m_dynamicBufferIndexes.size(); i++) { + m_dynamicBuffers[i] = boundDescriptors[m_dynamicBufferIndexes[i]]->buffer.get(); } } + // ------------------------------------- // Update Helper // ------------------------------------- diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 6521f8bb6..52810e6d7 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -29,7 +29,26 @@ class GDescriptorSet : public std::enable_shared_from_this { const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} - void getDynamicOffsets(std::array &dynamicOffsets, uint32_t &dynamicOffsetsSize); + inline void getDynamicOffsets(uint32_t *dynamicOffsets, uint32_t& dynamicOffsetsSize) { + const auto dynBufSize = m_dynamicBuffers.size(); + dynamicOffsetsSize = dynBufSize; +// +// auto pDynamicOffsets = dynamicOffsets.data(); +// +// assert(dynamicOffsetsSize <= 16); +// for (int i = 0; i < dynBufSize; i++) { +// +// auto& descriptor = boundDescriptors[m_dynamicBufferIndexes[i]]; +// assert(descriptor->descType == DescriptorRecord::DescriptorRecordType::UBODynamic); +// +// pDynamicOffsets[i] = (descriptor->buffer->getOffset()); +// } + +// auto pDynamicOffsets = dynamicOffsets.data(); + for (int i = 0; i < dynBufSize; i++) { + dynamicOffsets[i] = m_dynamicBuffers[i]->getOffset(); + } + } @@ -105,6 +124,7 @@ class GDescriptorSet : public std::enable_shared_from_this { const std::shared_ptr m_hDescriptorSetLayout; std::vector m_dynamicBufferIndexes; + std::vector m_dynamicBuffers; bool m_firstUpdate = true; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index efd6bbd0f..8c67f497e 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -6,10 +6,3 @@ #include "../GPipelineVLK.h" -GM2MeshVLK::GM2MeshVLK(const gMeshTemplate &meshTemplate, - const HMaterialVLK &material, int priorityPlane, int layer) : - GSortableMeshVLK(meshTemplate, material, priorityPlane), IM2Mesh(layer, priorityPlane), - ISortableMesh(priorityPlane) { - - m_layer = layer; -} diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h index 756d9fa72..6ff62b7e2 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.h @@ -8,10 +8,5 @@ #include "../../interface/meshes/IM2Mesh.h" #include "GSortableMeshVLK.h" -class GM2MeshVLK : public GSortableMeshVLK, public IM2Mesh { -public: - GM2MeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, int priorityPlane, int layer); - ~GM2MeshVLK() override = default ; -}; #endif //AWEBWOWVIEWERCPP_GM2MESH_H diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 810801680..5a9dcbeda 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -10,8 +10,9 @@ #include "../GPipelineVLK.h" GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, - const HMaterialVLK &material -) : m_meshType(meshTemplate.meshType), m_material(material) { + const HMaterialVLK &material, int layer, int priority) : + IM2Mesh(layer, priority), m_meshType(meshTemplate.meshType), + m_material(material) { m_bindings = meshTemplate.bindings; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index dfa48232e..9e43437bf 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -11,18 +11,20 @@ #include "../descriptorSets/GDescriptorSet.h" #include "../materials/ISimpleMaterialVLK.h" -class GMeshVLK : virtual public IMesh { +class GMeshVLK : public IM2Mesh { friend class GDeviceVLK; public: explicit GMeshVLK(const gMeshTemplate &meshTemplate, - const HMaterialVLK &material); + const HMaterialVLK &material, int layer, int priority); public: ~GMeshVLK() override; bool getIsTransparent() override; MeshType getMeshType() override; - + EGxBlendEnum getGxBlendMode() override { + return material()->getBlendMode(); + } public: auto material() const -> const HMaterialVLK& { return m_material; } auto scissorOffset() const -> const std::array& { return m_scissorOffset; } diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp index 917714acd..c19999b82 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.cpp @@ -4,7 +4,3 @@ #include "GSortableMeshVLK.h" -GSortableMeshVLK::GSortableMeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, - int priorityPlane) : GMeshVLK(meshTemplate, material), ISortableMesh(priorityPlane) { - -} diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h index a5b380d38..d8dd822d9 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GSortableMeshVLK.h @@ -9,17 +9,7 @@ #include "GMeshVLK.h" #include "../../interface/meshes/ISortableMesh.h" -class GSortableMeshVLK : public GMeshVLK, public virtual ISortableMesh { -public: - GSortableMeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, - int priorityPlane); - ~GSortableMeshVLK() override = default; - - EGxBlendEnum getGxBlendMode() override { - return material()->getBlendMode(); - } -}; #endif //AWEBWOWVIEWERCPP_GSORTABLEMESHVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 3022a8327..dba8be632 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -200,6 +200,9 @@ void GShaderPermutationVLK::createPipelineLayout() { if (vkCreatePipelineLayout(m_device->getVkDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create pipeline layout!"); } + + auto combinedName = this->getShaderCombinedName(); + m_device->setObjectName(reinterpret_cast(pipelineLayout), VK_OBJECT_TYPE_PIPELINE_LAYOUT, combinedName.c_str()); } const std::shared_ptr diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 1f3e79910..12520c698 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -36,7 +36,7 @@ enum class EFreeStrategy : char { class Config { public: Config() { - m_hardwareThreadCount = std::max((int)std::thread::hardware_concurrency()-2, 1); + m_hardwareThreadCount = std::max((int)std::thread::hardware_concurrency()-3, 1); } public: diff --git a/wowViewerLib/src/renderer/frame/FrameInputParams.h b/wowViewerLib/src/renderer/frame/FrameInputParams.h index 54e3a7875..87566b4f2 100644 --- a/wowViewerLib/src/renderer/frame/FrameInputParams.h +++ b/wowViewerLib/src/renderer/frame/FrameInputParams.h @@ -16,13 +16,9 @@ struct ViewPortDimensions{ template struct FrameInputParams { std::shared_ptr frameParameters; - std::shared_ptr screenShotParameters; //Time advance animTime_t delta = 0; - - //Parameters for framebuffer - ViewPortDimensions viewPortDimensions = {{0,0}, {64, 64}}; }; #endif //AWEBWOWVIEWERCPP_FRAMEINPUTPARAMS_H diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h index 9bd3c63ce..9724a6a71 100644 --- a/wowViewerLib/src/renderer/frame/FrameProfile.h +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -22,6 +22,7 @@ #define ZoneScopedN(a) #define TracyVkContext(x,y,z,w) #define TracyMessageStr(a) +#define VkZone(a, b) #endif diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index ea9384d83..6f16d3865 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -6,6 +6,7 @@ #include #include "SceneComposer.h" #include "FrameProfile.h" +#include "tbb/tbb.h" #ifdef __EMSCRIPTEN__ #include @@ -40,6 +41,9 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon }); cullingThread = std::thread(([&]() { +// tbb::global_control global_limit(oneapi::tbb::global_control::max_allowed_parallelism, +// 2*apiContainer->getConfig()->hardwareThreadCount()); + using namespace std::chrono_literals; setThreadName("Culling"); @@ -59,6 +63,9 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon })); updateThread = std::thread(([&]() { +// tbb::global_control global_limit(oneapi::tbb::global_control::max_allowed_parallelism, +// apiContainer->getConfig()->hardwareThreadCount()); + using namespace std::chrono_literals; setThreadName("Update"); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h index b6941cc0b..c9cdcd701 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h @@ -9,11 +9,22 @@ #include "../../engine/CameraMatrices.h" #include "../../engine/objects/iScene.h" +class IRenderView { +public: + virtual ~IRenderView() = default; +}; + struct MapSceneParams { std::shared_ptr scene; HCameraMatrices matricesForCulling; - HCameraMatrices cameraMatricesForRendering; - HCameraMatrices cameraMatricesForDebugCamera; + + struct RenderTuple { + HCameraMatrices cameraMatricesForRendering = nullptr; + std::shared_ptr target = nullptr; + ViewPortDimensions viewPortDimensions = {{0,0}, {64, 64}}; + bool clearTarget = false; + }; + std::vector renderTargets; mathfu::vec4 clearColor; }; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 7bf1b6042..572835df1 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -107,10 +107,12 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public bool isVulkan, animTime_t sceneTime); + virtual std::shared_ptr createRenderView(int width, int height) = 0; private: Config *m_config; }; + //typedef FrameInputParams MapSceneRendererInputParams; typedef FrameInputParams MapSceneRendererInputParams; typedef std::shared_ptr HMapSceneRenderer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 032981ffc..67764f6c5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -14,6 +14,7 @@ #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../../frame/FrameProfile.h" +#include "../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" #include static const ShaderConfig forwardShaderConfig = { @@ -96,7 +97,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), true, false); - defaultView = std::make_unique(m_device, uboBuffer, m_drawQuadVao); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao); sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) @@ -546,7 +547,7 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); //3. Bind pipeline - auto material = meshVlk->material(); + const auto &material = meshVlk->material(); cmdBuf.bindPipeline(material->getPipeline()); //4. Bind Descriptor sets @@ -583,11 +584,17 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - defaultView->update( - frameInputParams->viewPortDimensions.maxs[0], - frameInputParams->viewPortDimensions.maxs[1], - framePlan->frameDependentData->currentGlow - ); + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + if (!updatingTarget) updatingTarget = defaultView; + + updatingTarget->update( + renderTarget.viewPortDimensions.maxs[0], + renderTarget.viewPortDimensions.maxs[1], + framePlan->frameDependentData->currentGlow + ); + } + //Create meshes auto opaqueMeshes = std::make_shared>(); @@ -705,8 +712,10 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { ZoneScopedN("submit opaque"); VkZone(frameBufCmd, "render opaque") - for (auto const &mesh: *opaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + auto const &pOpaqueMeshes = *opaqueMeshes; + auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); + for (int i = 0; i < pOpaqueMeshesSize; i++) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], CmdBufRecorder::ViewportType::vp_usual); } } { @@ -731,7 +740,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); } if (renderSky && skyMesh0x4) @@ -778,11 +787,11 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { } HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } HGSortableMesh MapSceneRenderForwardVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } @@ -790,27 +799,31 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } +std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int width, int height) { + return std::make_shared(m_device, uboBuffer, m_drawQuadVao); +} + /* - * RenderView + * RenderViewForwardVLK */ -MapSceneRenderForwardVLK::RenderView::RenderView(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device) { +MapSceneRenderForwardVLK::RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device) { glowPass = std::make_unique(m_device, uboBuffer, quadVAO); createFrameBuffers(); } -void MapSceneRenderForwardVLK::RenderView::createFrameBuffers() { +void MapSceneRenderForwardVLK::RenderViewForwardVLK::createFrameBuffers() { { auto const dataFormat = {ITextureFormat::itRGBA}; @@ -827,7 +840,7 @@ void MapSceneRenderForwardVLK::RenderView::createFrameBuffers() { } } -void MapSceneRenderForwardVLK::RenderView::update(int width, int height, float glow) { +void MapSceneRenderForwardVLK::RenderViewForwardVLK::update(int width, int height, float glow) { if (width != m_width || height != m_height) { m_width = width; m_height = height; @@ -848,7 +861,7 @@ void MapSceneRenderForwardVLK::RenderView::update(int width, int height, float g glowPass->assignFFXGlowUBOConsts(glow); } -RenderPassHelper MapSceneRenderForwardVLK::RenderView::beginPass(CmdBufRecorder &frameBufCmd, +RenderPassHelper MapSceneRenderForwardVLK::RenderViewForwardVLK::beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor) { @@ -861,10 +874,10 @@ RenderPassHelper MapSceneRenderForwardVLK::RenderView::beginPass(CmdBufRecorder true); } -void MapSceneRenderForwardVLK::RenderView::doPostGlow(CmdBufRecorder &frameBufCmd) { +void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostGlow(CmdBufRecorder &frameBufCmd) { glowPass->doPass(frameBufCmd); } -void MapSceneRenderForwardVLK::RenderView::doPostFinal(CmdBufRecorder &bufCmd) { +void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostFinal(CmdBufRecorder &bufCmd) { glowPass->doFinalPass(bufCmd); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 54cf69eb7..005d717d1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -96,6 +96,13 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + +//-------------------------------------- +// RenderView +//-------------------------------------- + + std::shared_ptr createRenderView(int width, int height) override; + private: HGDeviceVLK m_device; @@ -141,9 +148,11 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { std::shared_ptr m_stagingRingBuffer; private: - class RenderView { + class RenderViewForwardVLK : public IRenderView { public: - RenderView(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); + RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); + ~RenderViewForwardVLK() override = default; + void update(int width, int height, float glow); RenderPassHelper beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, @@ -163,7 +172,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { void createFrameBuffers(); }; - std::unique_ptr defaultView; + std::shared_ptr defaultView; }; class IM2ModelDataVLK : public IM2ModelData { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index ba7ffebad..50bf2a7c1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -7,6 +7,7 @@ #include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" #include "../../../../gapi/vulkan/GVertexBufferBindingsVLK.h" #include "../../../frame/FrameProfile.h" +#include "../../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device), m_drawQuadVao(quadVAO) { From 4ecae90a000a355a030e0e9ea3c4fccb67da846b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 28 Sep 2023 07:43:30 +0300 Subject: [PATCH 118/212] - after much struggle add debug rendering window --- CMakeLists.txt | 4 +- src/ui/FrontendUI.cpp | 34 ++- src/ui/FrontendUI.h | 2 + src/ui/childWindow/BLPViewer.cpp | 4 +- src/ui/childWindow/BLPViewer.h | 2 +- .../textureRenderer/DebugRendererWindow.cpp | 70 ++++++ .../textureRenderer/DebugRendererWindow.h | 44 ++++ .../vulkan/FrontendUIRenderForwardVLK.cpp | 7 +- wowViewerLib/src/gapi/interface/IDevice.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 6 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 1 + .../src/gapi/vulkan/GFrameBufferVLK.cpp | 4 - .../src/gapi/vulkan/GFrameBufferVLK.h | 3 + .../src/gapi/vulkan/TextureManagerVLK.cpp | 8 +- .../src/gapi/vulkan/TextureManagerVLK.h | 2 + .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 16 -- .../CommandBufferRecorder.h | 2 +- .../CommandBufferRecorder_inline.h | 45 ++-- .../vulkan/materials/ISimpleMaterialVLK.cpp | 13 +- .../vulkan/materials/ISimpleMaterialVLK.h | 4 +- .../vulkan/materials/MaterialBuilderVLK.h | 9 +- .../gapi/vulkan/textures/GBlpTextureVLK.cpp | 3 +- .../src/gapi/vulkan/textures/GBlpTextureVLK.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 19 +- .../src/gapi/vulkan/textures/GTextureVLK.h | 10 +- .../src/renderer/mapScene/MapSceneParams.h | 23 +- .../renderer/mapScene/MapSceneRenderer.cpp | 20 +- .../src/renderer/mapScene/MapSceneRenderer.h | 4 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 220 ++++++++++++------ .../vulkan/MapSceneRenderForwardVLK.h | 13 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 23 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.h | 3 +- 32 files changed, 432 insertions(+), 189 deletions(-) create mode 100644 src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp create mode 100644 src/ui/childWindow/textureRenderer/DebugRendererWindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 31842fb45..9fa32ad46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,7 +237,9 @@ set(SOURCE_FILES src/ui/childWindow/mapSelectionWindow/MapSelectDialog.cpp src/ui/childWindow/mapSelectionWindow/MapSelectDialog.h src/ui/imguiLib/wheelCapture/wheelCapture.cpp - src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h) + src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h + src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp + src/ui/childWindow/textureRenderer/DebugRendererWindow.h) set(SOURCE_FILES_VULKAN diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 01a167e88..1d53519b3 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -134,6 +134,8 @@ void FrontendUI::composeUI() { showCurrentStatsDialog(); showMinimapGenerationSettingsDialog(); showBlpViewer(); + if (m_debugRenderWindow) + m_debugRenderWindow->draw(); // Rendering ImGui::Render(); @@ -1409,6 +1411,13 @@ void FrontendUI::showSettingsDialog() { bool useDoubleCameraDebug = m_api->getConfig()->doubleCameraDebug; if (ImGui::Checkbox("Enable second camera(for debug)", &useDoubleCameraDebug)) { m_api->getConfig()->doubleCameraDebug = useDoubleCameraDebug; + if (!useDoubleCameraDebug) { + m_debugRenderWindow = nullptr; + m_debugRenderView = nullptr; + } else if (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) { + m_debugRenderView = m_sceneRenderer->createRenderView(640, 480, true); + m_debugRenderWindow = std::make_shared(m_api, m_uiRenderer, m_debugRenderView); + } } if (useDoubleCameraDebug) { @@ -1704,8 +1713,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do std::shared_ptr target = nullptr; std::shared_ptr debugTarget = nullptr; - if (m_api->debugCamera && m_api->getConfig()->doubleCameraDebug) { - if (!m_debugRenderView) m_debugRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight); + if (m_api->debugCamera && m_api->getConfig()->doubleCameraDebug && m_debugRenderView) { debugTarget = m_debugRenderView; if (m_api->getConfig()->swapMainAndDebug) { @@ -1715,15 +1723,21 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do std::vector renderTargetParams = { { - .camera = m_api->camera, - .dimensions = dimension, - .target = target + m_api->camera, + dimension, + target } }; if (m_api->getConfig()->doubleCameraDebug) { + ViewPortDimensions debugViewDimension = { + {0, 0}, + {static_cast(m_debugRenderWindow->getWidth()), + static_cast(m_debugRenderWindow->getHeight())} + }; + auto &debugParams = renderTargetParams.emplace_back(); debugParams.camera = m_api->debugCamera; - debugParams.dimensions = dimension; + debugParams.dimensions = debugViewDimension; debugParams.target = debugTarget; } @@ -1739,7 +1753,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do //---------------------- if (needToMakeScreenshot) { - auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight); + auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight, true); auto wowSceneScreenshotFrameInput = std::make_shared>(); wowSceneScreenshotFrameInput->delta = 0; @@ -1747,12 +1761,12 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do *m_api, fov, {{ - .camera = m_api->camera, - .dimensions = { + m_api->camera, + { {0, 0}, {static_cast(screenShotWidth), static_cast(screenShotHeight)} }, - .target = screenShotRenderView + screenShotRenderView }}, m_currentScene ); diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index a82a794b9..5d55f74d5 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -27,6 +27,7 @@ #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" #include "childWindow/BLPViewer.h" #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" +#include "childWindow/textureRenderer/DebugRendererWindow.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -191,6 +192,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_minimapGenerationWindow = nullptr; std::shared_ptr m_blpViewerWindow = nullptr; + std::shared_ptr m_debugRenderWindow; //Test export diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index c00be2c73..7508f6a51 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -6,7 +6,9 @@ #include "imgui.h" #include -BLPViewer::BLPViewer(HApiContainer &api, std::shared_ptr uiRenderer) : m_api(api), m_uiRenderer(uiRenderer) { +BLPViewer::BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer) : + m_api(api), m_uiRenderer(uiRenderer) +{ } diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h index a0582b3a3..be2589ec6 100644 --- a/src/ui/childWindow/BLPViewer.h +++ b/src/ui/childWindow/BLPViewer.h @@ -12,7 +12,7 @@ class BLPViewer { public: - BLPViewer(HApiContainer &api, std::shared_ptr uiRenderer); + BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer); bool draw(); private: diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp new file mode 100644 index 000000000..f2c7aed4f --- /dev/null +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp @@ -0,0 +1,70 @@ +// +// Created by Deamon on 9/26/2023. +// + +#include "DebugRendererWindow.h" +#include "../../../../wowViewerLib/src/renderer/mapScene/MapSceneParams.h" + +DebugRendererWindow::DebugRendererWindow(const HApiContainer &api, + const std::shared_ptr &renderer, + const std::shared_ptr &renderView) : + m_renderView(renderView), m_api(api), m_renderer(renderer) { + + createMaterials(); +} + +DebugRendererWindow::~DebugRendererWindow() { + m_renderView->eraseOnUpdate(iteratorUnique); +} + +void DebugRendererWindow::draw() { + if (iteratorUnique == nullptr) { + auto l_weak = this->weak_from_this(); + iteratorUnique = m_renderView->addOnUpdate([l_weak] { + auto shared = l_weak.lock(); + if (shared) { + shared->createMaterials(); + } + }); + } + + auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + + ImGui::Begin("Debug Render Window"); + { + float sizeX = 0, sizeY = 0; + auto windowSize = ImGui::GetContentRegionAvail(); + sizeX = windowSize.x; + sizeY = windowSize.y; + + if (m_width != sizeX || m_height != sizeY) { + m_width = sizeX > 0 ? sizeX : 1; + m_height = sizeY > 0 ? sizeY : 1; + } + + if (currentSelectionIndex < m_selections.size()) { + auto const ¤tMaterial = m_selections[currentSelectionIndex].materials[currentFrame]; + if (currentMaterial) { + ImGui::Image(currentMaterial, {sizeX, sizeY}); + } + } + } + ImGui::End(); +} + +void DebugRendererWindow::createMaterials() { + this->m_selections.clear(); + m_renderView->iterateOverOutputTextures([&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, + const std::string &name, ITextureFormat textureFormat) { + SelectionRecord &record = this->m_selections.emplace_back(); + record.name = name; + + if (textureFormat == ITextureFormat::itRGBA) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + record.materials[i] = this->m_renderer->createUIMaterial(textures[i]); + } + } + }); + if (currentSelectionIndex > m_selections.size()) + currentSelectionIndex = 0; +} diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.h b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h new file mode 100644 index 000000000..f717fb4f8 --- /dev/null +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h @@ -0,0 +1,44 @@ +// +// Created by Deamon on 9/26/2023. +// + +#ifndef AWEBWOWVIEWERCPP_DEBUGRENDERERWINDOW_H +#define AWEBWOWVIEWERCPP_DEBUGRENDERERWINDOW_H + +#include "../../renderer/uiScene/FrontendUIRenderer.h" +#include "../../../../wowViewerLib/src/engine/ApiContainer.h" +#include "../../../../wowViewerLib/src/renderer/mapScene/MapSceneParams.h" + +class DebugRendererWindow : public std::enable_shared_from_this { +public: + DebugRendererWindow(const HApiContainer &api, const std::shared_ptr &renderer, + const std::shared_ptr &renderView); + ~DebugRendererWindow(); + + void draw(); + void createMaterials(); + + uint16_t getWidth() { return m_width;} + uint16_t getHeight() { return m_height;} +private: + HApiContainer m_api; + std::shared_ptr m_renderView; + + struct SelectionRecord { + std::string name; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> materials; + }; + + int currentSelectionIndex = 0; + std::vector m_selections; + std::shared_ptr m_renderer; + + typedef std::list>::const_iterator OnUpdateIter; + std::unique_ptr iteratorUnique; + + uint16_t m_width = 640; + uint16_t m_height = 480; +}; + + +#endif //AWEBWOWVIEWERCPP_DEBUGRENDERERWINDOW_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 46caafe14..15056bd4d 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -135,11 +135,8 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( //4. Bind Descriptor sets auto const &descSets = material->getDescriptorSets(); - for (int i = 0; i < descSets.size(); i++) { - if (descSets[i] != nullptr) { - swapChainCmd.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); - } - } + swapChainCmd.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); + //5. Set view port swapChainCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index 3e3675bb4..18965c939 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -187,6 +187,7 @@ class IDevice { virtual HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) = 0; virtual HGSamplableTexture createTexture(bool xWrapTex, bool yWrapTex) = 0; + virtual HGSamplableTexture createSampledTexture(HGTexture texture, bool xWrapTex, bool yWrapTex) = 0; virtual HGSamplableTexture getWhiteTexturePixel() = 0; virtual HGSamplableTexture getBlackTexturePixel() = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate) = 0; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index c401f1c4a..c769bd7c8 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -1603,3 +1603,7 @@ int GDeviceVLK::getMaxSamplesCnt() { VkSampleCountFlagBits GDeviceVLK::getMaxSamplesBit() { return sampleCountToVkSampleCountFlagBits(getMaxSamplesCnt()); } + +HGSamplableTexture GDeviceVLK::createSampledTexture(HGTexture texture, bool xWrapTex, bool yWrapTex) { + return this->m_textureManager->createSampledTexture(xWrapTex, yWrapTex, texture); +} diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 3e7ff54f3..3f80fa242 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -110,6 +110,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getDescriptorSetUpdater() override { return m_descriptorSetUpdater;}; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index 2895e3e3e..f4f8fd1f7 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -62,7 +62,6 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, h_depthTexture.reset(new GTextureVLK( mdevice, std::max(width, 1), std::max(height, 1), - false, false, true, fbDepthFormat, VK_SAMPLE_COUNT_1_BIT, @@ -129,7 +128,6 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, h_texture.reset(new GTextureVLK( mdevice, width, height, - false, false, false, textureFormat, sampleCountToVkSampleCountFlagBits(multiSampleCnt), @@ -145,7 +143,6 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, h_texture.reset(new GTextureVLK( mdevice, width, height, - false, false, false, textureFormat, VK_SAMPLE_COUNT_1_BIT, @@ -168,7 +165,6 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, h_depthTexture.reset(new GTextureVLK( mdevice, width, height, - false, false, true, fbDepthFormat, sampleCountToVkSampleCountFlagBits(multiSampleCnt), diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index 1c35408df..b071c1ff4 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -25,6 +25,9 @@ class GFrameBufferVLK : public IFrameBuffer { void bindFrameBuffer() override; void copyRenderBufferToTexture() override; + int getWidth() {return m_width;} + int getHeight() {return m_height;} + static void iterateOverAttachments(const std::vector &textureAttachments, std::function callback); VkFramebuffer getFrameBuffer() {return m_frameBuffer;}; diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index efce34e45..ccb867e64 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -22,6 +22,10 @@ void TextureManagerVLK::initialize() { HGSamplableTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture, bool wrapX, bool wrapY) { auto textureVlk = createBlpTexture(texture); + return createSampledTexture(wrapX, wrapY, textureVlk); +} + +HGSamplableTexture TextureManagerVLK::createSampledTexture(bool wrapX, bool wrapY, const HGTexture &textureVlk) { SampledTextureCacheRecord sampledTextureCacheRecord = { .texture = std::weak_ptr(textureVlk), .wrapX = wrapX, @@ -64,7 +68,7 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { } } - auto hgTexture = std::make_shared(static_cast(mdevice), texture, true, true, onUpdateCallback); + auto hgTexture = std::make_shared(static_cast(mdevice), texture, onUpdateCallback); std::weak_ptr weakPtr(hgTexture); { @@ -77,7 +81,7 @@ HGTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture) { } HGSamplableTexture TextureManagerVLK::createTexture(bool wrapX, bool wrapY) { - std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), true, true, onUpdateCallback); + std::shared_ptr h_texture = std::make_shared(static_cast(mdevice), onUpdateCallback); auto sampler = m_textureSamplers[((wrapX ? 1 : 0) * 2) + (wrapY ? 1 : 0)]; return std::make_shared(h_texture,sampler); diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h index 8b2703d34..47c0fc1a7 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.h @@ -19,6 +19,7 @@ class TextureManagerVLK : public std::enable_shared_from_this HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool wrapX, bool wrapY); HGSamplableTexture createTexture(bool wrapX, bool wrapY); + HGSamplableTexture createSampledTexture(bool wrapX, bool wrapY, const HGTexture &textureVlk); MutexLockedVector> getReadyToUploadTextures() { @@ -94,6 +95,7 @@ class TextureManagerVLK : public std::enable_shared_from_this std::list> m_blpTextLoadQueue; std::array, 4> m_textureSamplers; + }; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 63e138a9b..8e845312b 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -252,24 +252,8 @@ MutexLockedVector GBufferVLK::getSubmitRecords() { auto& stagingRecords = uploadRegionsPerStaging[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; for (auto &stagingRecord : stagingRecords) { auto &intervals = stagingRecord.second; - std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) -> bool { - return - a.srcOffset != b.srcOffset - ? a.srcOffset < b.srcOffset - : a.size < b.size; - }); if (!intervals.empty()) { - auto currInterval = intervals[0]; - const static auto calcIntervalEnd = [](decltype(currInterval) interval, int aligment) -> size_t { -// return aligment > 0 ? -// ((interval.srcOffset + interval.size + aligment - 1) / aligment) * aligment : -// interval.srcOffset + interval.size; - return interval.srcOffset + interval.size; - }; - - size_t currIntervalEnd = calcIntervalEnd(currInterval, m_alignment); - auto &uploadData = dataToBeUploaded.emplace_back(); uploadData.src = stagingRecord.first; uploadData.dst = m_gpuBuffer->getBuffer(); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index d96304871..48e087aac 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -54,7 +54,7 @@ class CmdBufRecorder { void bindVertexBuffers(const std::vector> &bufferVlk); inline void bindPipeline(const std::shared_ptr &pipeline); - inline void bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet); + inline void bindDescriptorSets(VkPipelineBindPoint bindPoint, const std::vector> &descriptorSets); void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h index e55d84347..b950da1d3 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h @@ -17,35 +17,46 @@ inline void CmdBufRecorder::bindPipeline(const std::shared_ptr &pi m_currentPipelineLayout = pipeline->getLayout(); } -inline void CmdBufRecorder::bindDescriptorSet(VkPipelineBindPoint bindPoint, uint32_t bindIndex, const std::shared_ptr &descriptorSet) { - { +inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, const std::vector> &descriptorSets) { + //TODO: bindpoints: VK_PIPELINE_BIND_POINT_GRAPHICS and others //Which leads to three separate states for: // VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR // Also, implement "Pipeline Layout Compatibility" thing from spec + uint32_t dynamicOffsets[16]; + uint32_t dynamicOffsetsSize = 0; + uint32_t *p_dynamicOffset; + p_dynamicOffset = &dynamicOffsets[0]; -// if (m_currentDescriptorSet[bindIndex] == descriptorSet) return; - - auto pDescriptorSet = descriptorSet.get(); + std::vector descs; + descs.reserve(descriptorSets.size()); - if (m_currentDescriptorSet[bindIndex] != pDescriptorSet) { - auto vkDescSet = pDescriptorSet->getDescSet(); - constexpr uint32_t vkDescCnt = 1; + uint32_t bindIndexStart = -1; + for (int i = 0; i < descriptorSets.size(); i++) { + auto const pDescriptorSet = descriptorSets[i].get(); + if (m_currentDescriptorSet[i] != pDescriptorSet) { + bindIndexStart = bindIndexStart==-1 ? i : bindIndexStart; - uint32_t dynamicOffsets[16]; - uint32_t dynamicOffsetsSize; - pDescriptorSet->getDynamicOffsets(dynamicOffsets, dynamicOffsetsSize); + auto vkDescSet = pDescriptorSet->getDescSet(); + descs.push_back(vkDescSet); - vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, - m_currentPipelineLayout, - bindIndex, - vkDescCnt, &vkDescSet, - dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets : nullptr); + uint32_t thisSize = 0; + pDescriptorSet->getDynamicOffsets(p_dynamicOffset, thisSize); + p_dynamicOffset+=thisSize; + dynamicOffsetsSize+=thisSize; - m_currentDescriptorSet[bindIndex] = pDescriptorSet; + m_currentDescriptorSet[i] = pDescriptorSet; } } + + if (descs.size() > 0) { + vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, + m_currentPipelineLayout, + bindIndexStart, + descs.size(), descs.data(), + dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets : nullptr); + } } #endif //AWEBWOWVIEWERCPP_COMMANDBUFFERRECORDER_INLINE_H diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index 0550a843c..a60e39481 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -13,8 +13,17 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const HGShaderPermutation &shader, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : m_shader(shader), m_pipelineTemplate(pipelineTemplate), - m_pipeline(pipeline), descriptors(descriptorSets) { - + m_pipeline(pipeline) { + for (int i = descriptorSets.size()-1; i < descriptorSets.size(); i--) { + if (descriptorSets[i] != nullptr) { + this->descriptors.resize(i+1); + + for (int j = 0; j <= i; j++) { + this->descriptors[j] = descriptorSets[j]; + } + break; + } + } } //Works under assumption that meshes do not change the renderpass, on which they are rendered, too often diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 2f19b364c..edcb8dc0b 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -25,7 +25,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this return m_shader; } - const std::array, MAX_SHADER_DESC_SETS> &getDescriptorSets() { + const std::vector> &getDescriptorSets() { return descriptors; } const HPipelineVLK &getPipeline() const { @@ -38,7 +38,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this EGxBlendEnum getBlendMode(); private: - std::array, MAX_SHADER_DESC_SETS> descriptors; + std::vector> descriptors; HGShaderPermutation m_shader; HPipelineVLK m_pipeline; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 52f10f716..e0429dff1 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -27,7 +27,7 @@ class MaterialBuilderVLK { return {device, materialVlk->getShader(), materialVlk->getPipeline(), materialVlk->getPipelineTemplate(), - materialVlk->getDescriptorSets() + toArray(materialVlk->getDescriptorSets()) }; } @@ -49,6 +49,13 @@ class MaterialBuilderVLK { ~MaterialBuilderVLK() = default; private: + static inline std::array, MAX_SHADER_DESC_SETS> toArray(const std::vector> &input) { + std::array, MAX_SHADER_DESC_SETS> res; + for (int i = 0; i < input.size(); i++) { + res[i] = input[i]; + } + return res; + } MaterialBuilderVLK(const std::shared_ptr &device, const std::vector &shaderFiles, const ShaderConfig &shaderConfig); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp index b4ce88bad..8c99dcfce 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.cpp @@ -17,9 +17,8 @@ std::atomic blpTexturesVulkanSizeLoaded = 0; GBlpTextureVLK::GBlpTextureVLK(IDeviceVulkan &device, const HBlpTexture &texture, - bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) - : GTextureVLK(device,xWrapTex,yWrapTex, onUpdateCallback), m_texture(texture) { + : GTextureVLK(device, onUpdateCallback), m_texture(texture) { std::string blpAddress_str = addrToStr(texture.get()); std::string selfAddr_str = addrToStr(this); diff --git a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h index f2fb7ec51..6212068d0 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GBlpTextureVLK.h @@ -10,7 +10,7 @@ class GBlpTextureVLK : public GTextureVLK { public: - explicit GBlpTextureVLK(IDeviceVulkan &device, const HBlpTexture &texture, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback); + explicit GBlpTextureVLK(IDeviceVulkan &device, const HBlpTexture &texture, const std::function&)> &onUpdateCallback); ~GBlpTextureVLK() override; GBlpTextureVLK(const GBlpTextureVLK&) = delete; GBlpTextureVLK(const GBlpTextureVLK&&) = delete; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index bcee73304..ef2d66b73 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -6,25 +6,18 @@ #include "GTextureVLK.h" #include "../../interface/IDevice.h" -GTextureVLK::GTextureVLK(IDeviceVulkan &device, bool xWrapTex, bool yWrapTex, const std::function&)> &onUpdateCallback) +GTextureVLK::GTextureVLK(IDeviceVulkan &device, const std::function&)> &onUpdateCallback) : m_device(device), m_onDataUpdate(onUpdateCallback), IDSBindable(false) { - this->m_wrapX = xWrapTex; - this->m_wrapY = yWrapTex; - createBuffer(); } GTextureVLK::GTextureVLK(IDeviceVulkan &device, int width, int height, - bool xWrapTex, bool yWrapTex, bool isDepthTexture, const VkFormat textureFormatGPU, VkSampleCountFlagBits numSamples, int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device), IDSBindable(false) { //For use in frameBuffer - this->m_wrapX = xWrapTex; - this->m_wrapY = yWrapTex; - m_width = width; m_height = height; @@ -62,9 +55,6 @@ GTextureVLK::~GTextureVLK() { destroyBuffer(); } -void GTextureVLK::createBuffer() { -} - void GTextureVLK::destroyBuffer() { if (!m_uploaded) return; @@ -85,13 +75,6 @@ void GTextureVLK::destroyBuffer() { }); } -void GTextureVLK::bind() { - -} - -void GTextureVLK::unbind() { -} - bool GTextureVLK::getIsLoaded() { return m_loaded; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 7137b4891..3d2e8b5f1 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -19,7 +19,6 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); + explicit GTextureVLK(IDeviceVulkan &device, const std::function&)> &onUpdateCallback); void createTexture(const HMipmapsVector &mipmaps, const VkFormat &textureFormatGPU, const std::vector &unitedBuffer); private: @@ -88,15 +87,10 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this m_tempUpdateData = nullptr; - VmaAllocation imageAllocation = VK_NULL_HANDLE; VmaAllocationInfo imageAllocationInfo = {}; @@ -109,8 +103,6 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this #include "../../engine/CameraMatrices.h" #include "../../engine/objects/iScene.h" class IRenderView { public: virtual ~IRenderView() = default; + virtual void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) = 0; + + + std::unique_ptr>::const_iterator> addOnUpdate(std::function callback) { + m_onHandleChangeList.push_back(callback); + return std::make_unique>::const_iterator>( + std::prev(m_onHandleChangeList.end()) + ); + }; + void eraseOnUpdate(std::unique_ptr>::const_iterator> &iterator) { + m_onHandleChangeList.erase(*iterator); + iterator = nullptr; + }; +protected: + void executeOnChange() { + for (auto &callBack : m_onHandleChangeList) { + callBack(); + } + } +private: + std::list> m_onHandleChangeList; }; struct MapSceneParams { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 3575650a8..865f19246 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -88,7 +88,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende } void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, - const HCameraMatrices &renderingMatrices, + const std::vector &renderingMatricess, const HFrameDependantData &fdd, bool isVulkan, animTime_t sceneTime @@ -102,11 +102,13 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrgetObject(0); + auto &blockPSVS = sceneWideChunk->getObject(i); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; if (isVulkan) { - blockPSVS.uPMatrix = vulkanMatrixFix*renderingMatrices->perspectiveMat; + blockPSVS.uPMatrix = vulkanMatrixFix * renderingMatrices->perspectiveMat; } else { blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; } @@ -120,8 +122,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorDirectColorDir, 1.0); blockPSVS.extLight.uAdtSpecMult_FogCount = mathfu::vec4(m_config->adtSpecMult, fdd->fogResults.size(), 0, 1.0); - for (int i = 0; i < std::min(fdd->fogResults.size(), FOG_MAX_SHADER_COUNT); i++) - { + for (int i = 0; i < std::min(fdd->fogResults.size(), FOG_MAX_SHADER_COUNT); i++) { auto &fogResult = fdd->fogResults[i]; auto &fogData = blockPSVS.fogData; @@ -140,7 +141,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrfogDensityIncreaser); + const float densityMultFix = 0.00050000002 * std::pow(10, m_config->fogDensityIncreaser); float fogScaler = fogResult.FogScaler; if (fogScaler <= 0.00000001f) fogScaler = 0.5f; float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; @@ -171,8 +172,8 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr 0) ? - fogResult.EndFogColorDistance : - 1000.0f + fogResult.EndFogColorDistance : + 1000.0f ); fogData.sunPercentage = mathfu::vec4( fogResult.SunFogAngle * fogResult.SunFogStrength, @@ -197,5 +198,6 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrsaveVersion(0); + sceneWideChunk->saveVersion(i); +} } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 572835df1..740cda392 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -102,12 +102,12 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, - const HCameraMatrices &renderingMatrices, + const std::vector &renderingMatrices, const HFrameDependantData &fdd, bool isVulkan, animTime_t sceneTime); - virtual std::shared_ptr createRenderView(int width, int height) = 0; + virtual std::shared_ptr createRenderView(int width, int height, bool createOutput) = 0; private: Config *m_config; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 67764f6c5..01d6f5fac 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -97,7 +97,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), true, false); - defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) @@ -537,7 +537,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { if (mesh == nullptr) return; - const auto &meshVlk = std::dynamic_pointer_cast(mesh); + const auto &meshVlk = (GMeshVLK*) mesh.get(); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); //1. Bind VBOs @@ -552,11 +552,7 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM //4. Bind Descriptor sets auto const &descSets = material->getDescriptorSets(); - for (int i = 0; i < descSets.size(); i++) { - if (descSets[i] != nullptr) { - cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); - } - } + cmdBuf.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); //5. Set view port cmdBuf.setViewPort(viewportType); @@ -584,17 +580,6 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { - auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); - if (!updatingTarget) updatingTarget = defaultView; - - updatingTarget->update( - renderTarget.viewPortDimensions.maxs[0], - renderTarget.viewPortDimensions.maxs[1], - framePlan->frameDependentData->currentGlow - ); - } - //Create meshes auto opaqueMeshes = std::make_shared>(); @@ -621,8 +606,13 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha mapScene->update(framePlan); mapScene->updateBuffers(l_this, framePlan); + std::vector renderingMatricess; + for (auto &rt : frameInputParams->frameParameters->renderTargets) { + renderingMatricess.push_back(rt.cameraMatricesForRendering); + } + updateSceneWideChunk(sceneWideChunk, - framePlan->renderingMatrices, + renderingMatricess, framePlan->frameDependentData, true, mapScene->getCurrentSceneTime()); @@ -636,11 +626,22 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha bool renderSky = framePlan->renderSky; auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; - return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes](CmdBufRecorder &uploadCmd) -> void { + return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes, frameInputParams](CmdBufRecorder &uploadCmd) -> void { { ZoneScopedN("Post Load"); //Do postLoad here. So creation of stuff is done from main thread + mapScene->doPostLoad(l_this, framePlan); + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + if (!updatingTarget) updatingTarget = l_this->defaultView; + + updatingTarget->update( + renderTarget.viewPortDimensions.maxs[0], + renderTarget.viewPortDimensions.maxs[1], + framePlan->frameDependentData->currentGlow + ); + } } { ZoneScopedN("Collect Portal Meshes"); @@ -703,34 +704,44 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // ---------------------- // Draw meshes // ---------------------- - l_this->sceneWideChunk->setCurrentVersion(0); { - auto passHelper = l_this->defaultView->beginPass(frameBufCmd, l_this->m_renderPass, + uint8_t wideChunkVersion = 0; + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + l_this->sceneWideChunk->setCurrentVersion(wideChunkVersion++); + + auto currentView = renderTarget.target == nullptr ? + l_this->defaultView : + std::dynamic_pointer_cast(renderTarget.target); + { + auto passHelper = currentView->beginPass(frameBufCmd, l_this->m_renderPass, false, frameInputParams->frameParameters->clearColor); - { - ZoneScopedN("submit opaque"); - VkZone(frameBufCmd, "render opaque") - auto const &pOpaqueMeshes = *opaqueMeshes; - auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); - for (int i = 0; i < pOpaqueMeshesSize; i++) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], CmdBufRecorder::ViewportType::vp_usual); - } - } - { - //Sky opaque - if (renderSky && skyMesh) - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); - - for (auto const &mesh: *skyOpaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); - } - } - { - //Sky transparent - for (int i = 0; i < skyTransparentMeshes->size(); i++) { - auto const &mesh = skyTransparentMeshes->at(i); + { + ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") + auto const &pOpaqueMeshes = *opaqueMeshes; + auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); + for (int i = 0; i < pOpaqueMeshesSize; i++) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], + CmdBufRecorder::ViewportType::vp_usual); + } + } + { + //Sky opaque + if (renderSky && skyMesh) + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, + CmdBufRecorder::ViewportType::vp_skyBox); + + for (auto const &mesh: *skyOpaqueMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + } + { + //Sky transparent + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); // std::string debugMess = // "Drawing mesh " @@ -741,22 +752,25 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); - } - if (renderSky && skyMesh0x4) - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); - } - { - //Render liquids - for (auto const &mesh: *liquidMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); - } - } - { - VkZone(frameBufCmd, "render transparent") - ZoneScopedN("submit transparent"); - for (int i = 0; i < transparentMeshes->size(); i++) { - auto const &mesh = transparentMeshes->at(i); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + if (renderSky && skyMesh0x4) + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh0x4, + CmdBufRecorder::ViewportType::vp_skyBox); + } + { + //Render liquids + for (auto const &mesh: *liquidMeshes) { + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } + } + { + VkZone(frameBufCmd, "render transparent") + ZoneScopedN("submit transparent"); + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); // // std::string debugMess = // "Drawing mesh " @@ -767,18 +781,21 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } + } + } + { + currentView->doPostGlow(frameBufCmd); + if (currentView == l_this->defaultView) { + currentView->doPostFinal(swapChainCmd); + } else { + currentView->doOutputPass(frameBufCmd); + } } } } - - { -// VkZone(frameBufCmd, "glowPassFrameBuf"); -// VkZone(swapChainCmd, "glowPassSwapBuf"); - - l_this->defaultView->doPostGlow(frameBufCmd); - l_this->defaultView->doPostFinal(swapChainCmd); - } }); } @@ -809,15 +826,18 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemp return mesh; } -std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int width, int height) { - return std::make_shared(m_device, uboBuffer, m_drawQuadVao); +std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int width, int height, bool createOutput) { + return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } /* * RenderViewForwardVLK */ -MapSceneRenderForwardVLK::RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO) : m_device(device) { +MapSceneRenderForwardVLK::RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, + const HGBufferVLK &uboBuffer, + const HGVertexBufferBindings &quadVAO, + bool createOutputFBO) : m_device(device), m_createOutputFBO(createOutputFBO) { glowPass = std::make_unique(m_device, uboBuffer, quadVAO); createFrameBuffers(); @@ -838,6 +858,26 @@ void MapSceneRenderForwardVLK::RenderViewForwardVLK::createFrameBuffers() { ); } } + if (m_createOutputFBO) { + auto const dataFormat = {ITextureFormat::itRGBA}; + bool invertZ = false; + + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, + VK_SAMPLE_COUNT_1_BIT, + invertZ, false); + + for (auto &outputFrameBuffer: m_outputFrameBuffers) { + outputFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itNone, + 1, + invertZ, + m_width, m_height + ); + } + } + } void MapSceneRenderForwardVLK::RenderViewForwardVLK::update(int width, int height, float glow) { @@ -855,8 +895,10 @@ void MapSceneRenderForwardVLK::RenderViewForwardVLK::update(int width, int heigh glowPass->updateDimensions(m_width, m_height, inputColorTextures, - m_device->getSwapChainRenderPass()); + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); } + + this->executeOnChange(); } glowPass->assignFFXGlowUBOConsts(glow); } @@ -874,10 +916,40 @@ RenderPassHelper MapSceneRenderForwardVLK::RenderViewForwardVLK::beginPass(CmdBu true); } +void MapSceneRenderForwardVLK::RenderViewForwardVLK::doOutputPass(CmdBufRecorder &frameBufCmd) { + auto frameBuff = m_outputFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + + glowPass->doFinalPass(frameBufCmd, frameBuff); +} + void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostGlow(CmdBufRecorder &frameBufCmd) { glowPass->doPass(frameBufCmd); } void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostFinal(CmdBufRecorder &bufCmd) { - glowPass->doFinalPass(bufCmd); + glowPass->doFinalDraw(bufCmd); +} + +void MapSceneRenderForwardVLK::RenderViewForwardVLK::iterateOverOutputTextures( + std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &, + const std::string &, ITextureFormat)> callback) { + + //1. Color output + if (m_createOutputFBO) { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> colorTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + colorTextures[i] = m_outputFrameBuffers[i]->getAttachment(0); + + callback(colorTextures, "Color Texture", ITextureFormat::itRGBA); + } + + //2. Depth buffer + { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + depthTextures[i] = m_device->createSampledTexture(m_colorFrameBuffers[i]->getDepthTexture(), false, false); + + callback(depthTextures, "Depth buffer", ITextureFormat::itDepth32); + } + } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 005d717d1..dd74b826b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -101,7 +101,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { // RenderView //-------------------------------------- - std::shared_ptr createRenderView(int width, int height) override; + std::shared_ptr createRenderView(int width, int height, bool createOutput) override; private: HGDeviceVLK m_device; @@ -150,7 +150,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: class RenderViewForwardVLK : public IRenderView { public: - RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO); + RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); ~RenderViewForwardVLK() override = default; void update(int width, int height, float glow); @@ -158,18 +158,27 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { RenderPassHelper beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + void doOutputPass(CmdBufRecorder &frameBufCmd); + void doPostGlow(CmdBufRecorder &frameBufCmd); void doPostFinal(CmdBufRecorder &bufCmd); + + void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; private: uint32_t m_width = 640; uint32_t m_height = 480; HGDeviceVLK m_device; + bool m_createOutputFBO; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; std::unique_ptr glowPass; + std::shared_ptr m_renderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; + void createFrameBuffers(); + std::vector> onUpdates; }; std::shared_ptr defaultView; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 50bf2a7c1..07b36a9e2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -118,11 +118,7 @@ void FFXGlowPassVLK::drawMaterial (CmdBufRecorder& cmdBuf, const std::shared_ptr //4. Bind Descriptor sets auto const &descSets = material->getDescriptorSets(); - for (int i = 0; i < descSets.size(); i++) { - if (descSets[i] != nullptr) { - cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); - } - } + cmdBuf.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); //7. Draw the mesh cmdBuf.drawIndexed(6, 1, 0, 0); @@ -149,7 +145,7 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd) { } } } -void FFXGlowPassVLK::doFinalPass(CmdBufRecorder &finalBufCmd) { +void FFXGlowPassVLK::doFinalDraw(CmdBufRecorder &finalBufCmd) { auto currentFrame = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; { @@ -158,6 +154,19 @@ void FFXGlowPassVLK::doFinalPass(CmdBufRecorder &finalBufCmd) { drawMaterial(finalBufCmd, ffxGlowMat[currentFrame]); } } +void FFXGlowPassVLK::doFinalPass(CmdBufRecorder &finalBufCmd, const std::shared_ptr &frameBuff) { + auto passHelper = finalBufCmd.beginRenderPass( + false, + m_renderPass, + frameBuff, + {0,0}, + {static_cast(frameBuff->getWidth()), static_cast(frameBuff->getHeight())}, + {0, 0, 0},//todo + true + ); + + doFinalDraw(finalBufCmd); +} void FFXGlowPassVLK::assignFFXGlowUBOConsts(float glow) { ZoneScoped; @@ -251,3 +260,5 @@ FFXGlowPassVLK::createFFXGlowMat( return material; } + + diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h index 9e72a2347..bc7044dc1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h @@ -22,7 +22,8 @@ class FFXGlowPassVLK { void doPass(CmdBufRecorder &frameBufCmd); - void doFinalPass(CmdBufRecorder &finalBufCmds); + void doFinalDraw(CmdBufRecorder &finalBufCmd); + void doFinalPass(CmdBufRecorder &finalBufCmd, const std::shared_ptr &frameBuff); private: static constexpr int GAUSS_PASS_COUNT = 3; From b25bb17123de69b3fff21e820d554f1b8089e43d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 30 Sep 2023 17:22:16 +0300 Subject: [PATCH 119/212] - work on lowering the memory consumption a bit --- src/ui/FrontendUI.cpp | 47 +- src/ui/FrontendUI.h | 3 +- src/ui/childWindow/BLPViewer.cpp | 2 +- src/ui/childWindow/BLPViewer.h | 2 +- .../MinimapGenerationWindow.cpp | 40 +- .../textureRenderer/DebugRendererWindow.cpp | 2 +- .../textureRenderer/DebugRendererWindow.h | 2 +- src/ui/imguiLib/imgui.cpp | 2 +- src/ui/imguiLib/imguiCustomConfig.h | 5 +- src/ui/imguiLib/imgui_widgets.cpp | 2 +- .../renderer/uiScene/FrontendUIRenderer.cpp | 7 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 1 + .../uiScene/IFrontendUIBufferCreate.h | 2 +- .../renderer/uiScene/materials/UIMaterial.h | 6 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 31 +- .../vulkan/FrontendUIRenderForwardVLK.h | 13 +- .../src/engine/shader/ShaderDefinitions.h | 1228 ++++++++--------- wowViewerLib/src/gapi/interface/IDevice.h | 3 +- .../src/gapi/interface/materials/IMaterial.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 30 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 17 +- .../gapi/vulkan/buffers/GStagingRingBuffer.h | 2 +- .../CommandBufferRecorder.cpp | 21 +- .../gapi/vulkan/synchronization/GFenceVLK.cpp | 4 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 4 + .../src/gapi/vulkan/textures/GTextureVLK.h | 1 + .../vulkan/MapSceneRenderForwardVLK.cpp | 96 +- .../vulkan/MapSceneRenderForwardVLK.h | 3 - 28 files changed, 807 insertions(+), 770 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 1d53519b3..b823a44d9 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -457,7 +457,7 @@ void FrontendUI::showAdtSelectionMinimap() { for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { if (adtSelectionMinimapMaterials[i][j] != nullptr) { - if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j], + if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j]->uniqueId, ImVec2(prevZoomedSize, prevZoomedSize))) { auto mousePos = ImGui::GetMousePos(); const ImGuiStyle &style = ImGui::GetStyle(); @@ -1414,11 +1414,13 @@ void FrontendUI::showSettingsDialog() { if (!useDoubleCameraDebug) { m_debugRenderWindow = nullptr; m_debugRenderView = nullptr; - } else if (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) { - m_debugRenderView = m_sceneRenderer->createRenderView(640, 480, true); - m_debugRenderWindow = std::make_shared(m_api, m_uiRenderer, m_debugRenderView); } } + if (useDoubleCameraDebug && (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) && m_sceneRenderer != nullptr) { + m_debugRenderView = m_sceneRenderer->createRenderView(640, 480, true); + m_debugRenderWindow = std::make_shared(m_api, m_uiRenderer, m_debugRenderView); + } + if (useDoubleCameraDebug) { if (m_api->debugCamera == nullptr) { @@ -1664,25 +1666,31 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, float nearPlane = 1.0; float fovR = toRadian(fov); - auto width = renderTargetParams[0].dimensions.maxs[0]; - auto height = renderTargetParams[0].dimensions.maxs[1]; - float canvasAspect = (float)width / (float)height; - - result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); + { + auto width = renderTargetParams[0].dimensions.maxs[0]; + auto height = renderTargetParams[0].dimensions.maxs[1]; + float canvasAspect = (float) width / (float) height; + result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, + farPlaneCulling); + } bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); - auto assignInfiniteZ = [&](auto renderTarget) { + auto assignInfiniteZ = [&](auto renderTarget, auto canvasAspect) { float f = 1.0f / tan(fovR / 2.0f); renderTarget.cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); }; for (auto &targetParam : renderTargetParams) { + auto width = targetParam.dimensions.maxs[0]; + auto height = targetParam.dimensions.maxs[1]; + float canvasAspect = (float)width / (float)height; + auto &renderTarget = result->renderTargets.emplace_back(); renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling);; renderTarget.viewPortDimensions = targetParam.dimensions; renderTarget.target = targetParam.target; - if (isInfZSupported) assignInfiniteZ(renderTarget); + if (isInfZSupported) assignInfiniteZ(renderTarget, canvasAspect); } result->clearColor = apiContainer.getConfig()->clearColor; @@ -1706,6 +1714,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do {0, 0}, {static_cast(canvWidth), static_cast(canvHeight)} }; + ViewPortDimensions debugViewDimension = dimension; if (m_sceneRenderer != nullptr) { auto wowSceneFrameInput = std::make_shared>(); @@ -1716,8 +1725,15 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do if (m_api->debugCamera && m_api->getConfig()->doubleCameraDebug && m_debugRenderView) { debugTarget = m_debugRenderView; + debugViewDimension = { + {0, 0}, + {static_cast(m_debugRenderWindow->getWidth()), + static_cast(m_debugRenderWindow->getHeight())} + }; + if (m_api->getConfig()->swapMainAndDebug) { std::swap(target, debugTarget); + std::swap(dimension, debugViewDimension); } } @@ -1729,12 +1745,6 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do } }; if (m_api->getConfig()->doubleCameraDebug) { - ViewPortDimensions debugViewDimension = { - {0, 0}, - {static_cast(m_debugRenderWindow->getWidth()), - static_cast(m_debugRenderWindow->getHeight())} - }; - auto &debugParams = renderTargetParams.emplace_back(); debugParams.camera = m_api->debugCamera; debugParams.dimensions = debugViewDimension; @@ -1994,6 +2004,7 @@ void FrontendUI::createFontTexture() { // Upload texture to graphics system // Store our identifier - io.Fonts->TexID = this->m_uiRenderer->createUIMaterial({this->m_uiRenderer->uploadFontTexture(pixels, width, height)}); + fontMat = this->m_uiRenderer->createUIMaterial({this->m_uiRenderer->uploadFontTexture(pixels, width, height)}); + io.Fonts->TexID = fontMat->uniqueId; } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 5d55f74d5..a693309ff 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -66,6 +66,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_uiRenderer; + std::shared_ptr fontMat; // HCullStage m_lastCullstage = {}; @@ -97,7 +98,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this, 64> adtSelectionMinimapTextures; - std::array, 64> adtSelectionMinimapMaterials; + std::array, 64>, 64> adtSelectionMinimapMaterials; void emptyMinimap() { for (int i = 0; i < 64; i++) { diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index 7508f6a51..1753037f0 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -46,7 +46,7 @@ bool BLPViewer::draw() { sizeX = windowSize.x; sizeY = windowSize.y; - ImGui::ImageButton(material, ImVec2(sizeX, sizeY)); + ImGui::ImageButton(material->uniqueId, ImVec2(sizeX, sizeY)); } } ImGui::End(); diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h index be2589ec6..1533530a8 100644 --- a/src/ui/childWindow/BLPViewer.h +++ b/src/ui/childWindow/BLPViewer.h @@ -22,7 +22,7 @@ class BLPViewer { HApiContainer m_api; std::shared_ptr m_uiRenderer; std::shared_ptr m_blpTexture; - HMaterial material = nullptr; + std::shared_ptr material = nullptr; }; diff --git a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp index 3ededb178..094642fb7 100644 --- a/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp +++ b/src/ui/childWindow/minimapGeneratonWindow/MinimapGenerationWindow.cpp @@ -73,26 +73,26 @@ void MinimapGenerationWindow::render() { ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0,0,0,1.0)); const int imageSize = 512; - - if (ImGui::ImageButton2(m_renderer->createUIMaterial({texture}), "previewImage", - ImVec2(imageSize, imageSize), - ImVec2(0,1), - ImVec2(1,0))) - { - auto mousePos = ImGui::GetMousePos(); - ImGuiStyle &style = ImGui::GetStyle(); - - mousePos.x += -ImGui::GetWindowPos().x - style.WindowPadding.x; - mousePos.y += -ImGui::GetWindowPos().y - style.WindowPadding.y; - - - previewX = ((0.5f - (mousePos.y / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewX; - previewY = ((0.5f - (mousePos.x / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewY; - - - - minimapGenerator->setLookAtPoint(previewX, previewY); - }; +//TODO: +// if (ImGui::ImageButton2(m_renderer->createUIMaterial({texture}), "previewImage", +// ImVec2(imageSize, imageSize), +// ImVec2(0,1), +// ImVec2(1,0))) +// { +// auto mousePos = ImGui::GetMousePos(); +// ImGuiStyle &style = ImGui::GetStyle(); +// +// mousePos.x += -ImGui::GetWindowPos().x - style.WindowPadding.x; +// mousePos.y += -ImGui::GetWindowPos().y - style.WindowPadding.y; +// +// +// previewX = ((0.5f - (mousePos.y / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewX; +// previewY = ((0.5f - (mousePos.x / (float)imageSize)) * minimapGenerator->GetOrthoDimension()) + previewY; +// +// +// +// minimapGenerator->setLookAtPoint(previewX, previewY); +// }; ImGui::PopStyleColor(3); ImGui::PopStyleVar(3); diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp index f2c7aed4f..142bfd327 100644 --- a/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp @@ -45,7 +45,7 @@ void DebugRendererWindow::draw() { if (currentSelectionIndex < m_selections.size()) { auto const ¤tMaterial = m_selections[currentSelectionIndex].materials[currentFrame]; if (currentMaterial) { - ImGui::Image(currentMaterial, {sizeX, sizeY}); + ImGui::Image(currentMaterial->uniqueId, {sizeX, sizeY}); } } } diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.h b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h index f717fb4f8..ba9b2a799 100644 --- a/src/ui/childWindow/textureRenderer/DebugRendererWindow.h +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h @@ -26,7 +26,7 @@ class DebugRendererWindow : public std::enable_shared_from_this, IDevice::MAX_FRAMES_IN_FLIGHT> materials; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> materials; }; int currentSelectionIndex = 0; diff --git a/src/ui/imguiLib/imgui.cpp b/src/ui/imguiLib/imgui.cpp index 2cbe9ce10..00db6afb2 100644 --- a/src/ui/imguiLib/imgui.cpp +++ b/src/ui/imguiLib/imgui.cpp @@ -14080,7 +14080,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, char buf[300]; ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", - pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId.get(), + pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) diff --git a/src/ui/imguiLib/imguiCustomConfig.h b/src/ui/imguiLib/imguiCustomConfig.h index 14db6cafc..dd8e3acb7 100644 --- a/src/ui/imguiLib/imguiCustomConfig.h +++ b/src/ui/imguiLib/imguiCustomConfig.h @@ -1,8 +1,11 @@ #ifndef AWEBWOWVIEWERCPP_IMGUICUSTOMCONFIG_H #define AWEBWOWVIEWERCPP_IMGUICUSTOMCONFIG_H + #include "../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" -#define ImTextureID std::shared_ptr +#include + +#define ImTextureID uint32_t diff --git a/src/ui/imguiLib/imgui_widgets.cpp b/src/ui/imguiLib/imgui_widgets.cpp index 1b6c8eb18..f4daa49e0 100644 --- a/src/ui/imguiLib/imgui_widgets.cpp +++ b/src/ui/imguiLib/imgui_widgets.cpp @@ -1089,7 +1089,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I return false; // Default to using texture ID as ID. User can still push string/integer prefixes. - PushID(user_texture_id.get()); + PushID(user_texture_id); const ImGuiID id = window->GetID("#image"); PopID(); diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp index 25c367c88..c07a64a01 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.cpp @@ -107,8 +107,11 @@ void FrontendUIRenderer::consumeFrameInput(const std::shared_ptrIdxOffset * sizeof(ImDrawIdx); meshTemplate.end = pcmd->ElemCount; - auto material = pcmd->TextureId; - meshes.push_back(this->createMesh(meshTemplate, material)); + auto material = m_materialCacheIdMap[pcmd->TextureId].lock(); + + if (material != nullptr) { + meshes.push_back(this->createMesh(meshTemplate, material)); + } } } } diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index f8be0c3a0..c7510fb25 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -45,6 +45,7 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; void consumeFrameInput(const std::shared_ptr> &frameInputParams, std::vector &meshes); diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index 9d9cb7f00..be05ef519 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -18,7 +18,7 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; - virtual HMaterial createUIMaterial(const HGSamplableTexture &hgtexture) = 0; + virtual std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/materials/UIMaterial.h b/src/ui/renderer/uiScene/materials/UIMaterial.h index d558230df..56a865bf5 100644 --- a/src/ui/renderer/uiScene/materials/UIMaterial.h +++ b/src/ui/renderer/uiScene/materials/UIMaterial.h @@ -12,7 +12,11 @@ #include "../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" #include "../../../../wowViewerLib/src/include/custom_container_key.h" +struct IUIMaterial : public IMaterial{ + uint32_t uniqueId; +}; -typedef std::unordered_map>, std::weak_ptr> UiMaterialCache; +typedef std::unordered_map>, std::weak_ptr> UiMaterialCache; +typedef std::unordered_map> UiMaterialCacheMap; #endif //AWEBWOWVIEWERCPP_IUIMATERIAL_H diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 15056bd4d..6d373471f 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -12,8 +12,8 @@ #include "../../../../../wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h" -FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer( - hDevice), m_device(hDevice) { +FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : + FrontendUIRenderer(hDevice), m_device(hDevice) { m_lastRenderPass = m_device->getSwapChainRenderPass(); m_emptyImguiVAO = createVAO(nullptr,nullptr); @@ -22,11 +22,9 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevic } void FrontendUIRenderForwardVLK::createBuffers() { - m_ringBuffer = std::make_shared(m_device); - - iboBuffer = m_device->createIndexBuffer("UI_Ibo_Buffer", 1024*1024, m_ringBuffer); - vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024, m_ringBuffer); - uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT, m_ringBuffer); + iboBuffer = m_device->createIndexBuffer("UI_Ibo_Buffer", 1024*1024); + vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024); + uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); m_imguiUbo = std::make_shared>(uboBuffer); } @@ -48,7 +46,7 @@ HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vert return imguiVAO; } -HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture &hgtexture) { +std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture &hgtexture) { auto weakTexture = std::weak_ptr(hgtexture); auto i = m_materialCache.find(weakTexture); if (i != m_materialCache.end()) { @@ -70,10 +68,13 @@ HMaterial FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture ds->beginUpdate() .texture(5, hgtexture); }) - .toMaterial(); + .toMaterial([&] (IUIMaterial *uiMat){ + uiMat->uniqueId = this->generateUniqueMatId(); + }); - std::weak_ptr weakPtr = material; + auto weakPtr = material; m_materialCache[weakTexture] = weakPtr; + m_materialCacheIdMap[material->uniqueId] = std::dynamic_pointer_cast(material); return material; } @@ -106,7 +107,6 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( // --------------------- // Upload stuff // --------------------- - l_this->m_ringBuffer->flushBuffers(); uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->vboBuffer); @@ -154,3 +154,12 @@ std::unique_ptr FrontendUIRenderForwardVLK::update( }) ); } + +uint32_t FrontendUIRenderForwardVLK::generateUniqueMatId() { + uint32_t random; + do { + random = idDistr(eng); + } while (!m_materialCacheIdMap[random].expired()); + + return random; +} diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index d0d31daad..4f1300ee2 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -7,6 +7,7 @@ #include +#include #include "../FrontendUIRenderer.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h" @@ -26,14 +27,16 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; - HMaterial createUIMaterial(const HGSamplableTexture &hgtexture) override; - + std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture) override; + uint32_t generateUniqueMatId(); private: HGDeviceVLK m_device; - //Frame counter - int m_frame = 0; + + std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator + //and seed it with entropy. + std::uniform_int_distribution idDistr; //Rendering pipelining std::mutex m_inputParamsMtx; @@ -42,8 +45,6 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboBuffer; - std::shared_ptr m_ringBuffer; - void createBuffers(); std::shared_ptr m_lastRenderPass; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index ed1f84b25..c0b684ee3 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,46 +295,20 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,0,84}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -326,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -341,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,480}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -379,24 +372,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, + {0,2,12}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -407,14 +393,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -423,17 +409,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -445,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -460,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -477,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -497,14 +492,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -512,7 +509,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -533,15 +529,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -569,15 +565,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -605,14 +601,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -625,12 +622,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -641,15 +637,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,112}, + {0,0,480}, }, { { - {2,2,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -662,12 +659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -679,24 +674,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, + {0,1,12}, }, { { - {0,0,1}, - {1,6,6}, - {5,5,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -707,17 +695,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -726,15 +710,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -762,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { @@ -835,15 +819,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -871,15 +855,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -892,10 +876,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -907,15 +893,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -943,18 +929,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,480}, - {1,1,64}, + {0,4,32}, }, { { - {0,0,1}, - {1,2,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,21 +950,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -990,15 +966,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1009,24 +985,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,15 +1004,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1056,11 +1024,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1071,16 +1040,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, - {1,1,64}, + {0,1,80}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1088,6 +1055,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -1108,16 +1076,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,4,32}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1129,14 +1098,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1146,17 +1116,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1168,21 +1137,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1192,16 +1152,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,480}, + {1,1,96}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1213,12 +1174,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,17 +1189,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1250,13 +1217,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1265,17 +1236,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,13 +1264,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1303,17 +1279,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,480}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1325,13 +1299,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1341,24 +1314,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,16}, + {1,3,4096}, {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1369,17 +1337,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1388,16 +1353,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,15 +1389,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1461,11 +1425,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {1,4,96}, {0,0,480}, }, { @@ -1484,14 +1448,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1501,16 +1463,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1537,17 +1500,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,5,96}, {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1558,13 +1528,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,16 +1547,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1593,13 +1575,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1608,16 +1591,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,32}, + {0,0,480}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1629,13 +1613,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,24 +1637,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {1,2,16}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1688,18 +1675,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1709,16 +1694,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {2,5, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1727,17 +1720,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1766,35 +1766,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 5, { - {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, + {"drawFrustumShader", { { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1825,21 +1811,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { { - 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -2293,6 +2209,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2344,23 +2286,51 @@ const std::unordered_map HMaterial; + #endif //AWEBWOWVIEWERCPP_IMATERIAL_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index c769bd7c8..b3352354d 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -364,7 +364,6 @@ void GDeviceVLK::initialize() { m_textureManager->initialize(); //--------------- - createSwapChainAndFramebuffer(); createCommandPool(); @@ -384,6 +383,7 @@ void GDeviceVLK::initialize() { unsigned int ff = 0xffffffff; m_whitePixelTexture->getTexture()->loadData(1,1,&ff, ITextureFormat::itRGBA); + m_ringBuffer = std::make_shared(shared_from_this()); } void GDeviceVLK::setObjectName(uint64_t object, VkObjectType objectType, const char *name) @@ -934,10 +934,12 @@ bool GDeviceVLK::getIsBCCompressedTexturesSupported() { float GDeviceVLK::getAnisLevel() { return deviceProperties.limits.maxSamplerAnisotropy; } +void GDeviceVLK::flushRingBuffer() { + m_ringBuffer->flushBuffers(); +} void GDeviceVLK::drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) { ZoneScoped; - this->waitInDrawStageAndDeps.beginMeasurement(); int currentDrawFrame = getProcessingFrameNumber(); @@ -983,6 +985,7 @@ void GDeviceVLK::drawFrame(const std::vector> & } } } + flushRingBuffer(); { submitQueue( uploadQueue, @@ -1058,7 +1061,6 @@ void GDeviceVLK::drawFrame(const std::vector> & } executeDeallocators(); - this->waitInDrawStageAndDeps.endMeasurement(); } RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBufRecorder &swapChainCmd) { @@ -1226,24 +1228,24 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName return sharedPtr; } -HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); +HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize, const std::shared_ptr &ringBuff) { - auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); +HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize) { + auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { - auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize) { + auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); return h_vertexBuffer; } -HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize, const std::shared_ptr &ringBuff) { - auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, ringBuff, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize) { + auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); return h_indexBuffer; } @@ -1475,10 +1477,6 @@ GDeviceVLK::createDescriptorSet(std::shared_ptr &hDescript return result; } - -void GDeviceVLK::initUploadThread() { -} - void GDeviceVLK::singleExecuteAndWait(std::function callback) { //Allocate temporary command buffer VkCommandBufferAllocateInfo allocInfo = {}; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 3f80fa242..1a35777aa 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -90,22 +90,18 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &meshes) override; bool getIsVulkanAxisSystem() override {return true;} - void initUploadThread() override; + void flushRingBuffer(); const QueueFamilyIndices &getQueueFamilyIndices() override { return indices; } public: - double getWaitForUpdate() override { - return this->waitInDrawStageAndDeps.getTimePerFrame(); - } - std::shared_ptr getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); - HGBufferVLK createUniformBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); - HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize, const std::shared_ptr &ringBuff); - HGBufferVLK createVertexBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); - HGBufferVLK createIndexBuffer(const char * objName, size_t size, const std::shared_ptr &ringBuff); + HGBufferVLK createUniformBuffer(const char * objName, size_t size); + HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize); + HGBufferVLK createVertexBuffer(const char * objName, size_t size); + HGBufferVLK createIndexBuffer(const char * objName, size_t size); HGVertexBufferBindings createVertexBufferBindings() override; HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) override; @@ -262,7 +258,6 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_ringBuffer; HGSamplableTexture m_blackPixelTexture = nullptr; HGSamplableTexture m_whitePixelTexture = nullptr; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h index 6b4ac1dd4..4a6789ca7 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -24,7 +24,7 @@ class GStagingRingBuffer { std::mutex m_mutex; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> offsets = {0,0,0}; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> offsets = {0}; struct BufferAndCPU { std::shared_ptr staging; std::array cpuBuffer; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index d5e88038c..d252effd0 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -68,11 +68,13 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( createDefaultScissors(areaOffset, areaSize); m_currentRenderPass = renderPassVlk; - return RenderPassHelper( + auto renderPass = RenderPassHelper( *this, isAboutToExecSecondaryCMD, renderPassVlk, frameBuffer, areaOffset, areaSize, colorClearColor, depthClear ); + setDefaultScissors(); + return renderPass; } @@ -307,12 +309,23 @@ void CmdBufRecorder::createViewPortTypes(const std::array &areaOffse void CmdBufRecorder::createDefaultScissors(const std::array &areaOffset, const std::array &areaSize) { - defaultScissor = {}; - defaultScissor.offset = {areaOffset[0], areaOffset[1]}; - defaultScissor.extent = { + + VkOffset2D offset2D = {areaOffset[0], areaOffset[1]}; + VkExtent2D extent2D = { static_cast(areaSize[0]), static_cast(areaSize[1]) }; + + if ( + defaultScissor.offset.x != offset2D.x || defaultScissor.offset.y != offset2D.y || + defaultScissor.extent.width != extent2D.width || defaultScissor.extent.height != extent2D.height + ) { + defaultScissor = {}; + defaultScissor.offset = offset2D; + defaultScissor.extent = extent2D; + + m_currentScissorsIsDefault = false; + } } #ifdef LINK_TRACY diff --git a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp index eea2b5609..4a3b82bd1 100644 --- a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp @@ -28,7 +28,9 @@ GFenceVLK::~GFenceVLK() { constexpr int FENCES_COUNT = 1; void GFenceVLK::wait(uint64_t maxWaitTime) { - ERR_GUARD_VULKAN(vkWaitForFences(m_device->getVkDevice(), FENCES_COUNT, &m_fence, VK_TRUE, maxWaitTime)); + auto result = vkWaitForFences(m_device->getVkDevice(), FENCES_COUNT, &m_fence, VK_TRUE, maxWaitTime); + + ERR_GUARD_VULKAN(result); } void GFenceVLK::reset() { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index ef2d66b73..35f872ddc 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -17,6 +17,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, VkSampleCountFlagBits numSamples, int vulkanMipMapCount, VkImageUsageFlags imageUsageFlags) : m_device(device), IDSBindable(false) { //For use in frameBuffer + m_isFrameBufferImage = true; m_width = width; m_height = height; @@ -220,6 +221,9 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te VmaAllocationCreateInfo allocImageCreateInfo = {}; allocImageCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; // allocImageCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; //this bit forces to create per one texture per memory + if (m_isFrameBufferImage) { + allocImageCreateInfo.flags = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT; + } vmaCreateImage(m_device.getVMAAllocator(), &imageCreateInfo, &allocImageCreateInfo, &texture.image, diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 3d2e8b5f1..5d6a6958b 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -99,6 +99,7 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this(m_device); - iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024, m_stagingRingBuffer); + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); - vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, m_stagingRingBuffer); - vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024, m_stagingRingBuffer); - vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024, m_stagingRingBuffer); - vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024, m_stagingRingBuffer); - vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, m_stagingRingBuffer); - vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, m_stagingRingBuffer); - vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, m_stagingRingBuffer); - vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024, m_stagingRingBuffer); - vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200, m_stagingRingBuffer); + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); + vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); + vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); + vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200); { const float epsilon = 0.f; @@ -64,8 +63,8 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C 0, 1, 2, 2, 1, 3 }; - m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed), m_stagingRingBuffer); - m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t), m_stagingRingBuffer); + m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); @@ -75,10 +74,10 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_drawQuadVao->save(); } - uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024, m_stagingRingBuffer); - uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024, m_stagingRingBuffer); + uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024); + uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024); - uboM2BoneMatrixBuffer = m_device->createUniformBuffer("Scene_UBO_M2BoneMats", 5000*64, m_stagingRingBuffer); + uboM2BoneMatrixBuffer = m_device->createUniformBuffer("Scene_UBO_M2BoneMats", 5000*64); m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); @@ -661,43 +660,38 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha //Needs to be executed only after lock l_this->m_lastCreatedPlan = framePlan; } + // --------------------- + // Upload stuff + // --------------------- { - ZoneScopedN("Flush Staging Buffer"); - l_this->m_stagingRingBuffer->flushBuffers(); + ZoneScopedN("submit buffers"); + VkZone(uploadCmd, "submit buffers") + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + + uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); } - - // --------------------- - // Upload stuff - // --------------------- - { - ZoneScopedN("submit buffers"); - VkZone(uploadCmd, "submit buffers") - uploadCmd.submitBufferUploads(l_this->uboBuffer); - uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); - - uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); - - uploadCmd.submitBufferUploads(l_this->vboM2Buffer); - uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); - uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); - uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); - uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); - - uploadCmd.submitBufferUploads(l_this->iboBuffer); - uploadCmd.submitBufferUploads(l_this->m_vboQuad); - uploadCmd.submitBufferUploads(l_this->m_iboQuad); - } - }, [opaqueMeshes, transparentMeshes, liquidMeshes, - skyOpaqueMeshes, skyTransparentMeshes, - renderSky, - skyMesh, - skyMesh0x4, - mapScene, framePlan, - l_this, frameInputParams](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + }, [opaqueMeshes, transparentMeshes, liquidMeshes, + skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + mapScene, framePlan, + l_this, frameInputParams](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index dd74b826b..175375538 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -144,9 +144,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; - - std::shared_ptr m_stagingRingBuffer; - private: class RenderViewForwardVLK : public IRenderView { public: From 33f67d989942857ce3aada4884f7a4309a96dc5e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 30 Sep 2023 21:12:34 +0300 Subject: [PATCH 120/212] - screenshots work --- src/minimapGenerator/minimapGenerator.cpp | 3 ++- src/screenshots/screenshotMaker.cpp | 14 +++++--------- src/screenshots/screenshotMaker.h | 5 ++--- src/ui/FrontendUI.cpp | 8 ++++++++ wowViewerLib/src/gapi/interface/IDevice.h | 8 +++++++- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp | 10 +++++++--- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 2 +- .../gapi/vulkan/synchronization/GFenceVLK.cpp | 6 ++++++ .../gapi/vulkan/synchronization/GFenceVLK.h | 3 ++- .../src/renderer/frame/SceneComposer.cpp | 18 ++++++++++-------- .../src/renderer/frame/SceneComposer.h | 6 +++--- .../src/renderer/frame/SceneScenario.h | 2 ++ .../src/renderer/mapScene/MapSceneParams.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 7 +++++++ .../mapScene/vulkan/MapSceneRenderForwardVLK.h | 1 + 16 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 6d40ffe26..6085025eb 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -837,7 +837,8 @@ void MinimapGenerator::saveDrawStageToFile(std::string folderToSave, const HFram ) + ".png"; std::vector buffer = std::vector(m_width * m_height * 4 + 1); - saveDataFromDrawStage(lastFrameBuffer, fileName, m_width, m_height, buffer); +//TODO: +// saveDataFromDrawStage(lastFrameBuffer, fileName, m_width, m_height, buffer); } void MinimapGenerator::createSceneDrawStage(HFrameScenario sceneScenario) { diff --git a/src/screenshots/screenshotMaker.cpp b/src/screenshots/screenshotMaker.cpp index 6964e2e06..a0cb4ef78 100644 --- a/src/screenshots/screenshotMaker.cpp +++ b/src/screenshots/screenshotMaker.cpp @@ -172,17 +172,14 @@ static bool endsWith3(std::string_view str, std::string_view suffix) return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix); } -void saveDataFromDrawStage(const HFrameBuffer& fb, +void saveDataFromDrawStage(std::function readRGBAPixels, const std::string& screenshotFileName, - int screenshotWidth, int screenshotHeight, - std::vector &buffer) { - if (fb == nullptr) - return; - + int screenshotWidth, int screenshotHeight) { std::vector internalBuffer = std::vector(screenshotWidth*screenshotHeight*4); - fb->readRGBAPixels( 0, 0, screenshotWidth, screenshotHeight, internalBuffer.data()); + std::vector buffer = std::vector(screenshotWidth*screenshotHeight*4+1); + readRGBAPixels( 0, 0, screenshotWidth, screenshotHeight, internalBuffer.data()); - //In internalbuffer rn image is in bgra format. Let's turn it into RGBA and make alpha 256 + //In internalbuffer rn image is in bgra format. Let's turn it into RGBA and make alpha 1.0f for (int j = 0; j < screenshotHeight; j++) { for (int i = 0; i < screenshotWidth; i++) { std::array ind = @@ -200,7 +197,6 @@ void saveDataFromDrawStage(const HFrameBuffer& fb, screenshotWidth * 4 * (j) + (i * 4) + 3, }; - auto b = internalBuffer[ind[0]]; auto g = internalBuffer[ind[1]]; auto r = internalBuffer[ind[2]]; diff --git a/src/screenshots/screenshotMaker.h b/src/screenshots/screenshotMaker.h index 7d9103f7c..0608f3540 100644 --- a/src/screenshots/screenshotMaker.h +++ b/src/screenshots/screenshotMaker.h @@ -13,8 +13,7 @@ void saveScreenshotLodePng(const std::string &name, int width, int height, std::vector &rgbaBuff); -void saveDataFromDrawStage(const HFrameBuffer& fb, +void saveDataFromDrawStage(std::function readRGBAPixels, const std::string& screenshotFileName, - int screenshotWidth, int screenshotHeight, - std::vector &buffer); + int screenshotWidth, int screenshotHeight); #endif //AWEBWOWVIEWERCPP_SCREENSHOTMAKER_H diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index b823a44d9..21ca7e9fd 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1780,7 +1780,15 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do }}, m_currentScene ); + scenario->onFinish.push_back([screenShotRenderView, this, processingFrame]() { + saveDataFromDrawStage([screenShotRenderView, processingFrame](int x, int y, int width, int height, uint8_t* data){ + screenShotRenderView->readRGBAPixels(processingFrame, x, y, width, height, data); + }, screenshotFilename, screenShotWidth, screenShotHeight); + }); needToMakeScreenshot = false; + + scenario->cullFunctions.push_back( + m_sceneRenderer->createCullUpdateRenderChain(wowSceneScreenshotFrameInput, processingFrame, updateFrameNumberLambda)); } } diff --git a/wowViewerLib/src/gapi/interface/IDevice.h b/wowViewerLib/src/gapi/interface/IDevice.h index c23a55d4d..35b11ded4 100644 --- a/wowViewerLib/src/gapi/interface/IDevice.h +++ b/wowViewerLib/src/gapi/interface/IDevice.h @@ -65,6 +65,11 @@ typedef std::shared_ptr HFrameBuffer; #include "IFrameBuffer.h" #include "../../renderer/IRenderParameters.h" +struct FrameRenderFuncs { + std::vector> renderFuncs; + std::vector> onFinish; +}; + struct M2ShaderCacheRecord { int vertexShader; int pixelShader; @@ -170,7 +175,8 @@ class IDevice { // virtual void updateBuffers(std::vector*> &bufferChunks, std::vector &frameDepedantData)= 0; virtual void uploadTextureForMeshes(std::vector &meshes) = 0; - virtual void drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) = 0; + + virtual void drawFrame(const FrameRenderFuncs &renderFuncs, bool windowSizeChanged) = 0; // virtual void drawStageAndDeps(HDrawStage drawStage) = 0; virtual bool getIsAnisFiltrationSupported(); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index b3352354d..696458565 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -938,7 +938,7 @@ void GDeviceVLK::flushRingBuffer() { m_ringBuffer->flushBuffers(); } -void GDeviceVLK::drawFrame(const std::vector> &renderFuncs, bool windowSizeChanged) { +void GDeviceVLK::drawFrame(const FrameRenderFuncs &frameRenderFuncs, bool windowSizeChanged) { ZoneScoped; int currentDrawFrame = getProcessingFrameNumber(); @@ -966,6 +966,7 @@ void GDeviceVLK::drawFrame(const std::vector> & { auto uploadCmd = uploadCmdBuf->beginRecord(nullptr); { + auto const &renderFuncs = frameRenderFuncs.renderFuncs; for (int i = 0; i < renderFuncs.size(); i++) { dynamic_cast(renderFuncs[i].get())->executeUpload(*this, uploadCmd); } @@ -1019,6 +1020,7 @@ void GDeviceVLK::drawFrame(const std::vector> & this->getNextSwapImageIndex(imageIndex); auto swapChainRenderPass = this->beginSwapChainRenderPass(imageIndex, swapChainCmd); + auto const &renderFuncs = frameRenderFuncs.renderFuncs; for (int i = 0; i < renderFuncs.size(); i++) { dynamic_cast(renderFuncs[i].get())->executeRender(*this, frameBufCmd, swapChainCmd); } @@ -1046,12 +1048,15 @@ void GDeviceVLK::drawFrame(const std::vector> & graphicsQueue, waitSemaphores, {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}, - {swapChainCmdBuf->getNativeCmdBuffer()}, signalSemaphores, inFlightFences[currentDrawFrame]->getNativeFence() ); + for (auto const &callback : frameRenderFuncs.onFinish) { + inFlightFences[currentDrawFrame]->addOnFinish(callback); + } + if (swapChain != VK_NULL_HANDLE) { presentQueue( {renderFinishedSemaphores[currentDrawFrame]->getNativeSemaphore()}, @@ -1501,7 +1506,6 @@ void GDeviceVLK::singleExecuteAndWait(std::function callb callback(copyCmd); - if (copyCmd == VK_NULL_HANDLE) { return; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 1a35777aa..cdbf049ab 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -84,7 +84,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> &renderFuncs, bool windowSizeChanged) override; + void drawFrame(const FrameRenderFuncs &renderFuncs, bool windowSizeChanged) override; void updateBuffers(/*std::vector*> &bufferChunks*/std::vector &frameDepedantData); void uploadTextureForMeshes(std::vector &meshes) override; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index f4f8fd1f7..c53565587 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -244,7 +244,7 @@ void GFrameBufferVLK::readRGBAPixels(int x, int y, int width, int height, void * } // Source for the copy is the last rendered swapchain image - VkImage srcImage = ((GTextureVLK *)(getAttachment(attachmentIndex).get()))->texture.image; + VkImage srcImage = std::dynamic_pointer_cast(getAttachment(attachmentIndex)->getTexture())->texture.image; // Create the linear tiled destination image to copy to and to read the memory from VkImageCreateInfo imageCreateCI = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; diff --git a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp index 4a3b82bd1..f3148fab1 100644 --- a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.cpp @@ -30,6 +30,12 @@ constexpr int FENCES_COUNT = 1; void GFenceVLK::wait(uint64_t maxWaitTime) { auto result = vkWaitForFences(m_device->getVkDevice(), FENCES_COUNT, &m_fence, VK_TRUE, maxWaitTime); + if (result == VK_SUCCESS) { + for (auto const &callback : onFinish) { + callback(); + } + onFinish.clear(); + } ERR_GUARD_VULKAN(result); } diff --git a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h index 353162ce8..82a7bc189 100644 --- a/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h +++ b/wowViewerLib/src/gapi/vulkan/synchronization/GFenceVLK.h @@ -16,12 +16,13 @@ class GFenceVLK { void wait(uint64_t maxWaitTime); void reset(); + void addOnFinish(const std::function& callback) {onFinish.push_back(callback);}; VkFence getNativeFence() {return m_fence;}; private: std::shared_ptr m_device; VkFence m_fence; - + std::vector> onFinish; }; diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.cpp b/wowViewerLib/src/renderer/frame/SceneComposer.cpp index 6f16d3865..08a52d8c5 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.cpp +++ b/wowViewerLib/src/renderer/frame/SceneComposer.cpp @@ -75,13 +75,14 @@ SceneComposer::SceneComposer(HApiContainer apiContainer) : m_apiContainer(apiCon continue; //Do the culling and make function for further pipeline - std::shared_ptr>> renderFuncs = std::make_shared(); + std::shared_ptr frameRenderFuncs = std::make_shared(); if (frameScenario != nullptr) { - consumeUpdate(frameScenario, *renderFuncs); + consumeUpdate(frameScenario, *frameRenderFuncs); + frameRenderFuncs->onFinish = frameScenario->onFinish; } //Pass the culling result down the pipeline - drawInput.pushInput(renderFuncs); + drawInput.pushInput(frameRenderFuncs); } })); } @@ -105,18 +106,19 @@ void SceneComposer::consumeCulling(const HFrameScenario &frameScenario) { } -void SceneComposer::consumeUpdate(const HFrameScenario &frameScenario, std::vector> &renderFunctions) { +void SceneComposer::consumeUpdate(const HFrameScenario &frameScenario, FrameRenderFuncs &frameRenderFunctions) { ZoneScoped ; if (frameScenario == nullptr) return; + auto &renderFuncs = frameRenderFunctions.renderFuncs; for (int i = 0; i < frameScenario->drawUpdateFunction.size(); i++) { - renderFunctions.push_back(std::move(frameScenario->drawUpdateFunction[i]())); + renderFuncs.push_back(std::move(frameScenario->drawUpdateFunction[i]())); } } -void SceneComposer::consumeDraw(const std::vector> &renderFuncs, bool windowSizeChanged) { +void SceneComposer::consumeDraw(const FrameRenderFuncs &renderFuncs, bool windowSizeChanged) { ZoneScoped ; m_apiContainer->hDevice->drawFrame(renderFuncs, windowSizeChanged); } @@ -133,9 +135,9 @@ void SceneComposer::draw(const HFrameScenario &frameScenario, bool windowSizeCha if (!m_supportThreads) { consumeCulling(frameScenario); - std::vector> renderFuncs = {}; + FrameRenderFuncs renderFuncs = {}; m_apiContainer->requestProcessor->processRequests(10); - consumeUpdate(frameScenario,renderFuncs); + consumeUpdate(frameScenario, renderFuncs); consumeDraw(renderFuncs, windowSizeChanged); } else { cullingInput.pushInput(frameScenario); diff --git a/wowViewerLib/src/renderer/frame/SceneComposer.h b/wowViewerLib/src/renderer/frame/SceneComposer.h index d8927f0aa..d30b62c00 100644 --- a/wowViewerLib/src/renderer/frame/SceneComposer.h +++ b/wowViewerLib/src/renderer/frame/SceneComposer.h @@ -28,8 +28,8 @@ class SceneComposer { bool m_firstFrame = true; void consumeCulling(const HFrameScenario &frameScenario); - void consumeUpdate(const HFrameScenario &frameScenario, std::vector> &renderFunctions); - void consumeDraw(const std::vector> &renderFuncs, bool windowSizeChanged); + void consumeUpdate(const HFrameScenario &frameScenario, FrameRenderFuncs &frameRenderFunctions); + void consumeDraw(const FrameRenderFuncs &renderFuncs, bool windowSizeChanged); //Flip-flop delta promises int frameMod = 0; @@ -37,7 +37,7 @@ class SceneComposer { ProdConsumerIOConnector cullingInput = {m_isTerminating}; ProdConsumerIOConnector updateInput = {m_isTerminating}; - ProdConsumerIOConnector>>> drawInput = {m_isTerminating}; + ProdConsumerIOConnector> drawInput = {m_isTerminating}; public: SceneComposer(HApiContainer apiContainer); ~SceneComposer() { diff --git a/wowViewerLib/src/renderer/frame/SceneScenario.h b/wowViewerLib/src/renderer/frame/SceneScenario.h index 2a640a976..1382ffe9f 100644 --- a/wowViewerLib/src/renderer/frame/SceneScenario.h +++ b/wowViewerLib/src/renderer/frame/SceneScenario.h @@ -41,6 +41,8 @@ class FrameScenarioBuilder { struct FrameScenario { std::vector cullFunctions; std::vector drawUpdateFunction; + + std::vector> onFinish; }; typedef std::shared_ptr HFrameScenario; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h index 0303e8905..8f93124e4 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneParams.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneParams.h @@ -13,7 +13,7 @@ class IRenderView { public: virtual ~IRenderView() = default; virtual void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) = 0; - + virtual void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata) = 0; std::unique_ptr>::const_iterator> addOnUpdate(std::function callback) { m_onHandleChangeList.push_back(callback); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 52d17e281..ab3ecf6c0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -947,3 +947,10 @@ void MapSceneRenderForwardVLK::RenderViewForwardVLK::iterateOverOutputTextures( } } + +void +MapSceneRenderForwardVLK::RenderViewForwardVLK::readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata) { + if (m_createOutputFBO) { + m_outputFrameBuffers[frameNumber % IDevice::MAX_FRAMES_IN_FLIGHT]->readRGBAPixels(x,y,width,height,outputdata); + } +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 175375538..714f698d5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -161,6 +161,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { void doPostFinal(CmdBufRecorder &bufCmd); void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; + void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata); private: uint32_t m_width = 640; uint32_t m_height = 480; From 765fe71fcc7f89393c7fed19fda1851a25716a26 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 30 Sep 2023 23:17:53 +0300 Subject: [PATCH 121/212] - more smooth world loading when using HDD --- .../frame/prodConsumerChain/ProdConsumerIOConnector.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h index 8a5c19d28..e4f0c5466 100644 --- a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h +++ b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h @@ -42,9 +42,13 @@ class ProdConsumerIOConnector { void blockProcessWithoutWait(int limit, const std::function &callback) { ZoneScoped; int processed; + std::unique_lock lock{m_queueMutex, std::defer_lock}; while ((processed < limit) && (!m_queue.empty())) { + lock.lock(); auto result = std::move(m_queue.front()); m_queue.pop(); + lock.unlock(); + callback(result); processed++; } @@ -60,10 +64,10 @@ class ProdConsumerIOConnector { { return !l_queue.empty() || l_terminated; }); + lock.unlock(); } blockProcessWithoutWait(INT_MAX, callback); - lock.unlock(); }; bool empty() {return m_queue.empty(); } From e71c69bafb095fba88518a4b1c8feec0af02aaf3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 1 Oct 2023 20:55:54 +0300 Subject: [PATCH 122/212] - restore gpu tracing in tracy --- src/ui/FrontendUI.cpp | 3 ++- .../src/engine/objects/adt/adtObject.cpp | 13 +++++++++-- .../src/engine/objects/scenes/map.cpp | 23 +++++++++++-------- .../vulkan/commandBuffer/CommandBuffer.cpp | 18 +++++++-------- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 21ca7e9fd..6856b1c11 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -457,7 +457,8 @@ void FrontendUI::showAdtSelectionMinimap() { for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { if (adtSelectionMinimapMaterials[i][j] != nullptr) { - if (ImGui::ImageButton(adtSelectionMinimapMaterials[i][j]->uniqueId, + if (ImGui::ImageButton(std::to_string(i*64+j).c_str(), + adtSelectionMinimapMaterials[i][j]->uniqueId, ImVec2(prevZoomedSize, prevZoomedSize))) { auto mousePos = ImGui::GetMousePos(); const ImGuiStyle &style = ImGui::GetStyle(); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index e87ee10bd..971d3c8e8 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -15,9 +15,10 @@ #include "tbb/parallel_for.h" #include "tbb/blocked_range2d.h" #include "../../../gapi/interface/materials/IMaterial.h" - +#include "../../../renderer/frame/FrameProfile.h" void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; // std::cout << "AdtObject::loadingFinished finished called"; // texturesPerMCNK = std::vector(m_adtFile->mcnkRead+1); @@ -39,6 +40,7 @@ void AdtObject::loadingFinished(const HMapSceneBufferCreate &sceneRenderer) { } void AdtObject::loadM2s() { + ZoneScoped; uint32_t offset = 0; int32_t length = m_adtFileObj->doodadDef_len; //1. Load non-lod @@ -81,6 +83,8 @@ void AdtObject::loadM2s() { } } void AdtObject::loadWmos() { + ZoneScoped; + uint32_t offset = 0; int32_t length = m_adtFileObj->mapObjDef_len; @@ -127,6 +131,7 @@ void AdtObject::loadWmos() { } void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { + ZoneScoped; if (m_adtFile->mH2OHeader == nullptr) return; m_waterPlacementChunk = sceneRenderer->createWMOWideChunk(); @@ -176,7 +181,7 @@ void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { /* 1. help index + Heights + texCoords + */ - + ZoneScoped; std::vector vboArray ; //DEBUG @@ -335,6 +340,7 @@ void AdtObject::calcBoundingBoxes() { } void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; HGDevice device = m_api->hDevice; auto adtFileTex = m_adtFileTex; @@ -469,6 +475,7 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } void AdtObject::loadAlphaTextures() { + ZoneScoped; int chunkCount = m_adtFileTex->mcnkRead+1; int maxAlphaTexPerChunk = 4; int alphaTexSize = 64; @@ -1199,6 +1206,8 @@ int AdtObject::getAreaId(int mcnk_x, int mcnk_y) { } void AdtObject::createIBOAndBinding(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; + auto const &strips = !m_api->getConfig()->ignoreADTHoles ? m_adtFile->strips : m_adtFile->stripsNoHoles; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index c40c75709..3aad689e1 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1496,9 +1496,9 @@ void Map::update(const HMapRenderPlan &renderPlan) { } } - //2. Calc distance every 100 ms { + ZoneScopedN("Calc m2 distance"); oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); arena.execute([&] { tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), @@ -1514,20 +1514,23 @@ void Map::update(const HMapRenderPlan &renderPlan) { } //Cleanup ADT every 10 seconds - if (adtFreeLambda!= nullptr && adtFreeLambda(true, false, this->m_currentTime)) { - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - auto adtObj = mapTiles[i][j]; - //Free obj, if it was unused for 10 secs - if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { + { + ZoneScopedN("Cleanup ADT"); + if (adtFreeLambda != nullptr && adtFreeLambda(true, false, this->m_currentTime)) { + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + auto adtObj = mapTiles[i][j]; + //Free obj, if it was unused for 10 secs + if (adtObj != nullptr && adtObj->getFreeStrategy()(true, false, this->m_currentTime)) { // std::cout << "try to free adtObj" << std::endl; - mapTiles[i][j] = nullptr; + mapTiles[i][j] = nullptr; + } } } - } - adtFreeLambda(false, true, this->m_currentTime + deltaTime); + adtFreeLambda(false, true, this->m_currentTime + deltaTime); + } } this->m_currentTime += deltaTime; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index a21b4a3a8..431f56166 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -33,19 +33,19 @@ CmdBufRecorder GCommandBuffer::beginRecord(const std::shared_ptr void GCommandBuffer::createCommandBufVLK() { if (m_cmdBufWasCreated) { // //Dispose of previous buffer -// auto l_cmdBuf = m_cmdBuffer; // // auto l_deviceVlk = m_device.getVkDevice(); // auto l_commandPool = m_commandPool; -// auto l_tracyContext = tracyContext; // -// m_device.addDeallocationRecord([l_cmdBuf, l_deviceVlk, l_tracyContext, l_commandPool]() -> void { -//#ifdef LINK_TRACY -// TracyVkCollect(l_tracyContext, l_cmdBuf); -//#endif -// vkFreeCommandBuffers(l_deviceVlk, l_commandPool, 1, &l_cmdBuf); -// }); + + auto l_cmdBuf = m_cmdBuffer; + auto l_tracyContext = tracyContext; + +#ifdef LINK_TRACY + TracyVkCollect(l_tracyContext, l_cmdBuf); +#endif vkResetCommandBuffer(m_cmdBuffer, 0); + } else { VkCommandBufferAllocateInfo allocInfo = {}; @@ -62,7 +62,7 @@ void GCommandBuffer::createCommandBufVLK() { if (!m_cmdBufWasCreated) { #ifdef LINK_TRACY tracyContext = TracyVkContext(m_device.getVkPhysicalDevice(), m_device.getVkDevice(), m_vkQueue, m_cmdBuffer); -#endif LINK_TRACY +#endif } m_cmdBufWasCreated = true; } From c4339e316bd5a9755cba559f2175df7a9b14203a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 4 Oct 2023 14:29:57 +0300 Subject: [PATCH 123/212] fixes for ubuntu --- src/main.cpp | 7 +- src/ui/FrontendUI.cpp | 4 +- src/ui/renderer/uiScene/ImGUIPlan.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1158 +++++++---------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 23 +- .../vulkan/buffers/GStagingRingBuffer.cpp | 39 +- .../gapi/vulkan/buffers/GStagingRingBuffer.h | 2 +- .../ProdConsumerIOConnector.h | 2 +- 8 files changed, 539 insertions(+), 698 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c0fecaf59..d4681a148 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -454,8 +454,9 @@ int main(){ frontendUI->setUIScale(uiScale); // auto native_me = std::this_thread::get_id().native_handle(); +#if WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); - +#endif //This has to be called after setting all callbacks specific to this app. //ImGUI takes care of previous callbacks and calls them before applying it's own logic over data //Otherwise keys like backspace, delete etc wont work @@ -501,11 +502,11 @@ int main(){ sceneComposer.draw(sceneScenario, windowSizeChanged); windowSizeChanged = false; - double currentDeltaAfterDraw = (glfwGetTime() - lastFrame)*(1000.0f); + double currentDeltaAfterDraw = (glfwGetTime() - currentFrame)*(1000.0f); lastFrame = currentFrame; if (currentDeltaAfterDraw < 5.0) { using namespace std::chrono_literals; - std::this_thread::sleep_for(std::chrono::milliseconds((int)(1.0))); + std::this_thread::sleep_for(std::chrono::milliseconds((int)(4.0))); } if (rendererName == "ogl3" || rendererName == "ogl2") { diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 6856b1c11..ef2436588 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -816,7 +816,9 @@ void FrontendUI::initImgui( std::string s = std::string(&lastCascDir[0]); // std::cout << " read string s = " << s << std::endl; - fileDialog.SetPwd(s); + if (ghc::filesystem::exists(s)) { + fileDialog.SetPwd(s); + } } int lastWidth = 0; if (sscanf(line, "windowWidth=%d", &lastWidth) == 1) { diff --git a/src/ui/renderer/uiScene/ImGUIPlan.h b/src/ui/renderer/uiScene/ImGUIPlan.h index 00e788552..fdd7aa37d 100644 --- a/src/ui/renderer/uiScene/ImGUIPlan.h +++ b/src/ui/renderer/uiScene/ImGUIPlan.h @@ -33,7 +33,7 @@ namespace ImGuiFramePlan { m_imData.CmdLists[i]->~ImDrawList(); IM_FREE(m_imData.CmdLists[i]); } - delete m_imData.CmdLists; + delete[] m_imData.CmdLists; } } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index c0b684ee3..1ae8d983a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,19 +276,40 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {1,3,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -319,12 +321,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +336,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,17 +374,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -393,14 +399,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {3,9, "uBumpTexture"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,18 +415,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,21 +437,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +452,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,96}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +469,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,16 +489,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,64}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -509,6 +504,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -529,15 +525,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -565,15 +561,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -601,15 +597,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,11 +617,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -637,16 +633,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,480}, + {0,2,168}, }, { { - {0,1,2}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -659,10 +654,11 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -674,17 +670,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {2,5,96}, + {0,0,480}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -695,13 +692,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -710,15 +711,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,1,112}, + {0,0,480}, }, { { @@ -819,15 +819,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -855,15 +854,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -876,12 +875,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -893,15 +890,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,0,144}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,16 +926,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,2,48}, + {0,0,480}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,13 +949,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,15 +973,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,0,480}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -985,17 +992,23 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,14 +1017,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,12 +1038,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,15 +1053,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1076,17 +1089,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,0,84}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1110,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,16 +1125,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1137,12 +1147,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,17 +1171,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,4,32}, }, { { - {0,0,1}, - {1,1,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,11 +1192,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1189,24 +1208,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,2,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,17 +1229,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,24 +1244,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,4,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1264,11 +1265,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1279,15 +1282,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,96}, + {0,0,480}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1299,12 +1304,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1314,19 +1320,23 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,480}, + {1,1,64}, + {1,6,4096}, }, { { {0,0,1}, - {3,4,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1337,14 +1347,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,15 +1366,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,15 +1403,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1425,11 +1439,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, + {1,4,32}, {0,0,480}, }, { @@ -1448,12 +1462,14 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1463,17 +1479,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1500,24 +1515,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { - {0,0,1}, - {1,6,6}, - {5,5,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1528,17 +1535,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1547,24 +1550,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1575,14 +1570,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1591,17 +1585,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, - {4,4,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1613,21 +1606,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1637,18 +1622,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,16}, }, { { {0,0,1}, - {1,2,2}, + {1,3,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1675,16 +1660,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1694,24 +1680,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1720,24 +1698,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1766,21 +1737,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1811,6 +1771,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2250,27 +2182,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_2_5_values0", true, 0, 1, 4, 0}, + {"_2_5_values1", true, 16, 1, 4, 0}, + {"_2_5_values2", true, 32, 1, 4, 0}, + {"_2_5_values3", true, 48, 1, 4, 0}, + {"_2_5_values4", true, 64, 1, 4, 0}, + {"_2_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -2286,51 +2204,23 @@ const std::unordered_map swapChainSupport.capabilities.maxImageCount && (swapChainSupport.capabilities.maxImageCount != 0)) - || (imageCount < swapChainSupport.capabilities.minImageCount)) { - std::cerr << "Your GPU doesnt support " << MAX_FRAMES_IN_FLIGHT << " images for swapchain, which is required by this application" << std::endl << std::flush; - throw new std::runtime_error("Boo!"); + if (swapChainSupport.capabilities.minImageCount < 2) { + std::cerr << "Your GPU doesnt support 2 swapchain images inFlight, which is required by app" << std::endl << std::flush; } + imageCount = swapChainSupport.capabilities.minImageCount; + + + // if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { // imageCount = swapChainSupport.capabilities.maxImageCount; // } @@ -683,6 +685,11 @@ void GDeviceVLK::pickPhysicalDevice() { for (const auto& device : devices) { if (isDeviceSuitable(device)) { physicalDevice = device; + + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(device, &props); + std::cout << "Selected " << props.deviceName << " -- " << (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ? "suitable GPU" : "integrated GPU") << std::endl; + break; } } @@ -986,7 +993,9 @@ void GDeviceVLK::drawFrame(const FrameRenderFuncs &frameRenderFuncs, bool window } } } - flushRingBuffer(); + if (!frameRenderFuncs.renderFuncs.empty()) { + flushRingBuffer(); + } { submitQueue( uploadQueue, @@ -1104,10 +1113,6 @@ void GDeviceVLK::getNextSwapImageIndex(uint32_t &imageIndex) { // throw std::runtime_error("failed to acquire swap chain image!"); } - if (imageIndex >= inFlightFences.size()) { - std::cout << "imageIndex >= inFlightFences.size()" << std::endl; - } - // std::cout << "imageIndex = " << imageIndex << " currentDrawFrame = " << currentDrawFrame << std::endl << std::flush; if (((imageIndex+1)&3) != currentDrawFrame) { diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index 850ff9ef3..4bc45149a 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -12,6 +12,9 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of int bufferIndex = 0; auto ¤tOffset = offsets[frame]; + //Add alignment + size += 16; + if (size > STAGE_BUFFER_SIZE) throw std::runtime_error(("size > STAGE_BUFFER_SIZE; size = " + std::to_string(size))); @@ -26,9 +29,12 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of currentIndexAfter = (offset + size) / STAGE_BUFFER_SIZE; if (currentIndexAfter >= vec.size()) { - std::unique_lock l(m_mutex); + std::unique_lock l(m_mutex);// + while (currentIndexAfter >= vec.size()) { - vec.emplace_back().staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); + auto &bufferAndCPU = vec.emplace_back(); + bufferAndCPU = std::make_shared(); + bufferAndCPU->staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); } } @@ -36,13 +42,28 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of bufferIndex = currentIndex; startOffset = offset % STAGE_BUFFER_SIZE; + if (bufferIndex >= vec.size()) { + throw "OOOOSP"; + } + auto &bufferAndCPU = vec[bufferIndex]; + auto buffPtr = reinterpret_cast(bufferAndCPU->cpuBuffer.data()); + + uint32_t buffPtrAlign = buffPtr % 16; + uint32_t offsetAlign = startOffset % 16; + uint32_t alignAdd = 0; + if (buffPtrAlign > offsetAlign) { + alignAdd = (16-buffPtrAlign) + (buffPtrAlign - offsetAlign); + } else { + alignAdd = (16-buffPtrAlign) + ((16 - offsetAlign) + buffPtrAlign); + } + alignAdd %= 16; + startOffset += alignAdd; - auto &staging = vec[bufferIndex]; - auto allocatedPtr = ((uint8_t *)staging.cpuBuffer.data()) + startOffset; - if ((startOffset + size) > staging.cpuBuffer.size()) { - size++; + auto allocatedPtr = ((uint8_t *)bufferAndCPU->cpuBuffer.data()) + startOffset; + if ((startOffset + size) > bufferAndCPU->cpuBuffer.size()) { + throw "OOOOSP"; } - o_staging = staging.staging->getBuffer(); + o_staging = bufferAndCPU->staging->getBuffer(); o_offset = startOffset; return allocatedPtr; @@ -58,11 +79,11 @@ void GStagingRingBuffer::flushBuffers() { for (int i = 0; i < maxIndex; i++) { auto &stagingRec = vec[i]; - memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), STAGE_BUFFER_SIZE); + memcpy(stagingRec->staging->getPointer(), stagingRec->cpuBuffer.data(), STAGE_BUFFER_SIZE); } if (currentOffset > 0) { auto &stagingRec = vec[maxIndex]; - memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); + memcpy(stagingRec->staging->getPointer(), stagingRec->cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); } uint32_t prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h index 4a6789ca7..b34c7d344 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -30,7 +30,7 @@ class GStagingRingBuffer { std::array cpuBuffer; }; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_stagingBuffers; + std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> m_stagingBuffers; }; diff --git a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h index e4f0c5466..62aed5529 100644 --- a/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h +++ b/wowViewerLib/src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h @@ -41,7 +41,7 @@ class ProdConsumerIOConnector { void blockProcessWithoutWait(int limit, const std::function &callback) { ZoneScoped; - int processed; + int processed = 0; std::unique_lock lock{m_queueMutex, std::defer_lock}; while ((processed < limit) && (!m_queue.empty())) { lock.lock(); From 99cc3e0e7fbc4ab55c512bb1371a2c07f2e9e92b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 4 Oct 2023 19:31:13 +0300 Subject: [PATCH 124/212] - add sqlite_orm --- 3rdparty/sqlite_orm/sqlite_orm.h | 17224 ++++++++++++++++ src/main.cpp | 2 +- .../src/engine/objects/adt/adtObject.cpp | 96 +- .../src/engine/objects/adt/adtObject.h | 9 + 4 files changed, 17299 insertions(+), 32 deletions(-) create mode 100644 3rdparty/sqlite_orm/sqlite_orm.h diff --git a/3rdparty/sqlite_orm/sqlite_orm.h b/3rdparty/sqlite_orm/sqlite_orm.h new file mode 100644 index 000000000..76f1d0809 --- /dev/null +++ b/3rdparty/sqlite_orm/sqlite_orm.h @@ -0,0 +1,17224 @@ +#pragma once + +#if defined(_MSC_VER) +#if defined(min) +__pragma(push_macro("min")) +#undef min +#define __RESTORE_MIN__ +#endif +#if defined(max) + __pragma(push_macro("max")) +#undef max +#define __RESTORE_MAX__ +#endif +#endif // defined(_MSC_VER) + +#include // due to #166 + +#if __cplusplus >= 201703L // use of C++17 or higher +// Enables use of std::optional in SQLITE_ORM. +#define SQLITE_ORM_OPTIONAL_SUPPORTED +#define SQLITE_ORM_STRING_VIEW_SUPPORTED +#define SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED +#endif +#pragma once + +#include // std::error_code, std::system_error +#include // std::string +#include +#include +#include // std::ostringstream + + namespace sqlite_orm { + + enum class orm_error_code { + not_found = 1, + type_is_not_mapped_to_storage, + trying_to_dereference_null_iterator, + too_many_tables_specified, + incorrect_set_fields_specified, + column_not_found, + table_has_no_primary_key_column, + cannot_start_a_transaction_within_a_transaction, + no_active_transaction, + incorrect_journal_mode_string, + invalid_collate_argument_enum, + failed_to_init_a_backup, + unknown_member_value, + incorrect_order, + cannot_use_default_value, + arguments_count_does_not_match, + function_not_found, + index_is_out_of_bounds, + }; +} + +namespace sqlite_orm { + + class orm_error_category : public std::error_category { + public: + const char* name() const noexcept override final { + return "ORM error"; + } + + std::string message(int c) const override final { + switch(static_cast(c)) { + case orm_error_code::not_found: + return "Not found"; + case orm_error_code::type_is_not_mapped_to_storage: + return "Type is not mapped to storage"; + case orm_error_code::trying_to_dereference_null_iterator: + return "Trying to dereference null iterator"; + case orm_error_code::too_many_tables_specified: + return "Too many tables specified"; + case orm_error_code::incorrect_set_fields_specified: + return "Incorrect set fields specified"; + case orm_error_code::column_not_found: + return "Column not found"; + case orm_error_code::table_has_no_primary_key_column: + return "Table has no primary key column"; + case orm_error_code::cannot_start_a_transaction_within_a_transaction: + return "Cannot start a transaction within a transaction"; + case orm_error_code::no_active_transaction: + return "No active transaction"; + case orm_error_code::invalid_collate_argument_enum: + return "Invalid collate_argument enum"; + case orm_error_code::failed_to_init_a_backup: + return "Failed to init a backup"; + case orm_error_code::unknown_member_value: + return "Unknown member value"; + case orm_error_code::incorrect_order: + return "Incorrect order"; + case orm_error_code::cannot_use_default_value: + return "The statement 'INSERT INTO * DEFAULT VALUES' can be used with only one row"; + case orm_error_code::arguments_count_does_not_match: + return "Arguments count does not match"; + case orm_error_code::function_not_found: + return "Function not found"; + case orm_error_code::index_is_out_of_bounds: + return "Index is out of bounds"; + default: + return "unknown error"; + } + } + }; + + class sqlite_error_category : public std::error_category { + public: + const char* name() const noexcept override final { + return "SQLite error"; + } + + std::string message(int c) const override final { + return sqlite3_errstr(c); + } + }; + + inline const orm_error_category& get_orm_error_category() { + static orm_error_category res; + return res; + } + + inline const sqlite_error_category& get_sqlite_error_category() { + static sqlite_error_category res; + return res; + } + + template + std::string get_error_message(sqlite3* db, T&&... args) { + std::ostringstream stream; + using unpack = int[]; + static_cast(unpack{0, (static_cast(static_cast(stream << args)), 0)...}); + stream << sqlite3_errmsg(db); + return stream.str(); + } + + template + [[noreturn]] void throw_error(sqlite3* db, T&&... args) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + get_error_message(db, std::forward(args)...)); + } +} + +namespace std { + template<> + struct is_error_code_enum : std::true_type {}; + + inline std::error_code make_error_code(sqlite_orm::orm_error_code errorCode) { + return std::error_code(static_cast(errorCode), sqlite_orm::get_orm_error_category()); + } +} +#pragma once + +#include // std::tuple, std::get, std::tuple_element, std::tuple_size +#include // std::false_type, std::true_type + +// #include "static_magic.h" + +#include // std::false_type, std::true_type, std::integral_constant + +namespace sqlite_orm { + + // got from here + // https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co + namespace internal { + + static inline decltype(auto) empty_callable() { + static auto res = [](auto&&...) {}; + return (res); + } + + template + decltype(auto) static_if(std::true_type, const T& t, const F&) { + return (t); + } + + template + decltype(auto) static_if(std::false_type, const T&, const F& f) { + return (f); + } + + template + decltype(auto) static_if(const T& t, const F& f) { + return static_if(std::integral_constant{}, t, f); + } + + template + decltype(auto) static_if(const T& t) { + return static_if(std::integral_constant{}, t, empty_callable()); + } + + template + using static_not = std::integral_constant; + } + +} + +namespace sqlite_orm { + + // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type + namespace tuple_helper { + /** + * HAS_TYPE type trait + */ + template + struct has_type; + + template + struct has_type> : std::false_type {}; + + template + struct has_type> : has_type> {}; + + template + struct has_type> : std::true_type {}; + + template + using tuple_contains_type = typename has_type::type; + + /** + * HAS_SOME_TYPE type trait + */ + template class TT, typename Tuple> + struct has_some_type; + + template class TT> + struct has_some_type> : std::false_type {}; + + template class TT, typename U, typename... Ts> + struct has_some_type> : has_some_type> {}; + + template class TT, typename T, typename... Ts> + struct has_some_type, Ts...>> : std::true_type {}; + + template class TT, typename Tuple> + using tuple_contains_some_type = typename has_some_type::type; + + template + struct iterator_impl { + + template + void operator()(const std::tuple& tuple, const L& lambda, bool reverse = true) { + if(reverse) { + lambda(std::get(tuple)); + iterator_impl()(tuple, lambda, reverse); + } else { + iterator_impl()(tuple, lambda, reverse); + lambda(std::get(tuple)); + } + } + + template + void operator()(const L& lambda) { + iterator_impl()(lambda); + lambda((const typename std::tuple_element>::type*)nullptr); + } + }; + + template + struct iterator_impl<0, Args...> { + + template + void operator()(const std::tuple& tuple, const L& lambda, bool /*reverse*/ = true) { + lambda(std::get<0>(tuple)); + } + + template + void operator()(const L& lambda) { + lambda((const typename std::tuple_element<0, std::tuple>::type*)nullptr); + } + }; + + template + struct iterator_impl { + + template + void operator()(const std::tuple<>&, const L&, bool /*reverse*/ = true) { + //.. + } + + template + void operator()(const L&) { + //.. + } + }; + + template + struct iterator_impl2; + + template<> + struct iterator_impl2<> { + + template + void operator()(const L&) const { + //.. + } + }; + + template + struct iterator_impl2 { + + template + void operator()(const L& lambda) const { + lambda((const H*)nullptr); + iterator_impl2{}(lambda); + } + }; + + template + struct iterator; + + template + struct iterator> { + + template + void operator()(const L& lambda) const { + iterator_impl2{}(lambda); + } + }; + } + + namespace internal { + + // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer + template + auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { + return (f.*functionPointer)(std::get(t)...); + } + + template + auto call(Function& f, FunctionPointer functionPointer, Tuple t) { + static constexpr auto size = std::tuple_size::value; + return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); + } + + template + auto call(Function& f, Tuple t) { + return call(f, &Function::operator(), move(t)); + } + + template + void move_tuple_impl(L& lhs, R& rhs) { + std::get(lhs) = std::move(std::get(rhs)); + internal::static_if{}>([](auto& l, auto& r) { + move_tuple_impl(l, r); + })(lhs, rhs); + } + + template + void move_tuple(L& lhs, R& rhs) { + using bool_type = std::integral_constant; + static_if([](auto& l, auto& r) { + move_tuple_impl(l, r); + })(lhs, rhs); + } + + template + void iterate_tuple(const std::tuple& tuple, const L& lambda) { + using tuple_type = std::tuple; + tuple_helper::iterator_impl::value - 1, Args...>()(tuple, lambda, false); + } + + template + void iterate_tuple(const L& lambda) { + tuple_helper::iterator{}(lambda); + } + + template + using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); + + template + struct conc_tuple { + using type = tuple_cat_t; + }; + } +} +#pragma once + +#include // std::tuple +#include // std::enable_if + +namespace sqlite_orm { + namespace internal { + + template class C, class SFINAE = void> + struct find_in_tuple; + + template class C> + struct find_in_tuple, C, void> { + using type = void; + }; + + template class C> + struct find_in_tuple, C, typename std::enable_if::value>::type> { + using type = H; + }; + + template class C> + struct find_in_tuple, C, typename std::enable_if::value>::type> { + using type = typename find_in_tuple, C>::type; + }; + } +} +#pragma once + +#include // std::tuple + +namespace sqlite_orm { + namespace internal { + + template class F> + struct tuple_transformer; + + template class F> + struct tuple_transformer, F> { + using type = std::tuple::type...>; + }; + } +} +#pragma once + +#include // std::tuple + +namespace sqlite_orm { + namespace internal { + + template class C> + struct count_tuple; + + template class C> + struct count_tuple, C> { + static constexpr const int value = 0; + }; + + template class C> + struct count_tuple, C> { + static constexpr const int value = C::value + count_tuple, C>::value; + }; + } +} +#pragma once + +namespace sqlite_orm { + namespace internal { + + /** + * Accepts any number of arguments and evaluates `type` alias as T if all arguments are the same or void otherwise + */ + template + struct same_or_void { + using type = void; + }; + + template + struct same_or_void { + using type = A; + }; + + template + struct same_or_void { + using type = void; + }; + + template + struct same_or_void { + using type = A; + }; + + template + struct same_or_void { + using type = typename same_or_void::type; + }; + + } +} +#pragma once + +#include // std::string +#include // std::shared_ptr, std::unique_ptr +#include // std::vector +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +namespace sqlite_orm { + + /** + * This class accepts c++ type and transfers it to sqlite name (int -> INTEGER, std::string -> TEXT) + */ + template + struct type_printer; + + struct integer_printer { + inline const std::string& print() { + static const std::string res = "INTEGER"; + return res; + } + }; + + struct text_printer { + inline const std::string& print() { + static const std::string res = "TEXT"; + return res; + } + }; + + struct real_printer { + inline const std::string& print() { + static const std::string res = "REAL"; + return res; + } + }; + + struct blob_printer { + inline const std::string& print() { + static const std::string res = "BLOB"; + return res; + } + }; + + // Note unsigned/signed char and simple char used for storing integer values, not char values. + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public integer_printer {}; + + template<> + struct type_printer : public text_printer {}; + + template<> + struct type_printer : public text_printer {}; + + template<> + struct type_printer : public text_printer {}; + + template<> + struct type_printer : public real_printer {}; + + template<> + struct type_printer : public real_printer {}; + + template + struct type_printer, void> : public type_printer {}; + + template + struct type_printer, void> : public type_printer {}; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct type_printer, void> : public type_printer {}; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template<> + struct type_printer, void> : public blob_printer {}; +} +#pragma once + +namespace sqlite_orm { + + namespace internal { + + enum class collate_argument { + binary, + nocase, + rtrim, + }; + } + +} +#pragma once + +#include // std::string +#include // std::tuple, std::make_tuple +#include // std::stringstream +#include // std::is_base_of, std::false_type, std::true_type +#include // std::ostream + +// #include "table_type.h" + +#include // std::enable_if, std::is_member_pointer, std::is_member_function_pointer + +// #include "member_traits/getter_traits.h" + +// #include "getters.h" + +namespace sqlite_orm { + namespace internal { + + template + using getter_by_value_const = T (O::*)() const; + + template + using getter_by_value = T (O::*)(); + + template + using getter_by_ref_const = T& (O::*)() const; + + template + using getter_by_ref = T& (O::*)(); + + template + using getter_by_const_ref_const = const T& (O::*)() const; + + template + using getter_by_const_ref = const T& (O::*)(); +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + using getter_by_value_const_noexcept = T (O::*)() const noexcept; + + template + using getter_by_value_noexcept = T (O::*)() noexcept; + + template + using getter_by_ref_const_noexcept = T& (O::*)() const noexcept; + + template + using getter_by_ref_noexcept = T& (O::*)() noexcept; + + template + using getter_by_const_ref_const_noexcept = const T& (O::*)() const noexcept; + + template + using getter_by_const_ref_noexcept = const T& (O::*)() noexcept; +#endif + } +} + +namespace sqlite_orm { + namespace internal { + + template + struct getter_traits; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = false; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = false; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = false; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = false; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; + + template + struct getter_traits> { + using object_type = O; + using field_type = T; + + static constexpr const bool returns_lvalue = true; + }; +#endif + } +} + +// #include "member_traits/setter_traits.h" + +// #include "setters.h" + +namespace sqlite_orm { + namespace internal { + + template + using setter_by_value = void (O::*)(T); + + template + using setter_by_ref = void (O::*)(T&); + + template + using setter_by_const_ref = void (O::*)(const T&); +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + using setter_by_value_noexcept = void (O::*)(T) noexcept; + + template + using setter_by_ref_noexcept = void (O::*)(T&) noexcept; + + template + using setter_by_const_ref_noexcept = void (O::*)(const T&) noexcept; +#endif + } +} + +namespace sqlite_orm { + namespace internal { + + template + struct setter_traits; + + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; + + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; + + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; + + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; + + template + struct setter_traits> { + using object_type = O; + using field_type = T; + }; +#endif + } +} + +// #include "member_traits/is_getter.h" + +#include // std::false_type, std::true_type + +// #include "getters.h" + +namespace sqlite_orm { + namespace internal { + + template + struct is_getter : std::false_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; + + template + struct is_getter> : std::true_type {}; +#endif + } +} + +// #include "member_traits/is_setter.h" + +// #include "setters.h" + +namespace sqlite_orm { + namespace internal { + + template + struct is_setter : std::false_type {}; + + template + struct is_setter> : std::true_type {}; + + template + struct is_setter> : std::true_type {}; + + template + struct is_setter> : std::true_type {}; +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct is_setter> : std::true_type {}; + + template + struct is_setter> : std::true_type {}; + + template + struct is_setter> : std::true_type {}; +#endif + } +} + +namespace sqlite_orm { + + namespace internal { + + template + struct column_pointer; + + /** + * Trait class used to define table mapped type by setter/getter/member + * T - member pointer + * `type` is a type which is mapped. + * E.g. + * - `table_type::type` is `User` + * - `table_type::type` is `User` + * - `table_type::type` is `User` + */ + template + struct table_type; + + template + struct table_type::value && + !std::is_member_function_pointer::value>::type> { + using type = O; + }; + + template + struct table_type::value>::type> { + using type = typename getter_traits::object_type; + }; + + template + struct table_type::value>::type> { + using type = typename setter_traits::object_type; + }; + + template + struct table_type, void> { + using type = T; + }; + } +} + +// #include "tuple_helper/tuple_helper.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * AUTOINCREMENT constraint class. + */ + struct autoincrement_t { + + operator std::string() const { + return "AUTOINCREMENT"; + } + }; + + struct primary_key_base { + enum class order_by { + unspecified, + ascending, + descending, + }; + + order_by asc_option = order_by::unspecified; + + operator std::string() const { + std::string res = "PRIMARY KEY"; + switch(this->asc_option) { + case order_by::ascending: + res += " ASC"; + break; + case order_by::descending: + res += " DESC"; + break; + default: + break; + } + return res; + } + }; + + /** + * PRIMARY KEY constraint class. + * Cs is parameter pack which contains columns (member pointers and/or function pointers). Can be empty when + * used withen `make_column` function. + */ + template + struct primary_key_t : primary_key_base { + using order_by = primary_key_base::order_by; + using columns_tuple = std::tuple; + + columns_tuple columns; + + primary_key_t(decltype(columns) c) : columns(move(c)) {} + + primary_key_t asc() const { + auto res = *this; + res.asc_option = order_by::ascending; + return res; + } + + primary_key_t desc() const { + auto res = *this; + res.asc_option = order_by::descending; + return res; + } + }; + + struct unique_base { + operator std::string() const { + return "UNIQUE"; + } + }; + + /** + * UNIQUE constraint class. + */ + template + struct unique_t : unique_base { + using columns_tuple = std::tuple; + + columns_tuple columns; + + unique_t(columns_tuple columns_) : columns(move(columns_)) {} + }; + + /** + * DEFAULT constraint class. + * T is a value type. + */ + template + struct default_t { + using value_type = T; + + value_type value; + + operator std::string() const { + return "DEFAULT"; + } + }; + +#if SQLITE_VERSION_NUMBER >= 3006019 + + /** + * FOREIGN KEY constraint class. + * Cs are columns which has foreign key + * Rs are column which C references to + * Available in SQLite 3.6.19 or higher + */ + + template + struct foreign_key_t; + + enum class foreign_key_action { + none, // not specified + no_action, + restrict_, + set_null, + set_default, + cascade, + }; + + inline std::ostream& operator<<(std::ostream& os, foreign_key_action action) { + switch(action) { + case decltype(action)::no_action: + os << "NO ACTION"; + break; + case decltype(action)::restrict_: + os << "RESTRICT"; + break; + case decltype(action)::set_null: + os << "SET NULL"; + break; + case decltype(action)::set_default: + os << "SET DEFAULT"; + break; + case decltype(action)::cascade: + os << "CASCADE"; + break; + case decltype(action)::none: + break; + } + return os; + } + + struct on_update_delete_base { + const bool update; // true if update and false if delete + + operator std::string() const { + if(this->update) { + return "ON UPDATE"; + } else { + return "ON DELETE"; + } + } + }; + + /** + * F - foreign key class + */ + template + struct on_update_delete_t : on_update_delete_base { + using foreign_key_type = F; + + const foreign_key_type& fk; + + on_update_delete_t(decltype(fk) fk_, decltype(update) update_, foreign_key_action action_) : + on_update_delete_base{update_}, fk(fk_), _action(action_) {} + + foreign_key_action _action = foreign_key_action::none; + + foreign_key_type no_action() const { + auto res = this->fk; + if(update) { + res.on_update._action = foreign_key_action::no_action; + } else { + res.on_delete._action = foreign_key_action::no_action; + } + return res; + } + + foreign_key_type restrict_() const { + auto res = this->fk; + if(update) { + res.on_update._action = foreign_key_action::restrict_; + } else { + res.on_delete._action = foreign_key_action::restrict_; + } + return res; + } + + foreign_key_type set_null() const { + auto res = this->fk; + if(update) { + res.on_update._action = foreign_key_action::set_null; + } else { + res.on_delete._action = foreign_key_action::set_null; + } + return res; + } + + foreign_key_type set_default() const { + auto res = this->fk; + if(update) { + res.on_update._action = foreign_key_action::set_default; + } else { + res.on_delete._action = foreign_key_action::set_default; + } + return res; + } + + foreign_key_type cascade() const { + auto res = this->fk; + if(update) { + res.on_update._action = foreign_key_action::cascade; + } else { + res.on_delete._action = foreign_key_action::cascade; + } + return res; + } + + operator bool() const { + return this->_action != decltype(this->_action)::none; + } + }; + + template + struct foreign_key_t, std::tuple> { + using columns_type = std::tuple; + using references_type = std::tuple; + using self = foreign_key_t; + + /** + * Holds obect type of all referenced columns. + */ + using target_type = typename same_or_void::type...>::type; + + /** + * Holds obect type of all source columns. + */ + using source_type = typename same_or_void::type...>::type; + + columns_type columns; + references_type references; + + on_update_delete_t on_update; + on_update_delete_t on_delete; + + static_assert(std::tuple_size::value == std::tuple_size::value, + "Columns size must be equal to references tuple"); + static_assert(!std::is_same::value, "All references must have the same type"); + + foreign_key_t(columns_type columns_, references_type references_) : + columns(std::move(columns_)), references(std::move(references_)), + on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} + + foreign_key_t(const self& other) : + columns(other.columns), references(other.references), on_update(*this, true, other.on_update._action), + on_delete(*this, false, other.on_delete._action) {} + + self& operator=(const self& other) { + this->columns = other.columns; + this->references = other.references; + this->on_update = {*this, true, other.on_update._action}; + this->on_delete = {*this, false, other.on_delete._action}; + return *this; + } + + template + void for_each_column(const L&) {} + + template + constexpr bool has_every() const { + return false; + } + }; + + /** + * Cs can be a class member pointer, a getter function member pointer or setter + * func member pointer + * Available in SQLite 3.6.19 or higher + */ + template + struct foreign_key_intermediate_t { + using tuple_type = std::tuple; + + tuple_type columns; + + foreign_key_intermediate_t(tuple_type columns_) : columns(std::move(columns_)) {} + + template + foreign_key_t, std::tuple> references(Rs... refs) { + return {std::move(this->columns), std::make_tuple(std::forward(refs)...)}; + } + }; +#endif + + struct collate_constraint_t { + internal::collate_argument argument = internal::collate_argument::binary; + + collate_constraint_t(internal::collate_argument argument_) : argument(argument_) {} + + operator std::string() const { + std::string res = "COLLATE " + this->string_from_collate_argument(this->argument); + return res; + } + + static std::string string_from_collate_argument(internal::collate_argument argument) { + switch(argument) { + case decltype(argument)::binary: + return "BINARY"; + case decltype(argument)::nocase: + return "NOCASE"; + case decltype(argument)::rtrim: + return "RTRIM"; + } + throw std::system_error(std::make_error_code(orm_error_code::invalid_collate_argument_enum)); + } + }; + + struct check_string { + operator std::string() const { + return "CHECK"; + } + }; + + template + struct check_t : check_string { + using expression_type = T; + + expression_type expression; + + check_t(expression_type expression_) : expression(std::move(expression_)) {} + }; + + template + struct is_constraint : std::false_type {}; + + template<> + struct is_constraint : std::true_type {}; + + template + struct is_constraint> : std::true_type {}; + + template + struct is_constraint> : std::true_type {}; + + template + struct is_constraint> : std::true_type {}; + + template + struct is_constraint> : std::true_type {}; + + template<> + struct is_constraint : std::true_type {}; + + template + struct is_constraint> : std::true_type {}; + + template + struct constraints_size; + + template<> + struct constraints_size<> { + static constexpr const int value = 0; + }; + + template + struct constraints_size { + static constexpr const int value = is_constraint::value + constraints_size::value; + }; + } + +#if SQLITE_VERSION_NUMBER >= 3006019 + + /** + * FOREIGN KEY constraint construction function that takes member pointer as argument + * Available in SQLite 3.6.19 or higher + */ + template + internal::foreign_key_intermediate_t foreign_key(Cs... columns) { + return {std::make_tuple(std::forward(columns)...)}; + } +#endif + + /** + * UNIQUE constraint builder function. + */ + template + internal::unique_t unique(Args... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + inline internal::unique_t<> unique() { + return {{}}; + } + + inline internal::autoincrement_t autoincrement() { + return {}; + } + + template + internal::primary_key_t primary_key(Cs... cs) { + return {std::make_tuple(std::forward(cs)...)}; + } + + inline internal::primary_key_t<> primary_key() { + return {{}}; + } + + template + internal::default_t default_value(T t) { + return {std::move(t)}; + } + + inline internal::collate_constraint_t collate_nocase() { + return {internal::collate_argument::nocase}; + } + + inline internal::collate_constraint_t collate_binary() { + return {internal::collate_argument::binary}; + } + + inline internal::collate_constraint_t collate_rtrim() { + return {internal::collate_argument::rtrim}; + } + + template + internal::check_t check(T t) { + return {std::move(t)}; + } + + namespace internal { + + /** + * FOREIGN KEY traits. Common case + */ + template + struct is_foreign_key : std::false_type {}; + + /** + * FOREIGN KEY traits. Specialized case + */ + template + struct is_foreign_key> : std::true_type {}; + + /** + * PRIMARY KEY traits. Common case + */ + template + struct is_primary_key : public std::false_type {}; + + /** + * PRIMARY KEY traits. Specialized case + */ + template + struct is_primary_key> : public std::true_type {}; + + /** + * PRIMARY KEY INSERTABLE traits. + */ + template + struct is_primary_key_insertable { + using field_type = typename T::field_type; + using constraints_type = typename T::constraints_type; + + static_assert((tuple_helper::tuple_contains_type, constraints_type>::value), + "an unexpected type was passed"); + + static constexpr bool value = + (tuple_helper::tuple_contains_some_type::value || + tuple_helper::tuple_contains_type::value || + std::is_base_of>::value); + }; + } + +} +#pragma once + +#include // std::false_type, std::true_type +#include // std::shared_ptr, std::unique_ptr +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +namespace sqlite_orm { + + /** + * This is class that tells `sqlite_orm` that type is nullable. Nullable types + * are mapped to sqlite database as `NULL` and not-nullable are mapped as `NOT NULL`. + * Default nullability status for all types is `NOT NULL`. So if you want to map + * custom type as `NULL` (for example: boost::optional) you have to create a specialiation + * of type_is_nullable for your type and derive from `std::true_type`. + */ + template + struct type_is_nullable : public std::false_type { + bool operator()(const T&) const { + return true; + } + }; + + /** + * This is a specialization for std::shared_ptr. std::shared_ptr is nullable in sqlite_orm. + */ + template + struct type_is_nullable> : public std::true_type { + bool operator()(const std::shared_ptr& t) const { + return static_cast(t); + } + }; + + /** + * This is a specialization for std::unique_ptr. std::unique_ptr is nullable too. + */ + template + struct type_is_nullable> : public std::true_type { + bool operator()(const std::unique_ptr& t) const { + return static_cast(t); + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * This is a specialization for std::optional. std::optional is nullable. + */ + template + struct type_is_nullable> : public std::true_type { + bool operator()(const std::optional& t) const { + return t.has_value(); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +} +#pragma once + +#include // std::unique_ptr +#include // std::string +#include // std::stringstream + +// #include "constraints.h" + +// #include "serializator_context.h" + +namespace sqlite_orm { + + namespace internal { + + struct serializator_context_base { + bool replace_bindable_with_question = false; + bool skip_table_name = true; + bool use_parentheses = true; + + template + const std::string* column_name(F O::*) const { + return nullptr; + } + }; + + template + struct serializator_context : serializator_context_base { + using impl_type = I; + + const impl_type& impl; + + serializator_context(const impl_type& impl_) : impl(impl_) {} + + template + const std::string* column_name(F O::*m) const { + return this->impl.column_name(m); + } + }; + + template + struct serializator_context_builder { + using storage_type = S; + using impl_type = typename storage_type::impl_type; + + serializator_context_builder(const storage_type& storage_) : storage(storage_) {} + + serializator_context operator()() const { + return {this->storage.impl}; + } + + const storage_type& storage; + }; + + } + +} + +namespace sqlite_orm { + + namespace internal { + + /** + * This class is used in tuple interation to know whether tuple constains `default_value_t` + * constraint class and what it's value if it is + */ + struct default_value_extractor { + + template + std::unique_ptr operator()(const A&) { + return {}; + } + + template + std::unique_ptr operator()(const default_t& t) { + serializator_context_base context; + return std::make_unique(serialize(t.value, context)); + } + }; + + } + +} +#pragma once + +#include // std::false_type, std::true_type +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::nullopt +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "tags.h" + +namespace sqlite_orm { + namespace internal { + struct negatable_t {}; + + /** + * Inherit from this class if target class can be chained with other conditions with '&&' and '||' operators + */ + struct condition_t {}; + } +} + +namespace sqlite_orm { + + namespace internal { + + /** + * Inherit this class to support arithmetic types overloading + */ + struct arithmetic_t {}; + + template + struct binary_operator : Ds... { + using left_type = L; + using right_type = R; + + left_type lhs; + right_type rhs; + + binary_operator(left_type lhs_, right_type rhs_) : lhs(std::move(lhs_)), rhs(std::move(rhs_)) {} + }; + + struct conc_string { + operator std::string() const { + return "||"; + } + }; + + /** + * Result of concatenation || operator + */ + template + using conc_t = binary_operator; + + struct add_string { + operator std::string() const { + return "+"; + } + }; + + /** + * Result of addition + operator + */ + template + using add_t = binary_operator; + + struct sub_string { + operator std::string() const { + return "-"; + } + }; + + /** + * Result of substitute - operator + */ + template + using sub_t = binary_operator; + + struct mul_string { + operator std::string() const { + return "*"; + } + }; + + /** + * Result of multiply * operator + */ + template + using mul_t = binary_operator; + + struct div_string { + operator std::string() const { + return "/"; + } + }; + + /** + * Result of divide / operator + */ + template + using div_t = binary_operator; + + struct mod_operator_string { + operator std::string() const { + return "%"; + } + }; + + /** + * Result of mod % operator + */ + template + using mod_t = binary_operator; + + struct bitwise_shift_left_string { + operator std::string() const { + return "<<"; + } + }; + + /** + * Result of bitwise shift left << operator + */ + template + using bitwise_shift_left_t = binary_operator; + + struct bitwise_shift_right_string { + operator std::string() const { + return ">>"; + } + }; + + /** + * Result of bitwise shift right >> operator + */ + template + using bitwise_shift_right_t = binary_operator; + + struct bitwise_and_string { + operator std::string() const { + return "&"; + } + }; + + /** + * Result of bitwise and & operator + */ + template + using bitwise_and_t = binary_operator; + + struct bitwise_or_string { + operator std::string() const { + return "|"; + } + }; + + /** + * Result of bitwise or | operator + */ + template + using bitwise_or_t = binary_operator; + + struct bitwise_not_string { + operator std::string() const { + return "~"; + } + }; + + /** + * Result of bitwise not ~ operator + */ + template + struct bitwise_not_t : bitwise_not_string, arithmetic_t, negatable_t { + using argument_type = T; + + argument_type argument; + + bitwise_not_t(argument_type argument_) : argument(std::move(argument_)) {} + }; + + struct assign_string { + operator std::string() const { + return "="; + } + }; + + /** + * Result of assign = operator + */ + template + using assign_t = binary_operator; + + /** + * Assign operator traits. Common case + */ + template + struct is_assign_t : public std::false_type {}; + + /** + * Assign operator traits. Specialized case + */ + template + struct is_assign_t> : public std::true_type {}; + + template + struct in_t; + + } + + /** + * Public interface for || concatenation operator. Example: `select(conc(&User::name, "@gmail.com"));` => SELECT + * name || '@gmail.com' FROM users + */ + template + internal::conc_t conc(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users + */ + template + internal::add_t add(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for - operator. Example: `select(sub(&User::age, 1));` => SELECT age - 1 FROM users + */ + template + internal::sub_t sub(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for * operator. Example: `select(mul(&User::salary, 2));` => SELECT salary * 2 FROM users + */ + template + internal::mul_t mul(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for / operator. Example: `select(div(&User::salary, 3));` => SELECT salary / 3 FROM users + * @note Please notice that ::div function already exists in pure C standard library inside header. + * If you use `using namespace sqlite_orm` directive you an specify which `div` you call explicitly using `::div` or `sqlite_orm::div` statements. + */ + template + internal::div_t div(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for % operator. Example: `select(mod(&User::age, 5));` => SELECT age % 5 FROM users + */ + template + internal::mod_t mod(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_shift_left_t bitwise_shift_left(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_shift_right_t bitwise_shift_right(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_and_t bitwise_and(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_or_t bitwise_or(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_not_t bitwise_not(T t) { + return {std::move(t)}; + } + + template + internal::assign_t assign(L l, R r) { + return {std::move(l), std::move(r)}; + } + +} +#pragma once + +#include // std::tuple +#include // std::string +#include // std::unique_ptr +#include // std::true_type, std::false_type, std::is_same, std::enable_if, std::is_member_pointer, std::is_member_function_pointer + +// #include "type_is_nullable.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "default_value_extractor.h" + +// #include "constraints.h" + +// #include "member_traits/member_traits.h" + +#include // std::enable_if + +// #include "is_field_member_pointer.h" + +#include // std::false_type, std::true_type, std::is_member_pointer, std::is_member_function_pointer + +namespace sqlite_orm { + namespace internal { + + template + struct is_field_member_pointer : std::false_type {}; + + template + struct is_field_member_pointer::value && + !std::is_member_function_pointer::value>::type> + : std::true_type {}; + } +} + +// #include "is_getter.h" + +// #include "field_member_traits.h" + +#include // std::enable_if + +// #include "is_field_member_pointer.h" + +namespace sqlite_orm { + namespace internal { + + template + struct field_member_traits; + + template + struct field_member_traits::value>::type> { + using object_type = O; + using field_type = F; + }; + } +} + +// #include "is_setter.h" + +// #include "getter_traits.h" + +// #include "setter_traits.h" + +namespace sqlite_orm { + namespace internal { + + template + struct member_traits; + + template + struct member_traits::value>::type> { + using object_type = typename field_member_traits::object_type; + using field_type = typename field_member_traits::field_type; + }; + + template + struct member_traits::value>::type> { + using object_type = typename getter_traits::object_type; + using field_type = typename getter_traits::field_type; + }; + + template + struct member_traits::value>::type> { + using object_type = typename setter_traits::object_type; + using field_type = typename setter_traits::field_type; + }; + } +} + +namespace sqlite_orm { + + namespace internal { + + struct column_base { + + /** + * Column name. Specified during construction in `make_column`. + */ + const std::string name; + }; + + /** + * This class stores single column info. column_t is a pair of [column_name:member_pointer] mapped to a storage + * O is a mapped class, e.g. User + * T is a mapped class'es field type, e.g. &User::name + * Op... is a constraints pack, e.g. primary_key_t, autoincrement_t etc + */ + template + struct column_t : column_base { + using object_type = O; + using field_type = T; + using constraints_type = std::tuple; + using member_pointer_t = field_type object_type::*; + using getter_type = G; + using setter_type = S; + + /** + * Member pointer used to read/write member + */ + member_pointer_t member_pointer /* = nullptr*/; + + /** + * Getter member function pointer to get a value. If member_pointer is null than + * `getter` and `setter` must be not null + */ + getter_type getter /* = nullptr*/; + + /** + * Setter member function + */ + setter_type setter /* = nullptr*/; + + /** + * Constraints tuple + */ + constraints_type constraints; + + column_t(std::string name_, + member_pointer_t member_pointer_, + getter_type getter_, + setter_type setter_, + constraints_type constraints_) : + column_base{std::move(name_)}, + member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(constraints_)) {} + + /** + * Simplified interface for `NOT NULL` constraint + */ + bool not_null() const { + return !type_is_nullable::value; + } + + template + constexpr bool has() const { + return tuple_helper::tuple_contains_type::value; + } + + template + constexpr bool has_every() const { + if(has() && has()) { + return true; + } else { + return has_every(); + } + } + + template + constexpr bool has_every() const { + return has(); + } + + /** + * Simplified interface for `DEFAULT` constraint + * @return string representation of default value if it exists otherwise nullptr + */ + std::unique_ptr default_value() const { + std::unique_ptr res; + iterate_tuple(this->constraints, [&res](auto& v) { + auto dft = internal::default_value_extractor()(v); + if(dft) { + res = std::move(dft); + } + }); + return res; + } + }; + + // we are compelled to wrap all sfinae-implemented traits to prevent "error: type/value mismatch at argument 2 in template parameter list" + namespace sfinae { + /** + * Column with insertable primary key traits. Common case. + */ + template + struct is_column_with_insertable_primary_key : public std::false_type {}; + + /** + * Column with insertable primary key traits. Specialized case case. + */ + template + struct is_column_with_insertable_primary_key< + column_t, + typename std::enable_if<(tuple_helper::tuple_contains_type< + primary_key_t<>, + typename column_t::constraints_type>::value)>::type> { + using column_type = column_t; + static constexpr bool value = is_primary_key_insertable::value; + }; + + /** + * Column with noninsertable primary key traits. Common case. + */ + template + struct is_column_with_noninsertable_primary_key : public std::false_type {}; + + /** + * Column with noninsertable primary key traits. Specialized case case. + */ + template + struct is_column_with_noninsertable_primary_key< + column_t, + typename std::enable_if<(tuple_helper::tuple_contains_type< + primary_key_t<>, + typename column_t::constraints_type>::value)>::type> { + using column_type = column_t; + static constexpr bool value = !is_primary_key_insertable::value; + }; + + } + + /** + * Column traits. Common case. + */ + template + struct is_column : public std::false_type {}; + + /** + * Column traits. Specialized case case. + */ + template + struct is_column> : public std::true_type {}; + + /** + * Column with insertable primary key traits. + */ + template + struct is_column_with_insertable_primary_key : public sfinae::is_column_with_insertable_primary_key {}; + + /** + * Column with noninsertable primary key traits. + */ + template + struct is_column_with_noninsertable_primary_key : public sfinae::is_column_with_noninsertable_primary_key {}; + + template + struct column_field_type { + using type = void; + }; + + template + struct column_field_type> { + using type = typename column_t::field_type; + }; + + template + struct column_constraints_type { + using type = std::tuple<>; + }; + + template + struct column_constraints_type> { + using type = typename column_t::constraints_type; + }; + + } + + /** + * Column builder function. You should use it to create columns instead of constructor + */ + template::value>::type, + class... Op> + internal::column_t + make_column(const std::string& name, T O::*m, Op... constraints) { + static_assert(internal::template constraints_size::value == std::tuple_size>::value, + "Incorrect constraints pack"); + static_assert(internal::is_field_member_pointer::value, + "second argument expected as a member field pointer, not member function pointer"); + return {name, m, nullptr, nullptr, std::make_tuple(constraints...)}; + } + + /** + * Column builder function with setter and getter. You should use it to create columns instead of constructor + */ + template::value>::type, + typename = typename std::enable_if::value>::type, + class... Op> + internal::column_t::object_type, + typename internal::setter_traits::field_type, + G, + S, + Op...> + make_column(const std::string& name, S setter, G getter, Op... constraints) { + static_assert(std::is_same::field_type, + typename internal::getter_traits::field_type>::value, + "Getter and setter must get and set same data type"); + static_assert(internal::template constraints_size::value == std::tuple_size>::value, + "Incorrect constraints pack"); + return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; + } + + /** + * Column builder function with getter and setter (reverse order). You should use it to create columns instead of + * constructor + */ + template::value>::type, + typename = typename std::enable_if::value>::type, + class... Op> + internal::column_t::object_type, + typename internal::setter_traits::field_type, + G, + S, + Op...> + make_column(const std::string& name, G getter, S setter, Op... constraints) { + static_assert(std::is_same::field_type, + typename internal::getter_traits::field_type>::value, + "Getter and setter must get and set same data type"); + static_assert(internal::template constraints_size::value == std::tuple_size>::value, + "Incorrect constraints pack"); + return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; + } + +} +#pragma once + +#include // std::string +#include // std::stringstream +#include // std::vector +#include // std::nullptr_t +#include // std::shared_ptr, std::unique_ptr +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +namespace sqlite_orm { + + /** + * Is used to print members mapped to objects in storage_t::dump member function. + * Other developers can create own specialization to map custom types + */ + template + struct field_printer { + std::string operator()(const T& t) const { + std::stringstream stream; + stream << t; + return stream.str(); + } + }; + + /** + * Upgrade to integer is required when using unsigned char(uint8_t) + */ + template<> + struct field_printer { + std::string operator()(const unsigned char& t) const { + std::stringstream stream; + stream << +t; + return stream.str(); + } + }; + + /** + * Upgrade to integer is required when using signed char(int8_t) + */ + template<> + struct field_printer { + std::string operator()(const signed char& t) const { + std::stringstream stream; + stream << +t; + return stream.str(); + } + }; + + /** + * char is neigher signer char nor unsigned char so it has its own specialization + */ + template<> + struct field_printer { + std::string operator()(const char& t) const { + std::stringstream stream; + stream << +t; + return stream.str(); + } + }; + + template<> + struct field_printer { + std::string operator()(const std::string& t) const { + return t; + } + }; + + template<> + struct field_printer, void> { + std::string operator()(const std::vector& t) const { + std::stringstream ss; + ss << std::hex; + for(auto c: t) { + ss << c; + } + return ss.str(); + } + }; + + template<> + struct field_printer { + std::string operator()(const std::nullptr_t&) const { + return "null"; + } + }; +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template<> + struct field_printer { + std::string operator()(const std::nullopt_t&) const { + return "null"; + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct field_printer, void> { + std::string operator()(const std::shared_ptr& t) const { + if(t) { + return field_printer()(*t); + } else { + return field_printer()(nullptr); + } + } + }; + + template + struct field_printer, void> { + std::string operator()(const std::unique_ptr& t) const { + if(t) { + return field_printer()(*t); + } else { + return field_printer()(nullptr); + } + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct field_printer, void> { + std::string operator()(const std::optional& t) const { + if(t.has_value()) { + return field_printer()(*t); + } else { + return field_printer()(nullptr); + } + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +} +#pragma once + +#include // std::string +#include // std::enable_if, std::is_same +#include // std::vector +#include // std::tuple, std::tuple_size +#include // std::stringstream + +// #include "collate_argument.h" + +// #include "constraints.h" + +// #include "optional_container.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * This is a cute class which allows storing something or nothing + * depending on template argument. Useful for optional class members + */ + template + struct optional_container { + using type = T; + + type field; + + template + void apply(const L& l) const { + l(this->field); + } + }; + + template<> + struct optional_container { + using type = void; + + template + void apply(const L&) const { + //.. + } + }; + } +} + +// #include "tags.h" + +// #include "expression.h" +// #include "operators.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct and_condition_t; + + template + struct or_condition_t; + + /** + * Is not an operator but a result of c(...) function. Has operator= overloaded which returns assign_t + */ + template + struct expression_t : condition_t { + T value; + + expression_t(T value_) : value(std::move(value_)) {} + + template + assign_t operator=(R r) const { + return {this->value, std::move(r)}; + } + + assign_t operator=(std::nullptr_t) const { + return {this->value, nullptr}; + } +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + assign_t operator=(std::nullopt_t) const { + return {this->value, std::nullopt}; + } +#endif + template + in_t in(Args... args) const { + return {this->value, std::make_tuple(std::forward(args)...), false}; + } + + template + in_t not_in(Args... args) const { + return {this->value, std::make_tuple(std::forward(args)...), true}; + } + + template + and_condition_t and_(R right) const { + return {this->value, std::move(right)}; + } + + template + or_condition_t or_(R right) const { + return {this->value, std::move(right)}; + } + }; + + template + T get_from_expression(T value) { + return std::move(value); + } + + template + T get_from_expression(expression_t expression) { + return std::move(expression.value); + } + } + + /** + * Public interface for syntax sugar for columns. Example: `where(c(&User::id) == 5)` or + * `storage.update(set(c(&User::name) = "Dua Lipa")); + */ + template + internal::expression_t c(T value) { + return {std::move(value)}; + } +} + +namespace sqlite_orm { + + namespace internal { + + struct limit_string { + operator std::string() const { + return "LIMIT"; + } + }; + + /** + * Stores LIMIT/OFFSET info + */ + template + struct limit_t : limit_string { + T lim; + optional_container off; + + limit_t() = default; + + limit_t(decltype(lim) lim_) : lim(std::move(lim_)) {} + + limit_t(decltype(lim) lim_, decltype(off) off_) : lim(std::move(lim_)), off(std::move(off_)) {} + }; + + template + struct is_limit : std::false_type {}; + + template + struct is_limit> : std::true_type {}; + + /** + * Stores OFFSET only info + */ + template + struct offset_t { + T off; + }; + + template + struct is_offset : std::false_type {}; + + template + struct is_offset> : std::true_type {}; + + /** + * Collated something + */ + template + struct collate_t : public condition_t { + T expr; + collate_argument argument; + + collate_t(T expr_, collate_argument argument_) : expr(std::move(expr_)), argument(argument_) {} + + operator std::string() const { + return collate_constraint_t{this->argument}; + } + }; + + struct named_collate_base { + std::string name; + + operator std::string() const { + return "COLLATE " + this->name; + } + }; + + /** + * Collated something with custom collate function + */ + template + struct named_collate : named_collate_base { + T expr; + + named_collate(T expr_, std::string name_) : named_collate_base{std::move(name_)}, expr(std::move(expr_)) {} + }; + + struct negated_condition_string { + operator std::string() const { + return "NOT"; + } + }; + + /** + * Result of not operator + */ + template + struct negated_condition_t : condition_t, negated_condition_string { + C c; + + negated_condition_t(C c_) : c(std::move(c_)) {} + }; + + /** + * Base class for binary conditions + * L is left argument type + * R is right argument type + * S is 'string' class (a class which has cast to `std::string` operator) + * Res is result type + */ + template + struct binary_condition : condition_t, S { + using left_type = L; + using right_type = R; + using result_type = Res; + + left_type l; + right_type r; + + binary_condition() = default; + + binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} + }; + + struct and_condition_string { + operator std::string() const { + return "AND"; + } + }; + + /** + * Result of and operator + */ + template + struct and_condition_t : binary_condition { + using super = binary_condition; + + using super::super; + }; + + template + and_condition_t make_and_condition(L left, R right) { + return {std::move(left), std::move(right)}; + } + + struct or_condition_string { + operator std::string() const { + return "OR"; + } + }; + + /** + * Result of or operator + */ + template + struct or_condition_t : binary_condition { + using super = binary_condition; + + using super::super; + }; + + template + or_condition_t make_or_condition(L left, R right) { + return {std::move(left), std::move(right)}; + } + + struct is_equal_string { + operator std::string() const { + return "="; + } + }; + + /** + * = and == operators object + */ + template + struct is_equal_t : binary_condition, negatable_t { + using self = is_equal_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + + named_collate collate(std::string name) const { + return {*this, std::move(name)}; + } + + template + named_collate collate() const { + std::stringstream ss; + ss << C::name(); + auto name = ss.str(); + ss.flush(); + return {*this, std::move(name)}; + } + }; + + struct is_not_equal_string { + operator std::string() const { + return "!="; + } + }; + + /** + * != operator object + */ + template + struct is_not_equal_t : binary_condition, negatable_t { + using self = is_not_equal_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + }; + + struct greater_than_string { + operator std::string() const { + return ">"; + } + }; + + /** + * > operator object. + */ + template + struct greater_than_t : binary_condition, negatable_t { + using self = greater_than_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + }; + + struct greater_or_equal_string { + operator std::string() const { + return ">="; + } + }; + + /** + * >= operator object. + */ + template + struct greater_or_equal_t : binary_condition, negatable_t { + using self = greater_or_equal_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + }; + + struct lesser_than_string { + operator std::string() const { + return "<"; + } + }; + + /** + * < operator object. + */ + template + struct lesser_than_t : binary_condition, negatable_t { + using self = lesser_than_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + }; + + struct lesser_or_equal_string { + operator std::string() const { + return "<="; + } + }; + + /** + * <= operator object. + */ + template + struct lesser_or_equal_t : binary_condition, negatable_t { + using self = lesser_or_equal_t; + + using binary_condition::binary_condition; + + collate_t collate_binary() const { + return {*this, collate_argument::binary}; + } + + collate_t collate_nocase() const { + return {*this, collate_argument::nocase}; + } + + collate_t collate_rtrim() const { + return {*this, collate_argument::rtrim}; + } + }; + + struct in_base { + bool negative = false; // used in not_in + + operator std::string() const { + if(!this->negative) { + return "IN"; + } else { + return "NOT IN"; + } + } + }; + + /** + * IN operator object. + */ + template + struct dynamic_in_t : condition_t, in_base, negatable_t { + using self = dynamic_in_t; + + L left; // left expression + A argument; // in arg + + dynamic_in_t(L left_, A argument_, bool negative_) : + in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} + }; + + template + struct in_t : condition_t, in_base, negatable_t { + L left; + std::tuple argument; + + in_t(L left_, decltype(argument) argument_, bool negative_) : + in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} + }; + + struct is_null_string { + operator std::string() const { + return "IS NULL"; + } + }; + + /** + * IS NULL operator object. + */ + template + struct is_null_t : is_null_string, negatable_t { + using self = is_null_t; + + T t; + + is_null_t(T t_) : t(std::move(t_)) {} + }; + + struct is_not_null_string { + operator std::string() const { + return "IS NOT NULL"; + } + }; + + /** + * IS NOT NULL operator object. + */ + template + struct is_not_null_t : is_not_null_string, negatable_t { + using self = is_not_null_t; + + T t; + + is_not_null_t(T t_) : t(std::move(t_)) {} + }; + + struct order_by_base { + int asc_desc = 0; // 1: asc, -1: desc + std::string _collate_argument; + + order_by_base() = default; + + order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) : + asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {} + }; + + struct order_by_string { + operator std::string() const { + return "ORDER BY"; + } + }; + + /** + * ORDER BY argument holder. + */ + template + struct order_by_t : order_by_base, order_by_string { + using expression_type = O; + using self = order_by_t; + + expression_type expression; + + order_by_t(expression_type expression_) : order_by_base(), expression(std::move(expression_)) {} + + self asc() { + auto res = *this; + res.asc_desc = 1; + return res; + } + + self desc() { + auto res = *this; + res.asc_desc = -1; + return res; + } + + self collate_binary() const { + auto res = *this; + res._collate_argument = + collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::binary); + return res; + } + + self collate_nocase() const { + auto res = *this; + res._collate_argument = + collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::nocase); + return res; + } + + self collate_rtrim() const { + auto res = *this; + res._collate_argument = + collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::rtrim); + return res; + } + + self collate(std::string name) const { + auto res = *this; + res._collate_argument = std::move(name); + return res; + } + + template + self collate() const { + std::stringstream ss; + ss << C::name(); + auto name = ss.str(); + ss.flush(); + return this->collate(move(name)); + } + }; + + /** + * ORDER BY pack holder. + */ + template + struct multi_order_by_t : order_by_string { + using args_type = std::tuple; + + args_type args; + + multi_order_by_t(args_type&& args_) : args(std::move(args_)) {} + }; + + struct dynamic_order_by_entry_t : order_by_base { + std::string name; + + dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : + order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} + }; + + /** + * C - serializator context class + */ + template + struct dynamic_order_by_t : order_by_string { + using context_t = C; + using entry_t = dynamic_order_by_entry_t; + using const_iterator = typename std::vector::const_iterator; + + dynamic_order_by_t(const context_t& context_) : context(context_) {} + + template + void push_back(order_by_t order_by) { + auto newContext = this->context; + newContext.skip_table_name = true; + auto columnName = serialize(order_by.expression, newContext); + entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + } + + const_iterator begin() const { + return this->entries.begin(); + } + + const_iterator end() const { + return this->entries.end(); + } + + void clear() { + this->entries.clear(); + } + + protected: + std::vector entries; + context_t context; + }; + + template + struct is_order_by : std::false_type {}; + + template + struct is_order_by> : std::true_type {}; + + template + struct is_order_by> : std::true_type {}; + + template + struct is_order_by> : std::true_type {}; + + struct group_by_string { + operator std::string() const { + return "GROUP BY"; + } + }; + + /** + * GROUP BY pack holder. + */ + template + struct group_by_t : group_by_string { + using args_type = std::tuple; + args_type args; + + group_by_t(args_type&& args_) : args(std::move(args_)) {} + }; + + template + struct is_group_by : std::false_type {}; + + template + struct is_group_by> : std::true_type {}; + + struct between_string { + operator std::string() const { + return "BETWEEN"; + } + }; + + /** + * BETWEEN operator object. + */ + template + struct between_t : condition_t, between_string { + using expression_type = A; + using lower_type = T; + using upper_type = T; + + expression_type expr; + lower_type b1; + upper_type b2; + + between_t(expression_type expr_, lower_type b1_, upper_type b2_) : + expr(std::move(expr_)), b1(std::move(b1_)), b2(std::move(b2_)) {} + }; + + struct like_string { + operator std::string() const { + return "LIKE"; + } + }; + + /** + * LIKE operator object. + */ + template + struct like_t : condition_t, like_string, negatable_t { + using self = like_t; + using arg_t = A; + using pattern_t = T; + using escape_t = E; + + arg_t arg; + pattern_t pattern; + optional_container arg3; // not escape cause escape exists as a function here + + like_t(arg_t arg_, pattern_t pattern_, optional_container escape_) : + arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape_)) {} + + template + like_t escape(C c) const { + optional_container newArg3{std::move(c)}; + return {std::move(this->arg), std::move(this->pattern), std::move(newArg3)}; + } + }; + + struct glob_string { + operator std::string() const { + return "GLOB"; + } + }; + + template + struct glob_t : condition_t, glob_string, internal::negatable_t { + using self = glob_t; + using arg_t = A; + using pattern_t = T; + + arg_t arg; + pattern_t pattern; + + glob_t(arg_t arg_, pattern_t pattern_) : arg(std::move(arg_)), pattern(std::move(pattern_)) {} + }; + + struct cross_join_string { + operator std::string() const { + return "CROSS JOIN"; + } + }; + + /** + * CROSS JOIN holder. + * T is joined type which represents any mapped table. + */ + template + struct cross_join_t : cross_join_string { + using type = T; + }; + + struct natural_join_string { + operator std::string() const { + return "NATURAL JOIN"; + } + }; + + /** + * NATURAL JOIN holder. + * T is joined type which represents any mapped table. + */ + template + struct natural_join_t : natural_join_string { + using type = T; + }; + + struct left_join_string { + operator std::string() const { + return "LEFT JOIN"; + } + }; + + /** + * LEFT JOIN holder. + * T is joined type which represents any mapped table. + * O is on(...) argument type. + */ + template + struct left_join_t : left_join_string { + using type = T; + using on_type = O; + + on_type constraint; + + left_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} + }; + + struct join_string { + operator std::string() const { + return "JOIN"; + } + }; + + /** + * Simple JOIN holder. + * T is joined type which represents any mapped table. + * O is on(...) argument type. + */ + template + struct join_t : join_string { + using type = T; + using on_type = O; + + on_type constraint; + + join_t(on_type constraint_) : constraint(std::move(constraint_)) {} + }; + + struct left_outer_join_string { + operator std::string() const { + return "LEFT OUTER JOIN"; + } + }; + + /** + * LEFT OUTER JOIN holder. + * T is joined type which represents any mapped table. + * O is on(...) argument type. + */ + template + struct left_outer_join_t : left_outer_join_string { + using type = T; + using on_type = O; + + on_type constraint; + + left_outer_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} + }; + + struct on_string { + operator std::string() const { + return "ON"; + } + }; + + /** + * on(...) argument holder used for JOIN, LEFT JOIN, LEFT OUTER JOIN and INNER JOIN + * T is on type argument. + */ + template + struct on_t : on_string { + using arg_type = T; + + arg_type arg; + + on_t(arg_type arg_) : arg(std::move(arg_)) {} + }; + + /** + * USING argument holder. + */ + template + struct using_t { + F O::*column = nullptr; + + operator std::string() const { + return "USING"; + } + }; + + struct inner_join_string { + operator std::string() const { + return "INNER JOIN"; + } + }; + + /** + * INNER JOIN holder. + * T is joined type which represents any mapped table. + * O is on(...) argument type. + */ + template + struct inner_join_t : inner_join_string { + using type = T; + using on_type = O; + + on_type constraint; + + inner_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} + }; + + struct exists_string { + operator std::string() const { + return "EXISTS"; + } + }; + + template + struct exists_t : condition_t, exists_string, internal::negatable_t { + using type = T; + using self = exists_t; + + type t; + + exists_t(T t_) : t(std::move(t_)) {} + }; + + struct having_string { + operator std::string() const { + return "HAVING"; + } + }; + + /** + * HAVING holder. + * T is having argument type. + */ + template + struct having_t : having_string { + using type = T; + + type t; + + having_t(type t_) : t(std::move(t_)) {} + }; + + template + struct is_having : std::false_type {}; + + template + struct is_having> : std::true_type {}; + + struct cast_string { + operator std::string() const { + return "CAST"; + } + }; + + /** + * CAST holder. + * T is a type to cast to + * E is an expression type + * Example: cast(&User::id) + */ + template + struct cast_t : cast_string { + using to_type = T; + using expression_type = E; + + expression_type expression; + + cast_t(expression_type expression_) : expression(std::move(expression_)) {} + }; + + template + struct from_t { + using tuple_type = std::tuple; + }; + + template + struct is_from : std::false_type {}; + + template + struct is_from> : std::true_type {}; + } + + /** + * Explicit FROM function. Usage: + * `storage.select(&User::id, from());` + */ + template + internal::from_t from() { + static_assert(std::tuple_size>::value > 0, ""); + return {}; + } + + template::value>::type> + internal::negated_condition_t operator!(T arg) { + return {std::move(arg)}; + } + + /** + * Cute operators for columns + */ + template + internal::lesser_than_t operator<(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::lesser_than_t operator<(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::greater_than_t operator>(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::greater_than_t operator>(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::greater_or_equal_t operator>=(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::greater_or_equal_t operator>=(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::is_equal_t operator==(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::is_equal_t operator==(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::is_not_equal_t operator!=(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::is_not_equal_t operator!=(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::conc_t operator||(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::conc_t operator||(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::add_t operator+(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::add_t operator+(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::add_t operator+(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::sub_t operator-(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::sub_t operator-(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::mul_t operator*(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::mul_t operator*(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::div_t operator/(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::div_t operator/(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::div_t operator/(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::mod_t operator%(internal::expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } + + template + internal::mod_t operator%(L l, internal::expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } + + template + internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } + + template + internal::using_t using_(F O::*p) { + return {std::move(p)}; + } + + template + internal::on_t on(T t) { + return {std::move(t)}; + } + + template + internal::cross_join_t cross_join() { + return {}; + } + + template + internal::natural_join_t natural_join() { + return {}; + } + + template + internal::left_join_t left_join(O o) { + return {std::move(o)}; + } + + template + internal::join_t join(O o) { + return {std::move(o)}; + } + + template + internal::left_outer_join_t left_outer_join(O o) { + return {std::move(o)}; + } + + template + internal::inner_join_t inner_join(O o) { + return {std::move(o)}; + } + + template + internal::offset_t offset(T off) { + return {std::move(off)}; + } + + template + internal::limit_t limit(T lim) { + return {std::move(lim)}; + } + + template + typename std::enable_if::value, internal::limit_t>::type limit(O off, + T lim) { + return {std::move(lim), {std::move(off)}}; + } + + template + internal::limit_t limit(T lim, internal::offset_t offt) { + return {std::move(lim), {std::move(offt.off)}}; + } + + template::value || + std::is_base_of::value>::type> + auto operator&&(L l, R r) { + using internal::get_from_expression; + return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + } + + template + auto and_(L l, R r) { + using internal::get_from_expression; + return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + } + + template::value || + std::is_base_of::value>::type> + auto operator||(L l, R r) { + using internal::get_from_expression; + return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + } + + template + auto or_(L l, R r) { + using internal::get_from_expression; + return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + } + + template + internal::is_not_null_t is_not_null(T t) { + return {std::move(t)}; + } + + template + internal::is_null_t is_null(T t) { + return {std::move(t)}; + } + + template + internal::dynamic_in_t> in(L l, std::vector values) { + return {std::move(l), std::move(values), false}; + } + + template + internal::dynamic_in_t> in(L l, std::initializer_list values) { + return {std::move(l), std::move(values), false}; + } + + template + internal::dynamic_in_t in(L l, A arg) { + return {std::move(l), std::move(arg), false}; + } + + template + internal::dynamic_in_t> not_in(L l, std::vector values) { + return {std::move(l), std::move(values), true}; + } + + template + internal::dynamic_in_t> not_in(L l, std::initializer_list values) { + return {std::move(l), std::move(values), true}; + } + + template + internal::dynamic_in_t not_in(L l, A arg) { + return {std::move(l), std::move(arg), true}; + } + + template + internal::is_equal_t is_equal(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::is_equal_t eq(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::is_not_equal_t is_not_equal(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::is_not_equal_t ne(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::greater_than_t greater_than(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::greater_than_t gt(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::greater_or_equal_t greater_or_equal(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::greater_or_equal_t ge(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::lesser_than_t lesser_than(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::lesser_than_t lt(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::lesser_or_equal_t lesser_or_equal(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::lesser_or_equal_t le(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * ORDER BY column + * Example: storage.select(&User::name, order_by(&User::id)) + */ + template + internal::order_by_t order_by(O o) { + return {std::move(o)}; + } + + /** + * ORDER BY column1, column2 + * Example: storage.get_all(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) + */ + template + internal::multi_order_by_t multi_order_by(Args&&... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * ORDER BY column1, column2 + * Difference from `multi_order_by` is that `dynamic_order_by` can be changed at runtime using `push_back` member + * function Example: + * auto orderBy = dynamic_order_by(storage); + * if(someCondition) { + * orderBy.push_back(&User::id); + * } else { + * orderBy.push_back(&User::name); + * orderBy.push_back(&User::birthDate); + * } + */ + template + internal::dynamic_order_by_t> + dynamic_order_by(const S& storage) { + internal::serializator_context_builder builder(storage); + return builder(); + } + + /** + * GROUP BY column. + * Example: storage.get_all(group_by(&Employee::name)) + */ + template + internal::group_by_t group_by(Args&&... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * X BETWEEN Y AND Z + * Example: storage.select(between(&User::id, 10, 20)) + */ + template + internal::between_t between(A expr, T b1, T b2) { + return {std::move(expr), std::move(b1), std::move(b2)}; + } + + /** + * X LIKE Y + * Example: storage.select(like(&User::name, "T%")) + */ + template + internal::like_t like(A a, T t) { + return {std::move(a), std::move(t), {}}; + } + + /** + * X GLOB Y + * Example: storage.select(glob(&User::name, "*S")) + */ + template + internal::glob_t glob(A a, T t) { + return {std::move(a), std::move(t)}; + } + + /** + * X LIKE Y ESCAPE Z + * Example: storage.select(like(&User::name, "T%", "%")) + */ + template + internal::like_t like(A a, T t, E e) { + return {std::move(a), std::move(t), {std::move(e)}}; + } + + /** + * EXISTS(condition). + * Example: storage.select(columns(&Agent::code, &Agent::name, &Agent::workingArea, &Agent::comission), + where(exists(select(asterisk(), + where(is_equal(&Customer::grade, 3) and + is_equal(&Agent::code, &Customer::agentCode))))), + order_by(&Agent::comission)); + */ + template + internal::exists_t exists(T t) { + return {std::move(t)}; + } + + /** + * HAVING(expression). + * Example: storage.get_all(group_by(&Employee::name), having(greater_than(count(&Employee::name), 2))); + */ + template + internal::having_t having(T t) { + return {std::move(t)}; + } + + /** + * CAST(X AS type). + * Example: cast(&User::id) + */ + template + internal::cast_t cast(E e) { + return {std::move(e)}; + } +} +#pragma once + +#include // std::enable_if, std::is_base_of, std::is_member_pointer +#include // std::stringstream +#include // std::string + +namespace sqlite_orm { + + /** + * This is base class for every class which is used as a custom table alias. + * For more information please look through self_join.cpp example + */ + struct alias_tag {}; + + namespace internal { + + /** + * This is a common built-in class used for custom single character table aliases. + * Also you can use language aliases `alias_a`, `alias_b` etc. instead + */ + template + struct table_alias : alias_tag { + using type = T; + + static char get() { + return A; + } + }; + + /** + * Column expression with table alias attached like 'C.ID'. This is not a column alias + */ + template + struct alias_column_t { + using alias_type = T; + using column_type = C; + + column_type column; + + alias_column_t(){}; + + alias_column_t(column_type column_) : column(std::move(column_)) {} + }; + + template + struct alias_extractor; + + template + struct alias_extractor::value>::type> { + static std::string get() { + std::stringstream ss; + ss << T::get(); + return ss.str(); + } + }; + + template + struct alias_extractor::value>::type> { + static std::string get() { + return {}; + } + }; + + /** + * Used to store alias for expression + */ + template + struct as_t { + using alias_type = T; + using expression_type = E; + + expression_type expression; + }; + + template + struct alias_holder { + using type = T; + }; + } + + /** + * @return column with table alias attached. Place it instead of a column statement in case you need to specify a + * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example + */ + template + internal::alias_column_t alias_column(C c) { + static_assert(std::is_member_pointer::value, + "alias_column argument must be a member pointer mapped to a storage"); + return {c}; + } + + template + internal::as_t as(E expression) { + return {std::move(expression)}; + } + + template + internal::alias_holder get() { + return {}; + } + + template + using alias_a = internal::table_alias; + template + using alias_b = internal::table_alias; + template + using alias_c = internal::table_alias; + template + using alias_d = internal::table_alias; + template + using alias_e = internal::table_alias; + template + using alias_f = internal::table_alias; + template + using alias_g = internal::table_alias; + template + using alias_h = internal::table_alias; + template + using alias_i = internal::table_alias; + template + using alias_j = internal::table_alias; + template + using alias_k = internal::table_alias; + template + using alias_l = internal::table_alias; + template + using alias_m = internal::table_alias; + template + using alias_n = internal::table_alias; + template + using alias_o = internal::table_alias; + template + using alias_p = internal::table_alias; + template + using alias_q = internal::table_alias; + template + using alias_r = internal::table_alias; + template + using alias_s = internal::table_alias; + template + using alias_t = internal::table_alias; + template + using alias_u = internal::table_alias; + template + using alias_v = internal::table_alias; + template + using alias_w = internal::table_alias; + template + using alias_x = internal::table_alias; + template + using alias_y = internal::table_alias; + template + using alias_z = internal::table_alias; +} +#pragma once + +// #include "conditions.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct join_iterator; + + template<> + struct join_iterator<> { + + template + void operator()(const L&) const { + //.. + } + }; + + template + struct join_iterator : public join_iterator { + using super = join_iterator; + + template + void operator()(const L& l) const { + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = cross_join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = natural_join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = left_join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = left_outer_join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + + template + struct join_iterator, Tail...> : public join_iterator { + using super = join_iterator; + using join_type = inner_join_t; + + template + void operator()(const L& l) const { + l(*this); + this->super::operator()(l); + } + }; + } +} +#pragma once + +#include // std::string +#include // std::make_tuple, std::tuple_size +#include // std::forward, std::is_base_of, std::enable_if +#include // std::unique_ptr +#include // std::vector + +// #include "conditions.h" + +// #include "operators.h" + +// #include "is_base_of_template.h" + +#include // std::true_type, std::false_type, std::declval + +namespace sqlite_orm { + + namespace internal { + + /* + * This is because of bug in MSVC, for more information, please visit + * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 + */ +#if defined(_MSC_VER) + template class Base, typename Derived> + struct is_base_of_template_impl { + template + static constexpr std::true_type test(const Base*); + + static constexpr std::false_type test(...); + + using type = decltype(test(std::declval())); + }; + + template class Base> + using is_base_of_template = typename is_base_of_template_impl::type; + +#else + template class C, typename... Ts> + std::true_type is_base_of_template_impl(const C*); + + template class C> + std::false_type is_base_of_template_impl(...); + + template class C> + using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); +#endif + } +} + +// #include "serialize_result_type.h" + +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // string_view +#else +#include // std::string +#endif + +namespace sqlite_orm { + namespace internal { +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + using serialize_result_type = std::string_view; +#else + using serialize_result_type = std::string; +#endif + } +} + +namespace sqlite_orm { + + using int64 = sqlite_int64; + using uint64 = sqlite_uint64; + + namespace internal { + + template + struct is_into; + + template + struct unique_ptr_result_of {}; + + /** + * Base class for operator overloading + * R - return type + * S - class with operator std::string + * Args - function arguments types + */ + template + struct built_in_function_t : S, arithmetic_t { + using return_type = R; + using string_type = S; + using args_type = std::tuple; + + static constexpr const size_t args_size = std::tuple_size::value; + + args_type args; + + built_in_function_t(args_type&& args_) : args(std::move(args_)) {} + }; + + struct typeof_string { + serialize_result_type serialize() const { + return "TYPEOF"; + } + }; + + struct unicode_string { + serialize_result_type serialize() const { + return "UNICODE"; + } + }; + + struct length_string { + serialize_result_type serialize() const { + return "LENGTH"; + } + }; + + struct abs_string { + serialize_result_type serialize() const { + return "ABS"; + } + }; + + struct lower_string { + serialize_result_type serialize() const { + return "LOWER"; + } + }; + + struct upper_string { + serialize_result_type serialize() const { + return "UPPER"; + } + }; + + struct last_insert_rowid_string { + serialize_result_type serialize() const { + return "LAST_INSERT_ROWID"; + } + }; + + struct total_changes_string { + serialize_result_type serialize() const { + return "TOTAL_CHANGES"; + } + }; + + struct changes_string { + serialize_result_type serialize() const { + return "CHANGES"; + } + }; + + struct trim_string { + serialize_result_type serialize() const { + return "TRIM"; + } + }; + + struct ltrim_string { + serialize_result_type serialize() const { + return "LTRIM"; + } + }; + + struct rtrim_string { + serialize_result_type serialize() const { + return "RTRIM"; + } + }; + + struct hex_string { + serialize_result_type serialize() const { + return "HEX"; + } + }; + + struct quote_string { + serialize_result_type serialize() const { + return "QUOTE"; + } + }; + + struct randomblob_string { + serialize_result_type serialize() const { + return "RANDOMBLOB"; + } + }; + + struct instr_string { + serialize_result_type serialize() const { + return "INSTR"; + } + }; + + struct replace_string { + serialize_result_type serialize() const { + return "REPLACE"; + } + }; + + struct round_string { + serialize_result_type serialize() const { + return "ROUND"; + } + }; + +#if SQLITE_VERSION_NUMBER >= 3007016 + + struct char_string { + serialize_result_type serialize() const { + return "CHAR"; + } + }; + + struct random_string { + serialize_result_type serialize() const { + return "RANDOM"; + } + }; + +#endif + + struct coalesce_string { + serialize_result_type serialize() const { + return "COALESCE"; + } + }; + + struct ifnull_string { + serialize_result_type serialize() const { + return "IFNULL"; + } + }; + + struct date_string { + serialize_result_type serialize() const { + return "DATE"; + } + }; + + struct time_string { + serialize_result_type serialize() const { + return "TIME"; + } + }; + + struct datetime_string { + serialize_result_type serialize() const { + return "DATETIME"; + } + }; + + struct julianday_string { + serialize_result_type serialize() const { + return "JULIANDAY"; + } + }; + + struct strftime_string { + serialize_result_type serialize() const { + return "STRFTIME"; + } + }; + + struct zeroblob_string { + serialize_result_type serialize() const { + return "ZEROBLOB"; + } + }; + + struct substr_string { + serialize_result_type serialize() const { + return "SUBSTR"; + } + }; +#ifdef SQLITE_SOUNDEX + struct soundex_string { + serialize_result_type serialize() const { + return "SOUNDEX"; + } + }; +#endif + struct total_string { + serialize_result_type serialize() const { + return "TOTAL"; + } + }; + + struct sum_string { + serialize_result_type serialize() const { + return "SUM"; + } + }; + + struct count_string { + serialize_result_type serialize() const { + return "COUNT"; + } + }; + + /** + * T is use to specify type explicitly for queries like + * SELECT COUNT(*) FROM table_name; + * T can be omitted with void. + */ + template + struct count_asterisk_t : count_string { + using type = T; + }; + + /** + * The same thing as count() but without T arg. + * Is used in cases like this: + * SELECT cust_code, cust_name, cust_city, grade + * FROM customer + * WHERE grade=2 AND EXISTS + * (SELECT COUNT(*) + * FROM customer + * WHERE grade=2 + * GROUP BY grade + * HAVING COUNT(*)>2); + * `c++` + * auto rows = + * storage.select(columns(&Customer::code, &Customer::name, &Customer::city, &Customer::grade), + * where(is_equal(&Customer::grade, 2) + * and exists(select(count(), + * where(is_equal(&Customer::grade, 2)), + * group_by(&Customer::grade), + * having(greater_than(count(), 2)))))); + */ + struct count_asterisk_without_type : count_string {}; + + struct avg_string { + serialize_result_type serialize() const { + return "AVG"; + } + }; + + struct max_string { + serialize_result_type serialize() const { + return "MAX"; + } + }; + + struct min_string { + serialize_result_type serialize() const { + return "MIN"; + } + }; + + struct group_concat_string { + serialize_result_type serialize() const { + return "GROUP_CONCAT"; + } + }; +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + struct acos_string { + serialize_result_type serialize() const { + return "ACOS"; + } + }; + + struct acosh_string { + serialize_result_type serialize() const { + return "ACOSH"; + } + }; + + struct asin_string { + serialize_result_type serialize() const { + return "ASIN"; + } + }; + + struct asinh_string { + serialize_result_type serialize() const { + return "ASINH"; + } + }; + + struct atan_string { + serialize_result_type serialize() const { + return "ATAN"; + } + }; + + struct atan2_string { + serialize_result_type serialize() const { + return "ATAN2"; + } + }; + + struct atanh_string { + serialize_result_type serialize() const { + return "ATANH"; + } + }; + + struct ceil_string { + serialize_result_type serialize() const { + return "CEIL"; + } + }; + + struct ceiling_string { + serialize_result_type serialize() const { + return "CEILING"; + } + }; + + struct cos_string { + serialize_result_type serialize() const { + return "COS"; + } + }; + + struct cosh_string { + serialize_result_type serialize() const { + return "COSH"; + } + }; + + struct degrees_string { + serialize_result_type serialize() const { + return "DEGREES"; + } + }; + + struct exp_string { + serialize_result_type serialize() const { + return "EXP"; + } + }; + + struct floor_string { + serialize_result_type serialize() const { + return "FLOOR"; + } + }; + + struct ln_string { + serialize_result_type serialize() const { + return "LN"; + } + }; + + struct log_string { + serialize_result_type serialize() const { + return "LOG"; + } + }; + + struct log10_string { + serialize_result_type serialize() const { + return "LOG10"; + } + }; + + struct log2_string { + serialize_result_type serialize() const { + return "LOG2"; + } + }; + + struct mod_string { + serialize_result_type serialize() const { + return "MOD"; + } + }; + + struct pi_string { + serialize_result_type serialize() const { + return "PI"; + } + }; + + struct pow_string { + serialize_result_type serialize() const { + return "POW"; + } + }; + + struct power_string { + serialize_result_type serialize() const { + return "POWER"; + } + }; + + struct radians_string { + serialize_result_type serialize() const { + return "RADIANS"; + } + }; + + struct sin_string { + serialize_result_type serialize() const { + return "SIN"; + } + }; + + struct sinh_string { + serialize_result_type serialize() const { + return "SINH"; + } + }; + + struct sqrt_string { + serialize_result_type serialize() const { + return "SQRT"; + } + }; + + struct tan_string { + serialize_result_type serialize() const { + return "TAN"; + } + }; + + struct tanh_string { + serialize_result_type serialize() const { + return "TANH"; + } + }; + + struct trunc_string { + serialize_result_type serialize() const { + return "TRUNC"; + } + }; + +#endif // SQLITE_ENABLE_MATH_FUNCTIONS +#ifdef SQLITE_ENABLE_JSON1 + struct json_string { + serialize_result_type serialize() const { + return "JSON"; + } + }; + + struct json_array_string { + serialize_result_type serialize() const { + return "JSON_ARRAY"; + } + }; + + struct json_array_length_string { + serialize_result_type serialize() const { + return "JSON_ARRAY_LENGTH"; + } + }; + + struct json_extract_string { + serialize_result_type serialize() const { + return "JSON_EXTRACT"; + } + }; + + struct json_insert_string { + serialize_result_type serialize() const { + return "JSON_INSERT"; + } + }; + + struct json_replace_string { + serialize_result_type serialize() const { + return "JSON_REPLACE"; + } + }; + + struct json_set_string { + serialize_result_type serialize() const { + return "JSON_SET"; + } + }; + + struct json_object_string { + serialize_result_type serialize() const { + return "JSON_OBJECT"; + } + }; + + struct json_patch_string { + serialize_result_type serialize() const { + return "JSON_PATCH"; + } + }; + + struct json_remove_string { + serialize_result_type serialize() const { + return "JSON_REMOVE"; + } + }; + + struct json_type_string { + serialize_result_type serialize() const { + return "JSON_TYPE"; + } + }; + + struct json_valid_string { + serialize_result_type serialize() const { + return "JSON_VALID"; + } + }; + + struct json_quote_string { + serialize_result_type serialize() const { + return "JSON_QUOTE"; + } + }; + + struct json_group_array_string { + serialize_result_type serialize() const { + return "JSON_GROUP_ARRAY"; + } + }; + + struct json_group_object_string { + serialize_result_type serialize() const { + return "JSON_GROUP_OBJECT"; + } + }; +#endif // SQLITE_ENABLE_JSON1 + } + + /** + * Cute operators for core functions + */ + template::value>::type> + internal::lesser_than_t operator<(F f, R r) { + return {std::move(f), std::move(r)}; + } + + template::value>::type> + internal::lesser_or_equal_t operator<=(F f, R r) { + return {std::move(f), std::move(r)}; + } + + template::value>::type> + internal::greater_than_t operator>(F f, R r) { + return {std::move(f), std::move(r)}; + } + + template::value>::type> + internal::greater_or_equal_t operator>=(F f, R r) { + return {std::move(f), std::move(r)}; + } + + template::value>::type> + internal::is_equal_t operator==(F f, R r) { + return {std::move(f), std::move(r)}; + } + + template::value>::type> + internal::is_not_equal_t operator!=(F f, R r) { + return {std::move(f), std::move(r)}; + } +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + + /** + * ACOS(X) function https://www.sqlite.org/lang_mathfunc.html#acos + * + * Example: + * + * auto rows = storage.select(sqlite_orm::acos(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t acos(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ACOS(X) function https://www.sqlite.org/lang_mathfunc.html#acos + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::acos>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t acos(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ACOSH(X) function https://www.sqlite.org/lang_mathfunc.html#acosh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::acosh(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t acosh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ACOSH(X) function https://www.sqlite.org/lang_mathfunc.html#acosh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::acosh>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t acosh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ASIN(X) function https://www.sqlite.org/lang_mathfunc.html#asin + * + * Example: + * + * auto rows = storage.select(sqlite_orm::asin(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t asin(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ASIN(X) function https://www.sqlite.org/lang_mathfunc.html#asin + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::asin>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t asin(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ASINH(X) function https://www.sqlite.org/lang_mathfunc.html#asinh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::asinh(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t asinh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ASINH(X) function https://www.sqlite.org/lang_mathfunc.html#asinh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::asinh>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t asinh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ATAN(X) function https://www.sqlite.org/lang_mathfunc.html#atan + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atan(1)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t atan(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ATAN(X) function https://www.sqlite.org/lang_mathfunc.html#atan + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atan>(1)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t atan(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ATAN2(X, Y) function https://www.sqlite.org/lang_mathfunc.html#atan2 + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atan2(1, 3)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t atan2(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * ATAN2(X, Y) function https://www.sqlite.org/lang_mathfunc.html#atan2 + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atan2>(1, 3)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t atan2(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * ATANH(X) function https://www.sqlite.org/lang_mathfunc.html#atanh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atanh(1)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t atanh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ATANH(X) function https://www.sqlite.org/lang_mathfunc.html#atanh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::atanh>(1)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t atanh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * CEIL(X) function https://www.sqlite.org/lang_mathfunc.html#ceil + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ceil(&User::rating)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t ceil(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * CEIL(X) function https://www.sqlite.org/lang_mathfunc.html#ceil + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ceil>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t ceil(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * CEILING(X) function https://www.sqlite.org/lang_mathfunc.html#ceil + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ceiling(&User::rating)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t ceiling(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * CEILING(X) function https://www.sqlite.org/lang_mathfunc.html#ceil + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ceiling>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t ceiling(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COS(X) function https://www.sqlite.org/lang_mathfunc.html#cos + * + * Example: + * + * auto rows = storage.select(sqlite_orm::cos(&Triangle::cornerB)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t cos(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COS(X) function https://www.sqlite.org/lang_mathfunc.html#cos + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::cos>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t cos(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COSH(X) function https://www.sqlite.org/lang_mathfunc.html#cosh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::cosh(&Triangle::cornerB)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t cosh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COSH(X) function https://www.sqlite.org/lang_mathfunc.html#cosh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::cosh>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t cosh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * DEGREES(X) function https://www.sqlite.org/lang_mathfunc.html#degrees + * + * Example: + * + * auto rows = storage.select(sqlite_orm::degrees(&Triangle::cornerB)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t degrees(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * DEGREES(X) function https://www.sqlite.org/lang_mathfunc.html#degrees + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::degrees>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t degrees(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * EXP(X) function https://www.sqlite.org/lang_mathfunc.html#exp + * + * Example: + * + * auto rows = storage.select(sqlite_orm::exp(&Triangle::cornerB)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t exp(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * EXP(X) function https://www.sqlite.org/lang_mathfunc.html#exp + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::exp>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t exp(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * FLOOR(X) function https://www.sqlite.org/lang_mathfunc.html#floor + * + * Example: + * + * auto rows = storage.select(sqlite_orm::floor(&User::rating)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t floor(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * FLOOR(X) function https://www.sqlite.org/lang_mathfunc.html#floor + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::floor>(&User::rating)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t floor(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LN(X) function https://www.sqlite.org/lang_mathfunc.html#ln + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ln(200)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t ln(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LN(X) function https://www.sqlite.org/lang_mathfunc.html#ln + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::ln>(200)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t ln(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG(X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log(100)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t log(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG(X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log>(100)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t log(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG10(X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log10(100)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t log10(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG10(X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log10>(100)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t log10(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG(B, X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log(10, 100)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t log(B b, X x) { + return {std::tuple{std::forward(b), std::forward(x)}}; + } + + /** + * LOG(B, X) function https://www.sqlite.org/lang_mathfunc.html#log + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log>(10, 100)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t log(B b, X x) { + return {std::tuple{std::forward(b), std::forward(x)}}; + } + + /** + * LOG2(X) function https://www.sqlite.org/lang_mathfunc.html#log2 + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log2(64)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t log2(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LOG2(X) function https://www.sqlite.org/lang_mathfunc.html#log2 + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::log2>(64)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t log2(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * MOD(X, Y) function https://www.sqlite.org/lang_mathfunc.html#mod + * + * Example: + * + * auto rows = storage.select(sqlite_orm::mod_f(6, 5)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t mod_f(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * MOD(X, Y) function https://www.sqlite.org/lang_mathfunc.html#mod + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::mod_f>(6, 5)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t mod_f(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * PI() function https://www.sqlite.org/lang_mathfunc.html#pi + * + * Example: + * + * auto rows = storage.select(sqlite_orm::pi()); // decltype(rows) is std::vector + */ + inline internal::built_in_function_t pi() { + return {{}}; + } + + /** + * PI() function https://www.sqlite.org/lang_mathfunc.html#pi + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, etc. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::pi()); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t pi() { + return {{}}; + } + + /** + * POW(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow + * + * Example: + * + * auto rows = storage.select(sqlite_orm::pow(2, 5)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t pow(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * POW(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::pow>(2, 5)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t pow(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * POWER(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow + * + * Example: + * + * auto rows = storage.select(sqlite_orm::power(2, 5)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t power(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * POWER(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::power>(2, 5)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t power(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * RADIANS(X) function https://www.sqlite.org/lang_mathfunc.html#radians + * + * Example: + * + * auto rows = storage.select(sqlite_orm::radians(&Triangle::cornerAInDegrees)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t radians(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * RADIANS(X) function https://www.sqlite.org/lang_mathfunc.html#radians + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::radians>(&Triangle::cornerAInDegrees)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t radians(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SIN(X) function https://www.sqlite.org/lang_mathfunc.html#sin + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sin(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t sin(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SIN(X) function https://www.sqlite.org/lang_mathfunc.html#sin + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sin>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t sin(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SINH(X) function https://www.sqlite.org/lang_mathfunc.html#sinh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sinh(&Triangle::cornerA)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t sinh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SINH(X) function https://www.sqlite.org/lang_mathfunc.html#sinh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sinh>(&Triangle::cornerA)); // decltype(rows) is std::vector> + */ + template + internal::built_in_function_t sinh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SQRT(X) function https://www.sqlite.org/lang_mathfunc.html#sqrt + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sqrt(25)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t sqrt(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SQRT(X) function https://www.sqlite.org/lang_mathfunc.html#sqrt + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::sqrt(25)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t sqrt(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TAN(X) function https://www.sqlite.org/lang_mathfunc.html#tan + * + * Example: + * + * auto rows = storage.select(sqlite_orm::tan(&Triangle::cornerC)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t tan(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TAN(X) function https://www.sqlite.org/lang_mathfunc.html#tan + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::tan(&Triangle::cornerC)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t tan(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TANH(X) function https://www.sqlite.org/lang_mathfunc.html#tanh + * + * Example: + * + * auto rows = storage.select(sqlite_orm::tanh(&Triangle::cornerC)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t tanh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TANH(X) function https://www.sqlite.org/lang_mathfunc.html#tanh + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::tanh(&Triangle::cornerC)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t tanh(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TRUNC(X) function https://www.sqlite.org/lang_mathfunc.html#trunc + * + * Example: + * + * auto rows = storage.select(sqlite_orm::trunc(5.5)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t trunc(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * TRUNC(X) function https://www.sqlite.org/lang_mathfunc.html#trunc + * + * Difference with the previous function is that previous override has `double` as return type but this + * override accepts return type from you as a template argument. You can use any bindable type: + * `float`, `int`, `std::optional` etc. This override is handy when you expect `null` as result. + * + * Example: + * + * auto rows = storage.select(sqlite_orm::trunc(5.5)); // decltype(rows) is std::vector + */ + template + internal::built_in_function_t trunc(X x) { + return {std::tuple{std::forward(x)}}; + } +#endif // SQLITE_ENABLE_MATH_FUNCTIONS + /** + * TYPEOF(x) function https://sqlite.org/lang_corefunc.html#typeof + */ + template + internal::built_in_function_t typeof_(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * UNICODE(x) function https://sqlite.org/lang_corefunc.html#unicode + */ + template + internal::built_in_function_t unicode(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * LENGTH(x) function https://sqlite.org/lang_corefunc.html#length + */ + template + internal::built_in_function_t length(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * ABS(x) function https://sqlite.org/lang_corefunc.html#abs + */ + template + internal::built_in_function_t, internal::abs_string, T> abs(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * LOWER(x) function https://sqlite.org/lang_corefunc.html#lower + */ + template + internal::built_in_function_t lower(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * UPPER(x) function https://sqlite.org/lang_corefunc.html#upper + */ + template + internal::built_in_function_t upper(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * LAST_INSERT_ROWID(x) function https://www.sqlite.org/lang_corefunc.html#last_insert_rowid + */ + inline internal::built_in_function_t last_insert_rowid() { + return {{}}; + } + + /** + * TOTAL_CHANGES() function https://sqlite.org/lang_corefunc.html#total_changes + */ + inline internal::built_in_function_t total_changes() { + return {{}}; + } + + /** + * CHANGES() function https://sqlite.org/lang_corefunc.html#changes + */ + inline internal::built_in_function_t changes() { + return {{}}; + } + + /** + * TRIM(X) function https://sqlite.org/lang_corefunc.html#trim + */ + template + internal::built_in_function_t trim(T t) { + return {std::tuple{std::forward(t)}}; + } + + /** + * TRIM(X,Y) function https://sqlite.org/lang_corefunc.html#trim + */ + template + internal::built_in_function_t trim(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * LTRIM(X) function https://sqlite.org/lang_corefunc.html#ltrim + */ + template + internal::built_in_function_t ltrim(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * LTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#ltrim + */ + template + internal::built_in_function_t ltrim(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * RTRIM(X) function https://sqlite.org/lang_corefunc.html#rtrim + */ + template + internal::built_in_function_t rtrim(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * RTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#rtrim + */ + template + internal::built_in_function_t rtrim(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * HEX(X) function https://sqlite.org/lang_corefunc.html#hex + */ + template + internal::built_in_function_t hex(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * QUOTE(X) function https://sqlite.org/lang_corefunc.html#quote + */ + template + internal::built_in_function_t quote(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * RANDOMBLOB(X) function https://sqlite.org/lang_corefunc.html#randomblob + */ + template + internal::built_in_function_t, internal::randomblob_string, X> randomblob(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * INSTR(X) function https://sqlite.org/lang_corefunc.html#instr + */ + template + internal::built_in_function_t instr(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * REPLACE(X) function https://sqlite.org/lang_corefunc.html#replace + */ + template + typename std::enable_if, internal::is_into>::value == 0, + internal::built_in_function_t>::type + replace(X x, Y y, Z z) { + return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + } + + /** + * ROUND(X) function https://sqlite.org/lang_corefunc.html#round + */ + template + internal::built_in_function_t round(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * ROUND(X, Y) function https://sqlite.org/lang_corefunc.html#round + */ + template + internal::built_in_function_t round(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + +#if SQLITE_VERSION_NUMBER >= 3007016 + + /** + * CHAR(X1,X2,...,XN) function https://sqlite.org/lang_corefunc.html#char + */ + template + internal::built_in_function_t char_(Args... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * RANDOM() function https://www.sqlite.org/lang_corefunc.html#random + */ + inline internal::built_in_function_t random() { + return {{}}; + } + +#endif + + /** + * COALESCE(X,Y,...) function https://www.sqlite.org/lang_corefunc.html#coalesce + */ + template + internal::built_in_function_t coalesce(Args... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * IFNULL(X,Y) function https://www.sqlite.org/lang_corefunc.html#ifnull + */ + template + internal::built_in_function_t ifnull(X x, Y y) { + return {std::make_tuple(std::move(x), std::move(y))}; + } + + /** + * DATE(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html + */ + template + internal::built_in_function_t date(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + /** + * TIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html + */ + template + internal::built_in_function_t time(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + /** + * DATETIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html + */ + template + internal::built_in_function_t datetime(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + /** + * JULIANDAY(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html + */ + template + internal::built_in_function_t julianday(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + /** + * STRFTIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html + */ + template + internal::built_in_function_t strftime(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + /** + * ZEROBLOB(N) function https://www.sqlite.org/lang_corefunc.html#zeroblob + */ + template + internal::built_in_function_t, internal::zeroblob_string, N> zeroblob(N n) { + return {std::tuple{std::forward(n)}}; + } + + /** + * SUBSTR(X,Y) function https://www.sqlite.org/lang_corefunc.html#substr + */ + template + internal::built_in_function_t substr(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + /** + * SUBSTR(X,Y,Z) function https://www.sqlite.org/lang_corefunc.html#substr + */ + template + internal::built_in_function_t substr(X x, Y y, Z z) { + return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + } + +#ifdef SQLITE_SOUNDEX + /** + * SOUNDEX(X) function https://www.sqlite.org/lang_corefunc.html#soundex + */ + template + internal::core_function_t soundex(X x) { + return {std::tuple{std::forward(x)}}; + } +#endif + + /** + * TOTAL(X) aggregate function. + */ + template + internal::built_in_function_t total(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * SUM(X) aggregate function. + */ + template + internal::built_in_function_t, internal::sum_string, X> sum(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COUNT(X) aggregate function. + */ + template + internal::built_in_function_t count(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * COUNT(*) without FROM function. + */ + inline internal::count_asterisk_without_type count() { + return {}; + } + + /** + * COUNT(*) with FROM function. Specified type T will be serializeed as + * a from argument. + */ + template + internal::count_asterisk_t count() { + return {}; + } + + /** + * AVG(X) aggregate function. + */ + template + internal::built_in_function_t avg(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * MAX(X) aggregate function. + */ + template + internal::built_in_function_t, internal::max_string, X> max(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * MIN(X) aggregate function. + */ + template + internal::built_in_function_t, internal::min_string, X> min(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * GROUP_CONCAT(X) aggregate function. + */ + template + internal::built_in_function_t group_concat(X x) { + return {std::tuple{std::forward(x)}}; + } + + /** + * GROUP_CONCAT(X, Y) aggregate function. + */ + template + internal::built_in_function_t group_concat(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } +#ifdef SQLITE_ENABLE_JSON1 + template + internal::built_in_function_t json(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_array(Args... args) { + return {std::tuple{std::forward(args)...}}; + } + + template + internal::built_in_function_t json_array_length(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_array_length(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_array_length(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + template + internal::built_in_function_t json_array_length(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + template + internal::built_in_function_t json_extract(X x, Args... args) { + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_insert(X x, + Args... args) { + static_assert(std::tuple_size>::value % 2 == 0, + "number of arguments in json_insert must be odd"); + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_replace(X x, + Args... args) { + static_assert(std::tuple_size>::value % 2 == 0, + "number of arguments in json_replace must be odd"); + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_set(X x, Args... args) { + static_assert(std::tuple_size>::value % 2 == 0, + "number of arguments in json_set must be odd"); + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_object(Args... args) { + static_assert(std::tuple_size>::value % 2 == 0, + "number of arguments in json_object must be even"); + return {std::tuple{std::forward(args)...}}; + } + + template + internal::built_in_function_t json_patch(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + template + internal::built_in_function_t json_remove(X x, + Args... args) { + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_remove(X x, Args... args) { + return {std::tuple{std::forward(x), std::forward(args)...}}; + } + + template + internal::built_in_function_t json_type(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_type(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_type(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + template + internal::built_in_function_t json_type(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + + template + internal::built_in_function_t json_valid(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_quote(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_group_array(X x) { + return {std::tuple{std::forward(x)}}; + } + + template + internal::built_in_function_t json_group_object(X x, Y y) { + return {std::tuple{std::forward(x), std::forward(y)}}; + } + +#endif // SQLITE_ENABLE_JSON1 + template::value + + std::is_base_of::value > + 0)>::type> + internal::add_t operator+(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template::value + + std::is_base_of::value > + 0)>::type> + internal::sub_t operator-(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template::value + + std::is_base_of::value > + 0)>::type> + internal::mul_t operator*(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template::value + + std::is_base_of::value > + 0)>::type> + internal::div_t operator/(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template::value + + std::is_base_of::value > + 0)>::type> + internal::mod_t operator%(L l, R r) { + return {std::move(l), std::move(r)}; + } +} +#pragma once + +namespace sqlite_orm { + + namespace internal { + + /** + * Cute class used to compare setters/getters and member pointers with each other. + */ + template + struct typed_comparator { + bool operator()(const L&, const R&) const { + return false; + } + }; + + template + struct typed_comparator { + bool operator()(const O& lhs, const O& rhs) const { + return lhs == rhs; + } + }; + + template + bool compare_any(const L& lhs, const R& rhs) { + return typed_comparator()(lhs, rhs); + } + } +} +#pragma once + +#include // std::string +#include // std::declval +#include // std::tuple, std::get, std::tuple_size +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +// #include "is_base_of_template.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "optional_container.h" + +// #include "ast/where.h" + +// #include "../serialize_result_type.h" + +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // string_view +#else +#include // std::string +#endif + +namespace sqlite_orm { + namespace internal { +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + using serialize_result_type = std::string_view; +#else + using serialize_result_type = std::string; +#endif + } +} + +namespace sqlite_orm { + namespace internal { + + struct where_string { + serialize_result_type serialize() const { + return "WHERE"; + } + }; + + /** + * WHERE argument holder. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * Don't construct it manually. Call `where(...)` function instead. + */ + template + struct where_t : where_string { + using expression_type = C; + + expression_type expression; + + where_t(expression_type expression_) : expression(std::move(expression_)) {} + }; + + template + struct is_where : std::false_type {}; + + template + struct is_where> : std::true_type {}; + } + + /** + * WHERE clause. Use it to add WHERE conditions wherever you like. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * @example + * // SELECT name + * // FROM letters + * // WHERE id > 3 + * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3))); + */ + template + internal::where_t where(C expression) { + return {std::move(expression)}; + } +} + +namespace sqlite_orm { + + namespace internal { +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct as_optional_t { + using value_type = T; + + value_type value; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + struct distinct_string { + operator std::string() const { + return "DISTINCT"; + } + }; + + /** + * DISCTINCT generic container. + */ + template + struct distinct_t : distinct_string { + using value_type = T; + + value_type value; + + distinct_t(value_type value_) : value(std::move(value_)) {} + }; + + struct all_string { + operator std::string() const { + return "ALL"; + } + }; + + /** + * ALL generic container. + */ + template + struct all_t : all_string { + T value; + + all_t(T value_) : value(std::move(value_)) {} + }; + + template + struct columns_t { + using columns_type = std::tuple; + + columns_type columns; + bool distinct = false; + + static constexpr const int count = std::tuple_size::value; + }; + + template + struct is_columns : std::false_type {}; + + template + struct is_columns> : std::true_type {}; + + struct set_string { + operator std::string() const { + return "SET"; + } + }; + + template + struct set_t : set_string { + using assigns_type = std::tuple; + + assigns_type assigns; + + set_t(assigns_type assigns_) : assigns(move(assigns_)) {} + }; + + /** + * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). + * Is useful when mapped type is derived from other type and base class has members mapped to a storage. + */ + template + struct column_pointer { + using self = column_pointer; + using type = T; + using field_type = F; + + field_type field; + + template + internal::is_equal_t operator==(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + internal::is_not_equal_t operator!=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + internal::lesser_than_t operator<(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + internal::lesser_or_equal_t operator<=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + internal::greater_than_t operator>(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + internal::greater_or_equal_t operator>=(R rhs) const { + return {*this, std::move(rhs)}; + } + }; + + /** + * Subselect object type. + */ + template + struct select_t { + using return_type = T; + using conditions_type = std::tuple; + + return_type col; + conditions_type conditions; + bool highest_level = false; + }; + + template + struct is_select : std::false_type {}; + + template + struct is_select> : std::true_type {}; + + /** + * Base for UNION, UNION ALL, EXCEPT and INTERSECT + */ + template + struct compound_operator { + using left_type = L; + using right_type = R; + + left_type left; + right_type right; + + compound_operator(left_type l, right_type r) : left(std::move(l)), right(std::move(r)) { + this->left.highest_level = true; + this->right.highest_level = true; + } + }; + + struct union_base { + bool all = false; + + operator std::string() const { + if(!this->all) { + return "UNION"; + } else { + return "UNION ALL"; + } + } + }; + + /** + * UNION object type. + */ + template + struct union_t : public compound_operator, union_base { + using left_type = typename compound_operator::left_type; + using right_type = typename compound_operator::right_type; + + union_t(left_type l, right_type r, decltype(all) all_) : + compound_operator(std::move(l), std::move(r)), union_base{all_} {} + + union_t(left_type l, right_type r) : union_t(std::move(l), std::move(r), false) {} + }; + + struct except_string { + operator std::string() const { + return "EXCEPT"; + } + }; + + /** + * EXCEPT object type. + */ + template + struct except_t : compound_operator, except_string { + using super = compound_operator; + using left_type = typename super::left_type; + using right_type = typename super::right_type; + + using super::super; + }; + + struct intersect_string { + operator std::string() const { + return "INTERSECT"; + } + }; + /** + * INTERSECT object type. + */ + template + struct intersect_t : compound_operator, intersect_string { + using super = compound_operator; + using left_type = typename super::left_type; + using right_type = typename super::right_type; + + using super::super; + }; + + /** + * Generic way to get DISTINCT value from any type. + */ + template + bool get_distinct(const T&) { + return false; + } + + template + bool get_distinct(const columns_t& cols) { + return cols.distinct; + } + + template + struct asterisk_t { + using type = T; + }; + + template + struct object_t { + using type = T; + }; + + template + struct then_t { + using expression_type = T; + + expression_type expression; + }; + + template + struct simple_case_t { + using return_type = R; + using case_expression_type = T; + using args_type = std::tuple; + using else_expression_type = E; + + optional_container case_expression; + args_type args; + optional_container else_expression; + }; + + /** + * T is a case expression type + * E is else type (void is ELSE is omitted) + * Args... is a pack of WHEN expressions + */ + template + struct simple_case_builder { + using return_type = R; + using case_expression_type = T; + using args_type = std::tuple; + using else_expression_type = E; + + optional_container case_expression; + args_type args; + optional_container else_expression; + + template + simple_case_builder> when(W w, then_t t) { + using result_args_type = std::tuple>; + std::pair newPair{std::move(w), std::move(t.expression)}; + result_args_type result_args = + std::tuple_cat(std::move(this->args), std::move(std::make_tuple(newPair))); + std::get::value - 1>(result_args) = std::move(newPair); + return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; + } + + simple_case_t end() { + return {std::move(this->case_expression), std::move(args), std::move(this->else_expression)}; + } + + template + simple_case_builder else_(El el) { + return {{std::move(this->case_expression)}, std::move(args), {std::move(el)}}; + } + }; + + template + void validate_conditions() { + static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 WHERE blocks"); + static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 GROUP BY blocks"); + static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 ORDER BY blocks"); + static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 LIMIT blocks"); + static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 FROM blocks"); + } + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + internal::as_optional_t as_optional(T value) { + return {std::move(value)}; + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + internal::then_t then(T t) { + return {std::move(t)}; + } + + template + internal::simple_case_builder case_(T t) { + return {{std::move(t)}}; + } + + template + internal::simple_case_builder case_() { + return {}; + } + + template + internal::distinct_t distinct(T t) { + return {std::move(t)}; + } + + template + internal::all_t all(T t) { + return {std::move(t)}; + } + + template + internal::columns_t distinct(internal::columns_t cols) { + cols.distinct = true; + return cols; + } + + /** + * SET keyword used in UPDATE ... SET queries. + * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) + */ + template + internal::set_t set(Args... args) { + using arg_tuple = std::tuple; + static_assert(std::tuple_size::value == + internal::count_tuple::value, + "set function accepts assign operators only"); + return {std::make_tuple(std::forward(args)...)}; + } + + template + internal::columns_t columns(Args... args) { + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * Use it like this: + * struct MyType : BaseType { ... }; + * storage.select(column(&BaseType::id)); + */ + template + internal::column_pointer column(F f) { + return {std::move(f)}; + } + + /** + * Public function for subselect query. Is useful in UNION queries. + */ + template + internal::select_t select(T t, Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + return {std::move(t), std::make_tuple(std::forward(args)...)}; + } + + /** + * Public function for UNION operator. + * lhs and rhs are subselect objects. + * Look through example in examples/union.cpp + */ + template + internal::union_t union_(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs)}; + } + + /** + * Public function for EXCEPT operator. + * lhs and rhs are subselect objects. + * Look through example in examples/except.cpp + */ + template + internal::except_t except(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs)}; + } + + template + internal::intersect_t intersect(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs)}; + } + + /** + * Public function for UNION ALL operator. + * lhs and rhs are subselect objects. + * Look through example in examples/union.cpp + */ + template + internal::union_t union_all(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs), true}; + } + + /** + * SELECT * FROM T function. + * T is typed mapped to a storage. + * Example: auto rows = storage.select(asterisk()); + * // decltype(rows) is std::vector> + * If you need to fetch result as objects not tuple please use `object` instead. + */ + template + internal::asterisk_t asterisk() { + return {}; + } + + /** + * SELECT * FROM T function. + * T is typed mapped to a storage. + * Example: auto rows = storage.select(object()); + * // decltype(rows) is std::vector + * If you need to fetch result as tuples not objects please use `asterisk` instead. + */ + template + internal::object_t object() { + return {}; + } +} +#pragma once + +#include // std::string + +namespace sqlite_orm { + + struct table_info { + int cid = 0; + std::string name; + std::string type; + bool notnull = false; + std::string dflt_value; + int pk = 0; + + table_info(decltype(cid) cid_, + decltype(name) name_, + decltype(type) type_, + decltype(notnull) notnull_, + decltype(dflt_value) dflt_value_, + decltype(pk) pk_) : + cid(cid_), + name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), pk(pk_) {} + }; + +} +#pragma once + +#include // std::unique_ptr +#include +#include // std::integral_constant + +namespace sqlite_orm { + + /** + * Guard class which finalizes `sqlite3_stmt` in dtor + */ + using statement_finalizer = + std::unique_ptr>; + +} +#pragma once + +namespace sqlite_orm { + + /** + * Helper classes used by statement_binder and row_extractor. + */ + struct int_or_smaller_tag {}; + struct bigint_tag {}; + struct real_tag {}; + + template + struct arithmetic_tag { + using type = std::conditional_t::value, + // Integer class + std::conditional_t, + // Floating-point class + real_tag>; + }; + + template + using arithmetic_tag_t = typename arithmetic_tag::type; +} +#pragma once + +#include +#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type +#include // std::string, std::wstring +#ifndef SQLITE_ORM_OMITS_CODECVT +#include // std::codecvt_utf8_utf16 +#endif // SQLITE_ORM_OMITS_CODECVT +#include // std::vector +#include // std::nullptr_t +#include // std::declval +#include // std::wstring_convert +#include // ::strncpy, ::strlen + +// #include "is_std_ptr.h" + +namespace sqlite_orm { + + /** + * Specialization for optional type (std::shared_ptr / std::unique_ptr). + */ + template + struct is_std_ptr : std::false_type {}; + + template + struct is_std_ptr> : std::true_type { + using element_type = T; + + static std::shared_ptr make(const T& v) { + return std::make_shared(v); + } + }; + + template + struct is_std_ptr> : std::true_type { + using element_type = T; + + static std::unique_ptr make(const T& v) { + return std::make_unique(v); + } + }; +} + +namespace sqlite_orm { + + /** + * Helper class used for binding fields to sqlite3 statements. + */ + template + struct statement_binder : std::false_type {}; + + /** + * Specialization for arithmetic types. + */ + template + struct statement_binder::value>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + return this->bind(stmt, index, value, tag()); + } + + void result(sqlite3_context* context, const V& value) const { + this->result(context, value, tag()); + } + + private: + using tag = arithmetic_tag_t; + + int bind(sqlite3_stmt* stmt, int index, const V& value, const int_or_smaller_tag&) const { + return sqlite3_bind_int(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, const int_or_smaller_tag&) const { + sqlite3_result_int(context, static_cast(value)); + } + + int bind(sqlite3_stmt* stmt, int index, const V& value, const bigint_tag&) const { + return sqlite3_bind_int64(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, const bigint_tag&) const { + sqlite3_result_int64(context, static_cast(value)); + } + + int bind(sqlite3_stmt* stmt, int index, const V& value, const real_tag&) const { + return sqlite3_bind_double(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, const real_tag&) const { + sqlite3_result_double(context, static_cast(value)); + } + }; + + /** + * Specialization for std::string and C-string. + */ + template + struct statement_binder< + V, + std::enable_if_t::value || std::is_same::value>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + auto stringData = this->string_data(value); + return sqlite3_bind_text(stmt, index, std::get<0>(stringData), std::get<1>(stringData), SQLITE_TRANSIENT); + } + + void result(sqlite3_context* context, const V& value) const { + auto stringData = this->string_data(value); + auto stringDataLength = std::get<1>(stringData); + auto dataCopy = new char[stringDataLength + 1]; + auto stringChars = std::get<0>(stringData); + ::strncpy(dataCopy, stringChars, stringDataLength + 1); + sqlite3_result_text(context, dataCopy, stringDataLength, [](void* pointer) { + auto charPointer = (char*)pointer; + delete[] charPointer; + }); + } + + private: + std::tuple string_data(const std::string& s) const { + return {s.c_str(), int(s.size())}; + } + + std::tuple string_data(const char* s) const { + auto length = int(::strlen(s)); + return {s, length}; + } + }; + +#ifndef SQLITE_ORM_OMITS_CODECVT + /** + * Specialization for std::wstring and C-wstring. + */ + template + struct statement_binder< + V, + std::enable_if_t::value || std::is_same::value>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + std::wstring_convert> converter; + std::string utf8Str = converter.to_bytes(value); + return statement_binder().bind(stmt, index, utf8Str); + } + + void result(sqlite3_context* context, const V& value) const { + sqlite3_result_text16(context, (const void*)value.data(), int(value.length()), nullptr); + } + }; +#endif // SQLITE_ORM_OMITS_CODECVT + + /** + * Specialization for std::nullptr_t. + */ + template<> + struct statement_binder { + int bind(sqlite3_stmt* stmt, int index, const std::nullptr_t&) const { + return sqlite3_bind_null(stmt, index); + } + + void result(sqlite3_context* context, const std::nullptr_t&) const { + sqlite3_result_null(context); + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * Specialization for std::nullopt_t. + */ + template<> + struct statement_binder { + int bind(sqlite3_stmt* stmt, int index, const std::nullopt_t&) const { + return sqlite3_bind_null(stmt, index); + } + + void result(sqlite3_context* context, const std::nullopt_t&) const { + sqlite3_result_null(context); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct statement_binder::value>> { + using value_type = typename is_std_ptr::element_type; + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + if(value) { + return statement_binder().bind(stmt, index, *value); + } else { + return statement_binder().bind(stmt, index, nullptr); + } + } + + void result(sqlite3_context* context, const V& value) const { + if(value) { + statement_binder().result(context, value); + } else { + statement_binder().result(context, nullptr); + } + } + }; + + /** + * Specialization for optional type (std::vector). + */ + template<> + struct statement_binder, void> { + int bind(sqlite3_stmt* stmt, int index, const std::vector& value) const { + if(value.size()) { + return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT); + } else { + return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT); + } + } + + void result(sqlite3_context* context, const std::vector& value) const { + if(value.size()) { + sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr); + } else { + sqlite3_result_blob(context, "", 0, nullptr); + } + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_binder, void> { + using value_type = T; + + int bind(sqlite3_stmt* stmt, int index, const std::optional& value) const { + if(value) { + return statement_binder().bind(stmt, index, *value); + } else { + return statement_binder().bind(stmt, index, std::nullopt); + } + } + + void result(sqlite3_context* context, const std::optional& value) const { + if(value) { + statement_binder().result(context, value); + } else { + statement_binder().result(context, std::nullopt); + } + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + namespace internal { + + template + using is_bindable = std::integral_constant>::value>; + + struct conditional_binder_base { + sqlite3_stmt* stmt = nullptr; + int& index; + + conditional_binder_base(decltype(stmt) stmt_, decltype(index) index_) : stmt(stmt_), index(index_) {} + }; + + template + struct conditional_binder; + + template + struct conditional_binder : conditional_binder_base { + + using conditional_binder_base::conditional_binder_base; + + int operator()(const T& t) const { + return statement_binder().bind(this->stmt, this->index++, t); + } + }; + + template + struct conditional_binder : conditional_binder_base { + using conditional_binder_base::conditional_binder_base; + + int operator()(const T&) const { + return SQLITE_OK; + } + }; + + template class F, class SFINAE = void> + struct tuple_filter_single; + + template class F> + struct tuple_filter_single::value>::type> { + using type = std::tuple; + }; + + template class F> + struct tuple_filter_single::value>::type> { + using type = std::tuple<>; + }; + + template class F> + struct tuple_filter; + + template class F> + struct tuple_filter, F> { + using type = typename conc_tuple::type...>::type; + }; + + template + struct bindable_filter_single : tuple_filter_single {}; + + template + struct bindable_filter; + + template + struct bindable_filter> { + using type = typename conc_tuple::type...>::type; + }; + } +} +#pragma once + +#include +#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::enable_if +#include // atof, atoi, atoll +#include // std::string, std::wstring +#ifndef SQLITE_ORM_OMITS_CODECVT +#include // std::wstring_convert, std::codecvt_utf8_utf16 +#endif // SQLITE_ORM_OMITS_CODECVT +#include // std::vector +#include // strlen +#include // std::copy +#include // std::back_inserter +#include // std::tuple, std::tuple_size, std::tuple_element + +// #include "arithmetic_tag.h" + +// #include "journal_mode.h" + +#include // std::string +#include // std::unique_ptr +#include // std::array +#include // std::transform +#include // std::toupper + +namespace sqlite_orm { + +/** + * Caps case cause of 1) delete keyword; 2) https://www.sqlite.org/pragma.html#pragma_journal_mode original spelling + */ +#ifdef DELETE +#undef DELETE +#endif + enum class journal_mode : signed char { + DELETE = 0, + TRUNCATE = 1, + PERSIST = 2, + MEMORY = 3, + WAL = 4, + OFF = 5, + }; + + namespace internal { + + inline const std::string& to_string(journal_mode j) { + static std::string res[] = { + "DELETE", + "TRUNCATE", + "PERSIST", + "MEMORY", + "WAL", + "OFF", + }; + return res[static_cast(j)]; + } + + inline std::unique_ptr journal_mode_from_string(const std::string& str) { + std::string upper_str; + std::transform(str.begin(), str.end(), std::back_inserter(upper_str), [](char c) { + return static_cast(std::toupper(static_cast(c))); + }); + static std::array all = {{ + journal_mode::DELETE, + journal_mode::TRUNCATE, + journal_mode::PERSIST, + journal_mode::MEMORY, + journal_mode::WAL, + journal_mode::OFF, + }}; + for(auto j: all) { + if(to_string(j) == upper_str) { + return std::make_unique(j); + } + } + return {}; + } + } +} + +// #include "error_code.h" + +namespace sqlite_orm { + + /** + * Helper class used to cast values from argv to V class + * which depends from column type. + * + */ + template + struct row_extractor { + // used in sqlite3_exec (select) + V extract(const char* row_value) const; + + // used in sqlite_column (iteration, get_all) + V extract(sqlite3_stmt* stmt, int columnIndex) const; + + // used in user defined functions + V extract(sqlite3_value* value) const; + }; + + /** + * Specialization for arithmetic types. + */ + template + struct row_extractor::value>> { + V extract(const char* row_value) const { + return this->extract(row_value, tag()); + } + + V extract(sqlite3_stmt* stmt, int columnIndex) const { + return this->extract(stmt, columnIndex, tag()); + } + + V extract(sqlite3_value* value) const { + return this->extract(value, tag()); + } + + private: + using tag = arithmetic_tag_t; + + V extract(const char* row_value, const int_or_smaller_tag&) const { + return static_cast(atoi(row_value)); + } + + V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { + return static_cast(sqlite3_column_int(stmt, columnIndex)); + } + + V extract(sqlite3_value* value, const int_or_smaller_tag&) const { + return static_cast(sqlite3_value_int(value)); + } + + V extract(const char* row_value, const bigint_tag&) const { + return static_cast(atoll(row_value)); + } + + V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { + return static_cast(sqlite3_column_int64(stmt, columnIndex)); + } + + V extract(sqlite3_value* value, const bigint_tag&) const { + return static_cast(sqlite3_value_int64(value)); + } + + V extract(const char* row_value, const real_tag&) const { + return static_cast(atof(row_value)); + } + + V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { + return static_cast(sqlite3_column_double(stmt, columnIndex)); + } + + V extract(sqlite3_value* value, const real_tag&) const { + return static_cast(sqlite3_value_double(value)); + } + }; + + /** + * Specialization for std::string. + */ + template<> + struct row_extractor { + std::string extract(const char* row_value) const { + if(row_value) { + return row_value; + } else { + return {}; + } + } + + std::string extract(sqlite3_stmt* stmt, int columnIndex) const { + if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { + return cStr; + } else { + return {}; + } + } + + std::string extract(sqlite3_value* value) const { + if(auto cStr = (const char*)sqlite3_value_text(value)) { + return cStr; + } else { + return {}; + } + } + }; +#ifndef SQLITE_ORM_OMITS_CODECVT + /** + * Specialization for std::wstring. + */ + template<> + struct row_extractor { + std::wstring extract(const char* row_value) const { + if(row_value) { + std::wstring_convert> converter; + return converter.from_bytes(row_value); + } else { + return {}; + } + } + + std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + if(cStr) { + std::wstring_convert> converter; + return converter.from_bytes(cStr); + } else { + return {}; + } + } + + std::wstring extract(sqlite3_value* value) const { + if(auto cStr = (const wchar_t*)sqlite3_value_text16(value)) { + return cStr; + } else { + return {}; + } + } + }; +#endif // SQLITE_ORM_OMITS_CODECVT + + template + struct row_extractor::value>> { + using value_type = typename is_std_ptr::element_type; + + V extract(const char* row_value) const { + if(row_value) { + return is_std_ptr::make(row_extractor().extract(row_value)); + } else { + return {}; + } + } + + V extract(sqlite3_stmt* stmt, int columnIndex) const { + auto type = sqlite3_column_type(stmt, columnIndex); + if(type != SQLITE_NULL) { + return is_std_ptr::make(row_extractor().extract(stmt, columnIndex)); + } else { + return {}; + } + } + + V extract(sqlite3_value* value) const { + auto type = sqlite3_value_type(value); + if(type != SQLITE_NULL) { + return is_std_ptr::make(row_extractor().extract(value)); + } else { + return {}; + } + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct row_extractor, void> { + using value_type = T; + + std::optional extract(const char* row_value) const { + if(row_value) { + return std::make_optional(row_extractor().extract(row_value)); + } else { + return std::nullopt; + } + } + + std::optional extract(sqlite3_stmt* stmt, int columnIndex) const { + auto type = sqlite3_column_type(stmt, columnIndex); + if(type != SQLITE_NULL) { + return std::make_optional(row_extractor().extract(stmt, columnIndex)); + } else { + return std::nullopt; + } + } + + std::optional extract(sqlite3_value* value) const { + auto type = sqlite3_value_type(value); + if(type != SQLITE_NULL) { + return std::make_optional(row_extractor().extract(value)); + } else { + return std::nullopt; + } + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * Specialization for std::vector. + */ + template<> + struct row_extractor> { + std::vector extract(const char* row_value) const { + if(row_value) { + auto len = ::strlen(row_value); + return this->go(row_value, len); + } else { + return {}; + } + } + + std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { + auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); + auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); + return this->go(bytes, len); + } + + std::vector extract(sqlite3_value* value) const { + auto bytes = static_cast(sqlite3_value_blob(value)); + auto len = static_cast(sqlite3_value_bytes(value)); + return this->go(bytes, len); + } + + protected: + std::vector go(const char* bytes, size_t len) const { + if(len) { + std::vector res; + res.reserve(len); + std::copy(bytes, bytes + len, std::back_inserter(res)); + return res; + } else { + return {}; + } + } + }; + + template + struct row_extractor> { + + std::tuple extract(char** argv) const { + std::tuple res; + this->extract::value>(res, argv); + return res; + } + + std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { + std::tuple res; + this->extract::value>(res, stmt); + return res; + } + + protected: + template::type* = nullptr> + void extract(std::tuple& t, sqlite3_stmt* stmt) const { + using tuple_type = typename std::tuple_element>::type; + std::get(t) = row_extractor().extract(stmt, I - 1); + this->extract(t, stmt); + } + + template::type* = nullptr> + void extract(std::tuple&, sqlite3_stmt*) const { + //.. + } + + template::type* = nullptr> + void extract(std::tuple& t, char** argv) const { + using tuple_type = typename std::tuple_element>::type; + std::get(t) = row_extractor().extract(argv[I - 1]); + this->extract(t, argv); + } + + template::type* = nullptr> + void extract(std::tuple&, char**) const { + //.. + } + }; + + /** + * Specialization for journal_mode. + */ + template<> + struct row_extractor { + journal_mode extract(const char* row_value) const { + if(row_value) { + if(auto res = internal::journal_mode_from_string(row_value)) { + return std::move(*res); + } else { + throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); + } + } else { + throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); + } + } + + journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + return this->extract(cStr); + } + }; +} +#pragma once + +#include +#include // std::string +#include // std::system_error, std::error_code + +namespace sqlite_orm { + + namespace internal { + inline void perform_step(sqlite3* db, sqlite3_stmt* stmt) { + auto rc = sqlite3_step(stmt); + if(rc == SQLITE_DONE) { + // done.. + } else { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + static void perform_void_exec(sqlite3* db, const std::string& query) { + int rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + template + inline auto call_insert_impl_and_catch_constraint_failed(const T& insert_impl) { + try { + return insert_impl(); + } catch(const std::system_error& e) { + if(e.code() == std::error_code(SQLITE_CONSTRAINT, get_sqlite_error_category())) { + std::stringstream ss; + ss << "Attempting to execute 'insert' request resulted in an error like \"" << e.what() + << "\". Perhaps ordinary 'insert' is not acceptable for this table and you should try " + "'replace' or 'insert' with explicit column listing?"; + throw std::system_error(e.code(), ss.str()); + } + throw; + } + } + } +} +#pragma once + +#include + +namespace sqlite_orm { + + enum class sync_schema_result { + + /** + * created new table, table with the same tablename did not exist + */ + new_table_created, + + /** + * table schema is the same as storage, nothing to be done + */ + already_in_sync, + + /** + * removed excess columns in table (than storage) without dropping a table + */ + old_columns_removed, + + /** + * lacking columns in table (than storage) added without dropping a table + */ + new_columns_added, + + /** + * both old_columns_removed and new_columns_added + */ + new_columns_added_and_old_columns_removed, + + /** + * old table is dropped and new is recreated. Reasons : + * 1. delete excess columns in the table than storage if preseve = false + * 2. Lacking columns in the table cannot be added due to NULL and DEFAULT constraint + * 3. Reasons 1 and 2 both together + * 4. data_type mismatch between table and storage. + */ + dropped_and_recreated, + }; + + inline std::ostream& operator<<(std::ostream& os, sync_schema_result value) { + switch(value) { + case sync_schema_result::new_table_created: + return os << "new table created"; + case sync_schema_result::already_in_sync: + return os << "table and storage is already in sync."; + case sync_schema_result::old_columns_removed: + return os << "old excess columns removed"; + case sync_schema_result::new_columns_added: + return os << "new columns added"; + case sync_schema_result::new_columns_added_and_old_columns_removed: + return os << "old excess columns removed and new columns added"; + case sync_schema_result::dropped_and_recreated: + return os << "old table dropped and recreated"; + } + return os; + } +} +#pragma once + +#include // std::tuple, std::make_tuple +#include // std::string +#include // std::forward + +// #include "indexed_column.h" + +#include // std::string + +namespace sqlite_orm { + + namespace internal { + + template + struct indexed_column_t { + using column_type = C; + + indexed_column_t(column_type _column_or_expression) : + column_or_expression(std::move(_column_or_expression)) {} + + column_type column_or_expression; + std::string _collation_name; + int _order = 0; // -1 = desc, 1 = asc, 0 = not specified + + indexed_column_t collate(std::string name) { + auto res = std::move(*this); + res._collation_name = move(name); + return res; + } + + indexed_column_t asc() { + auto res = std::move(*this); + res._order = 1; + return res; + } + + indexed_column_t desc() { + auto res = std::move(*this); + res._order = -1; + return res; + } + }; + + template + struct indexed_column_maker { + using type = indexed_column_t; + + indexed_column_t operator()(C col) const { + return {std::move(col)}; + } + }; + + template + struct indexed_column_maker> { + using type = indexed_column_t; + + indexed_column_t operator()(indexed_column_t col) const { + return std::move(col); + } + }; + + template + auto make_indexed_column(C col) { + indexed_column_maker maker; + return maker(std::move(col)); + } + + } + + /** + * Use this function to specify indexed column inside `make_index` function call. + * Example: make_index("index_name", indexed_column(&User::id).asc()) + */ + template + internal::indexed_column_t indexed_column(C column_or_expression) { + return {std::move(column_or_expression)}; + } + +} + +namespace sqlite_orm { + + namespace internal { + + struct index_base { + std::string name; + bool unique = false; + }; + + template + struct index_t : index_base { + using columns_type = std::tuple; + using object_type = void; + + index_t(std::string name_, bool unique_, columns_type columns_) : + index_base{move(name_), unique_}, columns(move(columns_)) {} + + columns_type columns; + }; + } + + template + internal::index_t::type...> make_index(const std::string& name, + Cols... cols) { + return {name, false, std::make_tuple(internal::make_indexed_column(cols)...)}; + } + + template + internal::index_t::type...> make_unique_index(const std::string& name, + Cols... cols) { + return {name, true, std::make_tuple(internal::make_indexed_column(cols)...)}; + } +} +#pragma once + +// #include "alias.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * If T is alias than mapped_type_proxy::type is alias::type + * otherwise T is T. + */ + template + struct mapped_type_proxy { + using type = T; + }; + + template + struct mapped_type_proxy::value>::type> { + using type = typename T::type; + }; + } +} +#pragma once + +#include // std::string + +namespace sqlite_orm { + + namespace internal { + + struct rowid_t { + operator std::string() const { + return "rowid"; + } + }; + + struct oid_t { + operator std::string() const { + return "oid"; + } + }; + + struct _rowid_t { + operator std::string() const { + return "_rowid_"; + } + }; + + template + struct table_rowid_t : public rowid_t { + using type = T; + }; + + template + struct table_oid_t : public oid_t { + using type = T; + }; + template + struct table__rowid_t : public _rowid_t { + using type = T; + }; + + } + + inline internal::rowid_t rowid() { + return {}; + } + + inline internal::oid_t oid() { + return {}; + } + + inline internal::_rowid_t _rowid_() { + return {}; + } + + template + internal::table_rowid_t rowid() { + return {}; + } + + template + internal::table_oid_t oid() { + return {}; + } + + template + internal::table__rowid_t _rowid_() { + return {}; + } +} +#pragma once + +#include // std::enable_if, std::is_same, std::decay, std::is_arithmetic +#include // std::tuple +#include // std::reference_wrapper + +// #include "core_functions.h" + +// #include "select_constraints.h" + +// #include "operators.h" + +// #include "rowid.h" + +// #include "alias.h" + +// #include "column.h" + +// #include "storage_traits.h" +#include // std::is_same, std::enable_if, std::true_type, std::false_type, std::integral_constant +#include // std::tuple + +namespace sqlite_orm { + + namespace internal { + + template + struct storage_impl; + + template + struct table_t; + + template + struct foreign_key_t; + + template + struct table_without_rowid_t; + + namespace storage_traits { + + /** + * S - storage_impl type + * T - mapped or not mapped data type + */ + template + struct type_is_mapped_impl; + + /** + * S - storage + * T - mapped or not mapped data type + */ + template + struct type_is_mapped : type_is_mapped_impl {}; + + /** + * Final specialisation + */ + template + struct type_is_mapped_impl, T, void> : std::false_type {}; + + template + struct type_is_mapped_impl< + S, + T, + typename std::enable_if::value>::type> + : std::true_type {}; + + template + struct type_is_mapped_impl< + S, + T, + typename std::enable_if::value>::type> + : type_is_mapped_impl {}; + + /** + * S - storage_impl type + * T - mapped or not mapped data type + */ + template + struct storage_columns_count_impl; + + /** + * S - storage + * T - mapped or not mapped data type + */ + template + struct storage_columns_count : storage_columns_count_impl {}; + + /** + * Final specialisation + */ + template + struct storage_columns_count_impl, T, void> : std::integral_constant {}; + + template + struct storage_columns_count_impl< + S, + T, + typename std::enable_if::value>::type> + : std::integral_constant {}; + + template + struct storage_columns_count_impl< + S, + T, + typename std::enable_if::value>::type> + : storage_columns_count_impl {}; + + /** + * T - table type. + */ + template + struct table_types; + + /** + * type is std::tuple of field types of mapped colums. + */ + template + struct table_types> { + using args_tuple = std::tuple; + using columns_tuple = typename tuple_filter::type; + + using type = typename tuple_transformer::type; + }; + + /** + * type is std::tuple of field types of mapped colums. + */ + template + struct table_types> { + using args_tuple = std::tuple; + using columns_tuple = typename tuple_filter::type; + + using type = typename tuple_transformer::type; + }; + + /** + * S - storage_impl type + * T - mapped or not mapped data type + */ + template + struct storage_mapped_columns_impl; + + /** + * S - storage + * T - mapped or not mapped data type + */ + template + struct storage_mapped_columns : storage_mapped_columns_impl {}; + + /** + * Final specialisation + */ + template + struct storage_mapped_columns_impl, T, void> { + using type = std::tuple<>; + }; + + template + struct storage_mapped_columns_impl< + S, + T, + typename std::enable_if::value>::type> { + using table_type = typename S::table_type; + using type = typename table_types::type; + }; + + template + struct storage_mapped_columns_impl< + S, + T, + typename std::enable_if::value>::type> + : storage_mapped_columns_impl {}; + + /** + * C is any column type: column_t or constraint type + * O - object type references in FOREIGN KEY + */ + template + struct column_foreign_keys_count : std::integral_constant {}; + + template + struct column_foreign_keys_count, O> { + using target_type = typename foreign_key_t::target_type; + + static constexpr const int value = std::is_same::value ? 1 : 0; + }; + + /** + * O - object type references in FOREIGN KEY + * Cs - column types which are stored in table_t::columns_type + */ + template + struct table_foreign_keys_count_impl; + + template + struct table_foreign_keys_count_impl { + static constexpr const int value = 0; + }; + + template + struct table_foreign_keys_count_impl { + static constexpr const int value = + column_foreign_keys_count::value + table_foreign_keys_count_impl::value; + }; + + /** + * T is table_t type + * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User) + */ + template + struct table_foreign_keys_count; + + template + struct table_foreign_keys_count, O> { + using table_type = table_t; + + static constexpr const int value = table_foreign_keys_count_impl::value; + }; + + /** + * S - storage class + * O - type mapped to S + */ + template + struct storage_foreign_keys_count_impl; + + template + struct storage_foreign_keys_count_impl, O> : std::integral_constant {}; + + template + struct storage_foreign_keys_count_impl, O> { + static constexpr const int value = table_foreign_keys_count::value + + storage_foreign_keys_count_impl, O>::value; + }; + + /** + * S - storage class + * O - type mapped to S + * This class tells how many types mapped to S have foreign keys to O + */ + template + struct storage_foreign_keys_count { + using impl_type = typename S::impl_type; + + static constexpr const int value = storage_foreign_keys_count_impl::value; + }; + + /** + * C is any column type: column_t or constraint type + * O - object type references in FOREIGN KEY + */ + template + struct column_fk_references { + using type = std::tuple<>; + }; + + template + struct column_fk_references< + foreign_key_t, + O, + typename std::enable_if::target_type>::value>::type> { + using target_type = typename foreign_key_t::source_type; + + using type = std::tuple; + }; + + template + struct column_fk_references< + foreign_key_t, + O, + typename std::enable_if::target_type>::value>::type> { + using type = std::tuple<>; + }; + + /** + * O - object type references in FOREIGN KEY + * Cs - column types which are stored in table_t::columns_type + */ + template + struct table_fk_references_impl; + + template + struct table_fk_references_impl { + using type = std::tuple<>; + }; + + template + struct table_fk_references_impl { + using head_tuple = typename column_fk_references::type; + using tail_tuple = typename table_fk_references_impl::type; + using type = typename conc_tuple::type; + }; + + /** + * T is table_t type + * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User) + */ + template + struct table_fk_references; + + template + struct table_fk_references, O> { + using table_type = table_t; + + using type = typename table_fk_references_impl::type; + }; + + /** + * S - storage class + * O - type mapped to S + */ + template + struct storage_fk_references_impl; + + template + struct storage_fk_references_impl, O> { + using type = std::tuple<>; + }; + + template + struct storage_fk_references_impl, O> { + using head_tuple = typename table_fk_references::type; + using tail_tuple = typename storage_fk_references_impl, O>::type; + using type = typename conc_tuple::type; + }; + + /** + * S - storage class + * O - type mapped to S + * type holds `std::tuple` with types that has references to O as foreign keys + */ + template + struct storage_fk_references { + using impl_type = typename S::impl_type; + + using type = typename storage_fk_references_impl::type; + }; + + } + } +} + +// #include "function.h" + +#include // std::string +#include +#include // std::tuple +#include // std::function + +namespace sqlite_orm { + + struct arg_values; + + namespace internal { + + struct function_base { + using func_call = std::function< + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; + + std::string name; + int argumentsCount = 0; + std::function create; + void (*destroy)(int*) = nullptr; + + function_base(decltype(name) name_, + decltype(argumentsCount) argumentsCount_, + decltype(create) create_, + decltype(destroy) destroy_) : + name(move(name_)), + argumentsCount(argumentsCount_), create(move(create_)), destroy(destroy_) {} + }; + + struct scalar_function_t : function_base { + func_call run; + + scalar_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(run) run_, + decltype(destroy) destroy_) : + function_base{move(name_), argumentsCount_, move(create_), destroy_}, + run(move(run_)) {} + }; + + struct aggregate_function_t : function_base { + func_call step; + final_call finalCall; + + aggregate_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(step) step_, + decltype(finalCall) finalCall_, + decltype(destroy) destroy_) : + function_base{move(name_), argumentsCount_, move(create_), destroy_}, + step(move(step_)), finalCall(move(finalCall_)) {} + }; + + // got it from here https://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature + template + struct is_scalar_function_impl { + + template + struct SFINAE; + + template + struct SFINAE {}; + + template + static char test(SFINAE*); + + template + static int test(...); + + static constexpr bool has = sizeof(test(0)) == sizeof(char); + }; + + template + struct is_aggregate_function_impl { + + template + struct SFINAE; + + template + struct SFINAE {}; + + template + static char test(SFINAE*); + + template + static int test(...); + + template + static char test2(SFINAE*); + + template + static int test2(...); + + static constexpr bool has = sizeof(test(0)) == sizeof(char); + static constexpr bool has2 = sizeof(test2(0)) == sizeof(char); + static constexpr bool has_both = has && has2; + }; + + template + struct is_scalar_function : std::integral_constant::has> {}; + + template + struct is_aggregate_function : std::integral_constant::has_both> {}; + + template + struct scalar_run_member_pointer { + using type = decltype(&F::operator()); + }; + + template + struct aggregate_run_member_pointer { + using step_type = decltype(&F::step); + using fin_type = decltype(&F::fin); + }; + + template + struct member_function_arguments; + + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...) const; + using tuple_type = std::tuple::type...>; + using return_type = R; + }; + + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...); + using tuple_type = std::tuple::type...>; + using return_type = R; + }; + + template + struct callable_arguments_impl; + + template + struct callable_arguments_impl { + using function_member_pointer = typename scalar_run_member_pointer::type; + using args_tuple = typename member_function_arguments::tuple_type; + using return_type = typename member_function_arguments::return_type; + }; + + template + struct callable_arguments_impl { + using step_function_member_pointer = typename aggregate_run_member_pointer::step_type; + using fin_function_member_pointer = typename aggregate_run_member_pointer::fin_type; + using args_tuple = typename member_function_arguments::tuple_type; + using return_type = typename member_function_arguments::return_type; + }; + + template + struct callable_arguments : callable_arguments_impl::value> {}; + + template + struct function_call { + using function_type = F; + using args_tuple = std::tuple; + + args_tuple args; + }; + } + + /** + * Used to call user defined function: `func(...);` + */ + template + internal::function_call func(Args... args) { + using args_tuple = std::tuple; + using function_args_tuple = typename internal::callable_arguments::args_tuple; + constexpr auto argsCount = std::tuple_size::value; + constexpr auto functionArgsCount = std::tuple_size::value; + static_assert( + (argsCount == functionArgsCount && !std::is_same>::value) || + std::is_same>::value, + "Arguments amount does not match"); + return {std::make_tuple(std::forward(args)...)}; + } + +} + +namespace sqlite_orm { + + namespace internal { + + /** + * This is a proxy class used to define what type must have result type depending on select + * arguments (member pointer, aggregate functions, etc). Below you can see specializations + * for different types. E.g. specialization for internal::length_t has `type` int cause + * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals + * c++ SELECT return type for T + * T - C++ type + * SFINAE - sfinae argument + */ + template + struct column_result_t; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct column_result_t, void> { + using type = std::optional::type>; + }; + +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct column_result_t::value && + !std::is_member_function_pointer::value>::type> { + using type = F; + }; + + template + struct column_result_t, void> { + using type = bool; + }; + + template + struct column_result_t, void> { + using type = bool; + }; + + /** + * Common case for all getter types. Getter types are defined in column.h file + */ + template + struct column_result_t::value>::type> { + using type = typename getter_traits::field_type; + }; + + /** + * Common case for all setter types. Setter types are defined in column.h file + */ + template + struct column_result_t::value>::type> { + using type = typename setter_traits::field_type; + }; + + template + struct column_result_t, void> { + using type = R; + }; + + template + struct column_result_t, void> { + using type = typename callable_arguments::return_type; + }; + + template + struct column_result_t, S, X>, void> { + using type = std::unique_ptr::type>; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t { + using type = int; + }; + + template + struct column_result_t, void> { + using type = typename column_result_t::type; + }; + + template + struct column_result_t, void> { + using type = typename column_result_t::type; + }; + + template + struct column_result_t, void> { + using type = std::string; + }; + + template + struct column_result_t, void> { + using type = double; + }; + + template + struct column_result_t, void> { + using type = double; + }; + + template + struct column_result_t, void> { + using type = double; + }; + + template + struct column_result_t, void> { + using type = double; + }; + + template + struct column_result_t, void> { + using type = double; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t, void> { + using type = int; + }; + + template + struct column_result_t { + using type = int64; + }; + + template + struct column_result_t { + using type = int64; + }; + + template + struct column_result_t { + using type = int64; + }; + + template + struct column_result_t, void> { + using type = int64; + }; + + template + struct column_result_t, void> { + using type = int64; + }; + + template + struct column_result_t, void> { + using type = int64; + }; + + template + struct column_result_t, void> { + using type = typename column_result_t::type; + }; + + template + struct column_result_t> : column_result_t {}; + + template + struct column_result_t, void> { + using type = std::tuple::type>::type...>; + }; + + template + struct column_result_t> : column_result_t {}; + + template + struct column_result_t::value>::type> { + using left_type = typename T::left_type; + using right_type = typename T::right_type; + using left_result = typename column_result_t::type; + using right_result = typename column_result_t::type; + static_assert(std::is_same::value, + "Compound subselect queries must return same types"); + using type = left_result; + }; + + template + struct column_result_t::value>::type> { + using type = typename T::result_type; + }; + + /** + * Result for the most simple queries like `SELECT 1` + */ + template + struct column_result_t::value>::type> { + using type = T; + }; + + /** + * Result for the most simple queries like `SELECT 'ototo'` + */ + template + struct column_result_t { + using type = std::string; + }; + + template + struct column_result_t { + using type = std::string; + }; + + template + struct column_result_t, void> : column_result_t::type, void> {}; + + template + struct column_result_t, void> { + using type = typename storage_traits::storage_mapped_columns::type; + }; + + template + struct column_result_t, void> { + using type = T; + }; + + template + struct column_result_t, void> { + using type = T; + }; + + template + struct column_result_t, void> { + using type = R; + }; + + template + struct column_result_t, void> { + using type = bool; + }; + + template + struct column_result_t, void> { + using type = bool; + }; + + template + struct column_result_t, void> { + using type = bool; + }; + + template + struct column_result_t, void> : column_result_t {}; + } +} +#pragma once + +#include // std::string +#include // std::remove_reference, std::is_same, std::is_base_of +#include // std::vector +#include // std::tuple_size, std::tuple_element +#include // std::reverse, std::find_if + +// #include "column_result.h" + +// #include "static_magic.h" + +// #include "typed_comparator.h" + +// #include "constraints.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "table_info.h" + +// #include "type_printer.h" + +// #include "column.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct table_base { + + /** + * Table name. + */ + std::string name; + + static constexpr const bool is_without_rowid = _without_rowid; + }; + + template + struct table_without_rowid_t; + + /** + * Template for table interface class. + */ + template + struct table_template : table_base<_without_rowid> { + using object_type = T; + using columns_type = std::tuple; + using super = table_base<_without_rowid>; + + static constexpr const int columns_count = static_cast(std::tuple_size::value); + + using super::name; + columns_type columns; + + table_template(std::string name_, columns_type columns_) : + super{std::move(name_)}, columns{std::move(columns_)} {} + + table_without_rowid_t without_rowid() const { + return {name, columns}; + } + + /** + * Function used to get field value from object by mapped member pointer/setter/getter + */ + template + const F* get_object_field_pointer(const object_type& obj, C c) const { + const F* res = nullptr; + this->for_each_column_with_field_type([&res, &c, &obj](auto& col) { + using column_type = typename std::remove_reference::type; + using member_pointer_t = typename column_type::member_pointer_t; + using getter_type = typename column_type::getter_type; + using setter_type = typename column_type::setter_type; + // Make static_if have at least one input as a workaround for GCC bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 + if(!res) { + static_if{}>([&res, &obj, &col](const C& c_) { + if(compare_any(col.member_pointer, c_)) { + res = &(obj.*col.member_pointer); + } + })(c); + } + if(!res) { + static_if{}>([&res, &obj, &col](const C& c_) { + if(compare_any(col.getter, c_)) { + res = &((obj).*(col.getter))(); + } + })(c); + } + if(!res) { + static_if{}>([&res, &obj, &col](const C& c_) { + if(compare_any(col.setter, c_)) { + res = &((obj).*(col.getter))(); + } + })(c); + } + }); + return res; + } + + /** + * @return vector of column names of table. + */ + std::vector column_names() const { + std::vector res; + this->for_each_column([&res](auto& c) { + res.push_back(c.name); + }); + return res; + } + + /** + * Calls **l** with every primary key dedicated constraint + */ + template + void for_each_primary_key(const L& l) const { + iterate_tuple(this->columns, [&l](auto& column) { + using column_type = typename std::decay::type; + static_if{}>(l)(column); + }); + } + + std::vector composite_key_columns_names() const { + std::vector res; + this->for_each_primary_key([this, &res](auto& c) { + res = this->composite_key_columns_names(c); + }); + return res; + } + + std::vector primary_key_column_names() const { + std::vector res; + this->for_each_column_with>([&res](auto& c) { + res.push_back(c.name); + }); + if(!res.size()) { + res = this->composite_key_columns_names(); + } + return res; + } + + template + std::vector composite_key_columns_names(const primary_key_t& pk) const { + std::vector res; + using pk_columns_tuple = decltype(pk.columns); + res.reserve(std::tuple_size::value); + iterate_tuple(pk.columns, [this, &res](auto& v) { + if(auto columnName = this->find_column_name(v)) { + res.push_back(*columnName); + } else { + res.push_back({}); + } + }); + return res; + } + + /** + * Searches column name by class member pointer passed as the first argument. + * @return column name or empty string if nothing found. + */ + template::value && + !std::is_member_function_pointer::value>::type> + const std::string* find_column_name(F O::*m) const { + const std::string* res = nullptr; + this->template for_each_column_with_field_type([&res, m](auto& c) { + if(c.member_pointer == m) { + res = &c.name; + } + }); + return res; + } + + /** + * Searches column name by class getter function member pointer passed as first argument. + * @return column name or empty string if nothing found. + */ + template + const std::string* find_column_name(G getter, + typename std::enable_if::value>::type* = nullptr) const { + const std::string* res = nullptr; + using field_type = typename getter_traits::field_type; + this->template for_each_column_with_field_type([&res, getter](auto& c) { + if(compare_any(c.getter, getter)) { + res = &c.name; + } + }); + return res; + } + + /** + * Searches column name by class setter function member pointer passed as first argument. + * @return column name or empty string if nothing found. + */ + template + const std::string* find_column_name(S setter, + typename std::enable_if::value>::type* = nullptr) const { + const std::string* res = nullptr; + using field_type = typename setter_traits::field_type; + this->template for_each_column_with_field_type([&res, setter](auto& c) { + if(compare_any(c.setter, setter)) { + res = &c.name; + } + }); + return res; + } + + /** + * Iterates all columns and fires passed lambda. Lambda must have one and only templated argument Otherwise + * code will not compile. Excludes table constraints (e.g. foreign_key_t) at the end of the columns list. To + * iterate columns with table constraints use iterate_tuple(columns, ...) instead. L is lambda type. Do + * not specify it explicitly. + * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} + */ + template + void for_each_column(const L& l) const { + iterate_tuple(this->columns, [&l](auto& column) { + using column_type = typename std::decay::type; + static_if{}>(l)(column); + }); + } + + template + void for_each_column_with_field_type(const L& l) const { + iterate_tuple(this->columns, [&l](auto& column) { + using column_type = typename std::decay::type; + using field_type = typename column_field_type::type; + static_if{}>(l)(column); + }); + } + + /** + * Iterates all columns that have specified constraints and fires passed lambda. + * Lambda must have one and only templated argument Otherwise code will not compile. + * L is lambda type. Do not specify it explicitly. + * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} + */ + template + void for_each_column_with(const L& l) const { + using tuple_helper::tuple_contains_type; + iterate_tuple(this->columns, [&l](auto& column) { + using column_type = typename std::decay::type; + using constraints_type = typename column_constraints_type::type; + static_if{}>(l)(column); + }); + } + + std::vector get_table_info() const { + std::vector res; + res.reserve(size_t(this->columns_count)); + this->for_each_column([&res](auto& col) { + std::string dft; + using field_type = typename std::decay::type::field_type; + if(auto d = col.default_value()) { + dft = *d; + } + table_info i{ + -1, + col.name, + type_printer().print(), + col.not_null(), + dft, + col.template has>(), + }; + res.emplace_back(i); + }); + auto compositeKeyColumnNames = this->composite_key_columns_names(); + for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { + auto& columnName = compositeKeyColumnNames[i]; + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_info& ti) { + return ti.name == columnName; + }); + if(it != res.end()) { + it->pk = static_cast(i + 1); + } + } + return res; + } + }; + + /** + * Table interface class. + */ + template + struct table_t : table_template { + using table_template::table_template; + }; + + /** + * Table interface class with 'without_rowid' tag. + */ + template + struct table_without_rowid_t : table_template { + using table_template::table_template; + }; + } + + /** + * Function used for table creation. Do not use table constructor - use this function + * cause table class is templated and its constructing too (just like std::make_unique or std::make_pair). + */ + template>::type::object_type> + internal::table_t make_table(const std::string& name, Cs... args) { + return {name, std::make_tuple(std::forward(args)...)}; + } + + template + internal::table_t make_table(const std::string& name, Cs... args) { + return {name, std::make_tuple(std::forward(args)...)}; + } +} +#pragma once + +#include // std::string +#include +#include // std::nullptr_t +#include // std::system_error, std::error_code +#include // std::stringstream +#include // std::atoi +#include // std::forward, std::enable_if, std::is_same, std::remove_reference, std::false_type, std::true_type +#include // std::pair, std::make_pair +#include // std::vector +#include // std::find_if +#include // std::type_index + +// #include "error_code.h" + +// #include "statement_finalizer.h" + +// #include "row_extractor.h" + +// #include "util.h" + +// #include "constraints.h" + +// #include "select_constraints.h" + +// #include "field_printer.h" + +// #include "table_info.h" + +// #include "sync_schema_result.h" + +// #include "field_value_holder.h" + +#include // std::enable_if + +// #include "column.h" + +namespace sqlite_orm { + namespace internal { + + template + struct field_value_holder; + + template + struct field_value_holder::returns_lvalue>::type> { + using type = typename getter_traits::field_type; + + const type& value; + }; + + template + struct field_value_holder::returns_lvalue>::type> { + using type = typename getter_traits::field_type; + + type value; + }; + } +} + +namespace sqlite_orm { + + namespace internal { + + struct storage_impl_base { + + bool table_exists(const std::string& tableName, sqlite3* db) const { + auto result = false; + std::stringstream ss; + ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = '" + << "table" + << "' AND name = '" << tableName << "'"; + auto query = ss.str(); + auto rc = sqlite3_exec( + db, + query.c_str(), + [](void* data, int argc, char** argv, char** /*azColName*/) -> int { + auto& res = *(bool*)data; + if(argc) { + res = !!std::atoi(argv[0]); + } + return 0; + }, + &result, + nullptr); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + return result; + } + + void rename_table(sqlite3* db, const std::string& oldName, const std::string& newName) const { + std::stringstream ss; + ss << "ALTER TABLE " << oldName << " RENAME TO " << newName; + perform_void_exec(db, ss.str()); + } + + static bool calculate_remove_add_columns(std::vector& columnsToAdd, + std::vector& storageTableInfo, + std::vector& dbTableInfo) { + bool notEqual = false; + + // iterate through storage columns + for(size_t storageColumnInfoIndex = 0; storageColumnInfoIndex < storageTableInfo.size(); + ++storageColumnInfoIndex) { + + // get storage's column info + auto& storageColumnInfo = storageTableInfo[storageColumnInfoIndex]; + auto& columnName = storageColumnInfo.name; + + // search for a column in db eith the same name + auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto& ti) { + return ti.name == columnName; + }); + if(dbColumnInfoIt != dbTableInfo.end()) { + auto& dbColumnInfo = *dbColumnInfoIt; + auto columnsAreEqual = + dbColumnInfo.name == storageColumnInfo.name && + dbColumnInfo.notnull == storageColumnInfo.notnull && + (dbColumnInfo.dflt_value.length() > 0) == (storageColumnInfo.dflt_value.length() > 0) && + dbColumnInfo.pk == storageColumnInfo.pk; + if(!columnsAreEqual) { + notEqual = true; + break; + } + dbTableInfo.erase(dbColumnInfoIt); + storageTableInfo.erase(storageTableInfo.begin() + + static_cast(storageColumnInfoIndex)); + --storageColumnInfoIndex; + } else { + columnsToAdd.push_back(&storageColumnInfo); + } + } + return notEqual; + } + + std::vector get_table_info(const std::string& tableName, sqlite3* db) const { + std::vector result; + auto query = "PRAGMA table_info('" + tableName + "')"; + auto rc = sqlite3_exec( + db, + query.c_str(), + [](void* data, int argc, char** argv, char**) -> int { + auto& res = *(std::vector*)data; + if(argc) { + auto index = 0; + auto cid = std::atoi(argv[index++]); + std::string name = argv[index++]; + std::string type = argv[index++]; + bool notnull = !!std::atoi(argv[index++]); + std::string dflt_value = argv[index] ? argv[index] : ""; + index++; + auto pk = std::atoi(argv[index++]); + res.push_back(table_info(cid, name, type, notnull, dflt_value, pk)); + } + return 0; + }, + &result, + nullptr); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + return result; + } + }; + + /** + * This is a generic implementation. Used as a tail in storage_impl inheritance chain + */ + template + struct storage_impl; + + template + struct storage_impl : public storage_impl { + using table_type = H; + using super = storage_impl; + + storage_impl(H h, Ts... ts) : super(std::forward(ts)...), table(std::move(h)) {} + + table_type table; + + template + void for_each(const L& l) { + this->super::for_each(l); + l(*this); + } + +#if SQLITE_VERSION_NUMBER >= 3006019 + + /** + * Returns foreign keys count in table definition + */ + int foreign_keys_count() { + auto res = 0; + iterate_tuple(this->table.columns, [&res](auto& c) { + if(internal::is_foreign_key::type>::value) { + ++res; + } + }); + return res; + } + +#endif + + /** + * Is used to get column name by member pointer to a base class. + * Main difference between `column_name` and `column_name_simple` is that + * `column_name` has SFINAE check for type equality but `column_name_simple` has not. + */ + template + const std::string* column_name_simple(F O::*m) const { + return this->table.find_column_name(m); + } + + /** + * Cute function used to find column name by its type and member pointer. Uses SFINAE to + * skip inequal type O. + */ + template + const std::string* column_name(F O::*m, + typename std::enable_if::value>::type* = nullptr) const { + return this->table.find_column_name(m); + } + + /** + * Opposite version of function defined above. Just calls same function in superclass. + */ + template + const std::string* + column_name(F O::*m, typename std::enable_if::value>::type* = nullptr) const { + return this->super::column_name(m); + } + + template + const std::string* column_name(const column_pointer& c, + typename std::enable_if::value>::type* = nullptr) const { + return this->column_name_simple(c.field); + } + + template + const std::string* + column_name(const column_pointer& c, + typename std::enable_if::value>::type* = nullptr) const { + return this->super::column_name(c); + } + + template + const auto& get_impl(typename std::enable_if::value>::type* = nullptr) const { + return *this; + } + + template + const auto& get_impl(typename std::enable_if::value>::type* = nullptr) const { + return this->super::template get_impl(); + } + + template + auto& get_impl(typename std::enable_if::value>::type* = nullptr) { + return *this; + } + + template + auto& get_impl(typename std::enable_if::value>::type* = nullptr) { + return this->super::template get_impl(); + } + + template + const auto* find_table(typename std::enable_if::value>::type* = nullptr) const { + return &this->table; + } + + template + const auto* find_table(typename std::enable_if::value>::type* = nullptr) const { + return this->super::template find_table(); + } + + std::string find_table_name(std::type_index ti) const { + std::type_index thisTypeIndex{typeid(typename H::object_type)}; + if(thisTypeIndex == ti) { + return this->table.name; + } else { + return this->super::find_table_name(ti); + } + } + + void add_column(const table_info& ti, sqlite3* db) const { + std::stringstream ss; + ss << "ALTER TABLE " << this->table.name << " ADD COLUMN " << ti.name; + ss << " " << ti.type; + if(ti.pk) { + ss << " PRIMARY KEY"; + } + if(ti.notnull) { + ss << " NOT NULL"; + } + if(ti.dflt_value.length()) { + ss << " DEFAULT " << ti.dflt_value; + } + perform_void_exec(db, ss.str()); + } + + /** + * Copies current table to another table with a given **name**. + * Performs CREATE TABLE %name% AS SELECT %this->table.columns_names()% FROM &this->table.name%; + */ + void + copy_table(sqlite3* db, const std::string& name, const std::vector& columnsToIgnore) const { + std::stringstream ss; + std::vector columnNames; + this->table.for_each_column([&columnNames, &columnsToIgnore](auto& c) { + auto& columnName = c.name; + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](auto tableInfoPointer) { + return columnName == tableInfoPointer->name; + }); + if(columnToIgnoreIt == columnsToIgnore.end()) { + columnNames.emplace_back(columnName); + } + }); + auto columnNamesCount = columnNames.size(); + ss << "INSERT INTO " << name << " ("; + for(size_t i = 0; i < columnNamesCount; ++i) { + ss << columnNames[i]; + if(i < columnNamesCount - 1) { + ss << ","; + } + ss << " "; + } + ss << ") "; + ss << "SELECT "; + for(size_t i = 0; i < columnNamesCount; ++i) { + ss << columnNames[i]; + if(i < columnNamesCount - 1) { + ss << ", "; + } + } + ss << " FROM '" << this->table.name << "' "; + perform_void_exec(db, ss.str()); + } + + sync_schema_result schema_status(sqlite3* db, bool preserve) const { + + auto res = sync_schema_result::already_in_sync; + + // first let's see if table with such name exists.. + auto gottaCreateTable = !this->table_exists(this->table.name, db); + if(!gottaCreateTable) { + + // get table info provided in `make_table` call.. + auto storageTableInfo = this->table.get_table_info(); + + // now get current table info from db using `PRAGMA table_info` query.. + auto dbTableInfo = this->get_table_info(this->table.name, db); + + // this vector will contain pointers to columns that gotta be added.. + std::vector columnsToAdd; + + if(this->calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) { + gottaCreateTable = true; + } + + if(!gottaCreateTable) { // if all storage columns are equal to actual db columns but there are + // excess columns at the db.. + if(dbTableInfo.size() > 0) { + // extra table columns than storage columns + if(!preserve) { + gottaCreateTable = true; + } else { + res = decltype(res)::old_columns_removed; + } + } + } + if(gottaCreateTable) { + res = decltype(res)::dropped_and_recreated; + } else { + if(columnsToAdd.size()) { + // extra storage columns than table columns + for(auto columnPointer: columnsToAdd) { + if(columnPointer->notnull && columnPointer->dflt_value.empty()) { + gottaCreateTable = true; + break; + } + } + if(!gottaCreateTable) { + if(res == decltype(res)::old_columns_removed) { + res = decltype(res)::new_columns_added_and_old_columns_removed; + } else { + res = decltype(res)::new_columns_added; + } + } else { + res = decltype(res)::dropped_and_recreated; + } + } else { + if(res != decltype(res)::old_columns_removed) { + res = decltype(res)::already_in_sync; + } + } + } + } else { + res = decltype(res)::new_table_created; + } + return res; + } + + private: + using self = storage_impl; + }; + + template<> + struct storage_impl<> : storage_impl_base { + + std::string find_table_name(std::type_index) const { + return {}; + } + + template + void for_each(const L&) {} + + int foreign_keys_count() { + return 0; + } + + template + const void* find_table() const { + return nullptr; + } + }; + + template + struct is_storage_impl : std::false_type {}; + + template + struct is_storage_impl> : std::true_type {}; + } +} +#pragma once + +#include // std::unique/shared_ptr, std::make_unique/shared +#include // std::string +#include +#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type +#include // std::ptrdiff_t +#include // std::input_iterator_tag, std::iterator_traits, std::distance +#include // std::function +#include // std::stringstream +#include // std::map +#include // std::vector +#include // std::tuple_size, std::tuple, std::make_tuple +#include // std::forward, std::pair +#include // std::find + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +// #include "alias.h" + +// #include "row_extractor_builder.h" + +// #include "row_extractor.h" + +// #include "mapped_row_extractor.h" + +#include + +// #include "object_from_column_builder.h" + +#include + +// #include "row_extractor.h" + +namespace sqlite_orm { + + namespace internal { + + struct object_from_column_builder_base { + sqlite3_stmt* stmt = nullptr; + mutable int index = 0; + }; + + /** + * This is a cute lambda replacement which is used in several places. + */ + template + struct object_from_column_builder : object_from_column_builder_base { + using object_type = O; + + object_type& object; + + object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : + object_from_column_builder_base{stmt_}, object(object_) {} + + template + void operator()(const C& c) const { + using field_type = typename C::field_type; + auto value = row_extractor().extract(this->stmt, this->index++); + if(c.member_pointer) { + this->object.*c.member_pointer = std::move(value); + } else { + ((this->object).*(c.setter))(std::move(value)); + } + } + }; + + } +} + +namespace sqlite_orm { + + namespace internal { + + /** + * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. + * Main difference from regular `row_extractor` is that this class takes table info which is required + * for constructing objects by member pointers. To construct please use `row_extractor_builder` class + * Type arguments: + * V is value type just like regular `row_extractor` has + * T is table info class `table_t` + */ + template + struct mapped_row_extractor { + using table_info_t = T; + + mapped_row_extractor(const table_info_t& tableInfo_) : tableInfo(tableInfo_) {} + + V extract(sqlite3_stmt* stmt, int /*columnIndex*/) { + V res; + object_from_column_builder builder{res, stmt}; + this->tableInfo.for_each_column(builder); + return res; + } + + const table_info_t& tableInfo; + }; + + } + +} + +namespace sqlite_orm { + + namespace internal { + + /** + * This builder is used to construct different row extractors depending on type. + * It has two specializations: for mapped to storage types (e.g. User, Visit etc) and + * for non-mapped (e.g. std::string, QString, int etc). For non mapped its operator() returns + * generic `row_extractor`, for mapped it returns `mapped_row_extractor` instance. + */ + template + struct row_extractor_builder; + + template + struct row_extractor_builder { + + row_extractor operator()(const I* /*tableInfo*/) const { + return {}; + } + }; + + template + struct row_extractor_builder { + + mapped_row_extractor operator()(const I* tableInfo) const { + return {*tableInfo}; + } + }; + + template + auto make_row_extractor(const I* tableInfo) { + using builder_t = row_extractor_builder; + return builder_t{}(tableInfo); + } + + } + +} + +// #include "error_code.h" + +// #include "type_printer.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "constraints.h" + +// #include "type_is_nullable.h" + +// #include "field_printer.h" + +// #include "rowid.h" + +// #include "operators.h" + +// #include "select_constraints.h" + +// #include "core_functions.h" + +// #include "conditions.h" + +// #include "statement_binder.h" + +// #include "column_result.h" + +// #include "mapped_type_proxy.h" + +// #include "sync_schema_result.h" + +// #include "table_info.h" + +// #include "storage_impl.h" + +// #include "journal_mode.h" + +// #include "field_value_holder.h" + +// #include "view.h" + +#include // std::shared_ptr +#include // std::string +#include // std::forward, std::move +#include +#include // std::system_error +#include // std::tuple, std::make_tuple + +// #include "row_extractor.h" + +// #include "statement_finalizer.h" + +// #include "error_code.h" + +// #include "iterator.h" + +#include // std::shared_ptr, std::unique_ptr, std::make_shared +#include +#include // std::decay +#include // std::move +#include // std::ptrdiff_t +#include // std::input_iterator_tag +#include // std::system_error +#include // std::make_error_code + +// #include "row_extractor.h" + +// #include "statement_finalizer.h" + +// #include "error_code.h" + +// #include "object_from_column_builder.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct iterator_t { + using view_type = V; + using value_type = typename view_type::mapped_type; + + protected: + /** + * The double-indirection is so that copies of the iterator + * share the same sqlite3_stmt from a sqlite3_prepare_v2() + * call. When one finishes iterating it the pointer + * inside the shared_ptr is nulled out in all copies. + */ + std::shared_ptr stmt; + + // only null for the default constructed iterator + view_type* view; + + /** + * shared_ptr is used over unique_ptr here + * so that the iterator can be copyable. + */ + std::shared_ptr current; + + void extract_value() { + auto& storage = this->view->storage; + auto& impl = storage.template get_impl(); + this->current = std::make_shared(); + object_from_column_builder builder{*this->current, this->stmt->get()}; + impl.table.for_each_column(builder); + } + + public: + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + + iterator_t() : view(nullptr){}; + + iterator_t(sqlite3_stmt* stmt_, view_type& view_) : + stmt(std::make_shared(stmt_)), view(&view_) { + next(); + } + + const value_type& operator*() const { + if(!this->stmt || !this->current) { + throw std::system_error(std::make_error_code(orm_error_code::trying_to_dereference_null_iterator)); + } + return *this->current; + } + + const value_type* operator->() const { + return &(this->operator*()); + } + + private: + void next() { + this->current.reset(); + if(this->stmt) { + auto statementPointer = this->stmt->get(); + auto ret = sqlite3_step(statementPointer); + switch(ret) { + case SQLITE_ROW: + this->extract_value(); + break; + case SQLITE_DONE: + this->stmt.reset(); + break; + default: { + auto db = this->view->connection.get(); + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + } + + public: + iterator_t& operator++() { + next(); + return *this; + } + + void operator++(int) { + this->operator++(); + } + + bool operator==(const iterator_t& other) const { + return this->current == other.current; + } + + bool operator!=(const iterator_t& other) const { + return !(*this == other); + } + }; + } +} + +// #include "ast_iterator.h" + +#include // std::vector +#include // std::reference_wrapper + +// #include "conditions.h" + +// #include "select_constraints.h" + +// #include "operators.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "core_functions.h" + +// #include "prepared_statement.h" + +#include +#include // std::iterator_traits +#include // std::string +#include // std::true_type, std::false_type +#include // std::pair + +// #include "connection_holder.h" + +#include +#include // std::string +#include // std::system_error + +// #include "error_code.h" + +namespace sqlite_orm { + + namespace internal { + + struct connection_holder { + + connection_holder(std::string filename_) : filename(move(filename_)) {} + + void retain() { + ++this->_retain_count; + if(1 == this->_retain_count) { + auto rc = sqlite3_open(this->filename.c_str(), &this->db); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), + sqlite3_errmsg(this->db)); + } + } + } + + void release() { + --this->_retain_count; + if(0 == this->_retain_count) { + auto rc = sqlite3_close(this->db); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), + sqlite3_errmsg(this->db)); + } + } + } + + sqlite3* get() const { + return this->db; + } + + int retain_count() const { + return this->_retain_count; + } + + const std::string filename; + + protected: + sqlite3* db = nullptr; + int _retain_count = 0; + }; + + struct connection_ref { + connection_ref(connection_holder& holder_) : holder(holder_) { + this->holder.retain(); + } + + connection_ref(const connection_ref& other) : holder(other.holder) { + this->holder.retain(); + } + + connection_ref(connection_ref&& other) : holder(other.holder) { + this->holder.retain(); + } + + ~connection_ref() { + this->holder.release(); + } + + sqlite3* get() const { + return this->holder.get(); + } + + protected: + connection_holder& holder; + }; + } +} + +// #include "select_constraints.h" + +// #include "values.h" + +#include // std::vector +#include +#include // std::tuple +#include // std::false_type, std::true_type + +namespace sqlite_orm { + + namespace internal { + + template + struct values_t { + using args_tuple = std::tuple; + + args_tuple tuple; + }; + + template + struct is_values : std::false_type {}; + + template + struct is_values> : std::true_type {}; + + template + struct dynamic_values_t { + std::vector vector; + }; + + } + + template + internal::values_t values(Args... args) { + return {{std::forward(args)...}}; + } + + template + internal::dynamic_values_t values(std::vector vector) { + return {{move(vector)}}; + } + +} + +namespace sqlite_orm { + + namespace internal { + + struct prepared_statement_base { + sqlite3_stmt* stmt = nullptr; + connection_ref con; + + ~prepared_statement_base() { + if(this->stmt) { + sqlite3_finalize(this->stmt); + this->stmt = nullptr; + } + } + + std::string sql() const { + if(this->stmt) { + if(auto res = sqlite3_sql(this->stmt)) { + return res; + } else { + return {}; + } + } else { + return {}; + } + } + +#if SQLITE_VERSION_NUMBER >= 3014000 + std::string expanded_sql() const { + if(this->stmt) { + if(auto res = sqlite3_expanded_sql(this->stmt)) { + std::string result = res; + sqlite3_free(res); + return result; + } else { + return {}; + } + } else { + return {}; + } + } +#endif +#if SQLITE_VERSION_NUMBER >= 3026000 and defined(SQLITE_ENABLE_NORMALIZE) + std::string normalized_sql() const { + if(this->stmt) { + if(auto res = sqlite3_normalized_sql(this->stmt)) { + return res; + } else { + return {}; + } + } else { + return {}; + } + } +#endif + }; + + template + struct prepared_statement_t : prepared_statement_base { + using expression_type = T; + + expression_type t; + + prepared_statement_t(T t_, sqlite3_stmt* stmt_, connection_ref con_) : + prepared_statement_base{stmt_, std::move(con_)}, t(std::move(t_)) {} + }; + + template + struct is_prepared_statement : std::false_type {}; + + template + struct is_prepared_statement> : std::true_type {}; + + /** + * T - type of object to obtain from a database + */ + template + struct get_all_t { + using type = T; + using return_type = R; + + using conditions_type = std::tuple; + + conditions_type conditions; + }; + + template + struct get_all_pointer_t { + using type = T; + using return_type = R; + + using conditions_type = std::tuple; + + conditions_type conditions; + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct get_all_optional_t { + using type = T; + using return_type = R; + + using conditions_type = std::tuple; + + conditions_type conditions; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct update_all_t; + + template + struct update_all_t, Wargs...> { + using set_type = set_t; + using conditions_type = std::tuple; + + set_type set; + conditions_type conditions; + }; + + template + struct remove_all_t { + using type = T; + using conditions_type = std::tuple; + + conditions_type conditions; + }; + + template + struct get_t { + using type = T; + using ids_type = std::tuple; + + ids_type ids; + }; + + template + struct get_pointer_t { + using type = T; + using ids_type = std::tuple; + + ids_type ids; + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct get_optional_t { + using type = T; + using ids_type = std::tuple; + + ids_type ids; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct update_t { + using type = T; + + type obj; + }; + + template + struct remove_t { + using type = T; + using ids_type = std::tuple; + + ids_type ids; + }; + + template + struct insert_t { + using type = T; + + type obj; + }; + + template + struct is_insert : std::false_type {}; + + template + struct is_insert> : std::true_type {}; + + template + struct insert_explicit { + using type = T; + using columns_type = columns_t; + + type obj; + columns_type columns; + }; + + template + struct replace_t { + using type = T; + + type obj; + }; + + template + struct is_replace : std::false_type {}; + + template + struct is_replace> : std::true_type {}; + + template + struct insert_range_t { + using iterator_type = It; + using container_object_type = typename std::iterator_traits::value_type; + using transformer_type = L; + using object_type = O; + + std::pair range; + transformer_type transformer; + }; + + template + struct is_insert_range : std::false_type {}; + + template + struct is_insert_range> : std::true_type {}; + + template + struct replace_range_t { + using iterator_type = It; + using container_object_type = typename std::iterator_traits::value_type; + using transformer_type = L; + using object_type = O; + + std::pair range; + transformer_type transformer; + }; + + template + struct is_replace_range : std::false_type {}; + + template + struct is_replace_range> : std::true_type {}; + + template + struct insert_raw_t { + using args_tuple = std::tuple; + + args_tuple args; + }; + + template + struct is_insert_raw : std::false_type {}; + + template + struct is_insert_raw> : std::true_type {}; + + template + struct replace_raw_t { + using args_tuple = std::tuple; + + args_tuple args; + }; + + template + struct is_replace_raw : std::false_type {}; + + template + struct is_replace_raw> : std::true_type {}; + + template + struct into_t { + using type = T; + }; + + template + struct is_into : std::false_type {}; + + template + struct is_into> : std::true_type {}; + + struct default_transformer { + + template + const T& operator()(const T& object) const { + return object; + } + }; + + struct default_values_t {}; + + template + using is_default_values = std::is_same; + + enum class insert_constraint { + abort, + fail, + ignore, + replace, + rollback, + }; + + template + using is_insert_constraint = std::is_same; + + template + struct is_upsert_clause; + } + + inline internal::insert_constraint or_rollback() { + return internal::insert_constraint::rollback; + } + + inline internal::insert_constraint or_replace() { + return internal::insert_constraint::replace; + } + + inline internal::insert_constraint or_ignore() { + return internal::insert_constraint::ignore; + } + + inline internal::insert_constraint or_fail() { + return internal::insert_constraint::fail; + } + + inline internal::insert_constraint or_abort() { + return internal::insert_constraint::abort; + } + + /** + * Use this function to add `DEFAULT VALUES` modifier to raw `INSERT`. + * + * @example + * ``` + * storage.insert(into(), default_values()); + * ``` + */ + inline internal::default_values_t default_values() { + return {}; + } + + template + internal::into_t into() { + return {}; + } + + /** + * Raw insert statement creation routine. Use this if `insert` with object does not fit you. This insert is designed to be able + * to call any type of `INSERT` query with no limitations. + * @example + * ```sql + * INSERT INTO users (id, name) VALUES(5, 'Little Mix') + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(insert(into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")))); + * storage.execute(statement)); + * ``` + * One more example: + * ```sql + * INSERT INTO singers (name) VALUES ('Sofia Reyes')('Kungs') + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(insert(into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")))); + * storage.execute(statement)); + * ``` + * One can use `default_values` to add `DEFAULT VALUES` modifier: + * ```sql + * INSERT INTO users DEFAULT VALUES + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(insert(into(), default_values())); + * storage.execute(statement)); + * ``` + * Also one can use `INSERT OR ABORT`/`INSERT OR FAIL`/`INSERT OR IGNORE`/`INSERT OR REPLACE`/`INSERT ROLLBACK`: + * ```c++ + * auto statement = storage.prepare(insert(or_ignore(), into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")))); + * auto statement2 = storage.prepare(insert(or_rollback(), into(), default_values())); + * auto statement3 = storage.prepare(insert(or_abort(), into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")))); + * ``` + */ + template + internal::insert_raw_t insert(Args... args) { + using args_tuple = std::tuple; + using internal::count_tuple; + using internal::is_columns; + using internal::is_insert_constraint; + using internal::is_into; + using internal::is_select; + using internal::is_upsert_clause; + using internal::is_values; + + constexpr int orArgsCount = count_tuple::value; + static_assert(orArgsCount < 2, "Raw insert must have only one OR... argument"); + + constexpr int intoArgsCount = count_tuple::value; + static_assert(intoArgsCount != 0, "Raw insert must have into argument"); + static_assert(intoArgsCount < 2, "Raw insert must have only one into argument"); + + constexpr int columnsArgsCount = count_tuple::value; + static_assert(columnsArgsCount < 2, "Raw insert must have only one columns(...) argument"); + + constexpr int valuesArgsCount = count_tuple::value; + static_assert(valuesArgsCount < 2, "Raw insert must have only one values(...) argument"); + + constexpr int defaultValuesCount = count_tuple::value; + static_assert(defaultValuesCount < 2, "Raw insert must have only one default_values() argument"); + + constexpr int selectsArgsCount = count_tuple::value; + static_assert(selectsArgsCount < 2, "Raw insert must have only one select(...) argument"); + + constexpr int upsertClausesCount = count_tuple::value; + static_assert(upsertClausesCount <= 2, "Raw insert can contain 2 instances of upsert clause maximum"); + + constexpr int argsCount = int(std::tuple_size::value); + static_assert(argsCount == intoArgsCount + columnsArgsCount + valuesArgsCount + defaultValuesCount + + selectsArgsCount + orArgsCount + upsertClausesCount, + "Raw insert has invalid arguments"); + + return {{std::forward(args)...}}; + } + + /** + * Raw replace statement creation routine. Use this if `replace` with object does not fit you. This replace is designed to be able + * to call any type of `REPLACE` query with no limitations. Actually this is the same query as raw insert except `OR...` option existance. + * @example + * ```sql + * REPLACE INTO users (id, name) VALUES(5, 'Little Mix') + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(replace(into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")))); + * storage.execute(statement)); + * ``` + * One more example: + * ```sql + * REPLACE INTO singers (name) VALUES ('Sofia Reyes')('Kungs') + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(replace(into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")))); + * storage.execute(statement)); + * ``` + * One can use `default_values` to add `DEFAULT VALUES` modifier: + * ```sql + * REPLACE INTO users DEFAULT VALUES + * ``` + * will be + * ```c++ + * auto statement = storage.prepare(replace(into(), default_values())); + * storage.execute(statement)); + * ``` + */ + template + internal::replace_raw_t replace(Args... args) { + using args_tuple = std::tuple; + using internal::count_tuple; + using internal::is_columns; + using internal::is_into; + using internal::is_values; + + constexpr int intoArgsCount = count_tuple::value; + static_assert(intoArgsCount != 0, "Raw replace must have into argument"); + static_assert(intoArgsCount < 2, "Raw replace must have only one into argument"); + + constexpr int columnsArgsCount = count_tuple::value; + static_assert(columnsArgsCount < 2, "Raw replace must have only one columns(...) argument"); + + constexpr int valuesArgsCount = count_tuple::value; + static_assert(valuesArgsCount < 2, "Raw replace must have only one values(...) argument"); + + constexpr int defaultValuesCount = count_tuple::value; + static_assert(defaultValuesCount < 2, "Raw replace must have only one default_values() argument"); + + constexpr int selectsArgsCount = count_tuple::value; + static_assert(selectsArgsCount < 2, "Raw replace must have only one select(...) argument"); + + constexpr int argsCount = int(std::tuple_size::value); + static_assert(argsCount == + intoArgsCount + columnsArgsCount + valuesArgsCount + defaultValuesCount + selectsArgsCount, + "Raw replace has invalid arguments"); + + return {{std::forward(args)...}}; + } + + /** + * Create a replace range statement + * + * @example + * ``` + * std::vector users; + * users.push_back(User{1, "Leony"}); + * auto statement = storage.prepare(replace_range(users.begin(), users.end())); + * storage.execute(statement); + * ``` + */ + template + internal::replace_range_t::value_type> + replace_range(It from, It to) { + return {{std::move(from), std::move(to)}}; + } + + /** + * Create an replace range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers, + * optionals or whatever. + * @example + * ``` + * std::vector> userPointers; + * userPointers.push_back(std::make_unique(1, "Eneli")); + * auto statement = storage.prepare(replace_range(userPointers.begin(), userPointers.end(), [](const std::unique_ptr &userPointer) -> const User & { + * return *userPointer; + * })); + * storage.execute(statement); + * ``` + */ + template + internal::replace_range_t replace_range(It from, It to, L transformer) { + return {{std::move(from), std::move(to)}, std::move(transformer)}; + } + + /** + * Create an insert range statement + * @example + * ``` + * std::vector users; + * users.push_back(User{1, "Leony"}); + * auto statement = storage.prepare(insert_range(users.begin(), users.end())); + * storage.execute(statement); + * ``` + */ + template + internal::insert_range_t::value_type> + insert_range(It from, It to) { + return {{std::move(from), std::move(to)}, internal::default_transformer{}}; + } + + /** + * Create an insert range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers, + * optionals or whatever. + * @example + * ``` + * std::vector> userPointers; + * userPointers.push_back(std::make_unique(1, "Eneli")); + * auto statement = storage.prepare(insert_range(userPointers.begin(), userPointers.end(), [](const std::unique_ptr &userPointer) -> const User & { + * return *userPointer; + * })); + * storage.execute(statement); + * ``` + */ + template + internal::insert_range_t insert_range(It from, It to, L transformer) { + return {{std::move(from), std::move(to)}, std::move(transformer)}; + } + /** + * Create a replace statement. + * T is an object type mapped to a storage. + * Usage: storage.replace(myUserInstance); + * Parameter obj is accepted by value. If you want to accept it by ref + * please use std::ref function: storage.replace(std::ref(myUserInstance)); + */ + template + internal::replace_t replace(T obj) { + return {std::move(obj)}; + } + + /** + * Create an insert statement. + * T is an object type mapped to a storage. + * Usage: storage.insert(myUserInstance); + * Parameter obj is accepted by value. If you want to accept it by ref + * please use std::ref function: storage.insert(std::ref(myUserInstance)); + */ + template + internal::insert_t insert(T obj) { + return {std::move(obj)}; + } + + /** + * Create an explicit insert statement. + * T is an object type mapped to a storage. + * Cols is columns types aparameter pack. Must contain member pointers + * Usage: storage.insert(myUserInstance, columns(&User::id, &User::name)); + * Parameter obj is accepted by value. If you want to accept it by ref + * please use std::ref function: storage.insert(std::ref(myUserInstance), columns(&User::id, &User::name)); + */ + template + internal::insert_explicit insert(T obj, internal::columns_t cols) { + return {std::move(obj), std::move(cols)}; + } + + /** + * Create a remove statement + * T is an object type mapped to a storage. + * Usage: remove(5); + */ + template + internal::remove_t remove(Ids... ids) { + std::tuple idsTuple{std::forward(ids)...}; + return {move(idsTuple)}; + } + + /** + * Create an update statement. + * T is an object type mapped to a storage. + * Usage: storage.update(myUserInstance); + * Parameter obj is accepted by value. If you want to accept it by ref + * please use std::ref function: storage.update(std::ref(myUserInstance)); + */ + template + internal::update_t update(T obj) { + return {std::move(obj)}; + } + + /** + * Create a get statement. + * T is an object type mapped to a storage. + * Usage: get(5); + */ + template + internal::get_t get(Ids... ids) { + std::tuple idsTuple{std::forward(ids)...}; + return {move(idsTuple)}; + } + + /** + * Create a get pointer statement. + * T is an object type mapped to a storage. + * Usage: get_pointer(5); + */ + template + internal::get_pointer_t get_pointer(Ids... ids) { + std::tuple idsTuple{std::forward(ids)...}; + return {move(idsTuple)}; + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * Create a get optional statement. + * T is an object type mapped to a storage. + * Usage: get_optional(5); + */ + template + internal::get_optional_t get_optional(Ids... ids) { + std::tuple idsTuple{std::forward(ids)...}; + return {move(idsTuple)}; + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + /** + * Create a remove all statement. + * T is an object type mapped to a storage. + * Usage: storage.remove_all(...); + */ + template + internal::remove_all_t remove_all(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + + /** + * Create a get all statement. + * T is an object type mapped to a storage. + * Usage: storage.get_all(...); + */ + template + internal::get_all_t, Args...> get_all(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + + /** + * Create a get all statement. + * T is an object type mapped to a storage. + * R is a container type. std::vector is default + * Usage: storage.get_all(...); + */ + template + internal::get_all_t get_all(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + + /** + * Create an update all statement. + * Usage: storage.update_all(set(...), ...); + */ + template + internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(wh)...}; + return {std::move(set), move(conditions)}; + } + + /** + * Create a get all pointer statement. + * T is an object type mapped to a storage. + * Usage: storage.get_all_pointer(...); + */ + template + internal::get_all_pointer_t>, Args...> get_all_pointer(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + /** + * Create a get all pointer statement. + * T is an object type mapped to a storage. + * R is a container return type. std::vector> is default + * Usage: storage.get_all_pointer(...); + */ + template + internal::get_all_pointer_t get_all_pointer(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * Create a get all optional statement. + * T is an object type mapped to a storage. + * Usage: storage.get_all_optional(...); + */ + template + internal::get_all_optional_t>, Args...> get_all_optional(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } + + /** + * Create a get all optional statement. + * T is an object type mapped to a storage. + * R is a container return type. std::vector> is default + * Usage: storage.get_all_optional(...); + */ + template + internal::get_all_optional_t get_all_optional(Args... args) { + using args_tuple = std::tuple; + internal::validate_conditions(); + args_tuple conditions{std::forward(args)...}; + return {move(conditions)}; + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +} + +// #include "values.h" + +// #include "function.h" + +// #include "ast/excluded.h" + +namespace sqlite_orm { + namespace internal { + + template + struct excluded_t { + using expression_type = T; + + expression_type expression; + }; + } + + template + internal::excluded_t excluded(T expression) { + return {std::move(expression)}; + } +} + +// #include "ast/upsert_clause.h" + +#include // std::tuple +#include // std::false_type, std::true_type + +namespace sqlite_orm { + namespace internal { + + template + struct upsert_clause; + + template + struct conflict_target { + using args_tuple = std::tuple; + + args_tuple args; + + upsert_clause> do_nothing() { + return {std::move(this->args), {}}; + } + + template + upsert_clause> do_update(ActionsArgs... actions) { + return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; + } + }; + + template + struct upsert_clause, std::tuple> { + using target_args_tuple = std::tuple; + using actions_tuple = std::tuple; + + target_args_tuple target_args; + + actions_tuple actions; + }; + + template + struct is_upsert_clause : std::false_type {}; + + template + struct is_upsert_clause> : std::true_type {}; + } + + /** + * ON CONFLICT upsert clause builder function. + * @example + * storage.insert(into(), + * columns(&Employee::id, &Employee::name, &Employee::age, &Employee::address, &Employee::salary), + * values(std::make_tuple(3, "Sofia", 26, "Madrid", 15000.0), + * std::make_tuple(4, "Doja", 26, "LA", 25000.0)), + * on_conflict(&Employee::id).do_update(set(c(&Employee::name) = excluded(&Employee::name), + * c(&Employee::age) = excluded(&Employee::age), + * c(&Employee::address) = excluded(&Employee::address), + * c(&Employee::salary) = excluded(&Employee::salary)))); + */ + template + internal::conflict_target on_conflict(Args... args) { + return {std::tuple(std::forward(args)...)}; + } +} + +// #include "ast/where.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * ast_iterator accepts any expression and a callable object + * which will be called for any node of provided expression. + * E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then + * callable object will be called with 5, &User::id and 10. + * ast_iterator is used mostly in finding literals to be bound to + * a statement. To use it just call `iterate_ast(object, callable);` + * T is an ast element. E.g. where_t + */ + template + struct ast_iterator { + using node_type = T; + + /** + * L is a callable type. Mostly is a templated lambda + */ + template + void operator()(const T& t, const L& l) const { + l(t); + } + }; + + /** + * Simplified API + */ + template + void iterate_ast(const T& t, const L& l) { + ast_iterator iterator; + iterator(t, l); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct ast_iterator, void> { + using node_type = as_optional_t; + + template + void operator()(const node_type& node, const L& lambda) const { + iterate_ast(node.value, lambda); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct ast_iterator, void> { + using node_type = std::reference_wrapper; + + template + void operator()(const node_type& r, const L& lambda) const { + iterate_ast(r.get(), lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = excluded_t; + + template + void operator()(const node_type& expression, const L& lambda) const { + iterate_ast(expression.expression, lambda); + } + }; + + template + struct ast_iterator, std::tuple>, void> { + using node_type = upsert_clause, std::tuple>; + + template + void operator()(const node_type& expression, const L& lambda) const { + iterate_ast(expression.actions, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = where_t; + + template + void operator()(const node_type& expression, const L& lambda) const { + iterate_ast(expression.expression, lambda); + } + }; + + template + struct ast_iterator::value>::type> { + using node_type = T; + + template + void operator()(const node_type& binaryCondition, const L& l) const { + iterate_ast(binaryCondition.l, l); + iterate_ast(binaryCondition.r, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = binary_operator; + + template + void operator()(const node_type& binaryOperator, const C& l) const { + iterate_ast(binaryOperator.lhs, l); + iterate_ast(binaryOperator.rhs, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = columns_t; + + template + void operator()(const node_type& cols, const L& l) const { + iterate_ast(cols.columns, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = dynamic_in_t; + + template + void operator()(const node_type& in, const C& l) const { + iterate_ast(in.left, l); + iterate_ast(in.argument, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = in_t; + + template + void operator()(const node_type& in, const C& l) const { + iterate_ast(in.left, l); + iterate_ast(in.argument, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = std::vector; + + template + void operator()(const node_type& vec, const L& l) const { + for(auto& i: vec) { + iterate_ast(i, l); + } + } + }; + + template<> + struct ast_iterator, void> { + using node_type = std::vector; + + template + void operator()(const node_type& vec, const L& l) const { + l(vec); + } + }; + + template + struct ast_iterator::value>::type> { + using node_type = T; + + template + void operator()(const node_type& c, const L& l) const { + iterate_ast(c.left, l); + iterate_ast(c.right, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = into_t; + + template + void operator()(const node_type& node, const L& l) const { + //.. + } + }; + + template + struct ast_iterator, void> { + using node_type = insert_raw_t; + + template + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.args, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = replace_raw_t; + + template + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.args, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = select_t; + + template + void operator()(const node_type& sel, const L& l) const { + iterate_ast(sel.col, l); + iterate_ast(sel.conditions, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = get_all_t; + + template + void operator()(const node_type& get, const L& l) const { + iterate_ast(get.conditions, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = get_all_pointer_t; + + template + void operator()(const node_type& get, const L& l) const { + iterate_ast(get.conditions, l); + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct ast_iterator, void> { + using node_type = get_all_optional_t; + + template + void operator()(const node_type& get, const L& l) const { + iterate_ast(get.conditions, l); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct ast_iterator, Wargs...>, void> { + using node_type = update_all_t, Wargs...>; + + template + void operator()(const node_type& u, const L& l) const { + iterate_ast(u.set, l); + iterate_ast(u.conditions, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = remove_all_t; + + template + void operator()(const node_type& r, const L& l) const { + iterate_ast(r.conditions, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = set_t; + + template + void operator()(const node_type& s, const L& l) const { + iterate_ast(s.assigns, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = std::tuple; + + template + void operator()(const node_type& tuple, const L& l) const { + iterate_tuple(tuple, [&l](auto& v) { + iterate_ast(v, l); + }); + } + }; + + template + struct ast_iterator, void> { + using node_type = having_t; + + template + void operator()(const node_type& hav, const L& l) const { + iterate_ast(hav.t, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = cast_t; + + template + void operator()(const node_type& c, const L& l) const { + iterate_ast(c.expression, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = exists_t; + + template + void operator()(const node_type& e, const L& l) const { + iterate_ast(e.t, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = like_t; + + template + void operator()(const node_type& lk, const L& l) const { + iterate_ast(lk.arg, l); + iterate_ast(lk.pattern, l); + lk.arg3.apply([&l](auto& value) { + iterate_ast(value, l); + }); + } + }; + + template + struct ast_iterator, void> { + using node_type = glob_t; + + template + void operator()(const node_type& lk, const L& l) const { + iterate_ast(lk.arg, l); + iterate_ast(lk.pattern, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = between_t; + + template + void operator()(const node_type& b, const L& l) const { + iterate_ast(b.expr, l); + iterate_ast(b.b1, l); + iterate_ast(b.b2, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = named_collate; + + template + void operator()(const node_type& col, const L& l) const { + iterate_ast(col.expr, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = negated_condition_t; + + template + void operator()(const node_type& neg, const L& l) const { + iterate_ast(neg.c, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = is_null_t; + + template + void operator()(const node_type& i, const L& l) const { + iterate_ast(i.t, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = is_not_null_t; + + template + void operator()(const node_type& i, const L& l) const { + iterate_ast(i.t, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = function_call; + + template + void operator()(const node_type& f, const L& l) const { + iterate_ast(f.args, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = built_in_function_t; + + template + void operator()(const node_type& f, const L& l) const { + iterate_ast(f.args, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = left_join_t; + + template + void operator()(const node_type& j, const L& l) const { + iterate_ast(j.constraint, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = on_t; + + template + void operator()(const node_type& o, const L& l) const { + iterate_ast(o.arg, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = join_t; + + template + void operator()(const node_type& j, const L& l) const { + iterate_ast(j.constraint, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = left_outer_join_t; + + template + void operator()(const node_type& j, const L& l) const { + iterate_ast(j.constraint, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = inner_join_t; + + template + void operator()(const node_type& j, const L& l) const { + iterate_ast(j.constraint, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = simple_case_t; + + template + void operator()(const node_type& c, const L& l) const { + c.case_expression.apply([&l](auto& c_) { + iterate_ast(c_, l); + }); + iterate_tuple(c.args, [&l](auto& pair) { + iterate_ast(pair.first, l); + iterate_ast(pair.second, l); + }); + c.else_expression.apply([&l](auto& el) { + iterate_ast(el, l); + }); + } + }; + + template + struct ast_iterator, void> { + using node_type = as_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.expression, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = limit_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.lim, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = limit_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.lim, l); + a.off.apply([&l](auto& value) { + iterate_ast(value, l); + }); + } + }; + + template + struct ast_iterator, void> { + using node_type = limit_t; + + template + void operator()(const node_type& a, const L& l) const { + a.off.apply([&l](auto& value) { + iterate_ast(value, l); + }); + iterate_ast(a.lim, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = distinct_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.value, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = all_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.value, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = bitwise_not_t; + + template + void operator()(const node_type& a, const L& l) const { + iterate_ast(a.argument, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = values_t; + + template + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.tuple, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = dynamic_values_t; + + template + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.vector, l); + } + }; + + template + struct ast_iterator, void> { + using node_type = collate_t; + + template + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.expr, l); + } + }; + + } +} + +// #include "prepared_statement.h" + +// #include "connection_holder.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * This class does not related to SQL view. This is a container like class which is returned by + * by storage_t::iterate function. This class contains STL functions: + * - size_t size() + * - bool empty() + * - iterator end() + * - iterator begin() + * All these functions are not right const cause all of them may open SQLite connections. + */ + template + struct view_t { + using mapped_type = T; + using storage_type = S; + using self = view_t; + + storage_type& storage; + connection_ref connection; + get_all_t, Args...> args; + + view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : + storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} + + size_t size() { + return this->storage.template count(); + } + + bool empty() { + return !this->size(); + } + + iterator_t begin() { + sqlite3_stmt* stmt = nullptr; + auto db = this->connection.get(); + using context_t = serializator_context; + context_t context{this->storage.impl}; + context.skip_table_name = false; + context.replace_bindable_with_question = true; + auto query = serialize(this->args, context); + auto ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr); + if(ret == SQLITE_OK) { + auto index = 1; + iterate_ast(this->args.conditions, [&index, stmt, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + return {stmt, *this}; + } else { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + iterator_t end() { + return {}; + } + }; + } +} + +// #include "ast_iterator.h" + +// #include "storage_base.h" + +#include // std::function, std::bind +#include +#include // std::string +#include // std::stringstream +#include // std::move +#include // std::system_error, std::error_code, std::make_error_code +#include // std::vector +#include // std::make_shared, std::shared_ptr +#include // std::map +#include // std::decay, std::is_same +#include // std::iter_swap + +// #include "pragma.h" + +#include // std::string +#include +#include // std::function +#include // std::shared_ptr +#include // std::vector + +// #include "error_code.h" + +// #include "util.h" + +// #include "row_extractor.h" + +// #include "journal_mode.h" + +// #include "connection_holder.h" + +namespace sqlite_orm { + + namespace internal { + struct storage_base; + + template + int getPragmaCallback(void* data, int argc, char** argv, char**) { + auto& res = *(T*)data; + if(argc) { + res = row_extractor().extract(argv[0]); + } + return 0; + } + + template<> + inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { + auto& res = *(std::vector*)data; + res.reserve(argc); + for(decltype(argc) i = 0; i < argc; ++i) { + auto rowString = row_extractor().extract(argv[i]); + res.push_back(move(rowString)); + } + return 0; + } + + struct pragma_t { + using get_connection_t = std::function; + + pragma_t(get_connection_t get_connection_) : get_connection(move(get_connection_)) {} + + void busy_timeout(int value) { + this->set_pragma("busy_timeout", value); + } + + int busy_timeout() { + return this->get_pragma("busy_timeout"); + } + + sqlite_orm::journal_mode journal_mode() { + return this->get_pragma("journal_mode"); + } + + void journal_mode(sqlite_orm::journal_mode value) { + this->_journal_mode = -1; + this->set_pragma("journal_mode", value); + this->_journal_mode = static_cast_journal_mode)>(value); + } + + int synchronous() { + return this->get_pragma("synchronous"); + } + + void synchronous(int value) { + this->_synchronous = -1; + this->set_pragma("synchronous", value); + this->_synchronous = value; + } + + int user_version() { + return this->get_pragma("user_version"); + } + + void user_version(int value) { + this->set_pragma("user_version", value); + } + + int auto_vacuum() { + return this->get_pragma("auto_vacuum"); + } + + void auto_vacuum(int value) { + this->set_pragma("auto_vacuum", value); + } + + std::vector integrity_check() { + return this->get_pragma>("integrity_check"); + } + + template + std::vector integrity_check(T table_name) { + std::ostringstream oss; + oss << "integrity_check(" << table_name << ")"; + return this->get_pragma>(oss.str()); + } + + std::vector integrity_check(int n) { + std::ostringstream oss; + oss << "integrity_check(" << n << ")"; + return this->get_pragma>(oss.str()); + } + + private: + friend struct storage_base; + + int _synchronous = -1; + signed char _journal_mode = -1; // if != -1 stores static_cast(journal_mode) + get_connection_t get_connection; + + template + T get_pragma(const std::string& name) { + auto connection = this->get_connection(); + auto query = "PRAGMA " + name; + T result; + auto db = connection.get(); + auto rc = sqlite3_exec(db, query.c_str(), getPragmaCallback, &result, nullptr); + if(rc == SQLITE_OK) { + return result; + } else { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + /** + * Yevgeniy Zakharov: I wanted to refactor this function with statements and value bindings + * but it turns out that bindings in pragma statements are not supported. + */ + template + void set_pragma(const std::string& name, const T& value, sqlite3* db = nullptr) { + auto con = this->get_connection(); + if(!db) { + db = con.get(); + } + std::stringstream ss; + ss << "PRAGMA " << name << " = " << value; + internal::perform_void_exec(db, ss.str()); + } + + void set_pragma(const std::string& name, const sqlite_orm::journal_mode& value, sqlite3* db = nullptr) { + auto con = this->get_connection(); + if(!db) { + db = con.get(); + } + std::stringstream ss; + ss << "PRAGMA " << name << " = " << internal::to_string(value); + internal::perform_void_exec(db, ss.str()); + } + }; + } +} + +// #include "limit_accesor.h" + +#include +#include // std::map +#include // std::function +#include // std::shared_ptr + +// #include "connection_holder.h" + +namespace sqlite_orm { + + namespace internal { + + struct limit_accesor { + using get_connection_t = std::function; + + limit_accesor(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} + + int length() { + return this->get(SQLITE_LIMIT_LENGTH); + } + + void length(int newValue) { + this->set(SQLITE_LIMIT_LENGTH, newValue); + } + + int sql_length() { + return this->get(SQLITE_LIMIT_SQL_LENGTH); + } + + void sql_length(int newValue) { + this->set(SQLITE_LIMIT_SQL_LENGTH, newValue); + } + + int column() { + return this->get(SQLITE_LIMIT_COLUMN); + } + + void column(int newValue) { + this->set(SQLITE_LIMIT_COLUMN, newValue); + } + + int expr_depth() { + return this->get(SQLITE_LIMIT_EXPR_DEPTH); + } + + void expr_depth(int newValue) { + this->set(SQLITE_LIMIT_EXPR_DEPTH, newValue); + } + + int compound_select() { + return this->get(SQLITE_LIMIT_COMPOUND_SELECT); + } + + void compound_select(int newValue) { + this->set(SQLITE_LIMIT_COMPOUND_SELECT, newValue); + } + + int vdbe_op() { + return this->get(SQLITE_LIMIT_VDBE_OP); + } + + void vdbe_op(int newValue) { + this->set(SQLITE_LIMIT_VDBE_OP, newValue); + } + + int function_arg() { + return this->get(SQLITE_LIMIT_FUNCTION_ARG); + } + + void function_arg(int newValue) { + this->set(SQLITE_LIMIT_FUNCTION_ARG, newValue); + } + + int attached() { + return this->get(SQLITE_LIMIT_ATTACHED); + } + + void attached(int newValue) { + this->set(SQLITE_LIMIT_ATTACHED, newValue); + } + + int like_pattern_length() { + return this->get(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); + } + + void like_pattern_length(int newValue) { + this->set(SQLITE_LIMIT_LIKE_PATTERN_LENGTH, newValue); + } + + int variable_number() { + return this->get(SQLITE_LIMIT_VARIABLE_NUMBER); + } + + void variable_number(int newValue) { + this->set(SQLITE_LIMIT_VARIABLE_NUMBER, newValue); + } + + int trigger_depth() { + return this->get(SQLITE_LIMIT_TRIGGER_DEPTH); + } + + void trigger_depth(int newValue) { + this->set(SQLITE_LIMIT_TRIGGER_DEPTH, newValue); + } + +#if SQLITE_VERSION_NUMBER >= 3008007 + int worker_threads() { + return this->get(SQLITE_LIMIT_WORKER_THREADS); + } + + void worker_threads(int newValue) { + this->set(SQLITE_LIMIT_WORKER_THREADS, newValue); + } +#endif + + protected: + get_connection_t get_connection; + + friend struct storage_base; + + /** + * Stores limit set between connections. + */ + std::map limits; + + int get(int id) { + auto connection = this->get_connection(); + return sqlite3_limit(connection.get(), id, -1); + } + + void set(int id, int newValue) { + this->limits[id] = newValue; + auto connection = this->get_connection(); + sqlite3_limit(connection.get(), id, newValue); + } + }; + } +} + +// #include "transaction_guard.h" + +#include // std::function + +// #include "connection_holder.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * Class used as a guard for a transaction. Calls `ROLLBACK` in destructor. + * Has explicit `commit()` and `rollback()` functions. After explicit function is fired + * guard won't do anything in d-tor. Also you can set `commit_on_destroy` to true to + * make it call `COMMIT` on destroy. + */ + struct transaction_guard_t { + /** + * This is a public lever to tell a guard what it must do in its destructor + * if `gotta_fire` is true + */ + bool commit_on_destroy = false; + + transaction_guard_t(connection_ref connection_, + std::function commit_func_, + std::function rollback_func_) : + connection(std::move(connection_)), + commit_func(std::move(commit_func_)), rollback_func(std::move(rollback_func_)) {} + + ~transaction_guard_t() { + if(this->gotta_fire) { + if(!this->commit_on_destroy) { + this->rollback_func(); + } else { + this->commit_func(); + } + } + } + + /** + * Call `COMMIT` explicitly. After this call + * guard will not call `COMMIT` or `ROLLBACK` + * in its destructor. + */ + void commit() { + this->commit_func(); + this->gotta_fire = false; + } + + /** + * Call `ROLLBACK` explicitly. After this call + * guard will not call `COMMIT` or `ROLLBACK` + * in its destructor. + */ + void rollback() { + this->rollback_func(); + this->gotta_fire = false; + } + + protected: + connection_ref connection; + std::function commit_func; + std::function rollback_func; + bool gotta_fire = true; + }; + } +} + +// #include "statement_finalizer.h" + +// #include "type_printer.h" + +// #include "tuple_helper/tuple_helper.h" + +// #include "row_extractor.h" + +// #include "util.h" + +// #include "connection_holder.h" + +// #include "backup.h" + +#include +#include // std::string +#include + +// #include "error_code.h" + +// #include "connection_holder.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * A backup class. Don't construct it as is, call storage.make_backup_from or storage.make_backup_to instead. + * An instance of this class represents a wrapper around sqlite3_backup pointer. Use this class + * to have maximum control on a backup operation. In case you need a single backup in one line you + * can skip creating a backup_t instance and just call storage.backup_from or storage.backup_to function. + */ + struct backup_t { + backup_t(connection_ref to_, + const std::string& zDestName, + connection_ref from_, + const std::string& zSourceName, + std::unique_ptr holder_) : + handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())), + to(to_), from(from_), holder(move(holder_)) { + if(!this->handle) { + throw std::system_error(std::make_error_code(orm_error_code::failed_to_init_a_backup)); + } + } + + backup_t(backup_t&& other) : + handle(other.handle), to(other.to), from(other.from), holder(move(other.holder)) { + other.handle = nullptr; + } + + ~backup_t() { + if(this->handle) { + (void)sqlite3_backup_finish(this->handle); + this->handle = nullptr; + } + } + + /** + * Calls sqlite3_backup_step with pages argument + */ + int step(int pages) { + return sqlite3_backup_step(this->handle, pages); + } + + /** + * Returns sqlite3_backup_remaining result + */ + int remaining() const { + return sqlite3_backup_remaining(this->handle); + } + + /** + * Returns sqlite3_backup_pagecount result + */ + int pagecount() const { + return sqlite3_backup_pagecount(this->handle); + } + + protected: + sqlite3_backup* handle = nullptr; + connection_ref to; + connection_ref from; + std::unique_ptr holder; + }; + } +} + +// #include "function.h" + +// #include "values_to_tuple.h" + +#include +#include // std::get, std::tuple_element + +// #include "row_extractor.h" + +// #include "arg_values.h" + +#include + +// #include "row_extractor.h" + +namespace sqlite_orm { + + struct arg_value { + + arg_value() : arg_value(nullptr) {} + + arg_value(sqlite3_value* value_) : value(value_) {} + + template + T get() const { + return row_extractor().extract(this->value); + } + + bool is_null() const { + auto type = sqlite3_value_type(this->value); + return type == SQLITE_NULL; + } + + bool is_text() const { + auto type = sqlite3_value_type(this->value); + return type == SQLITE_TEXT; + } + + bool is_integer() const { + auto type = sqlite3_value_type(this->value); + return type == SQLITE_INTEGER; + } + + bool is_float() const { + auto type = sqlite3_value_type(this->value); + return type == SQLITE_FLOAT; + } + + bool is_blob() const { + auto type = sqlite3_value_type(this->value); + return type == SQLITE_BLOB; + } + + bool empty() const { + return this->value == nullptr; + } + + private: + sqlite3_value* value = nullptr; + }; + + struct arg_values { + + struct iterator { + + iterator(const arg_values& container_, int index_) : + container(container_), index(index_), + currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} + + iterator& operator++() { + ++this->index; + if(this->index < int(this->container.size())) { + this->currentValue = this->container[this->index]; + } else { + this->currentValue = {}; + } + return *this; + } + + iterator operator++(int) { + auto res = *this; + ++this->index; + if(this->index < int(this->container.size())) { + this->currentValue = this->container[this->index]; + } else { + this->currentValue = {}; + } + return res; + } + + arg_value operator*() const { + if(this->index < int(this->container.size()) && this->index >= 0) { + return this->currentValue; + } else { + throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds)); + } + } + + arg_value* operator->() const { + return &this->currentValue; + } + + bool operator==(const iterator& other) const { + return &other.container == &this->container && other.index == this->index; + } + + bool operator!=(const iterator& other) const { + return !(*this == other); + } + + private: + const arg_values& container; + int index = 0; + mutable arg_value currentValue; + }; + + arg_values() : arg_values(0, nullptr) {} + + arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} + + size_t size() const { + return this->argsCount; + } + + bool empty() const { + return 0 == this->argsCount; + } + + arg_value operator[](int index) const { + if(index < this->argsCount && index >= 0) { + auto valuePointer = this->values[index]; + return {valuePointer}; + } else { + throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds)); + } + } + + arg_value at(int index) const { + return this->operator[](index); + } + + iterator begin() const { + return {*this, 0}; + } + + iterator end() const { + return {*this, this->argsCount}; + } + + private: + int argsCount = 0; + sqlite3_value** values = nullptr; + }; +} + +namespace sqlite_orm { + + namespace internal { + + /** + * T is a std::tuple type + * I is index to extract value from values C array to tuple. I must me < std::tuple_size::value + */ + template + struct values_to_tuple { + + void extract(sqlite3_value** values, T& tuple, int argsCount) const { + using element_type = typename std::tuple_element::type; + std::get(tuple) = row_extractor().extract(values[I]); + + values_to_tuple().extract(values, tuple, argsCount); + } + }; + + template + struct values_to_tuple { + void extract(sqlite3_value** values, T& tuple, int argsCount) const { + //.. + } + }; + + template<> + struct values_to_tuple, 0> { + void extract(sqlite3_value** values, std::tuple& tuple, int argsCount) const { + std::get<0>(tuple) = arg_values(argsCount, values); + } + }; + } +} + +// #include "arg_values.h" + +namespace sqlite_orm { + + namespace internal { + + struct storage_base { + using collating_function = std::function; + + std::function on_open; + pragma_t pragma; + limit_accesor limit; + + transaction_guard_t transaction_guard() { + this->begin_transaction(); + auto commitFunc = std::bind(static_cast(&storage_base::commit), this); + auto rollbackFunc = std::bind(static_cast(&storage_base::rollback), this); + return {this->get_connection(), move(commitFunc), move(rollbackFunc)}; + } + + void drop_index(const std::string& indexName) { + std::stringstream ss; + ss << "DROP INDEX '" << indexName + "'"; + perform_void_exec(get_connection().get(), ss.str()); + } + + void vacuum() { + perform_void_exec(get_connection().get(), "VACUUM"); + } + + /** + * Drops table with given name. + */ + void drop_table(const std::string& tableName) { + auto con = this->get_connection(); + this->drop_table_internal(tableName, con.get()); + } + + /** + * Rename table named `from` to `to`. + */ + void rename_table(const std::string& from, const std::string& to) { + std::stringstream ss; + ss << "ALTER TABLE '" << from << "' RENAME TO '" << to << "'"; + perform_void_exec(get_connection().get(), ss.str()); + } + + /** + * sqlite3_changes function. + */ + int changes() { + auto con = this->get_connection(); + return sqlite3_changes(con.get()); + } + + /** + * sqlite3_total_changes function. + */ + int total_changes() { + auto con = this->get_connection(); + return sqlite3_total_changes(con.get()); + } + + int64 last_insert_rowid() { + auto con = this->get_connection(); + return sqlite3_last_insert_rowid(con.get()); + } + + int busy_timeout(int ms) { + auto con = this->get_connection(); + return sqlite3_busy_timeout(con.get(), ms); + } + + /** + * Returns libsqltie3 lib version, not sqlite_orm + */ + std::string libversion() { + return sqlite3_libversion(); + } + + bool transaction(const std::function& f) { + auto guard = transaction_guard(); + auto shouldCommit = f(); + if(shouldCommit) { + guard.commit(); + } else { + guard.rollback(); + } + return shouldCommit; + } + + std::string current_timestamp() { + auto con = this->get_connection(); + return this->current_timestamp(con.get()); + } + +#if SQLITE_VERSION_NUMBER >= 3007010 + /** + * \fn db_release_memory + * \brief Releases freeable memory of database. It is function can/should be called periodically by + * application, if application has less memory usage constraint. \note sqlite3_db_release_memory added + * in 3.7.10 https://sqlite.org/changes.html + */ + int db_release_memory() { + auto con = this->get_connection(); + return sqlite3_db_release_memory(con.get()); + } +#endif + + /** + * Returns existing permanent table names in database. Doesn't check storage itself - works only with + * actual database. + * @return Returns list of tables in database. + */ + std::vector table_names() { + auto con = this->get_connection(); + std::vector tableNames; + std::string sql = "SELECT name FROM sqlite_master WHERE type='table'"; + using data_t = std::vector; + auto db = con.get(); + int res = sqlite3_exec( + db, + sql.c_str(), + [](void* data, int argc, char** argv, char** /*columnName*/) -> int { + auto& tableNames_ = *(data_t*)data; + for(int i = 0; i < argc; i++) { + if(argv[i]) { + tableNames_.push_back(argv[i]); + } + } + return 0; + }, + &tableNames, + nullptr); + + if(res != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + return tableNames; + } + + void open_forever() { + this->isOpenedForever = true; + this->connection->retain(); + if(1 == this->connection->retain_count()) { + this->on_open_internal(this->connection->get()); + } + } + + /** + * Call this to create user defined scalar function. Can be called at any time no matter connection is opened or no. + * T - function class. T must have operator() overload and static name function like this: + * ``` + * struct SqrtFunction { + * + * double operator()(double arg) const { + * return std::sqrt(arg); + * } + * + * static const char *name() { + * return "SQRT"; + * } + * }; + * ``` + */ + template + void create_scalar_function() { + static_assert(is_scalar_function::value, "F cannot be a scalar function"); + + std::stringstream ss; + ss << F::name(); + auto name = ss.str(); + using args_tuple = typename callable_arguments::args_tuple; + using return_type = typename callable_arguments::return_type; + auto argsCount = int(std::tuple_size::value); + if(std::is_same>::value) { + argsCount = -1; + } + this->scalarFunctions.emplace_back(new scalar_function_t{ + move(name), + argsCount, + []() -> int* { + return (int*)(new F()); + }, + /* call = */ + [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) { + auto& functionPointer = *static_cast(functionVoidPointer); + args_tuple argsTuple; + using tuple_size = std::tuple_size; + values_to_tuple().extract(values, argsTuple, argsCount); + auto result = call(functionPointer, std::move(argsTuple)); + statement_binder().result(context, result); + }, + delete_function_callback, + }); + + if(this->connection->retain_count() > 0) { + auto db = this->connection->get(); + try_to_create_function(db, static_cast(*this->scalarFunctions.back())); + } + } + + /** + * Call this to create user defined aggregate function. Can be called at any time no matter connection is opened or no. + * T - function class. T must have step member function, fin member function and static name function like this: + * ``` + * struct MeanFunction { + * double total = 0; + * int count = 0; + * + * void step(double value) { + * total += value; + * ++count; + * } + * + * int fin() const { + * return total / count; + * } + * + * static std::string name() { + * return "MEAN"; + * } + * }; + * ``` + */ + template + void create_aggregate_function() { + static_assert(is_aggregate_function::value, "F cannot be an aggregate function"); + + std::stringstream ss; + ss << F::name(); + auto name = ss.str(); + using args_tuple = typename callable_arguments::args_tuple; + using return_type = typename callable_arguments::return_type; + auto argsCount = int(std::tuple_size::value); + if(std::is_same>::value) { + argsCount = -1; + } + this->aggregateFunctions.emplace_back(new aggregate_function_t{ + move(name), + argsCount, + /* create = */ + []() -> int* { + return (int*)(new F()); + }, + /* step = */ + [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) { + auto& functionPointer = *static_cast(functionVoidPointer); + args_tuple argsTuple; + using tuple_size = std::tuple_size; + values_to_tuple().extract(values, argsTuple, argsCount); + call(functionPointer, &F::step, move(argsTuple)); + }, + /* finalCall = */ + [](sqlite3_context* context, void* functionVoidPointer) { + auto& functionPointer = *static_cast(functionVoidPointer); + auto result = functionPointer.fin(); + statement_binder().result(context, result); + }, + delete_function_callback, + }); + + if(this->connection->retain_count() > 0) { + auto db = this->connection->get(); + try_to_create_function(db, static_cast(*this->aggregateFunctions.back())); + } + } + + /** + * Use it to delete scalar function you created before. Can be called at any time no matter connection is open or no. + */ + template + void delete_scalar_function() { + static_assert(is_scalar_function::value, "F cannot be a scalar function"); + std::stringstream ss; + ss << F::name(); + auto name = ss.str(); + this->delete_function_impl(name, this->scalarFunctions); + } + + /** + * Use it to delete aggregate function you created before. Can be called at any time no matter connection is open or no. + */ + template + void delete_aggregate_function() { + static_assert(is_aggregate_function::value, "F cannot be an aggregate function"); + std::stringstream ss; + ss << F::name(); + auto name = ss.str(); + this->delete_function_impl(name, this->aggregateFunctions); + } + + template + void create_collation() { + collating_function func = [](int leftLength, const void* lhs, int rightLength, const void* rhs) { + C collatingObject; + return collatingObject(leftLength, lhs, rightLength, rhs); + }; + std::stringstream ss; + ss << C::name(); + auto name = ss.str(); + ss.flush(); + this->create_collation(name, move(func)); + } + + void create_collation(const std::string& name, collating_function f) { + collating_function* functionPointer = nullptr; + const auto functionExists = bool(f); + if(functionExists) { + functionPointer = &(collatingFunctions[name] = std::move(f)); + } else { + collatingFunctions.erase(name); + } + + // create collations if db is open + if(this->connection->retain_count() > 0) { + auto db = this->connection->get(); + auto resultCode = sqlite3_create_collation(db, + name.c_str(), + SQLITE_UTF8, + functionPointer, + functionExists ? collate_callback : nullptr); + if(resultCode != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + + template + void delete_collation() { + std::stringstream ss; + ss << C::name(); + auto name = ss.str(); + ss.flush(); + this->create_collation(name, {}); + } + + void begin_transaction() { + this->connection->retain(); + if(1 == this->connection->retain_count()) { + this->on_open_internal(this->connection->get()); + } + auto db = this->connection->get(); + perform_void_exec(db, "BEGIN TRANSACTION"); + } + + void commit() { + auto db = this->connection->get(); + perform_void_exec(db, "COMMIT"); + this->connection->release(); + if(this->connection->retain_count() < 0) { + throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); + } + } + + void rollback() { + auto db = this->connection->get(); + perform_void_exec(db, "ROLLBACK"); + this->connection->release(); + if(this->connection->retain_count() < 0) { + throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); + } + } + + void backup_to(const std::string& filename) { + auto backup = this->make_backup_to(filename); + backup.step(-1); + } + + void backup_to(storage_base& other) { + auto backup = this->make_backup_to(other); + backup.step(-1); + } + + void backup_from(const std::string& filename) { + auto backup = this->make_backup_from(filename); + backup.step(-1); + } + + void backup_from(storage_base& other) { + auto backup = this->make_backup_from(other); + backup.step(-1); + } + + backup_t make_backup_to(const std::string& filename) { + auto holder = std::make_unique(filename); + connection_ref conRef{*holder}; + return {conRef, "main", this->get_connection(), "main", move(holder)}; + } + + backup_t make_backup_to(storage_base& other) { + return {other.get_connection(), "main", this->get_connection(), "main", {}}; + } + + backup_t make_backup_from(const std::string& filename) { + auto holder = std::make_unique(filename); + connection_ref conRef{*holder}; + return {this->get_connection(), "main", conRef, "main", move(holder)}; + } + + backup_t make_backup_from(storage_base& other) { + return {this->get_connection(), "main", other.get_connection(), "main", {}}; + } + + const std::string& filename() const { + return this->connection->filename; + } + + /** + * Checks whether connection to database is opened right now. + * Returns always `true` for in memory databases. + */ + bool is_opened() const { + return this->connection->retain_count() > 0; + } + + int busy_handler(std::function handler) { + _busy_handler = move(handler); + if(this->is_opened()) { + if(_busy_handler) { + return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } else { + return sqlite3_busy_handler(this->connection->get(), nullptr, nullptr); + } + } else { + return SQLITE_OK; + } + } + + protected: + storage_base(const std::string& filename_, int foreignKeysCount) : + pragma(std::bind(&storage_base::get_connection, this)), + limit(std::bind(&storage_base::get_connection, this)), + inMemory(filename_.empty() || filename_ == ":memory:"), + connection(std::make_unique(filename_)), cachedForeignKeysCount(foreignKeysCount) { + if(this->inMemory) { + this->connection->retain(); + this->on_open_internal(this->connection->get()); + } + } + + storage_base(const storage_base& other) : + on_open(other.on_open), pragma(std::bind(&storage_base::get_connection, this)), + limit(std::bind(&storage_base::get_connection, this)), inMemory(other.inMemory), + connection(std::make_unique(other.connection->filename)), + cachedForeignKeysCount(other.cachedForeignKeysCount) { + if(this->inMemory) { + this->connection->retain(); + this->on_open_internal(this->connection->get()); + } + } + + ~storage_base() { + if(this->isOpenedForever) { + this->connection->release(); + } + if(this->inMemory) { + this->connection->release(); + } + } + + connection_ref get_connection() { + connection_ref res{*this->connection}; + if(1 == this->connection->retain_count()) { + this->on_open_internal(this->connection->get()); + } + return res; + } + +#if SQLITE_VERSION_NUMBER >= 3006019 + + void foreign_keys(sqlite3* db, bool value) { + std::stringstream ss; + ss << "PRAGMA foreign_keys = " << value; + perform_void_exec(db, ss.str()); + } + + bool foreign_keys(sqlite3* db) { + std::string query = "PRAGMA foreign_keys"; + auto result = false; + auto rc = sqlite3_exec( + db, + query.c_str(), + [](void* data, int argc, char** argv, char**) -> int { + auto& res = *(bool*)data; + if(argc) { + res = row_extractor().extract(argv[0]); + } + return 0; + }, + &result, + nullptr); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + return result; + } + +#endif + void on_open_internal(sqlite3* db) { + +#if SQLITE_VERSION_NUMBER >= 3006019 + if(this->cachedForeignKeysCount) { + this->foreign_keys(db, true); + } +#endif + if(this->pragma._synchronous != -1) { + this->pragma.synchronous(this->pragma._synchronous); + } + + if(this->pragma._journal_mode != -1) { + this->pragma.set_pragma("journal_mode", static_cast(this->pragma._journal_mode), db); + } + + for(auto& p: this->collatingFunctions) { + auto resultCode = + sqlite3_create_collation(db, p.first.c_str(), SQLITE_UTF8, &p.second, collate_callback); + if(resultCode != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + for(auto& p: this->limit.limits) { + sqlite3_limit(db, p.first, p.second); + } + + if(_busy_handler) { + sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } + + for(auto& functionPointer: this->scalarFunctions) { + try_to_create_function(db, static_cast(*functionPointer)); + } + + for(auto& functionPointer: this->aggregateFunctions) { + try_to_create_function(db, static_cast(*functionPointer)); + } + + if(this->on_open) { + this->on_open(db); + } + } + + void delete_function_impl(const std::string& name, + std::vector>& functionsVector) const { + auto it = find_if(functionsVector.begin(), functionsVector.end(), [&name](auto& functionPointer) { + return functionPointer->name == name; + }); + if(it != functionsVector.end()) { + functionsVector.erase(it); + it = functionsVector.end(); + + if(this->connection->retain_count() > 0) { + auto db = this->connection->get(); + auto resultCode = sqlite3_create_function_v2(db, + name.c_str(), + 0, + SQLITE_UTF8, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr); + if(resultCode != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } else { + throw std::system_error(std::make_error_code(orm_error_code::function_not_found)); + } + } + + void try_to_create_function(sqlite3* db, scalar_function_t& function) { + auto resultCode = sqlite3_create_function_v2(db, + function.name.c_str(), + function.argumentsCount, + SQLITE_UTF8, + &function, + scalar_function_callback, + nullptr, + nullptr, + nullptr); + if(resultCode != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + void try_to_create_function(sqlite3* db, aggregate_function_t& function) { + auto resultCode = sqlite3_create_function(db, + function.name.c_str(), + function.argumentsCount, + SQLITE_UTF8, + &function, + nullptr, + aggregate_function_step_callback, + aggregate_function_final_callback); + if(resultCode != SQLITE_OK) { + throw std::system_error(std::error_code(resultCode, get_sqlite_error_category()), + sqlite3_errstr(resultCode)); + } + } + + static void + aggregate_function_step_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { + auto functionVoidPointer = sqlite3_user_data(context); + auto functionPointer = static_cast(functionVoidPointer); + auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**)); + auto aggregateContextIntPointer = static_cast(aggregateContextVoidPointer); + if(*aggregateContextIntPointer == nullptr) { + *aggregateContextIntPointer = functionPointer->create(); + } + functionPointer->step(context, *aggregateContextIntPointer, argsCount, values); + } + + static void aggregate_function_final_callback(sqlite3_context* context) { + auto functionVoidPointer = sqlite3_user_data(context); + auto functionPointer = static_cast(functionVoidPointer); + auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**)); + auto aggregateContextIntPointer = static_cast(aggregateContextVoidPointer); + functionPointer->finalCall(context, *aggregateContextIntPointer); + functionPointer->destroy(*aggregateContextIntPointer); + } + + static void scalar_function_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { + auto functionVoidPointer = sqlite3_user_data(context); + auto functionPointer = static_cast(functionVoidPointer); + std::unique_ptr callablePointer(functionPointer->create(), + functionPointer->destroy); + if(functionPointer->argumentsCount != -1 && functionPointer->argumentsCount != argsCount) { + throw std::system_error(std::make_error_code(orm_error_code::arguments_count_does_not_match)); + } + functionPointer->run(context, functionPointer, argsCount, values); + } + + template + static void delete_function_callback(int* pointer) { + auto voidPointer = static_cast(pointer); + auto fPointer = static_cast(voidPointer); + delete fPointer; + } + + std::string current_timestamp(sqlite3* db) { + std::string result; + std::stringstream ss; + ss << "SELECT CURRENT_TIMESTAMP"; + auto query = ss.str(); + auto rc = sqlite3_exec( + db, + query.c_str(), + [](void* data, int argc, char** argv, char**) -> int { + auto& res = *(std::string*)data; + if(argc) { + if(argv[0]) { + res = row_extractor().extract(argv[0]); + } + } + return 0; + }, + &result, + nullptr); + if(rc != SQLITE_OK) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + return result; + } + + void drop_table_internal(const std::string& tableName, sqlite3* db) { + std::stringstream ss; + ss << "DROP TABLE '" << tableName + "'"; + perform_void_exec(db, ss.str()); + } + + static int collate_callback(void* arg, int leftLen, const void* lhs, int rightLen, const void* rhs) { + auto& f = *(collating_function*)arg; + return f(leftLen, lhs, rightLen, rhs); + } + + static int busy_handler_callback(void* selfPointer, int triesCount) { + auto& storage = *static_cast(selfPointer); + if(storage._busy_handler) { + return storage._busy_handler(triesCount); + } else { + return 0; + } + } + + // returns foreign keys count in storage definition + template + static int foreign_keys_count(T& storageImpl) { + auto res = 0; + storageImpl.for_each([&res](auto& impl) { + res += impl.foreign_keys_count(); + }); + return res; + } + + const bool inMemory; + bool isOpenedForever = false; + std::unique_ptr connection; + std::map collatingFunctions; + const int cachedForeignKeysCount; + std::function _busy_handler; + std::vector> scalarFunctions; + std::vector> aggregateFunctions; + }; + } +} + +// #include "prepared_statement.h" + +// #include "expression_object_type.h" + +#include // std::decay +#include // std::reference_wrapper + +// #include "prepared_statement.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct expression_object_type; + + template + struct expression_object_type> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type>> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type>> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type> { + using type = typename replace_range_t::object_type; + }; + + template + struct expression_object_type, L, O>> { + using type = typename replace_range_t, L, O>::object_type; + }; + + template + struct expression_object_type> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type>> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type> { + using transformer_type = L; + using type = typename insert_range_t::object_type; + }; + + template + struct expression_object_type, L, O>> { + using type = typename insert_range_t, L, O>::object_type; + }; + + template + struct expression_object_type> { + using type = typename std::decay::type; + }; + + template + struct expression_object_type, Cols...>> { + using type = typename std::decay::type; + }; + + template + struct get_ref_t { + + template + auto& operator()(O& t) const { + return t; + } + }; + + template + struct get_ref_t> { + + template + auto& operator()(O& t) const { + return t.get(); + } + }; + + template + auto& get_ref(T& t) { + using arg_type = typename std::decay::type; + get_ref_t g; + return g(t); + } + + template + struct get_object_t; + + template + struct get_object_t : get_object_t {}; + + template + auto& get_object(T& t) { + using expression_type = typename std::decay::type; + get_object_t obj; + return obj(t); + } + + template + struct get_object_t> { + using expression_type = replace_t; + + template + auto& operator()(O& e) const { + return get_ref(e.obj); + } + }; + + template + struct get_object_t> { + using expression_type = insert_t; + + template + auto& operator()(O& e) const { + return get_ref(e.obj); + } + }; + + template + struct get_object_t> { + using expression_type = update_t; + + template + auto& operator()(O& e) const { + return get_ref(e.obj); + } + }; + } +} + +// #include "statement_serializator.h" + +#include // std::stringstream +#include // std::string +#include // std::enable_if, std::remove_pointer +#include // std::vector +#include // std::iter_swap +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + +// #include "core_functions.h" + +// #include "constraints.h" + +// #include "conditions.h" + +// #include "column.h" + +// #include "rowid.h" + +// #include "type_printer.h" + +// #include "table_name_collector.h" + +#include // std::set +#include // std::string +#include // std::function +#include // std::type_index + +// #include "select_constraints.h" + +// #include "alias.h" + +// #include "core_functions.h" + +namespace sqlite_orm { + + namespace internal { + + struct table_name_collector { + using table_name_set = std::set>; + using find_table_name_t = std::function; + + find_table_name_t find_table_name; + mutable table_name_set table_names; + + table_name_collector() = default; + + table_name_collector(find_table_name_t _find_table_name) : find_table_name(std::move(_find_table_name)) {} + + template + table_name_set operator()(const T&) const { + return {}; + } + + template + void operator()(F O::*, std::string alias = {}) const { + if(this->find_table_name) { + table_names.insert(std::make_pair(this->find_table_name(typeid(O)), move(alias))); + } + } + + template + void operator()(const column_pointer&) const { + if(this->find_table_name) { + table_names.insert({this->find_table_name(typeid(T)), ""}); + } + } + + template + void operator()(const alias_column_t& a) const { + (*this)(a.column, alias_extractor::get()); + } + + template + void operator()(const count_asterisk_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + if(!tableName.empty()) { + table_names.insert(std::make_pair(move(tableName), "")); + } + } + } + + template + void operator()(const asterisk_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + table_names.insert(std::make_pair(move(tableName), "")); + } + } + + template + void operator()(const object_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + table_names.insert(std::make_pair(move(tableName), "")); + } + } + + template + void operator()(const table_rowid_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + table_names.insert(std::make_pair(move(tableName), "")); + } + } + + template + void operator()(const table_oid_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + table_names.insert(std::make_pair(move(tableName), "")); + } + } + + template + void operator()(const table__rowid_t&) const { + if(this->find_table_name) { + auto tableName = this->find_table_name(typeid(T)); + table_names.insert(std::make_pair(move(tableName), "")); + } + } + }; + + } + +} + +// #include "column_names_getter.h" + +#include // std::string +#include // std::vector +#include // std::reference_wrapper + +// #include "error_code.h" + +// #include "select_constraints.h" + +namespace sqlite_orm { + + namespace internal { + + template + std::string serialize(const T& t, const C& context); + + template + struct column_names_getter { + using expression_type = T; + + template + std::vector operator()(const expression_type& t, const C& context) { + auto newContext = context; + newContext.skip_table_name = false; + auto columnName = serialize(t, newContext); + if(columnName.length()) { + return {move(columnName)}; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + } + }; + + template + std::vector get_column_names(const T& t, const C& context) { + column_names_getter serializator; + return serializator(t, context); + } + + template + struct column_names_getter, void> { + using expression_type = std::reference_wrapper; + + template + std::vector operator()(const expression_type& expression, const C& context) { + return get_column_names(expression.get(), context); + } + }; + + template + struct column_names_getter, void> { + using expression_type = asterisk_t; + + template + std::vector operator()(const expression_type&, const C&) { + std::vector res; + res.push_back("*"); + return res; + } + }; + + template + struct column_names_getter, void> { + using expression_type = object_t; + + template + std::vector operator()(const expression_type&, const C&) { + std::vector res; + res.push_back("*"); + return res; + } + }; + + template + struct column_names_getter, void> { + using expression_type = columns_t; + + template + std::vector operator()(const expression_type& cols, const C& context) { + std::vector columnNames; + columnNames.reserve(static_cast(cols.count)); + auto newContext = context; + newContext.skip_table_name = false; + iterate_tuple(cols.columns, [&columnNames, &newContext](auto& m) { + auto columnName = serialize(m, newContext); + if(columnName.length()) { + columnNames.push_back(columnName); + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + }); + return columnNames; + } + }; + + } +} + +// #include "order_by_serializator.h" + +#include // std::string +#include // std::vector +#include // std::stringstream + +namespace sqlite_orm { + + namespace internal { + + template + struct order_by_serializator; + + template + std::string serialize_order_by(const T& t, const C& context) { + order_by_serializator serializator; + return serializator(t, context); + } + + template + struct order_by_serializator, void> { + using statement_type = order_by_t; + + template + std::string operator()(const statement_type& orderBy, const C& context) const { + std::stringstream ss; + auto newContext = context; + newContext.skip_table_name = false; + auto columnName = serialize(orderBy.expression, newContext); + ss << columnName << " "; + if(orderBy._collate_argument.length()) { + ss << "COLLATE " << orderBy._collate_argument << " "; + } + switch(orderBy.asc_desc) { + case 1: + ss << "ASC"; + break; + case -1: + ss << "DESC"; + break; + } + return ss.str(); + } + }; + + template + struct order_by_serializator, void> { + using statement_type = dynamic_order_by_t; + + template + std::string operator()(const statement_type& orderBy, const C&) const { + std::vector expressions; + for(auto& entry: orderBy) { + std::string entryString; + { + std::stringstream ss; + ss << entry.name << " "; + if(!entry._collate_argument.empty()) { + ss << "COLLATE " << entry._collate_argument << " "; + } + switch(entry.asc_desc) { + case 1: + ss << "ASC"; + break; + case -1: + ss << "DESC"; + break; + } + entryString = ss.str(); + } + expressions.push_back(move(entryString)); + }; + std::stringstream ss; + ss << static_cast(orderBy) << " "; + for(size_t i = 0; i < expressions.size(); ++i) { + ss << expressions[i]; + if(i < expressions.size() - 1) { + ss << ", "; + } + } + ss << " "; + return ss.str(); + } + }; + + } +} + +// #include "values.h" + +// #include "table_type.h" + +// #include "indexed_column.h" + +// #include "function.h" + +// #include "ast/upsert_clause.h" + +// #include "ast/excluded.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct statement_serializator; + + template + std::string serialize(const T& t, const C& context) { + statement_serializator serializator; + return serializator(t, context); + } + + template + struct statement_serializator::value>::type> { + using statement_type = T; + + template + std::string operator()(const statement_type& statement, const C& context) { + if(context.replace_bindable_with_question) { + return "?"; + } else { + return field_printer{}(statement); + } + } + }; + + template + struct statement_serializator, void> { + using statement_type = excluded_t; + + template + std::string operator()(const statement_type& statement, const C& context) { + std::stringstream ss; + ss << "excluded."; + if(auto columnNamePointer = context.impl.column_name(statement.expression)) { + ss << "\"" << *columnNamePointer << "\""; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + return ss.str(); + } + }; +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = as_optional_t; + + template + std::string operator()(const statement_type& statement, const C& context) { + return serialize(statement.value, context); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = std::reference_wrapper; + + template + std::string operator()(const statement_type& s, const C& context) { + return serialize(s.get(), context); + } + }; + + template<> + struct statement_serializator { + using statement_type = std::nullptr_t; + + template + std::string operator()(const statement_type&, const C&) { + return "?"; + } + }; +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template<> + struct statement_serializator { + using statement_type = std::nullopt_t; + + template + std::string operator()(const statement_type&, const C&) { + return "?"; + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = alias_holder; + + template + std::string operator()(const statement_type&, const C&) { + return T::get(); + } + }; + + template + struct statement_serializator, std::tuple>, void> { + using statement_type = upsert_clause, std::tuple>; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << "ON CONFLICT"; + iterate_tuple(statement.target_args, [&ss, &context](auto& value) { + using value_type = typename std::decay::type; + auto needParenthesis = std::is_member_pointer::value; + ss << ' '; + if(needParenthesis) { + ss << '('; + } + ss << serialize(value, context); + if(needParenthesis) { + ss << ')'; + } + }); + ss << ' ' << "DO"; + if(std::tuple_size::value == 0) { + ss << " NOTHING"; + } else { + ss << " UPDATE"; + auto updateContext = context; + updateContext.use_parentheses = false; + iterate_tuple(statement.actions, [&ss, &updateContext](auto& value) { + ss << ' ' << serialize(value, updateContext); + }); + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = built_in_function_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << statement.serialize() << "("; + std::vector args; + using args_type = typename std::decay::type::args_type; + args.reserve(std::tuple_size::value); + iterate_tuple(statement.args, [&args, &context](auto& v) { + args.push_back(serialize(v, context)); + }); + for(size_t i = 0; i < args.size(); ++i) { + ss << args[i]; + if(i < args.size() - 1) { + ss << ", "; + } + } + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = function_call; + + template + std::string operator()(const statement_type& statement, const C& context) const { + using args_tuple = std::tuple; + + std::stringstream ss; + ss << F::name() << "("; + auto index = 0; + iterate_tuple(statement.args, [&context, &ss, &index](auto& v) { + auto value = serialize(v, context); + ss << value; + if(index < std::tuple_size::value - 1) { + ss << ", "; + } + ++index; + }); + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = as_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto tableAliasString = alias_extractor::get(); + return serialize(c.expression, context) + " AS " + tableAliasString; + } + }; + + template + struct statement_serializator, void> { + using statement_type = alias_column_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "'" << T::get() << "'."; + } + auto newContext = context; + newContext.skip_table_name = true; + ss << serialize(c.column, newContext); + return ss.str(); + } + }; + + template<> + struct statement_serializator { + using statement_type = std::string; + + template + std::string operator()(const statement_type& c, const C& context) const { + if(context.replace_bindable_with_question) { + return "?"; + } else { + return "\'" + c + "\'"; + } + } + }; + + template<> + struct statement_serializator { + using statement_type = const char*; + + template + std::string operator()(const char* c, const C& context) const { + if(context.replace_bindable_with_question) { + return "?"; + } else { + return std::string("'") + c + "'"; + } + } + }; + + template + struct statement_serializator { + using statement_type = F O::*; + + template + std::string operator()(const statement_type& m, const C& context) const { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "\"" << context.impl.find_table_name(typeid(O)) << "\"."; + } + if(auto columnnamePointer = context.column_name(m)) { + ss << "\"" << *columnnamePointer << "\""; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + return ss.str(); + } + }; + + template<> + struct statement_serializator { + using statement_type = rowid_t; + + template + std::string operator()(const statement_type& s, const C&) { + return static_cast(s); + } + }; + + template<> + struct statement_serializator { + using statement_type = oid_t; + + template + std::string operator()(const statement_type& s, const C&) { + return static_cast(s); + } + }; + + template<> + struct statement_serializator<_rowid_t, void> { + using statement_type = _rowid_t; + + template + std::string operator()(const statement_type& s, const C&) { + return static_cast(s); + } + }; + + template + struct statement_serializator, void> { + using statement_type = table_rowid_t; + + template + std::string operator()(const statement_type& s, const C& context) { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + } + ss << static_cast(s); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = table_oid_t; + + template + std::string operator()(const statement_type& s, const C& context) { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + } + ss << static_cast(s); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = table__rowid_t; + + template + std::string operator()(const statement_type& s, const C& context) { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + } + ss << static_cast(s); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = binary_operator; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto lhs = serialize(c.lhs, context); + auto rhs = serialize(c.rhs, context); + std::stringstream ss; + if(context.use_parentheses) { + ss << '('; + } + ss << lhs << " " << static_cast(c) << " " << rhs; + if(context.use_parentheses) { + ss << ')'; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = count_asterisk_t; + + template + std::string operator()(const statement_type&, const C& context) const { + return serialize(count_asterisk_without_type{}, context); + } + }; + + template<> + struct statement_serializator { + using statement_type = count_asterisk_without_type; + + template + std::string operator()(const statement_type& c, const C&) const { + std::stringstream ss; + auto functionName = c.serialize(); + ss << functionName << "(*)"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = distinct_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto expr = serialize(c.value, context); + ss << static_cast(c) << "(" << expr << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = all_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto expr = serialize(c.value, context); + ss << static_cast(c) << "(" << expr << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = column_pointer; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + if(!context.skip_table_name) { + ss << "'" << context.impl.find_table_name(typeid(T)) << "'."; + } + if(auto columnNamePointer = context.impl.column_name_simple(c.field)) { + ss << "\"" << *columnNamePointer << "\""; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = cast_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " ("; + ss << serialize(c.expression, context) << " AS " << type_printer().print() << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator::value>::type> { + using statement_type = T; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << serialize(c.left, context) << " "; + ss << static_cast(c) << " "; + ss << serialize(c.right, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = simple_case_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << "CASE "; + c.case_expression.apply([&ss, context](auto& c_) { + ss << serialize(c_, context) << " "; + }); + iterate_tuple(c.args, [&ss, context](auto& pair) { + ss << "WHEN " << serialize(pair.first, context) << " "; + ss << "THEN " << serialize(pair.second, context) << " "; + }); + c.else_expression.apply([&ss, context](auto& el) { + ss << "ELSE " << serialize(el, context) << " "; + }); + ss << "END"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = is_null_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << serialize(c.t, context) << " " << static_cast(c); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = is_not_null_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << serialize(c.t, context) << " " << static_cast(c); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = bitwise_not_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " "; + auto cString = serialize(c.argument, context); + ss << " (" << cString << " )"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = negated_condition_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " "; + auto cString = serialize(c.c, context); + ss << " (" << cString << " )"; + return ss.str(); + } + }; + + template + struct statement_serializator::value>::type> { + using statement_type = T; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto leftString = serialize(c.l, context); + auto rightString = serialize(c.r, context); + std::stringstream ss; + if(context.use_parentheses) { + ss << "("; + } + ss << leftString << " " << static_cast(c) << " " << rightString; + if(context.use_parentheses) { + ss << ")"; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = named_collate; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto newContext = context; + newContext.use_parentheses = false; + auto res = serialize(c.expr, newContext); + return res + " " + static_cast(c); + } + }; + + template + struct statement_serializator, void> { + using statement_type = collate_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto newContext = context; + newContext.use_parentheses = false; + auto res = serialize(c.expr, newContext); + return res + " " + static_cast(c); + } + }; + + template + struct statement_serializator, void> { + using statement_type = dynamic_in_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto leftString = serialize(c.left, context); + ss << leftString << " " << static_cast(c) << " "; + auto newContext = context; + newContext.use_parentheses = true; + ss << serialize(c.argument, newContext); + return ss.str(); + } + }; + + template + struct statement_serializator>, void> { + using statement_type = dynamic_in_t>; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto leftString = serialize(c.left, context); + ss << leftString << " " << static_cast(c) << " ("; + for(size_t index = 0; index < c.argument.size(); ++index) { + auto& value = c.argument[index]; + ss << serialize(value, context); + if(index < c.argument.size() - 1) { + ss << ", "; + } + } + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = in_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto leftString = serialize(c.left, context); + ss << leftString << " " << static_cast(c) << " ("; + std::vector args; + using args_type = std::tuple; + args.reserve(std::tuple_size::value); + iterate_tuple(c.argument, [&args, &context](auto& v) { + args.push_back(serialize(v, context)); + }); + for(size_t i = 0; i < args.size(); ++i) { + ss << args[i]; + if(i < args.size() - 1) { + ss << ", "; + } + } + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = like_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << serialize(c.arg, context) << " "; + ss << static_cast(c) << " "; + ss << serialize(c.pattern, context); + c.arg3.apply([&ss, &context](auto& value) { + ss << " ESCAPE " << serialize(value, context); + }); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = glob_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << serialize(c.arg, context) << " "; + ss << static_cast(c) << " "; + ss << serialize(c.pattern, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = between_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + auto expr = serialize(c.expr, context); + ss << expr << " " << static_cast(c) << " "; + ss << serialize(c.b1, context); + ss << " AND "; + ss << serialize(c.b2, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = exists_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " "; + ss << serialize(c.t, context); + return ss.str(); + } + }; + + template<> + struct statement_serializator { + using statement_type = autoincrement_t; + + template + std::string operator()(const statement_type& c, const C&) const { + return static_cast(c); + } + }; + + template + struct statement_serializator, void> { + using statement_type = primary_key_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto res = static_cast(c); + using columns_tuple = typename statement_type::columns_tuple; + auto columnsCount = std::tuple_size::value; + if(columnsCount) { + res += "("; + decltype(columnsCount) columnIndex = 0; + iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) { + if(auto columnNamePointer = context.column_name(column)) { + res += *columnNamePointer; + if(columnIndex < columnsCount - 1) { + res += ", "; + } + ++columnIndex; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + }); + res += ")"; + } + return res; + } + }; + + template + struct statement_serializator, void> { + using statement_type = unique_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + auto res = static_cast(c); + using columns_tuple = typename statement_type::columns_tuple; + auto columnsCount = std::tuple_size::value; + if(columnsCount) { + res += "("; + decltype(columnsCount) columnIndex = 0; + iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) { + if(auto columnNamePointer = context.column_name(column)) { + res += *columnNamePointer; + if(columnIndex < columnsCount - 1) { + res += ", "; + } + ++columnIndex; + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + }); + res += ")"; + } + return res; + } + }; + + template<> + struct statement_serializator { + using statement_type = collate_constraint_t; + + template + std::string operator()(const statement_type& c, const C&) const { + return static_cast(c); + } + }; + + template + struct statement_serializator, void> { + using statement_type = default_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + return static_cast(c) + " (" + serialize(c.value, context) + ")"; + } + }; + + template + struct statement_serializator, std::tuple>, void> { + using statement_type = foreign_key_t, std::tuple>; + + template + std::string operator()(const statement_type& fk, const C& context) const { + std::stringstream ss; + std::vector columnNames; + using columns_type_t = typename std::decay::type::columns_type; + constexpr const size_t columnsCount = std::tuple_size::value; + columnNames.reserve(columnsCount); + iterate_tuple(fk.columns, [&columnNames, &context](auto& v) { + if(auto columnNamePointer = context.impl.column_name(v)) { + columnNames.push_back(*columnNamePointer); + } else { + columnNames.push_back({}); + } + }); + ss << "FOREIGN KEY("; + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << "'" << columnNames[i] << "'"; + if(i < columnNames.size() - 1) { + ss << ", "; + } + } + ss << ") REFERENCES "; + std::vector referencesNames; + using references_type_t = typename std::decay::type::references_type; + constexpr const size_t referencesCount = std::tuple_size::value; + referencesNames.reserve(referencesCount); + { + using first_reference_t = typename std::tuple_element<0, references_type_t>::type; + using first_reference_mapped_type = typename internal::table_type::type; + auto refTableName = context.impl.find_table_name(typeid(first_reference_mapped_type)); + ss << '\'' << refTableName << '\''; + } + iterate_tuple(fk.references, [&referencesNames, &context](auto& v) { + if(auto columnNamePointer = context.impl.column_name(v)) { + referencesNames.push_back(*columnNamePointer); + } else { + referencesNames.push_back({}); + } + }); + ss << "("; + for(size_t i = 0; i < referencesNames.size(); ++i) { + ss << "'" << referencesNames[i] << "'"; + if(i < referencesNames.size() - 1) { + ss << ", "; + } + } + ss << ")"; + if(fk.on_update) { + ss << ' ' << static_cast(fk.on_update) << " " << fk.on_update._action; + } + if(fk.on_delete) { + ss << ' ' << static_cast(fk.on_delete) << " " << fk.on_delete._action; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = check_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + return static_cast(c) + " " + serialize(c.expression, context); + } + }; + + template + struct statement_serializator, void> { + using statement_type = column_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << "'" << c.name << "' "; + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + using constraints_type = typename column_type::constraints_type; + ss << type_printer().print() << " "; + { + std::vector constraintsStrings; + constexpr const size_t constraintsCount = std::tuple_size::value; + constraintsStrings.reserve(constraintsCount); + int primaryKeyIndex = -1; + int autoincrementIndex = -1; + int tupleIndex = 0; + iterate_tuple( + c.constraints, + [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context](auto& v) { + using constraint_type = typename std::decay::type; + constraintsStrings.push_back(serialize(v, context)); + if(is_primary_key::value) { + primaryKeyIndex = tupleIndex; + } else if(std::is_same::value) { + autoincrementIndex = tupleIndex; + } + ++tupleIndex; + }); + if(primaryKeyIndex != -1 && autoincrementIndex != -1 && autoincrementIndex < primaryKeyIndex) { + iter_swap(constraintsStrings.begin() + primaryKeyIndex, + constraintsStrings.begin() + autoincrementIndex); + } + for(auto& str: constraintsStrings) { + ss << str << ' '; + } + } + if(c.not_null()) { + ss << "NOT NULL "; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = remove_all_t; + + template + std::string operator()(const statement_type& rem, const C& context) const { + auto& tImpl = context.impl.template get_impl(); + std::stringstream ss; + ss << "DELETE FROM '" << tImpl.table.name << "' "; + iterate_tuple(rem.conditions, [&context, &ss](auto& v) { + ss << serialize(v, context); + }); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = replace_t; + + template + std::string operator()(const statement_type& rep, const C& context) const { + return serialize_replace_range_impl(rep, context, 1); + } + }; + + template + struct statement_serializator, void> { + using statement_type = insert_explicit; + + template + std::string operator()(const statement_type& ins, const C& context) const { + constexpr const size_t colsCount = std::tuple_size>::value; + static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); + using expression_type = typename std::decay::type; + using object_type = typename expression_object_type::type; + auto& tImpl = context.impl.template get_impl(); + std::stringstream ss; + ss << "INSERT INTO '" << tImpl.table.name << "' "; + std::vector columnNames; + columnNames.reserve(colsCount); + { + auto columnsContext = context; + columnsContext.skip_table_name = true; + iterate_tuple(ins.columns.columns, [&columnNames, &columnsContext](auto& m) { + auto columnName = serialize(m, columnsContext); + if(!columnName.empty()) { + columnNames.push_back(columnName); + } else { + throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + } + }); + } + ss << "("; + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << columnNames[i]; + if(i < columnNames.size() - 1) { + ss << ","; + } else { + ss << ")"; + } + ss << " "; + } + ss << "VALUES ("; + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << "?"; + if(i < columnNames.size() - 1) { + ss << ","; + } else { + ss << ")"; + } + ss << " "; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = update_t; + + template + std::string operator()(const statement_type& upd, const C& context) const { + using expression_type = typename std::decay::type; + using object_type = typename expression_object_type::type; + auto& tImpl = context.impl.template get_impl(); + + std::stringstream ss; + ss << "UPDATE '" << tImpl.table.name << "' SET "; + std::vector setColumnNames; + tImpl.table.for_each_column([&setColumnNames](auto& c) { + if(!c.template has>()) { + setColumnNames.emplace_back(c.name); + } + }); + for(size_t i = 0; i < setColumnNames.size(); ++i) { + ss << "\"" << setColumnNames[i] << "\"" + << " = ?"; + if(i < setColumnNames.size() - 1) { + ss << ","; + } + ss << " "; + } + ss << "WHERE "; + auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); + for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { + ss << "\"" << primaryKeyColumnNames[i] << "\"" + << " = ?"; + if(i < primaryKeyColumnNames.size() - 1) { + ss << " AND"; + } + ss << " "; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = set_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << static_cast(statement); + auto assignsCount = std::tuple_size::value; + decltype(assignsCount) assignIndex = 0; + auto leftContext = context; + leftContext.skip_table_name = true; + iterate_tuple(statement.assigns, + [&ss, &context, &leftContext, &assignIndex, assignsCount](auto& value) { + ss << ' ' << serialize(value.lhs, leftContext); + ss << ' ' << static_cast(value) << ' '; + ss << serialize(value.rhs, context); + if(assignIndex < assignsCount - 1) { + ss << ","; + } + ++assignIndex; + }); + return ss.str(); + } + }; + + template + struct statement_serializator, Wargs...>, void> { + using statement_type = update_all_t, Wargs...>; + + template + std::string operator()(const statement_type& upd, const C& context) const { + std::stringstream ss; + ss << "UPDATE "; + table_name_collector collector([&context](std::type_index ti) { + return context.impl.find_table_name(ti); + }); + iterate_ast(upd.set.assigns, collector); + if(!collector.table_names.empty()) { + if(collector.table_names.size() == 1) { + ss << " '" << collector.table_names.begin()->first << "' "; + ss << static_cast(upd.set) << " "; + std::vector setPairs; + auto leftContext = context; + leftContext.skip_table_name = true; + iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto& asgn) { + std::stringstream sss; + sss << serialize(asgn.lhs, leftContext); + sss << " " << static_cast(asgn) << " "; + sss << serialize(asgn.rhs, context) << " "; + setPairs.push_back(sss.str()); + }); + auto setPairsCount = setPairs.size(); + for(size_t i = 0; i < setPairsCount; ++i) { + ss << setPairs[i] << " "; + if(i < setPairsCount - 1) { + ss << ", "; + } + } + iterate_tuple(upd.conditions, [&context, &ss](auto& v) { + ss << serialize(v, context); + }); + return ss.str(); + } else { + throw std::system_error(std::make_error_code(orm_error_code::too_many_tables_specified)); + } + } else { + throw std::system_error(std::make_error_code(orm_error_code::incorrect_set_fields_specified)); + } + } + }; + + template + std::string serialize_insert_range_impl(const T& /*statement*/, const C& context, const int valuesCount) { + using object_type = typename expression_object_type::type; + auto& tImpl = context.impl.template get_impl(); + + std::stringstream ss; + ss << "INSERT INTO '" << tImpl.table.name << "' "; + std::vector columnNames; + auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); + + tImpl.table.for_each_column([&columnNames, &compositeKeyColumnNames](auto& c) { + using table_type = typename std::decay::type; + if(table_type::is_without_rowid || !c.template has>()) { + auto it = find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); + if(it == compositeKeyColumnNames.end()) { + columnNames.emplace_back(c.name); + } + } + }); + + const auto columnNamesCount = columnNames.size(); + if(columnNamesCount) { + ss << "("; + for(size_t i = 0; i < columnNamesCount; ++i) { + ss << "\"" << columnNames[i] << "\""; + if(i < columnNamesCount - 1) { + ss << ","; + } else { + ss << ")"; + } + ss << " "; + } + } else { + ss << "DEFAULT "; + } + ss << "VALUES "; + if(columnNamesCount) { + auto valuesString = [columnNamesCount] { + std::stringstream ss_; + ss_ << "("; + for(size_t i = 0; i < columnNamesCount; ++i) { + ss_ << "?"; + if(i < columnNamesCount - 1) { + ss_ << ", "; + } else { + ss_ << ")"; + } + } + return ss_.str(); + }(); + for(auto i = 0; i < valuesCount; ++i) { + ss << valuesString; + if(i < valuesCount - 1) { + ss << ","; + } + ss << " "; + } + } else if(valuesCount != 1) { + throw std::system_error(std::make_error_code(orm_error_code::cannot_use_default_value)); + } + + return ss.str(); + } + + template + struct statement_serializator, void> { + using statement_type = insert_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + return serialize_insert_range_impl(statement, context, 1); + } + }; + + template + struct statement_serializator, void> { + using statement_type = into_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + auto& tImpl = context.impl.template get_impl(); + ss << "INTO " << tImpl.table.name; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = columns_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + auto index = 0; + if(context.use_parentheses) { + ss << '('; + } + iterate_tuple(statement.columns, [&context, &ss, &index](auto& value) { + ss << serialize(value, context); + if(index < int(std::tuple_size>::value) - 1) { + ss << ", "; + } + ++index; + }); + if(context.use_parentheses) { + ss << ')'; + } + return ss.str(); + } + }; + + template + struct statement_serializator< + T, + typename std::enable_if::value || is_replace_raw::value>::type> { + using statement_type = T; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + if(is_insert_raw::value) { + ss << "INSERT"; + } else { + ss << "REPLACE"; + } + iterate_tuple(statement.args, [&context, &ss](auto& value) { + using value_type = typename std::decay::type; + ss << ' '; + if(is_columns::value) { + auto newContext = context; + newContext.skip_table_name = true; + newContext.use_parentheses = true; + ss << serialize(value, newContext); + } else if(is_values::value || is_select::value) { + auto newContext = context; + newContext.use_parentheses = false; + ss << serialize(value, newContext); + } else { + ss << serialize(value, context); + } + }); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = remove_t; + + template + std::string operator()(const statement_type&, const C& context) const { + auto& tImpl = context.impl.template get_impl(); + std::stringstream ss; + ss << "DELETE FROM '" << tImpl.table.name << "' "; + ss << "WHERE "; + auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); + for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { + ss << "\"" << primaryKeyColumnNames[i] << "\"" + << " = ? "; + if(i < primaryKeyColumnNames.size() - 1) { + ss << "AND "; + } + } + return ss.str(); + } + }; + + template + std::string serialize_replace_range_impl(const T& rep, const C& context, const int valuesCount) { + using expression_type = typename std::decay::type; + using object_type = typename expression_object_type::type; + auto& tImpl = context.impl.template get_impl(); + std::stringstream ss; + ss << "REPLACE INTO '" << tImpl.table.name << "' ("; + auto columnNames = tImpl.table.column_names(); + auto columnNamesCount = columnNames.size(); + for(size_t i = 0; i < columnNamesCount; ++i) { + ss << "\"" << columnNames[i] << "\""; + if(i < columnNamesCount - 1) { + ss << ", "; + } else { + ss << ") "; + } + } + ss << "VALUES "; + auto valuesString = [columnNamesCount] { + std::stringstream ss_; + ss_ << "("; + for(size_t i = 0; i < columnNamesCount; ++i) { + ss_ << "?"; + if(i < columnNamesCount - 1) { + ss_ << ", "; + } else { + ss_ << ")"; + } + } + return ss_.str(); + }(); + for(auto i = 0; i < valuesCount; ++i) { + ss << valuesString; + if(i < valuesCount - 1) { + ss << ","; + } + ss << " "; + } + return ss.str(); + } + + template + struct statement_serializator, void> { + using statement_type = replace_range_t; + + template + std::string operator()(const statement_type& rep, const C& context) const { + auto valuesCount = static_cast(std::distance(rep.range.first, rep.range.second)); + return serialize_replace_range_impl(rep, context, valuesCount); + } + }; + + template + struct statement_serializator, void> { + using statement_type = insert_range_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + const auto valuesCount = static_cast(std::distance(statement.range.first, statement.range.second)); + return serialize_insert_range_impl(statement, context, valuesCount); + } + }; + + template + std::string serialize_get_all_impl(const T& get, const C& context) { + using primary_type = typename T::type; + + table_name_collector collector; + collector.table_names.insert( + std::make_pair(context.impl.find_table_name(typeid(primary_type)), std::string{})); + iterate_ast(get.conditions, collector); + std::stringstream ss; + ss << "SELECT "; + auto& tImpl = context.impl.template get_impl(); + auto columnNames = tImpl.table.column_names(); + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << "\"" << tImpl.table.name << "\"." + << "\"" << columnNames[i] << "\""; + if(i < columnNames.size() - 1) { + ss << ", "; + } else { + ss << " "; + } + } + ss << "FROM "; + std::vector> tableNames(collector.table_names.begin(), + collector.table_names.end()); + for(size_t i = 0; i < tableNames.size(); ++i) { + auto& tableNamePair = tableNames[i]; + ss << "'" << tableNamePair.first << "' "; + if(!tableNamePair.second.empty()) { + ss << tableNamePair.second << " "; + } + if(int(i) < int(tableNames.size()) - 1) { + ss << ","; + } + ss << " "; + } + iterate_tuple(get.conditions, [&context, &ss](auto& v) { + ss << serialize(v, context); + }); + return ss.str(); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = get_all_optional_t; + + template + std::string operator()(const statement_type& get, const C& context) const { + return serialize_get_all_impl(get, context); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct statement_serializator, void> { + using statement_type = get_all_pointer_t; + + template + std::string operator()(const statement_type& get, const C& context) const { + return serialize_get_all_impl(get, context); + } + }; + + template + struct statement_serializator, void> { + using statement_type = get_all_t; + + template + std::string operator()(const statement_type& get, const C& context) const { + return serialize_get_all_impl(get, context); + } + }; + + template + std::string serialize_get_impl(const T&, const C& context) { + using primary_type = typename T::type; + auto& tImpl = context.impl.template get_impl(); + std::stringstream ss; + ss << "SELECT "; + auto columnNames = tImpl.table.column_names(); + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << "\"" << columnNames[i] << "\""; + if(i < columnNames.size() - 1) { + ss << ","; + } + ss << " "; + } + ss << "FROM '" << tImpl.table.name << "' WHERE "; + auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); + if(!primaryKeyColumnNames.empty()) { + for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { + ss << "\"" << primaryKeyColumnNames[i] << "\"" + << " = ? "; + if(i < primaryKeyColumnNames.size() - 1) { + ss << "AND"; + } + ss << ' '; + } + return ss.str(); + } else { + throw std::system_error(std::make_error_code(orm_error_code::table_has_no_primary_key_column)); + } + } + + template + struct statement_serializator, void> { + using statement_type = get_t; + + template + std::string operator()(const statement_type& get, const C& context) const { + return serialize_get_impl(get, context); + } + }; + + template + struct statement_serializator, void> { + using statement_type = get_pointer_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + return serialize_get_impl(statement, context); + } + }; + + template<> + struct statement_serializator { + using statement_type = insert_constraint; + + template + std::string operator()(const statement_type& statement, const C& context) const { + switch(statement) { + case insert_constraint::abort: + return "OR ABORT"; + case insert_constraint::fail: + return "OR FAIL"; + case insert_constraint::ignore: + return "OR IGNORE"; + case insert_constraint::replace: + return "OR REPLACE"; + case insert_constraint::rollback: + return "OR ROLLBACK"; + } + } + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = get_optional_t; + + template + std::string operator()(const statement_type& get, const C& context) const { + return serialize_get_impl(get, context); + } + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct statement_serializator, void> { + using statement_type = select_t; + + template + std::string operator()(const statement_type& sel, const C& context) const { + std::stringstream ss; + const auto isCompoundOperator = is_base_of_template::value; + if(!isCompoundOperator) { + if(!sel.highest_level && context.use_parentheses) { + ss << "("; + } + ss << "SELECT "; + } + if(get_distinct(sel.col)) { + ss << static_cast(distinct(0)) << " "; + } + auto columnNames = get_column_names(sel.col, context); + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << columnNames[i]; + if(i < columnNames.size() - 1) { + ss << ", "; + } + } + table_name_collector collector([&context](std::type_index ti) { + return context.impl.find_table_name(ti); + }); + const auto explicitFromItemsCount = count_tuple, is_from>::value; + if(!explicitFromItemsCount) { + iterate_ast(sel.col, collector); + iterate_ast(sel.conditions, collector); + join_iterator()([&collector, &context](const auto& c) { + using original_join_type = typename std::decay::type::join_type::type; + using cross_join_type = typename internal::mapped_type_proxy::type; + auto crossJoinedTableName = context.impl.find_table_name(typeid(cross_join_type)); + auto tableAliasString = alias_extractor::get(); + std::pair tableNameWithAlias(std::move(crossJoinedTableName), + std::move(tableAliasString)); + collector.table_names.erase(tableNameWithAlias); + }); + if(!collector.table_names.empty() && !isCompoundOperator) { + ss << " FROM "; + std::vector> tableNames(collector.table_names.begin(), + collector.table_names.end()); + for(size_t i = 0; i < tableNames.size(); ++i) { + auto& tableNamePair = tableNames[i]; + ss << "'" << tableNamePair.first << "'"; + if(!tableNamePair.second.empty()) { + ss << ' ' << tableNamePair.second; + } + if(int(i) < int(tableNames.size()) - 1) { + ss << ", "; + } + } + } + } + iterate_tuple(sel.conditions, [&context, &ss](auto& v) { + ss << ' ' << serialize(v, context); + }); + if(!is_base_of_template::value) { + if(!sel.highest_level && context.use_parentheses) { + ss << ")"; + } + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = indexed_column_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << serialize(statement.column_or_expression, context); + if(!statement._collation_name.empty()) { + ss << " COLLATE " << statement._collation_name; + } + if(statement._order) { + switch(statement._order) { + case -1: + ss << " DESC"; + break; + case 1: + ss << " ASC"; + break; + default: + throw std::system_error(std::make_error_code(orm_error_code::incorrect_order)); + } + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = index_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << "CREATE "; + if(statement.unique) { + ss << "UNIQUE "; + } + using columns_type = typename std::decay::type::columns_type; + using head_t = typename std::tuple_element<0, columns_type>::type::column_type; + using indexed_type = typename table_type::type; + ss << "INDEX IF NOT EXISTS '" << statement.name << "' ON '" + << context.impl.find_table_name(typeid(indexed_type)) << "' ("; + std::vector columnNames; + iterate_tuple(statement.columns, [&columnNames, &context](auto& v) { + auto columnName = serialize(v, context); + columnNames.push_back(move(columnName)); + }); + for(size_t i = 0; i < columnNames.size(); ++i) { + ss << columnNames[i]; + if(i < columnNames.size() - 1) { + ss << ", "; + } + } + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = from_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + using tuple = std::tuple; + + std::stringstream ss; + ss << "FROM "; + size_t index = 0; + iterate_tuple([&context, &ss, &index](auto* itemPointer) { + using mapped_type = typename std::remove_pointer::type; + + auto aliasString = alias_extractor::get(); + ss << "'" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) + << "'"; + if(aliasString.length()) { + ss << " '" << aliasString << "'"; + } + if(index < std::tuple_size::value - 1) { + ss << ", "; + } + ++index; + }); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = where_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << statement.serialize() << " "; + auto whereString = serialize(statement.expression, context); + ss << "( " << whereString << ") "; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = order_by_t; + + template + std::string operator()(const statement_type& orderBy, const C& context) const { + std::stringstream ss; + ss << static_cast(orderBy) << " "; + auto orderByString = serialize_order_by(orderBy, context); + ss << orderByString << " "; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = dynamic_order_by_t; + + template + std::string operator()(const statement_type& orderBy, const CC& context) const { + return serialize_order_by(orderBy, context); + } + }; + + template + struct statement_serializator, void> { + using statement_type = multi_order_by_t; + + template + std::string operator()(const statement_type& orderBy, const C& context) const { + std::stringstream ss; + std::vector expressions; + iterate_tuple(orderBy.args, [&expressions, &context](auto& v) { + auto expression = serialize_order_by(v, context); + expressions.push_back(move(expression)); + }); + ss << static_cast(orderBy) << " "; + for(size_t i = 0; i < expressions.size(); ++i) { + ss << expressions[i]; + if(i < expressions.size() - 1) { + ss << ", "; + } + } + ss << " "; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = cross_join_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " "; + ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = inner_join_t; + + template + std::string operator()(const statement_type& l, const C& context) const { + std::stringstream ss; + ss << static_cast(l) << " "; + auto aliasString = alias_extractor::get(); + ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; + if(aliasString.length()) { + ss << "'" << aliasString << "' "; + } + ss << serialize(l.constraint, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = on_t; + + template + std::string operator()(const statement_type& t, const C& context) const { + std::stringstream ss; + auto newContext = context; + newContext.skip_table_name = false; + ss << static_cast(t) << " " << serialize(t.arg, newContext) << " "; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = join_t; + + template + std::string operator()(const statement_type& l, const C& context) const { + std::stringstream ss; + ss << static_cast(l) << " "; + auto aliasString = alias_extractor::get(); + ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; + if(aliasString.length()) { + ss << "'" << aliasString << "' "; + } + ss << serialize(l.constraint, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = left_join_t; + + template + std::string operator()(const statement_type& l, const C& context) const { + std::stringstream ss; + ss << static_cast(l) << " "; + auto aliasString = alias_extractor::get(); + ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; + if(aliasString.length()) { + ss << "'" << aliasString << "' "; + } + ss << serialize(l.constraint, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = left_outer_join_t; + + template + std::string operator()(const statement_type& l, const C& context) const { + std::stringstream ss; + ss << static_cast(l) << " "; + auto aliasString = alias_extractor::get(); + ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; + if(aliasString.length()) { + ss << "'" << aliasString << "' "; + } + ss << serialize(l.constraint, context); + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = natural_join_t; + + template + std::string operator()(const statement_type& c, const C& context) const { + std::stringstream ss; + ss << static_cast(c) << " "; + ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = group_by_t; + + template + std::string operator()(const statement_type& groupBy, const C& context) const { + std::stringstream ss; + std::vector expressions; + auto newContext = context; + newContext.skip_table_name = false; + iterate_tuple(groupBy.args, [&expressions, &newContext](auto& v) { + auto expression = serialize(v, newContext); + expressions.push_back(expression); + }); + ss << static_cast(groupBy) << " "; + for(size_t i = 0; i < expressions.size(); ++i) { + ss << expressions[i]; + if(i < expressions.size() - 1) { + ss << ", "; + } + } + ss << " "; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = having_t; + + template + std::string operator()(const statement_type& hav, const C& context) const { + std::stringstream ss; + auto newContext = context; + newContext.skip_table_name = false; + ss << static_cast(hav) << " "; + ss << serialize(hav.t, newContext) << " "; + return ss.str(); + } + }; + + /** + * HO - has offset + * OI - offset is implicit + */ + template + struct statement_serializator, void> { + using statement_type = limit_t; + + template + std::string operator()(const statement_type& limt, const C& context) const { + auto newContext = context; + newContext.skip_table_name = false; + std::stringstream ss; + ss << static_cast(limt) << " "; + if(HO) { + if(OI) { + limt.off.apply([&newContext, &ss](auto& value) { + ss << serialize(value, newContext); + }); + ss << ", "; + ss << serialize(limt.lim, newContext); + } else { + ss << serialize(limt.lim, newContext) << " OFFSET "; + limt.off.apply([&newContext, &ss](auto& value) { + ss << serialize(value, newContext); + }); + } + } else { + ss << serialize(limt.lim, newContext); + } + return ss.str(); + } + }; + + template<> + struct statement_serializator { + using statement_type = default_values_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + return "DEFAULT VALUES"; + } + }; + + template + struct statement_serializator, void> { + using statement_type = using_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + auto newContext = context; + newContext.skip_table_name = true; + return static_cast(statement) + " (" + serialize(statement.column, newContext) + " )"; + } + }; + + template + struct statement_serializator, void> { + using statement_type = std::tuple; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + ss << '('; + auto index = 0; + using TupleSize = std::tuple_size; + iterate_tuple(statement, [&context, &index, &ss](auto& value) { + ss << serialize(value, context); + if(index < TupleSize::value - 1) { + ss << ", "; + } + ++index; + }); + ss << ')'; + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = values_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + if(context.use_parentheses) { + ss << '('; + } + ss << "VALUES "; + { + auto index = 0; + auto& tuple = statement.tuple; + using tuple_type = typename std::decay::type; + using TupleSize = std::tuple_size; + iterate_tuple(tuple, [&context, &index, &ss](auto& value) { + ss << serialize(value, context); + if(index < TupleSize::value - 1) { + ss << ", "; + } + ++index; + }); + } + if(context.use_parentheses) { + ss << ')'; + } + return ss.str(); + } + }; + + template + struct statement_serializator, void> { + using statement_type = dynamic_values_t; + + template + std::string operator()(const statement_type& statement, const C& context) const { + std::stringstream ss; + if(context.use_parentheses) { + ss << '('; + } + ss << "VALUES "; + { + auto vectorSize = statement.vector.size(); + for(decltype(vectorSize) index = 0; index < vectorSize; ++index) { + auto& value = statement.vector[index]; + ss << serialize(value, context); + if(index < vectorSize - 1) { + ss << ", "; + } + } + } + if(context.use_parentheses) { + ss << ')'; + } + return ss.str(); + } + }; + + } +} + +// #include "table_name_collector.h" + +// #include "object_from_column_builder.h" + +// #include "table.h" + +// #include "column.h" + +namespace sqlite_orm { + + namespace internal { + + /** + * Storage class itself. Create an instanse to use it as an interfacto to sqlite db by calling `make_storage` + * function. + */ + template + struct storage_t : storage_base { + using self = storage_t; + using impl_type = storage_impl; + + /** + * @param filename database filename. + * @param impl_ storage_impl head + */ + storage_t(const std::string& filename, impl_type impl_) : + storage_base{filename, foreign_keys_count(impl_)}, impl(std::move(impl_)) {} + + storage_t(const storage_t& other) : storage_base(other), impl(other.impl) {} + + protected: + impl_type impl; + + template + friend struct view_t; + + template + friend struct dynamic_order_by_t; + + template + friend struct iterator_t; + + template + friend struct serializator_context_builder; + + template + void create_table(sqlite3* db, const std::string& tableName, const I& tableImpl) { + using table_type = typename std::decay::type; + std::stringstream ss; + ss << "CREATE TABLE '" << tableName << "' ( "; + auto columnsCount = tableImpl.table.columns_count; + auto index = 0; + using context_t = serializator_context; + context_t context{this->impl}; + iterate_tuple(tableImpl.table.columns, [columnsCount, &index, &ss, &context](auto& c) { + ss << serialize(c, context); + if(index < columnsCount - 1) { + ss << ", "; + } + index++; + }); + ss << ")"; + if(table_type::is_without_rowid) { + ss << " WITHOUT ROWID "; + } + perform_void_exec(db, ss.str()); + } + + template + void backup_table(sqlite3* db, const I& tableImpl, const std::vector& columnsToIgnore) { + + // here we copy source table to another with a name with '_backup' suffix, but in case table with such + // a name already exists we append suffix 1, then 2, etc until we find a free name.. + auto backupTableName = tableImpl.table.name + "_backup"; + if(tableImpl.table_exists(backupTableName, db)) { + int suffix = 1; + do { + std::stringstream stream; + stream << suffix; + auto anotherBackupTableName = backupTableName + stream.str(); + if(!tableImpl.table_exists(anotherBackupTableName, db)) { + backupTableName = anotherBackupTableName; + break; + } + ++suffix; + } while(true); + } + + this->create_table(db, backupTableName, tableImpl); + + tableImpl.copy_table(db, backupTableName, columnsToIgnore); + + this->drop_table_internal(tableImpl.table.name, db); + + tableImpl.rename_table(db, backupTableName, tableImpl.table.name); + } + + template + void assert_mapped_type() const { + using mapped_types_tuples = std::tuple; + static_assert(tuple_helper::has_type::value, "type is not mapped to a storage"); + } + + template + void assert_insertable_type() const { + auto& tImpl = this->get_impl(); + using table_type = typename std::decay::type; + using columns_type = typename std::decay::type; + + using bool_type = std::integral_constant; + + static_if( + [](auto& tImpl) { + std::ignore = tImpl; + + // all right. it's a "without_rowid" table + }, + [](auto& tImpl) { + std::ignore = tImpl; + static_assert( + count_tuple::value <= 1, + "Attempting to execute 'insert' request into an noninsertable table was detected. " + "Insertable table cannot contain > 1 primary keys. Please use 'replace' instead of " + "'insert', or you can use 'insert' with explicit column listing."); + static_assert( + count_tuple::value == 0, + "Attempting to execute 'insert' request into an noninsertable table was detected. " + "Insertable table cannot contain non-standard primary keys. Please use 'replace' instead " + "of 'insert', or you can use 'insert' with explicit column listing."); + + // unfortunately, this static_assert's can't see an composite keys(( + })(tImpl); + } + + template + auto& get_impl() const { + return this->impl.template get_impl(); + } + + template + auto& get_impl() { + return this->impl.template get_impl(); + } + + public: + template + view_t iterate(Args&&... args) { + this->assert_mapped_type(); + + auto con = this->get_connection(); + return {*this, std::move(con), std::forward(args)...}; + } + + /** + * Delete from routine. + * O is an object's type. Must be specified explicitly. + * @param args optional conditions: `where`, `join` etc + * @example: storage.remove_all(); - DELETE FROM users + * @example: storage.remove_all(where(in(&User::id, {5, 6, 7}))); - DELETE FROM users WHERE id IN (5, 6, 7) + */ + template + void remove_all(Args&&... args) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::remove_all(std::forward(args)...)); + this->execute(statement); + } + + /** + * Delete routine. + * O is an object's type. Must be specified explicitly. + * @param ids ids of object to be removed. + */ + template + void remove(Ids... ids) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::remove(std::forward(ids)...)); + this->execute(statement); + } + + /** + * Update routine. Sets all non primary key fields where primary key is equal. + * O is an object type. May be not specified explicitly cause it can be deduced by + * compiler from first parameter. + * @param o object to be updated. + */ + template + void update(const O& o) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::update(std::ref(o))); + this->execute(statement); + } + + template + void update_all(internal::set_t set, Wargs... wh) { + auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); + this->execute(statement); + } + + protected: + template + std::string group_concat_internal(F O::*m, std::unique_ptr y, Args&&... args) { + this->assert_mapped_type(); + std::vector rows; + if(y) { + rows = this->select(sqlite_orm::group_concat(m, move(*y)), std::forward(args)...); + } else { + rows = this->select(sqlite_orm::group_concat(m), std::forward(args)...); + } + if(!rows.empty()) { + return move(rows.front()); + } else { + return {}; + } + } + + public: + /** + * SELECT * routine. + * O is an object type to be extracted. Must be specified explicitly. + * @return All objects of type O stored in database at the moment in `std::vector`. + * @note If you need to return the result in a different container type then use a different `get_all` function overload `get_all>` + * @example: storage.get_all() - SELECT * FROM users + * @example: storage.get_all(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id + */ + template + auto get_all(Args&&... args) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); + return this->execute(statement); + } + + /** + * SELECT * routine. + * O is an object type to be extracted. Must be specified explicitly. + * R is an explicit return type. This type must have `push_back(O &&)` function. + * @return All objects of type O stored in database at the moment in `R`. + * @example: storage.get_all>(); - SELECT * FROM users + * @example: storage.get_all>(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id + */ + template + auto get_all(Args&&... args) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); + return this->execute(statement); + } + + /** + * SELECT * routine. + * O is an object type to be extracted. Must be specified explicitly. + * @return All objects of type O as `std::unique_ptr` inside a `std::vector` stored in database at the moment. + * @note If you need to return the result in a different container type then use a different `get_all_pointer` function overload `get_all_pointer>` + * @example: storage.get_all_pointer(); - SELECT * FROM users + * @example: storage.get_all_pointer(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 + */ + template + auto get_all_pointer(Args&&... args) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); + return this->execute(statement); + } + + /** + * SELECT * routine. + * O is an object type to be extracted. Must be specified explicitly. + * R is a container type. std::vector> is default + * @return All objects of type O as std::unique_ptr stored in database at the moment. + * @example: storage.get_all_pointer>(); - SELECT * FROM users + * @example: storage.get_all_pointer>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 + */ + template + auto get_all_pointer(Args&&... args) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); + return this->execute(statement); + } + + /** + * Select * by id routine. + * throws std::system_error(orm_error_code::not_found, orm_error_category) if object not found with given + * id. throws std::system_error with orm_error_category in case of db error. O is an object type to be + * extracted. Must be specified explicitly. + * @return Object of type O where id is equal parameter passed or throws + * `std::system_error(orm_error_code::not_found, orm_error_category)` if there is no object with such id. + */ + template + O get(Ids... ids) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get(std::forward(ids)...)); + return this->execute(statement); + } + + /** + * The same as `get` function but doesn't throw an exception if noting found but returns std::unique_ptr + * with null value. throws std::system_error in case of db error. + */ + template + std::unique_ptr get_pointer(Ids... ids) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_pointer(std::forward(ids)...)); + return this->execute(statement); + } + + /** + * A previous version of get_pointer() that returns a shared_ptr + * instead of a unique_ptr. New code should prefer get_pointer() + * unless the data needs to be shared. + * + * @note + * Most scenarios don't need shared ownership of data, so we should prefer + * unique_ptr when possible. It's more efficient, doesn't require atomic + * ops for a reference count (which can cause major slowdowns on + * weakly-ordered platforms like ARM), and can be easily promoted to a + * shared_ptr, exactly like we're doing here. + * (Conversely, you _can't_ go from shared back to unique.) + */ + template + std::shared_ptr get_no_throw(Ids... ids) { + return std::shared_ptr(get_pointer(std::forward(ids)...)); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * The same as `get` function but doesn't throw an exception if noting found but + * returns an empty std::optional. throws std::system_error in case of db error. + */ + template + std::optional get_optional(Ids... ids) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_optional(std::forward(ids)...)); + return this->execute(statement); + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + /** + * SELECT COUNT(*) https://www.sqlite.org/lang_aggfunc.html#count + * @return Number of O object in table. + */ + template::type> + int count(Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::count(), std::forward(args)...); + if(!rows.empty()) { + return rows.front(); + } else { + return 0; + } + } + + /** + * SELECT COUNT(X) https://www.sqlite.org/lang_aggfunc.html#count + * @param m member pointer to class mapped to the storage. + * @return count of `m` values from database. + */ + template + int count(F O::*m, Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::count(m), std::forward(args)...); + if(!rows.empty()) { + return rows.front(); + } else { + return 0; + } + } + + /** + * AVG(X) query. https://www.sqlite.org/lang_aggfunc.html#avg + * @param m is a class member pointer (the same you passed into make_column). + * @return average value from database. + */ + template + double avg(F O::*m, Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::avg(m), std::forward(args)...); + if(!rows.empty()) { + return rows.front(); + } else { + return 0; + } + } + + template + std::string group_concat(F O::*m) { + return this->group_concat_internal(m, {}); + } + + /** + * GROUP_CONCAT(X) query. https://www.sqlite.org/lang_aggfunc.html#groupconcat + * @param m is a class member pointer (the same you passed into make_column). + * @return group_concat query result. + */ + template, + typename sfinae = typename std::enable_if::value >= 1>::type> + std::string group_concat(F O::*m, Args&&... args) { + return this->group_concat_internal(m, {}, std::forward(args)...); + } + + /** + * GROUP_CONCAT(X, Y) query. https://www.sqlite.org/lang_aggfunc.html#groupconcat + * @param m is a class member pointer (the same you passed into make_column). + * @return group_concat query result. + */ + template + std::string group_concat(F O::*m, std::string y, Args&&... args) { + return this->group_concat_internal(m, + std::make_unique(move(y)), + std::forward(args)...); + } + + template + std::string group_concat(F O::*m, const char* y, Args&&... args) { + std::unique_ptr str; + if(y) { + str = std::make_unique(y); + } else { + str = std::make_unique(); + } + return this->group_concat_internal(m, move(str), std::forward(args)...); + } + + /** + * MAX(x) query. + * @param m is a class member pointer (the same you passed into make_column). + * @return std::unique_ptr with max value or null if sqlite engine returned null. + */ + template::type> + std::unique_ptr max(F O::*m, Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::max(m), std::forward(args)...); + if(!rows.empty()) { + return std::move(rows.front()); + } else { + return {}; + } + } + + /** + * MIN(x) query. + * @param m is a class member pointer (the same you passed into make_column). + * @return std::unique_ptr with min value or null if sqlite engine returned null. + */ + template::type> + std::unique_ptr min(F O::*m, Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::min(m), std::forward(args)...); + if(!rows.empty()) { + return std::move(rows.front()); + } else { + return {}; + } + } + + /** + * SUM(x) query. + * @param m is a class member pointer (the same you passed into make_column). + * @return std::unique_ptr with sum value or null if sqlite engine returned null. + */ + template::type> + std::unique_ptr sum(F O::*m, Args&&... args) { + this->assert_mapped_type(); + std::vector> rows = + this->select(sqlite_orm::sum(m), std::forward(args)...); + if(!rows.empty()) { + if(rows.front()) { + return std::make_unique(std::move(*rows.front())); + } else { + return {}; + } + } else { + return {}; + } + } + + /** + * TOTAL(x) query. + * @param m is a class member pointer (the same you passed into make_column). + * @return total value (the same as SUM but not nullable. More details here + * https://www.sqlite.org/lang_aggfunc.html) + */ + template + double total(F O::*m, Args&&... args) { + this->assert_mapped_type(); + auto rows = this->select(sqlite_orm::total(m), std::forward(args)...); + if(!rows.empty()) { + return std::move(rows.front()); + } else { + return {}; + } + } + + /** + * Select a single column into std::vector or multiple columns into std::vector>. + * For a single column use `auto rows = storage.select(&User::id, where(...)); + * For multicolumns use `auto rows = storage.select(columns(&User::id, &User::name), where(...)); + */ + template::type> + std::vector select(T m, Args... args) { + static_assert(!is_base_of_template::value || + std::tuple_size>::value == 0, + "Cannot use args with a compound operator"); + auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); + return this->execute(statement); + } + + template + typename std::enable_if::value, std::string>::type + dump(const T& preparedStatement) const { + using context_t = serializator_context; + context_t context{this->impl}; + return serialize(preparedStatement.t, context); + } + + /** + * Returns a string representation of object of a class mapped to the storage. + * Type of string has json-like style. + */ + template + typename std::enable_if::value, std::string>::type + dump(const O& o) { + auto& tImpl = this->get_impl(); + std::stringstream ss; + ss << "{ "; + using pair = std::pair; + std::vector pairs; + tImpl.table.for_each_column([&pairs, &o](auto& c) { + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + pair p{c.name, std::string()}; + if(c.member_pointer) { + p.second = field_printer()(o.*c.member_pointer); + } else { + using getter_type = typename column_type::getter_type; + field_value_holder valueHolder{((o).*(c.getter))()}; + p.second = field_printer()(valueHolder.value); + } + pairs.push_back(move(p)); + }); + for(size_t i = 0; i < pairs.size(); ++i) { + auto& p = pairs[i]; + ss << p.first << " : '" << p.second << "'"; + if(i < pairs.size() - 1) { + ss << ", "; + } else { + ss << " }"; + } + } + return ss.str(); + } + + /** + * This is REPLACE (INSERT OR REPLACE) function. + * Also if you need to insert value with knows id you should + * also you this function instead of insert cause inserts ignores + * id and creates own one. + */ + template + void replace(const O& o) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::replace(std::ref(o))); + this->execute(statement); + } + + template + void replace_range(It from, It to) { + using O = typename std::iterator_traits::value_type; + this->assert_mapped_type(); + if(from == to) { + return; + } + + auto statement = this->prepare(sqlite_orm::replace_range(from, to)); + this->execute(statement); + } + + template + void replace_range(It from, It to, L transformer) { + this->assert_mapped_type(); + if(from == to) { + return; + } + + auto statement = this->prepare(sqlite_orm::replace_range(from, to, std::move(transformer))); + this->execute(statement); + } + + template + int insert(const O& o, columns_t cols) { + constexpr const size_t colsCount = std::tuple_size>::value; + static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::insert(std::ref(o), std::move(cols))); + return int(this->execute(statement)); + } + + /** + * Insert routine. Inserts object with all non primary key fields in passed object. Id of passed + * object doesn't matter. + * @return id of just created object. + */ + template + int insert(const O& o) { + this->assert_mapped_type(); + this->assert_insertable_type(); + + return call_insert_impl_and_catch_constraint_failed([this, &o]() { + auto statement = this->prepare(sqlite_orm::insert(std::ref(o))); + return int(this->execute(statement)); + }); + } + + /** + * Raw insert routine. Use this if `insert` with object does not fit you. This insert is designed to be able + * to call any type of `INSERT` query with no limitations. + * @example + * ```sql + * INSERT INTO users (id, name) VALUES(5, 'Little Mix') + * ``` + * will be + * ```c++ + * storage.insert(into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))); + * ``` + * One more example: + * ```sql + * INSERT INTO singers (name) VALUES ('Sofia Reyes')('Kungs') + * ``` + * will be + * ```c++ + * storage.insert(into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))); + * ``` + * One can use `default_values` to add `DEFAULT VALUES` modifier: + * ```sql + * INSERT INTO users DEFAULT VALUES + * ``` + * will be + * ```c++ + * storage.insert(into(), default_values()); + * ``` + * Also one can use `INSERT OR ABORT`/`INSERT OR FAIL`/`INSERT OR IGNORE`/`INSERT OR REPLACE`/`INSERT ROLLBACK`: + * ```c++ + * storage.insert(or_ignore(), into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))); + * storage.insert(or_rollback(), into(), default_values()); + * storage.insert(or_abort(), into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))); + * ``` + */ + template + void insert(Args... args) { + auto statement = this->prepare(sqlite_orm::insert(std::forward(args)...)); + this->execute(statement); + } + + /** + * Raw replace statement creation routine. Use this if `replace` with object does not fit you. This replace is designed to be able + * to call any type of `REPLACE` query with no limitations. Actually this is the same query as raw insert except `OR...` option existance. + * @example + * ```sql + * REPLACE INTO users (id, name) VALUES(5, 'Little Mix') + * ``` + * will be + * ```c++ + * storage.prepare(replace(into, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")))); + * ``` + * One more example: + * ```sql + * REPLACE INTO singers (name) VALUES ('Sofia Reyes')('Kungs') + * ``` + * will be + * ```c++ + * storage.prepare(replace(into(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")))); + * ``` + * One can use `default_values` to add `DEFAULT VALUES` modifier: + * ```sql + * REPLACE INTO users DEFAULT VALUES + * ``` + * will be + * ```c++ + * storage.prepare(replace(into(), default_values())); + * ``` + */ + template + void replace(Args... args) { + auto statement = this->prepare(sqlite_orm::replace(std::forward(args)...)); + this->execute(statement); + } + + template + void insert_range(It from, It to) { + using O = typename std::iterator_traits::value_type; + this->assert_mapped_type(); + this->assert_insertable_type(); + if(from == to) { + return; + } + + call_insert_impl_and_catch_constraint_failed([this, from, to]() { + auto statement = this->prepare(sqlite_orm::insert_range(from, to)); + this->execute(statement); + }); + } + + template + void insert_range(It from, It to, L transformer) { + this->assert_mapped_type(); + this->assert_insertable_type(); + if(from == to) { + return; + } + call_insert_impl_and_catch_constraint_failed([this, from, to, transformer = std::move(transformer)]() { + auto statement = this->prepare(sqlite_orm::insert_range(from, to, std::move(transformer))); + this->execute(statement); + }); + } + + /** + * Change table name inside storage's schema info. This function does not + * affect database + */ + template + void rename_table(std::string name) { + this->assert_mapped_type(); + auto& tImpl = this->get_impl(); + tImpl.table.name = move(name); + } + + using storage_base::rename_table; + + /** + * Get table's name stored in storage's schema info. This function does not call + * any SQLite queries + */ + template + const std::string& tablename() const { + this->assert_mapped_type(); + auto& tImpl = this->get_impl(); + return tImpl.table.name; + } + + template + const std::string* column_name(F O::*memberPointer) const { + return this->impl.column_name(memberPointer); + } + + protected: + template + sync_schema_result schema_status(const storage_impl, Tss...>&, sqlite3*, bool) { + return sync_schema_result::already_in_sync; + } + + template class TTable, class... Tss, class... Cs> + sync_schema_result + schema_status(const storage_impl, Tss...>& tImpl, sqlite3* db, bool preserve) { + return tImpl.schema_status(db, preserve); + } + + template + sync_schema_result sync_table(const storage_impl, Tss...>& tableImpl, sqlite3* db, bool) { + auto res = sync_schema_result::already_in_sync; + using context_t = serializator_context; + context_t context{this->impl}; + auto query = serialize(tableImpl.table, context); + perform_void_exec(db, query); + return res; + } + + template class TTable, class... Tss, class... Cs> + sync_schema_result + sync_table(const storage_impl, Tss...>& tImpl, sqlite3* db, bool preserve) { + auto res = sync_schema_result::already_in_sync; + + auto schema_stat = tImpl.schema_status(db, preserve); + if(schema_stat != decltype(schema_stat)::already_in_sync) { + if(schema_stat == decltype(schema_stat)::new_table_created) { + this->create_table(db, tImpl.table.name, tImpl); + res = decltype(res)::new_table_created; + } else { + if(schema_stat == sync_schema_result::old_columns_removed || + schema_stat == sync_schema_result::new_columns_added || + schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { + + // get table info provided in `make_table` call.. + auto storageTableInfo = tImpl.table.get_table_info(); + + // now get current table info from db using `PRAGMA table_info` query.. + auto dbTableInfo = tImpl.get_table_info(tImpl.table.name, db); + + // this vector will contain pointers to columns that gotta be added.. + std::vector columnsToAdd; + + tImpl.calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo); + + if(schema_stat == sync_schema_result::old_columns_removed) { + + // extra table columns than storage columns + this->backup_table(db, tImpl, {}); + res = decltype(res)::old_columns_removed; + } + + if(schema_stat == sync_schema_result::new_columns_added) { + for(auto columnPointer: columnsToAdd) { + tImpl.add_column(*columnPointer, db); + } + res = decltype(res)::new_columns_added; + } + + if(schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { + + // remove extra columns + this->backup_table(db, tImpl, columnsToAdd); + res = decltype(res)::new_columns_added_and_old_columns_removed; + } + } else if(schema_stat == sync_schema_result::dropped_and_recreated) { + this->drop_table_internal(tImpl.table.name, db); + this->create_table(db, tImpl.table.name, tImpl); + res = decltype(res)::dropped_and_recreated; + } + } + } + return res; + } + + template + prepared_statement_t prepare_impl(S statement) { + auto con = this->get_connection(); + sqlite3_stmt* stmt; + auto db = con.get(); + using context_t = serializator_context; + context_t context{this->impl}; + context.skip_table_name = false; + context.replace_bindable_with_question = true; + auto query = serialize(statement, context); + if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { + return prepared_statement_t{std::forward(statement), stmt, con}; + } else { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + + public: + /** + * This is a cute function used to replace migration up/down functionality. + * It performs check storage schema with actual db schema and: + * * if there are excess tables exist in db they are ignored (not dropped) + * * every table from storage is compared with it's db analog and + * * if table doesn't exist it is being created + * * if table exists its colums are being compared with table_info from db and + * * if there are columns in db that do not exist in storage (excess) table will be dropped and + * recreated + * * if there are columns in storage that do not exist in db they will be added using `ALTER TABLE + * ... ADD COLUMN ...' command + * * if there is any column existing in both db and storage but differs by any of + * properties/constraints (type, pk, notnull, dflt_value) table will be dropped and recreated Be aware that + * `sync_schema` doesn't guarantee that data will not be dropped. It guarantees only that it will make db + * schema the same as you specified in `make_storage` function call. A good point is that if you have no db + * file at all it will be created and all tables also will be created with exact tables and columns you + * specified in `make_storage`, `make_table` and `make_column` call. The best practice is to call this + * function right after storage creation. + * @param preserve affects on function behaviour in case it is needed to remove a column. If it is `false` + * so table will be dropped if there is column to remove, if `true` - table is being copied into another + * table, dropped and copied table is renamed with source table name. Warning: sync_schema doesn't check + * foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please + * submit an issue https://github.com/fnc12/sqlite_orm/issues + * @return std::map with std::string key equal table name and `sync_schema_result` as value. + * `sync_schema_result` is a enum value that stores table state after syncing a schema. `sync_schema_result` + * can be printed out on std::ostream with `operator<<`. + */ + std::map sync_schema(bool preserve = false) { + auto con = this->get_connection(); + std::map result; + auto db = con.get(); + this->impl.for_each([&result, db, preserve, this](auto& tableImpl) { + auto res = this->sync_table(tableImpl, db, preserve); + result.insert({tableImpl.table.name, res}); + }); + return result; + } + + /** + * This function returns the same map that `sync_schema` returns but it + * doesn't perform `sync_schema` actually - just simulates it in case you want to know + * what will happen if you sync your schema. + */ + std::map sync_schema_simulate(bool preserve = false) { + auto con = this->get_connection(); + std::map result; + auto db = con.get(); + this->impl.for_each([&result, db, preserve, this](auto& tableImpl) { + auto schemaStatus = this->schema_status(tableImpl, db, preserve); + result.insert({tableImpl.table.name, schemaStatus}); + }); + return result; + } + + /** + * Checks whether table exists in db. Doesn't check storage itself - works only with actual database. + * Note: table can be not mapped to a storage + * @return true if table with a given name exists in db, false otherwise. + */ + bool table_exists(const std::string& tableName) { + auto con = this->get_connection(); + return this->impl.table_exists(tableName, con.get()); + } + + template + prepared_statement_t> prepare(select_t sel) { + sel.highest_level = true; + return prepare_impl>(std::move(sel)); + } + + template + prepared_statement_t> prepare(get_all_t get_) { + return prepare_impl>(std::move(get_)); + } + + template + prepared_statement_t> prepare(get_all_pointer_t get_) { + return prepare_impl>(std::move(get_)); + } + + template + prepared_statement_t> prepare(replace_raw_t ins) { + return prepare_impl>(std::move(ins)); + } + + template + prepared_statement_t> prepare(insert_raw_t ins) { + return prepare_impl>(std::move(ins)); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + prepared_statement_t> prepare(get_all_optional_t get_) { + return prepare_impl>(std::move(get_)); + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + prepared_statement_t, Wargs...>> + prepare(update_all_t, Wargs...> upd) { + return prepare_impl, Wargs...>>(std::move(upd)); + } + + template + prepared_statement_t> prepare(remove_all_t rem) { + return prepare_impl>(std::move(rem)); + } + + template + prepared_statement_t> prepare(get_t get_) { + return prepare_impl>(std::move(get_)); + } + + template + prepared_statement_t> prepare(get_pointer_t get_) { + return prepare_impl>(std::move(get_)); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + prepared_statement_t> prepare(get_optional_t get_) { + return prepare_impl>(std::move(get_)); + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + prepared_statement_t> prepare(update_t upd) { + return prepare_impl>(std::move(upd)); + } + + template + prepared_statement_t> prepare(remove_t rem) { + return prepare_impl>(std::move(rem)); + } + + template + prepared_statement_t> prepare(insert_t ins) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + this->assert_insertable_type(); + return prepare_impl>(std::move(ins)); + } + + template + prepared_statement_t> prepare(replace_t rep) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + return prepare_impl>(std::move(rep)); + } + + template + prepared_statement_t> prepare(insert_range_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + this->assert_insertable_type(); + return prepare_impl>(std::move(statement)); + } + + template + prepared_statement_t> prepare(replace_range_t rep) { + return prepare_impl>(std::move(rep)); + } + + template + prepared_statement_t> prepare(insert_explicit ins) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + return prepare_impl>(std::move(ins)); + } + + template + void execute(const prepared_statement_t>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + sqlite3_reset(stmt); + auto index = 1; + iterate_ast(statement.t.args, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + } + + template + void execute(const prepared_statement_t>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + sqlite3_reset(stmt); + auto index = 1; + iterate_ast(statement.t.args, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + } + + template + int64 execute(const prepared_statement_t>& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using object_type = typename expression_object_type::type; + auto index = 1; + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto& tImpl = this->get_impl(); + auto& o = statement.t.obj; + sqlite3_reset(stmt); + iterate_tuple(statement.t.columns.columns, [&o, &index, &stmt, &tImpl, db](auto& m) { + using column_type = typename std::decay::type; + using field_type = typename column_result_t::type; + const field_type* value = tImpl.table.template get_object_field_pointer(o, m); + if(SQLITE_OK != statement_binder().bind(stmt, index++, *value)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + return sqlite3_last_insert_rowid(db); + } + + template::value || is_replace::value)>::type* = nullptr> + void execute(const prepared_statement_t& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using object_type = typename expression_object_type::type; + auto& tImpl = this->get_impl(); + auto index = 1; + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + sqlite3_reset(stmt); + + auto processObject = [&index, &stmt, &tImpl, db](auto& o) { + tImpl.table.for_each_column([&](auto& c) { + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + if(c.member_pointer) { + if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } else { + using getter_type = typename column_type::getter_type; + field_value_holder valueHolder{((o).*(c.getter))()}; + if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + }); + }; + + static_if{}>( + [&processObject](auto& statement) { + auto& transformer = statement.t.transformer; + std::for_each( /// + statement.t.range.first, + statement.t.range.second, + [&processObject, &transformer](auto& object) { + auto& realObject = transformer(object); + processObject(realObject); + }); + }, + [&processObject](auto& statement) { + auto& o = get_object(statement.t); + processObject(o); + })(statement); + perform_step(db, stmt); + } + + template::value || is_insert::value)>::type* = nullptr> + int64 execute(const prepared_statement_t& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using object_type = typename expression_object_type::type; + auto index = 1; + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto& tImpl = this->get_impl(); + auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); + sqlite3_reset(stmt); + auto processObject = [&index, &stmt, &tImpl, &compositeKeyColumnNames, db](auto& o) { + tImpl.table.for_each_column([&](auto& c) { + using table_type = typename std::decay::type; + if(table_type::is_without_rowid || !c.template has>()) { + auto it = std::find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); + if(it == compositeKeyColumnNames.end()) { + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + if(c.member_pointer) { + if(SQLITE_OK != + statement_binder().bind(stmt, index++, o.*c.member_pointer)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } else { + using getter_type = typename column_type::getter_type; + field_value_holder valueHolder{((o).*(c.getter))()}; + if(SQLITE_OK != + statement_binder().bind(stmt, index++, valueHolder.value)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + } + }); + }; + + static_if{}>( + [&processObject](auto& statement) { + auto& transformer = statement.t.transformer; + std::for_each( /// + statement.t.range.first, + statement.t.range.second, + [&processObject, &transformer](auto& object) { + auto& realObject = transformer(object); + processObject(realObject); + }); + }, + [&processObject](auto& statement) { + auto& o = get_object(statement.t); + processObject(o); + })(statement); + + perform_step(db, stmt); + return sqlite3_last_insert_rowid(db); + } + + template + void execute(const prepared_statement_t>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { + using field_type = typename std::decay::type; + if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + } + + template + void execute(const prepared_statement_t>& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using object_type = typename expression_object_type::type; + auto con = this->get_connection(); + auto db = con.get(); + auto& tImpl = this->get_impl(); + auto stmt = statement.stmt; + auto index = 1; + auto& o = get_object(statement.t); + sqlite3_reset(stmt); + tImpl.table.for_each_column([&o, stmt, &index, db](auto& c) { + if(!c.template has>()) { + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + if(c.member_pointer) { + auto bind_res = statement_binder().bind(stmt, index++, o.*c.member_pointer); + if(SQLITE_OK != bind_res) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } else { + using getter_type = typename column_type::getter_type; + field_value_holder valueHolder{((o).*(c.getter))()}; + if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + }); + tImpl.table.for_each_column([&o, stmt, &index, db](auto& c) { + if(c.template has>()) { + using column_type = typename std::decay::type; + using field_type = typename column_type::field_type; + if(c.member_pointer) { + if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } else { + using getter_type = typename column_type::getter_type; + field_value_holder valueHolder{((o).*(c.getter))()}; + if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { + throw std::system_error( + std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + }); + perform_step(db, stmt); + } + + template + std::unique_ptr execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { + using field_type = typename std::decay::type; + if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + auto res = std::make_unique(); + object_from_column_builder builder{*res, stmt}; + tImpl.table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + return {}; + } break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + std::optional execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { + using field_type = typename std::decay::type; + if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + auto res = std::make_optional(); + object_from_column_builder builder{res.value(), stmt}; + tImpl.table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + return {}; + } break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + T execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { + using field_type = typename std::decay::type; + if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + tImpl.table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error(std::make_error_code(sqlite_orm::orm_error_code::not_found)); + } break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } + + template + void execute(const prepared_statement_t>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + } + + template + void execute(const prepared_statement_t, Wargs...>>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_tuple(statement.t.set.assigns, [&index, stmt, db](auto& setArg) { + iterate_ast(setArg, [&index, stmt, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + }); + iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + perform_step(db, stmt); + } + + template::type> + std::vector execute(const prepared_statement_t>& statement) { + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + std::vector res; + auto tableInfoPointer = this->impl.template find_table(); + int stepRes; + do { + stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + using table_info_pointer_t = typename std::remove_pointer::type; + using table_info_t = typename std::decay::type; + row_extractor_builder::value, table_info_t> + builder; + auto rowExtractor = builder(tableInfoPointer); + res.push_back(rowExtractor.extract(stmt, 0)); + } break; + case SQLITE_DONE: + break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } while(stepRes != SQLITE_DONE); + return res; + } + + template + R execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + R res; + int stepRes; + do { + stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T obj; + object_from_column_builder builder{obj, stmt}; + tImpl.table.for_each_column(builder); + res.push_back(std::move(obj)); + } break; + case SQLITE_DONE: + break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } while(stepRes != SQLITE_DONE); + return res; + } + + template + R execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + R res; + int stepRes; + do { + stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + auto obj = std::make_unique(); + object_from_column_builder builder{*obj, stmt}; + tImpl.table.for_each_column(builder); + res.push_back(move(obj)); + } break; + case SQLITE_DONE: + break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } while(stepRes != SQLITE_DONE); + return res; + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + R execute(const prepared_statement_t>& statement) { + auto& tImpl = this->get_impl(); + auto con = this->get_connection(); + auto db = con.get(); + auto stmt = statement.stmt; + auto index = 1; + sqlite3_reset(stmt); + iterate_ast(statement.t, [stmt, &index, db](auto& node) { + using node_type = typename std::decay::type; + conditional_binder> binder{stmt, index}; + if(SQLITE_OK != binder(node)) { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + }); + R res; + int stepRes; + do { + stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + auto obj = std::make_optional(); + object_from_column_builder builder{*obj, stmt}; + tImpl.table.for_each_column(builder); + res.push_back(move(obj)); + } break; + case SQLITE_DONE: + break; + default: { + throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), + sqlite3_errmsg(db)); + } + } + } while(stepRes != SQLITE_DONE); + return res; + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + /*template + bool has_dependent_rows(const O& object) { + auto res = false; + using TupleWithForeignKeyTypes = typename storage_traits::storage_fk_references::type; + iterate_tuple([&res, this](auto *itemPointer){ + using ConstItem = typename std::remove_pointer::type; + using Item = typename std::decay::type; + if(!res) { + auto rows = this->select(count()); + if (!rows.empty()) { + res = rows[0]; + } + } + }); + return res; + }*/ + }; // struct storage_t + + template + struct is_storage : std::false_type {}; + + template + struct is_storage> : std::true_type {}; + } + + template + internal::storage_t make_storage(const std::string& filename, Ts... tables) { + return {filename, internal::storage_impl(std::forward(tables)...)}; + } + + /** + * sqlite3_threadsafe() interface. + */ + inline int threadsafe() { + return sqlite3_threadsafe(); + } +} +#pragma once + +#if defined(_MSC_VER) +#if defined(__RESTORE_MIN__) +__pragma(pop_macro("min")) +#undef __RESTORE_MIN__ +#endif +#if defined(__RESTORE_MAX__) + __pragma(pop_macro("max")) +#undef __RESTORE_MAX__ +#endif +#endif // defined(_MSC_VER) +#pragma once + +#include // std::tuple +#include // std::pair +#include // std::reference_wrapper +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + // #include "conditions.h" + + // #include "operators.h" + + // #include "select_constraints.h" + + // #include "prepared_statement.h" + + // #include "optional_container.h" + + // #include "core_functions.h" + + // #include "function.h" + + // #include "ast/excluded.h" + + // #include "ast/upsert_clause.h" + + // #include "ast/where.h" + + namespace sqlite_orm { + + namespace internal { + + template + struct node_tuple { + using type = std::tuple; + }; + + template<> + struct node_tuple { + using type = std::tuple<>; + }; +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct node_tuple, void> { + using type = typename node_tuple::type; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct node_tuple, void> { + using type = typename node_tuple::type; + }; + + template + struct node_tuple, std::tuple>, void> { + using type = typename node_tuple>::type; + }; + + template + struct node_tuple, void> { + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = where_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple::value>::type> { + using node_type = T; + using left_type = typename node_type::left_type; + using right_type = typename node_type::right_type; + using left_node_tuple = typename node_tuple::type; + using right_node_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = binary_operator; + using left_type = typename node_type::left_type; + using right_type = typename node_type::right_type; + using left_node_tuple = typename node_tuple::type; + using right_node_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = columns_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = dynamic_in_t; + using left_tuple = typename node_tuple::type; + using right_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = in_t; + using left_tuple = typename node_tuple::type; + using right_tuple = typename conc_tuple::type...>::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple::value>::type> { + using node_type = T; + using left_type = typename node_type::left_type; + using right_type = typename node_type::right_type; + using left_tuple = typename node_tuple::type; + using right_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = select_t; + using columns_tuple = typename node_tuple::type; + using args_tuple = typename conc_tuple::type...>::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = insert_raw_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = replace_raw_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = into_t; + using type = std::tuple<>; + }; + + template + struct node_tuple, void> { + using node_type = values_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = std::tuple; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = get_all_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = get_all_pointer_t; + using type = typename conc_tuple::type...>::type; + }; + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct node_tuple, void> { + using node_type = get_all_optional_t; + using type = typename conc_tuple::type...>::type; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + struct node_tuple, Wargs...>, void> { + using node_type = update_all_t, Wargs...>; + using set_tuple = typename conc_tuple::type...>::type; + using conditions_tuple = typename conc_tuple::type...>::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = remove_all_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = having_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = cast_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = exists_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = optional_container; + using type = typename node_tuple::type; + }; + + template<> + struct node_tuple, void> { + using node_type = optional_container; + using type = std::tuple<>; + }; + + template + struct node_tuple, void> { + using node_type = like_t; + using arg_tuple = typename node_tuple::type; + using pattern_tuple = typename node_tuple::type; + using escape_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = glob_t; + using arg_tuple = typename node_tuple::type; + using pattern_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = between_t; + using expression_tuple = typename node_tuple::type; + using lower_tuple = typename node_tuple::type; + using upper_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = named_collate; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = is_null_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = is_not_null_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = negated_condition_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = built_in_function_t; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = function_call; + using type = typename conc_tuple::type...>::type; + }; + + template + struct node_tuple, void> { + using node_type = left_join_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = on_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = join_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = left_outer_join_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = inner_join_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = simple_case_t; + using case_tuple = typename node_tuple::type; + using args_tuple = typename conc_tuple::type...>::type; + using else_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = std::pair; + using left_tuple = typename node_tuple::type; + using right_tuple = typename node_tuple::type; + using type = typename conc_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = as_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = limit_t; + using type = typename node_tuple::type; + }; + + template + struct node_tuple, void> { + using node_type = limit_t; + using type = typename conc_tuple::type, typename node_tuple::type>::type; + }; + + template + struct node_tuple, void> { + using node_type = limit_t; + using type = typename conc_tuple::type, typename node_tuple::type>::type; + }; + } +} +#pragma once + +#include // std::is_same, std::decay, std::remove_reference + +// #include "prepared_statement.h" + +// #include "ast_iterator.h" + +// #include "static_magic.h" + +// #include "expression_object_type.h" + +namespace sqlite_orm { + + template + auto& get(internal::prepared_statement_t>& statement) { + return std::get(statement.t.range); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return std::get(statement.t.range); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + return std::get(statement.t.range); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return std::get(statement.t.range); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + auto& get(internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template + auto& get(internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + return internal::get_ref(std::get(statement.t.ids)); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for update statement"); + return internal::get_ref(statement.t.obj); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for update statement"); + return internal::get_ref(statement.t.obj); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for insert statement"); + return internal::get_ref(statement.t.obj); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for insert statement"); + return internal::get_ref(statement.t.obj); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for replace statement"); + return internal::get_ref(statement.t.obj); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for replace statement"); + return internal::get_ref(statement.t.obj); + } + + template + auto& get(internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for insert statement"); + return internal::get_ref(statement.t.obj); + } + + template + const auto& get(const internal::prepared_statement_t>& statement) { + static_assert(N == 0, "get<> works only with 0 argument for insert statement"); + return internal::get_ref(statement.t.obj); + } + + template + const auto& get(const internal::prepared_statement_t& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using node_tuple = typename internal::node_tuple::type; + using bind_tuple = typename internal::bindable_filter::type; + using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + const result_tupe* result = nullptr; + auto index = -1; + internal::iterate_ast(statement.t, [&result, &index](auto& node) { + using node_type = typename std::decay::type; + if(internal::is_bindable::value) { + ++index; + } + if(index == N) { + internal::static_if{}>([](auto& r, auto& n) { + r = const_cast::type>(&n); + })(result, node); + } + }); + return internal::get_ref(*result); + } + + template + auto& get(internal::prepared_statement_t& statement) { + using statement_type = typename std::decay::type; + using expression_type = typename statement_type::expression_type; + using node_tuple = typename internal::node_tuple::type; + using bind_tuple = typename internal::bindable_filter::type; + using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + result_tupe* result = nullptr; + auto index = -1; + internal::iterate_ast(statement.t, [&result, &index](auto& node) { + using node_type = typename std::decay::type; + if(internal::is_bindable::value) { + ++index; + } + if(index == N) { + internal::static_if{}>([](auto& r, auto& n) { + r = const_cast::type>(&n); + })(result, node); + } + }); + return internal::get_ref(*result); + } +} diff --git a/src/main.cpp b/src/main.cpp index d4681a148..9cacab348 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -454,7 +454,7 @@ int main(){ frontendUI->setUIScale(uiScale); // auto native_me = std::this_thread::get_id().native_handle(); -#if WIN32 +#ifdef WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif //This has to be called after setting all callbacks specific to this app. diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 971d3c8e8..9c0c797fa 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -952,19 +952,54 @@ bool AdtObject::checkReferences( if (m_freeStrategy != nullptr) m_freeStrategy(false, true, m_mapApi->getCurrentSceneTime()); +// checkWmoM2ByRef(lodLevel, m2ObjectsCandidates, wmoCandidates, x, y, x_len, y_len); + checkWmoGlobally(lodLevel, m2ObjectsCandidates, wmoCandidates, x, y, x_len, y_len); + + return true; +} + +void +AdtObject::checkWmoGlobally(int lodLevel, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates, int x, + int y, + int x_len, int y_len) { + + if (lodLevel >= 4) { + for (auto const &m2Object : objectLods[0].m2Objects) + m2ObjectsCandidates.addCandidate(m2Object); + } else { + for (auto const &m2Object: objectLods[1].m2Objects) { + m2ObjectsCandidates.addCandidate(m2Object); + } + } + + if (lodLevel >= 4) { + for (auto const &wmoObject : objectLods[0].wmoObjects) + wmoCandidates.addCand(wmoObject); + } else { + for (auto const &wmoObject: objectLods[1].wmoObjects) { + wmoCandidates.addCand(wmoObject); + } + } +} + +void +AdtObject::checkWmoM2ByRef(int lodLevel, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates, + int x, int y, int x_len, + int y_len) { + // tbb::parallel_for(tbb::blocked_range2d(x,x+x_len,y,y+y_len), [&](const tbb::blocked_range2d& r) { // for (size_t k = r.rows().begin(); k != r.rows().end(); ++k) { // for (size_t l = r.cols().begin(); l != r.cols().end(); ++l) { // { - for (size_t k = x; k < x+x_len; k++) { - for (size_t l = y; l < y+y_len; ++l) { - int i = this->m_adtFile->mcnkMap[k][l]; + for (size_t k = x; k < x+x_len; k++) { + for (size_t l = y; l < y+y_len; ++l) { + int i = m_adtFile->mcnkMap[k][l]; - if (i < 0) continue; + if (i < 0) continue; - bool wotlk = false; - float chunkDist = 1.0; - if (wotlk) { + bool wotlk = false; + float chunkDist = 1.0; + if (wotlk) { // SMChunk *mapTile = &m_adtFile->mapTile[i]; // mcnkStruct_t *mcnkContent = &m_adtFile->mcnkStructs[i]; // @@ -988,40 +1023,39 @@ bool AdtObject::checkReferences( // uint32_t wmoRef = mcnkContent->mcrf.object_refs[j]; // wmoCandidates.insert(this->wmoObjects[j]); // } - } else { - SMChunk *mapTile = &m_adtFile->mapTile[i]; - mcnkStruct_t *mcnkContent = &m_adtFileObj->mcnkStructs[i]; - if (lodLevel >= 4) { - if (mcnkContent->mcrd_doodad_refs_len > 0) { - for (int j = 0; j < mcnkContent->mcrd_doodad_refs_len; j++) { - uint32_t m2Ref = mcnkContent->mcrd_doodad_refs[j]; - m2ObjectsCandidates.addCandidate(this->objectLods[0].m2Objects[m2Ref]); - } - } - } else { - for (auto &m2Object: this->objectLods[1].m2Objects) { - m2ObjectsCandidates.addCandidate(m2Object); + } else { + SMChunk *mapTile = &m_adtFile->mapTile[i]; + mcnkStruct_t *mcnkContent = &m_adtFileObj->mcnkStructs[i]; + if (lodLevel >= 4) { + if (mcnkContent->mcrd_doodad_refs_len > 0) { + for (int j = 0; j < mcnkContent->mcrd_doodad_refs_len; j++) { + uint32_t m2Ref = mcnkContent->mcrd_doodad_refs[j]; + m2ObjectsCandidates.addCandidate(objectLods[0].m2Objects[m2Ref]); } } + } else { + for (auto &m2Object: objectLods[1].m2Objects) { + m2ObjectsCandidates.addCandidate(m2Object); + } + } - if (lodLevel >= 4) { - if (mcnkContent->mcrw_object_refs_len > 0) { - for (int j = 0; j < mcnkContent->mcrw_object_refs_len; j++) { - uint32_t wmoRef = mcnkContent->mcrw_object_refs[j]; - wmoCandidates.addCand(this->objectLods[0].wmoObjects[wmoRef]); - } - } - } else { - for (auto &wmoObject: this->objectLods[1].wmoObjects) { - wmoCandidates.addCand(wmoObject); + if (lodLevel >= 4) { + if (mcnkContent->mcrw_object_refs_len > 0) { + for (int j = 0; j < mcnkContent->mcrw_object_refs_len; j++) { + uint32_t wmoRef = mcnkContent->mcrw_object_refs[j]; + wmoCandidates.addCand(objectLods[0].wmoObjects[wmoRef]); } } + } else { + for (auto const &wmoObject: objectLods[1].wmoObjects) { + wmoCandidates.addCand(wmoObject); + } } } } + } // },tbb::auto_partitioner()); - return true; } bool AdtObject::checkFrustumCulling(ADTObjRenderRes &adtFrustRes, diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 9409d3944..cc402a890 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -200,6 +200,15 @@ class AdtObject { void fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMaterialTemplate &adtMaterialTemplate); + void + checkWmoM2ByRef(int lodLevel, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates, int x, + int y, + int x_len, int y_len); + + void + checkWmoGlobally(int lodLevel, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates, int x, + int y, + int x_len, int y_len); }; From 9efd381854be0fc571b4a1c9e9bbdc5b34b1d606 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 4 Oct 2023 21:32:29 +0300 Subject: [PATCH 125/212] - fix validation error --- wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag | 3 --- .../src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp | 6 +++++- wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h | 4 +++- .../renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag index 20e2b17e9..02f3644bb 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.frag @@ -7,9 +7,6 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" - - layout(location = 0) in vec4 vColor; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index e174c2d90..6e9288d28 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -37,6 +37,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr if (uboBinding.set != setIndex) continue; auto uniformType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uint32_t stageOverride = 0; { if (typeOverrides.find(uboBinding.set) != typeOverrides.end()) { auto &setTypeOverrides = typeOverrides.at(uboBinding.set); @@ -44,6 +45,9 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr auto const &overrideStruct = setTypeOverrides.at(uboBinding.binding); assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); uniformType = overrideStruct.type; + if (overrideStruct.stageMask != 0) { + stageOverride = overrideStruct.stageMask; + } } } } @@ -61,7 +65,7 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr uboLayoutBinding.descriptorCount = 1; uboLayoutBinding.descriptorType = uniformType; uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = vkStageFlag; + uboLayoutBinding.stageFlags = stageOverride == 0 ? vkStageFlag : stageOverride; shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); if (uboBinding.size > 0) { diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 7b156727f..4c245e961 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -10,14 +10,16 @@ //Per DescSet -> per binding point struct DescTypeConfig { - VkDescriptorType type; + VkDescriptorType type = VK_DESCRIPTOR_TYPE_MAX_ENUM; bool isBindless = false; int descriptorCount = 1; + uint32_t stageMask; bool operator==(const DescTypeConfig &other) const { return (type == other.type) && (isBindless == other.isBindless) && + (stageMask == other.stageMask) && (descriptorCount == other.descriptorCount); }; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index ab3ecf6c0..53d6bcf0c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -21,7 +21,7 @@ static const ShaderConfig forwardShaderConfig = { "forwardRendering", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} }} } }; From bc87124f65c7669fe2e996e461ecff263c98f43d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 5 Oct 2023 22:09:26 +0300 Subject: [PATCH 126/212] Some changes --- .gitignore | 5 +- CMakeLists.txt | 23 +- wowViewerLib/3rdparty/mathfu | 2 +- wowViewerLib/3rdparty/oneTbb | 2 +- wowViewerLib/CMakeLists.txt | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1133 ++++++++++------- .../vulkan/commandBuffer/CommandBuffer.cpp | 2 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 16 +- .../descriptorSets/GDescriptorSetLayout.cpp | 17 +- .../descriptorSets/GDescriptorSetLayout.h | 8 +- 10 files changed, 691 insertions(+), 519 deletions(-) diff --git a/.gitignore b/.gitignore index 9d6a11da7..10c68e828 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ cache cache__ cache_old cmake-build-* -venv \ No newline at end of file +venv +/.vs +/out/build +/CMakeSettings.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fa32ad46..e0ee96131 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,20 +111,21 @@ add_compile_definitions(HAVE_LIMITS_H) SET(CMAKE_USE_LIBSSH2 0) SET(CPR_BUILD_TESTS 0) SET(CURL_ZLIB OFF CACHE STRING "" FORCE) # disable this lib to download the zlib as external project -FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/whoshuu/cpr.git GIT_TAG db351ffbbadc6c4e9239daaa26e9aefa9f0ec82d) # the commit hash for 1.8.3 +FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git GIT_TAG 2553fc41450301cd09a9271c8d2c3e0cf3546b73) # the commit hash for 1.8.3 -FetchContent_GetProperties(cpr) -message("cpr_POPULATED = ${cpr_POPULATED}") -if(NOT cpr_POPULATED) +FetchContent_MakeAvailable(cpr) +#FetchContent_GetProperties(cpr) +#message("cpr_POPULATED = ${cpr_POPULATED}") +#if(NOT cpr_POPULATED) # Fetch the content using previously declared details - FetchContent_Populate(cpr) - message("cpr_BINARY_DIR = ${cpr_BINARY_DIR}") - message("cpr_SOURCE_DIR = ${cpr_SOURCE_DIR}") + #FetchContent_Populate(cpr) + #message("cpr_BINARY_DIR = ${cpr_BINARY_DIR}") + #message("cpr_SOURCE_DIR = ${cpr_SOURCE_DIR}") # Bring the populated content into the build - set(BUILD_SHARED_LIBS ON CACHE BOOL "") - add_subdirectory(${cpr_SOURCE_DIR} ${cpr_BINARY_DIR} EXCLUDE_FROM_ALL) - set(BUILD_SHARED_LIBS OFF CACHE BOOL "") -endif() + #set(BUILD_SHARED_LIBS ON CACHE BOOL "") + #add_subdirectory(${cpr_SOURCE_DIR} ${cpr_BINARY_DIR} EXCLUDE_FROM_ALL) + #set(BUILD_SHARED_LIBS OFF CACHE BOOL "") +#endif() #StormLib #add_subdirectory(3rdparty/stormlib) diff --git a/wowViewerLib/3rdparty/mathfu b/wowViewerLib/3rdparty/mathfu index f3e7f0d22..da23a1227 160000 --- a/wowViewerLib/3rdparty/mathfu +++ b/wowViewerLib/3rdparty/mathfu @@ -1 +1 @@ -Subproject commit f3e7f0d22fd1e2317c8fade8db5d85fac1fd0322 +Subproject commit da23a1227bb65fbb7f2f5b6c504fbbdd1dfdab4b diff --git a/wowViewerLib/3rdparty/oneTbb b/wowViewerLib/3rdparty/oneTbb index 549f03220..28c87bcf4 160000 --- a/wowViewerLib/3rdparty/oneTbb +++ b/wowViewerLib/3rdparty/oneTbb @@ -1 +1 @@ -Subproject commit 549f032201ecd3dad8925d776394afafa021fe3a +Subproject commit 28c87bcf46ca82bcba2b27182dbc52967ef85b67 diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index c9cc530e6..ffd8b1cb3 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 1) +set(LINK_TRACY 0) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 1ae8d983a..69447f660 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,40 +295,19 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, + {0,0,84}, }, { { {0,0,1}, - {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -321,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,480}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -374,21 +372,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, + {0,2,12}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -399,14 +393,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -415,17 +409,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -437,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -452,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -469,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -489,14 +492,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -504,7 +509,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -525,15 +529,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -561,15 +565,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -597,14 +601,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -617,12 +622,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -633,15 +637,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,112}, + {0,0,480}, }, { { - {2,2,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -654,11 +659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -670,18 +674,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,17 +695,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -711,14 +710,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { @@ -819,14 +819,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,480}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -854,15 +855,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -875,10 +876,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -890,15 +893,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -926,18 +929,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,480}, - {1,1,64}, + {0,4,32}, }, { { - {0,0,1}, - {1,2,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -949,21 +950,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -973,15 +966,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -992,23 +985,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, }, { - {3,0, "s_Textures"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1017,15 +1004,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1038,11 +1024,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1053,15 +1040,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,16 +1076,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,4,32}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1110,12 +1098,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1125,17 +1116,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1147,21 +1137,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1171,16 +1152,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,480}, + {1,1,96}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1192,12 +1174,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1208,17 +1189,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,13 +1217,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1244,17 +1236,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1265,13 +1264,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1282,17 +1279,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,480}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1304,13 +1299,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1320,23 +1314,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,16}, + {1,3,4096}, {0,0,480}, - {1,1,64}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1347,17 +1337,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1366,16 +1353,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1403,15 +1389,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1439,11 +1424,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {1,4,96}, {0,0,480}, }, { @@ -1462,14 +1447,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1479,16 +1462,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1515,16 +1499,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,5,96}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,13 +1527,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1550,16 +1546,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1570,13 +1574,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1585,16 +1590,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,32}, + {0,0,480}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1606,13 +1612,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1622,18 +1636,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, {1,1,64}, {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {1,3,3}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1660,17 +1674,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1680,16 +1693,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, + {1,3,0}, }, { - {2,5, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1698,17 +1719,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1737,10 +1765,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1771,21 +1810,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2182,13 +2249,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2204,29 +2285,21 @@ const std::unordered_map(imageAvailable); poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; poolSizes[2].descriptorCount = static_cast(dynUniformsAvailable); - poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - poolSizes[3].descriptorCount = static_cast(ssboAvailable); + //poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + //poolSizes[3].descriptorCount = static_cast(ssboAvailable); VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -33,7 +33,8 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device, bool isBindless) : if (isBindless) poolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; - if (vkCreateDescriptorPool(m_device.getVkDevice(), &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS) { + auto result = vkCreateDescriptorPool(m_device.getVkDevice(), &poolInfo, nullptr, &m_descriptorPool); + if (result != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -67,9 +68,10 @@ VkDescriptorSet GDescriptorPoolVLK::allocate(const std::shared_ptr } } } - if (uniformType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - m_totalUbos++; - } else if (uniformType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { - m_totalDynUbos++; - } m_requiredBindPoints[uboBinding.binding] = true; } @@ -137,6 +132,18 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr return a.binding < b.binding; }); + m_totalUbos = 0; m_totalDynUbos = 0; m_totalImages = 0; + for (auto& layout : layouts) { + if (layout.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + m_totalUbos++; + } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { + m_totalDynUbos++; + } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { + m_totalImages++; + } + } + + VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags{}; binding_flags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; std::vector flags; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index d1b78f5a9..01976ce77 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -34,10 +34,10 @@ class GDescriptorSetLayout { const std::unordered_map& getRequiredSSBOSize() const {return m_requiredSSBOSize;} ; const std::vector& getBindlessDescSizes() const {return m_bindlessDescSizes;} ; - int getTotalUbos() { return m_totalUbos; }; - int getTotalDynUbos() { return m_totalDynUbos; }; - int getTotalImages() { return m_totalImages; }; - bool getIsBindless() { return m_isBindless; }; + int getTotalUbos() const { return m_totalUbos; }; + int getTotalDynUbos() const { return m_totalDynUbos; }; + int getTotalImages() const { return m_totalImages; }; + bool getIsBindless() const { return m_isBindless; }; std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; private: std::unordered_map m_shaderLayoutBindings; From 37588cd5fb918b60dfe0b1ff970512050d4526e8 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 8 Oct 2023 18:01:10 +0300 Subject: [PATCH 127/212] - temp commit before debug --- wowViewerLib/CMakeLists.txt | 13 +- .../src/engine/shader/ShaderDefinitions.h | 1139 +++++++---------- .../descriptorSets/GDescriptorPoolVLK.cpp | 5 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 8 +- .../bindless/BindlessTextureHolder.cpp | 41 + .../bindless/BindlessTextureHolder.h | 29 + .../mapScene/materials/BindlessTexture.h | 25 + .../mapScene/materials/IMaterialStructs.h | 2 + .../vulkan/MapSceneRenderForwardVLK.cpp | 133 +- .../vulkan/MapSceneRenderForwardVLK.h | 35 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 293 +++-- .../vulkan/MapSceneRenderVisBufferVLK.h | 14 +- .../vulkan/view/RenderViewForwardVLK.cpp | 140 ++ .../vulkan/view/RenderViewForwardVLK.h | 46 + 14 files changed, 969 insertions(+), 954 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h create mode 100644 wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index ffd8b1cb3..dfa3db16a 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -356,7 +356,8 @@ set(SOURCE_FILES src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h - src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h src/gapi/interface/buffers/IBufferVersioned.h) + src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h src/gapi/interface/buffers/IBufferVersioned.h + src/renderer/mapScene/materials/BindlessTexture.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -510,8 +511,8 @@ if (LINK_VULKAN) src/gapi/vulkan/GRenderPassVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h -# src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp -# src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h + src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp + src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -567,7 +568,11 @@ if (LINK_VULKAN) src/gapi/vulkan/buffers/gpu/BufferStagingVLK.h src/gapi/vulkan/buffers/gpu/BufferGpuVLK.cpp src/gapi/vulkan/buffers/gpu/BufferGpuVLK.h - src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h) + src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h + src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp + src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h + src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp + src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 69447f660..1ae8d983a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,19 +276,40 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {1,3,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -319,12 +321,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +336,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,17 +374,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -393,14 +399,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {3,9, "uBumpTexture"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,18 +415,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,21 +437,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +452,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,96}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +469,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,16 +489,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,64}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -509,6 +504,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -529,15 +525,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -565,15 +561,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -601,15 +597,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,11 +617,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -637,16 +633,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,480}, + {0,2,168}, }, { { - {0,1,2}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -659,10 +654,11 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -674,17 +670,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {2,5,96}, + {0,0,480}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -695,13 +692,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -710,15 +711,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,1,112}, + {0,0,480}, }, { { @@ -819,15 +819,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -855,15 +854,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -876,12 +875,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -893,15 +890,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,0,144}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,16 +926,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,2,48}, + {0,0,480}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,13 +949,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,15 +973,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {0,0,480}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -985,17 +992,23 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,8,0}, + {1,5,0}, + {1,4,0}, + {1,2,0}, + {1,1,0}, + {1,7,0}, + {1,6,0}, }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,14 +1017,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,12 +1038,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,15 +1053,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1076,17 +1089,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,0,84}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1110,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,16 +1125,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1137,12 +1147,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,17 +1171,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,4,32}, }, { { - {0,0,1}, - {1,1,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,11 +1192,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1189,24 +1208,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,2,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,17 +1229,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,24 +1244,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,4,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1264,11 +1265,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1279,15 +1282,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,96}, + {0,0,480}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1299,12 +1304,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1314,19 +1320,23 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,480}, + {1,1,64}, + {1,6,4096}, }, { { {0,0,1}, - {3,4,2}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1337,14 +1347,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,15 +1366,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,14 +1403,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { + {0,1,112}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,11 +1439,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, + {1,4,32}, {0,0,480}, }, { @@ -1447,12 +1462,14 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1462,17 +1479,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1499,24 +1515,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { - {0,0,1}, - {1,6,6}, - {5,5,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1527,17 +1535,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,24 +1550,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1574,14 +1570,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1590,17 +1585,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, - {4,4,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1612,21 +1606,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1636,18 +1622,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,16}, }, { { {0,0,1}, - {1,2,2}, + {1,3,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1674,16 +1660,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1693,24 +1680,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, - {1,5,0}, - {1,4,0}, - {1,2,0}, - {1,1,0}, - {1,7,0}, - {1,6,0}, - {1,3,0}, }, { - {3,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1719,24 +1698,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1765,21 +1737,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1810,6 +1771,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2249,27 +2182,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_2_5_values0", true, 0, 1, 4, 0}, + {"_2_5_values1", true, 16, 1, 4, 0}, + {"_2_5_values2", true, 32, 1, 4, 0}, + {"_2_5_values3", true, 48, 1, 4, 0}, + {"_2_5_values4", true, 64, 1, 4, 0}, + {"_2_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -2285,21 +2204,29 @@ const std::unordered_mapgetTotalUbos(); dynUniformsAvailable -= hDescriptorSetLayout->getTotalDynUbos(); imageAvailable -= hDescriptorSetLayout->getTotalImages(); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index f2e0594eb..074853426 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -198,17 +198,17 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptr &buffer) { auto &slb = m_set.m_hDescriptorSetLayout->getShaderLayoutBindings(); - auto &uboSizes = m_set.m_hDescriptorSetLayout->getRequiredUBOSize(); + auto &ssboSizes = m_set.m_hDescriptorSetLayout->getRequiredSSBOSize(); #if (!defined(NDEBUG)) if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - std::cerr << "descriptor mismatch for UBO" << std::endl; + std::cerr << "descriptor mismatch for SSBO" << std::endl; throw std::runtime_error("descriptor mismatch for UBO"); } - if (uboSizes.find(bindIndex) != uboSizes.end() && buffer->getSize() != uboSizes.at(bindIndex)) { + if (ssboSizes.find(bindIndex) != ssboSizes.end() && buffer->getSize() != ssboSizes.at(bindIndex)) { std::cout << "buffers missmatch! for" << " binding = " << bindIndex - << " expected size " << uboSizes.at(bindIndex) + << " expected size " << ssboSizes.at(bindIndex) << ", provided size = " << (buffer->getSize()) << std::endl; } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp new file mode 100644 index 000000000..e5d957c6b --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp @@ -0,0 +1,41 @@ +// +// Created by Deamon on 10/6/2023. +// + +#include "BindlessTextureHolder.h" + +BindlessTextureHolder::BindlessTextureHolder(uint32_t textureCount) : + m_textureAllocator(OffsetAllocator::Allocator(textureCount)){ + +} + +std::shared_ptr BindlessTextureHolder::allocate(const HGSamplableTexture &texture) { + auto weakTexture = std::weak_ptr(texture); + + auto i = m_textureMap.find(weakTexture); + if (i != m_textureMap.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + m_textureMap.erase(i); + } + } + + OffsetAllocator::Allocation textNum = m_textureAllocator.allocate(1); + if (textNum.offset == OffsetAllocator::Allocation::NO_SPACE) { + std::cerr << "Could not allocate bindless texture"; + throw "oops"; + } + + auto l_weak = this->weak_from_this(); + auto bindlessTexture = std::make_shared(textNum.offset, [l_weak, textNum]() { + auto l_this = l_weak.lock(); + if (l_this == nullptr) return; + + l_this->m_textureAllocator.free(textNum); + }); + + m_textureMap[weakTexture] = bindlessTexture; + + return bindlessTexture; +} diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h new file mode 100644 index 000000000..643837a1f --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h @@ -0,0 +1,29 @@ +// +// Created by Deamon on 10/6/2023. +// + +#ifndef AWEBWOWVIEWERCPP_BINDLESSTEXTUREHOLDER_H +#define AWEBWOWVIEWERCPP_BINDLESSTEXTUREHOLDER_H + + +#include +#include "../../../interface/IDevice.h" +#include "../../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" +#include "../../../../include/custom_container_key.h" +#include "../GDescriptorSet.h" + +class BindlessTextureHolder : public std::enable_shared_from_this { +public: + BindlessTextureHolder(uint32_t textureCount); + + std::shared_ptr allocate(const HGSamplableTexture& texture); + +private: + OffsetAllocator::Allocator m_textureAllocator; + + //Texture -> Bindless in array + std::unordered_map>, std::weak_ptr> m_textureMap; +}; + + +#endif //AWEBWOWVIEWERCPP_BINDLESSTEXTUREHOLDER_H diff --git a/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h b/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h new file mode 100644 index 000000000..83c1cf352 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h @@ -0,0 +1,25 @@ +// +// Created by Deamon on 10/8/2023. +// + +#ifndef AWEBWOWVIEWERCPP_BINDLESSTEXTURE_H +#define AWEBWOWVIEWERCPP_BINDLESSTEXTURE_H + +#include +#include + +//Bindless stuff +class BindlessTexture { +public: + BindlessTexture(uint32_t index, const std::function &onDestroy): m_index(index){}; + ~BindlessTexture() { + if (onDestroy) onDestroy(); + } + uint32_t getIndex() const {return m_index;}; +private: + std::function onDestroy; + uint32_t m_index; +}; + + +#endif //AWEBWOWVIEWERCPP_BINDLESSTEXTURE_H diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 413f6f119..f5864b507 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -7,6 +7,7 @@ #include "../../../gapi/interface/materials/IMaterial.h" #include "../../../gapi/UniformBufferStructures.h" +#include "BindlessTexture.h" //---------------------------- // Material Templates //---------------------------- @@ -78,6 +79,7 @@ class IM2Material : public IMaterial { class IM2MaterialVis : public IM2Material { public: size_t instanceIndex; + std::vector> m_bindlessText; }; class IM2WaterFallMaterial : public IMaterial { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 53d6bcf0c..4b80eb218 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -567,9 +567,7 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } -static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { - return {vec[0], vec[1], vec[2]}; -} + std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { @@ -824,133 +822,4 @@ std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int widt return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } -/* - * RenderViewForwardVLK - */ - -MapSceneRenderForwardVLK::RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, - const HGBufferVLK &uboBuffer, - const HGVertexBufferBindings &quadVAO, - bool createOutputFBO) : m_device(device), m_createOutputFBO(createOutputFBO) { - glowPass = std::make_unique(m_device, uboBuffer, quadVAO); - - createFrameBuffers(); -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::createFrameBuffers() { - { - auto const dataFormat = {ITextureFormat::itRGBA}; - - for (auto &colorFrameBuffer: m_colorFrameBuffers) { - colorFrameBuffer = std::make_shared( - *m_device, - dataFormat, - ITextureFormat::itDepth32, - m_device->getMaxSamplesCnt(), - true, - m_width, m_height - ); - } - } - if (m_createOutputFBO) { - auto const dataFormat = {ITextureFormat::itRGBA}; - bool invertZ = false; - - m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, - VK_SAMPLE_COUNT_1_BIT, - invertZ, false); - - for (auto &outputFrameBuffer: m_outputFrameBuffers) { - outputFrameBuffer = std::make_shared( - *m_device, - dataFormat, - ITextureFormat::itNone, - 1, - invertZ, - m_width, m_height - ); - } - } - -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::update(int width, int height, float glow) { - if (width != m_width || height != m_height) { - m_width = width; - m_height = height; - - this->createFrameBuffers(); - - { - std::vector> inputColorTextures; - for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); - } - - glowPass->updateDimensions(m_width, m_height, - inputColorTextures, - !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); - } - - this->executeOnChange(); - } - glowPass->assignFFXGlowUBOConsts(glow); -} - -RenderPassHelper MapSceneRenderForwardVLK::RenderViewForwardVLK::beginPass(CmdBufRecorder &frameBufCmd, - const std::shared_ptr &renderPass, - bool willExecuteSecondaryBuffs, - mathfu::vec4 &clearColor) { - return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, - renderPass, - m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], - {0,0}, - {m_width, m_height}, - vec4ToArr3(clearColor), - true); -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::doOutputPass(CmdBufRecorder &frameBufCmd) { - auto frameBuff = m_outputFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; - - glowPass->doFinalPass(frameBufCmd, frameBuff); -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostGlow(CmdBufRecorder &frameBufCmd) { - glowPass->doPass(frameBufCmd); -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::doPostFinal(CmdBufRecorder &bufCmd) { - glowPass->doFinalDraw(bufCmd); -} - -void MapSceneRenderForwardVLK::RenderViewForwardVLK::iterateOverOutputTextures( - std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &, - const std::string &, ITextureFormat)> callback) { - //1. Color output - if (m_createOutputFBO) { - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> colorTextures; - for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) - colorTextures[i] = m_outputFrameBuffers[i]->getAttachment(0); - - callback(colorTextures, "Color Texture", ITextureFormat::itRGBA); - } - - //2. Depth buffer - { - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; - for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) - depthTextures[i] = m_device->createSampledTexture(m_colorFrameBuffers[i]->getDepthTexture(), false, false); - - callback(depthTextures, "Depth buffer", ITextureFormat::itDepth32); - } - -} - -void -MapSceneRenderForwardVLK::RenderViewForwardVLK::readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata) { - if (m_createOutputFBO) { - m_outputFrameBuffers[frameNumber % IDevice::MAX_FRAMES_IN_FLIGHT]->readRGBAPixels(x,y,width,height,outputdata); - } -} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 714f698d5..c2ab5cf5e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -11,6 +11,7 @@ #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" +#include "view/RenderViewForwardVLK.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { public: @@ -144,40 +145,6 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptySkyVAO = nullptr; HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; -private: - class RenderViewForwardVLK : public IRenderView { - public: - RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); - ~RenderViewForwardVLK() override = default; - - void update(int width, int height, float glow); - - RenderPassHelper beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, - bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); - - void doOutputPass(CmdBufRecorder &frameBufCmd); - - void doPostGlow(CmdBufRecorder &frameBufCmd); - void doPostFinal(CmdBufRecorder &bufCmd); - - void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; - void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata); - private: - uint32_t m_width = 640; - uint32_t m_height = 480; - - HGDeviceVLK m_device; - bool m_createOutputFBO; - - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; - std::unique_ptr glowPass; - - std::shared_ptr m_renderPass; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; - - void createFrameBuffers(); - std::vector> onUpdates; - }; std::shared_ptr defaultView; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index cdd07b6ad..bf997b4ac 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -14,6 +14,7 @@ #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../../frame/FrameProfile.h" +#include "view/RenderViewForwardVLK.h" #include static const ShaderConfig forwardShaderConfig = { @@ -65,35 +66,33 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic 0, 1, 2, 2, 1, 3 }; -// m_vboQuad = m_device->createVertexBuffer(vertexBuffer.size() * sizeof(mathfu::vec2_packed)); -// m_iboQuad = m_device->createIndexBuffer(indexBuffer.size() * sizeof(uint16_t)); -// m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); -// m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); -// -// m_drawQuadVao = m_device->createVertexBufferBindings(); -// m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); -// m_drawQuadVao->setIndexBuffer(m_iboQuad); -// m_drawQuadVao->save(); + m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + m_drawQuadVao = m_device->createVertexBufferBindings(); + m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); + m_drawQuadVao->setIndexBuffer(m_iboQuad); + m_drawQuadVao->save(); } //Create m2 shaders -// { -// m2Buffers.placementMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(M2::PlacementMatrix)); -// m2Buffers.boneMatrix = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); -// m2Buffers.m2Colors = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); -// m2Buffers.textureWeights = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::vec4_packed)); -// m2Buffers.textureMatrices = m_device->createSSBOBuffer(1024*1024, sizeof(mathfu::mat4)); -// m2Buffers.modelVertexDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS)); -// m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer(1024*1024, sizeof(M2::modelWideBlockPS)); -// -// m2Buffers.m2InstanceData = m_device->createSSBOBuffer(1024*1024, sizeof(M2::M2InstanceRecordBindless)); -// m2Buffers.meshWideBlocks = m_device->createSSBOBuffer(1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); -// } + { + m2Buffers.placementMatrix = m_device->createSSBOBuffer("M2 Placement", 1024*1024, sizeof(M2::PlacementMatrix)); + m2Buffers.boneMatrix = m_device->createSSBOBuffer("M2 BoneMatrices",1024*1024, sizeof(mathfu::mat4)); + m2Buffers.m2Colors = m_device->createSSBOBuffer("M2 BoneMatrices", 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureWeights = m_device->createSSBOBuffer("M2 TextureWeight", 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureMatrices = m_device->createSSBOBuffer("M2 TextureMatrices", 1024*1024, sizeof(mathfu::mat4)); + m2Buffers.modelVertexDatas = m_device->createSSBOBuffer("M2 VertexData", 1024*1024, sizeof(M2::meshWideBlockVSPS)); + m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer("M2 FragmentData", 1024*1024, sizeof(M2::modelWideBlockPS)); + + m2Buffers.m2InstanceData = m_device->createSSBOBuffer("M2 InstanceData", 1024*1024, sizeof(M2::M2InstanceRecordBindless)); + m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); + } -// uboBuffer = m_device->createUniformBuffer(1024*1024); -// uboStaticBuffer = m_device->createUniformBuffer(1024*1024); -// -// uboM2BoneMatrixBuffer = m_device->createUniformBuffer(5000*64); + uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); + uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); m_emptyADTVAO = createADTVAO(nullptr, nullptr); m_emptyM2VAO = createM2VAO(nullptr, nullptr); @@ -114,8 +113,6 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); - createFrameBuffers(); - sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createDescriptorSet(0, [&](std::shared_ptr &ds) { @@ -362,6 +359,15 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr .toMaterial([&vertexFragmentData](IM2MaterialVis *instance) -> void { instance->m_vertexFragmentData = vertexFragmentData; }); + { + auto dsUpdate = m2TextureDS->beginUpdate(); + + for (int i = 0; i < 4; i++) { + auto bindlessText = m2TextureHolder->allocate(m2MaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, m2MaterialTemplate.textures[i], bindlessText->getIndex()); + } + } /* .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { @@ -606,7 +612,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int b inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { if (mesh == nullptr) return; - const auto &meshVlk = std::dynamic_pointer_cast(mesh); + const auto &meshVlk = (GMeshVLK*) mesh.get(); auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); //1. Bind VBOs @@ -616,16 +622,12 @@ inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const H cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); //3. Bind pipeline - auto material = meshVlk->material(); + const auto &material = meshVlk->material(); cmdBuf.bindPipeline(material->getPipeline()); //4. Bind Descriptor sets auto const &descSets = material->getDescriptorSets(); - for (int i = 0; i < descSets.size(); i++) { - if (descSets[i] != nullptr) { - cmdBuf.bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, i, descSets[i]); - } - } + cmdBuf.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); //5. Set view port cmdBuf.setViewPort(viewportType); @@ -647,36 +649,17 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { + TracyMessageStr(("Update stage frame = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); ZoneScoped; - auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); - if (frameInputParams->viewPortDimensions.maxs[0] != m_width || - frameInputParams->viewPortDimensions.maxs[1] != m_height) { - m_width = frameInputParams->viewPortDimensions.maxs[0]; - m_height = frameInputParams->viewPortDimensions.maxs[1]; - - createFrameBuffers(); - - { - std::vector> inputColorTextures; - for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); - } - - glowPass->updateDimensions(m_width, m_height, - inputColorTextures, - m_device->getSwapChainRenderPass()); - } - - } - //Create meshes auto opaqueMeshes = std::make_shared>(); auto transparentMeshes = std::make_shared>(); + auto liquidMeshes = std::make_shared>(); auto skyOpaqueMeshes = std::make_shared>(); auto skyTransparentMeshes = std::make_shared>(); @@ -684,25 +667,27 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - m_lastCreatedPlan = framePlan; - //The portal meshes are created here. Need to call doPostLoad before CollectMeshes - mapScene->doPostLoad(l_this, framePlan); +// mapScene->doPostLoad(l_this, framePlan); // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { collectMeshes(framePlan, opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes); + liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); // } // ); mapScene->update(framePlan); - mapScene->updateBuffers(framePlan); - glowPass->assignFFXGlowUBOConsts(framePlan->frameDependentData->currentGlow); + mapScene->updateBuffers(l_this, framePlan); + + std::vector renderingMatricess; + for (auto &rt : frameInputParams->frameParameters->renderTargets) { + renderingMatricess.push_back(rt.cameraMatricesForRendering); + } updateSceneWideChunk(sceneWideChunk, - framePlan->renderingMatrices, + renderingMatricess, framePlan->frameDependentData, true, mapScene->getCurrentSceneTime()); @@ -716,19 +701,47 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s bool renderSky = framePlan->renderSky; auto skyMesh = framePlan->skyMesh; auto skyMesh0x4 = framePlan->skyMesh0x4; - return createRenderFuncVLK([opaqueMeshes, transparentMeshes, - skyOpaqueMeshes, skyTransparentMeshes, - renderSky, - skyMesh, - skyMesh0x4, - mapScene, framePlan, - l_this, frameInputParams](CmdBufRecorder &uploadCmd, CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { - + return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes, frameInputParams](CmdBufRecorder &uploadCmd) -> void { + { + ZoneScopedN("Post Load"); + //Do postLoad here. So creation of stuff is done from main thread + + mapScene->doPostLoad(l_this, framePlan); + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + if (!updatingTarget) updatingTarget = l_this->defaultView; + + updatingTarget->update( + renderTarget.viewPortDimensions.maxs[0], + renderTarget.viewPortDimensions.maxs[1], + framePlan->frameDependentData->currentGlow + ); + } + } + { + ZoneScopedN("Collect Portal Meshes"); + //And add portal meshes + for (auto const &view: framePlan->viewsHolder.getInteriorViews()) { + view->collectPortalMeshes(*transparentMeshes); + } + { + auto const &exteriorView = framePlan->viewsHolder.getExterior(); + if (exteriorView != nullptr) { + exteriorView->collectPortalMeshes(*transparentMeshes); + } + } + } + { + ZoneScopedN("Set Last Created Plan"); + //Needs to be executed only after lock + l_this->m_lastCreatedPlan = framePlan; + } // --------------------- // Upload stuff // --------------------- { ZoneScopedN("submit buffers"); + VkZone(uploadCmd, "submit buffers") uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -748,36 +761,57 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); } + }, [opaqueMeshes, transparentMeshes, liquidMeshes, + skyOpaqueMeshes, skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + mapScene, framePlan, + l_this, frameInputParams](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + + TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); // ---------------------- // Draw meshes // ---------------------- - l_this->sceneWideChunk->setCurrentVersion(0); { - auto passHelper = frameBufCmd.beginRenderPass(false, - l_this->m_renderPass, - l_this->m_colorFrameBuffers[l_this->m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], - frameInputParams->viewPortDimensions.mins, - frameInputParams->viewPortDimensions.maxs, - vec4ToArr3(frameInputParams->frameParameters->clearColor), - true - ); - - { - ZoneScopedN("submit opaque"); - for (auto const &mesh: *opaqueMeshes) { - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); - } - } - if (true) { - if (renderSky && skyMesh) - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); - - for (auto const &mesh: *skyOpaqueMeshes) { - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); - } - for (int i = 0; i < skyTransparentMeshes->size(); i++) { - auto const &mesh = skyTransparentMeshes->at(i); + uint8_t wideChunkVersion = 0; + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + l_this->sceneWideChunk->setCurrentVersion(wideChunkVersion++); + + auto currentView = renderTarget.target == nullptr ? + l_this->defaultView : + std::dynamic_pointer_cast(renderTarget.target); + { + auto passHelper = currentView->beginPass(frameBufCmd, l_this->m_renderPass, + false, + frameInputParams->frameParameters->clearColor); + + { + ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") + auto const &pOpaqueMeshes = *opaqueMeshes; + auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); + for (int i = 0; i < pOpaqueMeshesSize; i++) { + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], + CmdBufRecorder::ViewportType::vp_usual); + } + } + { + //Sky opaque + if (renderSky && skyMesh) + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh, + CmdBufRecorder::ViewportType::vp_skyBox); + + for (auto const &mesh: *skyOpaqueMeshes) { + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + } + { + //Sky transparent + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); // std::string debugMess = // "Drawing mesh " @@ -788,15 +822,25 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_skyBox); - } - if (renderSky && skyMesh0x4) - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh0x4, CmdBufRecorder::ViewportType::vp_skyBox); - } - { - ZoneScopedN("submit transparent"); - for (int i = 0; i < transparentMeshes->size(); i++) { - auto const &mesh = transparentMeshes->at(i); + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + if (renderSky && skyMesh0x4) + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh0x4, + CmdBufRecorder::ViewportType::vp_skyBox); + } + { + //Render liquids + for (auto const &mesh: *liquidMeshes) { + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } + } + { + VkZone(frameBufCmd, "render transparent") + ZoneScopedN("submit transparent"); + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); // // std::string debugMess = // "Drawing mesh " @@ -807,14 +851,21 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, CmdBufRecorder::ViewportType::vp_usual); + MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } + } + } + { + currentView->doPostGlow(frameBufCmd); + if (currentView == l_this->defaultView) { + currentView->doPostFinal(swapChainCmd); + } else { + currentView->doOutputPass(frameBufCmd); + } } } } - - l_this->glowPass->doPass(frameBufCmd, swapChainCmd, - l_this->m_device->getSwapChainRenderPass(), - frameInputParams->viewPortDimensions); }); } @@ -823,11 +874,11 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getLastCreatedPlan() } HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material)); + return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } @@ -835,28 +886,16 @@ HGM2Mesh MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } -void MapSceneRenderVisBufferVLK::createFrameBuffers() { - { - auto const dataFormat = {ITextureFormat::itRGBA}; - - for (auto &colorFrameBuffer: m_colorFrameBuffers) { - colorFrameBuffer = std::make_shared( - *m_device, - dataFormat, - ITextureFormat::itDepth32, - m_device->getMaxSamplesCnt(), - m_width, m_height - ); - } - } +std::shared_ptr MapSceneRenderVisBufferVLK::createRenderView(int width, int height, bool createOutput) { + return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 04ab22641..abce40c1e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -12,6 +12,8 @@ #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" #include "../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" +#include "view/RenderViewForwardVLK.h" +#include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { public: @@ -97,6 +99,13 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + +//-------------------------------------- +// RenderView +//-------------------------------------- + + std::shared_ptr createRenderView(int width, int height, bool createOutput) override; + private: std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); @@ -160,11 +169,12 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr sceneWideDS = nullptr; std::shared_ptr m2TextureDS = nullptr; + std::unique_ptr m2TextureHolder = nullptr; + std::shared_ptr m2BufferOneDS = nullptr; std::shared_ptr m2BufferTwoDS = nullptr; std::shared_ptr m_renderPass; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; std::shared_ptr m_lastCreatedPlan = nullptr; @@ -177,7 +187,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; - void createFrameBuffers(); + std::shared_ptr defaultView; }; class IM2ModelDataVisVLK : public IM2ModelData { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp new file mode 100644 index 000000000..d2022a080 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -0,0 +1,140 @@ +// +// Created by Deamon on 10/5/2023. +// + +#include "RenderViewForwardVLK.h" + +/* + * RenderViewForwardVLK + */ + +RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, + const HGBufferVLK &uboBuffer, + const HGVertexBufferBindings &quadVAO, + bool createOutputFBO) : m_device(device), m_createOutputFBO(createOutputFBO) { + glowPass = std::make_unique(m_device, uboBuffer, quadVAO); + + createFrameBuffers(); +} + +void RenderViewForwardVLK::createFrameBuffers() { + { + auto const dataFormat = {ITextureFormat::itRGBA}; + + for (auto &colorFrameBuffer: m_colorFrameBuffers) { + colorFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itDepth32, + m_device->getMaxSamplesCnt(), + true, + m_width, m_height + ); + } + } + if (m_createOutputFBO) { + auto const dataFormat = {ITextureFormat::itRGBA}; + bool invertZ = false; + + m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, + VK_SAMPLE_COUNT_1_BIT, + invertZ, false); + + for (auto &outputFrameBuffer: m_outputFrameBuffers) { + outputFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itNone, + 1, + invertZ, + m_width, m_height + ); + } + } + +} + +void RenderViewForwardVLK::update(int width, int height, float glow) { + if (width != m_width || height != m_height) { + m_width = width; + m_height = height; + + this->createFrameBuffers(); + + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); + } + + this->executeOnChange(); + } + glowPass->assignFFXGlowUBOConsts(glow); +} + +static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { + return {vec[0], vec[1], vec[2]}; +} + +RenderPassHelper RenderViewForwardVLK::beginPass(CmdBufRecorder &frameBufCmd, + const std::shared_ptr &renderPass, + bool willExecuteSecondaryBuffs, + mathfu::vec4 &clearColor) { + return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, + renderPass, + m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + {0,0}, + {m_width, m_height}, + vec4ToArr3(clearColor), + true); +} + +void RenderViewForwardVLK::doOutputPass(CmdBufRecorder &frameBufCmd) { + auto frameBuff = m_outputFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + + glowPass->doFinalPass(frameBufCmd, frameBuff); +} + +void RenderViewForwardVLK::doPostGlow(CmdBufRecorder &frameBufCmd) { + glowPass->doPass(frameBufCmd); +} + +void RenderViewForwardVLK::doPostFinal(CmdBufRecorder &bufCmd) { + glowPass->doFinalDraw(bufCmd); +} + +void RenderViewForwardVLK::iterateOverOutputTextures( + std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &, + const std::string &, ITextureFormat)> callback) { + + //1. Color output + if (m_createOutputFBO) { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> colorTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + colorTextures[i] = m_outputFrameBuffers[i]->getAttachment(0); + + callback(colorTextures, "Color Texture", ITextureFormat::itRGBA); + } + + //2. Depth buffer + { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + depthTextures[i] = m_device->createSampledTexture(m_colorFrameBuffers[i]->getDepthTexture(), false, false); + + callback(depthTextures, "Depth buffer", ITextureFormat::itDepth32); + } + +} + +void +RenderViewForwardVLK::readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata) { + if (m_createOutputFBO) { + m_outputFrameBuffers[frameNumber % IDevice::MAX_FRAMES_IN_FLIGHT]->readRGBAPixels(x,y,width,height,outputdata); + } +} \ No newline at end of file diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h new file mode 100644 index 000000000..5c0e66054 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h @@ -0,0 +1,46 @@ +// +// Created by Deamon on 10/5/2023. +// + +#ifndef AWEBWOWVIEWERCPP_RENDERVIEWFORWARDVLK_H +#define AWEBWOWVIEWERCPP_RENDERVIEWFORWARDVLK_H + +#include "../../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../MapSceneParams.h" +#include "../passes/FFXGlowPassVLK.h" + +class RenderViewForwardVLK : public IRenderView { +public: + RenderViewForwardVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); + ~RenderViewForwardVLK() override = default; + + void update(int width, int height, float glow); + + RenderPassHelper beginPass(CmdBufRecorder &frameBufCmd, const std::shared_ptr &renderPass, + bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + + void doOutputPass(CmdBufRecorder &frameBufCmd); + + void doPostGlow(CmdBufRecorder &frameBufCmd); + void doPostFinal(CmdBufRecorder &bufCmd); + + void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; + void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata); +private: + uint32_t m_width = 640; + uint32_t m_height = 480; + + HGDeviceVLK m_device; + bool m_createOutputFBO; + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + std::unique_ptr glowPass; + + std::shared_ptr m_renderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; + + void createFrameBuffers(); + std::vector> onUpdates; +}; + +#endif //AWEBWOWVIEWERCPP_RENDERVIEWFORWARDVLK_H From a76942b7f2d23d8025fc051d21a22e1a7de7b4f5 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 8 Oct 2023 23:52:46 +0300 Subject: [PATCH 128/212] - bindless: validation layers are silient, which is good --- wowViewerLib/CMakeLists.txt | 2 +- .../common/commonM2IndirectDescriptorSet.glsl | 22 ++- .../shaders/glsl/visBuffer/m2Shader.frag | 31 +--- .../shaders/glsl/visBuffer/m2Shader.vert | 32 ++-- .../src/engine/shader/ShaderDefinitions.h | 31 +++- .../src/gapi/UniformBufferStructures.h | 15 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 2 +- .../descriptorSets/GDescriptorSetLayout.cpp | 169 ++++++++++++------ .../descriptorSets/GDescriptorSetLayout.h | 10 ++ .../bindless/BindlessTextureHolder.h | 1 + .../mapScene/MapSceneRendererFactory.cpp | 5 +- .../mapScene/materials/IMaterialStructs.h | 3 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 59 +++--- .../vulkan/MapSceneRenderVisBufferVLK.h | 10 +- .../vulkan/view/RenderViewForwardVLK.cpp | 10 ++ 16 files changed, 247 insertions(+), 157 deletions(-) diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index dfa3db16a..cce982689 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -100,7 +100,7 @@ if (EMSCRIPTEN) else() set(My_Vectorize_Compile_Options "${My_Vectorize_Compile_Options};-msse3;-mavx2;-ftree-vectorize") - if (NOT MSVC) + if (NOT MSVC AND NOT MSVC_VERSION) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-multichar") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-multichar") diff --git a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl index 0204a488f..4ff354870 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl @@ -42,4 +42,24 @@ struct M2InstanceRecordBindless { }; layout(std430, set=1, binding=7) buffer m2Instances { M2InstanceRecordBindless instances[]; -}; \ No newline at end of file +}; + +struct meshWideBlockVSPS { + ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; + ivec4 PixelShader_UnFogged_blendMode; + ivec4 textureWeightIndexes; + ivec4 colorIndex_applyWeight; +}; + +layout(std430, set=1, binding=8) buffer meshWide { + meshWideBlockVSPS meshWides[]; +}; + +struct meshWideBlockVSPSBindless { + ivec4 instanceIndex_meshIndex; + ivec4 textureIndicies; +}; + +layout(std430, set=1, binding=9) buffer meshWideBindless { + meshWideBlockVSPSBindless meshWideBindleses[]; +}; diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index 8834aa30c..7aa722c05 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -24,21 +24,7 @@ layout(location=0) out vec4 outputColor; //Whole model #include "../common/commonM2IndirectDescriptorSet.glsl" -//Individual meshes -struct meshWideBlockVSPSBindless { - ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; - ivec4 PixelShader_UnFogged_blendMode; - ivec4 textureWeightIndexes; - ivec4 colorIndex_applyWeight_instanceIndex; - ivec4 textureIndicies; -}; - -layout(std430, set=2, binding=8) buffer meshWideBlockVSPS { - meshWideBlockVSPSBindless meshWides[]; -}; - - -layout (set = 3, binding = 0) uniform sampler2D s_Textures[]; +layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; void main() { /* Animation support */ @@ -48,8 +34,9 @@ void main() { vec4 finalColor = vec4(0); - meshWideBlockVSPSBindless meshWide = meshWides[meshIndex]; - int instanceIndex = meshWide.colorIndex_applyWeight_instanceIndex.y; + meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[meshIndex]; + meshWideBlockVSPS meshWide = meshWides[meshWideBindless.instanceIndex_meshIndex.y]; + int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; vec3 uTexSampleAlpha = vec3( meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], @@ -58,11 +45,11 @@ void main() { ); vec4 vMeshColorAlpha = vec4( - meshWide.colorIndex_applyWeight_instanceIndex.x < 0 ? + meshWide.colorIndex_applyWeight.x < 0 ? vec4(1.0,1.0,1.0,1.0) : - colors[meshWide.colorIndex_applyWeight_instanceIndex.x] + colors[meshWide.colorIndex_applyWeight.x] ); - if (meshWide.colorIndex_applyWeight_instanceIndex.y > 0) + if (meshWide.colorIndex_applyWeight.y > 0) vMeshColorAlpha.a *= meshWide.textureWeightIndexes.x < 0 ? 1.0 : @@ -140,8 +127,8 @@ void main() { calcM2FragMaterial(uPixelShader, - s_Textures[meshWide.textureIndicies.x], s_Textures[meshWide.textureIndicies.y], - s_Textures[meshWide.textureIndicies.z], s_Textures[meshWide.textureIndicies.w], + s_Textures[meshWideBindless.textureIndicies.x], s_Textures[meshWideBindless.textureIndicies.y], + s_Textures[meshWideBindless.textureIndicies.z], s_Textures[meshWideBindless.textureIndicies.w], texCoord, texCoord2, texCoord3, vMeshColorAlpha.rgb, vMeshColorAlpha.a, uTexSampleAlpha.rgb, diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert index 54f85f5b6..c57538a8c 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -20,19 +20,8 @@ layout(location=3) in vec4 boneWeights; layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; -//Whole scene - - //Whole model -#include "../common/commonM2DescriptorSet.glsl" - -//Individual meshes -layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { - ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; - ivec4 PixelShader_UnFogged_blendMode; - ivec4 textureWeightIndexes; - ivec4 colorIndex_applyWeight; -}; +#include "../common/commonM2IndirectDescriptorSet.glsl" //Shader output layout(location=0) out vec2 vTexCoord; @@ -49,18 +38,23 @@ void main() { vec4 aPositionVec4 = vec4(aPosition, 1); mat4 boneTransformMat = mat4(0.0); + meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[gl_InstanceIndex]; + meshWideBlockVSPS meshWide = meshWides[meshWideBindless.instanceIndex_meshIndex.y]; + int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; + if (dot(boneWeights, boneWeights) > 0) { - // - boneTransformMat += (boneWeights.x) * uBoneMatrixes[bones.x]; - boneTransformMat += (boneWeights.y) * uBoneMatrixes[bones.y]; - boneTransformMat += (boneWeights.z) * uBoneMatrixes[bones.z]; - boneTransformMat += (boneWeights.w) * uBoneMatrixes[bones.w]; + int boneIndex = instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.y; + + boneTransformMat += (boneWeights.x) * uBoneMatrixes[boneIndex + bones.x]; + boneTransformMat += (boneWeights.y) * uBoneMatrixes[boneIndex + bones.y]; + boneTransformMat += (boneWeights.z) * uBoneMatrixes[boneIndex + bones.z]; + boneTransformMat += (boneWeights.w) * uBoneMatrixes[boneIndex + bones.w]; } else { boneTransformMat = mat4(1.0); } - mat4 placementMat; - placementMat = uPlacementMat; + int placementIndex = instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + mat4 placementMat = uPlacementMats[placementIndex]; mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; vec4 vertexPosInView = viewModelMat * aPositionVec4; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 1ae8d983a..771ffc00f 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -302,14 +302,12 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,480}, }, { { {0,0,1}, - {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -319,6 +317,10 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, }, { }, @@ -992,7 +994,8 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,8,0}, + {1,9,0}, + {1,8,0}, {1,5,0}, {1,4,0}, {1,2,0}, @@ -1001,11 +1004,10 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -1013,6 +1015,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } @@ -1993,6 +1996,14 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 074853426..aa21a506c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -201,7 +201,7 @@ GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptrgetRequiredSSBOSize(); #if (!defined(NDEBUG)) - if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + if (slb.find(bindIndex) == slb.end() || slb.at(bindIndex).descriptorType != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { std::cerr << "descriptor mismatch for SSBO" << std::endl; throw std::runtime_error("descriptor mismatch for UBO"); } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index c0865b946..fe98d9cd4 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -31,57 +31,8 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } }(metaData.stage); - for (int i = 0; i < p_metaData->uboBindings.size(); i++) { - auto &uboBinding = p_metaData->uboBindings[i]; - - if (uboBinding.set != setIndex) continue; - - auto uniformType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uint32_t stageOverride = 0; - { - if (typeOverrides.find(uboBinding.set) != typeOverrides.end()) { - auto &setTypeOverrides = typeOverrides.at(uboBinding.set); - if (setTypeOverrides.find(uboBinding.binding) != setTypeOverrides.end()) { - auto const &overrideStruct = setTypeOverrides.at(uboBinding.binding); - assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); - uniformType = overrideStruct.type; - if (overrideStruct.stageMask != 0) { - stageOverride = overrideStruct.stageMask; - } - } - } - } - - auto it = shaderLayoutBindings.find(uboBinding.binding); - if (it != std::end( shaderLayoutBindings )) { - it->second.stageFlags |= vkStageFlag; - if (it->second.descriptorType != uniformType) { - std::cerr << "Type mismatch for ubo in GDescriptorSetLayout" << std::endl; - throw std::runtime_error("types mismatch"); - } - } else { - VkDescriptorSetLayoutBinding uboLayoutBinding = {}; - uboLayoutBinding.binding = uboBinding.binding; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = uniformType; - uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = stageOverride == 0 ? vkStageFlag : stageOverride; - - shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); - if (uboBinding.size > 0) { - if (m_requiredUBOSize.find(uboBinding.binding) == m_requiredUBOSize.end()) { - m_requiredUBOSize.insert({uboBinding.binding, uboBinding.size}); - } else { - if (m_requiredUBOSize.at(uboBinding.binding) != uboBinding.size) { - std::cerr << "Size mismatch for ubo for binding " << uboBinding.binding << std::endl; - throw std::runtime_error("UBO size mismatch"); - } - } - } - - m_requiredBindPoints[uboBinding.binding] = true; - } - } + fillUbo(setIndex, typeOverrides, shaderLayoutBindings, p_metaData, vkStageFlag); + fillSSBO(setIndex, typeOverrides, shaderLayoutBindings, p_metaData, vkStageFlag); for (int i = 0; i < p_metaData->imageBindings.size(); i++) { auto &imageBinding = p_metaData->imageBindings[i]; @@ -132,10 +83,12 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr return a.binding < b.binding; }); - m_totalUbos = 0; m_totalDynUbos = 0; m_totalImages = 0; + m_totalUbos = 0; m_totalDynUbos = 0; m_totalImages = 0; m_totalSSBOs = 0; for (auto& layout : layouts) { if (layout.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { m_totalUbos++; + } if (layout.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { + m_totalSSBOs++; } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { m_totalDynUbos++; } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { @@ -184,6 +137,118 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } } +void GDescriptorSetLayout::fillUbo(int setIndex, const DescTypeOverride &typeOverrides, + std::unordered_map &shaderLayoutBindings, + const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag) { + for (int i = 0; i < p_metaData->uboBindings.size(); i++) { + auto &uboBinding = p_metaData->uboBindings[i]; + + if (uboBinding.set != setIndex) continue; + + auto uniformType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uint32_t stageOverride = 0; + { + if (typeOverrides.find(uboBinding.set) != typeOverrides.end()) { + auto &setTypeOverrides = typeOverrides.at(uboBinding.set); + if (setTypeOverrides.find(uboBinding.binding) != setTypeOverrides.end()) { + auto const &overrideStruct = setTypeOverrides.at(uboBinding.binding); + assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); + uniformType = overrideStruct.type; + if (overrideStruct.stageMask != 0) { + stageOverride = overrideStruct.stageMask; + } + } + } + } + + auto it = shaderLayoutBindings.find(uboBinding.binding); + if (it != std::end( shaderLayoutBindings )) { + it->second.stageFlags |= vkStageFlag; + if (it->second.descriptorType != uniformType) { + std::cerr << "Type mismatch for ubo in GDescriptorSetLayout" << std::endl; + throw std::runtime_error("types mismatch"); + } + } else { + VkDescriptorSetLayoutBinding uboLayoutBinding = {}; + uboLayoutBinding.binding = uboBinding.binding; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.descriptorType = uniformType; + uboLayoutBinding.pImmutableSamplers = nullptr; + uboLayoutBinding.stageFlags = stageOverride == 0 ? vkStageFlag : stageOverride; + + shaderLayoutBindings.insert({uboBinding.binding, uboLayoutBinding}); + if (uboBinding.size > 0) { + if (m_requiredUBOSize.find(uboBinding.binding) == m_requiredUBOSize.end()) { + m_requiredUBOSize.insert({uboBinding.binding, uboBinding.size}); + } else { + if (m_requiredUBOSize.at(uboBinding.binding) != uboBinding.size) { + std::cerr << "Size mismatch for ubo for binding " << uboBinding.binding << std::endl; + throw std::runtime_error("UBO size mismatch"); + } + } + } + + m_requiredBindPoints[uboBinding.binding] = true; + } + } +} + +void GDescriptorSetLayout::fillSSBO(int setIndex, const DescTypeOverride &typeOverrides, + std::unordered_map &shaderLayoutBindings, + const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag) { + for (int i = 0; i < p_metaData->ssboBindingData.size(); i++) { + auto &ssboBinding = p_metaData->ssboBindingData[i]; + + if (ssboBinding.set != setIndex) continue; + + auto uniformType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + uint32_t stageOverride = 0; + { + if (typeOverrides.find(ssboBinding.set) != typeOverrides.end()) { + auto &setTypeOverrides = typeOverrides.at(ssboBinding.set); + if (setTypeOverrides.find(ssboBinding.binding) != setTypeOverrides.end()) { + auto const &overrideStruct = setTypeOverrides.at(ssboBinding.binding); + assert(overrideStruct.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC); + uniformType = overrideStruct.type; + if (overrideStruct.stageMask != 0) { + stageOverride = overrideStruct.stageMask; + } + } + } + } + + auto it = shaderLayoutBindings.find(ssboBinding.binding); + if (it != std::end( shaderLayoutBindings )) { + it->second.stageFlags |= vkStageFlag; + if (it->second.descriptorType != uniformType) { + std::cerr << "Type mismatch for ssbo in GDescriptorSetLayout" << std::endl; + throw std::runtime_error("types mismatch"); + } + } else { + VkDescriptorSetLayoutBinding ssboLayoutBinding = {}; + ssboLayoutBinding.binding = ssboBinding.binding; + ssboLayoutBinding.descriptorCount = 1; + ssboLayoutBinding.descriptorType = uniformType; + ssboLayoutBinding.pImmutableSamplers = nullptr; + ssboLayoutBinding.stageFlags = stageOverride == 0 ? vkStageFlag : stageOverride; + + shaderLayoutBindings.insert({ssboLayoutBinding.binding, ssboLayoutBinding}); + if (ssboBinding.size > 0) { + if (m_requiredSSBOSize.find(ssboBinding.binding) == m_requiredSSBOSize.end()) { + m_requiredSSBOSize.insert({ssboBinding.binding, ssboBinding.size}); + } else { + if (m_requiredSSBOSize.at(ssboBinding.binding) != ssboBinding.size) { + std::cerr << "Size mismatch for SSBO for binding " << ssboBinding.binding << std::endl; + throw std::runtime_error("SSBO size mismatch"); + } + } + } + + m_requiredBindPoints[ssboBinding.binding] = true; + } + } +} + GDescriptorSetLayout::~GDescriptorSetLayout() { vkDestroyDescriptorSetLayout(m_device->getVkDevice(), m_descriptorSetLayout, nullptr); } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 01976ce77..9aae75c15 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -36,6 +36,7 @@ class GDescriptorSetLayout { int getTotalUbos() const { return m_totalUbos; }; int getTotalDynUbos() const { return m_totalDynUbos; }; + int getTotalSsbos() const { return m_totalSSBOs; }; int getTotalImages() const { return m_totalImages; }; bool getIsBindless() const { return m_isBindless; }; std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; @@ -51,10 +52,19 @@ class GDescriptorSetLayout { int m_totalImages = 0; int m_totalUbos = 0; int m_totalDynUbos = 0; + int m_totalSSBOs = 0; bool m_isBindless = false; std::shared_ptr m_device; + + void fillUbo(int setIndex, const DescTypeOverride &typeOverrides, + std::unordered_map &shaderLayoutBindings, + const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag); + + void fillSSBO(int setIndex, const DescTypeOverride &typeOverrides, + std::unordered_map &shaderLayoutBindings, + const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag); }; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h index 643837a1f..f3acaacf4 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h @@ -11,6 +11,7 @@ #include "../../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" #include "../../../../include/custom_container_key.h" #include "../GDescriptorSet.h" +#include "../../../../renderer/mapScene/materials/BindlessTexture.h" class BindlessTextureHolder : public std::enable_shared_from_this { public: diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index 6865586d4..972054e80 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -4,13 +4,14 @@ #include "MapSceneRendererFactory.h" #include "vulkan/MapSceneRenderForwardVLK.h" +#include "vulkan/MapSceneRenderVisBufferVLK.h" std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - return std::make_shared(std::dynamic_pointer_cast(device), config); + return std::make_shared(std::dynamic_pointer_cast(device), config); default: - return nullptr; + return std::make_shared(std::dynamic_pointer_cast(device), config); } return nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index f5864b507..2d9d7d0bb 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -78,8 +78,9 @@ class IM2Material : public IMaterial { class IM2MaterialVis : public IM2Material { public: - size_t instanceIndex; + std::shared_ptr> m_vertexFragmentDataBindless = nullptr; std::vector> m_bindlessText; + int instanceIndex = 0; }; class IM2WaterFallMaterial : public IMaterial { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index bf997b4ac..31cce0026 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -32,10 +32,7 @@ static const ShaderConfig m2VisShaderConfig = { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }}, - {1, { - {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} - }}, - {3, { + {2, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; @@ -84,11 +81,10 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m2Buffers.m2Colors = m_device->createSSBOBuffer("M2 BoneMatrices", 1024*1024, sizeof(mathfu::vec4_packed)); m2Buffers.textureWeights = m_device->createSSBOBuffer("M2 TextureWeight", 1024*1024, sizeof(mathfu::vec4_packed)); m2Buffers.textureMatrices = m_device->createSSBOBuffer("M2 TextureMatrices", 1024*1024, sizeof(mathfu::mat4)); - m2Buffers.modelVertexDatas = m_device->createSSBOBuffer("M2 VertexData", 1024*1024, sizeof(M2::meshWideBlockVSPS)); m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer("M2 FragmentData", 1024*1024, sizeof(M2::modelWideBlockPS)); - m2Buffers.m2InstanceData = m_device->createSSBOBuffer("M2 InstanceData", 1024*1024, sizeof(M2::M2InstanceRecordBindless)); - m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); + m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS)); + m2Buffers.meshWideBlocksBindless = m_device->createSSBOBuffer("M2 MeshWide Bindless", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); } uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); @@ -113,6 +109,8 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createDescriptorSet(0, [&](std::shared_ptr &ds) { @@ -132,19 +130,15 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic .ssbo(5, m2Buffers.textureWeights) .ssbo(6, m2Buffers.textureMatrices) .ssbo(7, m2Buffers.m2InstanceData) - .ssbo(8, m2Buffers.meshWideBlocks); + .ssbo(8, m2Buffers.meshWideBlocks) + .ssbo(9, m2Buffers.meshWideBlocksBindless); m2BufferOneDS = ds; }) .createDescriptorSet(2, [&](std::shared_ptr &ds) { - ds->beginUpdate() - .ssbo(7, m2Buffers.modelVertexDatas); - - m2BufferTwoDS = ds; - }) - .createDescriptorSet(3, [&](std::shared_ptr &ds) { m2TextureDS = ds; }); + m2TextureHolder = std::make_unique(m2TexturesBindlessCount); } // ------------------ @@ -165,8 +159,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) - .bindDescriptorSet(2, m2BufferTwoDS) - .bindDescriptorSet(3, m2TextureDS) + .bindDescriptorSet(2, m2TextureDS) .toMaterial(); m_m2StaticMaterials[pipelineTemplate] = staticMaterial; @@ -350,13 +343,16 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) { - auto &l_sceneWideChunk = sceneWideChunk; - auto vertexFragmentData = std::make_shared>(m2Buffers.modelVertexDatas); + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + + auto vertexFragmentDataBindless = std::make_shared>(m2Buffers.meshWideBlocksBindless); + auto vertexFragmentData = std::make_shared>(m2Buffers.meshWideBlocks); auto staticMaterial = getM2StaticMaterial(pipelineTemplate); auto material = MaterialBuilderVLK::fromMaterial(m_device, staticMaterial) - .toMaterial([&vertexFragmentData](IM2MaterialVis *instance) -> void { + .toMaterial([&vertexFragmentDataBindless, &vertexFragmentData](IM2MaterialVis *instance) -> void { + instance->m_vertexFragmentDataBindless = vertexFragmentDataBindless; instance->m_vertexFragmentData = vertexFragmentData; }); { @@ -369,15 +365,19 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr } } - /* - .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { - ds->beginUpdate() - .texture(6, m2MaterialTemplate.textures[0]) - .texture(7, m2MaterialTemplate.textures[1]) - .texture(8, m2MaterialTemplate.textures[2]) - .texture(9, m2MaterialTemplate.textures[3]); - }) - */ + { + auto &modelFragmentDataVis = vertexFragmentDataBindless->getObject(); + + modelFragmentDataVis.instanceIndex = + BufferChunkHelperVLK::castToChunk(m2ModelDataVisVLK->m_instanceBindless)->getSubBuffer()->getIndex(); + modelFragmentDataVis.meshIndex = + vertexFragmentData->getSubBuffer()->getIndex(); + for (int i = 0; i < 4; i++) { + modelFragmentDataVis.textureIndicies[i] = material->m_bindlessText[i]->getIndex(); + } + + vertexFragmentDataBindless->save(); + } material->blendMode = pipelineTemplate.blendMode; material->depthWrite = pipelineTemplate.depthWrite; @@ -387,7 +387,6 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr material->batchIndex = m2MaterialTemplate.batchIndex; material->vertexShader = m2MaterialTemplate.vertexShader; material->pixelShader = m2MaterialTemplate.pixelShader; - material->instanceIndex = vertexFragmentData->getIndex(); return material; @@ -745,8 +744,6 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); - uploadCmd.submitBufferUploads(l_this->uboM2BoneMatrixBuffer); - uploadCmd.submitBufferUploads(l_this->vboM2Buffer); uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index abce40c1e..2a9f6c8ee 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -2,8 +2,8 @@ // Created by Deamon on 12/1/2022. // -#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H -#define AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H #include "../MapSceneRenderer.h" @@ -150,15 +150,14 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK m2Colors; HGBufferVLK textureWeights; HGBufferVLK textureMatrices; - HGBufferVLK modelVertexDatas; HGBufferVLK modelFragmentDatas; HGBufferVLK m2InstanceData; HGBufferVLK meshWideBlocks; + HGBufferVLK meshWideBlocksBindless; } m2Buffers; HGBufferVLK uboBuffer; - HGBufferVLK uboM2BoneMatrixBuffer; HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; @@ -172,7 +171,6 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::unique_ptr m2TextureHolder = nullptr; std::shared_ptr m2BufferOneDS = nullptr; - std::shared_ptr m2BufferTwoDS = nullptr; std::shared_ptr m_renderPass; @@ -198,4 +196,4 @@ class IM2ModelDataVisVLK : public IM2ModelData { -#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERFORWARDVLK_H +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp index d2022a080..498940e06 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -15,6 +15,16 @@ RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, glowPass = std::make_unique(m_device, uboBuffer, quadVAO); createFrameBuffers(); + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); + } } void RenderViewForwardVLK::createFrameBuffers() { From e5048e8c82dae00950473d8462dcf11fd12d469f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 9 Oct 2023 14:45:28 +0300 Subject: [PATCH 129/212] - first iteration of indirect kinda works --- .../shaders/glsl/visBuffer/m2Shader.frag | 13 +- .../shaders/glsl/visBuffer/m2Shader.vert | 19 +- .../src/engine/shader/ShaderDefinitions.h | 173 ++++++++++++++++-- .../src/gapi/UniformBufferStructures.h | 2 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 41 +++-- .../vulkan/descriptorSets/GDescriptorSet.h | 20 +- .../descriptorSets/GDescriptorSetLayout.cpp | 7 + .../descriptorSets/GDescriptorSetLayout.h | 4 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 8 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 20 +- 11 files changed, 243 insertions(+), 66 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index 7aa722c05..97dcf2286 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -12,10 +12,9 @@ precision highp int; layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec2 vTexCoord3; -layout(location=3) in vec3 vNormal; -layout(location=4) in vec4 vPosition_EdgeFade; -layout(location=5) in flat int meshIndex; +layout(location=2) in vec3 vNormal; +layout(location=3) in vec4 vPosition_EdgeFade; +layout(location=4) in flat int meshIndex; layout(location=0) out vec4 outputColor; @@ -30,7 +29,7 @@ void main() { /* Animation support */ vec2 texCoord = vTexCoord.xy; vec2 texCoord2 = vTexCoord2.xy; - vec2 texCoord3 = vTexCoord3.xy; + vec2 texCoord3 = vTexCoord2.xy; vec4 finalColor = vec4(0); @@ -127,8 +126,8 @@ void main() { calcM2FragMaterial(uPixelShader, - s_Textures[meshWideBindless.textureIndicies.x], s_Textures[meshWideBindless.textureIndicies.y], - s_Textures[meshWideBindless.textureIndicies.z], s_Textures[meshWideBindless.textureIndicies.w], + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.x)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.y)], + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.z)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.w)], texCoord, texCoord2, texCoord3, vMeshColorAlpha.rgb, vMeshColorAlpha.a, uTexSampleAlpha.rgb, diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert index c57538a8c..51419af7a 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require precision highp float; @@ -26,10 +27,9 @@ layout(location=5) in vec2 aTexCoord2; //Shader output layout(location=0) out vec2 vTexCoord; layout(location=1) out vec2 vTexCoord2; -layout(location=2) out vec2 vTexCoord3; -layout(location=3) out vec3 vNormal; -layout(location=4) out vec4 vPosition_EdgeFade; -layout(location=5) out flat int instanceIndex; +layout(location=2) out vec3 vNormal; +layout(location=3) out vec4 vPosition_EdgeFade; +layout(location=4) out flat int vInstanceIndex; void main() { @@ -39,11 +39,11 @@ void main() { mat4 boneTransformMat = mat4(0.0); meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[gl_InstanceIndex]; - meshWideBlockVSPS meshWide = meshWides[meshWideBindless.instanceIndex_meshIndex.y]; + meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; if (dot(boneWeights, boneWeights) > 0) { - int boneIndex = instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.y; + int boneIndex = instances[nonuniformEXT(instanceIndex)].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.y; boneTransformMat += (boneWeights.x) * uBoneMatrixes[boneIndex + bones.x]; boneTransformMat += (boneWeights.y) * uBoneMatrixes[boneIndex + bones.y]; @@ -53,8 +53,8 @@ void main() { boneTransformMat = mat4(1.0); } - int placementIndex = instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; - mat4 placementMat = uPlacementMats[placementIndex]; + int placementIndex = instances[nonuniformEXT(instanceIndex)].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + mat4 placementMat = uPlacementMats[nonuniformEXT(placementIndex)]; mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; vec4 vertexPosInView = viewModelMat * aPositionVec4; @@ -65,12 +65,11 @@ void main() { vTexCoord = aTexCoord; vTexCoord2 = aTexCoord2; - vTexCoord3 = aTexCoord2; gl_Position = scene.uPMatrix * vertexPosInView; vNormal = normal; vPosition_EdgeFade = vec4(vertexPosInView.xyz, 0.0); - instanceIndex = gl_InstanceIndex; + vInstanceIndex = gl_InstanceIndex; } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 771ffc00f..b8bb8176e 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -318,9 +318,14 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, + {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, }, { }, @@ -385,6 +390,9 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { @@ -657,10 +665,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -678,11 +687,17 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, + {1,6,6}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -717,10 +732,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -825,10 +841,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1002,6 +1019,7 @@ const std::unordered_map shaderMetaInfo = { {1,1,0}, {1,7,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1061,11 +1079,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,10 +1132,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1334,6 +1355,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, + {1,3,16384}, }, { { @@ -1632,12 +1654,17 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {1,3,3}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1668,12 +1695,13 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,16}, + {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1741,6 +1769,31 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { + { + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + } + }, { 1, { {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, @@ -1786,7 +1839,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 6, { + {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, + } + }, + { + 4, { + {"_1_4_colors[0]", true, 0, 1, 4, 256}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + } + }, + { + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2194,12 +2318,7 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index aa21a506c..c81703e3a 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -13,6 +13,12 @@ GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, con //Gets DS and gets pool it was allocated from into m_parentPool m_descriptorSet = m_device->allocateDescriptorSetPrimitive(m_hDescriptorSetLayout, m_parentPool); + + auto &arraySizes = hDescriptorSetLayout->getArraySizes(); + for (int i = 0; i < arraySizes.size(); i++) { + boundDescriptors[i].resize(arraySizes[i]); + }; + assert(m_descriptorSet != nullptr); } GDescriptorSet::~GDescriptorSet() { @@ -51,7 +57,7 @@ void GDescriptorSet::writeToDescriptorSets(std::vector &de m_dynamicBufferIndexes = dynamicBufferIndexes; m_dynamicBuffers.resize(m_dynamicBufferIndexes.size()); for (int i = 0; i < m_dynamicBufferIndexes.size(); i++) { - m_dynamicBuffers[i] = boundDescriptors[m_dynamicBufferIndexes[i]]->buffer.get(); + m_dynamicBuffers[i] = boundDescriptors[m_dynamicBufferIndexes[i]][0]->buffer.get(); } } @@ -75,7 +81,7 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture auto textureVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getTexture()) : nullptr; auto samplerVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getSampler()) : nullptr; - assignBoundDescriptors(bindIndex, samplableTextureVlk, DescriptorRecord::DescriptorRecordType::Texture); + assignBoundDescriptors(bindIndex, samplableTextureVlk, index, DescriptorRecord::DescriptorRecordType::Texture); auto texture = textureVlk; VkDescriptorImageInfo &imageInfo = imageInfos.emplace_back(); @@ -125,7 +131,7 @@ GDescriptorSet::SetUpdateHelper::ubo_dynamic(int bindIndex, const std::shared_pt } #endif - assignBoundDescriptors(bindIndex, buffer, DescriptorRecord::DescriptorRecordType::UBODynamic); + assignBoundDescriptors(bindIndex, buffer, 0, DescriptorRecord::DescriptorRecordType::UBODynamic); m_updateBindPoints[bindIndex] = true; VkDescriptorBufferInfo &bufferInfo = bufferInfos.emplace_back(); @@ -171,7 +177,7 @@ GDescriptorSet::SetUpdateHelper::ubo(int bindIndex, const std::shared_ptrgetIsBindless()) { + if (/*!m_set.m_hDescriptorSetLayout->getIsBindless()*/ true) { //Fill the rest of Descriptor with already bound values //This is needed, cause In this implementation of descriptor set, the descriptor set is getting free'd on update //and new one is created for (int bindPoint = 0; bindPoint < m_updateBindPoints.size(); bindPoint++) { - if (m_updateBindPoints[bindPoint] || m_boundDescriptors[bindPoint] == nullptr) continue; - - if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBO) { - ubo(bindPoint, m_boundDescriptors[bindPoint]->buffer); - } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::UBODynamic) { - ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint]->buffer); - } else if (m_boundDescriptors[bindPoint]->descType == DescriptorRecord::DescriptorRecordType::Texture) { - texture(bindPoint, m_boundDescriptors[bindPoint]->texture); + if (m_updateBindPoints[bindPoint]) continue; + + for (int bindIndex = 0; bindIndex < m_boundDescriptors[bindPoint].size(); bindIndex++) { + if (m_boundDescriptors[bindPoint][bindIndex] == nullptr) continue; + + if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::UBO) { + ubo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == + DescriptorRecord::DescriptorRecordType::UBODynamic) { + ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::SSBO) { + ssbo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::Texture) { + texture(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->texture, bindIndex); + } } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 52810e6d7..a3e59a8af 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -54,12 +54,12 @@ class GDescriptorSet : public std::enable_shared_from_this { class SetUpdateHelper { public: - explicit SetUpdateHelper(GDescriptorSet &set, std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors, + explicit SetUpdateHelper(GDescriptorSet &set, std::array>, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &boundDescriptors, std::shared_ptr descriptorSetUpdater) : m_set(set), m_boundDescriptors(boundDescriptors), m_descriptorSetUpdater(descriptorSetUpdater) { //So that the resize of these vectors would not lead to pointer invalidation in updates vector bufferInfos.reserve(32); - imageInfos.reserve(32); + imageInfos.reserve(2500); updates.reserve(64); } ~SetUpdateHelper(); @@ -78,20 +78,22 @@ class GDescriptorSet : public std::enable_shared_from_this { void cancelUpdate(); template - void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, DescriptorRecord::DescriptorRecordType descType) { + void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, int index, DescriptorRecord::DescriptorRecordType descType) { // static_assert(std::is_base_of::value, "T should inherit from B"); - bool createDescRecord = !m_boundDescriptors[bindPoint]; + assert(index < m_boundDescriptors[bindPoint].size()); + + bool createDescRecord = !m_boundDescriptors[bindPoint][index]; if (!createDescRecord) { if constexpr (std::is_base_of::value) { - createDescRecord = (m_boundDescriptors[bindPoint]->buffer != object); + createDescRecord = (m_boundDescriptors[bindPoint][index]->buffer != object); } else if constexpr (std::is_base_of::value) { - createDescRecord = (m_boundDescriptors[bindPoint]->texture != object); + createDescRecord = (m_boundDescriptors[bindPoint][index]->texture != object); } } if (createDescRecord) { std::function callback = createCallback(); - m_boundDescriptors[bindPoint] = std::make_unique(descType, object, callback); + m_boundDescriptors[bindPoint][index] = std::make_unique(descType, object, callback); } } std::unordered_map &getAccumulatedTypeOverrides() { @@ -100,7 +102,7 @@ class GDescriptorSet : public std::enable_shared_from_this { private: bool updateCancelled = false; GDescriptorSet &m_set; - std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &m_boundDescriptors; + std::array>, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &m_boundDescriptors; std::vector imageInfos; std::vector bufferInfos; @@ -128,7 +130,7 @@ class GDescriptorSet : public std::enable_shared_from_this { bool m_firstUpdate = true; - std::array, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> boundDescriptors; + std::array>, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> boundDescriptors; // Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea // //Defines amount of frames that the updates has to be copied from previous frame diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index fe98d9cd4..ed8d94c4c 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -11,6 +11,8 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr const std::vector &metaDatas, int setIndex, const DescTypeOverride &typeOverrides) : m_device(device) { + for (auto &size : m_arraySizes) size = 0; + //Create Layout auto &shaderLayoutBindings = m_shaderLayoutBindings; std::unordered_set bindlessBindPoints; @@ -69,6 +71,8 @@ GDescriptorSetLayout::GDescriptorSetLayout(const std::shared_ptr } } + m_arraySizes[imageLayoutBinding.binding] = imageLayoutBinding.descriptorCount; + shaderLayoutBindings.insert({imageBinding.binding, imageLayoutBinding}); m_totalImages += imageLayoutBinding.descriptorCount; @@ -161,6 +165,7 @@ void GDescriptorSetLayout::fillUbo(int setIndex, const DescTypeOverride &typeOve } } + auto it = shaderLayoutBindings.find(uboBinding.binding); if (it != std::end( shaderLayoutBindings )) { it->second.stageFlags |= vkStageFlag; @@ -188,6 +193,7 @@ void GDescriptorSetLayout::fillUbo(int setIndex, const DescTypeOverride &typeOve } } + m_arraySizes[uboLayoutBinding.binding] = uboLayoutBinding.descriptorCount; m_requiredBindPoints[uboBinding.binding] = true; } } @@ -244,6 +250,7 @@ void GDescriptorSetLayout::fillSSBO(int setIndex, const DescTypeOverride &typeOv } } + m_arraySizes[ssboLayoutBinding.binding] = ssboLayoutBinding.descriptorCount; m_requiredBindPoints[ssboBinding.binding] = true; } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 9aae75c15..1babb4df7 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -39,7 +39,8 @@ class GDescriptorSetLayout { int getTotalSsbos() const { return m_totalSSBOs; }; int getTotalImages() const { return m_totalImages; }; bool getIsBindless() const { return m_isBindless; }; - std::bitset getRequiredBindPoints() {return m_requiredBindPoints;}; + const std::bitset& getRequiredBindPoints() const {return m_requiredBindPoints;}; + const std::array& getArraySizes() const {return m_arraySizes;}; private: std::unordered_map m_shaderLayoutBindings; std::unordered_map m_requiredUBOSize; @@ -47,6 +48,7 @@ class GDescriptorSetLayout { std::vector m_bindlessDescSizes; + std::array m_arraySizes; std::bitset m_requiredBindPoints = 0; VkDescriptorSetLayout m_descriptorSetLayout; int m_totalImages = 0; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 9e43437bf..1fa127b3e 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -25,6 +25,8 @@ class GMeshVLK : public IM2Mesh { EGxBlendEnum getGxBlendMode() override { return material()->getBlendMode(); } + + int instanceIndex = -1; public: auto material() const -> const HMaterialVLK& { return m_material; } auto scissorOffset() const -> const std::array& { return m_scissorOffset; } @@ -40,12 +42,6 @@ class GMeshVLK : public IM2Mesh { std::array m_scissorSize = {0,0}; - -//Vulkan specific - std::vector descriptorSetsUpdated; - - std::shared_ptr m_lastRenderPass = nullptr; - std::shared_ptr m_lastPipelineForRenderPass; private: HMaterialVLK m_material; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 31cce0026..ae8314365 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -15,6 +15,7 @@ #include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" #include "../../frame/FrameProfile.h" #include "view/RenderViewForwardVLK.h" +#include "../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" #include static const ShaderConfig forwardShaderConfig = { @@ -379,6 +380,8 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr vertexFragmentDataBindless->save(); } + material->instanceIndex = vertexFragmentDataBindless->getSubBuffer()->getIndex(); + material->blendMode = pipelineTemplate.blendMode; material->depthWrite = pipelineTemplate.depthWrite; material->depthCulling = pipelineTemplate.depthCulling; @@ -639,7 +642,11 @@ inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const H } //7. Draw the mesh - cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); + if (meshVlk->instanceIndex != -1) { + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, meshVlk->instanceIndex); + } else { + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, 0); + } } static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { @@ -754,6 +761,16 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + uploadCmd.submitBufferUploads(l_this->m2Buffers.placementMatrix); + uploadCmd.submitBufferUploads(l_this->m2Buffers.boneMatrix); + uploadCmd.submitBufferUploads(l_this->m2Buffers.m2Colors); + uploadCmd.submitBufferUploads(l_this->m2Buffers.textureWeights); + uploadCmd.submitBufferUploads(l_this->m2Buffers.textureMatrices); + uploadCmd.submitBufferUploads(l_this->m2Buffers.modelFragmentDatas); + uploadCmd.submitBufferUploads(l_this->m2Buffers.m2InstanceData); + uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocks); + uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocksBindless); + uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); @@ -884,6 +901,7 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: int layer, int priorityPlane) { auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, From 245fedc8b83bcbd32a74fbdda6ea5031f0d59e3b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 9 Oct 2023 15:37:31 +0300 Subject: [PATCH 130/212] - fix animation and other dyn stuff in bindless --- .../shaders/glsl/visBuffer/m2Shader.frag | 35 ++-- .../src/engine/shader/ShaderDefinitions.h | 177 ++---------------- .../vulkan/commandBuffer/CommandBuffer.cpp | 2 +- 3 files changed, 42 insertions(+), 172 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index 97dcf2286..9d4f9e5e7 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -14,7 +14,7 @@ layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; layout(location=2) in vec3 vNormal; layout(location=3) in vec4 vPosition_EdgeFade; -layout(location=4) in flat int meshIndex; +layout(location=4) in flat int vMeshIndex; layout(location=0) out vec4 outputColor; @@ -33,26 +33,36 @@ void main() { vec4 finalColor = vec4(0); - meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[meshIndex]; - meshWideBlockVSPS meshWide = meshWides[meshWideBindless.instanceIndex_meshIndex.y]; + meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[vMeshIndex]; + meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; + int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; + M2InstanceRecordBindless m2Instance = instances[nonuniformEXT(instanceIndex)]; + + modelWideBlockPSStruct modelWide = modelWides[m2Instance.textureMatricesInd_modelFragmentDatasInd.y]; + + + int placementMatrixInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + int textureWeightsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.w; + int m2ColorsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.z; + int textureMatricesInd = m2Instance.textureMatricesInd_modelFragmentDatasInd.x; vec3 uTexSampleAlpha = vec3( - meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], - meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], - meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] + meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], + meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], + meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] ); vec4 vMeshColorAlpha = vec4( meshWide.colorIndex_applyWeight.x < 0 ? vec4(1.0,1.0,1.0,1.0) : - colors[meshWide.colorIndex_applyWeight.x] + colors[m2ColorsInd + meshWide.colorIndex_applyWeight.x] ); if (meshWide.colorIndex_applyWeight.y > 0) vMeshColorAlpha.a *= meshWide.textureWeightIndexes.x < 0 ? 1.0 : - textureWeight[meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; + textureWeight[textureWeightsInd + meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; vec3 l_Normal = vNormal; @@ -61,10 +71,9 @@ void main() { vec3 meshResColor = vMeshColorAlpha.rgb; vec3 accumLight = vec3(0.0); - modelWideBlockPSStruct modelWide = modelWides[instanceIndex]; + if ((meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { - mat4 placementMat = - uPlacementMats[instances[instanceIndex].placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x]; + mat4 placementMat = uPlacementMats[placementMatrixInd]; vec3 vPos3 = vPosition_EdgeFade.xyz; vec3 vNormal3 = normalize(l_Normal.xyz); @@ -103,8 +112,8 @@ void main() { int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; - textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; - textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex2]; float edgeFade = 1.0; calcM2VertexMat(uVertexShader, diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b8bb8176e..b30195330 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -318,14 +318,9 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, - {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, }, { }, @@ -390,9 +385,6 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { @@ -665,11 +657,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -687,17 +678,11 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, + {0,0,0}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -732,11 +717,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -841,11 +825,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1013,13 +996,12 @@ const std::unordered_map shaderMetaInfo = { { {1,9,0}, {1,8,0}, + {1,7,0}, + {1,2,0}, {1,5,0}, {1,4,0}, - {1,2,0}, {1,1,0}, - {1,7,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1079,12 +1061,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1132,12 +1113,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1355,7 +1334,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, - {1,3,16384}, }, { { @@ -1654,17 +1632,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1695,13 +1668,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,4,16}, - {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {3,4,2}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1769,31 +1741,6 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { - { - 5, { - {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, { 1, { {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, @@ -1839,7 +1786,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, - } - }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2318,7 +2194,12 @@ const std::unordered_map Date: Mon, 9 Oct 2023 20:31:53 +0300 Subject: [PATCH 131/212] - fix few errors in m2 bindless. and it seems to work --- wowViewerLib/CMakeLists.txt | 2 +- .../shaders/glsl/visBuffer/adtShader.frag | 167 +++ .../shaders/glsl/visBuffer/adtShader.vert | 83 ++ .../src/engine/shader/ShaderDefinitions.h | 1139 +++++++++-------- .../vulkan/buffers/GStagingRingBuffer.cpp | 9 +- .../mapScene/materials/BindlessTexture.h | 6 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 4 +- .../vulkan/MapSceneRenderVisBufferVLK.h | 2 +- 8 files changed, 901 insertions(+), 511 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/visBuffer/adtShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/adtShader.vert diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index cce982689..fa115b78e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 0) +set(LINK_TRACY 1) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag new file mode 100644 index 000000000..1b2d87e96 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -0,0 +1,167 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + +layout(location = 0) in vec2 vChunkCoords; +layout(location = 1) in vec3 vPosition; +layout(location = 2) in vec4 vColor; +layout(location = 3) in vec3 vNormal; +layout(location = 4) in vec3 vVertexLighting; + +layout(set=2, binding=5) uniform sampler2D uLayer0; +layout(set=2, binding=6) uniform sampler2D uLayer1; +layout(set=2, binding=7) uniform sampler2D uLayer2; +layout(set=2, binding=8) uniform sampler2D uLayer3; +layout(set=2, binding=9) uniform sampler2D uAlphaTexture; +layout(set=2, binding=10) uniform sampler2D uLayerHeight0; +layout(set=2, binding=11) uniform sampler2D uLayerHeight1; +layout(set=2, binding=12) uniform sampler2D uLayerHeight2; +layout(set=2, binding=13) uniform sampler2D uLayerHeight3; + +#include "../common/commonUboSceneData.glsl" + +layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { + vec4 uPos; + ivec4 uUseHeightMixFormula; + vec4 uHeightScale; + vec4 uHeightOffset; +}; + +layout(std140, set=1, binding=2) uniform meshWideBlockPS { + vec4 scaleFactorPerLayer; + ivec4 animation_rotationPerLayer; + ivec4 animation_speedPerLayer; +}; + + +layout(location = 0) out vec4 outColor; + +const InteriorLightParam intLight = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + +vec4 mixTextures(vec4 tex0, vec4 tex1, float alpha) { + return (alpha*(tex1-tex0)+tex0); +} + +const vec2 s_texDir[8] = { + {-1.0, 0.0}, + {-1.0, 1.0}, + {0.0, 1.0}, + {1.0, 1.0}, + {1.0, 0.0}, + {1.0, -1.0}, + {0.0, -1.0}, + {-1.0, -1.0} +}; +const float s_tempTexSpeed[8] = {64.0, 48.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0}; + +float fmod1(float x, float y) { + return x - (y * trunc(x/y)); +} + +vec2 transformUV(in vec2 uv, in int layer) { + vec2 translate = vec2(0.0); + int animation_rotation = animation_rotationPerLayer[layer]; + if (animation_rotation >= 0 && animation_rotation < 8) { + vec2 transVector = s_texDir[animation_rotation] * (scene.uViewUpSceneTime.w * 0.001); + transVector.xy = transVector.yx; //why? + transVector.x = fmod1(transVector.x, 64); + transVector.y = fmod1(transVector.y, 64); + + translate = + transVector * + (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[animation_speedPerLayer[layer]])); + } + return (uv * scaleFactorPerLayer[layer]) + translate; +} + +void main() { + vec2 vTexCoord = vChunkCoords; + const float threshold = 1.5; + + vec2 alphaCoord = vec2(vChunkCoords.x/8.0, vChunkCoords.y/8.0 ); + vec3 alphaBlend = texture( uAlphaTexture, alphaCoord).gba; + + vec2 tcLayer0 = transformUV(vTexCoord, 0); + vec2 tcLayer1 = transformUV(vTexCoord, 1); + vec2 tcLayer2 = transformUV(vTexCoord, 2); + vec2 tcLayer3 = transformUV(vTexCoord, 3); + + vec4 final; + if (uUseHeightMixFormula.r > 0) { + float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); + vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); + float weightedTexture_x = (minusAlphaBlendSum * ((texture(uLayerHeight0, tcLayer0).w * uHeightScale[0]) + uHeightOffset[0])); + float weightedTexture_y = (weightsVector.y * ((texture(uLayerHeight1, tcLayer1).w * uHeightScale[1]) + uHeightOffset[1])); + float weightedTexture_z = (weightsVector.z * ((texture(uLayerHeight2, tcLayer2).w * uHeightScale[2]) + uHeightOffset[2])); + float weightedTexture_w = (weightsVector.w * ((texture(uLayerHeight3, tcLayer3).w * uHeightScale[3]) + uHeightOffset[3])); + vec4 weights = vec4(weightedTexture_x, weightedTexture_y, weightedTexture_z, weightedTexture_w); + vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); + vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); + + vec4 weightedLayer_0 = (texture(uLayer0, tcLayer0) * weightsNormalized.x); + vec3 matDiffuse_0 = weightedLayer_0.xyz; + float specBlend_0 = weightedLayer_0.w; + + vec4 weightedLayer_1 = (texture(uLayer1, tcLayer1) * weightsNormalized.y); + vec3 matDiffuse_1 = (matDiffuse_0 + weightedLayer_1.xyz); + float specBlend_1 = (specBlend_0 + weightedLayer_1.w); + + vec4 weightedLayer_2 = (texture(uLayer2, tcLayer2) * weightsNormalized.z); + vec3 matDiffuse_2 = (matDiffuse_1 + weightedLayer_2.xyz); + float specBlend_2 = (specBlend_1 + weightedLayer_2.w); + + vec4 weightedLayer_3 = (texture(uLayer3, tcLayer3) * weightsNormalized.w); + vec3 matDiffuse_3 = (matDiffuse_2 + weightedLayer_3.xyz); + float specBlend_3 = (specBlend_2 + weightedLayer_3.w); + + final = vec4(matDiffuse_3, specBlend_3); + } else { + vec4 tex1 = texture(uLayer0, tcLayer0).rgba; + vec4 tex2 = texture(uLayer1, tcLayer1).rgba; + vec4 tex3 = texture(uLayer2, tcLayer2).rgba; + vec4 tex4 = texture(uLayer3, tcLayer3).rgba; + + final = mixTextures(mixTextures(mixTextures(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + } + + vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; + + + vec4 finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + 0.0, + scene, + intLight, + vVertexLighting.rgb, /* accumLight */ + vec3(0.0), /*precomputedLight*/ + vec3(0.0), /* specular */ + vec3(0.0) /* emissive */ + ), + 1.0 + ); + + //Spec part + float specBlend = final.a; + vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); + vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); + vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; + finalColor.rgb += specTerm; + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); + + finalColor.a = 1.0; + outColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert new file mode 100644 index 000000000..7c8299a08 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -0,0 +1,83 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + +/* vertex shader code */ +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec4 aColor; +layout(location = 2) in vec4 aVertexLighting; +layout(location = 3) in vec3 aNormal; + +#include "../common/commonUboSceneData.glsl" + +layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { + vec4 uPos; + ivec4 uUseHeightMixFormula; + vec4 uHeightScale; + vec4 uHeightOffset; +}; + +mat3 blizzTranspose(mat4 value) { + return mat3( + value[0].xyz, + value[1].xyz, + value[2].xyz + ); +} + +layout(location = 0) out vec2 vChunkCoords; +layout(location = 1) out vec3 vPosition; +layout(location = 2) out vec4 vColor; +layout(location = 3) out vec3 vNormal; +layout(location = 4) out vec3 vVertexLighting; + +const float UNITSIZE_X = (1600.0 / 3.0) / 16.0 / 8.0; +const float UNITSIZE_Y = (1600.0 / 3.0) / 16.0 / 8.0; + +void main() { + +/* + Y + X 0 1 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 16 +*/ + + //With current implementation ADT's VBO is combined buffer, which contains all vertexes from all MCNK of ADT + //Thus, we first need to get vertexNumber within MCNK + + int indexInMCNK = gl_VertexIndex % (9 * 9 + 8 * 8); + float iX = mod(indexInMCNK, 17.0); + float iY = floor(indexInMCNK/17.0); + + if (iX > 8.01) { + iY = iY + 0.5; + iX = iX - 8.5; + } + +// vec4 worldPoint = vec4( +// uPos.x - iY * UNITSIZE_Y, +// uPos.y - iX * UNITSIZE_X, +// uPos.z + aHeight, +// 1); + + vec4 worldPoint = vec4(aPos, 1); + + vChunkCoords = vec2(iX, iY); + + vPosition = (scene.uLookAtMat * worldPoint).xyz; + vColor = aColor; + vVertexLighting = aVertexLighting.rgb; + mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); + + vNormal = normal; + + gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; + +} diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index b30195330..82e68f683 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,33 +295,14 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,0,84}, }, { { @@ -317,16 +317,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -338,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,480}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -376,21 +372,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, - {0,0,480}, - {1,1,64}, + {0,2,12}, }, { { - {0,0,1}, - {1,6,6}, - {4,4,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -401,14 +393,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -417,17 +409,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -439,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -454,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,96}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -491,14 +492,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -506,7 +509,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -527,15 +529,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -563,15 +565,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -599,14 +601,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -619,12 +622,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -635,15 +637,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,1,112}, + {0,0,480}, }, { { - {2,2,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -656,11 +659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -672,18 +674,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -694,17 +695,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -713,14 +710,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -748,12 +746,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { @@ -821,14 +819,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,480}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -856,15 +855,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -877,10 +876,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -892,15 +893,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -928,18 +929,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,48}, - {0,0,480}, - {1,1,64}, + {0,4,32}, }, { { - {0,0,1}, - {1,2,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -951,21 +950,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, - {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -975,15 +966,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -994,23 +985,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, }, { - {2,0, "s_Textures"}, + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, + {5,6,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1020,15 +1004,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1041,11 +1024,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1056,15 +1040,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,1,80}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1092,16 +1076,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,4,32}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1113,12 +1098,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1128,17 +1116,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1150,21 +1137,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,16 +1152,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,480}, + {1,1,96}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1195,12 +1174,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1211,17 +1189,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1232,13 +1217,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1247,17 +1236,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { - {4,4,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1268,13 +1264,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1285,17 +1279,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,480}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1307,13 +1299,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1323,23 +1314,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,16}, + {1,3,4096}, {0,0,480}, - {1,1,64}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1350,17 +1337,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1369,16 +1353,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1406,15 +1389,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1442,11 +1424,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, + {1,4,96}, {0,0,480}, }, { @@ -1465,14 +1447,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1482,16 +1462,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1518,16 +1499,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,5,96}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1538,13 +1527,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1553,16 +1546,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,4,16}, + {1,6,4096}, + {1,3,16384}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,13 +1574,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1588,16 +1590,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,4,32}, + {0,0,480}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1609,13 +1612,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,18 +1636,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, {1,1,64}, {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {1,3,3}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1663,17 +1674,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1683,15 +1693,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { - {2,5, "uTexture"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1701,7 +1720,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -1720,6 +1739,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, }, { }, @@ -1740,10 +1768,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { + { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + } + }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -1774,21 +1813,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { + {"wmoShader", { + { + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2193,13 +2240,27 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2215,29 +2276,21 @@ const std::unordered_mapgetCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &vec = m_stagingBuffers[frame]; @@ -13,7 +13,7 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of auto ¤tOffset = offsets[frame]; //Add alignment - size += 16; + auto size = o_size + 16; if (size > STAGE_BUFFER_SIZE) throw std::runtime_error(("size > STAGE_BUFFER_SIZE; size = " + std::to_string(size))); @@ -28,7 +28,7 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of currentIndex = ( offset ) / STAGE_BUFFER_SIZE; currentIndexAfter = (offset + size) / STAGE_BUFFER_SIZE; - if (currentIndexAfter >= vec.size()) { + if (currentIndexAfter >= vec.size() || vec[currentIndexAfter] == nullptr) { std::unique_lock l(m_mutex);// while (currentIndexAfter >= vec.size()) { @@ -60,7 +60,8 @@ void * GStagingRingBuffer::allocateNext(int size, VkBuffer &o_staging, int &o_of startOffset += alignAdd; auto allocatedPtr = ((uint8_t *)bufferAndCPU->cpuBuffer.data()) + startOffset; - if ((startOffset + size) > bufferAndCPU->cpuBuffer.size()) { + if ((startOffset + o_size) > bufferAndCPU->cpuBuffer.size()) { + std::cerr << startOffset << " " << o_size << std::endl; throw "OOOOSP"; } o_staging = bufferAndCPU->staging->getBuffer(); diff --git a/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h b/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h index 83c1cf352..a9cbf60a0 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h +++ b/wowViewerLib/src/renderer/mapScene/materials/BindlessTexture.h @@ -11,13 +11,13 @@ //Bindless stuff class BindlessTexture { public: - BindlessTexture(uint32_t index, const std::function &onDestroy): m_index(index){}; + BindlessTexture(uint32_t index, const std::function &onDestroy): m_index(index), m_onDestroy(onDestroy){}; ~BindlessTexture() { - if (onDestroy) onDestroy(); + if (m_onDestroy) m_onDestroy(); } uint32_t getIndex() const {return m_index;}; private: - std::function onDestroy; + std::function m_onDestroy; uint32_t m_index; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index ae8314365..f8797bec2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -26,7 +26,7 @@ static const ShaderConfig forwardShaderConfig = { }} } }; -const int m2TexturesBindlessCount = 2048; +const int m2TexturesBindlessCount = 4096; static const ShaderConfig m2VisShaderConfig = { "visBuffer", { @@ -139,7 +139,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic .createDescriptorSet(2, [&](std::shared_ptr &ds) { m2TextureDS = ds; }); - m2TextureHolder = std::make_unique(m2TexturesBindlessCount); + m2TextureHolder = std::make_shared(m2TexturesBindlessCount); } // ------------------ diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 2a9f6c8ee..0c2fc790a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -168,7 +168,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr sceneWideDS = nullptr; std::shared_ptr m2TextureDS = nullptr; - std::unique_ptr m2TextureHolder = nullptr; + std::shared_ptr m2TextureHolder = nullptr; std::shared_ptr m2BufferOneDS = nullptr; From 34bf9f3ae44dcaf3709e9bcfacf1b9d1d267c80e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 10 Oct 2023 16:05:19 +0300 Subject: [PATCH 132/212] - ADT bindless ver 1 --- src/main.cpp | 13 +- wowViewerLib/CMakeLists.txt | 2 +- .../commonAdtIndirectDescriptorSet.glsl | 38 + .../common/commonM2IndirectDescriptorSet.glsl | 18 +- .../glsl/forwardRendering/ribbonShader.frag | 2 +- .../shaders/glsl/visBuffer/adtShader.frag | 105 +- .../shaders/glsl/visBuffer/adtShader.vert | 24 +- .../src/engine/objects/adt/adtObject.cpp | 35 +- .../src/engine/objects/adt/adtObject.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1200 ++++++++--------- .../src/gapi/UniformBufferStructures.h | 10 +- .../vulkan/descriptorSets/GDescriptorSet.h | 2 +- .../bindless/BindlessTextureHolder.cpp | 2 +- .../src/renderer/frame/FrameProfile.h | 1 + .../renderer/mapScene/IMapSceneBufferCreate.h | 1 + .../mapScene/materials/IMaterialStructs.h | 8 + .../vulkan/MapSceneRenderForwardVLK.cpp | 5 + .../vulkan/MapSceneRenderForwardVLK.h | 1 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 143 +- .../vulkan/MapSceneRenderVisBufferVLK.h | 17 + 20 files changed, 895 insertions(+), 734 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl diff --git a/src/main.cpp b/src/main.cpp index 9cacab348..fcaef1301 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,9 @@ #include "screenshots/screenshotMaker.h" #include "database/CEmptySqliteDB.h" #include +#ifdef WIN32 +#include +#endif #ifdef LINK_TRACY #include "Tracy.hpp" #endif @@ -456,6 +459,7 @@ int main(){ // auto native_me = std::this_thread::get_id().native_handle(); #ifdef WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + timeBeginPeriod(3); #endif //This has to be called after setting all callbacks specific to this app. //ImGUI takes care of previous callbacks and calls them before applying it's own logic over data @@ -506,7 +510,11 @@ int main(){ lastFrame = currentFrame; if (currentDeltaAfterDraw < 5.0) { using namespace std::chrono_literals; - std::this_thread::sleep_for(std::chrono::milliseconds((int)(4.0))); +#ifdef WIN32 + sqlite3_sleep(5.0f-currentDeltaAfterDraw); +#else + std::this_thread::sleep_for(std::chrono::milliseconds((int)(5.0-currentDeltaAfterDraw))); +#endif } if (rendererName == "ogl3" || rendererName == "ogl2") { @@ -525,6 +533,9 @@ int main(){ //} std::cout << "program ended" << std::endl; +#ifdef WIN32 + timeEndPeriod(3); +#endif // while (1) { // mainLoop(&myapp); // } diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index fa115b78e..cce982689 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 1) +set(LINK_TRACY 0) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) diff --git a/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl new file mode 100644 index 000000000..d4c3c33c0 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl @@ -0,0 +1,38 @@ +#ifndef COMMON_ADT_INDIRECT_DS +#define COMMON_ADT_INDIRECT_DS + +struct AdtMeshWideVSPS { + vec4 uPos; + ivec4 uUseHeightMixFormula; + vec4 uHeightScale; + vec4 uHeightOffset; +}; + +layout(std140, set=1, binding=1) buffer readonly meshWideBlockVSPS { + AdtMeshWideVSPS adtMeshWideVSPSes[]; +}; + +struct AdtMeshWidePS { + vec4 scaleFactorPerLayer; + ivec4 animation_rotationPerLayer; + ivec4 animation_speedPerLayer; +}; + +layout(std140, set=1, binding=2) buffer readonly meshWideBlockPS { + AdtMeshWidePS adtMeshWidePSes[]; +}; + + +struct AdtInstanceData { + ivec4 meshIndexVSPS_meshIndexPS_AlphaTextureInd; + ivec4 Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind; + ivec4 LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind; +}; + +layout(std140, set=1, binding=3) buffer readonly instanceData { + AdtInstanceData adtInstanceDatas[]; +}; + + + +#endif //COMMON_ADT_INDIRECT_DS \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl index 4ff354870..5c66d0487 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl @@ -5,7 +5,7 @@ #endif // Whole model -layout(std430, set=1, binding=1) buffer modelWideBlockVS { +layout(std430, set=1, binding=1) buffer readonly modelWideBlockVS { mat4 uPlacementMats[]; }; @@ -16,23 +16,23 @@ struct modelWideBlockPSStruct { vec4 interiorExteriorBlend; }; -layout(std430, set=1, binding=2) buffer modelWideBlockPS { +layout(std430, set=1, binding=2) buffer readonly modelWideBlockPS { modelWideBlockPSStruct modelWides[]; }; -layout(std430, set=1, binding=3) buffer boneMats { +layout(std430, set=1, binding=3) buffer readonly boneMats { mat4 uBoneMatrixes[]; }; -layout(std430, set=1, binding=4) buffer m2Colors { +layout(std430, set=1, binding=4) buffer readonly m2Colors { vec4 colors[]; }; -layout(std430, set=1, binding=5) buffer textureWeights { +layout(std430, set=1, binding=5) buffer readonly textureWeights { vec4 textureWeight[]; }; -layout(std430, set=1, binding=6) buffer textureMatrices { +layout(std430, set=1, binding=6) buffer readonly textureMatrices { mat4 textureMatrix[]; }; @@ -40,7 +40,7 @@ struct M2InstanceRecordBindless { ivec4 placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd; ivec4 textureMatricesInd_modelFragmentDatasInd; }; -layout(std430, set=1, binding=7) buffer m2Instances { +layout(std430, set=1, binding=7) buffer readonly m2Instances { M2InstanceRecordBindless instances[]; }; @@ -51,7 +51,7 @@ struct meshWideBlockVSPS { ivec4 colorIndex_applyWeight; }; -layout(std430, set=1, binding=8) buffer meshWide { +layout(std430, set=1, binding=8) buffer readonly meshWide { meshWideBlockVSPS meshWides[]; }; @@ -60,6 +60,6 @@ struct meshWideBlockVSPSBindless { ivec4 textureIndicies; }; -layout(std430, set=1, binding=9) buffer meshWideBindless { +layout(std430, set=1, binding=9) buffer readonly meshWideBindless { meshWideBlockVSPSBindless meshWideBindleses[]; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index b5ada8be1..704f9af66 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -38,7 +38,7 @@ void main() { texcoord = (vTexcoord0 * textCoordScale) + textureTranslate.xy; } - vec4 tex = texture(uTexture, vTexcoord0).rgba; + vec4 tex = texture(uTexture, texcoord).rgba; vec4 finalColor = vec4((vColor.rgb*tex.rgb), tex.a * vColor.a); diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index 1b2d87e96..b665b84ee 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require precision highp float; precision highp int; @@ -8,36 +9,32 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonAdtIndirectDescriptorSet.glsl" + layout(location = 0) in vec2 vChunkCoords; layout(location = 1) in vec3 vPosition; layout(location = 2) in vec4 vColor; layout(location = 3) in vec3 vNormal; layout(location = 4) in vec3 vVertexLighting; - -layout(set=2, binding=5) uniform sampler2D uLayer0; -layout(set=2, binding=6) uniform sampler2D uLayer1; -layout(set=2, binding=7) uniform sampler2D uLayer2; -layout(set=2, binding=8) uniform sampler2D uLayer3; -layout(set=2, binding=9) uniform sampler2D uAlphaTexture; -layout(set=2, binding=10) uniform sampler2D uLayerHeight0; -layout(set=2, binding=11) uniform sampler2D uLayerHeight1; -layout(set=2, binding=12) uniform sampler2D uLayerHeight2; -layout(set=2, binding=13) uniform sampler2D uLayerHeight3; +layout(location = 5) in flat int meshIndex; +layout(location = 6) in vec2 vAlphaCoords; + +layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; +layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; +layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; + +//layout(set=2, binding=5) uniform sampler2D uLayer0; +//layout(set=2, binding=6) uniform sampler2D uLayer1; +//layout(set=2, binding=7) uniform sampler2D uLayer2; +//layout(set=2, binding=8) uniform sampler2D uLayer3; +//layout(set=2, binding=9) uniform sampler2D uAlphaTexture; +//layout(set=2, binding=10) uniform sampler2D uLayerHeight0; +//layout(set=2, binding=11) uniform sampler2D uLayerHeight1; +//layout(set=2, binding=12) uniform sampler2D uLayerHeight2; +//layout(set=2, binding=13) uniform sampler2D uLayerHeight3; #include "../common/commonUboSceneData.glsl" -layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { - vec4 uPos; - ivec4 uUseHeightMixFormula; - vec4 uHeightScale; - vec4 uHeightOffset; -}; - -layout(std140, set=1, binding=2) uniform meshWideBlockPS { - vec4 scaleFactorPerLayer; - ivec4 animation_rotationPerLayer; - ivec4 animation_speedPerLayer; -}; layout(location = 0) out vec4 outColor; @@ -67,9 +64,9 @@ float fmod1(float x, float y) { return x - (y * trunc(x/y)); } -vec2 transformUV(in vec2 uv, in int layer) { +vec2 transformUV(in vec2 uv, in int layer, in AdtMeshWidePS adtMeshWidePS) { vec2 translate = vec2(0.0); - int animation_rotation = animation_rotationPerLayer[layer]; + int animation_rotation = adtMeshWidePS.animation_rotationPerLayer[layer]; if (animation_rotation >= 0 && animation_rotation < 8) { vec2 transVector = s_texDir[animation_rotation] * (scene.uViewUpSceneTime.w * 0.001); transVector.xy = transVector.yx; //why? @@ -78,57 +75,75 @@ vec2 transformUV(in vec2 uv, in int layer) { translate = transVector * - (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[animation_speedPerLayer[layer]])); + (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[adtMeshWidePS.animation_speedPerLayer[layer]])); } - return (uv * scaleFactorPerLayer[layer]) + translate; + return (uv * adtMeshWidePS.scaleFactorPerLayer[layer]) + translate; } void main() { + AdtInstanceData adtInstanceData = adtInstanceDatas[nonuniformEXT(meshIndex)]; + AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x)]; + AdtMeshWidePS adtMeshWidePS = adtMeshWidePSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.y)]; + + vec2 vTexCoord = vChunkCoords; const float threshold = 1.5; - vec2 alphaCoord = vec2(vChunkCoords.x/8.0, vChunkCoords.y/8.0 ); - vec3 alphaBlend = texture( uAlphaTexture, alphaCoord).gba; + vec2 alphaCoord = vec2(vAlphaCoords); + vec3 alphaBlend = texture( s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], alphaCoord).gba; + + vec2 tcLayer0 = transformUV(vTexCoord, 0, adtMeshWidePS); + vec2 tcLayer1 = transformUV(vTexCoord, 1, adtMeshWidePS); + vec2 tcLayer2 = transformUV(vTexCoord, 2, adtMeshWidePS); + vec2 tcLayer3 = transformUV(vTexCoord, 3, adtMeshWidePS); + + int layerHeight0 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.x; + int layerHeight1 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.y; + int layerHeight2 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.z; + int layerHeight3 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.w; + + int txLayer0 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.x; + int txLayer1 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.y; + int txLayer2 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.z; + int txLayer3 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.w; - vec2 tcLayer0 = transformUV(vTexCoord, 0); - vec2 tcLayer1 = transformUV(vTexCoord, 1); - vec2 tcLayer2 = transformUV(vTexCoord, 2); - vec2 tcLayer3 = transformUV(vTexCoord, 3); + vec4 heightScale = adtMeshWideVSPS.uHeightScale; + vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; vec4 final; - if (uUseHeightMixFormula.r > 0) { + if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); - float weightedTexture_x = (minusAlphaBlendSum * ((texture(uLayerHeight0, tcLayer0).w * uHeightScale[0]) + uHeightOffset[0])); - float weightedTexture_y = (weightsVector.y * ((texture(uLayerHeight1, tcLayer1).w * uHeightScale[1]) + uHeightOffset[1])); - float weightedTexture_z = (weightsVector.z * ((texture(uLayerHeight2, tcLayer2).w * uHeightScale[2]) + uHeightOffset[2])); - float weightedTexture_w = (weightsVector.w * ((texture(uLayerHeight3, tcLayer3).w * uHeightScale[3]) + uHeightOffset[3])); + float weightedTexture_x = (minusAlphaBlendSum * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight0)], tcLayer0).w * heightScale[0]) + heightOffset[0])); + float weightedTexture_y = (weightsVector.y * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight1)], tcLayer1).w * heightScale[1]) + heightOffset[1])); + float weightedTexture_z = (weightsVector.z * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight2)], tcLayer2).w * heightScale[2]) + heightOffset[2])); + float weightedTexture_w = (weightsVector.w * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight3)], tcLayer3).w * heightScale[3]) + heightOffset[3])); vec4 weights = vec4(weightedTexture_x, weightedTexture_y, weightedTexture_z, weightedTexture_w); vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); - vec4 weightedLayer_0 = (texture(uLayer0, tcLayer0) * weightsNormalized.x); + vec4 weightedLayer_0 = (texture(s_LayerTextures[nonuniformEXT(txLayer0)], tcLayer0) * weightsNormalized.x); vec3 matDiffuse_0 = weightedLayer_0.xyz; float specBlend_0 = weightedLayer_0.w; - vec4 weightedLayer_1 = (texture(uLayer1, tcLayer1) * weightsNormalized.y); + vec4 weightedLayer_1 = (texture(s_LayerTextures[nonuniformEXT(txLayer1)], tcLayer1) * weightsNormalized.y); vec3 matDiffuse_1 = (matDiffuse_0 + weightedLayer_1.xyz); float specBlend_1 = (specBlend_0 + weightedLayer_1.w); - vec4 weightedLayer_2 = (texture(uLayer2, tcLayer2) * weightsNormalized.z); + vec4 weightedLayer_2 = (texture(s_LayerTextures[nonuniformEXT(txLayer2)], tcLayer2) * weightsNormalized.z); vec3 matDiffuse_2 = (matDiffuse_1 + weightedLayer_2.xyz); float specBlend_2 = (specBlend_1 + weightedLayer_2.w); - vec4 weightedLayer_3 = (texture(uLayer3, tcLayer3) * weightsNormalized.w); + vec4 weightedLayer_3 = (texture(s_LayerTextures[nonuniformEXT(txLayer3)], tcLayer3) * weightsNormalized.w); vec3 matDiffuse_3 = (matDiffuse_2 + weightedLayer_3.xyz); float specBlend_3 = (specBlend_2 + weightedLayer_3.w); final = vec4(matDiffuse_3, specBlend_3); } else { - vec4 tex1 = texture(uLayer0, tcLayer0).rgba; - vec4 tex2 = texture(uLayer1, tcLayer1).rgba; - vec4 tex3 = texture(uLayer2, tcLayer2).rgba; - vec4 tex4 = texture(uLayer3, tcLayer3).rgba; + vec4 tex1 = texture(s_LayerTextures[nonuniformEXT(txLayer0)], tcLayer0).rgba; + vec4 tex2 = texture(s_LayerTextures[nonuniformEXT(txLayer1)], tcLayer1).rgba; + vec4 tex3 = texture(s_LayerTextures[nonuniformEXT(txLayer2)], tcLayer2).rgba; + vec4 tex4 = texture(s_LayerTextures[nonuniformEXT(txLayer3)], tcLayer3).rgba; final = mixTextures(mixTextures(mixTextures(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); } diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index 7c8299a08..de57e3b72 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -15,13 +15,8 @@ layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; #include "../common/commonUboSceneData.glsl" +#include "../common/commonAdtIndirectDescriptorSet.glsl" -layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { - vec4 uPos; - ivec4 uUseHeightMixFormula; - vec4 uHeightScale; - vec4 uHeightOffset; -}; mat3 blizzTranspose(mat4 value) { return mat3( @@ -36,9 +31,12 @@ layout(location = 1) out vec3 vPosition; layout(location = 2) out vec4 vColor; layout(location = 3) out vec3 vNormal; layout(location = 4) out vec3 vVertexLighting; +layout(location = 5) out flat int vMeshIndex; +layout(location = 6) out vec2 vAlphaCoords; + +const float TILESIZE = (1600.0 / 3.0); +const float UNITSIZE = TILESIZE / 16.0 / 8.0; -const float UNITSIZE_X = (1600.0 / 3.0) / 16.0 / 8.0; -const float UNITSIZE_Y = (1600.0 / 3.0) / 16.0 / 8.0; void main() { @@ -59,10 +57,11 @@ void main() { iY = iY + 0.5; iX = iX - 8.5; } + // vChunkCoords = vec2(iX, iY); // vec4 worldPoint = vec4( -// uPos.x - iY * UNITSIZE_Y, -// uPos.y - iX * UNITSIZE_X, +// uPos.x - iY * UNITSIZE, +// uPos.y - iX * UNITSIZE, // uPos.z + aHeight, // 1); @@ -70,9 +69,14 @@ void main() { vChunkCoords = vec2(iX, iY); + vAlphaCoords = (aPos.yx - floor(aPos.yx / TILESIZE)*TILESIZE) / TILESIZE; + vAlphaCoords.x = 1.0 - vAlphaCoords.x; + vAlphaCoords.y = 1.0 - vAlphaCoords.y; + vPosition = (scene.uLookAtMat * worldPoint).xyz; vColor = aColor; vVertexLighting = aVertexLighting.rgb; + vMeshIndex = gl_InstanceIndex; mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 9c0c797fa..c0932f21e 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -381,7 +381,7 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { aTemplate.start = stripOffsets[i] * 2; aTemplate.end = stripOffsets[i + 1] - stripOffsets[i]; - HGMesh hgMesh = sceneRenderer->createMesh(aTemplate, adtMaterial); + HGMesh hgMesh = sceneRenderer->createAdtMesh(aTemplate, adtMaterial); adtMeshes[i] = hgMesh; adtMaterials[i] = adtMaterial; @@ -454,7 +454,7 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } if (!noLayers) { - adtMaterialTemplate.textures[4] = alphaTextures[i]; + adtMaterialTemplate.textures[4] = alphaTexture; } else { adtMaterialTemplate.textures[4] = device->getBlackTexturePixel(); } @@ -474,25 +474,44 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } } +inline uint8_t &getChannel(std::vector &data, int x, int y, int width, int height, char channel) { + + assert(((width * y + x ) * 4 + channel) < data.size()); + return data[(width * y + x) * 4 + channel]; +}; + void AdtObject::loadAlphaTextures() { ZoneScoped; int chunkCount = m_adtFileTex->mcnkRead+1; int maxAlphaTexPerChunk = 4; int alphaTexSize = 64; - int texWidth = alphaTexSize; - int texHeight = alphaTexSize; + int texWidth = alphaTexSize * 16; + int texHeight = alphaTexSize * 16; int createdThisRun = 0; + alphaTexture = m_api->hDevice->createTexture(false, false); + std::vector bigTexture = std::vector(64*16 * 64*16 * 4, 0); for (int i = 0; i < chunkCount; i++) { - HGSamplableTexture alphaTexture = m_api->hDevice->createTexture(false, false); + auto const &mapTile = m_adtFile->mapTile[i]; + std::vector alphaTextureData; m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); - alphaTexture->getTexture()->loadData(texWidth, texHeight, &alphaTextureData[0], ITextureFormat::itRGBA); - alphaTextures.push_back(alphaTexture); + for (int x = 0; x < 64; x++) { + for (int y = 0; y < 64; y++) { + for (char channel = 0; channel < 4; channel++) { + getChannel(bigTexture, + mapTile.IndexX * 64 + x, mapTile.IndexY * 64 + y, + texWidth, texHeight, channel) = + getChannel(alphaTextureData, x, y, alphaTexSize, alphaTexSize, channel); + } + } + } } + alphaTexture->getTexture()->loadData(texWidth, texHeight, &bigTexture[0], ITextureFormat::itRGBA); + this->alphaTexturesLoaded += createdThisRun; } @@ -1112,7 +1131,7 @@ bool AdtObject::checkFrustumCulling(ADTObjRenderRes &adtFrustRes, return atLeastOneIsDrawn; } -AdtObject::AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, HWdtFile wdtFile) : alphaTextures(), adt_x(adt_x), adt_y(adt_y){ +AdtObject::AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, HWdtFile wdtFile) : adt_x(adt_x), adt_y(adt_y){ m_api = api; tileAabb = std::vector(256); waterTileAabb = std::vector(256); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index cc402a890..68c28375e 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -131,7 +131,7 @@ class AdtObject { HGVertexBufferBindings lodVertexBindings; private: - std::vector alphaTextures; + HGSamplableTexture alphaTexture; HBlpTexture lodDiffuseTexture = nullptr; HBlpTexture lodNormalTexture = nullptr; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 82e68f683..464f91219 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,14 +276,33 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,480}, }, { { @@ -317,14 +317,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +338,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,15 +376,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -391,17 +395,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {0,3, "diffuse"}, + {3,0, "s_AlphaTextures"}, + {4,0, "s_LayerHeightTextures"}, + {2,0, "s_LayerTextures"}, }, { { - {3,3,1}, - {0,0,0}, - {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,19 +418,21 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, + {2,4,16}, + {1,6,4096}, + {1,3,16384}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,2,2}, - {0,0,0}, + {1,6,6}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,22 +443,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, + {9,9,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +459,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +476,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,12 +496,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/skyConus.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, + {1,1,96}, }, { { @@ -529,11 +533,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,1,12}, }, { { @@ -565,15 +569,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -601,7 +605,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { ShaderStage::Vertex, { @@ -637,16 +641,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,480}, }, { { - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -659,11 +661,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -674,15 +677,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,2,168}, }, { { - {1,1,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -695,10 +698,11 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -710,17 +714,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {2,5,96}, + {0,0,480}, }, { { {0,0,1}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -731,13 +736,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,10, "uNormalTex"}, + {3,8, "uNoise"}, + {3,7, "uWhiteWater"}, + {3,6, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -746,16 +755,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, }, { { - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -783,16 +790,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, + {0,1,112}, + {0,0,480}, }, { { + {0,1,2}, {0,0,0}, - {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -819,16 +827,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {1,1,16}, }, { { - {0,0,1}, {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -855,15 +863,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -876,12 +883,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -893,15 +898,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/imguiShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,1,80}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,15 +934,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,32}, + {0,0,144}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,12 +955,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -966,16 +970,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,4,16}, + {1,2,48}, + {0,0,480}, + {1,1,64}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -987,14 +993,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, - {5,6,2}, {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,14 +1017,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { + {0,0,480}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1022,15 +1036,23 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, }, { - {1,5, "Texture"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1040,15 +1062,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,1,80}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1076,17 +1098,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1119,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,11 +1134,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,0,84}, }, { { @@ -1152,17 +1170,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, - {1,1,96}, }, { { {0,0,1}, - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,12 +1192,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1189,24 +1216,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,4,32}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1217,17 +1237,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {1,5, "texture0"}, }, { { {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1236,24 +1253,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, - {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {0,2,16}, }, { { - {0,0,1}, - {1,6,6}, - {7,7,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1279,14 +1289,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,4,16}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1299,11 +1310,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1314,18 +1327,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {1,4,96}, {0,0,480}, }, { { {0,0,1}, - {3,4,2}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,17 +1365,23 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,480}, + {1,1,64}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1374,13 +1392,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,14 +1411,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "visBuffer/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,480}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,17 +1447,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,96}, - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, - {4,4,1}, + {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1446,13 +1469,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1462,16 +1484,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,64}, + {0,1,112}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1479,6 +1499,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -1499,24 +1520,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, + {1,4,32}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {5,5,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1527,17 +1542,16 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, + {5,7,3}, {0,0,0}, - {6,10,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1546,24 +1560,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {2,4,16}, - {1,6,4096}, - {1,3,16384}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { {0,0,1}, - {1,6,6}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1574,14 +1581,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1590,17 +1596,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, - {0,0,480}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1612,21 +1616,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1636,18 +1631,90 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", + { + ShaderStage::Vertex, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/drawDepthShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,2,12}, + }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {0,3, "diffuse"}, + }, + { + { + {3,3,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,16}, }, { { {0,0,1}, - {1,2,2}, + {1,3,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1674,16 +1741,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, + {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1693,24 +1762,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1720,7 +1780,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -1739,15 +1799,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, }, { }, @@ -1768,21 +1819,10 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawBBShader", { + {"waterfallShader", { { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, } }, { @@ -1813,6 +1853,21 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2240,27 +2272,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 5, { + {"_2_5_values0", true, 0, 1, 4, 0}, + {"_2_5_values1", true, 16, 1, 4, 0}, + {"_2_5_values2", true, 32, 1, 4, 0}, + {"_2_5_values3", true, 48, 1, 4, 0}, + {"_2_5_values4", true, 64, 1, 4, 0}, + {"_2_5_baseColor", true, 80, 1, 4, 0}, } }, }}, @@ -2276,21 +2294,29 @@ const std::unordered_map { m_set(set), m_boundDescriptors(boundDescriptors), m_descriptorSetUpdater(descriptorSetUpdater) { //So that the resize of these vectors would not lead to pointer invalidation in updates vector bufferInfos.reserve(32); - imageInfos.reserve(2500); + imageInfos.reserve(4096); updates.reserve(64); } ~SetUpdateHelper(); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp index e5d957c6b..f41f2d516 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp @@ -5,7 +5,7 @@ #include "BindlessTextureHolder.h" BindlessTextureHolder::BindlessTextureHolder(uint32_t textureCount) : - m_textureAllocator(OffsetAllocator::Allocator(textureCount)){ + m_textureAllocator(OffsetAllocator::Allocator(textureCount, textureCount)){ } diff --git a/wowViewerLib/src/renderer/frame/FrameProfile.h b/wowViewerLib/src/renderer/frame/FrameProfile.h index 9724a6a71..d630d98ad 100644 --- a/wowViewerLib/src/renderer/frame/FrameProfile.h +++ b/wowViewerLib/src/renderer/frame/FrameProfile.h @@ -6,6 +6,7 @@ #define AWEBWOWVIEWERCPP_FRAMEPROFILE_H #ifdef LINK_TRACY +#include #include "Tracy.hpp" #ifdef LINK_VULKAN diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index f5d5f4480..63a013047 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -124,6 +124,7 @@ class IMapSceneBufferCreate { virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; + virtual HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; virtual HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 2d9d7d0bb..2a2d9830f 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -121,6 +121,14 @@ class IADTMaterial : public IMaterial { std::shared_ptr> m_materialPS = nullptr; }; +class IADTMaterialVis : public IADTMaterial { +public: + std::shared_ptr> m_instanceData = nullptr; + std::vector> m_bindlessText; + int instanceIndex = 0; +}; + + class IWaterMaterial : public IMaterial { public: mathfu::vec3 color; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 4b80eb218..336db9da4 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -804,6 +804,11 @@ HGSortableMesh MapSceneRenderForwardVLK::createSortableMesh(gMeshTemplate &meshT return mesh; } +HGMesh MapSceneRenderForwardVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + return mesh; +}; + HGM2Mesh MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index c2ab5cf5e..fd48ee6b3 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -95,6 +95,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; + HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index f8797bec2..adab7760c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -22,22 +22,40 @@ static const ShaderConfig forwardShaderConfig = { "forwardRendering", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} }} } }; const int m2TexturesBindlessCount = 4096; +const int adtTexturesBindlessCount = 4096; static const ShaderConfig m2VisShaderConfig = { "visBuffer", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} }}, {2, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; +static const ShaderConfig adtVisShaderConfig = { + "visBuffer", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }}, + {3, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }}, + {4, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }} + }}; + MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); @@ -87,6 +105,13 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS)); m2Buffers.meshWideBlocksBindless = m_device->createSSBOBuffer("M2 MeshWide Bindless", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); } + //Create adt Shader buffs + { + adtBuffers.adtMeshWideVSPSes = m_device->createSSBOBuffer("ADT MeshVSPS", 1024*1024, sizeof(ADT::meshWideBlockVSPS)); + adtBuffers.adtMeshWidePSes = m_device->createSSBOBuffer("ADT MeshPS", 1024*1024, sizeof(ADT::meshWideBlockPS)); + adtBuffers.adtInstanceDatas = m_device->createSSBOBuffer("ADT InstanceData", 1024*1024, sizeof(ADT::AdtInstanceData)); + } + uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); @@ -140,6 +165,39 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m2TextureDS = ds; }); m2TextureHolder = std::make_shared(m2TexturesBindlessCount); + + adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); + adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); + adtAlphaTextureHolder = std::make_shared(adtTexturesBindlessCount); + + //Create global ADT descriptor for bindless textures + { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtVisShaderConfig) + .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, adtBuffers.adtMeshWideVSPSes) + .ssbo(2, adtBuffers.adtMeshWidePSes) + .ssbo(3, adtBuffers.adtInstanceDatas); + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + adtLayerTextureDS = ds; + }) + .createDescriptorSet(3, [&](std::shared_ptr &ds) { + adtAlphaTextureDS = ds; + }) + .createDescriptorSet(4, [&](std::shared_ptr &ds) { + adtHeightLayerTextureDS = ds; + }).toMaterial(); + } } // ------------------ @@ -308,34 +366,58 @@ HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) std::shared_ptr MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; - auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto fragmentData = std::make_shared>(uboBuffer); + auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); + auto fragmentData = std::make_shared>(adtBuffers.adtMeshWidePSes); + auto instanceData = std::make_shared>(adtBuffers.adtInstanceDatas); - auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) - .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) - .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo(1, *vertexFragmentData) - .ubo(2, *fragmentData); - }) - .createDescriptorSet(2, [&adtMaterialTemplate](std::shared_ptr &ds) { - ds->beginUpdate() - .texture(5, adtMaterialTemplate.textures[0]) - .texture(6, adtMaterialTemplate.textures[1]) - .texture(7, adtMaterialTemplate.textures[2]) - .texture(8, adtMaterialTemplate.textures[3]) - .texture(9, adtMaterialTemplate.textures[4]) - .texture(10, adtMaterialTemplate.textures[5]) - .texture(11, adtMaterialTemplate.textures[6]) - .texture(12, adtMaterialTemplate.textures[7]) - .texture(13, adtMaterialTemplate.textures[8]); - }) - .toMaterial([&vertexFragmentData, &fragmentData](IADTMaterial *instance) -> void { + auto material = MaterialBuilderVLK::fromMaterial(m_device, g_adtMaterial) + .toMaterial([&fragmentData, &vertexFragmentData, &instanceData](IADTMaterialVis *instance) -> void { instance->m_materialVSPS = vertexFragmentData; instance->m_materialPS = fragmentData; + instance->m_instanceData = instanceData; }); + { + auto &adtInstanceData = instanceData->getObject(); + adtInstanceData.meshIndexVSPS = vertexFragmentData->getSubBuffer()->getIndex(); + adtInstanceData.meshIndexPS = fragmentData->getSubBuffer()->getIndex(); + { + auto dsUpdate = adtLayerTextureDS->beginUpdate(); + + for (int i = 0; i < 4; i++) { + auto bindlessText = adtLayerTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.LayerIndexes[i] = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto dsUpdate = adtAlphaTextureDS->beginUpdate(); + + for (int i = 4; i <= 4; i++) { + auto bindlessText = adtAlphaTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.AlphaTextureInd = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto dsUpdate = adtHeightLayerTextureDS->beginUpdate(); + + for (int i = 5; i < 9; i++) { + auto bindlessText = adtHeightLayerTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.LayerHeight[i-5] = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + instanceData->save(); + } + + material->instanceIndex = instanceData->getSubBuffer()->getIndex(); + return material; } @@ -771,6 +853,10 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocks); uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocksBindless); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWidePSes); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWideVSPSes); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtInstanceDatas); + uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); @@ -895,7 +981,12 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &mes auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } - +HGMesh +MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + return mesh; +} HGM2Mesh MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 0c2fc790a..29d347467 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -97,6 +97,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; + HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; @@ -157,6 +158,12 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK meshWideBlocksBindless; } m2Buffers; + struct { + HGBufferVLK adtMeshWideVSPSes; + HGBufferVLK adtMeshWidePSes; + HGBufferVLK adtInstanceDatas; + } adtBuffers; + HGBufferVLK uboBuffer; HGBufferVLK m_vboQuad; @@ -172,6 +179,16 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr m2BufferOneDS = nullptr; + std::shared_ptr g_adtMaterial = nullptr; + std::shared_ptr adtLayerTextureDS = nullptr; + std::shared_ptr adtLayerTextureHolder = nullptr; + std::shared_ptr adtHeightLayerTextureDS = nullptr; + std::shared_ptr adtHeightLayerTextureHolder = nullptr; + std::shared_ptr adtAlphaTextureDS = nullptr; + std::shared_ptr adtAlphaTextureHolder = nullptr; + + + std::shared_ptr m_renderPass; std::shared_ptr m_lastCreatedPlan = nullptr; From 755892936d75e744ea2703e800f0173d7ce4f945 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 11 Oct 2023 21:13:05 +0300 Subject: [PATCH 133/212] - do not do full update on bindless descriptor --- wowViewerLib/CMakeLists.txt | 2 +- .../src/engine/objects/adt/adtObject.cpp | 14 +- .../src/engine/persistance/adtFile.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 172 ++++++++++++++++-- .../src/gapi/interface/meshes/IMesh.h | 4 +- .../descriptorSets/GDescriptorPoolVLK.cpp | 2 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 66 +++++-- .../vulkan/descriptorSets/GDescriptorSet.h | 27 ++- .../src/gapi/vulkan/meshes/GMeshVLK.h | 1 - .../src/gapi/vulkan/shaders/ShaderConfig.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 7 +- 11 files changed, 244 insertions(+), 55 deletions(-) diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index cce982689..fa115b78e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 0) +set(LINK_TRACY 1) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index c0932f21e..45ea7dabd 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -483,19 +483,21 @@ inline uint8_t &getChannel(std::vector &data, int x, int y, int width, void AdtObject::loadAlphaTextures() { ZoneScoped; int chunkCount = m_adtFileTex->mcnkRead+1; - int maxAlphaTexPerChunk = 4; - int alphaTexSize = 64; + constexpr int maxAlphaTexPerChunk = 4; + constexpr int alphaTexSize = 64; - int texWidth = alphaTexSize * 16; - int texHeight = alphaTexSize * 16; + constexpr int texWidth = alphaTexSize * 16; + constexpr int texHeight = alphaTexSize * 16; int createdThisRun = 0; alphaTexture = m_api->hDevice->createTexture(false, false); - std::vector bigTexture = std::vector(64*16 * 64*16 * 4, 0); + std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); + std::vector alphaTextureData = std::vector(alphaTexSize * alphaTexSize * 4); for (int i = 0; i < chunkCount; i++) { auto const &mapTile = m_adtFile->mapTile[i]; + memset(alphaTextureData.data(), 0, alphaTextureData.size()); +// std::fill(alphaTextureData.begin(), alphaTextureData.end(), 0); - std::vector alphaTextureData; m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 3255e1279..5a37c9511 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -491,7 +491,7 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, std::vector &layers = mcnkObj.mcly; - currentLayer = std::vector((64*4) * 64, 0); + assert(currentLayer.size() >= (64*4) * 64); if (layers == nullptr || alphaArray == nullptr) return; for (int j = 0; j shaderMetaInfo = { }, { {1,9,0}, + {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, }, { }, @@ -427,6 +432,9 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { @@ -699,10 +707,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -720,11 +729,17 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, + {1,6,6}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -759,10 +774,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -867,10 +883,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1044,6 +1061,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1103,11 +1121,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1155,10 +1174,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1376,6 +1397,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, + {1,3,16384}, }, { { @@ -1430,6 +1452,9 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,1,0}, + {1,2,0}, + {1,3,0}, }, { }, @@ -1710,12 +1735,17 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {1,3,3}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1820,6 +1850,31 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { + { + 5, { + {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + } + }, { 1, { {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, @@ -1865,7 +1920,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 6, { + {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, + } + }, + { + 4, { + {"_1_4_colors[0]", true, 0, 1, 4, 256}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, + } + }, + { + 2, { + {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, + {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, + {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, + {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, + {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, + {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, + {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, + {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, + {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, + {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, + {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, + {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, + {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, + {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, + {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, + {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, + } + }, + { + 1, { + {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + } + }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2273,12 +2403,7 @@ const std::unordered_map const HGVertexBufferBindings& { return m_bindings; } -// auto texture() const -> const HGVertexBufferBindings& { return m_bindings; } + int vertexStart = -1; + int instanceIndex = -1; protected: HGVertexBufferBindings m_bindings; int m_start; int m_end; + public: virtual ~IMesh() = default; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp index f8f9a84d2..15bc6a832 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp @@ -31,7 +31,7 @@ GDescriptorPoolVLK::GDescriptorPoolVLK(IDeviceVulkan &device, bool isBindless) : poolInfo.pNext = nullptr; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT ; if (isBindless) - poolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + poolInfo.flags |= (VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT) ; auto result = vkCreateDescriptorPool(m_device.getVkDevice(), &poolInfo, nullptr, &m_descriptorPool); if (result != VK_SUCCESS) { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index c81703e3a..1ad416130 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -19,6 +19,10 @@ GDescriptorSet::GDescriptorSet(const std::shared_ptr &device, con boundDescriptors[i].resize(arraySizes[i]); }; + if (m_hDescriptorSetLayout->getIsBindless()) { + m_bindlessAccum = std::make_unique(); + } + assert(m_descriptorSet != nullptr); } GDescriptorSet::~GDescriptorSet() { @@ -248,9 +252,9 @@ GDescriptorSet::SetUpdateHelper::ssbo(int bindIndex, const std::shared_ptrgetIsBindless()*/ true) { + if (!m_set.m_hDescriptorSetLayout->getIsBindless()) { //Fill the rest of Descriptor with already bound values //This is needed, cause In this implementation of descriptor set, the descriptor set is getting free'd on update //and new one is created @@ -272,16 +277,7 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { for (int bindIndex = 0; bindIndex < m_boundDescriptors[bindPoint].size(); bindIndex++) { if (m_boundDescriptors[bindPoint][bindIndex] == nullptr) continue; - if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::UBO) { - ubo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); - } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == - DescriptorRecord::DescriptorRecordType::UBODynamic) { - ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); - } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::SSBO) { - ssbo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); - } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::Texture) { - texture(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->texture, bindIndex); - } + reassignBinding(bindPoint, bindIndex); } } @@ -299,6 +295,11 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { std::cerr << "required descriptors " << notSetBits << " were not set during update" << std::endl; throw std::runtime_error("required descriptors were not set"); } + } else { + auto updates = m_set.m_bindlessAccum->getUpdates(); + for (auto const &update: updates.get()){ + reassignBinding(update.bindIndex, update.arrayIndex); + } } std::sort(dynamicBufferIndexes.begin(), dynamicBufferIndexes.end()); @@ -306,9 +307,9 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { m_set.writeToDescriptorSets(updates, imageInfos, dynamicBufferIndexes); +#if (!defined(NDEBUG)) { int bufferIndex = 0; - int imageIndex = 0; for (int i = 0; i < updates.size(); i++) { if (updates[i].pBufferInfo != nullptr) { @@ -318,21 +319,46 @@ GDescriptorSet::SetUpdateHelper::~SetUpdateHelper() { } } } +#endif +} + +void GDescriptorSet::SetUpdateHelper::reassignBinding(int bindPoint, int bindIndex) { + if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::UBO) { + ubo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == + DescriptorRecord::DescriptorRecordType::UBODynamic) { + ubo_dynamic(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::SSBO) { + ssbo(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->buffer); + } else if (m_boundDescriptors[bindPoint][bindIndex]->descType == DescriptorRecord::DescriptorRecordType::Texture) { + texture(bindPoint, m_boundDescriptors[bindPoint][bindIndex]->texture, bindIndex); + } } void GDescriptorSet::SetUpdateHelper::cancelUpdate() { updateCancelled = true; } -std::function GDescriptorSet::SetUpdateHelper::createCallback() { +std::function GDescriptorSet::SetUpdateHelper::createCallback(int bindPoint, int arrayIndex) { auto ds_weak = m_set.weak_from_this(); auto l_descriptorSetUpdater = m_descriptorSetUpdater; - const std::function callback = ([ds_weak, l_descriptorSetUpdater]() -> void { - if (auto ds = ds_weak.lock()) { - l_descriptorSetUpdater->addToUpdate(ds); - } - }); + if (!m_set.m_hDescriptorSetLayout->getIsBindless()) { + const std::function callback = ([ds_weak, l_descriptorSetUpdater]() -> void { + if (auto ds = ds_weak.lock()) { + l_descriptorSetUpdater->addToUpdate(ds); + } + }); + + return callback; + } else { + const std::function callback = ([ds_weak, l_descriptorSetUpdater, bindPoint, arrayIndex]() -> void { + if (auto ds = ds_weak.lock()) { + ds->m_bindlessAccum->addUpdate(bindPoint, arrayIndex); + l_descriptorSetUpdater->addToUpdate(ds); + } + }); - return callback; + return callback; + } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index b989b36b3..1edc322aa 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -17,7 +17,26 @@ class GDescriptorPoolVLK; #include "GDescriptorSetLayout.h" #include "DescriptorRecord.h" #include "../bindable/DSBindable.h" +#include "../utils/MutexLockedVector.h" +class BindlessUpdateAccum { +public: + struct BindlesUpdate { + int bindIndex; + int arrayIndex; + }; + void addUpdate(int bindIndex, int arrayIndex) { + std::unique_lock m_lock(m_mutex); + m_bindlessUpdates.emplace_back() = {bindIndex, arrayIndex}; + }; + MutexLockedVector getUpdates() { + return MutexLockedVector(m_bindlessUpdates, m_mutex, true); + } + +private: + std::mutex m_mutex; + std::vector m_bindlessUpdates; +}; class GDescriptorSet : public std::enable_shared_from_this { public: @@ -92,7 +111,7 @@ class GDescriptorSet : public std::enable_shared_from_this { } } if (createDescRecord) { - std::function callback = createCallback(); + std::function callback = createCallback(bindPoint, index); m_boundDescriptors[bindPoint][index] = std::make_unique(descType, object, callback); } } @@ -114,7 +133,9 @@ class GDescriptorSet : public std::enable_shared_from_this { std::vector updates; std::bitset m_updateBindPoints = 0; - std::function createCallback(); + std::function createCallback(int bindPoint, int arrayIndex); + + void reassignBinding(int bindPoint, int bindIndex); }; SetUpdateHelper beginUpdate(); @@ -130,6 +151,8 @@ class GDescriptorSet : public std::enable_shared_from_this { bool m_firstUpdate = true; + std::unique_ptr m_bindlessAccum = nullptr; + std::array>, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> boundDescriptors; // Scrapped idea. The VkCopyDescriptorSet can cause copy GPU -> CPU -> GPU. So it's scrapped idea diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 1fa127b3e..981451d56 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -26,7 +26,6 @@ class GMeshVLK : public IM2Mesh { return material()->getBlendMode(); } - int instanceIndex = -1; public: auto material() const -> const HMaterialVLK& { return m_material; } auto scissorOffset() const -> const std::array& { return m_scissorOffset; } diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 4c245e961..6e7b2531c 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -13,7 +13,7 @@ struct DescTypeConfig { VkDescriptorType type = VK_DESCRIPTOR_TYPE_MAX_ENUM; bool isBindless = false; int descriptorCount = 1; - uint32_t stageMask; + uint32_t stageMask = 0; bool operator==(const DescTypeConfig &other) const { return diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 35f872ddc..87b756b5e 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -85,15 +85,12 @@ void GTextureVLK::loadData(int width, int height, void *data, ITextureFormat tex std::vector unifiedBuffer((uint8_t *)data, (uint8_t *)data + (width*height*4)); - HMipmapsVector mipmapsVector = std::make_shared>(); - mipmapStruct_t mipmap; + HMipmapsVector mipmapsVector = std::make_shared>(1); + mipmapStruct_t &mipmap = mipmapsVector->at(0); mipmap.height = height; mipmap.width = width; mipmap.texture = unifiedBuffer; - mipmapsVector->push_back(mipmap); - - createTexture(mipmapsVector, VK_FORMAT_R8G8B8A8_UNORM, unifiedBuffer); } From 2815dd2333f2cab867197881fff6380bc6ca5d93 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 14 Oct 2023 01:45:38 +0300 Subject: [PATCH 134/212] - bindless for WMO - TODO: restore water --- .../OffsetAllocator/offsetAllocator.hpp | 4 + wowViewerLib/CMakeLists.txt | 2 +- .../commonWMOIndirectDescriptorSet.glsl | 43 +++ .../glsl/forwardRendering/wmoShader.frag | 2 +- .../shaders/glsl/visBuffer/wmoShader.frag | 100 ++++++ .../shaders/glsl/visBuffer/wmoShader.vert | 67 ++++ wowViewerLib/src/engine/geometry/m2Geom.cpp | 1 + .../src/engine/geometry/wmoGroupGeom.cpp | 5 +- .../src/engine/geometry/wmoGroupGeom.h | 2 +- .../src/engine/objects/adt/adtObject.cpp | 42 +-- .../src/engine/objects/m2/m2Object.cpp | 17 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 19 +- .../src/engine/objects/wmo/wmoGroupObject.h | 2 + .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../src/engine/objects/wmo/wmoObject.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 286 ++++++++---------- .../src/gapi/UniformBufferStructures.h | 24 ++ .../renderer/mapScene/IMapSceneBufferCreate.h | 4 +- .../mapScene/materials/IMaterialStructs.h | 7 + .../vulkan/MapSceneRenderForwardVLK.cpp | 17 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 195 +++++++++--- .../vulkan/MapSceneRenderVisBufferVLK.h | 20 +- 23 files changed, 609 insertions(+), 258 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl create mode 100644 wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp index eea8f63d1..1d4c87605 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -2,6 +2,8 @@ // MIT License (see file: LICENSE) //#define USE_16_BIT_OFFSETS +#ifndef OFFSET_ALLOCATOR_HPP +#define OFFSET_ALLOCATOR_HPP #include #include @@ -110,3 +112,5 @@ namespace OffsetAllocator uint32 m_lastNode; }; } + +#endif //OFFSET_ALLOCATOR_HPP \ No newline at end of file diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index fa115b78e..cce982689 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 1) +set(LINK_TRACY 0) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) diff --git a/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl new file mode 100644 index 000000000..0a0c48f08 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl @@ -0,0 +1,43 @@ +#ifndef COMMON_WMO_INDIRECT_DS +#define COMMON_WMO_INDIRECT_DS + +layout(std140, set=1, binding=1) buffer modelWideBlockVS { + mat4 uPlacementMats[]; +}; + +layout(std140, set=1, binding=2) buffer meshWideBlockVS { + ivec4 VertexShader_UseLitColors[]; +}; + +struct WmoMeshWide { + ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; + vec4 FogColor_AlphaTest; +}; + +layout(std140, set=1, binding=3) buffer meshWideBlockPS { + WmoMeshWide wmoMeshWides[]; +}; + +struct WmoMeshWideBindless { + ivec4 placementMat_meshWideIndex_blockVSIndex_texture9; + ivec4 text1_text2_text3_text4; + ivec4 text5_text6_text7_text8; +}; + +layout(std140, set=1, binding=4) buffer meshWideBlockBindlessPS { + WmoMeshWideBindless wmoMeshWideBindlesses[]; +}; + +layout(std140, set=1, binding=5) buffer wmoLocalAmbient { + vec4 s_wmoAmbient[]; +}; + +struct WMOPerMeshData { + ivec4 meshWideBindlessIndex_wmoAmbientIndex; +}; + +layout(std140, set=1, binding=6) buffer _wmoPerMeshData { + WMOPerMeshData perMeshDatas[]; +}; + +#endif //COMMON_WMO_INDIRECT_DS \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index 3c0db6be6..d8985a738 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -27,7 +27,7 @@ layout(location=9) in vec4 vWmoAmbient; -layout(std140, set=1, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=3) uniform meshWideBlockPS { ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; vec4 FogColor_AlphaTest; }; diff --git a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag new file mode 100644 index 000000000..22ca68c6b --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag @@ -0,0 +1,100 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require + +#define FRAGMENT_SHADER 1 + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonWMOMaterial.glsl" +#include "../common/commonUboSceneData.glsl" + + + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec2 vTexCoord3; +layout(location=3) in vec2 vTexCoord4; +layout(location=4) in vec4 vColor; +layout(location=5) in vec4 vColor2; +layout(location=6) in vec4 vColorSecond; +layout(location=7) in vec4 vPosition; +layout(location=8) in vec3 vNormal; +layout(location=9) in flat int vMeshIndex; + + +#include "../common/commonWMOIndirectDescriptorSet.glsl" + + +layout(set=2, binding=0) uniform sampler2D s_Textures[]; + +layout (location = 0) out vec4 outputColor; + +void main() { + WMOPerMeshData perMeshData = perMeshDatas[nonuniformEXT(vMeshIndex)]; + WmoMeshWideBindless meshWideBindless = wmoMeshWideBindlesses[nonuniformEXT(perMeshData.meshWideBindlessIndex_wmoAmbientIndex.x)]; + WmoMeshWide wmoMeshWide = wmoMeshWides[nonuniformEXT(meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.y)]; + + int uPixelShader = wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.z; + + vec3 matDiffuse = vec3(0.0); + vec3 spec = vec3(0.0); + vec3 emissive = vec3(0.0); + float finalOpacity = 0.0; + bool doDiscard; + + int text1 = meshWideBindless.text1_text2_text3_text4.x; + int text2 = meshWideBindless.text1_text2_text3_text4.y; + int text3 = meshWideBindless.text1_text2_text3_text4.z; + int text4 = meshWideBindless.text1_text2_text3_text4.w; + int text5 = meshWideBindless.text5_text6_text7_text8.x; + int text6 = meshWideBindless.text5_text6_text7_text8.y; + int text7 = meshWideBindless.text5_text6_text7_text8.z; + int text8 = meshWideBindless.text5_text6_text7_text8.w; + int text9 = meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.w; + + caclWMOFragMat(uPixelShader, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.y == 1, + s_Textures[nonuniformEXT(text1)], s_Textures[nonuniformEXT(text2)], s_Textures[nonuniformEXT(text3)], s_Textures[nonuniformEXT(text4)], + s_Textures[text5], s_Textures[text6], s_Textures[text7], s_Textures[text8], + s_Textures[text9], + vPosition.xyz, vNormal, vTexCoord, vTexCoord2, vTexCoord3, vTexCoord4, + vColor2, + vColorSecond, + matDiffuse, spec, emissive, finalOpacity, + doDiscard + ); + + if (doDiscard) + discard; + + InteriorLightParam intLight; + intLight.uInteriorAmbientColorAndApplyInteriorLight = s_wmoAmbient[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.y]; + intLight.uInteriorDirectColorAndApplyExteriorLight = vec4(0, 0, 0, 1.0f); + + vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, + vColor.w, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vColor.rgb, + spec, /* specular */ + emissive + ), + finalOpacity + ); + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); + finalColor.a = 1.0; + + outputColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert new file mode 100644 index 000000000..d36869bf3 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert @@ -0,0 +1,67 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonFunctions.glsl" +#include "../common/commonWMOMaterial.glsl" + +/* vertex shader code */ +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoord; +layout (location = 3) in vec2 aTexCoord2; +layout (location = 4) in vec2 aTexCoord3; +layout (location = 5) in vec2 aTexCoord4; +layout (location = 6) in vec4 aColor; +layout (location = 7) in vec4 aColor2; +layout (location = 8) in vec4 aColorSecond; + +#include "../common/commonUboSceneData.glsl" +#include "../common/commonWMOIndirectDescriptorSet.glsl" + +layout(location=0) out vec2 vTexCoord; +layout(location=1) out vec2 vTexCoord2; +layout(location=2) out vec2 vTexCoord3; +layout(location=3) out vec2 vTexCoord4; +layout(location=4) out vec4 vColor; +layout(location=5) out vec4 vColor2; +layout(location=6) out vec4 vColorSecond; +layout(location=7) out vec4 vPosition; +layout(location=8) out vec3 vNormal; +layout(location=9) out flat int vMeshIndex; + + +void main() { + WMOPerMeshData perMeshData = perMeshDatas[gl_InstanceIndex]; + WmoMeshWideBindless meshWideBindless = wmoMeshWideBindlesses[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.x]; + int placementMatInd = meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.x; + int blockVSIndex = meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.y; + + mat4 placementMat = uPlacementMats[placementMatInd]; + vec4 worldPoint = placementMat * vec4(aPosition, 1); + + vec4 cameraPoint = scene.uLookAtMat * worldPoint; + + mat4 viewModelMat = scene.uLookAtMat * placementMat; + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + + gl_Position = scene.uPMatrix * cameraPoint; + vPosition = vec4(cameraPoint.xyz, 0); + vNormal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); + + vColor = aColor.bgra; + vColor2 = aColor2; + vColorSecond = aColorSecond; + vTexCoord4 = aTexCoord4; + + int uVertexShader = VertexShader_UseLitColors[blockVSIndex].x; + + calcWMOVertMat(uVertexShader, vPosition.xyz, vNormal, aTexCoord, aTexCoord2, aTexCoord3, vTexCoord, vTexCoord2, vTexCoord3); + + vMeshIndex = gl_InstanceIndex; +} diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 97bee4249..6a2b41833 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -399,6 +399,7 @@ M2Geom::createDynamicVao(const HMapSceneBufferCreate &sceneRenderer, } HGVertexBufferBindings M2Geom::getVAO(const HMapSceneBufferCreate &sceneRenderer, SkinGeom *skinGeom) { + ZoneScoped; HGVertexBufferBindings bufferBindings = nullptr; if (vaoMap.find(skinGeom) != vaoMap.end()) { bufferBindings = vaoMap.at(skinGeom); diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 2da75e19c..59ce1c1f5 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -380,7 +380,8 @@ HGIndexBuffer WmoGroupGeom::getIBO(const HMapSceneBufferCreate &sceneRenderer) { return indexVBO; } -HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, mathfu::vec4 localAmbient) { +HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, + const std::shared_ptr> &ambientBuffer) { if (vertexBufferBindings == nullptr) { //Do postLoading stuff here if (mohd) { @@ -389,7 +390,7 @@ HGVertexBufferBindings WmoGroupGeom::getVertexBindings(const HMapSceneBufferCrea this->m_attenuateFunc(*this); } } - vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer), localAmbient); + vertexBufferBindings = sceneRenderer->createWmoVAO(getVBO(sceneRenderer), getIBO(sceneRenderer), ambientBuffer); } return vertexBufferBindings; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index 0bbe42f3c..6d61d438f 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -41,7 +41,7 @@ class WmoGroupGeom : public PersistentFile { void setAttenuateFunction(std::function attenuateFunc) {this->m_attenuateFunc = attenuateFunc; }; bool hasWater() const {return m_mliq != nullptr; }; - HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, mathfu::vec4 localAmbient); + HGVertexBufferBindings getVertexBindings(const HMapSceneBufferCreate &sceneRenderer, SMOHeader *mohd, const std::shared_ptr> &ambientBuffer); HGVertexBufferBindings getWaterVertexBindings(const HMapSceneBufferCreate &sceneRenderer, LiquidTypes liquid_type, CAaBox &waterAaBB); int getFileDataId() const {return m_fileDataId;} diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 45ea7dabd..63ddc969d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -492,26 +492,32 @@ void AdtObject::loadAlphaTextures() { int createdThisRun = 0; alphaTexture = m_api->hDevice->createTexture(false, false); std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); - std::vector alphaTextureData = std::vector(alphaTexSize * alphaTexSize * 4); - for (int i = 0; i < chunkCount; i++) { - auto const &mapTile = m_adtFile->mapTile[i]; - memset(alphaTextureData.data(), 0, alphaTextureData.size()); -// std::fill(alphaTextureData.begin(), alphaTextureData.end(), 0); - - m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); - - - for (int x = 0; x < 64; x++) { - for (int y = 0; y < 64; y++) { - for (char channel = 0; channel < 4; channel++) { - getChannel(bigTexture, - mapTile.IndexX * 64 + x, mapTile.IndexY * 64 + y, - texWidth, texHeight, channel) = - getChannel(alphaTextureData, x, y, alphaTexSize, alphaTexSize, channel); + if (chunkCount > 0) { + oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); + arena.execute([&] { + oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { + std::vector alphaTextureData = std::vector(alphaTexSize * alphaTexSize * 4); + for (size_t i = r.begin(); i != r.end(); ++i) { + auto const &mapTile = m_adtFile->mapTile[i]; + memset(alphaTextureData.data(), 0, alphaTextureData.size()); + + m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); + + for (int x = 0; x < 64; x++) { + for (int y = 0; y < 64; y++) { + for (char channel = 0; channel < 4; channel++) { + getChannel(bigTexture, + mapTile.IndexX * 64 + x, mapTile.IndexY * 64 + y, + texWidth, texHeight, channel) = + getChannel(alphaTextureData, x, y, alphaTexSize, alphaTexSize, channel); + } + } + } } - } - } + }, tbb::auto_partitioner()); + }); } + alphaTexture->getTexture()->loadData(texWidth, texHeight, &bigTexture[0], ITextureFormat::itRGBA); this->alphaTexturesLoaded += createdThisRun; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 81166c3df..72adea062 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1383,6 +1383,8 @@ float wfv_convert(float value, int16_t random) { } HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRenderer, const HGVertexBufferBindings &finalBufferBindings) { +// return nullptr; + gMeshTemplate meshTemplate(bufferBindings); auto skinData = m_skinGeom->getSkinData(); @@ -1469,6 +1471,8 @@ HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRendere void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; + /* 1. Free previous subMeshArray */ this->m_meshArray.clear(); this->m_meshForcedTranspArray.clear(); @@ -1570,7 +1574,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } } else { - m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); +// m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); } @@ -1691,19 +1695,22 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorm_animationManager = std::make_unique(m_api, m_boneMasterData, m_m2Geom->exp2 != nullptr); } void M2Object::initBoneAnimMatrices() { + ZoneScoped; auto &bones = *m_boneMasterData->getSkelData()->m_m2CompBones; this->bonesMatrices = std::vector(bones.size, mathfu::mat4::Identity());; } void M2Object::initTextAnimMatrices() { + ZoneScoped; textAnimMatrices = std::vector(m_m2Geom->getM2Data()->texture_transforms.size, mathfu::mat4::Identity());; } void M2Object::initSubmeshColors() { + ZoneScoped; subMeshColors = std::vector(m_m2Geom->getM2Data()->colors.size); } @@ -1712,9 +1719,12 @@ void M2Object::initTransparencies() { } void M2Object::initLights() { + ZoneScoped; lights = std::vector(m_m2Geom->getM2Data()->lights.size); } void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; + particleEmitters.clear(); particleEmitters.reserve(m_m2Geom->getM2Data()->particle_emitters.size); for (int i = 0; i < m_m2Geom->getM2Data()->particle_emitters.size; i++) { @@ -1738,6 +1748,8 @@ void M2Object::initParticleEmitters(const HMapSceneBufferCreate &sceneRenderer) } void M2Object::initRibbonEmitters(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; + ribbonEmitters = std::vector>(); // ribbonEmitters.reserve(m_m2Geom->getM2Data()->ribbon_emitters.size); auto m2Data = m_m2Geom->getM2Data(); @@ -1971,6 +1983,7 @@ HBlpTexture M2Object::getHardCodedTexture(int textureInd) { } void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) { + ZoneScoped; HGDevice device = m_api->hDevice; //2. Create buffer binding and fill it diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 7a493301f..1e1139993 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -130,11 +130,17 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; - HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer, this->m_wmoApi->getWmoHeader(), - mathfu::vec4( - this->getAmbientColor().xyz(), - ((this->m_geom->mogp->flags.INTERIOR > 0) && (!this->m_geom->mogp->flags.EXTERIOR_LIT)) ? 1.0f : 0.0f - )); + m_ambientChunk = sceneRenderer->createWMOGroupAmbientChunk(); + { + auto &localAmbient = m_ambientChunk->getObject(); + localAmbient = mathfu::vec4( + this->getAmbientColor().xyz(), + ((this->m_geom->mogp->flags.INTERIOR > 0) && (!this->m_geom->mogp->flags.EXTERIOR_LIT)) ? 1.0f : 0.0f + ); + m_ambientChunk->save(); + } + + HGVertexBufferBindings binding = m_geom->getVertexBindings(sceneRenderer, this->m_wmoApi->getWmoHeader(), m_ambientChunk); MOGP *mogp = m_geom->mogp; @@ -160,7 +166,7 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { meshTemplate.end = renderBatch.num_indices; //Make mesh - HGMesh hmesh = sceneRenderer->createMesh(meshTemplate, materialInstance); + HGMesh hmesh = sceneRenderer->createWMOMesh(meshTemplate, materialInstance, m_ambientChunk); this->m_meshArray.push_back(hmesh); } } @@ -225,6 +231,7 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere //Get Liquid with new method setLiquidType(); + return; HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer, liquid_type, m_waterAaBB); if (binding == nullptr) return; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 49ec04388..41b304346 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -81,6 +81,8 @@ class WmoGroupObject { mathfu::mat4 *m_modelMatrix = nullptr; int m_groupNumber; + + std::shared_ptr> m_ambientChunk; std::vector m_meshArray = {}; std::vector m_sortableMeshArray = {}; std::vector> m_liquidInstances = {}; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index ab5941135..6303dbacd 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -339,7 +339,7 @@ void WmoObject::update() { //Update Materials for (int matIndex = 0; matIndex < m_materialCache.size(); matIndex++) { - auto materialInstance = m_materialCache[matIndex].lock(); + auto materialInstance = m_materialCache[matIndex]; if (materialInstance == nullptr) continue; const SMOMaterial &material = getMaterials()[matIndex]; @@ -1290,7 +1290,7 @@ PointerChecker &WmoObject::getMaterials() { std::shared_ptr WmoObject::getMaterialInstance(int materialIndex, const HMapSceneBufferCreate &sceneRenderer) { assert(materialIndex < m_materialCache.size()); - auto materialInstance = m_materialCache[materialIndex].lock(); + auto materialInstance = m_materialCache[materialIndex]; if (materialInstance != nullptr) return materialInstance; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index b03e4c465..3d8aecf6e 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -81,7 +81,7 @@ class WmoObject : public IWmoApi { std::unordered_map specularTextures; std::shared_ptr> m_modelWideChunk; - std::vector> m_materialCache; + std::vector> m_materialCache; HGMesh transformedAntiPortals; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a78d123c4..eedc15984 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -318,14 +318,9 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, - {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, }, { }, @@ -432,9 +427,6 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { @@ -685,6 +677,46 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/wmoShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,480}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, @@ -707,11 +739,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -729,17 +760,11 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, + {0,0,0}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -774,11 +799,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -883,11 +907,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1034,6 +1057,47 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/wmoShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,0,480}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + }, + { + {2,0, "s_Textures"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, @@ -1061,7 +1125,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1121,12 +1184,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1174,12 +1236,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1195,13 +1255,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,32}, + {1,3,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1397,7 +1457,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, - {1,3,16384}, }, { { @@ -1452,9 +1511,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,1,0}, - {1,2,0}, - {1,3,0}, }, { }, @@ -1735,17 +1791,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1850,31 +1901,6 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { - { - 5, { - {"_1_5_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, { 1, { {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, @@ -1920,7 +1946,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 2, { - {"_1_2_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_2_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_2_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_1_2_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_1_2_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_1_2_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_1_2_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_1_2_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_1_2_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_1_2_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_1_2_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_1_2_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_1_2_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_1_2_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_1_2_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_1_2_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, - } - }, { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2403,7 +2362,12 @@ const std::unordered_map> &ambientBuffer) = 0; virtual HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGVertexBufferBindings createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; @@ -108,6 +108,7 @@ class IMapSceneBufferCreate { virtual std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) = 0; virtual std::shared_ptr> createWMOWideChunk() = 0; + virtual std::shared_ptr> createWMOGroupAmbientChunk() = 0; virtual std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, @@ -126,6 +127,7 @@ class IMapSceneBufferCreate { virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; + virtual HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) = 0; virtual HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 2a2d9830f..7c097ad3f 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -114,6 +114,13 @@ class IWMOMaterial : public IMaterial { std::shared_ptr> m_materialVS= nullptr; std::shared_ptr> m_materialPS = nullptr; }; +class IWMOMaterialVis : public IWMOMaterial { +public: + std::shared_ptr> m_meshBindless = nullptr; + std::shared_ptr> m_perMeshData = nullptr; + std::vector> m_bindlessText; + int meshWideBindlessIndex = 0; +}; class IADTMaterial : public IMaterial { public: diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 336db9da4..f4de4b55c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -84,7 +84,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); - m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); + m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, nullptr); m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); @@ -120,20 +120,13 @@ HGVertexBufferBindings MapSceneRenderForwardVLK::createADTVAO(HGVertexBuffer ver return adtVAO; }; -HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) { +HGVertexBufferBindings MapSceneRenderForwardVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto wmoVAO = m_device->createVertexBufferBindings(); - HGVertexBuffer ambientBuffer = nullptr; - if (vertexBuffer != nullptr) { - ambientBuffer = vboWMOGroupAmbient->getSubBuffer(sizeof(mathfu::vec4_packed)); - auto packedAmbient = mathfu::vec4_packed(localAmbient); - static_assert(sizeof(packedAmbient) == 16); static_assert(sizeof(mathfu::vec4_packed) == 16); - - ambientBuffer->uploadData(&packedAmbient, sizeof(mathfu::vec4_packed)); - } wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); - wmoVAO->addVertexBufferBinding(ambientBuffer, std::vector(staticWmoGroupAmbient.begin(), staticWmoGroupAmbient.end()), true); + wmoVAO->addVertexBufferBinding(ambientBuffer ? BufferChunkHelperVLK::cast(ambientBuffer) : nullptr, + std::vector(staticWmoGroupAmbient.begin(), staticWmoGroupAmbient.end()), true); wmoVAO->setIndexBuffer(indexBuffer); return wmoVAO; @@ -419,7 +412,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const ds->beginUpdate() .ubo(1, BufferChunkHelperVLK::cast(modelWide)) .ubo(2, *l_vertexData) - .ubo(4, *l_fragmentData); + .ubo(3, *l_fragmentData); }) .createDescriptorSet(2, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index fd48ee6b3..610225aec 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -27,7 +27,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { // Buffer creation //------------------------------------- HGVertexBufferBindings createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; - HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; + HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index adab7760c..957e89184 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -26,6 +26,18 @@ static const ShaderConfig forwardShaderConfig = { }} } }; + +static const ShaderConfig m2ForwardShaderConfig = { + "forwardRendering", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + }}, + {1, { + {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} + }} + }}; + const int m2TexturesBindlessCount = 4096; const int adtTexturesBindlessCount = 4096; static const ShaderConfig m2VisShaderConfig = { @@ -39,6 +51,17 @@ static const ShaderConfig m2VisShaderConfig = { }} }}; +static const ShaderConfig wmoVisShaderConfig = { + "visBuffer", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} + }} + }}; + static const ShaderConfig adtVisShaderConfig = { "visBuffer", { @@ -68,7 +91,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); - vboWMOGroupAmbient = m_device->createVertexBuffer("Scene_VBO_WMOAmbient",16*200); + { const float epsilon = 0.f; @@ -111,7 +134,15 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic adtBuffers.adtMeshWidePSes = m_device->createSSBOBuffer("ADT MeshPS", 1024*1024, sizeof(ADT::meshWideBlockPS)); adtBuffers.adtInstanceDatas = m_device->createSSBOBuffer("ADT InstanceData", 1024*1024, sizeof(ADT::AdtInstanceData)); } - + //Create wmo Shader buffs + { + wmoBuffers.wmoPlacementMats = m_device->createSSBOBuffer("WMO PlaceMat", 1024*1024, sizeof(mathfu::mat4)); + wmoBuffers.wmoMeshWideVSes = m_device->createSSBOBuffer("WMO MeshWideVS", 1024*1024, sizeof(WMO::meshWideBlockVS)); + wmoBuffers.wmoMeshWidePSes = m_device->createSSBOBuffer("WMO MeshWidePS", 1024*1024, sizeof(WMO::meshWideBlockPS)); + wmoBuffers.wmoMeshWideBindless = m_device->createSSBOBuffer("WMO MeshWideBindless", 1024*1024, sizeof(WMO::meshWideBlockBindless)); + wmoBuffers.wmoPerMeshData = m_device->createSSBOBuffer("WMO PerMeshData", 1024*1024, sizeof(WMO::perMeshData)); + wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer("Scene_VBO_WMOAmbient",16*200, sizeof(mathfu::vec4_packed)); + } uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); @@ -121,7 +152,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); - m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, mathfu::vec4(0,0,0,0)); + m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, nullptr); m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); @@ -166,6 +197,24 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic }); m2TextureHolder = std::make_shared(m2TexturesBindlessCount); + //Create global wmo descriptor for bindless textures + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, wmoBuffers.wmoPlacementMats) + .ssbo(2, wmoBuffers.wmoMeshWideVSes) + .ssbo(3, wmoBuffers.wmoMeshWidePSes) + .ssbo(4, wmoBuffers.wmoMeshWideBindless) + .ssbo(5, wmoBuffers.wmoGroupAmbient) + .ssbo(6, wmoBuffers.wmoPerMeshData); + + wmoBufferOneDS = ds; + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + wmoTexturesDS = ds; + }); + wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); + adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtAlphaTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -200,9 +249,6 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic } } -// ------------------ - - std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_m2StaticMaterials.find(pipelineTemplate); if (i != m_m2StaticMaterials.end()) { @@ -225,6 +271,31 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater return staticMaterial; } + +std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate) { + auto i = m_wmoStaticMaterials.find(pipelineTemplate); + if (i != m_wmoStaticMaterials.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + m_wmoStaticMaterials.erase(i); + } + } + + auto staticMaterial = + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, wmoBufferOneDS) + .bindDescriptorSet(2, wmoTexturesDS) + .toMaterial(); + + m_wmoStaticMaterials[pipelineTemplate] = staticMaterial; + + return staticMaterial; +} + +// ------------------ // Buffer creation // ------------------ @@ -237,20 +308,11 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createADTVAO(HGVertexBuffer v return adtVAO; }; -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) { +HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto wmoVAO = m_device->createVertexBufferBindings(); - HGVertexBuffer ambientBuffer = nullptr; - if (vertexBuffer != nullptr) { - ambientBuffer = vboWMOGroupAmbient->getSubBuffer(sizeof(mathfu::vec4_packed)); - auto packedAmbient = mathfu::vec4_packed(localAmbient); - static_assert(sizeof(packedAmbient) == 16); static_assert(sizeof(mathfu::vec4_packed) == 16); - - ambientBuffer->uploadData(&packedAmbient, sizeof(mathfu::vec4_packed)); - } wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); - wmoVAO->addVertexBufferBinding(ambientBuffer, std::vector(staticWmoGroupAmbient.begin(), staticWmoGroupAmbient.end()), true); wmoVAO->setIndexBuffer(indexBuffer); return wmoVAO; @@ -484,7 +546,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Waterf auto vertexData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2VisShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) @@ -563,41 +625,57 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMat }; std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOWideChunk() { - return std::make_shared>(uboBuffer); + return std::make_shared>(wmoBuffers.wmoPlacementMats); +} +std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOGroupAmbientChunk() { + return std::make_shared>(wmoBuffers.wmoGroupAmbient); } std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WMOMaterialTemplate &wmoMaterialTemplate) { - auto l_vertexData = std::make_shared>(uboStaticBuffer); ; - auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; + auto l_vertexData = std::make_shared>(wmoBuffers.wmoMeshWideVSes); ; + auto l_fragmentData = std::make_shared>(wmoBuffers.wmoMeshWidePSes); ; + auto l_bindless = std::make_shared>(wmoBuffers.wmoMeshWideBindless); - auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) - .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) - .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo(1, BufferChunkHelperVLK::cast(modelWide)) - .ubo(2, *l_vertexData) - .ubo(4, *l_fragmentData); - }) - .createDescriptorSet(2, [&wmoMaterialTemplate](std::shared_ptr &ds) { - ds->beginUpdate() - .texture(5, wmoMaterialTemplate.textures[0]) - .texture(6, wmoMaterialTemplate.textures[1]) - .texture(7, wmoMaterialTemplate.textures[2]) - .texture(8, wmoMaterialTemplate.textures[3]) - .texture(9, wmoMaterialTemplate.textures[4]) - .texture(10, wmoMaterialTemplate.textures[5]) - .texture(11, wmoMaterialTemplate.textures[6]) - .texture(12, wmoMaterialTemplate.textures[7]) - .texture(13, wmoMaterialTemplate.textures[8]); - }) - .toMaterial([&l_vertexData, &l_fragmentData](IWMOMaterial *instance) -> void { - instance->m_materialVS = l_vertexData; + auto staticMaterial = getWMOStaticMaterial(pipelineTemplate); + + auto material = MaterialBuilderVLK::fromMaterial(m_device, staticMaterial) + .toMaterial([&l_vertexData, &l_fragmentData, &l_bindless](IWMOMaterialVis *instance) -> void { instance->m_materialPS = l_fragmentData; + instance->m_materialVS = l_vertexData; + instance->m_meshBindless = l_bindless; }); + { + auto dsUpdate = wmoTexturesDS->beginUpdate(); + + for (int i = 0; i < 9; i++) { + auto bindlessText = wmoTextureHolder->allocate(wmoMaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, wmoMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto &bindless = l_bindless->getObject(); + bindless.blockVSIndex = l_vertexData->getIndex(); + bindless.meshWideIndex = l_fragmentData->getIndex(); + bindless.placementMat = BufferChunkHelperVLK::cast(modelWide)->getIndex(); + + bindless.texture1 = material->m_bindlessText[0]->getIndex(); + bindless.texture2 = material->m_bindlessText[1]->getIndex(); + bindless.texture3 = material->m_bindlessText[2]->getIndex(); + bindless.texture4 = material->m_bindlessText[3]->getIndex(); + bindless.texture5 = material->m_bindlessText[4]->getIndex(); + bindless.texture6 = material->m_bindlessText[5]->getIndex(); + bindless.texture7 = material->m_bindlessText[6]->getIndex(); + bindless.texture8 = material->m_bindlessText[7]->getIndex(); + bindless.texture9 = material->m_bindlessText[8]->getIndex(); + + l_bindless->save(); + } + + material->meshWideBindlessIndex = l_bindless->getIndex(); return material; } @@ -839,7 +917,6 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); - uploadCmd.submitBufferUploads(l_this->vboWMOGroupAmbient); uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); @@ -857,6 +934,13 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWideVSPSes); uploadCmd.submitBufferUploads(l_this->adtBuffers.adtInstanceDatas); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoPlacementMats); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWideVSes); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWidePSes); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWideBindless); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoGroupAmbient); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoPerMeshData); + uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); @@ -995,6 +1079,27 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } +HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + const std::shared_ptr> &ambientBuffer) { + auto originalMat = std::dynamic_pointer_cast(material); + auto c_perMeshData = std::make_shared>(wmoBuffers.wmoPerMeshData); + + auto newMat = MaterialBuilderVLK::fromMaterial(m_device, std::dynamic_pointer_cast(material)) + .toMaterial([&c_perMeshData](IWMOMaterialVis *instance) -> void { + instance->m_perMeshData = c_perMeshData; + }); + + { + auto &perMeshData = c_perMeshData->getObject(); + perMeshData.meshWideBindlessIndex = originalMat->meshWideBindlessIndex; + perMeshData.wmoAmbientIndex = BufferChunkHelperVLK::castToChunk(ambientBuffer)->getIndex(); + c_perMeshData->save(); + } + + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); + mesh->instanceIndex = c_perMeshData->getIndex(); + return mesh; +} HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 29d347467..c7b564361 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -29,7 +29,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { // Buffer creation //------------------------------------- HGVertexBufferBindings createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; - HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, mathfu::vec4 localAmbient) override; + HGVertexBufferBindings createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) override; HGVertexBufferBindings createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; HGVertexBufferBindings createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override; @@ -79,6 +79,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) override; std::shared_ptr> createWMOWideChunk() override; + std::shared_ptr> createWMOGroupAmbientChunk() override; std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, @@ -99,6 +100,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; //-------------------------------------- @@ -109,6 +111,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { private: std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); + std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); struct PipelineTemplateHasher { std::size_t operator()(const PipelineTemplate& k) const { @@ -123,6 +126,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { }; }; std::unordered_map, PipelineTemplateHasher> m_m2StaticMaterials; + std::unordered_map, PipelineTemplateHasher> m_wmoStaticMaterials; private: HGDeviceVLK m_device; @@ -138,7 +142,6 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK vboAdtBuffer; HGBufferVLK vboWMOBuffer; - HGBufferVLK vboWMOGroupAmbient; HGBufferVLK vboWaterBuffer; HGBufferVLK vboSkyBuffer; @@ -164,6 +167,15 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK adtInstanceDatas; } adtBuffers; + struct { + HGBufferVLK wmoPlacementMats; + HGBufferVLK wmoMeshWideVSes; + HGBufferVLK wmoMeshWidePSes; + HGBufferVLK wmoMeshWideBindless; + HGBufferVLK wmoPerMeshData; + HGBufferVLK wmoGroupAmbient; + } wmoBuffers; + HGBufferVLK uboBuffer; HGBufferVLK m_vboQuad; @@ -187,6 +199,10 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr adtAlphaTextureDS = nullptr; std::shared_ptr adtAlphaTextureHolder = nullptr; + std::shared_ptr g_wmoMaterial = nullptr; + std::shared_ptr wmoBufferOneDS = nullptr; + std::shared_ptr wmoTexturesDS = nullptr; + std::shared_ptr wmoTextureHolder = nullptr; std::shared_ptr m_renderPass; From 7442c7fb5081ce82dda007caed4fa33ee93ef661 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 15 Oct 2023 08:54:50 +0300 Subject: [PATCH 135/212] - small optimizations in command buffer recordings - fix ADT UV coordinates --- .../shaders/glsl/visBuffer/adtShader.vert | 28 ++++++++++-- .../src/engine/shader/ShaderDefinitions.h | 10 +++++ .../CommandBufferRecorder.cpp | 45 +++++++++++++++---- .../CommandBufferRecorder.h | 8 ++++ .../CommandBufferRecorder_inline.h | 10 ++--- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 23 +++------- 6 files changed, 90 insertions(+), 34 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index de57e3b72..c2e19bf74 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -35,10 +35,25 @@ layout(location = 5) out flat int vMeshIndex; layout(location = 6) out vec2 vAlphaCoords; const float TILESIZE = (1600.0 / 3.0); -const float UNITSIZE = TILESIZE / 16.0 / 8.0; +const float CHUNKSIZE = TILESIZE / 16.0; +const float UNITSIZE = CHUNKSIZE / 8.0; +float fixUVBorder(float uvComp, float x) { + float alphaTextureSize_px = 1024.0; + float subPixel = -0.5 / alphaTextureSize_px; + float epsilon = 0.0001; + + if (x < epsilon) + uvComp -= subPixel; + if ((1.0 - x) < epsilon) + uvComp += subPixel; + + return uvComp ; +} void main() { + AdtInstanceData adtInstanceData = adtInstanceDatas[gl_InstanceIndex]; + AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x]; /* Y @@ -69,9 +84,14 @@ void main() { vChunkCoords = vec2(iX, iY); - vAlphaCoords = (aPos.yx - floor(aPos.yx / TILESIZE)*TILESIZE) / TILESIZE; - vAlphaCoords.x = 1.0 - vAlphaCoords.x; - vAlphaCoords.y = 1.0 - vAlphaCoords.y; + + vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - adtMeshWideVSPS.uPos.yx; //Top left point (17058 17063) becomes (0,0) + vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); + + vAlphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - aPos.yx) / TILESIZE; + + vAlphaCoords.x = fixUVBorder(vAlphaCoords.x, vChunkCoords.x/8.0); + vAlphaCoords.y = fixUVBorder(vAlphaCoords.y, vChunkCoords.y/8.0); vPosition = (scene.uLookAtMat * worldPoint).xyz; vColor = aColor; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index eedc15984..94d6445ee 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -1511,6 +1511,8 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, }, { }, @@ -1960,6 +1962,14 @@ const std::unordered_map &buffer) { + if (m_currentIndexBuffer == buffer) return; + auto bufferVlk = std::dynamic_pointer_cast(buffer); - if (m_currentIndexBuffer!= nullptr && m_currentIndexBuffer->getGPUBuffer() == bufferVlk->getGPUBuffer() && - m_currentIndexBuffer->getOffset() == bufferVlk->getOffset()) return; VkDeviceSize offset = bufferVlk->getOffset(); vkCmdBindIndexBuffer(m_gCmdBuffer.m_cmdBuffer, bufferVlk->getGPUBuffer(), offset, VK_INDEX_TYPE_UINT16); @@ -110,17 +111,15 @@ void CmdBufRecorder::bindVertexBuffers(const std::vector(buffers[i]); - auto pbufferVlk = bufferVlk.get(); - //firstBinding == i <- means we can only skip the start of the list; - if (firstBinding == i && m_currentVertexBuffers[i] != nullptr && - m_currentVertexBuffers[i]->getGPUBuffer() == pbufferVlk->getGPUBuffer() && - m_currentVertexBuffers[i]->getOffset() == pbufferVlk->getOffset()) { + if (firstBinding == i && m_currentVertexBuffers[i] == buffers[i]) { firstBinding++; continue; } + auto const &bufferVlk = std::dynamic_pointer_cast(buffers[i]); + auto pbufferVlk = bufferVlk.get(); + vbos[vboCnt++] = pbufferVlk->getGPUBuffer(); offsets[offsetCnt++] = pbufferVlk->getOffset(); @@ -331,4 +330,32 @@ void CmdBufRecorder::createDefaultScissors(const std::array &areaOff #ifdef LINK_TRACY VkCommandBuffer CmdBufRecorder::getNativeCmdBuffer() { return m_gCmdBuffer.getNativeCmdBuffer(); } TracyVkCtx const &CmdBufRecorder::getTracyContext() { return m_gCmdBuffer.tracyContext; } + +void CmdBufRecorder::bindMaterial(const std::shared_ptr &material) { + if (m_material == material) return; + + //1. Bind pipeline + this->bindPipeline(material->getPipeline()); + + //2. Bind Descriptor sets + auto const &descSets = material->getDescriptorSets(); + this->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); + + m_material = material; +} + +void CmdBufRecorder::bindVertexBindings(const std::shared_ptr &vertexBufferBindings) { + if (m_vertexBufferBindings == vertexBufferBindings) return; + + auto vulkanBindings = std::dynamic_pointer_cast(vertexBufferBindings); + + //1. Bind VBOs + this->bindVertexBuffers(vulkanBindings->getVertexBuffers()); + + //2. Bind IBOs + this->bindIndexBuffer(vulkanBindings->getIndexBuffer()); + + m_vertexBufferBindings = vertexBufferBindings; +} + #endif diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 48e087aac..e0f663388 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -12,6 +12,7 @@ +class ISimpleMaterialVLK; class CmdBufRecorder; class RenderPassHelper; class GCommandBuffer; @@ -22,6 +23,7 @@ class CommandBufferDebugLabel; #include "CommandBufferDebugLabel.h" #include "../../descriptorSets/GDescriptorSet.h" #include "../../GPipelineVLK.h" +#include "../../materials/ISimpleMaterialVLK.h" #ifdef LINK_TRACY #define VkZone(buffRecorder,a) TracyVkZone(buffRecorder.getTracyContext(), buffRecorder.getNativeCmdBuffer(), a) @@ -48,6 +50,9 @@ class CmdBufRecorder { const std::array &areaSize, const std::array &colorClearColor, float depthClear); + void bindMaterial(const std::shared_ptr &material); + void bindVertexBindings(const std::shared_ptr &vertexBufferBindings); + CommandBufferDebugLabel beginDebugLabel(const std::string &labelName, const std::array &colors); void bindIndexBuffer(const std::shared_ptr &bufferVlk); @@ -91,6 +96,9 @@ class CmdBufRecorder { bool m_currentScissorsIsDefault = false; ViewportType m_currentViewport = ViewportType::vp_none; + std::shared_ptr m_material = nullptr; + std::shared_ptr m_vertexBufferBindings = nullptr; + //Viewports std::array viewportsForThisStage; VkRect2D defaultScissor; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h index b950da1d3..d47cf4c62 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h @@ -28,8 +28,8 @@ inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, co uint32_t *p_dynamicOffset; p_dynamicOffset = &dynamicOffsets[0]; - std::vector descs; - descs.reserve(descriptorSets.size()); + std::array descs; + int descAmount = 0; uint32_t bindIndexStart = -1; for (int i = 0; i < descriptorSets.size(); i++) { @@ -39,7 +39,7 @@ inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, co bindIndexStart = bindIndexStart==-1 ? i : bindIndexStart; auto vkDescSet = pDescriptorSet->getDescSet(); - descs.push_back(vkDescSet); + descs[descAmount++] = vkDescSet; uint32_t thisSize = 0; pDescriptorSet->getDynamicOffsets(p_dynamicOffset, thisSize); @@ -50,11 +50,11 @@ inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, co } } - if (descs.size() > 0) { + if (descAmount > 0) { vkCmdBindDescriptorSets(m_gCmdBuffer.m_cmdBuffer, bindPoint, m_currentPipelineLayout, bindIndexStart, - descs.size(), descs.data(), + descAmount, descs.data(), dynamicOffsetsSize, dynamicOffsetsSize > 0 ? dynamicOffsets : nullptr); } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 957e89184..f3ca1a554 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -775,33 +775,24 @@ inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const H if (mesh == nullptr) return; const auto &meshVlk = (GMeshVLK*) mesh.get(); - auto vulkanBindings = std::dynamic_pointer_cast(mesh->bindings()); - //1. Bind VBOs - cmdBuf.bindVertexBuffers(vulkanBindings->getVertexBuffers()); + //1. Bind Vertex bindings + cmdBuf.bindVertexBindings(mesh->bindings()); - //2. Bind IBOs - cmdBuf.bindIndexBuffer(vulkanBindings->getIndexBuffer()); + //2. Bind Material + cmdBuf.bindMaterial(meshVlk->material()); - //3. Bind pipeline - const auto &material = meshVlk->material(); - cmdBuf.bindPipeline(material->getPipeline()); - - //4. Bind Descriptor sets - auto const &descSets = material->getDescriptorSets(); - cmdBuf.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, descSets); - - //5. Set view port + //3. Set view port cmdBuf.setViewPort(viewportType); - //6. Set scissors + //4. Set scissors if (meshVlk->scissorEnabled()) { cmdBuf.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); } else { cmdBuf.setDefaultScissors(); } - //7. Draw the mesh + //5. Draw the mesh if (meshVlk->instanceIndex != -1) { cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, meshVlk->instanceIndex); } else { From 348d89de32c0fd5c6ef81ab455164596853a892f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 15 Oct 2023 18:48:27 +0300 Subject: [PATCH 136/212] - start of work on water shaders --- .../shaders/glsl/visBuffer/adtShader.frag | 4 +- .../shaders/glsl/visBuffer/adtShader.vert | 12 +- .../shaders/glsl/visBuffer/waterShader.frag | 78 ++++++++++++ .../shaders/glsl/visBuffer/waterShader.vert | 43 +++++++ .../glsl/visBuffer/waterfallShader.frag | 120 ++++++++++++++++++ .../glsl/visBuffer/waterfallShader.vert | 79 ++++++++++++ 6 files changed, 328 insertions(+), 8 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/visBuffer/waterShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/waterShader.vert create mode 100644 wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index b665b84ee..b65817bd6 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -16,8 +16,8 @@ layout(location = 1) in vec3 vPosition; layout(location = 2) in vec4 vColor; layout(location = 3) in vec3 vNormal; layout(location = 4) in vec3 vVertexLighting; -layout(location = 5) in flat int meshIndex; -layout(location = 6) in vec2 vAlphaCoords; +layout(location = 5) in vec2 vAlphaCoords; +layout(location = 6) in flat int meshIndex; layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index c2e19bf74..fe29a649e 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -31,23 +31,23 @@ layout(location = 1) out vec3 vPosition; layout(location = 2) out vec4 vColor; layout(location = 3) out vec3 vNormal; layout(location = 4) out vec3 vVertexLighting; -layout(location = 5) out flat int vMeshIndex; -layout(location = 6) out vec2 vAlphaCoords; +layout(location = 5) out vec2 vAlphaCoords; +layout(location = 6) out flat int vMeshIndex; const float TILESIZE = (1600.0 / 3.0); const float CHUNKSIZE = TILESIZE / 16.0; const float UNITSIZE = CHUNKSIZE / 8.0; float fixUVBorder(float uvComp, float x) { - float alphaTextureSize_px = 1024.0; - float subPixel = -0.5 / alphaTextureSize_px; + const float alphaTextureSize_px = 1024.0; + const float subPixel = 0.5 / alphaTextureSize_px; float epsilon = 0.0001; if (x < epsilon) - uvComp -= subPixel; - if ((1.0 - x) < epsilon) uvComp += subPixel; + if ((1.0 - x) < epsilon) + uvComp -= subPixel; return uvComp ; } diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag new file mode 100644 index 000000000..183c9cc4f --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag @@ -0,0 +1,78 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + +precision highp float; +precision highp int; + +layout(location=0) in vec3 vPosition; +layout(location=1) in vec2 vTextCoords; +layout(location=2) in vec3 vNormal; + +layout(location=0) out vec4 outputColor; + +layout(set=2,binding=5) uniform sampler2D uTexture; + +#include "../common/commonUboSceneData.glsl" + +//Individual meshes +layout(std140, set=1, binding=4) uniform meshWideBlockPS { + ivec4 materialId; + vec4 color; + mat4 textureMatrix; +}; + +const InteriorLightParam intLight = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + +void main() { +// MaterialId: +// 1,3 - Water +// 2,4 - Magma +// 5 - Mercury, +// 10 - Fog +// 12 - LeyLine +// 13 - Fel +// 14 - Swamp +// 18 - Azerithe +// 8 - is probably debug material called Grid + + + vec2 animatedUV = (textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; + + vec3 matDiffuse = color.rgb+texture(uTexture, animatedUV).rgb; + + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; + + + vec4 finalColor = vec4(matDiffuse, 1.0); + + //Magma is not affected by light + if (materialId.x != 2 && materialId.x != 4) { + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + 0, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vec3(0.0), + vec3(0.0), /* specular */ + vec3(0.0) + ), + 1.0 + ); + } + + //BlendMode is always GxBlend_Alpha + finalColor.rgb = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; + + outputColor = vec4(finalColor.rgb, 0.7); +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert new file mode 100644 index 000000000..ac9658f93 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert @@ -0,0 +1,43 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + +layout(location=0) in vec4 aPositionTransp; +layout(location=1) in vec2 aTexCoord; + + + + +layout(std140, set=1, binding=1) uniform modelWideBlockVS { + mat4 uPlacementMat; +}; + +//out vec2 vTexCoord; +layout(location=0) out vec3 vPosition; +layout(location=1) out vec2 vTextCoords; +layout(location=2) out vec3 vNormal; + +void main() { + vec4 aPositionVec4 = vec4(aPositionTransp.xyz, 1); + mat4 viewModelMat = scene.uLookAtMat * uPlacementMat; + + vec4 cameraPoint = viewModelMat * aPositionVec4; + + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + + //const float posToTextPos = 1.0 / (1600.0/3.0/16.0); + vTextCoords = aTexCoord;//aPositionVec4.xy * posToTextPos; + + gl_Position = scene.uPMatrix * cameraPoint; + // vTexCoord = aTexCoord; + vPosition = cameraPoint.xyz; + vNormal = normalize(viewModelMatForNormal * vec4(vec3(0,0,1.0), 0.0)).xyz; + +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag new file mode 100644 index 000000000..edb9cd181 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag @@ -0,0 +1,120 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonFunctions.glsl" +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec2 vTexCoord2_animated; +layout(location=3) in vec3 vNormal; +layout(location=4) in vec3 vPosition; + +layout(set=3,binding=6) uniform sampler2D uMask; +layout(set=3,binding=7) uniform sampler2D uWhiteWater; +layout(set=3,binding=8) uniform sampler2D uNoise; +layout(set=3,binding=10) uniform sampler2D uNormalTex; + +layout(location=0) out vec4 outputColor; + + + +//Whole model +#include "../common/commonM2DescriptorSet.glsl" + +layout(std140, set=2, binding=5) uniform meshWideBlockPS { + vec4 values0; + vec4 values1; + vec4 values2; + vec4 values3; + vec4 values4; + vec4 baseColor; +}; + +const InteriorLightParam intLightWaterfall = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + +// For references: +// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html +// http://www.thetenthplanet.de/archives/1180 +// https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf + +vec3 PerturbNormal ( vec3 surf_pos, vec3 surf_norm ) +{ + vec2 dBdUV = (texture(uNormalTex, vTexCoord2_animated).xy*2.0f - 1.0f) * (values3.x * 100); + + vec2 duv1 = dFdx( vTexCoord2_animated ).xy; + vec2 duv2 = dFdy( vTexCoord2_animated ).xy; + + vec3 vSigmaS = dFdx ( surf_pos ); + vec3 vSigmaT = dFdy ( surf_pos ); + vec3 vN = surf_norm ; // normalized + vec3 vR1 = cross ( vSigmaT , vN ); + vec3 vR2 = cross (vN , vSigmaS ); + float fDet = dot ( vSigmaS , vR1 ); + float dBs = dBdUV.x * duv1.x + dBdUV.y * duv1.y; + float dBt = dBdUV.x * duv2.x + dBdUV.y * duv2.y; + vec3 vSurfGrad = sign ( fDet ) * ( dBs * vR1 + dBt * vR2 ); + return normalize ( abs ( fDet )*vN - vSurfGrad ); +} + +void main() { + vec3 perturbedNormal = PerturbNormal(-vPosition, normalize(vNormal)); + + vec2 vTexCoordNorm = vTexCoord / values1.x; + + float noise0 = texture(uNoise, vec2(vTexCoordNorm.x - values1.z, vTexCoordNorm.y-values1.z - values2.z)).x; + float noise1 = texture(uNoise, vec2(vTexCoordNorm.x - values1.z + 0.418f, vTexCoordNorm.y + 0.355f + values1.z - values2.z)).x; + float noise2 = texture(uNoise, vec2(vTexCoordNorm.x + values1.z + 0.865f, vTexCoordNorm.y + 0.148f - values1.z - values2.z)).x; + float noise3 = texture(uNoise, vec2(vTexCoordNorm.x + values1.z + 0.651, vTexCoordNorm.y + 0.752f + values1.z - values2.z)).x; + + float noise_avr = abs(noise0 + noise1 + noise2 + noise3) * 0.25f; + float noiseFinal = clamp(exp(values0.x * log2(noise_avr) * 2.2f) * values0.y, 0.0f, 1.0f); + + vec4 whiteWater_val = texture(uWhiteWater, vTexCoord2_animated); + vec4 mask_val_0 = texture(uMask, vTexCoord); + vec4 mask_val_1 = texture(uMask, vec2(vTexCoord.x, vTexCoord.y +values3.z)); + + float mix_alpha = clamp( + ((whiteWater_val.w * noiseFinal - mask_val_1.y * mask_val_0.x) * 2.0f + values0.z) * + (values0.w * 2.0f + 1.0f) - + values0.w, 0.0f, 1.0f); + + vec4 whiteWater_val_baseColor_mix = mix(baseColor, whiteWater_val, mix_alpha); + + vec3 colorAfterLight = calcLight( + whiteWater_val_baseColor_mix.rgb, + perturbedNormal, + true, + 0.0, + scene, + intLightWaterfall, + vec3(0.0), /* accumLight */ + vec3(0.0), /*precomputedLight*/ + vec3(0.0), /* specular */ + vec3(0.0) /* emissive */ + ); + + float w_clamped = clamp((1.0f - mask_val_0.w) * values1.w, 0.0f, 1.0f); + float w_alpha_combined = clamp(w_clamped + mix_alpha, 0.0f, 1.0f); + + vec4 finalColor = vec4( + mix(colorAfterLight.rgb, whiteWater_val_baseColor_mix.rgb, values3.w), + w_alpha_combined +// whiteWater_val.a+0.2 + ); + + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; + finalColor = makeFog2(fogData,/*int(scene.extLight.adtSpecMult_fogCount.y),*/ finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); + + + outputColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert new file mode 100644 index 000000000..4cd0ee86f --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert @@ -0,0 +1,79 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonFunctions.glsl" +#include "../common/commonM2Material.glsl" +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + +precision highp float; + +/* vertex shader code */ +layout(location=0) in vec3 aPosition; +layout(location=1) in vec3 aNormal; +layout(location=2) in uvec4 bones; +layout(location=3) in vec4 boneWeights; +layout(location=4) in vec2 aTexCoord; +layout(location=5) in vec2 aTexCoord2; + +//Whole scene + + +// Whole model +#include "../common/commonM2DescriptorSet.glsl" + +//Individual meshes +layout(std140, set=2, binding=4) uniform meshWideBlockVS { + vec4 bumpScaleTextIndexes; +}; + +layout(set=3,binding=9) uniform sampler2D uBumpTexture; + +//Shader output +layout(location=0) out vec2 vTexCoord; +layout(location=1) out vec2 vTexCoord2; +layout(location=2) out vec2 vTexCoord2_animated; +layout(location=3) out vec3 vNormal; +layout(location=4) out vec3 vPosition; + +void main() { + float bumpScale = bumpScaleTextIndexes.x; + int textMatIndex1 = floatBitsToInt(bumpScaleTextIndexes.y); + int textMatIndex2 = floatBitsToInt(bumpScaleTextIndexes.z); + + mat4 textMat[2]; + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + + vec2 texCoord2 = (textMat[0] * vec4(aTexCoord2, 0, 1)).xy; + + vec4 bumpValue = texture(uBumpTexture, texCoord2); + vec3 pos = (aNormal * bumpScale.x) * bumpValue.z + aPosition; + + mat4 boneTransformMat = mat4(0.0); + + boneTransformMat += (boneWeights.x ) * uBoneMatrixes[bones.x]; + boneTransformMat += (boneWeights.y ) * uBoneMatrixes[bones.y]; + boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; + boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; + + mat4 viewModelMat = scene.uLookAtMat * uPlacementMat * boneTransformMat ; + vec4 cameraPoint = viewModelMat * vec4(pos, 1.0); + + mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); + vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); + + vNormal = (scene.uLookAtMat * uPlacementMat * vec4(aNormal, 0)).xyz; + vPosition = pos; + + vTexCoord = aTexCoord; + vTexCoord2_animated = texCoord2; + vTexCoord2 = aTexCoord2; + + gl_Position = scene.uPMatrix * cameraPoint; +} From 600826855a29415860254786bdfb0df0dbfafa26 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 16 Oct 2023 23:30:08 +0300 Subject: [PATCH 137/212] - waterfall shader ported to bindless --- .../commonM2WaterfallDescriptorSet.glsl | 29 +++ .../forwardRendering/waterfallShader.frag | 8 +- .../forwardRendering/waterfallShader.vert | 20 +- .../glsl/visBuffer/waterfallShader.frag | 68 +++-- .../glsl/visBuffer/waterfallShader.vert | 54 ++-- .../src/engine/objects/m2/m2Object.cpp | 56 ++-- .../src/engine/shader/ShaderDefinitions.h | 240 +++++++++++++----- .../src/gapi/UniformBufferStructures.h | 15 +- .../mapScene/materials/IMaterialStructs.h | 9 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 30 +-- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 200 ++++++++++----- .../vulkan/MapSceneRenderVisBufferVLK.h | 13 + 13 files changed, 492 insertions(+), 252 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl diff --git a/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl new file mode 100644 index 000000000..f1dd179cd --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl @@ -0,0 +1,29 @@ +#ifndef COMMON_M2_WATERFALL_DESCRIPTOR_SET +#define COMMON_M2_WATERFALL_DESCRIPTOR_SET + +struct WaterfallCommon { + vec4 bumpScale_textTransformInd1_textTransformInd2; + vec4 values0; + vec4 values1; + vec4 values2; + vec4 values3; + vec4 values4; + vec4 baseColor; +}; + +layout(std140, set=2, binding=0) buffer waterfallCommonData { + WaterfallCommon waterfallCommons[]; +}; + +struct WaterfallBindless { + ivec4 instanceIndex_waterfallInd_bumpTextureInd_maskInd; + ivec4 whiteWaterInd_noiseInd_normalTexInd; +}; + +layout(std140, set=2, binding=1) buffer waterfallBindless { + WaterfallBindless waterfallBindlesses[]; +}; + +layout(set=3,binding=0) uniform sampler2D s_Textures[]; + +#endif //COMMON_M2_WATERFALL_DESCRIPTOR_SET \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index edb9cd181..2e4a389d2 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -16,10 +16,10 @@ layout(location=2) in vec2 vTexCoord2_animated; layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; -layout(set=3,binding=6) uniform sampler2D uMask; -layout(set=3,binding=7) uniform sampler2D uWhiteWater; -layout(set=3,binding=8) uniform sampler2D uNoise; -layout(set=3,binding=10) uniform sampler2D uNormalTex; +layout(set=3,binding=0) uniform sampler2D uMask; +layout(set=3,binding=1) uniform sampler2D uWhiteWater; +layout(set=3,binding=2) uniform sampler2D uNoise; +layout(set=3,binding=4) uniform sampler2D uNormalTex; layout(location=0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index 4cd0ee86f..ee3daeeda 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -28,11 +28,17 @@ layout(location=5) in vec2 aTexCoord2; #include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=2, binding=4) uniform meshWideBlockVS { - vec4 bumpScaleTextIndexes; +layout(std140, set=2, binding=0) uniform meshWideBlockVS { + vec4 bumpScale_textTransformInd1_textTransformInd2; + vec4 values0; + vec4 values1; + vec4 values2; + vec4 values3; + vec4 values4; + vec4 baseColor; }; -layout(set=3,binding=9) uniform sampler2D uBumpTexture; +layout(set=3,binding=3) uniform sampler2D uBumpTexture; //Shader output layout(location=0) out vec2 vTexCoord; @@ -42,9 +48,9 @@ layout(location=3) out vec3 vNormal; layout(location=4) out vec3 vPosition; void main() { - float bumpScale = bumpScaleTextIndexes.x; - int textMatIndex1 = floatBitsToInt(bumpScaleTextIndexes.y); - int textMatIndex2 = floatBitsToInt(bumpScaleTextIndexes.z); + float bumpScale = bumpScale_textTransformInd1_textTransformInd2.x; + int textMatIndex1 = floatBitsToInt(bumpScale_textTransformInd1_textTransformInd2.y); + int textMatIndex2 = floatBitsToInt(bumpScale_textTransformInd1_textTransformInd2.z); mat4 textMat[2]; textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; @@ -68,7 +74,7 @@ void main() { mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); - vNormal = (scene.uLookAtMat * uPlacementMat * vec4(aNormal, 0)).xyz; + vNormal = normal; vPosition = pos; vTexCoord = aTexCoord; diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag index edb9cd181..3c76c2ead 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require precision highp float; precision highp int; @@ -15,27 +16,15 @@ layout(location=1) in vec2 vTexCoord2; layout(location=2) in vec2 vTexCoord2_animated; layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; - -layout(set=3,binding=6) uniform sampler2D uMask; -layout(set=3,binding=7) uniform sampler2D uWhiteWater; -layout(set=3,binding=8) uniform sampler2D uNoise; -layout(set=3,binding=10) uniform sampler2D uNormalTex; +layout(location=5) flat in int meshInd; layout(location=0) out vec4 outputColor; //Whole model -#include "../common/commonM2DescriptorSet.glsl" - -layout(std140, set=2, binding=5) uniform meshWideBlockPS { - vec4 values0; - vec4 values1; - vec4 values2; - vec4 values3; - vec4 values4; - vec4 baseColor; -}; +#include "../common/commonM2IndirectDescriptorSet.glsl" +#include "../common/commonM2WaterfallDescriptorSet.glsl" const InteriorLightParam intLightWaterfall = { vec4(0,0,0,0), @@ -47,12 +36,12 @@ const InteriorLightParam intLightWaterfall = { // http://www.thetenthplanet.de/archives/1180 // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf -vec3 PerturbNormal ( vec3 surf_pos, vec3 surf_norm ) +vec3 PerturbNormal ( vec3 surf_pos, vec3 surf_norm, sampler2D uNormalTex, vec2 texCoord, float value3_x ) { - vec2 dBdUV = (texture(uNormalTex, vTexCoord2_animated).xy*2.0f - 1.0f) * (values3.x * 100); + vec2 dBdUV = (texture(uNormalTex, texCoord).xy*2.0f - 1.0f) * (value3_x * 100); - vec2 duv1 = dFdx( vTexCoord2_animated ).xy; - vec2 duv2 = dFdy( vTexCoord2_animated ).xy; + vec2 duv1 = dFdx( texCoord ).xy; + vec2 duv2 = dFdy( texCoord ).xy; vec3 vSigmaS = dFdx ( surf_pos ); vec3 vSigmaT = dFdy ( surf_pos ); @@ -67,28 +56,37 @@ vec3 PerturbNormal ( vec3 surf_pos, vec3 surf_norm ) } void main() { - vec3 perturbedNormal = PerturbNormal(-vPosition, normalize(vNormal)); + WaterfallBindless waterfallBindless = waterfallBindlesses[meshInd]; + WaterfallCommon waterfallCommon = waterfallCommons[waterfallBindless.instanceIndex_waterfallInd_bumpTextureInd_maskInd.y]; + + int normalTexInd = waterfallBindless.whiteWaterInd_noiseInd_normalTexInd.z; + vec3 perturbedNormal = PerturbNormal(-vPosition, normalize(vNormal), s_Textures[normalTexInd], vTexCoord2_animated, waterfallCommon.values3.x); - vec2 vTexCoordNorm = vTexCoord / values1.x; + vec2 vTexCoordNorm = vTexCoord / waterfallCommon.values1.x; - float noise0 = texture(uNoise, vec2(vTexCoordNorm.x - values1.z, vTexCoordNorm.y-values1.z - values2.z)).x; - float noise1 = texture(uNoise, vec2(vTexCoordNorm.x - values1.z + 0.418f, vTexCoordNorm.y + 0.355f + values1.z - values2.z)).x; - float noise2 = texture(uNoise, vec2(vTexCoordNorm.x + values1.z + 0.865f, vTexCoordNorm.y + 0.148f - values1.z - values2.z)).x; - float noise3 = texture(uNoise, vec2(vTexCoordNorm.x + values1.z + 0.651, vTexCoordNorm.y + 0.752f + values1.z - values2.z)).x; + int noiseInd = waterfallBindless.whiteWaterInd_noiseInd_normalTexInd.y; + + float noise0 = texture(s_Textures[noiseInd], vec2(vTexCoordNorm.x - waterfallCommon.values1.z, vTexCoordNorm.y-waterfallCommon.values1.z - waterfallCommon.values2.z)).x; + float noise1 = texture(s_Textures[noiseInd], vec2(vTexCoordNorm.x - waterfallCommon.values1.z + 0.418f, vTexCoordNorm.y + 0.355f + waterfallCommon.values1.z - waterfallCommon.values2.z)).x; + float noise2 = texture(s_Textures[noiseInd], vec2(vTexCoordNorm.x + waterfallCommon.values1.z + 0.865f, vTexCoordNorm.y + 0.148f - waterfallCommon.values1.z - waterfallCommon.values2.z)).x; + float noise3 = texture(s_Textures[noiseInd], vec2(vTexCoordNorm.x + waterfallCommon.values1.z + 0.651, vTexCoordNorm.y + 0.752f + waterfallCommon.values1.z - waterfallCommon.values2.z)).x; float noise_avr = abs(noise0 + noise1 + noise2 + noise3) * 0.25f; - float noiseFinal = clamp(exp(values0.x * log2(noise_avr) * 2.2f) * values0.y, 0.0f, 1.0f); + float noiseFinal = clamp(exp(waterfallCommon.values0.x * log2(noise_avr) * 2.2f) * waterfallCommon.values0.y, 0.0f, 1.0f); + + int whiteWaterInd = waterfallBindless.whiteWaterInd_noiseInd_normalTexInd.x; + vec4 whiteWater_val = texture(s_Textures[whiteWaterInd], vTexCoord2_animated); - vec4 whiteWater_val = texture(uWhiteWater, vTexCoord2_animated); - vec4 mask_val_0 = texture(uMask, vTexCoord); - vec4 mask_val_1 = texture(uMask, vec2(vTexCoord.x, vTexCoord.y +values3.z)); + int maskInd = waterfallBindless.instanceIndex_waterfallInd_bumpTextureInd_maskInd.w; + vec4 mask_val_0 = texture(s_Textures[maskInd], vTexCoord); + vec4 mask_val_1 = texture(s_Textures[maskInd], vec2(vTexCoord.x, vTexCoord.y +waterfallCommon.values3.z)); float mix_alpha = clamp( - ((whiteWater_val.w * noiseFinal - mask_val_1.y * mask_val_0.x) * 2.0f + values0.z) * - (values0.w * 2.0f + 1.0f) - - values0.w, 0.0f, 1.0f); + ((whiteWater_val.w * noiseFinal - mask_val_1.y * mask_val_0.x) * 2.0f + waterfallCommon.values0.z) * + (waterfallCommon.values0.w * 2.0f + 1.0f) - + waterfallCommon.values0.w, 0.0f, 1.0f); - vec4 whiteWater_val_baseColor_mix = mix(baseColor, whiteWater_val, mix_alpha); + vec4 whiteWater_val_baseColor_mix = mix(waterfallCommon.baseColor, whiteWater_val, mix_alpha); vec3 colorAfterLight = calcLight( whiteWater_val_baseColor_mix.rgb, @@ -103,11 +101,11 @@ void main() { vec3(0.0) /* emissive */ ); - float w_clamped = clamp((1.0f - mask_val_0.w) * values1.w, 0.0f, 1.0f); + float w_clamped = clamp((1.0f - mask_val_0.w) * waterfallCommon.values1.w, 0.0f, 1.0f); float w_alpha_combined = clamp(w_clamped + mix_alpha, 0.0f, 1.0f); vec4 finalColor = vec4( - mix(colorAfterLight.rgb, whiteWater_val_baseColor_mix.rgb, values3.w), + mix(colorAfterLight.rgb, whiteWater_val_baseColor_mix.rgb, waterfallCommon.values3.w), w_alpha_combined // whiteWater_val.a+0.2 ); diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert index 4cd0ee86f..309fff567 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require precision highp float; precision highp int; @@ -21,18 +22,10 @@ layout(location=3) in vec4 boneWeights; layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; -//Whole scene +#include "../common/commonM2IndirectDescriptorSet.glsl" +#include "../common/commonM2WaterfallDescriptorSet.glsl" -// Whole model -#include "../common/commonM2DescriptorSet.glsl" - -//Individual meshes -layout(std140, set=2, binding=4) uniform meshWideBlockVS { - vec4 bumpScaleTextIndexes; -}; - -layout(set=3,binding=9) uniform sampler2D uBumpTexture; //Shader output layout(location=0) out vec2 vTexCoord; @@ -40,35 +33,50 @@ layout(location=1) out vec2 vTexCoord2; layout(location=2) out vec2 vTexCoord2_animated; layout(location=3) out vec3 vNormal; layout(location=4) out vec3 vPosition; +layout(location=5) out flat int meshInd; void main() { - float bumpScale = bumpScaleTextIndexes.x; - int textMatIndex1 = floatBitsToInt(bumpScaleTextIndexes.y); - int textMatIndex2 = floatBitsToInt(bumpScaleTextIndexes.z); + + WaterfallBindless waterfallBindless = waterfallBindlesses[gl_InstanceIndex]; + int instanceIndex = waterfallBindless.instanceIndex_waterfallInd_bumpTextureInd_maskInd.x; + + M2InstanceRecordBindless instanceData = instances[nonuniformEXT(instanceIndex)]; + WaterfallCommon waterfallCommon = waterfallCommons[nonuniformEXT(waterfallBindless.instanceIndex_waterfallInd_bumpTextureInd_maskInd.y)]; + + float bumpScale = waterfallCommon.bumpScale_textTransformInd1_textTransformInd2.x; + int textMatIndex1 = floatBitsToInt(waterfallCommon.bumpScale_textTransformInd1_textTransformInd2.y); + int textMatIndex2 = floatBitsToInt(waterfallCommon.bumpScale_textTransformInd1_textTransformInd2.z); + + int boneMatInd = instanceData.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.y; + int textureMatInd = instanceData.textureMatricesInd_modelFragmentDatasInd.x; mat4 textMat[2]; - textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textMatIndex1]; - textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textMatIndex2]; + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatInd + textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatInd + textMatIndex2]; vec2 texCoord2 = (textMat[0] * vec4(aTexCoord2, 0, 1)).xy; - vec4 bumpValue = texture(uBumpTexture, texCoord2); + int bumpTextureInd = waterfallBindless.instanceIndex_waterfallInd_bumpTextureInd_maskInd.z; + + vec4 bumpValue = texture(s_Textures[bumpTextureInd], texCoord2); vec3 pos = (aNormal * bumpScale.x) * bumpValue.z + aPosition; mat4 boneTransformMat = mat4(0.0); - boneTransformMat += (boneWeights.x ) * uBoneMatrixes[bones.x]; - boneTransformMat += (boneWeights.y ) * uBoneMatrixes[bones.y]; - boneTransformMat += (boneWeights.z ) * uBoneMatrixes[bones.z]; - boneTransformMat += (boneWeights.w ) * uBoneMatrixes[bones.w]; + boneTransformMat += (boneWeights.x ) * uBoneMatrixes[boneMatInd + bones.x]; + boneTransformMat += (boneWeights.y ) * uBoneMatrixes[boneMatInd + bones.y]; + boneTransformMat += (boneWeights.z ) * uBoneMatrixes[boneMatInd + bones.z]; + boneTransformMat += (boneWeights.w ) * uBoneMatrixes[boneMatInd + bones.w]; - mat4 viewModelMat = scene.uLookAtMat * uPlacementMat * boneTransformMat ; + int placementMatInd = instanceData.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + mat4 placementMat = uPlacementMats[placementMatInd]; + mat4 viewModelMat = scene.uLookAtMat * placementMat * boneTransformMat ; vec4 cameraPoint = viewModelMat * vec4(pos, 1.0); mat4 viewModelMatForNormal = transpose(inverse(viewModelMat)); vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); - vNormal = (scene.uLookAtMat * uPlacementMat * vec4(aNormal, 0)).xyz; + vNormal = normal; vPosition = pos; vTexCoord = aTexCoord; @@ -76,4 +84,6 @@ void main() { vTexCoord2 = aTexCoord2; gl_Position = scene.uPMatrix * cameraPoint; + + meshInd = gl_InstanceIndex; } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 72adea062..ece590142 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1383,8 +1383,6 @@ float wfv_convert(float value, int16_t random) { } HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRenderer, const HGVertexBufferBindings &finalBufferBindings) { -// return nullptr; - gMeshTemplate meshTemplate(bufferBindings); auto skinData = m_skinGeom->getSkinData(); @@ -1417,53 +1415,47 @@ HGM2Mesh M2Object::createWaterfallMesh(const HMapSceneBufferCreate &sceneRendere auto waterfallMaterial = sceneRenderer->createM2WaterfallMaterial(m_modelWideDataBuff, pipelineTemplate, m2WaterfallMaterialTemplate); { - auto &meshblockVS = waterfallMaterial->m_vertexData->getObject(); - meshblockVS.bumpScale = wfv3Data->bumpScale; + auto &waterfallCommon = waterfallMaterial->m_waterfallCommon->getObject(); + waterfallCommon.bumpScale = wfv3Data->bumpScale; std::array textureMatrixIndexes = {-1, -1}; M2MeshBufferUpdater::getTextureMatrixIndexes(*this, 0, m2Data, skinData, textureMatrixIndexes); - meshblockVS.textureMatIndex1 = textureMatrixIndexes[0]; - meshblockVS.textureMatIndex2 = textureMatrixIndexes[1]; - - waterfallMaterial->m_vertexData->save(); - } + waterfallCommon.textureMatIndex1 = textureMatrixIndexes[0]; + waterfallCommon.textureMatIndex2 = textureMatrixIndexes[1]; - { - auto &meshblockPS = waterfallMaterial->m_fragmentData->getObject(); - meshblockPS.baseColor = mathfu::vec4( + waterfallCommon.baseColor = mathfu::vec4( wfv3Data->basecolor.a / 255.0f, wfv3Data->basecolor.r / 255.0f, wfv3Data->basecolor.g / 255.0f, wfv3Data->basecolor.b / 255.0f); - meshblockPS.values0.x = wfv3Data->values0_x; - meshblockPS.values0.y = wfv3Data->values0_y; - meshblockPS.values0.z = wfv3Data->values0_z; - meshblockPS.values0.w = wfv3Data->values0_w; + waterfallCommon.values0.x = wfv3Data->values0_x; + waterfallCommon.values0.y = wfv3Data->values0_y; + waterfallCommon.values0.z = wfv3Data->values0_z; + waterfallCommon.values0.w = wfv3Data->values0_w; - meshblockPS.values1.x = wfv3Data->value1_x; - meshblockPS.values1.y = wfv3Data->value1_y; - meshblockPS.values1.w = wfv3Data->value1_w; + waterfallCommon.values1.x = wfv3Data->value1_x; + waterfallCommon.values1.y = wfv3Data->value1_y; + waterfallCommon.values1.w = wfv3Data->value1_w; - meshblockPS.m_values3.x = wfv3Data->value3_x; - meshblockPS.m_values3.y = wfv3Data->value3_y; + waterfallCommon.m_values3.x = wfv3Data->value3_x; + waterfallCommon.m_values3.y = wfv3Data->value3_y; - meshblockPS.m_values2.x = wfv3Data->flags & 2; - meshblockPS.m_values2.y = wfv3Data->flags & 1; + waterfallCommon.m_values2.x = wfv3Data->flags & 2; + waterfallCommon.m_values2.y = wfv3Data->flags & 1; - meshblockPS.m_values2.w = wfv3Data->value2_w; - meshblockPS.m_values3.w = wfv3Data->values3_w; - meshblockPS.m_values4.y = wfv3Data->values4_y; + waterfallCommon.m_values2.w = wfv3Data->value2_w; + waterfallCommon.m_values3.w = wfv3Data->values3_w; + waterfallCommon.m_values4.y = wfv3Data->values4_y; - meshblockPS.values1.z = wfv_convert(meshblockPS.values1.y, (int16_t)((uint64_t)this)); - meshblockPS.m_values2.z = wfv_convert(meshblockPS.m_values2.w, (int16_t)((uint64_t)this)); - meshblockPS.m_values3.z = wfv_convert(wfv3Data->values3_z, (int16_t)((uint64_t)this)); + waterfallCommon.values1.z = wfv_convert(waterfallCommon.values1.y, (int16_t)((uint64_t)this)); + waterfallCommon.m_values2.z = wfv_convert(waterfallCommon.m_values2.w, (int16_t)((uint64_t)this)); + waterfallCommon.m_values3.z = wfv_convert(wfv3Data->values3_z, (int16_t)((uint64_t)this)); - waterfallMaterial->m_fragmentData->save(); + waterfallMaterial->m_waterfallCommon->save(); } //Make mesh - //TODO: auto hmesh = sceneRenderer->createM2WaterfallMesh(meshTemplate, waterfallMaterial, m2Batch->materialLayer, m2Batch->priorityPlane); return hmesh; @@ -1574,7 +1566,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { } } else { -// m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); + m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 94d6445ee..7e3584ccd 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -422,7 +422,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {2,4,16}, + {2,0,112}, {1,6,4096}, {1,3,16384}, {0,0,480}, @@ -432,7 +432,7 @@ const std::unordered_map shaderMetaInfo = { { {0,0,1}, {1,6,6}, - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -443,14 +443,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,9, "uBumpTexture"}, + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {9,9,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -533,6 +533,49 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/waterfallShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,480}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + }, + { + {3,0, "s_Textures"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, @@ -717,6 +760,44 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/waterShader.frag.spv", + { + ShaderStage::Fragment, + { + {1,4,96}, + {0,0,480}, + }, + { + { + {0,0,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {2,5, "uTexture"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {5,5,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, @@ -776,17 +857,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,10, "uNormalTex"}, - {3,8, "uNoise"}, - {3,7, "uWhiteWater"}, - {3,6, "uMask"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,10,5}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -903,6 +984,45 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/waterfallShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,0,480}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {2,1,0}, + {2,0,0}, + }, + { + {3,0, "s_Textures"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, @@ -1098,6 +1218,43 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/waterShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,480}, + {1,1,64}, + }, + { + { + {0,0,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, @@ -1904,51 +2061,26 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 1, { - {"_1_1_uPlacementMat", true, 0, 4, 4, 0}, + 7, { } }, { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 272, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 288, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 304, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 352, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 368, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 400, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 432, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 464, 1, 4, 0}, + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { 3, { - {"_1_3_uBoneMatrixes[0]", true, 0, 4, 4, 256}, + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 6, { - {"_1_6_textureMatrix[0]", true, 0, 4, 4, 64}, + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, } }, { - 4, { - {"_2_4_bumpScaleTextIndexes", true, 0, 1, 4, 0}, + 0, { } }, }}, @@ -2342,32 +2474,12 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 1, { + } + }, { 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 240, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 256, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 272, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 288, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 304, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 320, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 352, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 368, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 400, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 432, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 464, 1, 4, 0}, } }, { diff --git a/wowViewerLib/src/gapi/UniformBufferStructures.h b/wowViewerLib/src/gapi/UniformBufferStructures.h index e12a1d548..d1e2976c6 100644 --- a/wowViewerLib/src/gapi/UniformBufferStructures.h +++ b/wowViewerLib/src/gapi/UniformBufferStructures.h @@ -133,13 +133,11 @@ namespace M2 { }; namespace WaterfallData { - struct meshWideBlockVS { + struct WaterfallCommon { float bumpScale; int textureMatIndex1; int textureMatIndex2; int unused; - }; - struct meshWideBlockPS { mathfu::vec4_packed values0; mathfu::vec4_packed values1; mathfu::vec4_packed m_values2; @@ -147,6 +145,17 @@ namespace M2 { mathfu::vec4_packed m_values4; mathfu::vec4_packed baseColor; }; + struct WaterfallBindless { + int instanceIndex; + int waterfallInd; + + int bumpTextureInd; + int maskInd; + int whiteWaterInd; + int noiseInd; + int normalTexInd; + int unused; + }; } } namespace Particle { diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 7c097ad3f..0572b7ef3 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -89,8 +89,13 @@ class IM2WaterFallMaterial : public IMaterial { int pixelShader; EGxBlendEnum blendMode; - std::shared_ptr> m_vertexData = nullptr; - std::shared_ptr> m_fragmentData = nullptr; + std::shared_ptr> m_waterfallCommon = nullptr; +}; +class IM2WaterFallMaterialBindless : public IM2WaterFallMaterial { +public: + int instanceIndex = 0; + std::shared_ptr> m_waterfallBindless = nullptr; + std::vector> m_bindlessText; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index f4de4b55c..03a47f981 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -284,7 +284,7 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) .createDescriptorSet(2, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() .ubo(7, *vertexFragmentData); @@ -313,29 +313,27 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal const PipelineTemplate &pipelineTemplate, const M2WaterfallMaterialTemplate &m2MaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; - auto vertexData = std::make_shared>(uboStaticBuffer); - auto fragmentData = std::make_shared>(uboStaticBuffer); + auto waterfallCommonData = std::make_shared>(uboStaticBuffer); + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) - .createDescriptorSet(2, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) + .createDescriptorSet(2, [&m2ModelData, &waterfallCommonData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(4, *vertexData) - .ubo(5, *fragmentData); + .ubo(0, *waterfallCommonData); }) .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(6, m2MaterialTemplate.textures[0]) - .texture(7, m2MaterialTemplate.textures[1]) - .texture(8, m2MaterialTemplate.textures[2]) - .texture(9, m2MaterialTemplate.textures[3]) - .texture(10, m2MaterialTemplate.textures[4]); + .texture(0, m2MaterialTemplate.textures[0]) + .texture(1, m2MaterialTemplate.textures[1]) + .texture(2, m2MaterialTemplate.textures[2]) + .texture(3, m2MaterialTemplate.textures[3]) + .texture(4, m2MaterialTemplate.textures[4]); }) - .toMaterial([&vertexData, fragmentData](IM2WaterFallMaterial *instance) -> void { - instance->m_vertexData = vertexData; - instance->m_fragmentData = fragmentData; + .toMaterial([&waterfallCommonData](IM2WaterFallMaterial *instance) -> void { + instance->m_waterfallCommon = waterfallCommonData; }); return material; @@ -520,7 +518,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon .ubo(4, BufferChunkHelperVLK::cast(result->m_colors)) .ubo(5, BufferChunkHelperVLK::cast(result->m_textureWeights)) .ubo(6, BufferChunkHelperVLK::cast(result->m_textureMatrices)); - result->placementMatrixDS = ds; + result->m2CommonDS = ds; }); return result; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 610225aec..d4e6d0132 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -153,7 +153,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { class IM2ModelDataVLK : public IM2ModelData { public: ~IM2ModelDataVLK() override = default; - std::shared_ptr placementMatrixDS; + std::shared_ptr m2CommonDS; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index f3ca1a554..21e0c6547 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -39,6 +39,7 @@ static const ShaderConfig m2ForwardShaderConfig = { }}; const int m2TexturesBindlessCount = 4096; +const int m2WaterfallTexturesBindlessCount = 128; const int adtTexturesBindlessCount = 4096; static const ShaderConfig m2VisShaderConfig = { "visBuffer", @@ -50,6 +51,16 @@ static const ShaderConfig m2VisShaderConfig = { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; +static const ShaderConfig m2WaterfallVisShaderConfig = { + "visBuffer", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {3, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2WaterfallTexturesBindlessCount}} + }} + }}; static const ShaderConfig wmoVisShaderConfig = { "visBuffer", @@ -144,6 +155,9 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer("Scene_VBO_WMOAmbient",16*200, sizeof(mathfu::vec4_packed)); } + m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer("M2 Waterfall Common",200, sizeof(M2::WaterfallData::WaterfallCommon)); + m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer("M2 Waterfall Bindless",200, sizeof(M2::WaterfallData::WaterfallBindless)); + uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); @@ -168,53 +182,24 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); - sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); - MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) - .createDescriptorSet(0, [&](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo_dynamic(0, sceneWideChunk); - sceneWideDS = ds; - }); - - //Create global m2 descriptor for bindless textures - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) - .createDescriptorSet(1, [&](std::shared_ptr &ds) { - ds->beginUpdate() - .ssbo(1, m2Buffers.placementMatrix) - .ssbo(2, m2Buffers.modelFragmentDatas) - .ssbo(3, m2Buffers.boneMatrix) - .ssbo(4, m2Buffers.m2Colors) - .ssbo(5, m2Buffers.textureWeights) - .ssbo(6, m2Buffers.textureMatrices) - .ssbo(7, m2Buffers.m2InstanceData) - .ssbo(8, m2Buffers.meshWideBlocks) - .ssbo(9, m2Buffers.meshWideBlocksBindless); - - m2BufferOneDS = ds; - }) - .createDescriptorSet(2, [&](std::shared_ptr &ds) { - m2TextureDS = ds; - }); - m2TextureHolder = std::make_shared(m2TexturesBindlessCount); - - //Create global wmo descriptor for bindless textures - MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) - .createDescriptorSet(1, [&](std::shared_ptr &ds) { - ds->beginUpdate() - .ssbo(1, wmoBuffers.wmoPlacementMats) - .ssbo(2, wmoBuffers.wmoMeshWideVSes) - .ssbo(3, wmoBuffers.wmoMeshWidePSes) - .ssbo(4, wmoBuffers.wmoMeshWideBindless) - .ssbo(5, wmoBuffers.wmoGroupAmbient) - .ssbo(6, wmoBuffers.wmoPerMeshData); + { + //Create SceneWide descriptor + sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + .createDescriptorSet(0, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, sceneWideChunk); + sceneWideDS = ds; + }); + } - wmoBufferOneDS = ds; - }) - .createDescriptorSet(2, [&](std::shared_ptr &ds) { - wmoTexturesDS = ds; - }); - wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); + createM2GlobalMaterialData(); + createWMOGlobalMaterialData(); + createADTGlobalMaterialData(); + createM2WaterfallGlobalMaterialData(); +} +void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtAlphaTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -249,6 +234,62 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic } } +void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() {//Create global wmo descriptor for bindless textures + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, wmoBuffers.wmoPlacementMats) + .ssbo(2, wmoBuffers.wmoMeshWideVSes) + .ssbo(3, wmoBuffers.wmoMeshWidePSes) + .ssbo(4, wmoBuffers.wmoMeshWideBindless) + .ssbo(5, wmoBuffers.wmoGroupAmbient) + .ssbo(6, wmoBuffers.wmoPerMeshData); + + wmoBufferOneDS = ds; + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + wmoTexturesDS = ds; + }); + wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); +} + +void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() {//Create global m2 descriptor for bindless textures + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, m2Buffers.placementMatrix) + .ssbo(2, m2Buffers.modelFragmentDatas) + .ssbo(3, m2Buffers.boneMatrix) + .ssbo(4, m2Buffers.m2Colors) + .ssbo(5, m2Buffers.textureWeights) + .ssbo(6, m2Buffers.textureMatrices) + .ssbo(7, m2Buffers.m2InstanceData) + .ssbo(8, m2Buffers.meshWideBlocks) + .ssbo(9, m2Buffers.meshWideBlocksBindless); + + m2BufferOneDS = ds; + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + m2TextureDS = ds; + }); + m2TextureHolder = std::make_shared(m2TexturesBindlessCount); +} +void MapSceneRenderVisBufferVLK::createM2WaterfallGlobalMaterialData() { + MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallVisShaderConfig) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, m2WaterfallBuffer.waterfallCommon) + .ssbo(1, m2WaterfallBuffer.waterfallBindless); + + m2WaterfallBufferDS = ds; + }) + .createDescriptorSet(3, [&](std::shared_ptr &ds) { + m2WaterfallTextureDS = ds; + }); + + m2WaterfallTextureHolder = std::make_shared(m2WaterfallTexturesBindlessCount); +} + std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_m2StaticMaterials.find(pipelineTemplate); if (i != m_m2StaticMaterials.end()) { @@ -542,31 +583,53 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr std::shared_ptr MapSceneRenderVisBufferVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2WaterfallMaterialTemplate &m2MaterialTemplate) { + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + auto &l_sceneWideChunk = sceneWideChunk; - auto vertexData = std::make_shared>(uboStaticBuffer); - auto fragmentData = std::make_shared>(uboStaticBuffer); + auto commonData = std::make_shared>( + m2WaterfallBuffer.waterfallCommon); + auto bindlessData = std::make_shared>( + m2WaterfallBuffer.waterfallBindless); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, + m2WaterfallVisShaderConfig) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->placementMatrixDS) - .createDescriptorSet(2, [&m2ModelData, &vertexData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { - ds->beginUpdate() - .ubo(4, *vertexData) - .ubo(5, *fragmentData); - }) - .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { - ds->beginUpdate() - .texture(6, m2MaterialTemplate.textures[0]) - .texture(7, m2MaterialTemplate.textures[1]) - .texture(8, m2MaterialTemplate.textures[2]) - .texture(9, m2MaterialTemplate.textures[3]) - .texture(10, m2MaterialTemplate.textures[4]); - }) - .toMaterial([&vertexData, fragmentData](IM2WaterFallMaterial *instance) -> void { - instance->m_vertexData = vertexData; - instance->m_fragmentData = fragmentData; - }); + .bindDescriptorSet(1, m2BufferOneDS) + .bindDescriptorSet(2, m2WaterfallBufferDS) + .bindDescriptorSet(3, m2WaterfallTextureDS) + .toMaterial( + [&commonData, &bindlessData](IM2WaterFallMaterialBindless *instance) -> void { + instance->m_waterfallCommon = commonData; + instance->m_waterfallBindless = bindlessData; + }); + + { + auto dsUpdate = m2WaterfallTextureDS->beginUpdate(); + + for (int i = 0; i < 5; i++) { + auto bindlessText = m2WaterfallTextureHolder->allocate(m2MaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, m2MaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto &bindless = bindlessData->getObject(); + bindless.instanceIndex = BufferChunkHelperVLK::castToChunk(m2ModelDataVisVLK->m_instanceBindless)->getSubBuffer()->getIndex(); + bindless.waterfallInd = commonData->getIndex(); + + bindless.maskInd = material->m_bindlessText[0]->getIndex(); + bindless.whiteWaterInd = material->m_bindlessText[1]->getIndex(); + bindless.noiseInd = material->m_bindlessText[2]->getIndex(); + bindless.bumpTextureInd = material->m_bindlessText[3]->getIndex(); + bindless.normalTexInd = material->m_bindlessText[4]->getIndex(); + + + bindlessData->save(); + } + + material->instanceIndex = bindlessData->getIndex(); return material; } @@ -921,6 +984,9 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocks); uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocksBindless); + uploadCmd.submitBufferUploads(l_this->m2WaterfallBuffer.waterfallCommon); + uploadCmd.submitBufferUploads(l_this->m2WaterfallBuffer.waterfallBindless); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWidePSes); uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWideVSPSes); uploadCmd.submitBufferUploads(l_this->adtBuffers.adtInstanceDatas); @@ -1070,6 +1136,7 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } + HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { auto originalMat = std::dynamic_pointer_cast(material); @@ -1095,6 +1162,7 @@ HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTe const std::shared_ptr &material, int layer, int priorityPlane) { auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index c7b564361..5a4cd8407 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -160,6 +160,10 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK meshWideBlocks; HGBufferVLK meshWideBlocksBindless; } m2Buffers; + struct { + HGBufferVLK waterfallCommon; + HGBufferVLK waterfallBindless; + } m2WaterfallBuffer; struct { HGBufferVLK adtMeshWideVSPSes; @@ -191,6 +195,10 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr m2BufferOneDS = nullptr; + std::shared_ptr m2WaterfallBufferDS = nullptr; + std::shared_ptr m2WaterfallTextureDS = nullptr; + std::shared_ptr m2WaterfallTextureHolder = nullptr; + std::shared_ptr g_adtMaterial = nullptr; std::shared_ptr adtLayerTextureDS = nullptr; std::shared_ptr adtLayerTextureHolder = nullptr; @@ -219,6 +227,11 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWaterVAO = nullptr; std::shared_ptr defaultView; + + void createM2GlobalMaterialData(); + void createWMOGlobalMaterialData(); + void createADTGlobalMaterialData(); + void createM2WaterfallGlobalMaterialData(); }; class IM2ModelDataVisVLK : public IM2ModelData { From 7fc2d5d1ba0c3cd7c5d8e4c4ef72dac3e2c68b95 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 17 Oct 2023 21:55:07 +0300 Subject: [PATCH 138/212] - waterfall shader - no validation errors --- .../shaders/glsl/visBuffer/waterShader.frag | 1 - .../shaders/glsl/visBuffer/waterShader.vert | 5 +- .../src/engine/shader/ShaderDefinitions.h | 192 ++++++++++++++++-- .../src/gapi/vulkan/GDeviceVulkan.cpp | 10 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 3 + .../CommandBufferRecorder.cpp | 2 +- .../CommandBufferRecorder.h | 2 +- .../CommandBufferRecorder_inline.h | 2 +- .../descriptorSets/GDescriptorSetLayout.cpp | 7 +- .../vulkan/materials/ISimpleMaterialVLK.cpp | 4 +- .../vulkan/materials/ISimpleMaterialVLK.h | 6 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 20 +- .../vulkan/materials/MaterialBuilderVLK.h | 9 +- .../src/gapi/vulkan/meshes/GM2MeshVLK.cpp | 2 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 2 +- .../vulkan/pipeline/GPipelineLayoutVLK.cpp | 18 ++ .../gapi/vulkan/pipeline/GPipelineLayoutVLK.h | 23 +++ .../vulkan/{ => pipeline}/GPipelineVLK.cpp | 9 +- .../gapi/vulkan/{ => pipeline}/GPipelineVLK.h | 14 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 18 +- .../vulkan/shaders/GShaderPermutationVLK.h | 9 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 26 ++- .../vulkan/materials/IMaterialInstance.h | 2 +- 23 files changed, 310 insertions(+), 76 deletions(-) create mode 100644 wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.h rename wowViewerLib/src/gapi/vulkan/{ => pipeline}/GPipelineVLK.cpp (98%) rename wowViewerLib/src/gapi/vulkan/{ => pipeline}/GPipelineVLK.h (80%) diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag index 183c9cc4f..56bb0144d 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag @@ -42,7 +42,6 @@ void main() { // 18 - Azerithe // 8 - is probably debug material called Grid - vec2 animatedUV = (textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; vec3 matDiffuse = color.rgb+texture(uTexture, animatedUV).rgb; diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert index ac9658f93..99ecbc447 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert @@ -12,10 +12,7 @@ precision highp int; layout(location=0) in vec4 aPositionTransp; layout(location=1) in vec2 aTexCoord; - - - -layout(std140, set=1, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=1) buffer modelWideBlockVS { mat4 uPlacementMat; }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 7e3584ccd..9e426ba66 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -318,9 +318,14 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, + {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, }, { }, @@ -427,6 +432,9 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { @@ -558,6 +566,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -743,6 +756,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -820,10 +835,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -841,11 +857,17 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { {0,0,1}, - {0,0,0}, + {1,6,6}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -880,10 +902,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1005,6 +1028,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1027,10 +1059,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1200,6 +1233,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1223,12 +1258,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1238,6 +1272,7 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,1,64}, }, { }, @@ -1282,6 +1317,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1341,11 +1377,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1393,10 +1430,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1614,6 +1653,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, + {1,3,16384}, }, { { @@ -1670,6 +1710,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -1950,12 +1991,17 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {1,3,3}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2060,10 +2106,32 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, { 7, { } }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, @@ -2095,13 +2163,17 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2484,12 +2620,7 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -1415,6 +1415,7 @@ std::shared_ptr GDeviceVLK::getSwapChainRenderPass() { HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings, const HGShaderPermutation &shader, + const std::shared_ptr &pipelineLayout, const std::shared_ptr &renderPass, DrawElementMode element, bool backFaceCulling, @@ -1426,12 +1427,13 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings PipelineCacheRecord pipelineCacheRecord = { .shader = shader, .renderPass = std::weak_ptr(renderPass), + .pipelineLayout = std::weak_ptr(pipelineLayout), .element = element, .backFaceCulling = backFaceCulling, .triCCW = triCCW, .blendMode = blendMode, .depthCulling = depthCulling, - .depthWrite = depthWrite + .depthWrite = depthWrite, }; auto i = loadedPipeLines.find(pipelineCacheRecord); @@ -1444,7 +1446,7 @@ HPipelineVLK GDeviceVLK::createPipeline(const HGVertexBufferBindings &m_bindings } std::shared_ptr hgPipeline = std::make_shared(*this, - m_bindings, renderPass, + m_bindings, renderPass, pipelineLayout, shader, element, backFaceCulling, triCCW, diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index cdbf049ab..ff5267b5e 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -18,6 +18,7 @@ class GShaderPermutationVLK; class GMeshVLK; class GM2MeshVLK; class GPipelineVLK; +class GPipelineLayoutVLK; class GRenderPassVLK; class GDescriptorPoolVLK; class CmdBufRecorder; @@ -119,6 +120,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this &pipelineLayout, const std::shared_ptr &renderPass, DrawElementMode element, bool backFaceCulling, @@ -217,6 +219,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this> renderPass; + wtf::KeyContainer> pipelineLayout; DrawElementMode element; bool backFaceCulling; bool triCCW; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index eba89224a..ab2114fbd 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -4,7 +4,7 @@ #include "CommandBufferRecorder.h" #include "CommandBufferRecorder_inline.h" -#include "../../GPipelineVLK.h" +#include "../../pipeline/GPipelineVLK.h" // ---------------------------------------- // CmdBufRecorder diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index e0f663388..622e67bcd 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -22,7 +22,7 @@ class CommandBufferDebugLabel; #include "RenderPassHelper.h" #include "CommandBufferDebugLabel.h" #include "../../descriptorSets/GDescriptorSet.h" -#include "../../GPipelineVLK.h" +#include "../../pipeline/GPipelineVLK.h" #include "../../materials/ISimpleMaterialVLK.h" #ifdef LINK_TRACY diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h index d47cf4c62..ee7275ce4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h @@ -14,7 +14,7 @@ inline void CmdBufRecorder::bindPipeline(const std::shared_ptr &pi vkCmdBindPipeline(m_gCmdBuffer.m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pPipelineVlk->getPipeline()); m_currentPipeline = pPipelineVlk; - m_currentPipelineLayout = pipeline->getLayout(); + m_currentPipelineLayout = pipeline->getLayout()->getLayout(); } inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, const std::vector> &descriptorSets) { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index ed8d94c4c..839844ecd 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -257,5 +257,10 @@ void GDescriptorSetLayout::fillSSBO(int setIndex, const DescTypeOverride &typeOv } GDescriptorSetLayout::~GDescriptorSetLayout() { - vkDestroyDescriptorSetLayout(m_device->getVkDevice(), m_descriptorSetLayout, nullptr); + auto l_device = m_device->getVkDevice(); + auto l_descriptorSetLayout = m_descriptorSetLayout; + m_device->addDeallocationRecord([l_device, l_descriptorSetLayout]{ + vkDestroyDescriptorSetLayout(l_device, l_descriptorSetLayout, nullptr); + + }); } diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index a60e39481..93a7f3fb9 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -5,10 +5,10 @@ #include "ISimpleMaterialVLK.h" #include "../shaders/GShaderPermutationVLK.h" #include "../textures/GTextureVLK.h" -#include "../GPipelineVLK.h" +#include "../pipeline/GPipelineVLK.h" -ISimpleMaterialVLK::ISimpleMaterialVLK(const HGShaderPermutation &shader, +ISimpleMaterialVLK::ISimpleMaterialVLK(const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index edcb8dc0b..cea0f9309 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -15,13 +15,13 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this { public: - explicit ISimpleMaterialVLK(const HGShaderPermutation &shader, + explicit ISimpleMaterialVLK(const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); ~ISimpleMaterialVLK() override = default; - const HGShaderPermutation &getShader() const { + const std::shared_ptr &getShader() const { return m_shader; } @@ -40,7 +40,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this private: std::vector> descriptors; - HGShaderPermutation m_shader; + std::shared_ptr m_shader; HPipelineVLK m_pipeline; PipelineTemplate m_pipelineTemplate; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index 2e55935d2..253638046 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -10,26 +10,29 @@ MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &device, const std::vector &shaderFiles, const ShaderConfig &shaderConfig) : m_device(device) { - m_shader = std::dynamic_pointer_cast(device)->getShader( + m_shader = std::dynamic_pointer_cast(std::dynamic_pointer_cast(device)->getShader( shaderFiles[0], - shaderFiles[1], shaderConfig); + shaderFiles[1], shaderConfig)); + + m_pipelineLayout = m_shader->getPipelineLayout(); } MaterialBuilderVLK::MaterialBuilderVLK( const std::shared_ptr &device, - const HGShaderPermutation &shader, + const std::shared_ptr &shader, const HPipelineVLK &pipeline, + const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : m_device(device), m_shader(shader), m_pipeline(pipeline), m_pipelineTemplate(pipelineTemplate), - m_descriptorSets(descriptorSets) { + m_descriptorSets(descriptorSets), m_pipelineLayout(pipelineLayout) { } MaterialBuilderVLK &MaterialBuilderVLK::createDescriptorSet(int bindPoint, const std::function &ds)> &callback) { - auto shaderVLK = std::dynamic_pointer_cast(m_shader); + auto shaderVLK = m_shader; auto ds = std::make_shared(m_device, shaderVLK->getDescriptorLayout(bindPoint)); callback(ds); @@ -47,6 +50,12 @@ MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::sh return *this; } +MaterialBuilderVLK& MaterialBuilderVLK::overridePipelineLayout(const std::unordered_map> &dses) { + m_pipelineLayout = m_shader->createPipelineLayoutOverrided(dses); + + return *this; +} + MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindings &bindings, const std::shared_ptr &renderPass, const PipelineTemplate &pipelineTemplate) { @@ -55,6 +64,7 @@ MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindi m_pipeline = std::dynamic_pointer_cast(m_device)->createPipeline( bindings, m_shader, + m_pipelineLayout, renderPass, pipelineTemplate.element, pipelineTemplate.backFaceCulling, diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index e0429dff1..0384a1567 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -26,11 +26,12 @@ class MaterialBuilderVLK { const std::shared_ptr &materialVlk) { return {device, materialVlk->getShader(), materialVlk->getPipeline(), + materialVlk->getPipeline()->getLayout(), materialVlk->getPipelineTemplate(), toArray(materialVlk->getDescriptorSets()) }; } - + MaterialBuilderVLK& overridePipelineLayout(const std::unordered_map> &dses); MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); MaterialBuilderVLK& createDescriptorSet(int bindPoint, const std::function &ds)> &callback); MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, @@ -60,8 +61,9 @@ class MaterialBuilderVLK { const std::vector &shaderFiles, const ShaderConfig &shaderConfig); MaterialBuilderVLK(const std::shared_ptr &device, - const HGShaderPermutation &shader, + const std::shared_ptr &shader, const HPipelineVLK &pipeline, + const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); @@ -70,8 +72,9 @@ class MaterialBuilderVLK { //States const std::shared_ptr &m_device; - HGShaderPermutation m_shader; + std::shared_ptr m_shader; HPipelineVLK m_pipeline; + std::shared_ptr m_pipelineLayout; PipelineTemplate m_pipelineTemplate; std::array, MAX_SHADER_DESC_SETS> m_descriptorSets; }; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp index 8c67f497e..3aa267e22 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GM2MeshVLK.cpp @@ -3,6 +3,6 @@ // #include "GM2MeshVLK.h" -#include "../GPipelineVLK.h" +#include "../pipeline/GPipelineVLK.h" diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index 5a9dcbeda..a2819e3d0 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -7,7 +7,7 @@ #include "GMeshVLK.h" #include "../textures/GTextureVLK.h" #include "../shaders/GShaderPermutationVLK.h" -#include "../GPipelineVLK.h" +#include "../pipeline/GPipelineVLK.h" GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, const HMaterialVLK &material, int layer, int priority) : diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.cpp b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.cpp new file mode 100644 index 000000000..e1a4f5b60 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.cpp @@ -0,0 +1,18 @@ +// +// Created by Deamon on 10/17/2023. +// + +#include "GPipelineLayoutVLK.h" + +GPipelineLayoutVLK::GPipelineLayoutVLK(IDevice &device, VkPipelineLayout layout) : + m_layout(layout), m_device(dynamic_cast(device)) { + +} + +GPipelineLayoutVLK::~GPipelineLayoutVLK() { + auto l_layout = m_layout; + auto l_vkDevice = m_device.getVkDevice(); + m_device.addDeallocationRecord([l_layout, l_vkDevice]() { + vkDestroyPipelineLayout(l_vkDevice, l_layout, nullptr); + }); +} diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.h b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.h new file mode 100644 index 000000000..acae36da8 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineLayoutVLK.h @@ -0,0 +1,23 @@ +// +// Created by Deamon on 10/17/2023. +// + +#ifndef AWEBWOWVIEWERCPP_GPIPELINELAYOUTVLK_H +#define AWEBWOWVIEWERCPP_GPIPELINELAYOUTVLK_H + +#include "../../interface/IDevice.h" +#include "../GDeviceVulkan.h" + +class GPipelineLayoutVLK { +public: + GPipelineLayoutVLK(IDevice &device, VkPipelineLayout layout);; + ~GPipelineLayoutVLK(); + + VkPipelineLayout getLayout() {return m_layout;} +private: + GDeviceVLK &m_device; + VkPipelineLayout m_layout; +}; + + +#endif //AWEBWOWVIEWERCPP_GPIPELINELAYOUTVLK_H diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp similarity index 98% rename from wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp rename to wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp index 15822fc6a..8822b7214 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp @@ -4,9 +4,9 @@ #include #include "GPipelineVLK.h" -#include "shaders/GShaderPermutationVLK.h" +#include "../shaders/GShaderPermutationVLK.h" #include -#include "GRenderPassVLK.h" +#include "../GRenderPassVLK.h" struct BlendModeDescVLK { bool blendModeEnable; @@ -36,6 +36,7 @@ BlendModeDescVLK blendModesVLK[(int)EGxBlendEnum::GxBlend_MAX] = { GPipelineVLK::GPipelineVLK(IDevice &device, const HGVertexBufferBindings &m_bindings, const std::shared_ptr &renderPass, + const std::shared_ptr &pipelineLayout, const HGShaderPermutation &shader, DrawElementMode element, bool backFaceCulling, @@ -57,7 +58,7 @@ GPipelineVLK::GPipelineVLK(IDevice &device, } GShaderPermutationVLK* shaderVLK = reinterpret_cast(shader.get()); - m_pipelineLayout = shaderVLK->getPipelineLayout(); + m_pipelineLayout = pipelineLayout; m_isTransparent = blendMode > EGxBlendEnum::GxBlend_AlphaKey || !depthWrite; @@ -236,7 +237,7 @@ void GPipelineVLK::createPipeline( pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDepthStencilState = &depthStencil; pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.layout = shaderVLK->getPipelineLayout(); + pipelineInfo.layout = m_pipelineLayout->getLayout(); pipelineInfo.renderPass = renderPass->getRenderPass(); pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; diff --git a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h similarity index 80% rename from wowViewerLib/src/gapi/vulkan/GPipelineVLK.h rename to wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h index 54ac6c8bc..aca67efec 100644 --- a/wowViewerLib/src/gapi/vulkan/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h @@ -5,9 +5,12 @@ #ifndef AWEBWOWVIEWERCPP_GPIPELINEVLK_H #define AWEBWOWVIEWERCPP_GPIPELINEVLK_H -#include "../interface/IDevice.h" -#include "GDeviceVulkan.h" -#include "GVertexBufferBindingsVLK.h" +class GPipelineLayoutVLK; + +#include "../../interface/IDevice.h" +#include "../GDeviceVulkan.h" +#include "../GVertexBufferBindingsVLK.h" +#include "GPipelineLayoutVLK.h" class GPipelineVLK { friend class GDeviceVLK; @@ -15,6 +18,7 @@ class GPipelineVLK { explicit GPipelineVLK(IDevice &m_device, const HGVertexBufferBindings &m_bindings, const std::shared_ptr &renderPass, + const std::shared_ptr &pipelineLayout, const HGShaderPermutation &shader, DrawElementMode element, bool backFaceCulling, @@ -37,7 +41,7 @@ class GPipelineVLK { const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions); - VkPipelineLayout getLayout() { return m_pipelineLayout; }; + std::shared_ptr getLayout() { return m_pipelineLayout; }; VkPipeline getPipeline() { return graphicsPipeline; }; bool getIsTransparent() const { return m_isTransparent; @@ -49,7 +53,7 @@ class GPipelineVLK { private: GDeviceVLK &m_device; - VkPipelineLayout m_pipelineLayout; + std::shared_ptr m_pipelineLayout; VkPipeline graphicsPipeline; std::shared_ptr m_renderPass; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index dba8be632..f002c5d74 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -179,12 +179,17 @@ void GShaderPermutationVLK::createShaderLayout() { } } } - -void GShaderPermutationVLK::createPipelineLayout() { +std::shared_ptr +GShaderPermutationVLK::createPipelineLayoutOverrided(const std::unordered_map> &dses) { std::vector descLayouts; descLayouts.reserve(combinedShaderLayout.setLayouts.size()); for (int i = 0; i < combinedShaderLayout.setLayouts.size(); i++) { - descLayouts.push_back(this->getDescriptorLayout(i)->getSetLayout()); + + if (dses.find(i) != dses.end()) { + descLayouts.push_back(dses.at(i)->getDescSetLayout()->getSetLayout()); + } else { + descLayouts.push_back(this->getDescriptorLayout(i)->getSetLayout()); + } }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; @@ -197,12 +202,19 @@ void GShaderPermutationVLK::createPipelineLayout() { std::cout << "Pipeline layout for "+this->getShaderCombinedName() << std::endl; + VkPipelineLayout pipelineLayout; if (vkCreatePipelineLayout(m_device->getVkDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create pipeline layout!"); } auto combinedName = this->getShaderCombinedName(); m_device->setObjectName(reinterpret_cast(pipelineLayout), VK_OBJECT_TYPE_PIPELINE_LAYOUT, combinedName.c_str()); + + return std::make_shared(*m_device, pipelineLayout); +} + +void GShaderPermutationVLK::createPipelineLayout() { + m_pipelineLayout = createPipelineLayoutOverrided({}); } const std::shared_ptr diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index 0e44441ba..ec2494f4e 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -50,10 +50,12 @@ class GShaderPermutationVLK : public IShaderPermutation { return combinedShaderLayout; }; - VkPipelineLayout getPipelineLayout() { - return pipelineLayout; + std::shared_ptr getPipelineLayout() { + return m_pipelineLayout; } + std::shared_ptr createPipelineLayoutOverrided(const std::unordered_map> &dses); + protected: VkShaderModule createShaderModule(const std::vector& code); @@ -63,7 +65,7 @@ class GShaderPermutationVLK : public IShaderPermutation { VkShaderModule vertShaderModule; VkShaderModule fragShaderModule; - VkPipelineLayout pipelineLayout; + std::shared_ptr m_pipelineLayout; std::array, MAX_SHADER_DESC_SETS> descriptorSetLayouts = {}; @@ -84,6 +86,7 @@ class GShaderPermutationVLK : public IShaderPermutation { std::vector createMetaArray(); void createShaderLayout(); void createPipelineLayout(); + }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 21e0c6547..93e4616ef 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -27,17 +27,6 @@ static const ShaderConfig forwardShaderConfig = { } }; -static const ShaderConfig m2ForwardShaderConfig = { - "forwardRendering", - { - {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} - }}, - {1, { - {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} - }} - }}; - const int m2TexturesBindlessCount = 4096; const int m2WaterfallTexturesBindlessCount = 128; const int adtTexturesBindlessCount = 4096; @@ -51,6 +40,14 @@ static const ShaderConfig m2VisShaderConfig = { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; +static const ShaderConfig visShaderConfig = { + "visBuffer", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + }}; + static const ShaderConfig m2WaterfallVisShaderConfig = { "visBuffer", { @@ -593,6 +590,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Waterf auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallVisShaderConfig) + .overridePipelineLayout({{1, m2BufferOneDS}}) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) @@ -749,12 +747,12 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial( auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, visShaderConfig) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { + .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData, this](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, BufferChunkHelperVLK::cast(modelWide)) + .ssbo(1, wmoBuffers.wmoPlacementMats) .ubo(4, *l_fragmentData); }) .createDescriptorSet(2, [&waterMaterialTemplate](std::shared_ptr &ds) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h index bc0c70292..e6bc5a29e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h @@ -14,7 +14,7 @@ class IMaterialInstance : public ISimpleMaterialVLK, public IMaterialClass { public: inline IMaterialInstance( const std::function &initializer, - const HGShaderPermutation &shader, + const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : From 047b3a5a4a4a2f52d50963d1f9d71ce39ec3afda Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 18 Oct 2023 03:52:17 +0300 Subject: [PATCH 139/212] - fix error in handling offsetAllocator - water shader bindless --- .../OffsetAllocator/offsetAllocator.cpp | 2 +- .../OffsetAllocator/offsetAllocator.hpp | 9 +- wowViewerLib/CMakeLists.txt | 14 +- .../commonAdtIndirectDescriptorSet.glsl | 6 +- .../commonM2WaterfallDescriptorSet.glsl | 4 +- .../commonWMOIndirectDescriptorSet.glsl | 12 +- .../glsl/common/commonWaterIndirect.glsl | 29 +++ .../shaders/glsl/visBuffer/m2Shader.vert | 1 - .../shaders/glsl/visBuffer/waterShader.frag | 23 +- .../shaders/glsl/visBuffer/waterShader.vert | 11 +- .../engine/objects/liquid/LiquidInstance.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 232 +++--------------- .../src/gapi/UniformBufferStructures.h | 7 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- .../CommandBufferRecorder_inline.h | 6 + .../vulkan/shaders/GShaderPermutationVLK.cpp | 104 ++++---- .../vulkan/shaders/GShaderPermutationVLK.h | 7 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 1 + .../mapScene/materials/IMaterialStructs.h | 7 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 92 ++++++- .../vulkan/MapSceneRenderVisBufferVLK.h | 10 + 22 files changed, 270 insertions(+), 313 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp index 81115aa11..33370cd30 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.cpp @@ -145,7 +145,7 @@ namespace OffsetAllocator reset(); } - Allocator::Allocator(Allocator &&other) : + Allocator::Allocator(Allocator &other) : m_size(other.m_size), m_maxAllocs(other.m_maxAllocs), m_freeStorage(other.m_freeStorage), diff --git a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp index 1d4c87605..9755a2f52 100644 --- a/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp +++ b/wowViewerLib/3rdparty/OffsetAllocator/offsetAllocator.hpp @@ -58,15 +58,8 @@ namespace OffsetAllocator { public: Allocator(uint32 size, uint32 maxAllocs = 1024); - Allocator(Allocator &&other); - // user-defined copy assignment (copy-and-swap idiom) - Allocator& operator=(Allocator &&other) noexcept - { - Allocator(std::move(other)); - - return *this; - } + Allocator(Allocator &other); ~Allocator(); void reset(); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index cce982689..7c0b8ed9e 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -14,7 +14,7 @@ set(LINK_EGL 1) option(LINK_VULKAN "Enable Vulkan" ON) set(LINK_OPENMP 0) set(ENABLE_SIMD 1) -set(LINK_TRACY 0) +set(LINK_TRACY 1) set(COMPILE_SHADER_WITH_DEBUG 0) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(COMPILE_SHADER_WITH_DEBUG 1) @@ -100,7 +100,9 @@ if (EMSCRIPTEN) else() set(My_Vectorize_Compile_Options "${My_Vectorize_Compile_Options};-msse3;-mavx2;-ftree-vectorize") - if (NOT MSVC AND NOT MSVC_VERSION) + message(MSVC = "${MSVC}") + message(MSVC_VERSION = "${MSVC_VERSION}") + if (NOT DEFINED MSVC AND NOT DEFINED MSVC_VERSION) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-multichar") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-multichar") @@ -500,7 +502,10 @@ if (LINK_VULKAN) src/gapi/vulkan/meshes/GMeshVLK.cpp src/gapi/vulkan/textures/GTextureVLK.cpp src/gapi/vulkan/textures/GBlpTextureVLK.cpp - src/gapi/vulkan/GPipelineVLK.cpp src/gapi/vulkan/GPipelineVLK.h + src/gapi/vulkan/pipeline/GPipelineVLK.cpp + src/gapi/vulkan/pipeline/GPipelineVLK.h + src/gapi/vulkan/pipeline/GPipelineLayoutVLK.cpp + src/gapi/vulkan/pipeline/GPipelineLayoutVLK.h src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.cpp src/gapi/vulkan/descriptorSets/GDescriptorPoolVLK.h src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -572,7 +577,8 @@ if (LINK_VULKAN) src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp - src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h) + src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h +) message(VULKAN_SDK = $ENV{VULKAN_SDK}) find_package(Vulkan) diff --git a/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl index d4c3c33c0..3758ea309 100644 --- a/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl @@ -8,7 +8,7 @@ struct AdtMeshWideVSPS { vec4 uHeightOffset; }; -layout(std140, set=1, binding=1) buffer readonly meshWideBlockVSPS { +layout(std430, set=1, binding=1) buffer readonly meshWideBlockVSPS { AdtMeshWideVSPS adtMeshWideVSPSes[]; }; @@ -18,7 +18,7 @@ struct AdtMeshWidePS { ivec4 animation_speedPerLayer; }; -layout(std140, set=1, binding=2) buffer readonly meshWideBlockPS { +layout(std430, set=1, binding=2) buffer readonly meshWideBlockPS { AdtMeshWidePS adtMeshWidePSes[]; }; @@ -29,7 +29,7 @@ struct AdtInstanceData { ivec4 LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind; }; -layout(std140, set=1, binding=3) buffer readonly instanceData { +layout(std430, set=1, binding=3) buffer readonly instanceData { AdtInstanceData adtInstanceDatas[]; }; diff --git a/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl index f1dd179cd..47e8b6c2e 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2WaterfallDescriptorSet.glsl @@ -11,7 +11,7 @@ struct WaterfallCommon { vec4 baseColor; }; -layout(std140, set=2, binding=0) buffer waterfallCommonData { +layout(std430, set=2, binding=0) buffer readonly waterfallCommonData { WaterfallCommon waterfallCommons[]; }; @@ -20,7 +20,7 @@ struct WaterfallBindless { ivec4 whiteWaterInd_noiseInd_normalTexInd; }; -layout(std140, set=2, binding=1) buffer waterfallBindless { +layout(std430, set=2, binding=1) buffer readonly waterfallBindless { WaterfallBindless waterfallBindlesses[]; }; diff --git a/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl index 0a0c48f08..c0c5b01ab 100644 --- a/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWMOIndirectDescriptorSet.glsl @@ -1,11 +1,11 @@ #ifndef COMMON_WMO_INDIRECT_DS #define COMMON_WMO_INDIRECT_DS -layout(std140, set=1, binding=1) buffer modelWideBlockVS { +layout(std430, set=1, binding=1) buffer readonly modelWideBlockVS { mat4 uPlacementMats[]; }; -layout(std140, set=1, binding=2) buffer meshWideBlockVS { +layout(std430, set=1, binding=2) buffer readonly meshWideBlockVS { ivec4 VertexShader_UseLitColors[]; }; @@ -14,7 +14,7 @@ struct WmoMeshWide { vec4 FogColor_AlphaTest; }; -layout(std140, set=1, binding=3) buffer meshWideBlockPS { +layout(std430, set=1, binding=3) buffer readonly meshWideBlockPS { WmoMeshWide wmoMeshWides[]; }; @@ -24,11 +24,11 @@ struct WmoMeshWideBindless { ivec4 text5_text6_text7_text8; }; -layout(std140, set=1, binding=4) buffer meshWideBlockBindlessPS { +layout(std430, set=1, binding=4) buffer readonly meshWideBlockBindlessPS { WmoMeshWideBindless wmoMeshWideBindlesses[]; }; -layout(std140, set=1, binding=5) buffer wmoLocalAmbient { +layout(std430, set=1, binding=5) buffer readonly wmoLocalAmbient { vec4 s_wmoAmbient[]; }; @@ -36,7 +36,7 @@ struct WMOPerMeshData { ivec4 meshWideBindlessIndex_wmoAmbientIndex; }; -layout(std140, set=1, binding=6) buffer _wmoPerMeshData { +layout(std430, set=1, binding=6) buffer readonly _wmoPerMeshData { WMOPerMeshData perMeshDatas[]; }; diff --git a/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl b/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl new file mode 100644 index 000000000..1caa215bd --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl @@ -0,0 +1,29 @@ +#ifndef COMMON_WATER_INDIRECT +#define COMMON_WATER_INDIRECT + +struct WaterData { + ivec4 materialId; + vec4 color; + mat4 textureMatrix; +}; + +//Individual meshes +layout(std430, set=1, binding=0) buffer waterData { + WaterData waterDatas[]; +}; + +layout(std430, set=1, binding=1) buffer placementMats { + mat4 uPlacementMats[]; +}; + +struct WaterBindless { + ivec4 waterDataInd_placementMatInd_textureInd; +}; + +layout(std430, set=1, binding=2) buffer waterBindless { + WaterBindless waterBindlesses[]; +}; + +layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; + +#endif //COMMON_WATER_INDIRECT \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert index 51419af7a..cc0b09743 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert @@ -39,7 +39,6 @@ void main() { mat4 boneTransformMat = mat4(0.0); meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[gl_InstanceIndex]; - meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; if (dot(boneWeights, boneWeights) > 0) { diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag index 56bb0144d..c5f593bcf 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" @@ -11,19 +12,12 @@ precision highp int; layout(location=0) in vec3 vPosition; layout(location=1) in vec2 vTextCoords; layout(location=2) in vec3 vNormal; - -layout(location=0) out vec4 outputColor; - -layout(set=2,binding=5) uniform sampler2D uTexture; +layout(location=3) in flat int meshInd; #include "../common/commonUboSceneData.glsl" +#include "../common/commonWaterIndirect.glsl" -//Individual meshes -layout(std140, set=1, binding=4) uniform meshWideBlockPS { - ivec4 materialId; - vec4 color; - mat4 textureMatrix; -}; +layout(location=0) out vec4 outputColor; const InteriorLightParam intLight = { vec4(0,0,0,0), @@ -31,6 +25,9 @@ const InteriorLightParam intLight = { }; void main() { + WaterBindless waterBindless = waterBindlesses[meshInd]; + WaterData waterData = waterDatas[waterBindless.waterDataInd_placementMatInd_textureInd.x]; + // MaterialId: // 1,3 - Water // 2,4 - Magma @@ -42,9 +39,9 @@ void main() { // 18 - Azerithe // 8 - is probably debug material called Grid - vec2 animatedUV = (textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; + vec2 animatedUV = (waterData.textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; - vec3 matDiffuse = color.rgb+texture(uTexture, animatedUV).rgb; + vec3 matDiffuse = waterData.color.rgb+texture(s_Textures[waterBindless.waterDataInd_placementMatInd_textureInd.z], animatedUV).rgb; vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; @@ -52,7 +49,7 @@ void main() { vec4 finalColor = vec4(matDiffuse, 1.0); //Magma is not affected by light - if (materialId.x != 2 && materialId.x != 4) { + if (waterData.materialId.x != 2 && waterData.materialId.x != 4) { finalColor = vec4( calcLight( matDiffuse, diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert index 99ecbc447..cd28fabe6 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require precision highp float; precision highp int; @@ -12,18 +13,19 @@ precision highp int; layout(location=0) in vec4 aPositionTransp; layout(location=1) in vec2 aTexCoord; -layout(std140, set=1, binding=1) buffer modelWideBlockVS { - mat4 uPlacementMat; -}; +#include "../common/commonWaterIndirect.glsl" //out vec2 vTexCoord; layout(location=0) out vec3 vPosition; layout(location=1) out vec2 vTextCoords; layout(location=2) out vec3 vNormal; +layout(location=3) out flat int meshInd; void main() { + WaterBindless waterBindless = waterBindlesses[gl_InstanceIndex]; + vec4 aPositionVec4 = vec4(aPositionTransp.xyz, 1); - mat4 viewModelMat = scene.uLookAtMat * uPlacementMat; + mat4 viewModelMat = scene.uLookAtMat * uPlacementMats[waterBindless.waterDataInd_placementMatInd_textureInd.y]; vec4 cameraPoint = viewModelMat * aPositionVec4; @@ -37,4 +39,5 @@ void main() { vPosition = cameraPoint.xyz; vNormal = normalize(viewModelMatForNormal * vec4(vec3(0,0,1.0), 0.0)).xyz; + meshInd = gl_InstanceIndex; } diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 0d969d240..5666335e7 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -103,7 +103,7 @@ void LiquidInstance::createMaterialAndMesh(const HMapSceneBufferCreate &sceneRen meshTemplate.start = 0; meshTemplate.end = indexBufferSize; - auto mesh = sceneRenderer->createSortableMesh(meshTemplate, waterMaterial, 99); + auto mesh = sceneRenderer->createWaterMesh(meshTemplate, waterMaterial, 99); m_liquidMeshes.push_back(mesh); } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 9e426ba66..49aa5607c 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -318,14 +318,9 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, - {1,8,0}, {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, }, { }, @@ -432,9 +427,6 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { @@ -566,11 +558,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -756,8 +743,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -779,13 +764,12 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,96}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,15 +779,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, }, { - {2,5, "uTexture"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -835,11 +821,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -857,17 +842,11 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, + {0,0,0}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -902,11 +881,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1028,15 +1006,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1059,11 +1028,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1233,8 +1201,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1272,7 +1238,8 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,1,64}, + {1,2,0}, + {1,1,0}, }, { }, @@ -1317,7 +1284,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1377,12 +1343,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1430,12 +1395,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1653,7 +1616,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, - {1,3,16384}, }, { { @@ -1710,7 +1672,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -1991,17 +1952,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2106,32 +2062,10 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, { 7, { } }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, @@ -2163,17 +2097,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2620,7 +2490,12 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 8e845312b..fde63e24c 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -17,7 +17,7 @@ GBufferVLK::GBufferVLK(const HGDeviceVLK &device, const char *objName, m_objName = objName; //Create virtual buffer off this native buffer - auto allocator = OffsetAllocator::Allocator(m_bufferSize); + auto allocator =OffsetAllocator::Allocator(m_bufferSize); offsetAllocator = std::move(allocator); m_gpuBuffer = std::make_shared(m_device, maxSize, m_usageFlags, m_objName.c_str()); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h index ee7275ce4..d483a2035 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h @@ -38,6 +38,12 @@ inline void CmdBufRecorder::bindDescriptorSets(VkPipelineBindPoint bindPoint, co if (m_currentDescriptorSet[i] != pDescriptorSet) { bindIndexStart = bindIndexStart==-1 ? i : bindIndexStart; + if (m_currentDescriptorSet[i] != nullptr && m_currentDescriptorSet[i]->getDescSetLayout() != pDescriptorSet->getDescSetLayout()) { + //The DS was disturbed due to Pipeline Layout Compatibility + for (int j = i+1; j < 16; j++) + m_currentDescriptorSet[j] = nullptr; + } + auto vkDescSet = pDescriptorSet->getDescSet(); descs[descAmount++] = vkDescSet; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index f002c5d74..64b3ea386 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -69,8 +69,8 @@ void GShaderPermutationVLK::createSetDescriptorLayouts() { } void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const std::string &fragExtraDef) { - std::string vertShaderName = m_shaderConf.shaderFolder +"/" + m_shaderNameVert; - std::string vertShaderFrag = m_shaderConf.shaderFolder +"/" + m_shaderNameFrag; + vertShaderName = m_shaderConf.shaderFolder +"/" + m_shaderNameVert; + vertShaderFrag = m_shaderConf.shaderFolder +"/" + m_shaderNameFrag; auto vertShaderCode = readFile("spirv/" + vertShaderName + ".vert.spv"); auto fragShaderCode = readFile("spirv/" + vertShaderFrag + ".frag.spv"); @@ -97,68 +97,70 @@ inline void makeMax(unsigned int &a, const unsigned int b) { void GShaderPermutationVLK::createShaderLayout() { //UBO stuff - for (int i = 0; i < this->vertShaderMeta->uboBindings.size(); i++) { - auto &uboVertBinding = this->vertShaderMeta->uboBindings[i]; + auto metaArray = createMetaArray(); - auto &setLayout = combinedShaderLayout.setLayouts[uboVertBinding.set]; + for (auto const &shaderMeta : metaArray) { - setLayout.uboSizesPerBinding[uboVertBinding.binding] = uboVertBinding.size; - makeMin(setLayout.uboBindings.start, uboVertBinding.binding); - makeMax(setLayout.uboBindings.end, uboVertBinding.binding); - } - for (int i = 0; i < this->fragShaderMeta->uboBindings.size(); i++) { - auto &uboFragBinding = this->fragShaderMeta->uboBindings[i]; + for (int i = 0; i < shaderMeta->uboBindings.size(); i++) { + auto &uboBinding = shaderMeta->uboBindings[i]; - auto &setLayout = combinedShaderLayout.setLayouts[uboFragBinding.set]; + auto &setLayout = combinedShaderLayout.setLayouts[uboBinding.set]; - auto it = setLayout.uboSizesPerBinding.find(uboFragBinding.binding); - if (it != std::end(setLayout.uboSizesPerBinding)) { - if (it->second != uboFragBinding.size) { - std::cerr << "sizes mismatch for set = " << uboFragBinding.set - << " binding = " << uboFragBinding.binding - << " between " << m_shaderNameVert << " and " << m_shaderNameFrag - << std::endl; - } - } else { - setLayout.uboSizesPerBinding[uboFragBinding.binding] = uboFragBinding.size; + auto it = setLayout.uboSizesPerBinding.find(uboBinding.binding); + if (it != std::end(setLayout.uboSizesPerBinding)) { + if (it->second != uboBinding.size) { + std::cerr << "UBO sizes mismatch for set = " << uboBinding.set + << " binding = " << uboBinding.binding + << " between " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + } + } else { + setLayout.uboSizesPerBinding[uboBinding.binding] = uboBinding.size; - makeMin(setLayout.uboBindings.start, uboFragBinding.binding); - makeMax(setLayout.uboBindings.end, uboFragBinding.binding); + makeMin(setLayout.uboBindings.start, uboBinding.binding); + makeMax(setLayout.uboBindings.end, uboBinding.binding); + } } - } - //Image stuff - for (int i = 0; i < this->vertShaderMeta->imageBindings.size(); i++) { - auto &imageVertBinding = this->vertShaderMeta->imageBindings[i]; - auto &setLayout = combinedShaderLayout.setLayouts[imageVertBinding.set]; - - if (setLayout.uboSizesPerBinding.find(imageVertBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { - std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageVertBinding.set - << " binding = " << imageVertBinding.binding - << " in " << m_shaderNameVert << " and " << m_shaderNameFrag - << std::endl; - throw std::runtime_error("types mismatch"); - } + for (int i = 0; i < shaderMeta->ssboBindingData.size(); i++) { + auto &ssboBinding = shaderMeta->ssboBindingData[i]; - makeMin(setLayout.imageBindings.start, imageVertBinding.binding); - makeMax(setLayout.imageBindings.end, imageVertBinding.binding); - } - for (int i = 0; i < this->fragShaderMeta->imageBindings.size(); i++) { - auto &imageFragBinding = this->fragShaderMeta->imageBindings[i]; + auto &setLayout = combinedShaderLayout.setLayouts[ssboBinding.set]; - auto &setLayout = combinedShaderLayout.setLayouts[imageFragBinding.set]; + auto it = setLayout.ssboSizesPerBinding.find(ssboBinding.binding); + if (it != std::end(setLayout.ssboSizesPerBinding)) { + if (it->second != ssboBinding.size) { + std::cerr << "SSBO sizes mismatch for set = " << ssboBinding.set + << " binding = " << ssboBinding.binding + << " between " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + } + } else { + setLayout.ssboSizesPerBinding[ssboBinding.binding] = ssboBinding.size; - if (setLayout.uboSizesPerBinding.find(imageFragBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { - std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageFragBinding.set - << " binding = " << imageFragBinding.binding - << " in " << m_shaderNameVert << " and " << m_shaderNameFrag - << std::endl; - throw std::runtime_error("types mismatch"); + makeMin(setLayout.ssboBindings.start, ssboBinding.binding); + makeMax(setLayout.ssboBindings.end, ssboBinding.binding); + } } - makeMin(setLayout.imageBindings.start, imageFragBinding.binding); - makeMax(setLayout.imageBindings.end, imageFragBinding.binding); + for (int i = 0; i < shaderMeta->imageBindings.size(); i++) { + auto &imageBinding = shaderMeta->imageBindings[i]; + auto &setLayout = combinedShaderLayout.setLayouts[imageBinding.set]; + + if (setLayout.uboSizesPerBinding.find(imageBinding.binding) != std::end(setLayout.uboSizesPerBinding)) { + std::cerr << "types mismatch. image slot is used for UBO. for set = " << imageBinding.set + << " binding = " << imageBinding.binding + << " in " << m_shaderNameVert << " and " << m_shaderNameFrag + << std::endl; + throw std::runtime_error("types mismatch"); + } + + makeMin(setLayout.imageBindings.start, imageBinding.binding); + makeMax(setLayout.imageBindings.end, imageBinding.binding); + } } + + //Cleanup for (auto &shaderLayout : combinedShaderLayout.setLayouts) { { diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index ec2494f4e..52aa5e6ed 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -16,7 +16,9 @@ struct ShaderSetLayout { std::unordered_map uboSizesPerBinding; + std::unordered_map ssboSizesPerBinding; bindingAmountData uboBindings; + bindingAmountData ssboBindings; bindingAmountData imageBindings; }; @@ -27,9 +29,6 @@ struct CombinedShaderLayout { class GShaderPermutationVLK : public IShaderPermutation { friend class GDeviceVLK; public: - static const constexpr int UBO_SET_INDEX = 0; - static const constexpr int IMAGE_SET_INDEX = 1; - explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device, const ShaderConfig &shaderConf); ~GShaderPermutationVLK() override {}; @@ -81,6 +80,8 @@ class GShaderPermutationVLK : public IShaderPermutation { CombinedShaderLayout combinedShaderLayout; ShaderConfig m_shaderConf; + std::string vertShaderName = ""; + std::string vertShaderFrag = ""; void createSetDescriptorLayouts(); std::vector createMetaArray(); diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 9f78eea32..506a03620 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -127,6 +127,7 @@ class IMapSceneBufferCreate { virtual HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; + virtual HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; virtual HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) = 0; virtual HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 0572b7ef3..6d40514d4 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -147,6 +147,13 @@ class IWaterMaterial : public IMaterial { int liquidFlags; int materialId; std::shared_ptr> m_materialPS = nullptr; + std::shared_ptr> m_bindless = nullptr; +}; + +class IWaterMaterialBindless : public IWaterMaterial { +public: + std::vector> m_bindlessText; + int instanceIndex = 0; }; class IPortalMaterial : public IMaterial { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 93e4616ef..36ed0951e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -30,6 +30,8 @@ static const ShaderConfig forwardShaderConfig = { const int m2TexturesBindlessCount = 4096; const int m2WaterfallTexturesBindlessCount = 128; const int adtTexturesBindlessCount = 4096; +const int waterTexturesBindlessCount = 1024; + static const ShaderConfig m2VisShaderConfig = { "visBuffer", { @@ -87,6 +89,17 @@ static const ShaderConfig adtVisShaderConfig = { }} }}; +static const ShaderConfig waterVisShaderConfig = { + "visBuffer", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, waterTexturesBindlessCount}} + }} + }}; + MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); @@ -151,6 +164,11 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic wmoBuffers.wmoPerMeshData = m_device->createSSBOBuffer("WMO PerMeshData", 1024*1024, sizeof(WMO::perMeshData)); wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer("Scene_VBO_WMOAmbient",16*200, sizeof(mathfu::vec4_packed)); } + //Create water buffs + { + waterBuffer.waterDataBuffer = m_device->createSSBOBuffer("Water data", 1024, sizeof(Water::meshWideBlockPS)); + waterBuffer.waterBindlessBuffer = m_device->createSSBOBuffer("Water Bindless", 1024, sizeof(Water::WaterBindless)); + } m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer("M2 Waterfall Common",200, sizeof(M2::WaterfallData::WaterfallCommon)); m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer("M2 Waterfall Bindless",200, sizeof(M2::WaterfallData::WaterfallBindless)); @@ -194,6 +212,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic createWMOGlobalMaterialData(); createADTGlobalMaterialData(); createM2WaterfallGlobalMaterialData(); + createWaterGlobalMaterialData(); } void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { @@ -231,7 +250,26 @@ void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { } } -void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() {//Create global wmo descriptor for bindless textures +void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { + //Create global water descriptor for bindless textures + MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [this](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, waterBuffer.waterDataBuffer) + .ssbo(1, wmoBuffers.wmoPlacementMats) + .ssbo(2, waterBuffer.waterBindlessBuffer); + + waterDataDS = ds; + }) + .createDescriptorSet(2, [this](std::shared_ptr &ds) { + waterTexturesDS = ds; + }); + + waterTextureHolder = std::make_shared(waterTexturesBindlessCount); +} +void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { + //Create global wmo descriptor for bindless textures MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -744,29 +782,45 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(cons std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, const WaterMaterialTemplate &waterMaterialTemplate) { - auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; + auto l_fragmentData = std::make_shared>(waterBuffer.waterDataBuffer); ; + auto l_waterBindless = std::make_shared>(waterBuffer.waterBindlessBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, visShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData, this](std::shared_ptr &ds) { - ds->beginUpdate() - .ssbo(1, wmoBuffers.wmoPlacementMats) - .ubo(4, *l_fragmentData); - }) - .createDescriptorSet(2, [&waterMaterialTemplate](std::shared_ptr &ds) { - ds->beginUpdate() - .texture(5, waterMaterialTemplate.texture); - }) - .toMaterial([&l_fragmentData](IWaterMaterial *instance) -> void { + .bindDescriptorSet(1, waterDataDS) + .bindDescriptorSet(2, waterTexturesDS) + .toMaterial([&l_fragmentData, l_waterBindless](IWaterMaterialBindless *instance) -> void { instance->m_materialPS = l_fragmentData; + instance->m_bindless = l_waterBindless; }); material->color = waterMaterialTemplate.color; material->liquidFlags = waterMaterialTemplate.liquidFlags; material->materialId = waterMaterialTemplate.liquidMaterialId; + { + auto dsUpdate = waterTexturesDS->beginUpdate(); + +// for (int i = 0; i < 9; i++) { + auto bindlessText = waterTextureHolder->allocate(waterMaterialTemplate.texture); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, waterMaterialTemplate.texture, bindlessText->getIndex()); +// } + } + + { + auto &bindless = l_waterBindless->getObject(); + bindless.placementMatInd = BufferChunkHelperVLK::cast(modelWide)->getIndex(); + bindless.textureInd = material->m_bindlessText[0]->getIndex(); + bindless.waterDataInd = l_fragmentData->getIndex(); + + l_waterBindless->save(); + } + + material->instanceIndex = l_waterBindless->getIndex(); + return material; } @@ -996,6 +1050,9 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoGroupAmbient); uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoPerMeshData); + uploadCmd.submitBufferUploads(l_this->waterBuffer.waterDataBuffer); + uploadCmd.submitBufferUploads(l_this->waterBuffer.waterBindlessBuffer); + uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); @@ -1120,6 +1177,15 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &mes auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } + +HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto _material = std::dynamic_pointer_cast(material); + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + + mesh->instanceIndex = _material->instanceIndex; + return mesh; +} + HGMesh MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index 5a4cd8407..e61ae02eb 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -100,6 +100,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGSortableMesh createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; + HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; @@ -165,6 +166,11 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGBufferVLK waterfallBindless; } m2WaterfallBuffer; + struct { + HGBufferVLK waterDataBuffer; + HGBufferVLK waterBindlessBuffer; + } waterBuffer; + struct { HGBufferVLK adtMeshWideVSPSes; HGBufferVLK adtMeshWidePSes; @@ -212,6 +218,9 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr wmoTexturesDS = nullptr; std::shared_ptr wmoTextureHolder = nullptr; + std::shared_ptr waterDataDS = nullptr; + std::shared_ptr waterTexturesDS = nullptr; + std::shared_ptr waterTextureHolder = nullptr; std::shared_ptr m_renderPass; @@ -231,6 +240,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { void createM2GlobalMaterialData(); void createWMOGlobalMaterialData(); void createADTGlobalMaterialData(); + void createWaterGlobalMaterialData(); void createM2WaterfallGlobalMaterialData(); }; From 1b320cd246e1eca510d20ee89388b940a2fca704 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 18 Oct 2023 14:39:39 +0300 Subject: [PATCH 140/212] - minimize state changes --- .../shaders/glsl/visBuffer/adtShader.vert | 4 +- .../engine/objects/liquid/LiquidInstance.cpp | 1 + .../engine/objects/liquid/LiquidInstance.h | 1 + .../src/gapi/interface/meshes/IMesh.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 6 +-- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 2 +- .../CommandBufferRecorder.cpp | 4 +- .../CommandBufferRecorder.h | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 40 ++++++++++++++----- 9 files changed, 44 insertions(+), 18 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index fe29a649e..a5190fc13 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -1,6 +1,8 @@ #version 450 #extension GL_GOOGLE_include_directive: require +#extension GL_ARB_shader_draw_parameters: require + precision highp float; precision highp int; @@ -64,7 +66,7 @@ void main() { //With current implementation ADT's VBO is combined buffer, which contains all vertexes from all MCNK of ADT //Thus, we first need to get vertexNumber within MCNK - int indexInMCNK = gl_VertexIndex % (9 * 9 + 8 * 8); + int indexInMCNK = (gl_VertexIndex - gl_BaseVertexARB) % (9 * 9 + 8 * 8); float iX = mod(indexInMCNK, 17.0); float iY = floor(indexInMCNK/17.0); diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 5666335e7..695401c0a 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -94,6 +94,7 @@ void LiquidInstance::createMaterialAndMesh(const HMapSceneBufferCreate &sceneRen auto waterMaterial = sceneRenderer->createWaterMaterial(m_waterPlacementChunk, pipelineTemplate, waterMaterialTemplate); m_liquidMaterials.push_back(waterMaterial); + m_vertexWaterBufferBindings.push_back(vertexWaterBufferBindings); //Create mesh(es) for (int i = 0; i < m_liquidMaterials.size(); i++) { diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index a5a978cd8..06016b0f1 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -32,6 +32,7 @@ class LiquidInstance { const HApiContainer &m_api; const std::shared_ptr> m_waterPlacementChunk; std::vector> m_liquidMaterials; + std::vector m_vertexWaterBufferBindings; std::vector m_liquidMeshes; CAaBox &m_waterBBox; diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index f756f18fe..bbf7bfcc4 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -77,7 +77,7 @@ class IMesh { auto bindings() const -> const HGVertexBufferBindings& { return m_bindings; } - int vertexStart = -1; + int vertexStart = 0; int instanceIndex = -1; protected: HGVertexBufferBindings m_bindings; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 9724d0e3e..60085fffc 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1248,14 +1248,14 @@ HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSiz return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize) { - auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize); +HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize, int recordSize) { + auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize, recordSize); return h_vertexBuffer; } HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize) { - auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize); + auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize, 2); return h_indexBuffer; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index ff5267b5e..400ca59c2 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -101,7 +101,7 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_thisgetOffset(), + vertexOffset, firstInstance); } diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 622e67bcd..f830edead 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -61,7 +61,7 @@ class CmdBufRecorder { inline void bindPipeline(const std::shared_ptr &pipeline); inline void bindDescriptorSets(VkPipelineBindPoint bindPoint, const std::vector> &descriptorSets); - void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); + void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance, uint32_t vertexOffset = 0); void setScissors(const std::array &areaOffset, const std::array &areaSize); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 36ed0951e..7d11cf1d8 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -104,13 +104,13 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic m_device(hDevice), MapSceneRenderer(config) { iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); - vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, sizeof(M2Vertex)); vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); - vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024); - vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024); - vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, sizeof(AdtVertex)); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, sizeof(WMOVertex)); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, sizeof(LiquidVertexFormat)); vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); @@ -176,13 +176,13 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); - m_emptyADTVAO = createADTVAO(nullptr, nullptr); - m_emptyM2VAO = createM2VAO(nullptr, nullptr); + m_emptyADTVAO = createADTVAO(vboAdtBuffer, iboBuffer); + m_emptyM2VAO = createM2VAO(vboM2Buffer, iboBuffer); m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); m_emptySkyVAO = createSkyVAO(nullptr, nullptr); - m_emptyWMOVAO = createWmoVAO(nullptr, nullptr, nullptr); - m_emptyWaterVAO = createWaterVAO(nullptr, nullptr); + m_emptyWMOVAO = createWmoVAO(vboWMOBuffer, iboBuffer, nullptr); + m_emptyWaterVAO = createWaterVAO(vboWaterBuffer, iboBuffer); m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); //Framebuffers for rendering @@ -909,7 +909,7 @@ inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const H //5. Draw the mesh if (meshVlk->instanceIndex != -1) { - cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, meshVlk->instanceIndex); + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, meshVlk->instanceIndex, meshVlk->vertexStart); } else { cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, 0); } @@ -1179,30 +1179,50 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &mes } HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { +// auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); +// meshTemplate.bindings = m_emptyWaterVAO; + auto _material = std::dynamic_pointer_cast(material); auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); mesh->instanceIndex = _material->instanceIndex; +// mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); +// mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + return mesh; } HGMesh MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyADTVAO; + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + return mesh; } HGM2Mesh MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyM2VAO; auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + return mesh; } HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyWMOVAO; + auto originalMat = std::dynamic_pointer_cast(material); auto c_perMeshData = std::make_shared>(wmoBuffers.wmoPerMeshData); @@ -1220,6 +1240,8 @@ HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, co auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); mesh->instanceIndex = c_perMeshData->getIndex(); + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); return mesh; } HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, From 6944bdaf9bd4c51a8238c80cdc0f52034c29cd77 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 18 Oct 2023 23:33:07 +0300 Subject: [PATCH 141/212] - temporary commit with current state of affairs --- .../src/engine/objects/ViewsObjects.cpp | 3 +- .../src/engine/objects/ViewsObjects.h | 10 + .../src/engine/objects/m2/m2Object.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1296 +++++++++-------- .../src/renderer/mapScene/MapSceneRenderer.h | 1 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 37 +- 6 files changed, 764 insertions(+), 585 deletions(-) diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 2ed5d7133..ae0f7e733 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -10,8 +10,7 @@ #if (__AVX__ && __SSE2__) #include "../algorithms/mathHelper_culling_sse.h" #endif -#include "../algorithms/mathHelper_culling.h" -#include "../../gapi/interface/materials/IMaterial.h" + void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) { if (renderADT) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index f5a3c877b..93de1f5f4 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -30,6 +30,16 @@ class ADTObjRenderRes { std::array checkRefs = {false}; }; +class COpaqueMeshCollector { +public: + virtual void addM2Mesh(const HGM2Mesh &mesh) = 0; + virtual void addWMOMesh(const HGMesh &mesh) = 0; + virtual void addWaterMesh(const HGMesh &mesh) = 0; + virtual void addADTMesh(const HGMesh &mesh) = 0; + + virtual void addMesh(const HGMesh &mesh) = 0; +}; + class GeneralView { public: WMOGroupListContainer wmoGroupArray; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index ece590142..88413b796 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1043,7 +1043,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); //Update materials` - if (true) { + if (m_placementMatrixChanged) { auto &placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); placementMatrix.uPlacementMat = m_placementMatrix; m_modelWideDataBuff->m_placementMatrix->save(); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 49aa5607c..104f28a88 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,33 +295,14 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,0,84}, }, { { @@ -317,16 +317,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -338,18 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,480}, - {1,2,16}, + {0,0,144}, }, { { {0,0,1}, - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -376,15 +372,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -395,22 +391,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {3,0, "s_AlphaTextures"}, - {4,0, "s_LayerHeightTextures"}, - {2,0, "s_LayerTextures"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -418,21 +409,19 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,0,112}, - {1,6,4096}, - {1,3,16384}, + {1,2,48}, {0,0,480}, {1,1,64}, }, { { {0,0,1}, - {1,6,6}, - {0,0,1}, + {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -443,14 +432,22 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,3, "uBumpTexture"}, + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, + {5,13,9}, {0,0,0}, - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -459,16 +456,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, - {1,1,64}, + {0,1,12}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -476,6 +471,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -496,12 +492,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,96}, + {1,1,64}, }, { { @@ -533,9 +529,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "visBuffer/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,480}, }, @@ -552,19 +548,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, {1,6,0}, + {1,4,0}, {1,3,0}, + {1,5,0}, {1,1,0}, + {1,2,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -572,15 +567,16 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,1,112}, }, { { @@ -612,15 +608,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -648,11 +644,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,480}, }, { { @@ -667,6 +663,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -684,14 +686,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -704,12 +707,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -720,15 +722,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { + {0,1,112}, {0,0,480}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -739,10 +742,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, }, { }, @@ -760,15 +759,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,17 +778,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -799,15 +795,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,128}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -820,11 +816,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -836,18 +831,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,5,96}, - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, + {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -858,17 +853,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -877,15 +868,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { + {1,1,16}, }, { { {0,0,0}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -912,16 +904,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -949,16 +940,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, + {0,2,168}, }, { { + {2,2,1}, {0,0,0}, - {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -970,10 +961,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -985,15 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,480}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1004,18 +997,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1024,14 +1014,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { + {0,4,32}, }, { { - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1044,11 +1035,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1059,15 +1051,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {0,4,16}, }, { { - {1,1,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1080,11 +1072,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1095,15 +1089,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,11 +1109,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1131,18 +1125,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, - {0,0,480}, - {1,1,64}, + {0,1,80}, }, { { - {0,0,1}, - {1,2,2}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1154,21 +1146,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1178,16 +1161,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1197,19 +1181,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, }, { - {2,0, "s_Textures"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1219,7 +1201,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1238,8 +1220,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, }, { }, @@ -1257,16 +1237,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,480}, + {1,1,96}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1276,23 +1257,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1302,17 +1274,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, + {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1323,13 +1302,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1338,17 +1321,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/m2Shader.vert.spv", { ShaderStage::Vertex, { + {1,3,16384}, + {1,1,64}, {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1374,15 +1364,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1410,17 +1399,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,3,32}, {0,0,480}, }, { { {0,0,1}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1430,23 +1418,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1456,16 +1439,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {1,4,16}, + {1,3,4096}, + {0,0,480}, }, { { - {4,4,1}, - {0,0,0}, + {0,0,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1477,13 +1462,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {2,5, "uTexture"}, }, { { {0,0,0}, - {5,5,1}, {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1493,15 +1478,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "visBuffer/waterShader.vert.spv", { ShaderStage::Vertex, { - {0,2,16}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1512,14 +1497,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1529,15 +1518,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,0,480}, }, { { - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1550,13 +1539,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1567,17 +1554,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, - {0,0,480}, }, { { - {0,0,1}, - {4,4,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1589,13 +1574,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1605,23 +1589,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {1,4,96}, {0,0,480}, - {1,1,64}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1632,17 +1611,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1651,16 +1627,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, + {1,1,64}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1670,8 +1647,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, }, { }, @@ -1689,16 +1664,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "visBuffer/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1709,16 +1683,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {3,0, "s_AlphaTextures"}, + {4,0, "s_LayerHeightTextures"}, + {2,0, "s_LayerTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1726,17 +1706,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {2,5,96}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {1,1,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1747,13 +1734,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1762,17 +1753,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "visBuffer/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1782,17 +1772,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1802,17 +1792,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,0,112}, + {1,6,4096}, + {1,3,16384}, {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1823,13 +1820,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1838,15 +1836,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { + {1,3,32}, + {0,0,480}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1858,12 +1858,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1873,15 +1882,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1908,15 +1920,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1927,16 +1939,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { - {0,3, "diffuse"}, + {3,0, "s_Textures"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1945,18 +1968,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "visBuffer/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,3,16384}, - {1,1,64}, {0,0,480}, }, { { {0,0,1}, - {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1966,14 +1987,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1983,18 +2014,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2004,16 +2033,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {2,5, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2022,7 +2062,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -2041,6 +2081,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -2061,47 +2110,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { { - 7, { - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 0, { - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"adtShader", { + {"drawBBShader", { { 1, { - } - }, - { - 3, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -2133,7 +2156,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { { - 1, { + 2, { + {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, } }, { - 0, { + 6, { + } + }, + { + 4, { + } + }, + { + 3, { } }, { 5, { - {"_2_5_values0", true, 0, 1, 4, 0}, - {"_2_5_values1", true, 16, 1, 4, 0}, - {"_2_5_values2", true, 32, 1, 4, 0}, - {"_2_5_values3", true, 48, 1, 4, 0}, - {"_2_5_values4", true, 64, 1, 4, 0}, - {"_2_5_baseColor", true, 80, 1, 4, 0}, + {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, + } + }, + }}, +}; +const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { + { + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, + } + }, + }}, + {"drawBBShader", { + { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, }}, @@ -2511,29 +2591,18 @@ const std::unordered_map> &hliquidMeshes, const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes); + void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const std::vector &renderingMatrices, const HFrameDependantData &fdd, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 7d11cf1d8..a46739fb6 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -947,6 +947,33 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // [&]() { collectMeshes(framePlan, opaqueMeshes, transparentMeshes, liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); + + { + ZoneScopedN("sort opaque"); + std::sort(opaqueMeshes->begin(), opaqueMeshes->end(), [](const HGMesh &a, const HGMesh &b) -> bool { + const auto &mesh_a = (GMeshVLK*) a.get(); + const auto &mesh_b = (GMeshVLK*) b.get(); + + auto const &material_a = mesh_a->material(); + auto const &material_b = mesh_b->material(); + + const auto &shader_a = material_a->getShader(); + const auto &shader_b = material_b->getShader(); + + if (shader_a != shader_b) { + return shader_a < shader_b; + } + + const auto &pipeline_a = material_a->getPipeline(); + const auto &pipeline_b = material_b->getPipeline(); + + if (pipeline_a != pipeline_b) { + return pipeline_a < pipeline_b; + } + + return a->start() < b->start(); + }); + } // } // ); @@ -1083,11 +1110,13 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s false, frameInputParams->frameParameters->clearColor); + { ZoneScopedN("submit opaque"); VkZone(frameBufCmd, "render opaque") auto const &pOpaqueMeshes = *opaqueMeshes; auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); + for (int i = 0; i < pOpaqueMeshesSize; i++) { MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], CmdBufRecorder::ViewportType::vp_usual); @@ -1179,15 +1208,15 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &mes } HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { -// auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); -// meshTemplate.bindings = m_emptyWaterVAO; + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyWaterVAO; auto _material = std::dynamic_pointer_cast(material); auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); mesh->instanceIndex = _material->instanceIndex; -// mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); -// mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); return mesh; } From 2df1a2127f2bfc842fa1a43916433fb78880a5ee Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 19 Oct 2023 01:23:35 +0300 Subject: [PATCH 142/212] - implement mesh collector - disable forward for now --- .../src/engine/managers/CRibbonEmitter.cpp | 4 +- .../src/engine/managers/CRibbonEmitter.h | 2 +- .../managers/particles/particleEmitter.cpp | 4 +- .../managers/particles/particleEmitter.h | 2 +- .../src/engine/objects/ViewsObjects.cpp | 18 +- .../src/engine/objects/ViewsObjects.h | 12 +- .../engine/objects/liquid/LiquidInstance.cpp | 7 + .../engine/objects/liquid/LiquidInstance.h | 2 + .../src/engine/objects/m2/m2Object.cpp | 20 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 10 +- .../src/engine/objects/wmo/wmoGroupObject.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1386 ++++++++--------- .../src/gapi/interface/meshes/IMesh.h | 11 + .../renderer/mapScene/MapSceneRenderer.cpp | 23 +- .../src/renderer/mapScene/MapSceneRenderer.h | 5 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 5 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 236 ++- .../vulkan/MapSceneRenderVisBufferVLK.h | 16 +- 19 files changed, 961 insertions(+), 808 deletions(-) diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index cb02f4ebd..ca1f96585 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -839,7 +839,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV this->m_ribbonEmitterflags.m_initialized = 1; } -void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; if (currFrame.isDead) return; @@ -848,7 +848,7 @@ void CRibbonEmitter::collectMeshes(std::vector &opaqueMeshes, std::vecto if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { - opaqueMeshes.push_back(mesh); + opaqueMeshCollector.addMesh(mesh); } } } diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index 229c53499..ecc68e154 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -122,7 +122,7 @@ class CRibbonEmitter { //CTexture **SetTexture(unsigned int a2, CTexture *a3); //int ReplaceTexture(unsigned int a2, CTexture *a3); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 82263b380..8019b63ad 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -1114,7 +1114,7 @@ ParticleEmitter::BuildQuadT3( } -void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; @@ -1125,7 +1125,7 @@ void ParticleEmitter::collectMeshes(std::vector &opaqueMeshes, std::vect if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { - opaqueMeshes.push_back(mesh); + opaqueMeshCollector.addMesh(mesh); } } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 93dd870d7..3a0af43ed 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -68,7 +68,7 @@ class ParticleEmitter { CParticleGenerator * getGenerator(){ return generator; } - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index ae0f7e733..9f6ea7a88 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -12,25 +12,27 @@ #endif -void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) { +void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) { if (renderADT) { - auto inserter = std::back_inserter(opaqueMeshes); - std::copy(this->m_adtOpaqueMeshes.begin(), this->m_adtOpaqueMeshes.end(), inserter); + for (auto const &adtMesh : this->m_adtOpaqueMeshes ) { + opaqueMeshCollector.addADTMesh(adtMesh); + } } if (renderAdtLiquid) { - auto inserter = std::back_inserter(liquidMeshes); - std::copy(this->liquidMeshes.begin(), this->liquidMeshes.end(), inserter); + for (auto const &liquidMesh : this->liquidMeshes ) { + opaqueMeshCollector.addWaterMesh(liquidMesh); + } } - GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); + GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshCollector, transparentMeshes); } -void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) { +void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) { if (renderWMO) { for (auto &wmoGroup: wmoGroupArray.getToDraw()) { - wmoGroup->collectMeshes(opaqueMeshes, transparentMeshes, liquidMeshes, renderOrder); + wmoGroup->collectMeshes(opaqueMeshCollector, transparentMeshes, renderOrder); } } } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 93de1f5f4..327d6daab 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -30,15 +30,7 @@ class ADTObjRenderRes { std::array checkRefs = {false}; }; -class COpaqueMeshCollector { -public: - virtual void addM2Mesh(const HGM2Mesh &mesh) = 0; - virtual void addWMOMesh(const HGMesh &mesh) = 0; - virtual void addWaterMesh(const HGMesh &mesh) = 0; - virtual void addADTMesh(const HGMesh &mesh) = 0; - virtual void addMesh(const HGMesh &mesh) = 0; -}; class GeneralView { public: @@ -64,7 +56,7 @@ class GeneralView { std::vector liquidMeshes = {}; - virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes); + virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes); void collectPortalMeshes(std::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); @@ -85,7 +77,7 @@ class ExteriorView : public GeneralView { std::vector> drawnADTs = {}; std::vector m_adtOpaqueMeshes = {}; public: - void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes) override; + void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) override; }; class FrameViewsHolder { diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 695401c0a..74c02b340 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -327,6 +327,13 @@ void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDepen } } +void LiquidInstance::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector) { + //TODO: Get time and right mesh instance for animation + if (m_api->getConfig()->renderLiquid) { + opaqueMeshCollector.addWaterMesh(m_liquidMeshes[0]); + } +} + void LiquidInstance::collectMeshes(std::vector &transparentMeshes) { //TODO: Get time and right mesh instance for animation if (m_api->getConfig()->renderLiquid) { diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index 06016b0f1..abc364676 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -27,7 +27,9 @@ class LiquidInstance { CAaBox &waterAaBB); void updateLiquidMaterials(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector); void collectMeshes(std::vector &transparentMeshes); + private: const HApiContainer &m_api; const std::shared_ptr> m_waterPlacementChunk; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 88413b796..691e0e3a7 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1630,7 +1630,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index return m2Mesh; } -void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; @@ -1655,7 +1655,11 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorgetIsTransparent()) { transparentMeshes.push_back(mesh); } else { - opaqueMeshes.push_back(mesh); + if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { + opaqueMeshCollector.addM2Mesh(mesh); + } else { + opaqueMeshCollector.addMesh(mesh); + } } } @@ -1675,7 +1679,11 @@ void M2Object::collectMeshes(std::vector &opaqueMeshes, std::vectorgetIsTransparent()) { transparentMeshes.push_back(mesh); } else { - opaqueMeshes.push_back(mesh); + if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { + opaqueMeshCollector.addM2Mesh(mesh); + } else { + opaqueMeshCollector.addMesh(mesh); + } } } } @@ -1896,7 +1904,7 @@ int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { return -1; } -void M2Object::drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { // return; // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; @@ -1916,11 +1924,11 @@ void M2Object::drawParticles(std::vector &opaqueMeshes, std::vectorcollectMeshes(opaqueMeshes, transparentMeshes, renderOrder); + particleEmitters[i]->collectMeshes(opaqueMeshCollector, transparentMeshes, renderOrder); } for (int i = 0; i < ribbonEmitters.size(); i++) { - ribbonEmitters[i]->collectMeshes(opaqueMeshes, transparentMeshes, renderOrder); + ribbonEmitters[i]->collectMeshes(opaqueMeshCollector, transparentMeshes, renderOrder); } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 5dd52e45b..ca86ebff8 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -244,7 +244,7 @@ class M2Object { mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { if (m_useLocalDiffuseColor == -1) { @@ -288,7 +288,7 @@ class M2Object { m_ambientColorOverride = ambientColor; } - void drawParticles(std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); void createVertexBindings(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 1e1139993..ac95cc4bf 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -747,21 +747,21 @@ void WmoGroupObject::setModelFileId(int fileId) { m_modelFileId = fileId; } -void WmoGroupObject::collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes, int renderOrder) { +void WmoGroupObject::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { if (!m_loaded) return; - for (auto &i : this->m_meshArray) { - opaqueMeshes.push_back(i); + for (auto const &i : this->m_meshArray) { + opaqueMeshCollector.addWMOMesh(i); } for (auto &i : this->m_sortableMeshArray) { if (i->getIsTransparent()) { - opaqueMeshes.push_back(i); + opaqueMeshCollector.addWMOMesh(i); } else { transparentMeshes.push_back(i); } } for (auto const &liquidInstance : m_liquidInstances) { - liquidInstance->collectMeshes(liquidMeshes); + liquidInstance->collectMeshes(opaqueMeshCollector); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 41b304346..4b9865f40 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -45,7 +45,7 @@ class WmoGroupObject { void setModelFileName(std::string modelName); void setModelFileId(int fileId); - void collectMeshes(std::vector &opaqueMeshes, std::vector &transparentMeshes, std::vector &liquidMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 104f28a88..dd6de01f4 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,14 +276,33 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,480}, }, { { @@ -317,14 +317,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +343,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,144}, + {1,1,64}, + {0,0,480}, + {1,2,16}, }, { { {0,0,1}, - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,15 +381,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -391,17 +400,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {0,3, "diffuse"}, + {3,0, "s_AlphaTextures"}, + {4,0, "s_LayerHeightTextures"}, + {2,0, "s_LayerTextures"}, }, { { - {3,3,1}, - {0,0,0}, - {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,19 +423,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,48}, + {2,0,112}, + {1,6,4096}, + {1,3,16384}, {0,0,480}, {1,1,64}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, }, { { {0,0,1}, - {1,2,2}, - {0,0,0}, + {1,6,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -432,22 +451,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,14 +467,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,480}, + {1,1,64}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -471,7 +484,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { @@ -492,12 +504,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/skyConus.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, + {1,1,96}, }, { { @@ -529,9 +541,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "visBuffer/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,480}, }, @@ -548,18 +560,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, {1,6,0}, - {1,4,0}, {1,3,0}, - {1,5,0}, {1,1,0}, {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { - {2,0, "s_Textures"}, + {3,0, "s_Textures"}, }, { { + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -567,16 +585,15 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,1,12}, }, { { @@ -608,15 +625,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -644,11 +661,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,0,128}, }, { { @@ -663,12 +680,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -686,15 +697,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -707,11 +717,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -722,16 +733,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -742,6 +752,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -759,15 +775,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -778,14 +794,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,15 +815,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -816,10 +836,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -831,18 +853,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {2,5,96}, + {0,0,480}, + {1,1,64}, + {1,2,256}, + {1,3,16384}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, }, { { - {0,1,2}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {1,6,6}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -853,13 +881,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -868,15 +900,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, + {0,1,12}, }, { { - {0,0,0}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -884,6 +915,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -904,15 +936,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { + {0,1,112}, {0,0,480}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -940,16 +973,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {1,1,16}, }, { { - {2,2,1}, {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -961,12 +994,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +1009,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "visBuffer/waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,2,16}, + {0,0,480}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -997,15 +1028,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1014,15 +1057,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {0,4,32}, + {0,2,12}, }, { { - {4,4,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,12 +1078,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1051,15 +1093,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,4,16}, + {0,1,80}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1072,13 +1114,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,14 +1129,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,144}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1109,12 +1150,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1125,16 +1165,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,80}, + {1,2,48}, + {0,0,480}, + {1,1,64}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1146,12 +1188,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,9, "uAlphaTexture"}, + {2,10, "uLayerHeight0"}, + {2,11, "uLayerHeight1"}, + {2,12, "uLayerHeight2"}, + {2,13, "uLayerHeight3"}, + {2,5, "uLayer0"}, + {2,6, "uLayer1"}, + {2,7, "uLayer2"}, + {2,8, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1161,17 +1212,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "visBuffer/wmoShader.frag.spv", { ShaderStage::Fragment, { - {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1181,17 +1231,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1201,7 +1255,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "visBuffer/waterShader.vert.spv", { ShaderStage::Vertex, { @@ -1220,14 +1274,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1237,17 +1295,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "visBuffer/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,480}, - {1,1,96}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1257,14 +1314,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1274,24 +1341,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, - {0,0,480}, - {1,1,64}, - {1,6,4096}, - {1,3,16384}, + {0,0,128}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1302,17 +1362,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1321,24 +1377,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, + {1,1,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1364,14 +1414,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,0,84}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1384,10 +1435,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1399,16 +1452,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { + {1,3,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1418,18 +1472,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, - {1,1,0}, }, { - {2,0, "s_Textures"}, + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, + {2,8, "uTexture4"}, + {2,9, "uTexture5"}, + {2,10, "uTexture6"}, + {2,11, "uTexture7"}, + {2,12, "uTexture8"}, + {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {5,13,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1439,18 +1498,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, - {0,0,480}, + {0,4,32}, }, { { - {0,0,1}, - {3,4,2}, + {4,4,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1462,11 +1519,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {1,5, "texture0"}, }, { { - {0,0,0}, {0,0,0}, {5,5,1}, {0,0,0}, @@ -1474,19 +1530,20 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,480}, + {0,2,16}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1497,18 +1554,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1518,15 +1571,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,4,16}, }, { { - {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1539,11 +1592,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,5, "screenTex"}, + {1,6, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {5,6,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1554,15 +1609,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { + {1,4,96}, + {0,0,480}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1574,12 +1631,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,5,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1589,18 +1647,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,4,96}, + {2,7,64}, + {1,5,256}, + {1,4,4096}, + {1,2,256}, {0,0,480}, + {1,1,64}, + {1,6,4096}, + {1,3,16384}, }, { { {0,0,1}, - {4,4,1}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1611,14 +1675,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {3,6, "uTexture"}, + {3,7, "uTexture2"}, + {3,8, "uTexture3"}, + {3,9, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, {0,0,0}, + {6,9,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1627,17 +1694,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "visBuffer/adtShader.vert.spv", { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1647,6 +1713,9 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { }, @@ -1664,15 +1733,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,480}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1683,22 +1753,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {3,0, "s_AlphaTextures"}, - {4,0, "s_LayerHeightTextures"}, - {2,0, "s_LayerTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1706,24 +1770,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {2,5,96}, - {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, + {0,1,112}, }, { { - {0,0,1}, - {1,6,6}, - {5,5,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1734,17 +1791,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1753,16 +1806,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,4,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {4,4,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1772,17 +1826,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { + {2,5, "uTexture"}, + {2,6, "uTexture2"}, + {2,7, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {5,7,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1792,24 +1846,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,6,4096}, - {1,3,16384}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { {0,0,1}, - {1,6,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1820,14 +1867,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1836,17 +1882,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {1,3,32}, - {0,0,480}, }, { { - {0,0,1}, - {3,3,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1858,21 +1902,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1882,18 +1917,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {1,1,64}, - {0,0,480}, - {1,2,16}, }, { { - {0,0,1}, - {1,2,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1920,15 +1952,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1939,27 +1971,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1968,17 +1989,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,480}, + {1,3,16384}, + {1,1,64}, + {0,0,480}, + {1,2,256}, + {1,4,4096}, + {1,5,256}, + {1,6,4096}, + {2,7,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {1,6,6}, + {7,7,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1987,24 +2015,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2014,16 +2032,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,4,16}, + {1,3,4096}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2033,27 +2053,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,5, "uTexture"}, }, { { {0,0,0}, {0,0,0}, + {5,5,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2062,7 +2071,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -2081,15 +2090,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -2110,21 +2110,73 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 2, { + } + }, + { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, { 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"drawBBShader", { + {"adtLodShader", { + { + 0, { + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + } + }, + }}, + {"adtShader", { + { + 2, { + } + }, + { + 3, { + } + }, { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -2156,16 +2208,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { - 2, { - {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, + 9, { + } + }, + { + 8, { + } + }, + { + 7, { } }, { 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, } }, { 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, } }, { 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, + 2, { } }, - }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 0, { + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, } }, }}, @@ -2591,18 +2621,29 @@ const std::unordered_map &renderPlan, - const std::shared_ptr> &hopaqueMeshes, + COpaqueMeshCollector &opaqueMeshCollector, + COpaqueMeshCollector &skyOpaqueMeshCollector, const std::shared_ptr> &htransparentMeshes, - const std::shared_ptr> &hliquidMeshes, - const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes) { ZoneScoped; - auto &opaqueMeshes = *hopaqueMeshes; auto &transparentMeshes = *htransparentMeshes; - auto &skyOpaqueMeshes = *hSkyOpaqueMeshes; auto &skyTransparentMeshes = *hSkyTransparentMeshes; - auto &liquidMeshes = *hliquidMeshes; - opaqueMeshes.reserve(30000); transparentMeshes.reserve(30000); - - skyOpaqueMeshes.reserve(1000); skyTransparentMeshes.reserve(1000); const auto& cullStage = renderPlan; @@ -51,29 +44,29 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende bool renderWMO = m_config->renderWMO; for (auto &view : cullStage->viewsHolder.getInteriorViews()) { - view->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); + view->collectMeshes(renderADT, true, renderWMO, opaqueMeshCollector, transparentMeshes); } { auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { - exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshes, transparentMeshes, liquidMeshes); + exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshCollector, transparentMeshes); } } if (m_config->renderM2) { for (auto &m2Object : cullStage->m2Array.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(opaqueMeshes, transparentMeshes, m_viewRenderOrder); - m2Object->drawParticles(opaqueMeshes, transparentMeshes, m_viewRenderOrder); + m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); + m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); } auto skyBoxView = cullStage->viewsHolder.getSkybox(); if (skyBoxView) { for (auto &m2Object : skyBoxView->m2List.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(skyOpaqueMeshes, skyTransparentMeshes, m_viewRenderOrder); - m2Object->drawParticles(skyOpaqueMeshes, skyTransparentMeshes, m_viewRenderOrder); + m2Object->collectMeshes(skyOpaqueMeshCollector, skyTransparentMeshes, m_viewRenderOrder); + m2Object->drawParticles(skyOpaqueMeshCollector, skyTransparentMeshes, m_viewRenderOrder); } } } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 666ff0a66..a8a1186f0 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -96,10 +96,9 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public std::shared_ptr processCulling(const std::shared_ptr> &frameInputParams) override; void collectMeshes(const std::shared_ptr &renderPlan, - const std::shared_ptr> &hopaqueMeshes, + COpaqueMeshCollector &opaqueMeshCollector, + COpaqueMeshCollector &skyOpaqueMeshCollector, const std::shared_ptr> &htransparentMeshes, - const std::shared_ptr> &hliquidMeshes, - const std::shared_ptr> &hSkyOpaqueMeshes, const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 03a47f981..5656b212d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -586,8 +586,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { - collectMeshes(framePlan, opaqueMeshes, transparentMeshes, - liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); + //TODO: +// collectMeshes(framePlan, opaqueMeshes, transparentMeshes, +// liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); // } // ); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index a46739fb6..6e1f77f1d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -251,8 +251,16 @@ void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { } void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + //Create global water descriptor for bindless textures - MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) + g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) + .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { ds->beginUpdate() @@ -264,13 +272,22 @@ void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { }) .createDescriptorSet(2, [this](std::shared_ptr &ds) { waterTexturesDS = ds; - }); + }).toMaterial();; waterTextureHolder = std::make_shared(waterTexturesBindlessCount); } void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + //Create global wmo descriptor for bindless textures - MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() .ssbo(1, wmoBuffers.wmoPlacementMats) @@ -284,12 +301,22 @@ void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { }) .createDescriptorSet(2, [&](std::shared_ptr &ds) { wmoTexturesDS = ds; - }); + }).toMaterial(); wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); } -void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() {//Create global m2 descriptor for bindless textures - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) +void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + //Create global m2 descriptor for bindless textures + g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() .ssbo(1, m2Buffers.placementMatrix) @@ -306,7 +333,7 @@ void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() {//Create global m }) .createDescriptorSet(2, [&](std::shared_ptr &ds) { m2TextureDS = ds; - }); + }).toMaterial(); m2TextureHolder = std::make_shared(m2TexturesBindlessCount); } void MapSceneRenderVisBufferVLK::createM2WaterfallGlobalMaterialData() { @@ -919,6 +946,144 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { return {vec[0], vec[1], vec[2]}; } +class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ +public: + COpaqueMeshCollectorBindlessVLK(MapSceneRenderVisBufferVLK &rendererVlk) : m_renderer(rendererVlk) { + commonMeshes.reserve(1000); + } +private: + MapSceneRenderVisBufferVLK &m_renderer; + struct DrawCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + uint32_t firstInstance; + uint32_t vertexOffset; + }; + + typedef std::unordered_map, std::vector> MeshMap; + + MeshMap m2MeshMap; + MeshMap wmoMeshMap; + MeshMap waterMeshMap; + MeshMap adtMeshMap; + std::vector commonMeshes; + + inline void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { + const auto &meshVlk = (GMeshVLK*) mesh.get(); + auto const &pipeline = meshVlk->material()->getPipeline(); + + if (meshMap.find(pipeline) == meshMap.end()) { + meshMap.reserve(3000); + } + + auto &drawCommand = meshMap[pipeline].emplace_back(); + drawCommand.indexCount = meshVlk->end(); + drawCommand.instanceCount = 1; + drawCommand.firstIndex = meshVlk->start() / 2; + + if (meshVlk->instanceIndex != -1) { + drawCommand.firstInstance = meshVlk->instanceIndex; + drawCommand.vertexOffset = meshVlk->vertexStart; + } else { + drawCommand.firstInstance = 0; + drawCommand.vertexOffset = 0; + } + } +public: + void addM2Mesh(const HGM2Mesh &mesh) override { + fillMapWithMesh(m2MeshMap, mesh); + }; + void addWMOMesh(const HGMesh &mesh) override { + fillMapWithMesh(wmoMeshMap, mesh); + } ; + void addWaterMesh(const HGMesh &mesh) override { + fillMapWithMesh(waterMeshMap, mesh); + } ; + void addADTMesh(const HGMesh &mesh) override { + fillMapWithMesh(adtMeshMap, mesh); + } ; + + void addMesh(const HGMesh &mesh) override { + commonMeshes.push_back(mesh); + }; + + void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + cmdBuf.setDefaultScissors(); + cmdBuf.setViewPort(viewPortType); + + if (!adtMeshMap.empty()) + { + //1. Render ADT + cmdBuf.bindVertexBindings(m_renderer.getDefaultADTVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalADTMaterial()); + + for (auto const &record : adtMeshMap) { + cmdBuf.bindPipeline(record.first); + + for (auto const & drawCmd : record.second) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + } + + if (!wmoMeshMap.empty()) + { + //2. Render WMO + cmdBuf.bindVertexBindings(m_renderer.getDefaultWMOVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalWMOMaterial()); + + for (auto const &record : wmoMeshMap) { + cmdBuf.bindPipeline(record.first); + + for (auto const & drawCmd : record.second) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + } + + if (!m2MeshMap.empty()) + { + //3. Render m2 + cmdBuf.bindVertexBindings(m_renderer.getDefaultM2Vao()); + cmdBuf.bindMaterial(m_renderer.getGlobalM2Material()); + + for (auto const &record : m2MeshMap) { + cmdBuf.bindPipeline(record.first); + + for (auto const & drawCmd : record.second) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + } + + //Render commonMeshes + for (auto const &mesh : commonMeshes ) { + MapSceneRenderVisBufferVLK::drawMesh(cmdBuf, mesh, viewPortType); + } + } + void renderWater(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + cmdBuf.setDefaultScissors(); + cmdBuf.setViewPort(viewPortType); + + if (!waterMeshMap.empty()) + { + //4. Render water + cmdBuf.bindVertexBindings(m_renderer.getDefaultWaterVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalWaterMaterial()); + + for (auto const &record : waterMeshMap) { + cmdBuf.bindPipeline(record.first); + + for (auto const & drawCmd : record.second) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + } + } + +}; + std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { TracyMessageStr(("Update stage frame = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); @@ -929,11 +1094,10 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s //Create meshes - auto opaqueMeshes = std::make_shared>(); + std::unique_ptr u_collector = std::make_unique(*this); + std::unique_ptr u_skyCollector = std::make_unique(*this); auto transparentMeshes = std::make_shared>(); - auto liquidMeshes = std::make_shared>(); - auto skyOpaqueMeshes = std::make_shared>(); auto skyTransparentMeshes = std::make_shared>(); framePlan->m2Array.lock(); framePlan->wmoArray.lock(); @@ -945,35 +1109,8 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { - collectMeshes(framePlan, opaqueMeshes, transparentMeshes, - liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); - - { - ZoneScopedN("sort opaque"); - std::sort(opaqueMeshes->begin(), opaqueMeshes->end(), [](const HGMesh &a, const HGMesh &b) -> bool { - const auto &mesh_a = (GMeshVLK*) a.get(); - const auto &mesh_b = (GMeshVLK*) b.get(); + collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); - auto const &material_a = mesh_a->material(); - auto const &material_b = mesh_b->material(); - - const auto &shader_a = material_a->getShader(); - const auto &shader_b = material_b->getShader(); - - if (shader_a != shader_b) { - return shader_a < shader_b; - } - - const auto &pipeline_a = material_a->getPipeline(); - const auto &pipeline_b = material_b->getPipeline(); - - if (pipeline_a != pipeline_b) { - return pipeline_a < pipeline_b; - } - - return a->start() < b->start(); - }); - } // } // ); @@ -1084,8 +1221,9 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); } - }, [opaqueMeshes, transparentMeshes, liquidMeshes, - skyOpaqueMeshes, skyTransparentMeshes, + }, [transparentMeshes, l_opaqueMeshes = std::move(u_collector), + l_skyOpaqueMeshes = std::move(u_skyCollector), + skyTransparentMeshes, renderSky, skyMesh, skyMesh0x4, @@ -1114,13 +1252,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s { ZoneScopedN("submit opaque"); VkZone(frameBufCmd, "render opaque") - auto const &pOpaqueMeshes = *opaqueMeshes; - auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); - - for (int i = 0; i < pOpaqueMeshesSize; i++) { - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], - CmdBufRecorder::ViewportType::vp_usual); - } + l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); } { //Sky opaque @@ -1128,10 +1260,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); - for (auto const &mesh: *skyOpaqueMeshes) { - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_skyBox); - } + l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); } { //Sky transparent @@ -1156,10 +1285,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s } { //Render liquids - for (auto const &mesh: *liquidMeshes) { - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_usual); - } + l_opaqueMeshes->renderWater(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); } { VkZone(frameBufCmd, "render transparent") diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index e61ae02eb..ae7996153 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -196,11 +196,11 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr> sceneWideChunk; std::shared_ptr sceneWideDS = nullptr; + std::shared_ptr g_m2Material = nullptr; + std::shared_ptr m2BufferOneDS = nullptr; std::shared_ptr m2TextureDS = nullptr; std::shared_ptr m2TextureHolder = nullptr; - std::shared_ptr m2BufferOneDS = nullptr; - std::shared_ptr m2WaterfallBufferDS = nullptr; std::shared_ptr m2WaterfallTextureDS = nullptr; std::shared_ptr m2WaterfallTextureHolder = nullptr; @@ -218,6 +218,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr wmoTexturesDS = nullptr; std::shared_ptr wmoTextureHolder = nullptr; + std::shared_ptr g_waterMaterial = nullptr; std::shared_ptr waterDataDS = nullptr; std::shared_ptr waterTexturesDS = nullptr; std::shared_ptr waterTextureHolder = nullptr; @@ -242,6 +243,17 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { void createADTGlobalMaterialData(); void createWaterGlobalMaterialData(); void createM2WaterfallGlobalMaterialData(); +public: + const std::shared_ptr &getGlobalADTMaterial() const {return g_adtMaterial;}; + const std::shared_ptr &getGlobalM2Material() const {return g_m2Material;}; + const std::shared_ptr &getGlobalWMOMaterial() const {return g_wmoMaterial;}; + const std::shared_ptr &getGlobalWaterMaterial() const {return g_waterMaterial;}; + + const HGVertexBufferBindings getDefaultADTVao() {return m_emptyADTVAO;}; + const HGVertexBufferBindings getDefaultM2Vao() {return m_emptyM2VAO;}; + const HGVertexBufferBindings getDefaultWMOVao() {return m_emptyWMOVAO;}; + const HGVertexBufferBindings getDefaultWaterVao() {return m_emptyWaterVAO;}; + }; class IM2ModelDataVisVLK : public IM2ModelData { From 65b96ad45450261a28210d9b66fc6ca6820a0be4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 21 Oct 2023 05:09:52 +0300 Subject: [PATCH 143/212] - ribbon shader in Bindless ver 1 - fixes for waterfallShader --- .../forwardRendering/waterfallShader.vert | 2 +- .../shaders/glsl/visBuffer/adtShader.vert | 5 +- .../shaders/glsl/visBuffer/ribbonShader.frag | 50 +++ .../shaders/glsl/visBuffer/ribbonShader.vert | 33 ++ .../glsl/visBuffer/waterfallShader.vert | 2 +- .../src/engine/objects/ViewsObjects.cpp | 2 +- .../src/engine/objects/m2/m2Object.cpp | 6 +- .../src/engine/objects/scenes/map.cpp | 98 ++---- wowViewerLib/src/engine/objects/scenes/map.h | 1 - .../src/engine/objects/wmo/wmoGroupObject.cpp | 1 - .../src/engine/shader/ShaderDefinitions.h | 297 +++++++----------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 24 +- .../descriptorSets/GDescriptorSetLayout.cpp | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 20 +- 14 files changed, 279 insertions(+), 264 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert index ee3daeeda..c004d046f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.vert @@ -75,7 +75,7 @@ void main() { vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); vNormal = normal; - vPosition = pos; + vPosition = cameraPoint.xyz; vTexCoord = aTexCoord; vTexCoord2_animated = texCoord2; diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index a5190fc13..5d530bcca 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -86,8 +86,11 @@ void main() { vChunkCoords = vec2(iX, iY); + // Top left point (17058 17063) becomes (0,0) + vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - adtMeshWideVSPS.uPos.yx; + // Add half chunk to do little offset before doing floor in next step + coordsInAdtIndexSpace += vec2(CHUNKSIZE/2.0); - vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - adtMeshWideVSPS.uPos.yx; //Top left point (17058 17063) becomes (0,0) vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); vAlphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - aPos.yx) / TILESIZE; diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag new file mode 100644 index 000000000..72a744069 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag @@ -0,0 +1,50 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + +precision highp float; +layout(location = 0) in vec3 vPosition; +layout(location = 1) in vec4 vColor; +layout(location = 2) in vec2 vTexcoord0; + + + +layout(std140, set=1, binding=3) buffer readonly textureMatrices { + mat4 textureMatrix[64]; +}; +layout(std140, set=1, binding=4) uniform meshWideBlockPS { + ivec4 uPixelShader_BlendMode_TextureTransformIndex; +}; + +layout(set=2, binding=5) uniform sampler2D uTexture; + +layout(location = 0) out vec4 outputColor; + +void main() { + int textureTransformIndex = uPixelShader_BlendMode_TextureTransformIndex.z; + + vec2 texcoord = vTexcoord0; + if (textureTransformIndex >= 0) { + mat4 textMat = textureMatrix[textureTransformIndex]; + vec2 textCoordScale = vec2(length(textMat[0].xyz), length(textMat[2].xyz)); + vec2 textureTranslate = textMat[3].xy; + texcoord = (vTexcoord0 * textCoordScale) + textureTranslate.xy; + } + + vec4 tex = texture(uTexture, texcoord).rgba; + + vec4 finalColor = vec4((vColor.rgb*tex.rgb), tex.a * vColor.a); + + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); + + outputColor = finalColor; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert new file mode 100644 index 000000000..e07baea34 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert @@ -0,0 +1,33 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require + +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + +precision highp float; +layout(location = 0) in vec3 aPosition; +layout(location = 1) in vec4 aColor; +layout(location = 2) in vec2 aTexcoord0; + + + +layout(location = 0) out vec3 vPosition; +layout(location = 1) out vec4 vColor; +layout(location = 2) out vec2 vTexcoord0; + +void main() { + vec4 aPositionVec4 = vec4(aPosition, 1); + + vColor = aColor; + vTexcoord0 = aTexcoord0; + vec4 vertexViewSpace = (scene.uLookAtMat * aPositionVec4); + + vPosition = vertexViewSpace.xyz; + gl_Position = scene.uPMatrix * vertexViewSpace; + +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert index 309fff567..950371a99 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert @@ -77,7 +77,7 @@ void main() { vec3 normal = normalize((viewModelMatForNormal * vec4(aNormal, 0.0)).xyz); vNormal = normal; - vPosition = pos; + vPosition = cameraPoint.xyz; vTexCoord = aTexCoord; vTexCoord2_animated = texCoord2; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 9f6ea7a88..9656a349e 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -10,7 +10,7 @@ #if (__AVX__ && __SSE2__) #include "../algorithms/mathHelper_culling_sse.h" #endif - +#include "../algorithms/mathHelper_culling.h" void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) { if (renderADT) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 691e0e3a7..571f72560 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1636,6 +1636,8 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vec int minBatch = m_api->getConfig()->m2MinBatch; int maxBatch = std::min(m_api->getConfig()->m2MaxBatch, (const int &) this->m_meshArray.size()); + bool isWaterFallMesh = m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr; + if (m_api->getConfig()->renderM2) { for (int i = 0; i < this->m_meshArray.size(); i++) { int currentM2BatchIndex = std::get<1>(this->m_meshArray[i]); @@ -1655,7 +1657,7 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vec if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { - if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { + if (isWaterFallMesh) { opaqueMeshCollector.addM2Mesh(mesh); } else { opaqueMeshCollector.addMesh(mesh); @@ -1679,7 +1681,7 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vec if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { - if (m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr) { + if (!isWaterFallMesh) { opaqueMeshCollector.addM2Mesh(mesh); } else { opaqueMeshCollector.addMesh(mesh); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 3aad689e1..b1ced366e 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1309,47 +1309,57 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende { ZoneScopedN("Load m2 main"); - for (auto &m2Object: renderPlan->m2Array.getToLoadMain()) { - if (m2Object == nullptr) continue; - m2Object->doLoadMainFile(); + if (m_api->getConfig()->renderM2) { + for (auto &m2Object: renderPlan->m2Array.getToLoadMain()) { + if (m2Object == nullptr) continue; + m2Object->doLoadMainFile(); + } } } { ZoneScopedN("Load m2 geom"); - for (auto &m2Object: renderPlan->m2Array.getToLoadGeom()) { - if (m2Object == nullptr) continue; - m2Object->doLoadGeom(sceneRenderer); - m2ProcessedThisFrame++; + if (m_api->getConfig()->renderM2) { + for (auto &m2Object: renderPlan->m2Array.getToLoadGeom()) { + if (m2Object == nullptr) continue; + m2Object->doLoadGeom(sceneRenderer); + m2ProcessedThisFrame++; // if (m2ProcessedThisFrame > 100) break; + } } } - if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { - for (auto &m2Object : skyboxView->m2List.getToLoadMain()) { - if (m2Object == nullptr) continue; - m2Object->doLoadMainFile(); - } - for (auto &m2Object: skyboxView->m2List.getToLoadGeom()) { - if (m2Object == nullptr) continue; - m2Object->doLoadGeom(sceneRenderer); + if (m_api->getConfig()->renderSkyDom) { + if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { + for (auto &m2Object: skyboxView->m2List.getToLoadMain()) { + if (m2Object == nullptr) continue; + m2Object->doLoadMainFile(); + } + for (auto &m2Object: skyboxView->m2List.getToLoadGeom()) { + if (m2Object == nullptr) continue; + m2Object->doLoadGeom(sceneRenderer); + } } } // } { ZoneScopedN("Load wmoObject"); - for (auto &wmoObject: renderPlan->wmoArray.getToLoad()) { - if (wmoObject == nullptr) continue; - wmoObject->doPostLoad(sceneRenderer); + if (m_api->getConfig()->renderWMO) { + for (auto &wmoObject: renderPlan->wmoArray.getToLoad()) { + if (wmoObject == nullptr) continue; + wmoObject->doPostLoad(sceneRenderer); + } } } { ZoneScopedN("Load wmo group"); - for (auto &wmoGroupObject: renderPlan->wmoGroupArray.getToLoad()) { - if (wmoGroupObject == nullptr) continue; - wmoGroupObject->doPostLoad(sceneRenderer); - wmoGroupsProcessedThisFrame++; - if (wmoGroupsProcessedThisFrame > 20) break; + if (m_api->getConfig()->renderWMO) { + for (auto &wmoGroupObject: renderPlan->wmoGroupArray.getToLoad()) { + if (wmoGroupObject == nullptr) continue; + wmoGroupObject->doPostLoad(sceneRenderer); + wmoGroupsProcessedThisFrame++; + if (wmoGroupsProcessedThisFrame > 20) break; + } } } @@ -1360,48 +1370,6 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende } } - if (quadBindings == nullptr) - { - const float epsilon = 0.f; - - std::array vertexBuffer = { - mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, -1.0f + epsilon)), - mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, 1.0f - epsilon)), - mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, -1.0f+ epsilon)), - mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, 1.f - epsilon)) - }; - std::vector indexBuffer = { - 0, 1, 2, - 2, 1, 3 - }; - -// std::cout << "indexBuffer.size = " << indexBuffer.size() << std::endl; - -//TODO: -/* - auto quadIBO = m_api->hDevice->createIndexBuffer(); - quadIBO->uploadData( - indexBuffer.data(), - indexBuffer.size() * sizeof(uint16_t)); - - auto quadVBO = m_api->hDevice->createVertexBuffer(); - quadVBO->uploadData( - vertexBuffer.data(), - vertexBuffer.size() * sizeof(mathfu::vec2_packed) - ); - - quadBindings = m_api->hDevice->createVertexBufferBindings(); - quadBindings->setIndexBuffer(quadIBO); - - GVertexBufferBinding vertexBinding; - vertexBinding.vertexBuffer = quadVBO; - - vertexBinding.bindings = std::vector(fullScreen.begin(), fullScreen.end()); - - quadBindings->addVertexBufferBinding(vertexBinding); - quadBindings->save(); - */ - } if (skyMesh == nullptr) { auto skyMeshBinding = createSkyBindings(sceneRenderer); std::tie(skyMesh, skyMeshMat) = createSkyMesh(sceneRenderer, skyMeshBinding, false); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 4ad3a049a..ff48b2102 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -60,7 +60,6 @@ class Map : public IScene, public IMapApi { int m_viewRenderOrder = 0; - HGVertexBufferBindings quadBindings; float m_skyConeAlpha = 0.0; HGMesh skyMesh = nullptr; std::shared_ptr skyMeshMat = nullptr; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index ac95cc4bf..d1da1c60e 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -231,7 +231,6 @@ void WmoGroupObject::createWaterMeshes(const HMapSceneBufferCreate &sceneRendere //Get Liquid with new method setLiquidType(); - return; HGVertexBufferBindings binding = m_geom->getWaterVertexBindings(sceneRenderer, liquid_type, m_waterAaBB); if (binding == nullptr) return; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index dd6de01f4..d403f6a5e 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -298,6 +298,81 @@ const std::unordered_map> attributesPe }; const std::unordered_map shaderMetaInfo = { +{ "visBuffer/ribbonShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,480}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "visBuffer/ribbonShader.frag.spv", + { + ShaderStage::Fragment, + { + {1,4,16}, + {0,0,480}, + }, + { + { + {0,0,1}, + {4,4,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,3,4096}, + }, + { + {2,5, "uTexture"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {5,5,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, @@ -321,11 +396,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -432,9 +502,6 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {0,0,480}, {1,1,64}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, }, { { @@ -566,11 +633,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -756,8 +818,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -796,7 +856,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -837,11 +896,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -859,17 +917,11 @@ const std::unordered_map shaderMetaInfo = { { {2,5,96}, {0,0,480}, - {1,1,64}, - {1,2,256}, - {1,3,16384}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, }, { { {0,0,1}, - {1,6,6}, + {0,0,0}, {5,5,1}, {0,0,0}, {0,0,0}, @@ -904,11 +956,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1030,15 +1081,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1061,11 +1103,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1235,8 +1276,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1276,16 +1315,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1322,7 +1359,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1382,12 +1418,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,12 +1470,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1658,7 +1691,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,1,64}, {1,6,4096}, - {1,3,16384}, }, { { @@ -1715,7 +1747,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -1996,17 +2027,12 @@ const std::unordered_map shaderMetaInfo = { {1,3,16384}, {1,1,64}, {0,0,480}, - {1,2,256}, - {1,4,4096}, - {1,5,256}, - {1,6,4096}, - {2,7,64}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {1,3,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2111,32 +2137,10 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, { 7, { } }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, @@ -2168,17 +2172,13 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2605,7 +2565,12 @@ const std::unordered_map &ds) { ds->beginUpdate() .ssbo(0, m2WaterfallBuffer.waterfallCommon) @@ -530,6 +534,7 @@ HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) std::shared_ptr MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { + ZoneScoped; auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); auto fragmentData = std::make_shared>(adtBuffers.adtMeshWidePSes); @@ -590,6 +595,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2MaterialTemplate &m2MaterialTemplate) { + ZoneScoped; auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); @@ -731,12 +737,12 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMat auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; - auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, visShaderConfig) .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ssbo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) .ubo(4, *l_fragmentData); }) .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { @@ -973,9 +979,9 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ const auto &meshVlk = (GMeshVLK*) mesh.get(); auto const &pipeline = meshVlk->material()->getPipeline(); - if (meshMap.find(pipeline) == meshMap.end()) { - meshMap.reserve(3000); - } + auto &vec = meshMap[pipeline]; + if (vec.empty()) + vec.reserve(3000); auto &drawCommand = meshMap[pipeline].emplace_back(); drawCommand.indexCount = meshVlk->end(); @@ -1349,6 +1355,8 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTe HGMesh MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { + ZoneScoped; + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyADTVAO; @@ -1362,7 +1370,7 @@ MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const st HGM2Mesh MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - + ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyM2VAO; auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); From 3b970012142aacb0f97999199b2a487a3edbb521 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 22 Oct 2023 00:03:34 +0300 Subject: [PATCH 144/212] - restore forward rendering --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- .../glsl/common/commonM2DescriptorSet.glsl | 12 +- .../glsl/forwardRendering/adtShader.frag | 27 +- .../glsl/forwardRendering/adtShader.vert | 38 +- .../forwardRendering/drawPortalShader.frag | 2 +- .../glsl/forwardRendering/drawQuad.vert | 2 +- .../glsl/forwardRendering/ffxgauss4.frag | 9 +- .../glsl/forwardRendering/ffxglow.frag | 6 +- .../glsl/forwardRendering/imguiShader.frag | 2 +- .../glsl/forwardRendering/imguiShader.vert | 2 +- .../forwardRendering/m2ParticleShader.frag | 8 +- .../glsl/forwardRendering/m2Shader.frag | 10 +- .../glsl/forwardRendering/m2Shader.vert | 2 +- .../glsl/forwardRendering/ribbonShader.frag | 6 +- .../glsl/forwardRendering/skyConus.vert | 2 +- .../glsl/forwardRendering/waterShader.frag | 4 +- .../glsl/forwardRendering/waterShader.vert | 2 +- .../forwardRendering/waterfallShader.frag | 3 +- .../glsl/forwardRendering/wmoShader.frag | 22 +- .../glsl/forwardRendering/wmoShader.vert | 4 +- .../src/engine/objects/scenes/map.cpp | 2 - .../src/engine/shader/ShaderDefinitions.h | 386 +++++++++--------- .../vulkan/descriptorSets/GDescriptorSet.cpp | 4 +- .../vulkan/descriptorSets/GDescriptorSet.h | 2 +- .../mapScene/MapSceneRendererFactory.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 194 +++++---- .../vulkan/MapSceneRenderForwardVLK.h | 4 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 14 +- 28 files changed, 414 insertions(+), 361 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 6d373471f..ed82e7198 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -62,11 +62,11 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *l_imguiUbo); + .ubo(0, *l_imguiUbo); }) .createDescriptorSet(1, [&hgtexture](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, hgtexture); + .texture(0, hgtexture); }) .toMaterial([&] (IUIMaterial *uiMat){ uiMat->uniqueId = this->generateUniqueMatId(); diff --git a/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl index f68c8b48c..98bfbb370 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2DescriptorSet.glsl @@ -5,29 +5,29 @@ #endif // Whole model -layout(std140, set=1, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=0) uniform modelWideBlockVS { mat4 uPlacementMat; }; -layout(std140, set=1, binding=2) uniform modelWideBlockPS { +layout(std140, set=1, binding=1) uniform modelWideBlockPS { InteriorLightParam intLight; LocalLight pc_lights[4]; ivec4 lightCountAndBcHack; vec4 interiorExteriorBlend; }; -layout(std140, set=1, binding=3) uniform boneMats { +layout(std140, set=1, binding=2) uniform boneMats { mat4 uBoneMatrixes[MAX_MATRIX_NUM]; }; -layout(std140, set=1, binding=4) uniform m2Colors { +layout(std140, set=1, binding=3) uniform m2Colors { vec4 colors[256]; }; -layout(std140, set=1, binding=5) uniform textureWeights { +layout(std140, set=1, binding=4) uniform textureWeights { vec4 textureWeight[16]; }; -layout(std140, set=1, binding=6) uniform textureMatrices { +layout(std140, set=1, binding=5) uniform textureMatrices { mat4 textureMatrix[64]; }; \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 1b2d87e96..073c035b5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -13,27 +13,28 @@ layout(location = 1) in vec3 vPosition; layout(location = 2) in vec4 vColor; layout(location = 3) in vec3 vNormal; layout(location = 4) in vec3 vVertexLighting; - -layout(set=2, binding=5) uniform sampler2D uLayer0; -layout(set=2, binding=6) uniform sampler2D uLayer1; -layout(set=2, binding=7) uniform sampler2D uLayer2; -layout(set=2, binding=8) uniform sampler2D uLayer3; -layout(set=2, binding=9) uniform sampler2D uAlphaTexture; -layout(set=2, binding=10) uniform sampler2D uLayerHeight0; -layout(set=2, binding=11) uniform sampler2D uLayerHeight1; -layout(set=2, binding=12) uniform sampler2D uLayerHeight2; -layout(set=2, binding=13) uniform sampler2D uLayerHeight3; +layout(location = 5) in vec2 vAlphaCoords; + +layout(set=2, binding=0) uniform sampler2D uLayer0; +layout(set=2, binding=1) uniform sampler2D uLayer1; +layout(set=2, binding=2) uniform sampler2D uLayer2; +layout(set=2, binding=3) uniform sampler2D uLayer3; +layout(set=2, binding=4) uniform sampler2D uAlphaTexture; +layout(set=2, binding=5) uniform sampler2D uLayerHeight0; +layout(set=2, binding=6) uniform sampler2D uLayerHeight1; +layout(set=2, binding=7) uniform sampler2D uLayerHeight2; +layout(set=2, binding=8) uniform sampler2D uLayerHeight3; #include "../common/commonUboSceneData.glsl" -layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { +layout(std140, set=1, binding=0) uniform meshWideBlockVSPS { vec4 uPos; ivec4 uUseHeightMixFormula; vec4 uHeightScale; vec4 uHeightOffset; }; -layout(std140, set=1, binding=2) uniform meshWideBlockPS { +layout(std140, set=1, binding=1) uniform meshWideBlockPS { vec4 scaleFactorPerLayer; ivec4 animation_rotationPerLayer; ivec4 animation_speedPerLayer; @@ -87,7 +88,7 @@ void main() { vec2 vTexCoord = vChunkCoords; const float threshold = 1.5; - vec2 alphaCoord = vec2(vChunkCoords.x/8.0, vChunkCoords.y/8.0 ); + vec2 alphaCoord = vec2(vAlphaCoords); vec3 alphaBlend = texture( uAlphaTexture, alphaCoord).gba; vec2 tcLayer0 = transformUV(vTexCoord, 0); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 7c8299a08..64a12c452 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -16,7 +16,7 @@ layout(location = 3) in vec3 aNormal; #include "../common/commonUboSceneData.glsl" -layout(std140, set=1, binding=1) uniform meshWideBlockVSPS { +layout(std140, set=1, binding=0) uniform meshWideBlockVSPS { vec4 uPos; ivec4 uUseHeightMixFormula; vec4 uHeightScale; @@ -36,9 +36,25 @@ layout(location = 1) out vec3 vPosition; layout(location = 2) out vec4 vColor; layout(location = 3) out vec3 vNormal; layout(location = 4) out vec3 vVertexLighting; +layout(location = 5) out vec2 vAlphaCoords; -const float UNITSIZE_X = (1600.0 / 3.0) / 16.0 / 8.0; -const float UNITSIZE_Y = (1600.0 / 3.0) / 16.0 / 8.0; +const float TILESIZE = (1600.0 / 3.0); +const float CHUNKSIZE = TILESIZE / 16.0; +const float UNITSIZE = CHUNKSIZE / 8.0; + +float fixUVBorder(float uvComp, float x) { + const float alphaTextureSize_px = 1024.0; + const float subPixel = 0.5 / alphaTextureSize_px; + + float epsilon = 0.0001; + + if (x < epsilon) + uvComp += subPixel; + if ((1.0 - x) < epsilon) + uvComp -= subPixel; + + return uvComp ; +} void main() { @@ -61,8 +77,8 @@ void main() { } // vec4 worldPoint = vec4( -// uPos.x - iY * UNITSIZE_Y, -// uPos.y - iX * UNITSIZE_X, +// uPos.x - iY * UNITSIZE, +// uPos.y - iX * UNITSIZE, // uPos.z + aHeight, // 1); @@ -70,6 +86,18 @@ void main() { vChunkCoords = vec2(iX, iY); + // Top left point (17058 17063) becomes (0,0) + vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - uPos.yx; + // Add half chunk to do little offset before doing floor in next step + coordsInAdtIndexSpace += vec2(CHUNKSIZE/2.0); + + vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); + + vAlphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - aPos.yx) / TILESIZE; + + vAlphaCoords.x = fixUVBorder(vAlphaCoords.x, vChunkCoords.x/8.0); + vAlphaCoords.y = fixUVBorder(vAlphaCoords.y, vChunkCoords.y/8.0); + vPosition = (scene.uLookAtMat * worldPoint).xyz; vColor = aColor; vVertexLighting = aVertexLighting.rgb; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag index 5bb45fe53..74af02983 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawPortalShader.frag @@ -4,7 +4,7 @@ precision highp float; precision highp int; //Individual mesh -layout(std140, set=1, binding=1) uniform meshWideBlockPS { +layout(std140, set=1, binding=0) uniform meshWideBlockPS { vec4 uColor; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert b/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert index 8f238526f..94022eea5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/drawQuad.vert @@ -5,7 +5,7 @@ precision highp int; layout (location = 0) in vec2 position; -layout(std140, set=0, binding=2) uniform meshWideBlockVS { +layout(std140, set=0, binding=0) uniform meshWideBlockVS { vec4 uWidth_uHeight_uX_uY; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag b/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag index 523ac8bef..bf7b1ddd5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ffxgauss4.frag @@ -6,13 +6,14 @@ precision highp int; layout(location = 0) in vec2 texCoord; layout(location = 0) out vec4 out_result; -layout(set=1,binding=5) uniform sampler2D texture0; -layout(std140, binding=4) uniform meshWideBlockPS { - vec4 texOffsetX; - vec4 texOffsetY; +layout(std140, set=0, binding=1) uniform meshWideBlockPS { +vec4 texOffsetX; +vec4 texOffsetY; }; +layout(set=1,binding=0) uniform sampler2D texture0; + //const float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); const float weight[5] = float[] (0, 0.125, 0.375, 0.375, 0.125); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag b/wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag index 808b5602e..9679e96fe 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ffxglow.frag @@ -5,12 +5,12 @@ precision highp int; layout(location = 0) in vec2 texCoord; -layout(std140, binding=4) uniform meshWideBlockPS { +layout(std140, binding=1) uniform meshWideBlockPS { vec4 blurAmount; }; -layout(set=1,binding=5) uniform sampler2D screenTex; -layout(set=1,binding=6) uniform sampler2D blurTex; +layout(set=1,binding=0) uniform sampler2D screenTex; +layout(set=1,binding=1) uniform sampler2D blurTex; layout (location = 0) out vec4 Out_Color; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag index f3549a2d7..e862de005 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.frag @@ -6,7 +6,7 @@ precision highp int; layout(location=0) in vec2 Frag_UV; layout(location=1) in vec4 Frag_Color; -layout(set=1,binding=5) uniform sampler2D Texture; +layout(set=1,binding=0) uniform sampler2D Texture; layout (location = 0) out vec4 Out_Color; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert index f2cdcdfe4..e281668e4 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader.vert @@ -7,7 +7,7 @@ layout (location = 0) in vec2 Position; layout (location = 1) in vec2 UV; layout (location = 2) in vec4 Color; -layout(std140, set=0, binding=1) uniform modelWideBlockVS { +layout(std140, set=0, binding=0) uniform modelWideBlockVS { mat4 ProjMtx; vec4 uiScale; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag index 2aed8930f..65eca5e51 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2ParticleShader.frag @@ -19,14 +19,14 @@ layout(location = 5) in float alphaCutoff; //Individual meshes -layout(std140, set=1, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=0) uniform meshWideBlockPS { vec4 uAlphaTest_alphaMult_colorMult; ivec4 uPixelShaderBlendModev; }; -layout(set=2,binding=5) uniform sampler2D uTexture; -layout(set=2,binding=6) uniform sampler2D uTexture2; -layout(set=2,binding=7) uniform sampler2D uTexture3; +layout(set=2,binding=0) uniform sampler2D uTexture; +layout(set=2,binding=1) uniform sampler2D uTexture2; +layout(set=2,binding=2) uniform sampler2D uTexture3; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 61d22fd8e..f064c4b6c 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -23,17 +23,17 @@ layout(location=0) out vec4 outputColor; #include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { +layout(std140, set=2, binding=0) uniform meshWideBlockVSPS { ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; ivec4 PixelShader_UnFogged_blendMode; ivec4 textureWeightIndexes; ivec4 colorIndex_applyWeight; }; -layout(set=3,binding=6) uniform sampler2D uTexture; -layout(set=3,binding=7) uniform sampler2D uTexture2; -layout(set=3,binding=8) uniform sampler2D uTexture3; -layout(set=3,binding=9) uniform sampler2D uTexture4; +layout(set=3,binding=0) uniform sampler2D uTexture; +layout(set=3,binding=1) uniform sampler2D uTexture2; +layout(set=3,binding=2) uniform sampler2D uTexture3; +layout(set=3,binding=3) uniform sampler2D uTexture4; void main() { /* Animation support */ diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert index ca68f773f..1981bce40 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.vert @@ -27,7 +27,7 @@ layout(location=5) in vec2 aTexCoord2; #include "../common/commonM2DescriptorSet.glsl" //Individual meshes -layout(std140, set=2, binding=7) uniform meshWideBlockVSPS { +layout(std140, set=2, binding=0) uniform meshWideBlockVSPS { ivec4 vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2; ivec4 PixelShader_UnFogged_blendMode; ivec4 textureWeightIndexes; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag index 704f9af66..95163b43f 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/ribbonShader.frag @@ -16,14 +16,14 @@ layout(location = 2) in vec2 vTexcoord0; -layout(std140, set=1, binding=3) uniform textureMatrices { +layout(std140, set=1, binding=0) uniform textureMatrices { mat4 textureMatrix[64]; }; -layout(std140, set=1, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=1) uniform meshWideBlockPS { ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; -layout(set=2, binding=5) uniform sampler2D uTexture; +layout(set=2, binding=0) uniform sampler2D uTexture; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert index fdbc53b11..9d22fa4b5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/skyConus.vert @@ -12,7 +12,7 @@ precision highp int; precision highp float; -layout(std140, set=1, binding=1) uniform meshWideBlockVS { +layout(std140, set=1, binding=0) uniform meshWideBlockVS { vec4 skyColor[6]; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 183c9cc4f..c26c33025 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -14,12 +14,12 @@ layout(location=2) in vec3 vNormal; layout(location=0) out vec4 outputColor; -layout(set=2,binding=5) uniform sampler2D uTexture; +layout(set=2,binding=0) uniform sampler2D uTexture; #include "../common/commonUboSceneData.glsl" //Individual meshes -layout(std140, set=1, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=1) uniform meshWideBlockPS { ivec4 materialId; vec4 color; mat4 textureMatrix; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert index ac9658f93..d0445c7c5 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.vert @@ -15,7 +15,7 @@ layout(location=1) in vec2 aTexCoord; -layout(std140, set=1, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=0) uniform modelWideBlockVS { mat4 uPlacementMat; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index 2e4a389d2..deafcb8d4 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -28,7 +28,8 @@ layout(location=0) out vec4 outputColor; //Whole model #include "../common/commonM2DescriptorSet.glsl" -layout(std140, set=2, binding=5) uniform meshWideBlockPS { +layout(std140, set=2, binding=0) uniform meshWideBlockVS { + vec4 bumpScale_textTransformInd1_textTransformInd2; vec4 values0; vec4 values1; vec4 values2; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index d8985a738..c7e9f1107 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -25,22 +25,20 @@ layout(location=7) in vec4 vPosition; layout(location=8) in vec3 vNormal; layout(location=9) in vec4 vWmoAmbient; - - -layout(std140, set=1, binding=3) uniform meshWideBlockPS { +layout(std140, set=1, binding=2) uniform meshWideBlockPS { ivec4 UseLitColor_EnableAlpha_PixelShader_BlendMode; vec4 FogColor_AlphaTest; }; -layout(set=2, binding=5) uniform sampler2D uTexture; -layout(set=2, binding=6) uniform sampler2D uTexture2; -layout(set=2, binding=7) uniform sampler2D uTexture3; -layout(set=2, binding=8) uniform sampler2D uTexture4; -layout(set=2, binding=9) uniform sampler2D uTexture5; -layout(set=2, binding=10) uniform sampler2D uTexture6; -layout(set=2, binding=11) uniform sampler2D uTexture7; -layout(set=2, binding=12) uniform sampler2D uTexture8; -layout(set=2, binding=13) uniform sampler2D uTexture9; +layout(set=2, binding=0) uniform sampler2D uTexture; +layout(set=2, binding=1) uniform sampler2D uTexture2; +layout(set=2, binding=2) uniform sampler2D uTexture3; +layout(set=2, binding=3) uniform sampler2D uTexture4; +layout(set=2, binding=4) uniform sampler2D uTexture5; +layout(set=2, binding=5) uniform sampler2D uTexture6; +layout(set=2, binding=6) uniform sampler2D uTexture7; +layout(set=2, binding=7) uniform sampler2D uTexture8; +layout(set=2, binding=8) uniform sampler2D uTexture9; layout (location = 0) out vec4 outputColor; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert index 8c9436e1c..31db2c9ba 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.vert @@ -24,11 +24,11 @@ layout (location = 9) in vec4 wmoAmbient; #include "../common/commonUboSceneData.glsl" -layout(std140, set=1, binding=1) uniform modelWideBlockVS { +layout(std140, set=1, binding=0) uniform modelWideBlockVS { mat4 uPlacementMat; }; -layout(std140, set=1, binding=2) uniform meshWideBlockVS { +layout(std140, set=1, binding=1) uniform meshWideBlockVS { ivec4 VertexShader_UseLitColor; }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index b1ced366e..8f90fce46 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1298,8 +1298,6 @@ void Map::createAdtFreeLamdas() { } - - void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRenderPlan &renderPlan) { ZoneScoped; int processedThisFrame = 0; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d403f6a5e..a27ec370f 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -417,14 +417,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {1,1,64}, + {1,0,64}, {0,0,480}, - {1,2,16}, + {1,1,16}, }, { { {0,0,1}, - {1,2,2}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -498,15 +498,15 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {2,0,112}, - {1,6,4096}, - {1,3,16384}, + {1,5,4096}, + {1,2,16384}, {0,0,480}, - {1,1,64}, + {1,0,64}, }, { { {0,0,1}, - {1,6,6}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -539,12 +539,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,64}, + {1,0,64}, }, { { {0,0,1}, - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -576,12 +576,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,0,480}, - {1,1,96}, + {1,0,96}, }, { { {0,0,1}, - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -779,12 +779,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "Texture"}, + {1,0, "Texture"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -915,14 +915,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {2,5,96}, + {2,0,112}, {0,0,480}, }, { { {0,0,1}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1028,12 +1028,12 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,1,16}, + {1,0,16}, }, { { {0,0,0}, - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1138,11 +1138,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,1,80}, + {0,0,80}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1210,14 +1210,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,2,48}, + {1,1,48}, {0,0,480}, - {1,1,64}, + {1,0,64}, }, { { {0,0,1}, - {1,2,2}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,21 +1229,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,9, "uAlphaTexture"}, - {2,10, "uLayerHeight0"}, - {2,11, "uLayerHeight1"}, - {2,12, "uLayerHeight2"}, - {2,13, "uLayerHeight3"}, - {2,5, "uLayer0"}, - {2,6, "uLayer1"}, - {2,7, "uLayer2"}, - {2,8, "uLayer3"}, + {2,4, "uAlphaTexture"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1417,12 +1417,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { + {1,0,64}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,13 +1490,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,3,32}, + {1,2,32}, {0,0,480}, }, { { {0,0,1}, - {3,3,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1507,21 +1508,21 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, - {2,8, "uTexture4"}, - {2,9, "uTexture5"}, - {2,10, "uTexture6"}, - {2,11, "uTexture7"}, - {2,12, "uTexture8"}, - {2,13, "uTexture9"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {5,13,9}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1535,11 +1536,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,32}, + {0,1,32}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1552,12 +1553,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "texture0"}, + {1,0, "texture0"}, }, { { {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1572,11 +1573,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,2,16}, + {0,0,16}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1608,11 +1609,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,4,16}, + {0,1,16}, }, { { - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,13 +1626,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,5, "screenTex"}, - {1,6, "blurTex"}, + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {5,6,2}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1646,13 +1647,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,96}, + {1,1,96}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1664,13 +1665,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1684,19 +1685,19 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {2,7,64}, - {1,5,256}, - {1,4,4096}, - {1,2,256}, + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,480}, - {1,1,64}, - {1,6,4096}, + {1,0,64}, + {1,5,4096}, }, { { {0,0,1}, - {1,6,6}, - {7,7,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1707,17 +1708,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,6, "uTexture"}, - {3,7, "uTexture2"}, - {3,8, "uTexture3"}, - {3,9, "uTexture4"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {6,9,4}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1841,13 +1842,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,32}, + {1,0,32}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1859,15 +1860,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, - {2,6, "uTexture2"}, - {2,7, "uTexture3"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {5,7,3}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2024,14 +2025,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {1,3,16384}, - {1,1,64}, + {1,2,16384}, + {1,0,64}, {0,0,480}, }, { { {0,0,1}, - {1,3,3}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2062,14 +2063,14 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,16}, - {1,3,4096}, + {1,1,16}, + {1,0,4096}, {0,0,480}, }, { { {0,0,1}, - {3,4,2}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2081,13 +2082,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,5, "uTexture"}, + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2137,6 +2138,16 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, { 7, { } @@ -2147,13 +2158,13 @@ const std::unordered_mapaddToUpdate(m_set.shared_from_this()); } std::function GDescriptorSet::SetUpdateHelper::createCallback(int bindPoint, int arrayIndex) { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 1edc322aa..513070c6a 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -94,7 +94,7 @@ class GDescriptorSet : public std::enable_shared_from_this { //TODO: add version of this array texture case (aka bindless) SetUpdateHelper& texture(int bindIndex, const HGSamplableTexture &textureVlk, int index = 0); - void cancelUpdate(); + void delayUpdate(); template void assignBoundDescriptors(int bindPoint, const std::shared_ptr &object, int index, DescriptorRecord::DescriptorRecordType descType) { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index 972054e80..0acb74432 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -9,7 +9,7 @@ std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - return std::make_shared(std::dynamic_pointer_cast(device), config); + return std::make_shared(std::dynamic_pointer_cast(device), config); default: return std::make_shared(std::dynamic_pointer_cast(device), config); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 5656b212d..d42860c1d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -30,9 +30,6 @@ static const ShaderConfig m2ForwardShaderConfig = { { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} - }}, - {1, { - {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC}} }} }}; @@ -102,7 +99,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createDescriptorSet(0, [&](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, sceneWideChunk); + .ubo_dynamic(0, sceneWideChunk).delayUpdate(); sceneWideDS = ds; }); } @@ -250,20 +247,20 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *vertexFragmentData) - .ubo(2, *fragmentData); + .ubo(0, *vertexFragmentData) + .ubo(1, *fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&adtMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, adtMaterialTemplate.textures[0]) - .texture(6, adtMaterialTemplate.textures[1]) - .texture(7, adtMaterialTemplate.textures[2]) - .texture(8, adtMaterialTemplate.textures[3]) - .texture(9, adtMaterialTemplate.textures[4]) - .texture(10, adtMaterialTemplate.textures[5]) - .texture(11, adtMaterialTemplate.textures[6]) - .texture(12, adtMaterialTemplate.textures[7]) - .texture(13, adtMaterialTemplate.textures[8]); + .texture(0, adtMaterialTemplate.textures[0]) + .texture(1, adtMaterialTemplate.textures[1]) + .texture(2, adtMaterialTemplate.textures[2]) + .texture(3, adtMaterialTemplate.textures[3]) + .texture(4, adtMaterialTemplate.textures[4]) + .texture(5, adtMaterialTemplate.textures[5]) + .texture(6, adtMaterialTemplate.textures[6]) + .texture(7, adtMaterialTemplate.textures[7]) + .texture(8, adtMaterialTemplate.textures[8]); }) .toMaterial([&vertexFragmentData, &fragmentData](IADTMaterial *instance) -> void { instance->m_materialVSPS = vertexFragmentData; @@ -285,16 +282,16 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) - .createDescriptorSet(2, [&m2ModelData, &vertexFragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { + .createDescriptorSet(2, [&vertexFragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(7, *vertexFragmentData); + .ubo(0, *vertexFragmentData).delayUpdate(); }) .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(6, m2MaterialTemplate.textures[0]) - .texture(7, m2MaterialTemplate.textures[1]) - .texture(8, m2MaterialTemplate.textures[2]) - .texture(9, m2MaterialTemplate.textures[3]); + .texture(0, m2MaterialTemplate.textures[0]) + .texture(1, m2MaterialTemplate.textures[1]) + .texture(2, m2MaterialTemplate.textures[2]) + .texture(3, m2MaterialTemplate.textures[3]); }) .toMaterial([&vertexFragmentData](IM2Material *instance) -> void { instance->m_vertexFragmentData = vertexFragmentData; @@ -320,9 +317,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) - .createDescriptorSet(2, [&m2ModelData, &waterfallCommonData](std::shared_ptr &ds) { + .createDescriptorSet(2, [&waterfallCommonData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(0, *waterfallCommonData); + .ubo(0, *waterfallCommonData).delayUpdate(); }) .createDescriptorSet(3, [&m2MaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() @@ -349,15 +346,15 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(4, *l_fragmentData); + .ubo(0, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, m2ParticleMatTemplate.textures[0]) - .texture(6, m2ParticleMatTemplate.textures[1]) - .texture(7, m2ParticleMatTemplate.textures[2]); + .texture(0, m2ParticleMatTemplate.textures[0]) + .texture(1, m2ParticleMatTemplate.textures[1]) + .texture(2, m2ParticleMatTemplate.textures[2]); }) .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { instance->m_fragmentData = l_fragmentData; @@ -378,12 +375,12 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) - .ubo(4, *l_fragmentData); + .ubo(0, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ubo(1, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, m2RibbonMaterialTemplate.textures[0]); + .texture(0, m2RibbonMaterialTemplate.textures[0]); }) .toMaterial([l_fragmentData](IM2RibbonMaterial *instance) -> void { instance->m_fragmentData = l_fragmentData; @@ -395,6 +392,9 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater std::shared_ptr> MapSceneRenderForwardVLK::createWMOWideChunk() { return std::make_shared>(uboBuffer); } +std::shared_ptr> MapSceneRenderForwardVLK::createWMOGroupAmbientChunk() { + return std::make_shared>(vboWMOGroupAmbient); +} std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, @@ -408,21 +408,21 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, BufferChunkHelperVLK::cast(modelWide)) - .ubo(2, *l_vertexData) - .ubo(3, *l_fragmentData); + .ubo(0, BufferChunkHelperVLK::cast(modelWide)) + .ubo(1, *l_vertexData) + .ubo(2, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&wmoMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, wmoMaterialTemplate.textures[0]) - .texture(6, wmoMaterialTemplate.textures[1]) - .texture(7, wmoMaterialTemplate.textures[2]) - .texture(8, wmoMaterialTemplate.textures[3]) - .texture(9, wmoMaterialTemplate.textures[4]) - .texture(10, wmoMaterialTemplate.textures[5]) - .texture(11, wmoMaterialTemplate.textures[6]) - .texture(12, wmoMaterialTemplate.textures[7]) - .texture(13, wmoMaterialTemplate.textures[8]); + .texture(0, wmoMaterialTemplate.textures[0]) + .texture(1, wmoMaterialTemplate.textures[1]) + .texture(2, wmoMaterialTemplate.textures[2]) + .texture(3, wmoMaterialTemplate.textures[3]) + .texture(4, wmoMaterialTemplate.textures[4]) + .texture(5, wmoMaterialTemplate.textures[5]) + .texture(6, wmoMaterialTemplate.textures[6]) + .texture(7, wmoMaterialTemplate.textures[7]) + .texture(8, wmoMaterialTemplate.textures[8]); }) .toMaterial([&l_vertexData, &l_fragmentData](IWMOMaterial *instance) -> void { instance->m_materialVS = l_vertexData; @@ -443,12 +443,12 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, BufferChunkHelperVLK::cast(modelWide)) - .ubo(4, *l_fragmentData); + .ubo(0, BufferChunkHelperVLK::cast(modelWide)) + .ubo(1, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&waterMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, waterMaterialTemplate.texture); + .texture(0, waterMaterialTemplate.texture); }) .toMaterial([&l_fragmentData](IWaterMaterial *instance) -> void { instance->m_materialPS = l_fragmentData; @@ -472,7 +472,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *skyColors); + .ubo(0, *skyColors).delayUpdate(); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { instance->m_skyColors = skyColors; @@ -490,7 +490,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *materialPS); + .ubo(0, *materialPS).delayUpdate(); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { instance->m_materialPS = materialPS; @@ -502,7 +502,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); - DynamicBufferChunkHelperVLK::create(m_device, uboBuffer, result->m_placementMatrix); + BufferChunkHelperVLK::create(uboBuffer, result->m_placementMatrix); BufferChunkHelperVLK::create(uboM2BoneMatrixBuffer, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); BufferChunkHelperVLK::create(uboBuffer, result->m_textureWeights, sizeof(float) * textureWeightsCount); @@ -512,12 +512,12 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(1, DynamicBufferChunkHelperVLK::cast(result->m_placementMatrix)) - .ubo(2, BufferChunkHelperVLK::cast(result->m_modelFragmentData)) - .ubo(3, BufferChunkHelperVLK::cast(result->m_bonesData)) - .ubo(4, BufferChunkHelperVLK::cast(result->m_colors)) - .ubo(5, BufferChunkHelperVLK::cast(result->m_textureWeights)) - .ubo(6, BufferChunkHelperVLK::cast(result->m_textureMatrices)); + .ubo(0, BufferChunkHelperVLK::cast(result->m_placementMatrix)) + .ubo(1, BufferChunkHelperVLK::cast(result->m_modelFragmentData)) + .ubo(2, BufferChunkHelperVLK::cast(result->m_bonesData)) + .ubo(3, BufferChunkHelperVLK::cast(result->m_colors)) + .ubo(4, BufferChunkHelperVLK::cast(result->m_textureWeights)) + .ubo(5, BufferChunkHelperVLK::cast(result->m_textureMatrices)).delayUpdate(); result->m2CommonDS = ds; }); @@ -558,7 +558,46 @@ inline void MapSceneRenderForwardVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGM cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start()/2, 0); } +class COpaqueMeshCollectorForwardVLK : public COpaqueMeshCollector{ +public: + COpaqueMeshCollectorForwardVLK() { + commonMeshes.reserve(10000); + waterMeshes.reserve(1000); + } +private: + std::vector commonMeshes; + std::vector waterMeshes; +public: + void addM2Mesh(const HGM2Mesh &mesh) override { + commonMeshes.push_back(mesh); + }; + void addWMOMesh(const HGMesh &mesh) override { + commonMeshes.push_back(mesh); + } ; + void addWaterMesh(const HGMesh &mesh) override { + waterMeshes.push_back(mesh); + } ; + void addADTMesh(const HGMesh &mesh) override { + commonMeshes.push_back(mesh); + } ; + + void addMesh(const HGMesh &mesh) override { + commonMeshes.push_back(mesh); + }; + + void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + //Render commonMeshes + for (auto const &mesh : commonMeshes ) { + MapSceneRenderForwardVLK::drawMesh(cmdBuf, mesh, viewPortType); + } + } + void renderWater(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + for (auto const &mesh : waterMeshes ) { + MapSceneRenderForwardVLK::drawMesh(cmdBuf, mesh, viewPortType); + } + } +}; std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) { @@ -570,25 +609,21 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha //Create meshes - auto opaqueMeshes = std::make_shared>(); + std::unique_ptr u_collector = std::make_unique(); + std::unique_ptr u_skyCollector = std::make_unique(); auto transparentMeshes = std::make_shared>(); - auto liquidMeshes = std::make_shared>(); - auto skyOpaqueMeshes = std::make_shared>(); + + auto skyTransparentMeshes = std::make_shared>(); framePlan->m2Array.lock(); framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - //The portal meshes are created here. Need to call doPostLoad before CollectMeshes -// mapScene->doPostLoad(l_this, framePlan); - // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { - //TODO: -// collectMeshes(framePlan, opaqueMeshes, transparentMeshes, -// liquidMeshes, skyOpaqueMeshes, skyTransparentMeshes); + collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); // } // ); @@ -675,8 +710,9 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); } - }, [opaqueMeshes, transparentMeshes, liquidMeshes, - skyOpaqueMeshes, skyTransparentMeshes, + }, [transparentMeshes, l_opaqueMeshes = std::move(u_collector), + l_skyOpaqueMeshes = std::move(u_skyCollector), + skyTransparentMeshes, renderSky, skyMesh, skyMesh0x4, @@ -704,12 +740,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha { ZoneScopedN("submit opaque"); VkZone(frameBufCmd, "render opaque") - auto const &pOpaqueMeshes = *opaqueMeshes; - auto const pOpaqueMeshesSize = pOpaqueMeshes.size(); - for (int i = 0; i < pOpaqueMeshesSize; i++) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, pOpaqueMeshes[i], - CmdBufRecorder::ViewportType::vp_usual); - } + l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); } { //Sky opaque @@ -717,10 +748,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha MapSceneRenderForwardVLK::drawMesh(frameBufCmd, skyMesh, CmdBufRecorder::ViewportType::vp_skyBox); - for (auto const &mesh: *skyOpaqueMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_skyBox); - } + l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); } { //Sky transparent @@ -745,10 +773,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha } { //Render liquids - for (auto const &mesh: *liquidMeshes) { - MapSceneRenderForwardVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_usual); - } + l_opaqueMeshes->renderWater(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); } { VkZone(frameBufCmd, "render transparent") @@ -815,6 +840,15 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemp return mesh; } +HGSortableMesh MapSceneRenderForwardVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + return mesh; +} +HGMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { + auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + return mesh; +} + std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int width, int height, bool createOutput) { return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index d4e6d0132..f18ebafb9 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -77,6 +77,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) override; std::shared_ptr> createWMOWideChunk() override; + std::shared_ptr> createWMOGroupAmbientChunk() override; std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, const PipelineTemplate &pipelineTemplate, @@ -98,7 +99,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; - + HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; + HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; //-------------------------------------- // RenderView //-------------------------------------- diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 07b36a9e2..a4e7f76a1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -223,12 +223,12 @@ FFXGlowPassVLK::createFFXGaussMat( .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelperVLK::cast(ffxGaussVs)) - .ubo(4, BufferChunkHelperVLK::cast(ffxGaussPS)); + .ubo(0, BufferChunkHelperVLK::cast(ffxGaussVs)) + .ubo(1, BufferChunkHelperVLK::cast(ffxGaussPS)).delayUpdate(); }) .createDescriptorSet(1, [texture](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, texture); + .texture(0, texture); }) .toMaterial(); @@ -248,13 +248,13 @@ FFXGlowPassVLK::createFFXGlowMat( .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(2, BufferChunkHelperVLK::cast(ffxGlowVs)) - .ubo(4, BufferChunkHelperVLK::cast(ffxGlowPS)); + .ubo(0, BufferChunkHelperVLK::cast(ffxGlowVs)) + .ubo(1, BufferChunkHelperVLK::cast(ffxGlowPS)).delayUpdate(); }) .createDescriptorSet(1, [screenTex, blurTex](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, screenTex) - .texture(6, blurTex); + .texture(0, screenTex) + .texture(1, blurTex); }) .toMaterial(); From be819743777e52df4678fb089824f940dca0370e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 22 Oct 2023 00:30:37 +0300 Subject: [PATCH 145/212] - small fixes --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- .../shaders/glsl/visBuffer/ribbonShader.frag | 4 +- .../src/engine/shader/ShaderDefinitions.h | 259 ++++++++++++------ wowViewerLib/src/gapi/interface/IDevice.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 + wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 5 +- .../mapScene/MapSceneRendererFactory.cpp | 9 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 2 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 22 +- 9 files changed, 202 insertions(+), 104 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index ed82e7198..d4bc4a92e 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -14,7 +14,7 @@ FrontendUIRenderForwardVLK::FrontendUIRenderForwardVLK(const HGDeviceVLK &hDevice) : FrontendUIRenderer(hDevice), m_device(hDevice) { - + std::cout << "Create Bindless scene renderer " << std::endl; m_lastRenderPass = m_device->getSwapChainRenderPass(); m_emptyImguiVAO = createVAO(nullptr,nullptr); diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag index 72a744069..512c344d8 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag @@ -16,10 +16,10 @@ layout(location = 2) in vec2 vTexcoord0; -layout(std140, set=1, binding=3) buffer readonly textureMatrices { +layout(std140, set=1, binding=0) buffer readonly textureMatrices { mat4 textureMatrix[64]; }; -layout(std140, set=1, binding=4) uniform meshWideBlockPS { +layout(std140, set=1, binding=1) uniform meshWideBlockPS { ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index a27ec370f..ba09ed262 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -338,13 +338,13 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,4,16}, + {1,1,16}, {0,0,480}, }, { { {0,0,1}, - {4,4,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -354,7 +354,7 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,4096}, + {1,0,4096}, }, { {2,5, "uTexture"}, @@ -396,6 +396,11 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -502,6 +507,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,480}, {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { @@ -633,6 +641,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -818,6 +831,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -856,6 +871,7 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, @@ -896,10 +912,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -917,11 +934,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,480}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -956,10 +979,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1081,6 +1105,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1103,10 +1136,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1276,6 +1310,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1315,14 +1351,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1359,6 +1397,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1471,10 +1510,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1692,6 +1733,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,480}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -1748,6 +1790,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -2028,12 +2071,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,480}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2139,8 +2187,11 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { } }, { @@ -2152,6 +2203,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2633,42 +2737,9 @@ const std::unordered_map MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - return std::make_shared(std::dynamic_pointer_cast(device), config); + if (!device->supportsBindless()) { + return std::make_shared(std::dynamic_pointer_cast(device), + config); + } else { + return std::make_shared(std::dynamic_pointer_cast(device), config); + } default: - return std::make_shared(std::dynamic_pointer_cast(device), config); + return std::make_shared(std::dynamic_pointer_cast(device), config); } return nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index d42860c1d..0447b057b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -36,6 +36,8 @@ static const ShaderConfig m2ForwardShaderConfig = { MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { + std::cout << "Create Forward scene renderer " << std::endl; + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index c3c84a105..f838c0211 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -105,6 +105,8 @@ static const ShaderConfig waterVisShaderConfig = { MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { + std::cout << "Create Bindless scene renderer " << std::endl; + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, sizeof(M2Vertex)); @@ -713,15 +715,15 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Particl auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) - .createDescriptorSet(1, [&l_sceneWideChunk, l_fragmentData](std::shared_ptr &ds) { + .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(4, *l_fragmentData); + .ubo(0, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&m2ParticleMatTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, m2ParticleMatTemplate.textures[0]) - .texture(6, m2ParticleMatTemplate.textures[1]) - .texture(7, m2ParticleMatTemplate.textures[2]); + .texture(0, m2ParticleMatTemplate.textures[0]) + .texture(1, m2ParticleMatTemplate.textures[1]) + .texture(2, m2ParticleMatTemplate.textures[2]); }) .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { instance->m_fragmentData = l_fragmentData; @@ -742,12 +744,12 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMat .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() - .ssbo(3, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) - .ubo(4, *l_fragmentData); + .ssbo(0, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ubo(1, *l_fragmentData).delayUpdate(); }) .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { ds->beginUpdate() - .texture(5, m2RibbonMaterialTemplate.textures[0]); + .texture(0, m2RibbonMaterialTemplate.textures[0]); }) .toMaterial([l_fragmentData](IM2RibbonMaterial *instance) -> void { instance->m_fragmentData = l_fragmentData; @@ -868,7 +870,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMater .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *skyColors); + .ubo(0, *skyColors).delayUpdate(); }) .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { instance->m_skyColors = skyColors; @@ -886,7 +888,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() - .ubo(1, *materialPS); + .ubo(0, *materialPS).delayUpdate(); }) .toMaterial([&materialPS](IPortalMaterial *instance) -> void { instance->m_materialPS = materialPS; From 8e167a529d727250fadf2f183d30f5e85979dfc1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 22 Oct 2023 01:14:44 +0300 Subject: [PATCH 146/212] Several error fixes on AMD --- wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag | 2 +- .../commandBufferRecorder/CommandBufferRecorder.cpp | 9 ++++----- .../gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp | 2 +- wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp | 7 +++++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag index 512c344d8..969df2c16 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag @@ -23,7 +23,7 @@ layout(std140, set=1, binding=1) uniform meshWideBlockPS { ivec4 uPixelShader_BlendMode_TextureTransformIndex; }; -layout(set=2, binding=5) uniform sampler2D uTexture; +layout(set=2, binding=0) uniform sampler2D uTexture; layout(location = 0) out vec4 outputColor; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index ff8d8928d..a1ee19b72 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -327,10 +327,6 @@ void CmdBufRecorder::createDefaultScissors(const std::array &areaOff } } -#ifdef LINK_TRACY -VkCommandBuffer CmdBufRecorder::getNativeCmdBuffer() { return m_gCmdBuffer.getNativeCmdBuffer(); } -TracyVkCtx const &CmdBufRecorder::getTracyContext() { return m_gCmdBuffer.tracyContext; } - void CmdBufRecorder::bindMaterial(const std::shared_ptr &material) { if (m_material == material) return; @@ -358,4 +354,7 @@ void CmdBufRecorder::bindVertexBindings(const std::shared_ptr } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { m_totalDynUbos++; } else if (layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { - m_totalImages++; + m_totalImages+= layout.descriptorCount; } } diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp index 8822b7214..58a5cb111 100644 --- a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp @@ -242,8 +242,11 @@ void GPipelineVLK::createPipeline( pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - if (vkCreateGraphicsPipelines(m_device.getVkDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, - &graphicsPipeline) != VK_SUCCESS) { + auto res = vkCreateGraphicsPipelines(m_device.getVkDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, + &graphicsPipeline); + + if (res != VK_SUCCESS) { + std::cerr << "failed to create graphics pipeline!" << std::endl; throw std::runtime_error("failed to create graphics pipeline!"); } From b73c23fc65f02d404370c734d40bb0bbc1f66448 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 23 Oct 2023 20:43:30 +0300 Subject: [PATCH 147/212] - add opaque material for imGUI - expose width and height to BLPViewer - correct alpha channel in blp - correct the water (Ruby Sanctum map) --- src/ui/childWindow/BLPViewer.cpp | 34 +- src/ui/childWindow/BLPViewer.h | 3 + src/ui/renderer/uiScene/FrontendUIRenderer.h | 1 + .../uiScene/IFrontendUIBufferCreate.h | 2 +- .../vulkan/FrontendUIRenderForwardVLK.cpp | 13 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- .../forwardRendering/imguiShader_opaque.frag | 16 + .../engine/objects/liquid/LiquidInstance.cpp | 13 +- .../src/engine/shader/ShaderDefinitions.h | 446 ++++++++++-------- .../src/engine/texture/BlpTexture.cpp | 2 +- .../src/gapi/interface/textures/ITexture.h | 3 + .../CommandBufferRecorder.cpp | 9 + .../src/gapi/vulkan/textures/GTextureVLK.h | 2 + 13 files changed, 320 insertions(+), 226 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/forwardRendering/imguiShader_opaque.frag diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index 1753037f0..7e4c1b8ef 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -29,12 +29,12 @@ bool BLPViewer::draw() { if (fileDataId > 0) { m_blpTexture = m_api->cacheStorage->getTextureCache()->getFileId(fileDataId); - auto textureObj = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); - material = m_uiRenderer->createUIMaterial({textureObj}); + m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({m_texture}, true); } else { m_blpTexture = m_api->cacheStorage->getTextureCache()->get(blpName.data()); - auto textureObj = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); - material = m_uiRenderer->createUIMaterial({textureObj}); + m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({m_texture}, true); } } if (m_blpTexture && m_blpTexture->getStatus() == FileStatus::FSRejected) { @@ -42,11 +42,29 @@ bool BLPViewer::draw() { } else if (m_blpTexture && m_blpTexture->getStatus() == FileStatus::FSLoaded && material) { float sizeX = 0, sizeY = 0; - auto windowSize = ImGui::GetContentRegionAvail(); - sizeX = windowSize.x; - sizeY = windowSize.y; - ImGui::ImageButton(material->uniqueId, ImVec2(sizeX, sizeY)); + sizeX = (m_texture && m_texture->getTexture()) ? m_texture->getTexture()->getWidth() : 0; + sizeY = (m_texture && m_texture->getTexture()) ? m_texture->getTexture()->getHeight() : 0; + + ImGui::Text("Width = %0.0f, Height = %0.0f", sizeX, sizeY); + ImGui::Checkbox("Stretch image", &stretchImage); + + + if (sizeX > 0 && sizeY > 0 && stretchImage) { + auto windowSize = ImGui::GetContentRegionAvail(); + + // Calculate resize ratios for resizing + float ratioW = windowSize.x / sizeX; + float ratioH = windowSize.y / sizeY; + + // smaller ratio will ensure that the image fits in the view + float ratio = ratioW < ratioH ? ratioW : ratioH; + + sizeX = sizeX * ratio; + sizeY = sizeY * ratio; + } + + ImGui::Image(material->uniqueId, ImVec2(sizeX, sizeY)); } } ImGui::End(); diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h index 1533530a8..b6f1364fd 100644 --- a/src/ui/childWindow/BLPViewer.h +++ b/src/ui/childWindow/BLPViewer.h @@ -19,9 +19,12 @@ class BLPViewer { bool m_showWindow = true; std::array blpName = {0};\ + bool stretchImage = false; + HApiContainer m_api; std::shared_ptr m_uiRenderer; std::shared_ptr m_blpTexture; + HGSamplableTexture m_texture; std::shared_ptr material = nullptr; }; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index c7510fb25..99b1ef645 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -45,6 +45,7 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index be05ef519..463fb895f 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -18,7 +18,7 @@ class IFrontendUIBufferCreate { virtual HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) = 0; virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; - virtual std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture) = 0; + virtual std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture, bool opaque = false) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index d4bc4a92e..db79b3072 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -46,19 +46,20 @@ HGVertexBufferBindings FrontendUIRenderForwardVLK::createVAO(HGVertexBuffer vert return imguiVAO; } -std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture &hgtexture) { +std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const HGSamplableTexture &hgtexture, bool opaque) { auto weakTexture = std::weak_ptr(hgtexture); - auto i = m_materialCache.find(weakTexture); - if (i != m_materialCache.end()) { + auto &materialCache = !opaque ? m_materialCache : m_materialCacheOpaque; + auto i = materialCache.find(weakTexture); + if (i != materialCache.end()) { if (!i->second.expired()) { return i->second.lock(); } else { - m_materialCache.erase(i); + materialCache.erase(i); } } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShader"}, {"forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering"}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() @@ -73,7 +74,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const }); auto weakPtr = material; - m_materialCache[weakTexture] = weakPtr; + materialCache[weakTexture] = weakPtr; m_materialCacheIdMap[material->uniqueId] = std::dynamic_pointer_cast(material); return material; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 4f1300ee2..adabfca21 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -27,7 +27,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; - std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture) override; + std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture, bool opaque = false) override; uint32_t generateUniqueMatId(); private: diff --git a/wowViewerLib/shaders/glsl/forwardRendering/imguiShader_opaque.frag b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader_opaque.frag new file mode 100644 index 000000000..1a4d7c960 --- /dev/null +++ b/wowViewerLib/shaders/glsl/forwardRendering/imguiShader_opaque.frag @@ -0,0 +1,16 @@ +#version 450 + +precision highp float; +precision highp int; + +layout(location=0) in vec2 Frag_UV; +layout(location=1) in vec4 Frag_Color; + +layout(set=1,binding=0) uniform sampler2D Texture; + +layout (location = 0) out vec4 Out_Color; + +void main() +{ + Out_Color = Frag_Color * vec4(texture(Texture, Frag_UV.st).rgb, 1.0); +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 74c02b340..1288784fa 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -246,16 +246,19 @@ void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, for (int y = y_begin; y < y_end; y++) { for (int x = x_begin; x < x_end; x++) { - int maskIndex = (y - y_begin) * (x_end - x_begin) + (x - x_begin); + auto x_local = x - x_begin; + auto y_local = y - y_begin; + + int maskIndex = (y_local) * (x_end - x_begin) + (x_local); bool exists = (existsTable[maskIndex >> 3] >> ((maskIndex & 7))) & 1; if (!exists) continue; const int16_t vertIndexes[4] = { - (int16_t) (y * (liquidInstance.width + 1 ) + x), - (int16_t) (y * (liquidInstance.width + 1) + x + 1), - (int16_t) ((y + 1) * (liquidInstance.width + 1) + x), - (int16_t) ((y + 1) * (liquidInstance.width + 1) + x + 1), + (int16_t) (y_local * (liquidInstance.width + 1 ) + x_local), + (int16_t) (y_local * (liquidInstance.width + 1) + x_local + 1), + (int16_t) ((y_local + 1) * (liquidInstance.width + 1) + x_local), + (int16_t) ((y_local + 1) * (liquidInstance.width + 1) + x_local + 1), }; indexBuffer.push_back (vertIndexes[0]); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index ba09ed262..f8a353784 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -357,13 +357,13 @@ const std::unordered_map shaderMetaInfo = { {1,0,4096}, }, { - {2,5, "uTexture"}, + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {5,5,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -616,6 +616,41 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "forwardRendering/skyConus.frag.spv", + { + ShaderStage::Fragment, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/waterfallShader.vert.spv", { ShaderStage::Vertex, @@ -1287,11 +1322,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,0,84}, }, { { @@ -1306,21 +1341,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1330,16 +1360,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1349,18 +1380,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1370,15 +1406,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,0,480}, + {0,1,32}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1389,22 +1425,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, + {1,0, "texture0"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1412,15 +1438,16 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,16}, }, { { @@ -1452,17 +1479,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, - {0,0,480}, + {0,1,16}, }, { { - {0,0,1}, - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1474,11 +1500,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1489,16 +1517,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {1,1,96}, + {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1510,14 +1539,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {2,0, "uTexture"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1527,18 +1555,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,480}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {2,2,1}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1549,22 +1583,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,15 +1602,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "visBuffer/wmoShader.frag.spv", { ShaderStage::Fragment, { - {0,1,32}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1592,15 +1621,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { - {1,0, "texture0"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1610,11 +1645,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "visBuffer/waterShader.vert.spv", { ShaderStage::Vertex, { - {0,0,16}, + {0,0,480}, }, { { @@ -1629,14 +1664,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1646,15 +1685,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,0,480}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1665,16 +1704,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1684,17 +1731,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,96}, - {0,0,480}, + {0,0,128}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1706,13 +1752,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1722,45 +1767,35 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, - {0,0,480}, {1,0,64}, - {1,5,4096}, - {1,2,16384}, + {0,0,480}, }, { { {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,3,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1769,15 +1804,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.vert.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,480}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1788,16 +1822,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1808,16 +1840,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "visBuffer/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,480}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1828,6 +1859,9 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { }, @@ -1845,15 +1879,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,128}, + {0,1,64}, }, { { - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1881,17 +1916,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, - {0,0,480}, + {0,1,112}, }, { { - {0,0,1}, - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1903,15 +1937,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1921,16 +1952,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,0,32}, {0,0,480}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1942,12 +1974,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1957,14 +1992,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,480}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2656,6 +2692,79 @@ const std::unordered_mappalette[colIndex * 4 + 0]; uint8_t g = blpFile->palette[colIndex * 4 + 1]; uint8_t r = blpFile->palette[colIndex * 4 + 2]; - uint8_t a = paleteData[width * height + j]; + uint8_t a = blpFile->palette[colIndex * 4 + 3]; mipmapStruct.texture[j * 4 + 0] = r; mipmapStruct.texture[j * 4 + 1] = g; diff --git a/wowViewerLib/src/gapi/interface/textures/ITexture.h b/wowViewerLib/src/gapi/interface/textures/ITexture.h index 8bff95d07..9db66cdc0 100644 --- a/wowViewerLib/src/gapi/interface/textures/ITexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ITexture.h @@ -35,6 +35,9 @@ class ITexture { virtual TextureStatus postLoad() = 0; virtual void createTexture(TextureFormat textureFormat, const HMipmapsVector &mipmaps) = 0; + + virtual uint32_t getWidth() = 0; + virtual uint32_t getHeight() = 0; }; extern std::atomic blpTexturesVulkanLoaded; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index a1ee19b72..d085aba7a 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -69,6 +69,15 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( createDefaultScissors(areaOffset, areaSize); m_currentRenderPass = renderPassVlk; + + m_currentPipeline = nullptr; + m_currentPipelineLayout = nullptr; + m_currentIndexBuffer = nullptr; + m_currentVertexBuffers = {}; + m_currentDescriptorSet = {}; + m_material = nullptr; + m_vertexBufferBindings = nullptr; + auto renderPass = RenderPassHelper( *this, isAboutToExecSecondaryCMD, diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index 5d6a6958b..e23236874 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -33,6 +33,8 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); From e4fd94c92dd078a5045ec54e222291c543fe5970 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 24 Oct 2023 02:18:03 +0300 Subject: [PATCH 148/212] - optimization on m2 animations, that allows to push less data - optimization in water rendering, that allows to push less data --- .../glsl/common/commonLightFunctions.glsl | 5 + .../glsl/common/commonWaterIndirect.glsl | 6 +- .../glsl/forwardRendering/waterShader.frag | 66 +- .../shaders/glsl/visBuffer/waterShader.frag | 73 +- wowViewerLib/src/engine/algorithms/animate.h | 35 +- .../src/engine/managers/animationManager.cpp | 56 +- .../src/engine/managers/animationManager.h | 19 + .../engine/objects/liquid/LiquidInstance.cpp | 66 +- .../src/engine/objects/m2/m2Object.cpp | 11 +- .../src/engine/objects/wmo/wmoObject.cpp | 62 +- .../src/engine/shader/ShaderDefinitions.h | 766 ++++++++---------- .../src/gapi/UniformBufferStructures.h | 11 +- .../renderer/mapScene/MapSceneRenderer.cpp | 195 ++--- 13 files changed, 740 insertions(+), 631 deletions(-) diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index d7643ffc8..20d346160 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -21,6 +21,11 @@ struct SceneWideParams { mat4 uPMatrix; vec4 uViewUpSceneTime; vec4 uInteriorSunDir; + + vec4 closeRiverColor; + vec4 farRiverColor; + vec4 closeOceanColor; + vec4 farOceanColor; SceneExteriorLight extLight; }; diff --git a/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl b/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl index 1caa215bd..5f0fdfa7e 100644 --- a/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl +++ b/wowViewerLib/shaders/glsl/common/commonWaterIndirect.glsl @@ -2,9 +2,9 @@ #define COMMON_WATER_INDIRECT struct WaterData { - ivec4 materialId; - vec4 color; - mat4 textureMatrix; + ivec4 materialId_liquidFlags; + vec4 matColor; + vec4 float0_float1; }; //Individual meshes diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index c26c33025..e0d946076 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -20,9 +20,9 @@ layout(set=2,binding=0) uniform sampler2D uTexture; //Individual meshes layout(std140, set=1, binding=1) uniform meshWideBlockPS { - ivec4 materialId; - vec4 color; - mat4 textureMatrix; + ivec4 materialId_liquidFlags; + vec4 matColor; + vec4 float0_float1; }; const InteriorLightParam intLight = { @@ -30,6 +30,40 @@ const InteriorLightParam intLight = { vec4(0,0,0,1) }; +const float ROUNDING_ERROR_f32 = 0.001f; +bool feq(const float a, const float b) +{ + return (a + ROUNDING_ERROR_f32 >= b) && (a - ROUNDING_ERROR_f32 <= b); +} +vec2 GetTexScrollMtx(float time, vec2 scrollVec) { + float scrollX = 0.0f; + float scrollY = 0.0f; + + if (!feq(scrollVec.x, 0.0)) { + scrollX = (int(time) % int(1000.0f / scrollVec.x)) / float(int(1000.0f / scrollVec.x)); + } + if (!feq(scrollVec.y, 0.0)) { + scrollY = (int(time) % int(1000.0f / scrollVec.y)) / float(int(1000.0f / scrollVec.y)); + } + + return vec2(scrollX, scrollY); +} + +#define M_PI 3.1415926538 +mat4 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + + void main() { // MaterialId: // 1,3 - Water @@ -42,18 +76,38 @@ void main() { // 18 - Azerithe // 8 - is probably debug material called Grid + vec4 color = vec4(0.0); + int liquidFlags = materialId_liquidFlags.y; + if ((materialId_liquidFlags.y & 1024) > 0) {// Ocean + color = scene.closeOceanColor; + } else if (liquidFlags == 15) { //River/Lake + //Query river color + color = vec4(scene.closeRiverColor.xyz, 0.7); + } else { + color = vec4(matColor.xyz, 0.7); + } + + vec2 animatedUV = vTextCoords; - vec2 animatedUV = (textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; + float sceneTime = scene.uViewUpSceneTime.w; + float float0 = float0_float1.x; + float float1 = float0_float1.y; + int materialId = materialId_liquidFlags.x; + if (materialId == 1 || materialId == 3) { + animatedUV *= float0; + animatedUV = (rotationMatrix(vec3(0,0,1), float1 * (M_PI / 180.0f)) * vec4(animatedUV, 0.0, 0.0)).xy; + } else if (materialId == 2 || materialId == 4) { + animatedUV += GetTexScrollMtx(sceneTime, vec2(float0,float1)); + }; vec3 matDiffuse = color.rgb+texture(uTexture, animatedUV).rgb; vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; - vec4 finalColor = vec4(matDiffuse, 1.0); //Magma is not affected by light - if (materialId.x != 2 && materialId.x != 4) { + if (materialId != 2 && materialId != 4) { finalColor = vec4( calcLight( matDiffuse, diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag index c5f593bcf..97367213e 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag @@ -24,6 +24,49 @@ const InteriorLightParam intLight = { vec4(0,0,0,1) }; +const float ROUNDING_ERROR_f32 = 0.001f; +bool feq(const float a, const float b) +{ + return (a + ROUNDING_ERROR_f32 >= b) && (a - ROUNDING_ERROR_f32 <= b); +} + +vec2 GetTexScrollMtx(float time, vec2 scrollVec) { + float scrollX = 0.0f; + float scrollY = 0.0f; + + if (!feq(scrollVec.x, 0.0)) { + scrollX = (int(time) % int(1000.0f / scrollVec.x)) / float(int(1000.0f / scrollVec.x)); + } + if (!feq(scrollVec.y, 0.0)) { + scrollY = (int(time) % int(1000.0f / scrollVec.y)) / float(int(1000.0f / scrollVec.y)); + } + + return vec2(scrollX, scrollY); +} + +#define M_PI 3.1415926538 +mat4 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + +mat4 rotationZ(float angle) { + return mat4( + cos(angle), -sin(angle), 0.0, 0.0 , + sin(angle), cos(angle), 0.0, 0.0 , + 0.0, 0.0, 1.0, 0.0 , + 0.0, 0.0, 0.0, 1.0 + ); +} + void main() { WaterBindless waterBindless = waterBindlesses[meshInd]; WaterData waterData = waterDatas[waterBindless.waterDataInd_placementMatInd_textureInd.x]; @@ -39,9 +82,33 @@ void main() { // 18 - Azerithe // 8 - is probably debug material called Grid - vec2 animatedUV = (waterData.textureMatrix*vec4(vTextCoords, 0.0, 1.0)).st; + vec4 color = vec4(0.0); + int liquidFlags = waterData.materialId_liquidFlags.y; + int materialId = waterData.materialId_liquidFlags.x; + + if ((liquidFlags & 1024) > 0) {// Ocean + color = scene.closeOceanColor; + } else if (liquidFlags == 15) { //River/Lake + //Query river color + color = vec4(scene.closeRiverColor.xyz, 0.7); + } else { + color = vec4(waterData.matColor.xyz, 0.7); + } + + vec2 animatedUV = vTextCoords; + + float sceneTime = scene.uViewUpSceneTime.w; + float float0 = waterData.float0_float1.x; + float float1 = waterData.float0_float1.y; + if (materialId == 1 || materialId == 3) { + animatedUV *= float0; +// animatedUV = (rotationMatrix(vec3(0,0,1), float1 * (M_PI / 180.0f)) * vec4(animatedUV, 0.0, 0.0)).xy; + animatedUV = (rotationZ(float1 * (M_PI / 180.0f)) * vec4(animatedUV, 0.0, 0.0)).xy; + } else if (materialId == 2 || materialId == 4) { + animatedUV += GetTexScrollMtx(sceneTime, vec2(float0,float1)); + }; - vec3 matDiffuse = waterData.color.rgb+texture(s_Textures[waterBindless.waterDataInd_placementMatInd_textureInd.z], animatedUV).rgb; + vec3 matDiffuse = color.rgb+texture(s_Textures[waterBindless.waterDataInd_placementMatInd_textureInd.z], animatedUV).rgb; vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; @@ -49,7 +116,7 @@ void main() { vec4 finalColor = vec4(matDiffuse, 1.0); //Magma is not affected by light - if (waterData.materialId.x != 2 && waterData.materialId.x != 4) { + if (materialId != 2 && materialId != 4) { finalColor = vec4( calcLight( matDiffuse, diff --git a/wowViewerLib/src/engine/algorithms/animate.h b/wowViewerLib/src/engine/algorithms/animate.h index 9c7a52646..368309d43 100644 --- a/wowViewerLib/src/engine/algorithms/animate.h +++ b/wowViewerLib/src/engine/algorithms/animate.h @@ -8,8 +8,19 @@ #include "../persistance/header/M2FileHeader.h" #include "../../include/iostuff.h" #include +#include #include +enum class EAnimDataType : uint8_t { + bonesMatrices = 0, textAnimMatrices = 1, subMeshColors = 2, transparencies = 3, lights = 4, + particles = 5, ribbons = 6, MAX_ANIM_DATA_TYPE = 7 +}; +template +constexpr typename std::underlying_type::type EAnimDataTypeToInt(E e) noexcept { + return static_cast::type>(e); +} + + struct AnimationStruct { int animationIndex; @@ -20,6 +31,17 @@ struct AnimationStruct { int mainVariationIndex; M2Sequence* mainVariationRecord; + + bool firstUpdate = false; + std::array changedData = {true, true, true, true}; + + inline void resetChangedData() { + for (auto &val : changedData) val = firstUpdate; + } + + inline void setDataChange(EAnimDataType dataType) { + changedData[EAnimDataTypeToInt(dataType)] = true; + } }; struct FullAnimationInfo { @@ -266,10 +288,11 @@ inline R interpolateHermite(M2SplineKey &value1, M2SplineKey &value2, floa template R animateTrack( - const AnimationStruct &animationStruct, + AnimationStruct &animationStruct, M2Track &animationBlock, M2Array &global_loops, std::vector &globalSequenceTimes, + EAnimDataType animType, R &defaultValue) { animTime_t currTime = animationStruct.animationTime; @@ -309,6 +332,11 @@ R animateTrack( } else { timeIndex = 0; } + + if (times->size > 1) { + animationStruct.setDataChange(animType); + } + if (timeIndex == times->size-1) { return convertHelper(*values->getElement(timeIndex)); } else if (timeIndex >= 0) { @@ -333,10 +361,11 @@ R animateTrack( template R animateTrackWithBlend( - const FullAnimationInfo &animationInfo, + FullAnimationInfo &animationInfo, M2Track &animationBlock, M2Array &global_loops, std::vector &globalSequenceTimes, + EAnimDataType animType, R &defaultValue) { R result = animateTrack( @@ -344,6 +373,7 @@ R animateTrackWithBlend( animationBlock, global_loops, globalSequenceTimes, + animType, defaultValue ); if (animationInfo.nextSubAnimation.animationIndex > -1 && animationInfo.blendFactor < 0.999f) { @@ -352,6 +382,7 @@ R animateTrackWithBlend( animationBlock, global_loops, globalSequenceTimes, + animType, defaultValue ); result = lerpHelper(result1, result, animationInfo.blendFactor); diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index 485362067..a93b8d30d 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -21,6 +21,7 @@ AnimationManager::AnimationManager(HApiContainer api, std::shared_ptranimationInfo.currentAnimation.animationFoundInParent = false; this->animationInfo.currentAnimation.mainVariationIndex = 0; this->animationInfo.currentAnimation.mainVariationRecord = this->animationInfo.currentAnimation.animationRecord; + this->animationInfo.currentAnimation.firstUpdate = true; calcAnimRepetition(this->animationInfo.currentAnimation); this->animationInfo.nextSubAnimation.animationIndex = -1; @@ -102,7 +103,7 @@ bool AnimationManager::setAnimationId(int animationId, bool reset) { boneMasterData->getSkelData()->m_sequence_lookups, boneMasterData->getSkelData()->m_sequences); - auto sequences = boneMasterData->getSkelData()->m_sequences; + auto *sequences = boneMasterData->getSkelData()->m_sequences; if (animationIndex <= -1 && boneMasterData->getParentSkelData() != nullptr) { bool animationIsBanned = false; @@ -145,6 +146,7 @@ bool AnimationManager::setAnimationId(int animationId, bool reset) { this->animationInfo.currentAnimation.animationFoundInParent = animationFoundInParent; this->animationInfo.currentAnimation.mainVariationIndex = animationIndex; this->animationInfo.currentAnimation.mainVariationRecord = (*sequences)[animationIndex]; + this->animationInfo.currentAnimation.firstUpdate = true; calcAnimRepetition(this->animationInfo.currentAnimation); @@ -172,7 +174,7 @@ inline void calcAnimationTransform( M2Track &translationTrack, M2Track &rotationTrack, M2Track &scaleTrack, - const FullAnimationInfo &animationInfo + FullAnimationInfo &animationInfo ) { tranformMat = tranformMat * mathfu::mat4::FromTranslationVector(pivotPoint.xyz()); // @@ -183,6 +185,7 @@ inline void calcAnimationTransform( translationTrack, global_loops, globalSequenceTimes, + EAnimDataType::bonesMatrices, defaultValue ); @@ -196,6 +199,7 @@ inline void calcAnimationTransform( rotationTrack, global_loops, globalSequenceTimes, + EAnimDataType::bonesMatrices, defaultValue); tranformMat = tranformMat * quaternionResult.ToMatrix4(); @@ -208,6 +212,7 @@ inline void calcAnimationTransform( scaleTrack, global_loops, globalSequenceTimes, + EAnimDataType::bonesMatrices, defaultValue); tranformMat = tranformMat * mathfu::mat4::FromScaleVector(scaleResult.xyz()); @@ -225,7 +230,7 @@ inline void calcTextureAnimationTransform( M2Track &translationTrack, M2Track &rotationTrack, M2Track &scaleTrack, - const FullAnimationInfo &animationInfo + FullAnimationInfo &animationInfo ) { if (rotationTrack.values.size > 0) { @@ -235,6 +240,7 @@ inline void calcTextureAnimationTransform( rotationTrack, global_loops, globalSequenceTimes, + EAnimDataType::textAnimMatrices, defaultValue); tranformMat = tranformMat * mathfu::mat4::FromTranslationVector(pivotPoint.xyz()); @@ -249,6 +255,7 @@ inline void calcTextureAnimationTransform( scaleTrack, global_loops, globalSequenceTimes, + EAnimDataType::textAnimMatrices, defaultValue); tranformMat = tranformMat * mathfu::mat4::FromTranslationVector(pivotPoint.xyz()); @@ -264,6 +271,7 @@ inline void calcTextureAnimationTransform( translationTrack, global_loops, globalSequenceTimes, + EAnimDataType::textAnimMatrices, defaultValue ); @@ -452,6 +460,8 @@ AnimationManager::calcBoneMatrix( parentBoneMat = modifiedMatrixUnder0x7; + animationInfo.currentAnimation.setDataChange(EAnimDataType::bonesMatrices); + animationInfo.nextSubAnimation.setDataChange(EAnimDataType::bonesMatrices); } } @@ -483,6 +493,9 @@ AnimationManager::calcBoneMatrix( int boneBillboardFlags = boneDefinition->flags_raw & 0x4000078; if (boneBillboardFlags) { + animationInfo.currentAnimation.setDataChange(EAnimDataType::bonesMatrices); + animationInfo.nextSubAnimation.setDataChange(EAnimDataType::bonesMatrices); + mathfu::mat4 ¤tBoneMat = boneMatrices[boneIndex]; mathfu::mat4 currentBoneMatCopy = currentBoneMat; mathfu::vec3 scaleVector = mathfu::vec3( @@ -792,6 +805,7 @@ void AnimationManager::update( this->animationInfo.nextSubAnimation.animationFoundInParent = this->animationInfo.currentAnimation.animationFoundInParent; this->animationInfo.nextSubAnimation.mainVariationIndex = this->animationInfo.currentAnimation.mainVariationIndex; this->animationInfo.nextSubAnimation.mainVariationRecord = this->animationInfo.currentAnimation.mainVariationRecord; + this->animationInfo.nextSubAnimation.firstUpdate = true; calcAnimRepetition(this->animationInfo.nextSubAnimation); } else { //This is done to trigger blending in transition start and end of same variation when it's repeated for whatever reason @@ -801,6 +815,9 @@ void AnimationManager::update( } } + animationInfo.currentAnimation.resetChangedData(); + animationInfo.nextSubAnimation.resetChangedData(); + animTime_t currAnimLeft = currentAnimationRecord->duration - this->animationInfo.currentAnimation.animationTime; animTime_t subAnimBlendTime = 0; @@ -919,6 +936,11 @@ void AnimationManager::update( this->calcLights(lights, bonesMatrices); this->calcParticleEmitters(particleEmitters, bonesMatrices); this->calcRibbonEmitters(ribbonEmitters); + + if (this->animationInfo.blendFactor < 1.0) + this->animationInfo.nextSubAnimation.firstUpdate = false; + + this->animationInfo.currentAnimation.firstUpdate = false; } void AnimationManager::calcSubMeshColors(std::vector &subMeshColors) { @@ -934,6 +956,7 @@ void AnimationManager::calcSubMeshColors(std::vector &subMeshColor colors[i]->color, global_loops, this->globalSequenceTimes, + EAnimDataType::subMeshColors, defaultVector ); @@ -946,6 +969,7 @@ void AnimationManager::calcSubMeshColors(std::vector &subMeshColor colors[i]->alpha, global_loops, this->globalSequenceTimes, + EAnimDataType::subMeshColors, defaultAlpha ); @@ -965,6 +989,7 @@ void AnimationManager::calcTransparencies(std::vector &transparencies) { transparencyRecords[i]->weight, global_loops, this->globalSequenceTimes, + EAnimDataType::transparencies, defaultAlpha ); @@ -991,6 +1016,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->ambient_color, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultVector ), 1.0); @@ -1000,6 +1026,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->ambient_intensity, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultFloat ); mathfu::vec4 diffuse_color = @@ -1008,6 +1035,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->diffuse_color, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultVector ), 1.0); @@ -1047,6 +1075,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->diffuse_intensity, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultFloat ); @@ -1056,6 +1085,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->attenuation_start, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultFloat ); float attenuation_end = @@ -1064,6 +1094,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->attenuation_end, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultFloat ); @@ -1074,6 +1105,7 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto lightRecord->visibility, global_loops, this->globalSequenceTimes, + EAnimDataType::lights, defaultChar ); @@ -1205,6 +1237,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultChar ); } @@ -1218,6 +1251,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->speedVariation = @@ -1226,6 +1260,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->verticalRange = @@ -1234,6 +1269,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->horizontalRange = @@ -1242,6 +1278,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); if (peRecord.old.flags & 0x800000) { @@ -1250,6 +1287,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultVector ); } else { @@ -1261,6 +1299,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat )); } @@ -1272,6 +1311,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->emissionRate = @@ -1280,6 +1320,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->emissionAreaY = @@ -1288,6 +1329,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); aniProp->emissionAreaX = @@ -1296,6 +1338,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); if (!m_hasExp2) { @@ -1305,6 +1348,7 @@ void AnimationManager::calcParticleEmitters(const std::vectorglobalSequenceTimes, + EAnimDataType::particles, defaultFloat ); } @@ -1335,6 +1379,7 @@ void AnimationManager::calcRibbonEmitters(std::vectorcolorTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultVector4 ); ribbonEmitter->SetColor(colorRGBA.x, colorRGBA.y, colorRGBA.z); @@ -1345,6 +1390,7 @@ void AnimationManager::calcRibbonEmitters(std::vectoralphaTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultFloat ); @@ -1356,6 +1402,7 @@ void AnimationManager::calcRibbonEmitters(std::vectorheightAboveTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultFloat ); ribbonEmitter->SetAbove(above); @@ -1366,6 +1413,7 @@ void AnimationManager::calcRibbonEmitters(std::vectorheightBelowTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultFloat ); ribbonEmitter->SetBelow(below); @@ -1376,6 +1424,7 @@ void AnimationManager::calcRibbonEmitters(std::vectortexSlotTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultInt ); @@ -1387,6 +1436,7 @@ void AnimationManager::calcRibbonEmitters(std::vectorvisibilityTrack, global_loops, this->globalSequenceTimes, + EAnimDataType::ribbons, defaultChar ); ribbonEmitter->SetDataEnabled(dataEnabled); diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index 9e898a623..63b7050db 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -43,6 +43,9 @@ class AnimationManager { void calcAnimMatrixes (std::vector &textAnimMatrices); void calcAnimRepetition(AnimationStruct &animationStruct); + + + public: AnimationManager(HApiContainer api, std::shared_ptr boneMasterData, bool hasExp2); @@ -90,6 +93,22 @@ class AnimationManager { void calcRibbonEmitters(std::vector> &ribbonEmitters); void calcCamera(M2CameraResult &camera, int cameraId, mathfu::mat4 &placementMatrix); + + inline const std::array getCombinedChangedData() { + if (animationInfo.blendFactor < 1.0) { + std::array result; + + for (int i = 0; i < EAnimDataTypeToInt(EAnimDataType::MAX_ANIM_DATA_TYPE); i++) { + + auto const ¤tChangedData = animationInfo.currentAnimation.changedData; + auto const &nextSubChangedData = animationInfo.nextSubAnimation.changedData; + result[i] = currentChangedData[i] || nextSubChangedData[i] ; + } + return result; + } + + return animationInfo.currentAnimation.changedData; + } }; diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 1288784fa..be4afb700 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -96,6 +96,17 @@ void LiquidInstance::createMaterialAndMesh(const HMapSceneBufferCreate &sceneRen m_liquidMaterials.push_back(waterMaterial); m_vertexWaterBufferBindings.push_back(vertexWaterBufferBindings); + { + auto &waterChunk = waterMaterial->m_materialPS->getObject(); + waterChunk.materialId = waterMaterial->materialId; + waterChunk.liquidFlags = waterMaterial->liquidFlags; + waterChunk.float0_float1.x = m_liqMatAndType.m_floats[0]; + waterChunk.float0_float1.y = m_liqMatAndType.m_floats[1]; + waterChunk.matColor = mathfu::vec4(waterMaterial->color, 0.7f); + waterMaterial->m_materialPS->save(); + } + + //Create mesh(es) for (int i = 0; i < m_liquidMaterials.size(); i++) { gMeshTemplate meshTemplate(vertexWaterBufferBindings); @@ -273,61 +284,6 @@ void LiquidInstance::createAdtVertexData(const SMLiquidInstance &liquidInstance, } void LiquidInstance::updateLiquidMaterials(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime) { - for (auto &waterMaterial : m_liquidMaterials) { - auto &waterChunk = waterMaterial->m_materialPS->getObject(); - waterChunk.materialId = waterMaterial->materialId; - - if ((waterMaterial->liquidFlags & 1024) > 0) {// Ocean - waterChunk.color = frameDependantData->closeOceanColor; - } else if (waterMaterial->liquidFlags == 15) { //River/Lake - //Query river color - mathfu::vec3 closeRiverColor = frameDependantData->closeRiverColor.xyz(); - if (m_api->getConfig()->useCloseRiverColorForDB) { - - mathfu::vec3 waterPos = (mathfu::vec3(m_waterBBox.max) + mathfu::vec3(m_waterBBox.min)) / 2.0f; - bool waterColorFound = true; - if (m_api->getConfig()->colorOverrideHolder != nullptr) { - waterColorFound = false; - - for (auto &riverOverride : *m_api->getConfig()->colorOverrideHolder) { - if (riverOverride.liquidObjectId == liquid_object || riverOverride.liquidType == liquidType) { - closeRiverColor = riverOverride.color.xyz(); - waterColorFound = true; - break; - } - } - } - } - - waterChunk.color = mathfu::vec4(closeRiverColor, 0.7);; - } else { - waterChunk.color = mathfu::vec4(waterMaterial->color, 0.7); - } - - if (m_liqMatAndType.materialID == 1 || m_liqMatAndType.materialID == 3) { - waterChunk.textureMatrix = mathfu::mat4::Identity(); - MathHelper::RotationZ(m_liqMatAndType.m_floats[1] * (M_PI / 180.0f)) * - mathfu::mat4::FromScaleVector( - mathfu::vec3(m_liqMatAndType.m_floats[0],m_liqMatAndType.m_floats[0],m_liqMatAndType.m_floats[0]) - ); - } else if (m_liqMatAndType.materialID == 2 || m_liqMatAndType.materialID == 4) { - waterChunk.textureMatrix = -// MathHelper::RotationZ(m_liqMatAndType.m_floats[7] * (M_PI / 180.0f)) * -// mathfu::mat4::FromScaleVector( -// mathfu::vec3(m_liqMatAndType.m_floats[4],m_liqMatAndType.m_floats[4],m_liqMatAndType.m_floats[4]) -// ) * - GetTexScrollMtx(mapCurrentTime, mathfu::vec2( - m_liqMatAndType.m_floats[0], - m_liqMatAndType.m_floats[1] - )) - ; - - } else { - waterChunk.textureMatrix = mathfu::mat4::Identity(); - } - - waterMaterial->m_materialPS->save(); - } } void LiquidInstance::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 571f72560..efadc51a0 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -480,7 +480,6 @@ void M2Object::createAABB() { auto min = mathfu::vec3(9999, 9999, 9999); auto max = mathfu::vec3(-9999, -9999, -9999); -// auto indexBuffer = m_skinGeom->generateIndexBuffer(); // auto m2SkinProfile = m_skinGeom->getSkinData(); // for (int batchIndex = 0; batchIndex < m2SkinProfile->batches.size; batchIndex++) { // M2Batch *textMaterial = m2SkinProfile->batches.getElement(batchIndex); @@ -1042,6 +1041,8 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa M2Data * m2File = this->m_m2Geom->getM2Data(); M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); + auto const dataIsChanged = m_animationManager->getCombinedChangedData(); + //Update materials` if (m_placementMatrixChanged) { auto &placementMatrix = m_modelWideDataBuff->m_placementMatrix->getObject(); @@ -1049,14 +1050,14 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_placementMatrix->save(); m_placementMatrixChanged = false; } - if (bonesMatrices.size() > 0) { + if (bonesMatrices.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::bonesMatrices)]) { auto &bonesData = m_modelWideDataBuff->m_bonesData->getObject(); int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, bonesData.uBoneMatrixes); m_modelWideDataBuff->m_bonesData->save(); } - if (subMeshColors.size() > 0) { + if (subMeshColors.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::subMeshColors)]) { auto &m2Colors = m_modelWideDataBuff->m_colors->getObject(); int m2ColorsCnt = (int) std::min(subMeshColors.size(), (size_t) MAX_M2COLORS_NUM); @@ -1064,7 +1065,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_colors->save(); } - if (transparencies.size() > 0) { + if (transparencies.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::transparencies)]) { auto &textureWeights = m_modelWideDataBuff->m_textureWeights->getObject(); int textureWeightsCnt = (int) std::min(transparencies.size(), (size_t) MAX_TEXTURE_WEIGHT_NUM); @@ -1072,7 +1073,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_textureWeights->save(); } - if (textAnimMatrices.size() > 0) { + if (textAnimMatrices.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::textAnimMatrices)]) { auto &textureMatrices = m_modelWideDataBuff->m_textureMatrices->getObject(); int textureMatricesCnt = (int) std::min(textAnimMatrices.size(), (size_t) MAX_TEXTURE_MATRIX_NUM); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 6303dbacd..a2651371a 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -337,42 +337,6 @@ void WmoObject::update() { modelWide.uPlacementMat = m_placementMatrix; m_modelWideChunk->save(); - //Update Materials - for (int matIndex = 0; matIndex < m_materialCache.size(); matIndex++) { - auto materialInstance = m_materialCache[matIndex]; - if (materialInstance == nullptr) continue; - - const SMOMaterial &material = getMaterials()[matIndex]; - assert(material.shader < MAX_WMO_SHADERS && material.shader >= 0); - auto shaderId = material.shader; - if (shaderId >= MAX_WMO_SHADERS) { - shaderId = 0; - } - int pixelShader = wmoMaterialShader[shaderId].pixelShader; - int vertexShader = wmoMaterialShader[shaderId].vertexShader; - auto blendMode = material.blendMode; - - float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; - - - //Update VS block - auto &blockVS = materialInstance->m_materialVS->getObject(); - blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; - blockVS.VertexShader = vertexShader; - materialInstance->m_materialVS->save(); - - //Update PS block - auto &blockPS = materialInstance->m_materialPS->getObject(); - blockPS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; - blockPS.EnableAlpha = (blendMode > 0) ? 1 : 0; - blockPS.PixelShader = pixelShader; - blockPS.BlendMode = blendMode; - blockPS.uFogColor_AlphaTest = mathfu::vec4_packed( - mathfu::vec4(0,0,0, alphaTest)); - materialInstance->m_materialPS->save(); - } - - for (int i= 0; i < groupObjects.size(); i++) { if(groupObjects[i] != nullptr) { groupObjects[i]->update(); @@ -1341,11 +1305,31 @@ std::shared_ptr WmoObject::getMaterialInstance(int materialIndex, materialTemplate.textures[8] = getTexture(material.runTimeData[3], false); } - auto wmoMaterialInstance = sceneRenderer->createWMOMaterial(m_modelWideChunk, + materialInstance = sceneRenderer->createWMOMaterial(m_modelWideChunk, pipelineTemplate, materialTemplate); - m_materialCache[materialIndex] = wmoMaterialInstance; + m_materialCache[materialIndex] = materialInstance; + + { + float alphaTest = (blendMode > 0) ? 0.00392157f : -1.0f; + + //Update VS block + auto &blockVS = materialInstance->m_materialVS->getObject(); + blockVS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; + blockVS.VertexShader = vertexShader; + materialInstance->m_materialVS->save(); + + //Update PS block + auto &blockPS = materialInstance->m_materialPS->getObject(); + blockPS.UseLitColor = (material.flags.F_UNLIT > 0) ? 0 : 1; + blockPS.EnableAlpha = (blendMode > 0) ? 1 : 0; + blockPS.PixelShader = pixelShader; + blockPS.BlendMode = blendMode; + blockPS.uFogColor_AlphaTest = mathfu::vec4_packed( + mathfu::vec4(0,0,0, alphaTest)); + materialInstance->m_materialPS->save(); + } - return wmoMaterialInstance; + return materialInstance; }; std::shared_ptr WmoObject::getSkyBoxForGroup(int groupNum) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f8a353784..258d00f96 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -302,7 +302,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -339,7 +339,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,1,16}, - {0,0,480}, + {0,0,544}, }, { { @@ -377,7 +377,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -396,11 +396,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -423,7 +418,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,0,64}, - {0,0,480}, + {0,0,544}, {1,1,16}, }, { @@ -460,7 +455,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,544}, }, { { @@ -505,11 +500,8 @@ const std::unordered_map shaderMetaInfo = { {2,0,112}, {1,5,4096}, {1,2,16384}, - {0,0,480}, + {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -546,7 +538,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, {1,0,64}, }, { @@ -583,7 +575,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, {1,0,96}, }, { @@ -655,7 +647,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -676,11 +668,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -739,7 +726,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -847,7 +834,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -866,8 +853,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -889,7 +874,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,544}, }, { { @@ -906,7 +891,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -947,11 +931,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -968,18 +951,12 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {2,0,112}, - {0,0,480}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, + {0,0,544}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1014,11 +991,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1051,7 +1027,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {0,1,112}, - {0,0,480}, + {0,0,544}, }, { { @@ -1123,7 +1099,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,544}, }, { { @@ -1140,15 +1116,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1171,11 +1138,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1280,7 +1246,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,1,48}, - {0,0,480}, + {0,0,544}, {1,0,64}, }, { @@ -1343,12 +1309,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1365,7 +1329,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,2,32}, - {0,0,480}, + {0,0,544}, }, { { @@ -1521,8 +1485,8 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,1,96}, - {0,0,480}, + {1,1,48}, + {0,0,544}, }, { { @@ -1563,10 +1527,9 @@ const std::unordered_map shaderMetaInfo = { {1,4,256}, {1,3,4096}, {1,1,256}, - {0,0,480}, + {0,0,544}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -1606,7 +1569,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,544}, }, { { @@ -1625,8 +1588,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1649,7 +1610,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -1666,16 +1627,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1689,7 +1648,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,480}, + {0,0,544}, }, { { @@ -1712,7 +1671,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1772,7 +1730,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,0,64}, - {0,0,480}, + {0,0,544}, }, { { @@ -1844,7 +1802,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -1861,7 +1819,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -1957,7 +1914,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, - {0,0,480}, + {0,0,544}, }, { { @@ -1996,7 +1953,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -2106,18 +2063,13 @@ const std::unordered_map shaderMetaInfo = { { {1,2,16384}, {1,0,64}, - {0,0,480}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, + {0,0,544}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2149,7 +2101,7 @@ const std::unordered_map shaderMetaInfo = { { {1,1,16}, {1,0,4096}, - {0,0,480}, + {0,0,544}, }, { { @@ -2186,7 +2138,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,480}, + {0,0,544}, }, { { @@ -2223,11 +2175,8 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 9, { - } - }, - { - 8, { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { @@ -2239,16 +2188,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2701,19 +2629,19 @@ const std::unordered_mapgetObject(i); - blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; - if (isVulkan) { - blockPSVS.uPMatrix = vulkanMatrixFix * renderingMatrices->perspectiveMat; - } else { - blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; - } - blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; - blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); - - blockPSVS.extLight.uExteriorAmbientColor = fdd->colors.exteriorAmbientColor; - blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->colors.exteriorHorizontAmbientColor; - blockPSVS.extLight.uExteriorGroundAmbientColor = fdd->colors.exteriorGroundAmbientColor; - blockPSVS.extLight.uExteriorDirectColor = fdd->colors.exteriorDirectColor; - blockPSVS.extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); - blockPSVS.extLight.uAdtSpecMult_FogCount = mathfu::vec4(m_config->adtSpecMult, fdd->fogResults.size(), 0, 1.0); - - for (int i = 0; i < std::min(fdd->fogResults.size(), FOG_MAX_SHADER_COUNT); i++) { - auto &fogResult = fdd->fogResults[i]; - - auto &fogData = blockPSVS.fogData; - - mathfu::vec4 heightPlane = mathfu::vec4( - zUp.xyz(), - -(mathfu::vec3::DotProduct(zUp.xyz(), (zUp * fogResult.FogHeight).xyz())) - ); - heightPlane = renderingMatrices->invTranspViewMat * heightPlane; - - float fogEnd = std::min(std::max(m_config->farPlane, 277.5), m_config->farPlane); - if (m_config->disableFog || !fdd->FogDataFound) { - fogEnd = 100000000.0f; - fogResult.FogScaler = 0; - fogResult.FogDensity = 0; - fogResult.FogHeightDensity = 0; + for (int i = 0; i < renderingMatricess.size(); i++) { + auto const &renderingMatrices = renderingMatricess[i]; + + auto &blockPSVS = sceneWideChunk->getObject(i); + blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; + if (isVulkan) { + blockPSVS.uPMatrix = vulkanMatrixFix * renderingMatrices->perspectiveMat; + } else { + blockPSVS.uPMatrix = renderingMatrices->perspectiveMat; } + blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; + blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); + + blockPSVS.closeOceanColor = fdd->closeOceanColor; + blockPSVS.farOceanColor = fdd->farOceanColor; + blockPSVS.closeRiverColor = fdd->closeRiverColor; + blockPSVS.farRiverColor = fdd->farRiverColor; + + blockPSVS.extLight.uExteriorAmbientColor = fdd->colors.exteriorAmbientColor; + blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->colors.exteriorHorizontAmbientColor; + blockPSVS.extLight.uExteriorGroundAmbientColor = fdd->colors.exteriorGroundAmbientColor; + blockPSVS.extLight.uExteriorDirectColor = fdd->colors.exteriorDirectColor; + blockPSVS.extLight.uExteriorDirectColorDir = mathfu::vec4(fdd->exteriorDirectColorDir, 1.0); + blockPSVS.extLight.uAdtSpecMult_FogCount = mathfu::vec4(m_config->adtSpecMult, fdd->fogResults.size(), 0, 1.0); + + for (int i = 0; i < std::min(fdd->fogResults.size(), FOG_MAX_SHADER_COUNT); i++) { + auto &fogResult = fdd->fogResults[i]; + + auto &fogData = blockPSVS.fogData; + + mathfu::vec4 heightPlane = mathfu::vec4( + zUp.xyz(), + -(mathfu::vec3::DotProduct(zUp.xyz(), (zUp * fogResult.FogHeight).xyz())) + ); + heightPlane = renderingMatrices->invTranspViewMat * heightPlane; + + float fogEnd = std::min(std::max(m_config->farPlane, 277.5), m_config->farPlane); + if (m_config->disableFog || !fdd->FogDataFound) { + fogEnd = 100000000.0f; + fogResult.FogScaler = 0; + fogResult.FogDensity = 0; + fogResult.FogHeightDensity = 0; + } - const float densityMultFix = 0.00050000002 * std::pow(10, m_config->fogDensityIncreaser); - float fogScaler = fogResult.FogScaler; - if (fogScaler <= 0.00000001f) fogScaler = 0.5f; - float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; - - fogData.densityParams = mathfu::vec4( - fogStart, - fogEnd, - fogResult.FogDensity * densityMultFix, - 0); - fogData.classicFogParams = mathfu::vec4(0, 0, 0, 0); - fogData.heightPlane = heightPlane; - fogData.color_and_heightRate = mathfu::vec4(fogResult.FogColor, fogResult.FogHeightScaler -// * 0.01 - ); - fogData.heightDensity_and_endColor = mathfu::vec4( - fogResult.FogHeightDensity * densityMultFix, - fogResult.EndFogColor.x, - fogResult.EndFogColor.y, - fogResult.EndFogColor.z - ); - - fogData.sunAngle_and_sunColor = mathfu::vec4( - fogResult.SunFogAngle, - fogResult.SunFogColor.x, - fogResult.SunFogColor.y, - fogResult.SunFogColor.z - ); - fogData.heightColor_and_endFogDistance = mathfu::vec4( - fogResult.FogHeightColor, - (fogResult.EndFogColorDistance > 0) ? - fogResult.EndFogColorDistance : - 1000.0f - ); - fogData.sunPercentage = mathfu::vec4( - fogResult.SunFogAngle * fogResult.SunFogStrength, - 0, 1.0, 1.0); - fogData.sunDirection_and_fogZScalar = mathfu::vec4( - fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position - fogResult.FogZScalar - ); - fogData.heightFogCoeff = fogResult.FogHeightCoefficients; - fogData.mainFogCoeff = fogResult.MainFogCoefficients; - fogData.heightDensityFogCoeff = fogResult.HeightDensityFogCoefficients; - - bool mainFogOk = (fogResult.MainFogStartDist + 0.001 <= fogResult.MainFogEndDist); - fogData.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( - mainFogOk ? fogResult.MainFogEndDist : fogResult.MainFogStartDist + 0.001, - fogResult.MainFogStartDist >= 0.0 ? fogResult.MainFogStartDist : 0.0f, - fogResult.LegacyFogScalar, - fogResult.FogBlendAlpha - ); - fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( - fogResult.HeightEndFogColor, - fogResult.FogStartOffset - ); + const float densityMultFix = 0.00050000002 * std::pow(10, m_config->fogDensityIncreaser); + float fogScaler = fogResult.FogScaler; + if (fogScaler <= 0.00000001f) fogScaler = 0.5f; + float fogStart = std::min(m_config->farPlane, 3000) * fogScaler; + + fogData.densityParams = mathfu::vec4( + fogStart, + fogEnd, + fogResult.FogDensity * densityMultFix, + 0); + fogData.classicFogParams = mathfu::vec4(0, 0, 0, 0); + fogData.heightPlane = heightPlane; + fogData.color_and_heightRate = mathfu::vec4(fogResult.FogColor, fogResult.FogHeightScaler + // * 0.01 + ); + fogData.heightDensity_and_endColor = mathfu::vec4( + fogResult.FogHeightDensity * densityMultFix, + fogResult.EndFogColor.x, + fogResult.EndFogColor.y, + fogResult.EndFogColor.z + ); + + fogData.sunAngle_and_sunColor = mathfu::vec4( + fogResult.SunFogAngle, + fogResult.SunFogColor.x, + fogResult.SunFogColor.y, + fogResult.SunFogColor.z + ); + fogData.heightColor_and_endFogDistance = mathfu::vec4( + fogResult.FogHeightColor, + (fogResult.EndFogColorDistance > 0) ? + fogResult.EndFogColorDistance : + 1000.0f + ); + fogData.sunPercentage = mathfu::vec4( + fogResult.SunFogAngle * fogResult.SunFogStrength, + 0, 1.0, 1.0); + fogData.sunDirection_and_fogZScalar = mathfu::vec4( + fdd->exteriorDirectColorDir, //TODO: for fog this is calculated from SUN position + fogResult.FogZScalar + ); + fogData.heightFogCoeff = fogResult.FogHeightCoefficients; + fogData.mainFogCoeff = fogResult.MainFogCoefficients; + fogData.heightDensityFogCoeff = fogResult.HeightDensityFogCoefficients; + + bool mainFogOk = (fogResult.MainFogStartDist + 0.001 <= fogResult.MainFogEndDist); + fogData.mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha = mathfu::vec4( + mainFogOk ? fogResult.MainFogEndDist : fogResult.MainFogStartDist + 0.001, + fogResult.MainFogStartDist >= 0.0 ? fogResult.MainFogStartDist : 0.0f, + fogResult.LegacyFogScalar, + fogResult.FogBlendAlpha + ); + fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( + fogResult.HeightEndFogColor, + fogResult.FogStartOffset + ); + } + sceneWideChunk->saveVersion(i); } - sceneWideChunk->saveVersion(i); -} } From 324a03643fcf522fafd460adf63cfb9d51d0e8af Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 28 Oct 2023 09:37:50 +0300 Subject: [PATCH 149/212] - file list view step 1 --- CMakeLists.txt | 4 +- src/ui/FrontendUI.cpp | 20 +- src/ui/FrontendUI.h | 3 + .../fileListWindow/FileListWindow.cpp | 102 ++++++++ .../fileListWindow/FileListWindow.h | 50 ++++ .../shaders/glsl/visBuffer/adtShader.frag | 2 +- .../src/engine/objects/adt/adtObject.cpp | 35 +-- .../src/engine/objects/m2/m2Object.cpp | 17 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 1 + .../src/engine/objects/scenes/wmoScene.cpp | 21 +- .../src/engine/persistance/adtFile.cpp | 9 +- wowViewerLib/src/engine/persistance/adtFile.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 222 +++++++++++++----- .../vulkan/materials/ISimpleMaterialVLK.cpp | 5 +- .../vulkan/materials/ISimpleMaterialVLK.h | 5 +- .../vulkan/materials/MaterialBuilderVLK.cpp | 16 +- .../vulkan/materials/MaterialBuilderVLK.h | 11 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 102 +++++--- .../vulkan/MapSceneRenderVisBufferVLK.h | 31 ++- .../vulkan/materials/IMaterialInstance.h | 5 +- 20 files changed, 528 insertions(+), 135 deletions(-) create mode 100644 src/ui/childWindow/fileListWindow/FileListWindow.cpp create mode 100644 src/ui/childWindow/fileListWindow/FileListWindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0ee96131..c0b2aa350 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,7 +240,9 @@ set(SOURCE_FILES src/ui/imguiLib/wheelCapture/wheelCapture.cpp src/ui/imguiLib/wheelCapture/wheelCapture.h src/ui/childWindow/BLPViewer.cpp src/ui/childWindow/BLPViewer.h src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.cpp src/ui/childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp - src/ui/childWindow/textureRenderer/DebugRendererWindow.h) + src/ui/childWindow/textureRenderer/DebugRendererWindow.h + src/ui/childWindow/fileListWindow/FileListWindow.cpp + src/ui/childWindow/fileListWindow/FileListWindow.h) set(SOURCE_FILES_VULKAN diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index ef2436588..1ad0d986d 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -128,7 +128,7 @@ void FrontendUI::composeUI() { showSettingsDialog(); showQuickLinksDialog(); - + showFileList(); showMapSelectionDialog(); showMakeScreenshotDialog(); showCurrentStatsDialog(); @@ -360,6 +360,15 @@ void FrontendUI::showBlpViewer() { } } +void FrontendUI::showFileList() { + if (!m_fileListWindow) return; + + if (!m_fileListWindow->draw()) { + m_fileListWindow = nullptr; + } +} + + // templated version of my_equal so it could work with both char and wchar_t template struct my_equal { @@ -754,7 +763,10 @@ void FrontendUI::showMainMenu() { ImGui::EndMenu(); } if (ImGui::BeginMenu("View")) { - if (ImGui::MenuItem("Open minimap")) {} + if (ImGui::MenuItem("Open File List", "", false, cascOpened)) { + if (!m_fileListWindow) + m_fileListWindow = std::make_shared(m_api); + } if (ImGui::MenuItem("Open current stats")) { showCurrentStats = true; } ImGui::Separator(); if (ImGui::MenuItem("Open settings")) {showSettings = true;} @@ -767,6 +779,7 @@ void FrontendUI::showMainMenu() { if (!m_blpViewerWindow) m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer); } + if (ImGui::MenuItem("Test export")) { if (m_currentScene != nullptr) { exporter = std::make_shared("./gltf/"); @@ -960,6 +973,9 @@ void FrontendUI::showQuickLinksDialog() { if (ImGui::Button("8du_zuldazarraid_antiportal01.wmo", ImVec2(-1, 0))) { openWMOSceneByfdid(2574165); } + if (ImGui::Button("someShip.wmo", ImVec2(-1, 0))) { + openWMOSceneByfdid(4638404); + } if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, "world/wmo/dungeon/az_karazahn/karazhan.wmo"); diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index a693309ff..62360e6ba 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -28,6 +28,7 @@ #include "childWindow/BLPViewer.h" #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "childWindow/textureRenderer/DebugRendererWindow.h" +#include "childWindow/fileListWindow/FileListWindow.h" class FrontendUI : public IScene, public std::enable_shared_from_this { @@ -193,6 +194,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_minimapGenerationWindow = nullptr; std::shared_ptr m_blpViewerWindow = nullptr; + std::shared_ptr m_fileListWindow = nullptr; std::shared_ptr m_debugRenderWindow; @@ -238,6 +240,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this(); +} + +bool FileListWindow::draw() { + ImGui::Begin("File list", &m_showWindow); + { + if (ImGui::Button("Import filelist.csv...")) { + importCSV(); + } + ImGui::SameLine(); + if (ImGui::Button("Scan repository...")) { + + } + + if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Sortable | + ImGuiTableFlags_NoHostExtendX | + ImGuiTableFlags_NoHostExtendY | + ImGuiTableFlags_ScrollX, ImVec2(-1, -1))) { + + ImGui::TableSetupColumn("FileDataId", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("FileName", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("FileType", ImGuiTableColumnFlags_None); + ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible + ImGui::TableHeadersRow(); + + { + ImGuiListClipper clipper; + clipper.Begin(m_filesTotal); + while (clipper.Step()) { + auto f_amount = clipper.DisplayEnd-clipper.DisplayStart; + auto f_offset = clipper.DisplayStart; + + using namespace sqlite_orm; + auto items = m_storage.get_all( + order_by(&FileListDB::FileRecord::fileDataId), limit(f_offset, f_amount)); + + for (int i = 0; i < items.size(); i++) { + auto const &fileItem = items[i]; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d", fileItem.fileDataId); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileName.c_str()); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileType.c_str()); + } + } + } + ImGui::EndTable(); + } + } + ImGui::End(); + + return m_showWindow; +} + +void FileListWindow::importCSV() { + auto csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); + + int currentFileDataId; + std::string currentFileName; + + using namespace sqlite_orm; + auto statement = m_storage.prepare( + select( + columns(&FileListDB::FileRecord::fileType), from(), + where(is_equal(&FileListDB::FileRecord::fileDataId, std::ref(currentFileDataId))) + ) + ); + + while (csv->read_row(currentFileDataId, currentFileName)) { + auto typeFromDB = m_storage.execute(statement); + + std::string fileType = ""; + if (!typeFromDB.empty()) { + fileType = get<0>(typeFromDB[0]); + } + + m_storage.replace(FileListDB::FileRecord({currentFileDataId, currentFileName, fileType})); + } + + m_filesTotal = m_storage.count(); + + delete csv; +} diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h new file mode 100644 index 000000000..efc7ed694 --- /dev/null +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -0,0 +1,50 @@ +// +// Created by Deamon on 10/28/2023. +// + +#ifndef AWEBWOWVIEWERCPP_FILELISTWINDOW_H +#define AWEBWOWVIEWERCPP_FILELISTWINDOW_H + +#include "../../renderer/uiScene/FrontendUIRenderer.h" +#include "../../../../wowViewerLib/src/engine/ApiContainer.h" +#include "../../../3rdparty/sqlite_orm/sqlite_orm.h" + +namespace FileListDB { + struct FileRecord { + int fileDataId; + std::string fileName; + std::string fileType; + }; + + inline static auto makeStorage(const std::string &dataBaseFile) { + using namespace sqlite_orm; + return make_storage(dataBaseFile, + make_index("idx_files_name", &FileRecord::fileName), + make_index("idx_files_type", &FileRecord::fileType), + make_table("files", + make_column("fileDataId", &FileRecord::fileDataId, primary_key()), + make_column("fileName", &FileRecord::fileName), + make_column("file_type", &FileRecord::fileType) + ) + ); + }; +} + +class FileListWindow { +public: + FileListWindow(const HApiContainer &api); + + bool draw(); +private: + HApiContainer m_api; + + bool m_showWindow; + int m_filesTotal; + decltype(FileListDB::makeStorage("")) m_storage; + +private: + void importCSV(); +}; + + +#endif //AWEBWOWVIEWERCPP_FILELISTWINDOW_H diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index b65817bd6..bc38f77d4 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -145,7 +145,7 @@ void main() { vec4 tex3 = texture(s_LayerTextures[nonuniformEXT(txLayer2)], tcLayer2).rgba; vec4 tex4 = texture(s_LayerTextures[nonuniformEXT(txLayer3)], tcLayer3).rgba; - final = mixTextures(mixTextures(mixTextures(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + final = mix(mix(mix(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); } vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 63ddc969d..fd7f1f79c 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -474,9 +474,9 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } } -inline uint8_t &getChannel(std::vector &data, int x, int y, int width, int height, char channel) { +inline uint8_t &getChannel(uint8_t *data, int x, int y, int width, int height, char channel) { - assert(((width * y + x ) * 4 + channel) < data.size()); +// assert(((width * y + x ) * 4 + channel) < data.size()); return data[(width * y + x) * 4 + channel]; }; @@ -492,30 +492,35 @@ void AdtObject::loadAlphaTextures() { int createdThisRun = 0; alphaTexture = m_api->hDevice->createTexture(false, false); std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); - if (chunkCount > 0) { - oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); - arena.execute([&] { - oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { - std::vector alphaTextureData = std::vector(alphaTexSize * alphaTexSize * 4); - for (size_t i = r.begin(); i != r.end(); ++i) { + memset(bigTexture.data(), 0, bigTexture.size()); + std::array alphaTextureData; + + if (chunkCount > 0) + for (int i = 0; i < chunkCount; i++){ +// oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); +// arena.execute([&] { +// oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { +// for (size_t i = r.begin(); i != r.end(); ++i) { auto const &mapTile = m_adtFile->mapTile[i]; + const auto indexX = mapTile.IndexX; + const auto indexY = mapTile.IndexY; memset(alphaTextureData.data(), 0, alphaTextureData.size()); - m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData); + m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData.data(), alphaTextureData.size()); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { for (char channel = 0; channel < 4; channel++) { - getChannel(bigTexture, - mapTile.IndexX * 64 + x, mapTile.IndexY * 64 + y, + getChannel(bigTexture.data(), + indexX * 64 + x, indexY * 64 + y, texWidth, texHeight, channel) = - getChannel(alphaTextureData, x, y, alphaTexSize, alphaTexSize, channel); + getChannel(alphaTextureData.data(), x, y, alphaTexSize, alphaTexSize, channel); } } } - } - }, tbb::auto_partitioner()); - }); +// } +// }, tbb::auto_partitioner()); +// }); } alphaTexture->getTexture()->loadData(texWidth, texHeight, &bigTexture[0], ITextureFormat::itRGBA); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index efadc51a0..06053f6ed 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1019,6 +1019,14 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v ribbonEmitters[i]->SetPos(transformMat, nullPos, nullptr); ribbonEmitters[i]->Update(deltaTime * 0.001f, 0); } + + M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); + for (int i = 0; i < this->m_meshArray.size(); i++) { + int currentM2BatchIndex = std::get<1>(this->m_meshArray[i]); + + float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); + m_finalTransparencies[i] = finalTransparency; + } } void M2Object::fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer) { @@ -1570,7 +1578,7 @@ void M2Object::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { m_meshArray.push_back({createWaterfallMesh(sceneRenderer, bufferBindings), 0}); } - + m_finalTransparencies.resize(m_meshArray.size(), 1.0); } EGxBlendEnum M2Object::getBlendMode(int batchIndex) { @@ -1637,14 +1645,15 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vec int minBatch = m_api->getConfig()->m2MinBatch; int maxBatch = std::min(m_api->getConfig()->m2MaxBatch, (const int &) this->m_meshArray.size()); - bool isWaterFallMesh = m_m2Geom->m_wfv3 == nullptr && m_m2Geom->m_wfv1 == nullptr; + bool isWaterFallMesh = m_m2Geom->m_wfv3 != nullptr && m_m2Geom->m_wfv1 != nullptr; if (m_api->getConfig()->renderM2) { for (int i = 0; i < this->m_meshArray.size(); i++) { int currentM2BatchIndex = std::get<1>(this->m_meshArray[i]); if (currentM2BatchIndex < minBatch || currentM2BatchIndex > maxBatch ) continue; - float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); +// float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, currentM2BatchIndex, skinData); + float finalTransparency = m_finalTransparencies[i]; bool meshIsInvisible = finalTransparency < 0.0001; if (m_api->getConfig()->discardInvisibleMeshes && meshIsInvisible) continue; @@ -1658,7 +1667,7 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vec if (mesh->getIsTransparent()) { transparentMeshes.push_back(mesh); } else { - if (isWaterFallMesh) { + if (!isWaterFallMesh) { opaqueMeshCollector.addM2Mesh(mesh); } else { opaqueMeshCollector.addMesh(mesh); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index ca86ebff8..268baab39 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -139,6 +139,7 @@ class M2Object { //Tuple of Mesh and batch index std::vector> m_meshForcedTranspArray; std::vector> m_meshArray; + std::vector m_finalTransparencies; //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp index cc03ac842..2ceccbf95 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.cpp @@ -32,16 +32,25 @@ void WmoScene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, Mat Map::updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); - mathfu::vec4 ambient = mathfu::vec4(1.0,1.0,1.0,1.0); + mathfu::vec4 exteriorAmbient = mathfu::vec4(1.0,1.0,1.0,1.0); auto frameDependantData = mapRenderPlan->frameDependentData; - - frameDependantData->colors.exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->colors.exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDependantData->colors.exteriorDirectColor = mathfu::vec4(0.3, 0.30, 0.3, 0.3); frameDependantData->exteriorDirectColorDir = MathHelper::calcExteriorColorDir( mapRenderPlan->renderingMatrices->lookAtMat, m_api->getConfig()->currentTime ); + + if (m_api->getConfig()->globalLighting == EParameterSource::eDatabase) { + frameDependantData->colors.exteriorAmbientColor = mathfu::vec4(exteriorAmbient.x, exteriorAmbient.y, exteriorAmbient.z, 1.0); + frameDependantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(exteriorAmbient.x, exteriorAmbient.y, exteriorAmbient.z, 1.0); + frameDependantData->colors.exteriorGroundAmbientColor = mathfu::vec4(exteriorAmbient.x, exteriorAmbient.y, exteriorAmbient.z, 1.0); + frameDependantData->colors.exteriorDirectColor = mathfu::vec4(0.5, 0.5, 0.5, 0.5); + } else if (config->globalLighting == EParameterSource::eConfig) { + auto fdd = mapRenderPlan->frameDependentData; + + fdd->colors.exteriorAmbientColor = config->exteriorColors.exteriorAmbientColor; + fdd->colors.exteriorGroundAmbientColor = config->exteriorColors.exteriorGroundAmbientColor; + fdd->colors.exteriorHorizontAmbientColor = config->exteriorColors.exteriorHorizontAmbientColor; + fdd->colors.exteriorDirectColor = config->exteriorColors.exteriorDirectColor; + } } \ No newline at end of file diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 5a37c9511..6189a3cae 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -486,15 +486,18 @@ chunkDef AdtFile::adtFileTable = { } }; -void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, std::vector ¤tLayer) { +void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize) { mcnkStruct_t &mcnkObj = mcnkStructs[i]; uint8_t* alphaArray = mcnkObj.mcal; PointerChecker &layers = mcnkObj.mcly; - assert(currentLayer.size() >= (64*4) * 64); + assert(currentLayerSize >= (64*4) * 64); + assert(mcnkObj.mclyCnt <= 4); if (layers == nullptr || alphaArray == nullptr) return; - for (int j = 0; j ¤tLayer); + void processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize); void process(HFileContent adtFile, const std::string &fileName) override; void setIsMain(bool isMain) { m_mainAdt = isMain; }; public: diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 258d00f96..d40550ab6 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,6 +396,11 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -502,6 +507,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { @@ -668,6 +676,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -853,6 +866,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -891,6 +906,7 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, @@ -931,10 +947,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -952,11 +969,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -991,10 +1014,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,6 +1140,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1138,10 +1171,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1309,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1530,6 +1566,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -1588,6 +1625,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1627,14 +1666,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1671,6 +1712,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1819,6 +1861,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -2064,12 +2107,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2175,8 +2223,11 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { } }, { @@ -2188,6 +2239,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2628,10 +2728,6 @@ const std::unordered_map &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, - const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, + uint32_t materialId) : m_shader(shader), m_pipelineTemplate(pipelineTemplate), - m_pipeline(pipeline) { + m_pipeline(pipeline), m_materialId(materialId) { for (int i = descriptorSets.size()-1; i < descriptorSets.size(); i--) { if (descriptorSets[i] != nullptr) { this->descriptors.resize(i+1); diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index cea0f9309..7d4e3b26c 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -18,7 +18,8 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this explicit ISimpleMaterialVLK(const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, - const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, + uint32_t materialId); ~ISimpleMaterialVLK() override = default; const std::shared_ptr &getShader() const { @@ -34,12 +35,14 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this const PipelineTemplate &getPipelineTemplate() const { return m_pipelineTemplate; } + const uint32_t getMaterialId() {return m_materialId;} std::shared_ptr getPipeLineForRenderPass(const std::shared_ptr &renderPass); EGxBlendEnum getBlendMode(); private: std::vector> descriptors; + uint32_t m_materialId; std::shared_ptr m_shader; HPipelineVLK m_pipeline; PipelineTemplate m_pipelineTemplate; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index 253638046..eb0debc9d 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -14,6 +14,8 @@ MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &dev shaderFiles[0], shaderFiles[1], shaderConfig)); + m_materialId = 0; + m_pipelineLayout = m_shader->getPipelineLayout(); } @@ -23,9 +25,10 @@ MaterialBuilderVLK::MaterialBuilderVLK( const HPipelineVLK &pipeline, const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, - const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, + uint32_t materialId) : m_device(device), m_shader(shader), m_pipeline(pipeline), m_pipelineTemplate(pipelineTemplate), - m_descriptorSets(descriptorSets), m_pipelineLayout(pipelineLayout) { + m_descriptorSets(descriptorSets), m_pipelineLayout(pipelineLayout), m_materialId(materialId) { } @@ -77,11 +80,18 @@ MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindi return *this; } +MaterialBuilderVLK &MaterialBuilderVLK::setMaterialId(uint32_t matId) { + m_materialId = matId; + + return *this; +} + std::shared_ptr MaterialBuilderVLK::toMaterial() { return std::make_shared( m_shader, m_pipelineTemplate, m_pipeline, - m_descriptorSets + m_descriptorSets, + m_materialId ); } diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index 0384a1567..ab9ad0bb6 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -28,7 +28,8 @@ class MaterialBuilderVLK { materialVlk->getPipeline(), materialVlk->getPipeline()->getLayout(), materialVlk->getPipelineTemplate(), - toArray(materialVlk->getDescriptorSets()) + toArray(materialVlk->getDescriptorSets()), + materialVlk->getMaterialId() }; } MaterialBuilderVLK& overridePipelineLayout(const std::unordered_map> &dses); @@ -37,6 +38,7 @@ class MaterialBuilderVLK { MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, const std::shared_ptr &renderPass, const PipelineTemplate &pipelineTemplate); + MaterialBuilderVLK& setMaterialId(uint32_t matId); std::shared_ptr toMaterial(); template @@ -45,7 +47,8 @@ class MaterialBuilderVLK { m_shader, m_pipelineTemplate, m_pipeline, - m_descriptorSets); + m_descriptorSets, + m_materialId); } ~MaterialBuilderVLK() = default; @@ -65,13 +68,15 @@ class MaterialBuilderVLK { const HPipelineVLK &pipeline, const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, - const std::array, MAX_SHADER_DESC_SETS> &descriptorSets); + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, + uint32_t materialId); private: //States const std::shared_ptr &m_device; + uint32_t m_materialId; std::shared_ptr m_shader; HPipelineVLK m_pipeline; std::shared_ptr m_pipelineLayout; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index f838c0211..1a48351c3 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -361,15 +361,12 @@ void MapSceneRenderVisBufferVLK::createM2WaterfallGlobalMaterialData() { std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_m2StaticMaterials.find(pipelineTemplate); if (i != m_m2StaticMaterials.end()) { - if (!i->second.expired()) { - return i->second.lock(); - } else { - m_m2StaticMaterials.erase(i); - } + return i->second; } auto staticMaterial = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + .setMaterialId(generateUniqueM2MatId()) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) @@ -377,6 +374,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater .toMaterial(); m_m2StaticMaterials[pipelineTemplate] = staticMaterial; + m_m2MatCacheId[staticMaterial->getMaterialId()] = staticMaterial; return staticMaterial; } @@ -384,15 +382,12 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_wmoStaticMaterials.find(pipelineTemplate); if (i != m_wmoStaticMaterials.end()) { - if (!i->second.expired()) { - return i->second.lock(); - } else { - m_wmoStaticMaterials.erase(i); - } + return i->second; } auto staticMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + .setMaterialId(generateUniqueWMOMatId()) .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, wmoBufferOneDS) @@ -400,6 +395,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMate .toMaterial(); m_wmoStaticMaterials[pipelineTemplate] = staticMaterial; + m_wmoMatCacheId[staticMaterial->getMaterialId()] = staticMaterial; return staticMaterial; } @@ -958,10 +954,13 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ public: COpaqueMeshCollectorBindlessVLK(MapSceneRenderVisBufferVLK &rendererVlk) : m_renderer(rendererVlk) { commonMeshes.reserve(1000); + m2DrawVec.reserve(5000); + wmoDrawVec.reserve(5000); } private: MapSceneRenderVisBufferVLK &m_renderer; struct DrawCommand { + uint32_t matId; uint32_t indexCount; uint32_t instanceCount; uint32_t firstIndex; @@ -971,13 +970,13 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ typedef std::unordered_map, std::vector> MeshMap; - MeshMap m2MeshMap; - MeshMap wmoMeshMap; + std::vector m2DrawVec; + std::vector wmoDrawVec; MeshMap waterMeshMap; - MeshMap adtMeshMap; + std::vector adtDrawVec; std::vector commonMeshes; - inline void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { + inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { const auto &meshVlk = (GMeshVLK*) mesh.get(); auto const &pipeline = meshVlk->material()->getPipeline(); @@ -990,6 +989,24 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ drawCommand.instanceCount = 1; drawCommand.firstIndex = meshVlk->start() / 2; + if (meshVlk->instanceIndex != -1) { + drawCommand.firstInstance = meshVlk->instanceIndex; + drawCommand.vertexOffset = meshVlk->vertexStart; + } else { + drawCommand.firstInstance = 0; + drawCommand.vertexOffset = 0; + } + } + inline static void addDrawCommand(std::vector &drawVec, const HGMesh &mesh) { + const auto &meshVlk = (GMeshVLK*) mesh.get(); + auto const matId = meshVlk->material()->getMaterialId(); + + auto &drawCommand = drawVec.emplace_back(); + drawCommand.matId = matId; + drawCommand.indexCount = meshVlk->end(); + drawCommand.instanceCount = 1; + drawCommand.firstIndex = meshVlk->start() / 2; + if (meshVlk->instanceIndex != -1) { drawCommand.firstInstance = meshVlk->instanceIndex; drawCommand.vertexOffset = meshVlk->vertexStart; @@ -1000,16 +1017,16 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ } public: void addM2Mesh(const HGM2Mesh &mesh) override { - fillMapWithMesh(m2MeshMap, mesh); + addDrawCommand(m2DrawVec, mesh); }; void addWMOMesh(const HGMesh &mesh) override { - fillMapWithMesh(wmoMeshMap, mesh); + addDrawCommand(wmoDrawVec, mesh); } ; void addWaterMesh(const HGMesh &mesh) override { fillMapWithMesh(waterMeshMap, mesh); } ; void addADTMesh(const HGMesh &mesh) override { - fillMapWithMesh(adtMeshMap, mesh); + addDrawCommand(adtDrawVec, mesh); } ; void addMesh(const HGMesh &mesh) override { @@ -1017,51 +1034,68 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ }; void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + std::sort(m2DrawVec.begin(), m2DrawVec.end(), [](DrawCommand const &a, DrawCommand const &b) { + return a.matId < b.matId; + }); + std::sort(wmoDrawVec.begin(), wmoDrawVec.end(), [](DrawCommand const &a, DrawCommand const &b) { + return a.matId < b.matId; + }); + cmdBuf.setDefaultScissors(); cmdBuf.setViewPort(viewPortType); - if (!adtMeshMap.empty()) + if (!adtDrawVec.empty()) { //1. Render ADT cmdBuf.bindVertexBindings(m_renderer.getDefaultADTVao()); cmdBuf.bindMaterial(m_renderer.getGlobalADTMaterial()); - for (auto const &record : adtMeshMap) { - cmdBuf.bindPipeline(record.first); - - for (auto const & drawCmd : record.second) { - cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); - } + for (auto const & drawCmd : adtDrawVec) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } } - if (!wmoMeshMap.empty()) + if (!wmoDrawVec.empty()) { //2. Render WMO cmdBuf.bindVertexBindings(m_renderer.getDefaultWMOVao()); cmdBuf.bindMaterial(m_renderer.getGlobalWMOMaterial()); - for (auto const &record : wmoMeshMap) { - cmdBuf.bindPipeline(record.first); + uint32_t currentMatId = 0xFFFFFFFF; + for (auto const &drawCmd : wmoDrawVec) { + if (currentMatId != drawCmd.matId) { + auto material = m_renderer.m_wmoMatCacheId[drawCmd.matId].lock(); + if (!material) + continue; - for (auto const & drawCmd : record.second) { - cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + cmdBuf.bindPipeline(material->getPipeline()); + + currentMatId = drawCmd.matId; } + + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } } - if (!m2MeshMap.empty()) + if (!m2DrawVec.empty()) { //3. Render m2 cmdBuf.bindVertexBindings(m_renderer.getDefaultM2Vao()); cmdBuf.bindMaterial(m_renderer.getGlobalM2Material()); - for (auto const &record : m2MeshMap) { - cmdBuf.bindPipeline(record.first); + uint32_t currentMatId = 0xFFFFFFFF; + for (auto const &drawCmd : m2DrawVec) { + if (currentMatId != drawCmd.matId) { + auto material = m_renderer.m_m2MatCacheId[drawCmd.matId].lock(); + if (!material) + continue; - for (auto const & drawCmd : record.second) { - cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + cmdBuf.bindPipeline(material->getPipeline()); + + currentMatId = drawCmd.matId; } + + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index ae7996153..c4e2be44e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -16,6 +16,7 @@ #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { + friend class COpaqueMeshCollectorBindlessVLK; public: explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); ~MapSceneRenderVisBufferVLK() override = default; @@ -126,8 +127,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { (hash{}(k.colorMask) << 18); }; }; - std::unordered_map, PipelineTemplateHasher> m_m2StaticMaterials; - std::unordered_map, PipelineTemplateHasher> m_wmoStaticMaterials; + std::unordered_map, PipelineTemplateHasher> m_m2StaticMaterials; + std::unordered_map, PipelineTemplateHasher> m_wmoStaticMaterials; private: HGDeviceVLK m_device; @@ -243,6 +244,32 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { void createADTGlobalMaterialData(); void createWaterGlobalMaterialData(); void createM2WaterfallGlobalMaterialData(); + + + std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator + //and seed it with entropy. + std::uniform_int_distribution idDistr; + std::unordered_map> m_m2MatCacheId; + std::unordered_map> m_wmoMatCacheId; + + uint32_t generateUniqueWMOMatId() { + uint32_t random; + do { + random = idDistr(eng); + } while (!m_wmoMatCacheId[random].expired()); + + return random; + } + + uint32_t generateUniqueM2MatId() { + uint32_t random; + do { + random = idDistr(eng); + } while (!m_m2MatCacheId[random].expired()); + + return random; + } + public: const std::shared_ptr &getGlobalADTMaterial() const {return g_adtMaterial;}; const std::shared_ptr &getGlobalM2Material() const {return g_m2Material;}; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h index e6bc5a29e..5ed5e6224 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h @@ -17,8 +17,9 @@ class IMaterialInstance : public ISimpleMaterialVLK, public IMaterialClass { const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, - const std::array, MAX_SHADER_DESC_SETS> &descriptorSets) : - ISimpleMaterialVLK(shader, pipelineTemplate, pipeline, descriptorSets) { + const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, + uint32_t materialId) : + ISimpleMaterialVLK(shader, pipelineTemplate, pipeline, descriptorSets, materialId) { initializer(this); } From 6979140ee07e8fbbc3a36b063dc3fcaf2ab77ce0 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 6 Nov 2023 20:06:45 +0200 Subject: [PATCH 150/212] - stage 1 of adding of filelist --- 3rdparty/sqlite_orm/sqlite_orm.h | 17282 +++++++++------- CMakeLists.txt | 1 + .../dataExporter/DataExporterClass.h | 2 +- src/minimapGenerator/storage/CMinimapDataDB.h | 4 +- .../fileListWindow/FileListWindow.cpp | 86 +- .../fileListWindow/FileListWindow.h | 69 +- 6 files changed, 10380 insertions(+), 7064 deletions(-) diff --git a/3rdparty/sqlite_orm/sqlite_orm.h b/3rdparty/sqlite_orm/sqlite_orm.h index 76f1d0809..24a958e8c 100644 --- a/3rdparty/sqlite_orm/sqlite_orm.h +++ b/3rdparty/sqlite_orm/sqlite_orm.h @@ -1,35 +1,434 @@ #pragma once #if defined(_MSC_VER) -#if defined(min) __pragma(push_macro("min")) #undef min -#define __RESTORE_MIN__ -#endif -#if defined(max) - __pragma(push_macro("max")) +__pragma(push_macro("max")) #undef max -#define __RESTORE_MAX__ -#endif #endif // defined(_MSC_VER) +#pragma once -#include // due to #166 +// #include "cxx_universal.h" -#if __cplusplus >= 201703L // use of C++17 or higher -// Enables use of std::optional in SQLITE_ORM. -#define SQLITE_ORM_OPTIONAL_SUPPORTED -#define SQLITE_ORM_STRING_VIEW_SUPPORTED +/* + * This header makes central C++ functionality on which sqlite_orm depends universally available: + * - alternative operator representations + * - ::size_t, ::ptrdiff_t, ::nullptr_t + * - C++ core language feature macros + * - macros for dealing with compiler quirks + */ + +#include // alternative operator representations +#include // sqlite_orm is using size_t, ptrdiff_t, nullptr_t everywhere, pull it in early + +// earlier clang versions didn't make nullptr_t available in the global namespace via stddef.h, +// though it should have according to C++ documentation (see https://en.cppreference.com/w/cpp/types/nullptr_t#Notes). +// actually it should be available when including stddef.h +using std::nullptr_t; + +// #include "cxx_core_features.h" + +/* + * This header detects core C++ language features on which sqlite_orm depends. + * May be updated/overwritten by cxx_compiler_quirks.h + */ + +#ifdef __has_cpp_attribute +#define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) +#else +#define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) 0L +#endif + +#ifdef __has_include +#define SQLITE_ORM_HAS_INCLUDE(file) __has_include(file) +#else +#define SQLITE_ORM_HAS_INCLUDE(file) 0L +#endif + +#if __cpp_aggregate_nsdmi >= 201304L +#define SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED +#endif + +#if __cpp_constexpr >= 201304L +#define SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED +#endif + +#if __cpp_noexcept_function_type >= 201510L #define SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED #endif + +#if __cpp_aggregate_bases >= 201603L +#define SQLITE_ORM_AGGREGATE_BASES_SUPPORTED +#endif + +#if __cpp_fold_expressions >= 201603L +#define SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED +#endif + +#if __cpp_if_constexpr >= 201606L +#define SQLITE_ORM_IF_CONSTEXPR_SUPPORTED +#endif + +#if __cpp_inline_variables >= 201606L +#define SQLITE_ORM_INLINE_VARIABLES_SUPPORTED +#endif + +#if __cpp_generic_lambdas >= 201707L +#define SQLITE_ORM_EXPLICIT_GENERIC_LAMBDA_SUPPORTED +#else +#endif + +#if __cpp_consteval >= 201811L +#define SQLITE_ORM_CONSTEVAL_SUPPORTED +#endif + +#if __cpp_aggregate_paren_init >= 201902L +#define SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED +#endif + +#if __cpp_concepts >= 201907L +#define SQLITE_ORM_CONCEPTS_SUPPORTED +#endif + +#if __cpp_nontype_template_args >= 201911L +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif + +#if __cpp_nontype_template_args >= 201911L +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif + +#if(__cplusplus >= 202002L) +#define SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED +#endif + +// #include "cxx_compiler_quirks.h" + +/* + * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. + * May amend cxx_core_features.h + */ + +#ifdef __clang__ +#define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) +#endif + +#ifdef __clang__ +#define SQLITE_ORM_CLANG_SUPPRESS(warnoption, ...) \ + SQLITE_ORM_DO_PRAGMA(clang diagnostic push) \ + SQLITE_ORM_DO_PRAGMA(clang diagnostic ignored warnoption) \ + __VA_ARGS__ \ + SQLITE_ORM_DO_PRAGMA(clang diagnostic pop) + +#else +#define SQLITE_ORM_CLANG_SUPPRESS(warnoption, ...) __VA_ARGS__ +#endif + +// clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. +// This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, +// see https://en.cppreference.com/w/cpp/language/aggregate_initialization: +// "The braces around the nested initializer lists may be elided (omitted), +// in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, +// and the subsequent initializer clauses are used to initialize the following members of the object." +// In this sense clang should only warn about missing field initializers. +// Because we know what we are doing, we suppress the diagnostic message +#define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#endif + +// These compilers are known to have problems with alias templates in SFINAE contexts: +// clang 3.5 +// gcc 8.3 +// msvc 15.9 +// Type replacement may fail if an alias template has dependent expression or decltype in it. +// In these cases we have to use helper structures to break down the type alias. +// Note that the detection of specific compilers is so complicated because some compilers emulate other compilers, +// so we simply exclude all compilers that do not support C++20, even though this test is actually inaccurate. +#if(defined(_MSC_VER) && (_MSC_VER < 1920)) || (!defined(_MSC_VER) && (__cplusplus < 202002L)) +#define SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE +#endif + +// overwrite SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#if(__cpp_nontype_template_args < 201911L) && \ + (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif + +// clang 10 chokes on concepts that don't depend on template parameters; +// when it tries to instantiate an expression in a requires expression, which results in an error, +// the compiler reports an error instead of dismissing the templated function. +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && (defined(__clang__) && (__clang_major__ == 10)) +#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS +#endif + +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif + +#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED +#define SQLITE_ORM_INLINE_VAR inline +#else +#define SQLITE_ORM_INLINE_VAR +#endif + +#if SQLITE_ORM_HAS_CPP_ATTRIBUTE(no_unique_address) >= 201803L +#define SQLITE_ORM_NOUNIQUEADDRESS [[no_unique_address]] +#else +#define SQLITE_ORM_NOUNIQUEADDRESS +#endif + +#ifdef SQLITE_ORM_CONSTEVAL_SUPPORTED +#define SQLITE_ORM_CONSTEVAL consteval +#else +#define SQLITE_ORM_CONSTEVAL constexpr +#endif + +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && __cpp_lib_concepts >= 202002L +#define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#endif + +#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \ + defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \ + (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) +#define SQLITE_ORM_WITH_CPP20_ALIASES +#endif +#pragma once + +#include // std::enable_if, std::is_same +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES +#include +#endif + +// #include "functional/cxx_type_traits_polyfill.h" + +#include + +// #include "cxx_universal.h" + +namespace sqlite_orm { + namespace internal { + namespace polyfill { +#if __cpp_lib_void_t >= 201411L + using std::void_t; +#else + template + using void_t = void; +#endif + +#if __cpp_lib_bool_constant >= 201505L + using std::bool_constant; +#else + template + using bool_constant = std::integral_constant; +#endif + +#if __cpp_lib_logical_traits >= 201510L && __cpp_lib_type_trait_variable_templates >= 201510L + using std::conjunction; + using std::conjunction_v; + using std::disjunction; + using std::disjunction_v; + using std::negation; + using std::negation_v; +#else + template + struct conjunction : std::true_type {}; + template + struct conjunction : B1 {}; + template + struct conjunction : std::conditional_t, B1> {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool conjunction_v = conjunction::value; + + template + struct disjunction : std::false_type {}; + template + struct disjunction : B1 {}; + template + struct disjunction : std::conditional_t> {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool disjunction_v = disjunction::value; + + template + struct negation : bool_constant {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool negation_v = negation::value; +#endif + +#if __cpp_lib_remove_cvref >= 201711L + using std::remove_cvref, std::remove_cvref_t; +#else + template + struct remove_cvref : std::remove_cv> {}; + + template + using remove_cvref_t = typename remove_cvref::type; +#endif + +#if __cpp_lib_type_identity >= 201806L + using std::type_identity, std::type_identity_t; +#else + template + struct type_identity { + using type = T; + }; + + template + using type_identity_t = typename type_identity::type; +#endif + +#if 0 // __cpp_lib_detect >= 0L // library fundamentals TS v2, [meta.detect] + using std::nonesuch; + using std::detector; + using std::is_detected, std::is_detected_v; + using std::detected, std::detected_t; + using std::detected_or, std::detected_or_t; +#else + struct nonesuch { + ~nonesuch() = delete; + nonesuch(const nonesuch&) = delete; + void operator=(const nonesuch&) = delete; + }; + + template class Op, class... Args> + struct detector { + using value_t = std::false_type; + using type = Default; + }; + + template class Op, class... Args> + struct detector>, Op, Args...> { + using value_t = std::true_type; + using type = Op; + }; + + template class Op, class... Args> + using is_detected = typename detector::value_t; + + template class Op, class... Args> + using detected = detector; + + template class Op, class... Args> + using detected_t = typename detector::type; + + template class Op, class... Args> + using detected_or = detector; + + template class Op, class... Args> + using detected_or_t = typename detected_or::type; + + template class Op, class... Args> + SQLITE_ORM_INLINE_VAR constexpr bool is_detected_v = is_detected::value; +#endif + +#if 0 // proposed but not pursued + using std::is_specialization_of, std::is_specialization_of_t, std::is_specialization_of_v; +#else + // is_specialization_of: https://github.com/cplusplus/papers/issues/812 + + template class Primary> + SQLITE_ORM_INLINE_VAR constexpr bool is_specialization_of_v = false; + + template class Primary, class... Types> + SQLITE_ORM_INLINE_VAR constexpr bool is_specialization_of_v, Primary> = true; + + template class Primary> + struct is_specialization_of : bool_constant> {}; +#endif + + template + SQLITE_ORM_INLINE_VAR constexpr bool always_false_v = false; + + template + using index_constant = std::integral_constant; + } + } + + namespace polyfill = internal::polyfill; +} + +namespace sqlite_orm { + // C++ generic traits used throughout the library + namespace internal { + template + using is_any_of = polyfill::disjunction...>; + + // enable_if for types + template class Op, class... Args> + using match_if = std::enable_if_t::value>; + + // enable_if for types + template class Op, class... Args> + using match_if_not = std::enable_if_t>>; + + // enable_if for types + template class Primary> + using match_specialization_of = std::enable_if_t>; + + // enable_if for functions + template class Op, class... Args> + using satisfies = std::enable_if_t::value, bool>; + + // enable_if for functions + template class Op, class... Args> + using satisfies_not = std::enable_if_t>::value, bool>; + + // enable_if for functions + template class Primary> + using satisfies_is_specialization_of = std::enable_if_t, bool>; + } + + // type name template aliases for syntactic sugar + namespace internal { + template + using type_t = typename T::type; + + template + using field_type_t = typename T::field_type; + + template + using constraints_type_t = typename T::constraints_type; + + template + using columns_tuple_t = typename T::columns_tuple; + + template + using object_type_t = typename T::object_type; + + template + using elements_type_t = typename T::elements_type; + + template + using target_type_t = typename T::target_type; + + template + using on_type_t = typename T::on_type; + } + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + template + concept orm_names_type = requires { typename T::type; }; +#endif +} #pragma once +#include #include // std::error_code, std::system_error #include // std::string -#include #include #include // std::ostringstream +#include - namespace sqlite_orm { +namespace sqlite_orm { + + /** @short Enables classifying sqlite error codes. + + @note We don't bother listing all possible values; + this also allows for compatibility with + 'Construction rules for enum class values (P0138R2)' + */ + enum class sqlite_errc {}; enum class orm_error_code { not_found = 1, @@ -50,7 +449,18 @@ __pragma(push_macro("min")) arguments_count_does_not_match, function_not_found, index_is_out_of_bounds, + value_is_null, + no_tables_specified, }; + +} + +namespace std { + template<> + struct is_error_code_enum<::sqlite_orm::sqlite_errc> : true_type {}; + + template<> + struct is_error_code_enum<::sqlite_orm::orm_error_code> : true_type {}; } namespace sqlite_orm { @@ -97,6 +507,10 @@ namespace sqlite_orm { return "Function not found"; case orm_error_code::index_is_out_of_bounds: return "Index is out of bounds"; + case orm_error_code::value_is_null: + return "Value is null"; + case orm_error_code::no_tables_specified: + return "No tables specified"; default: return "unknown error"; } @@ -124,320 +538,511 @@ namespace sqlite_orm { return res; } + inline std::error_code make_error_code(sqlite_errc ev) noexcept { + return {static_cast(ev), get_sqlite_error_category()}; + } + + inline std::error_code make_error_code(orm_error_code ev) noexcept { + return {static_cast(ev), get_orm_error_category()}; + } + template std::string get_error_message(sqlite3* db, T&&... args) { std::ostringstream stream; using unpack = int[]; - static_cast(unpack{0, (static_cast(static_cast(stream << args)), 0)...}); + (void)unpack{0, (stream << args, 0)...}; stream << sqlite3_errmsg(db); return stream.str(); } template [[noreturn]] void throw_error(sqlite3* db, T&&... args) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - get_error_message(db, std::forward(args)...)); + throw std::system_error{sqlite_errc(sqlite3_errcode(db)), get_error_message(db, std::forward(args)...)}; } -} -namespace std { - template<> - struct is_error_code_enum : std::true_type {}; + inline std::system_error sqlite_to_system_error(int ev) { + return {sqlite_errc(ev)}; + } + + inline std::system_error sqlite_to_system_error(sqlite3* db) { + return {sqlite_errc(sqlite3_errcode(db)), sqlite3_errmsg(db)}; + } + + [[noreturn]] inline void throw_translated_sqlite_error(int ev) { + throw sqlite_to_system_error(ev); + } + + [[noreturn]] inline void throw_translated_sqlite_error(sqlite3* db) { + throw sqlite_to_system_error(db); + } - inline std::error_code make_error_code(sqlite_orm::orm_error_code errorCode) { - return std::error_code(static_cast(errorCode), sqlite_orm::get_orm_error_category()); + [[noreturn]] inline void throw_translated_sqlite_error(sqlite3_stmt* stmt) { + throw sqlite_to_system_error(sqlite3_db_handle(stmt)); } } #pragma once -#include // std::tuple, std::get, std::tuple_element, std::tuple_size -#include // std::false_type, std::true_type +#include // std::string +#include // std::shared_ptr, std::unique_ptr +#include // std::vector +// #include "functional/cxx_optional.h" -// #include "static_magic.h" +// #include "cxx_core_features.h" -#include // std::false_type, std::true_type, std::integral_constant +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif -namespace sqlite_orm { +#if __cpp_lib_optional >= 201606L +#define SQLITE_ORM_OPTIONAL_SUPPORTED +#endif - // got from here - // https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co - namespace internal { +// #include "functional/cxx_type_traits_polyfill.h" - static inline decltype(auto) empty_callable() { - static auto res = [](auto&&...) {}; - return (res); - } +// #include "type_traits.h" - template - decltype(auto) static_if(std::true_type, const T& t, const F&) { - return (t); - } +// #include "is_std_ptr.h" - template - decltype(auto) static_if(std::false_type, const T&, const F& f) { - return (f); - } +#include +#include - template - decltype(auto) static_if(const T& t, const F& f) { - return static_if(std::integral_constant{}, t, f); - } +namespace sqlite_orm { - template - decltype(auto) static_if(const T& t) { - return static_if(std::integral_constant{}, t, empty_callable()); + /** + * Specialization for optional type (std::shared_ptr / std::unique_ptr). + */ + template + struct is_std_ptr : std::false_type {}; + + template + struct is_std_ptr> : std::true_type { + using element_type = typename std::shared_ptr::element_type; + + static std::shared_ptr make(std::remove_cv_t&& v) { + return std::make_shared(std::move(v)); } + }; - template - using static_not = std::integral_constant; - } + template + struct is_std_ptr> : std::true_type { + using element_type = typename std::unique_ptr::element_type; + static auto make(std::remove_cv_t&& v) { + return std::make_unique(std::move(v)); + } + }; } namespace sqlite_orm { - // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type - namespace tuple_helper { - /** - * HAS_TYPE type trait - */ - template - struct has_type; + /** + * This class transforms a C++ type to a sqlite type name (int -> INTEGER, ...) + */ + template + struct type_printer {}; - template - struct has_type> : std::false_type {}; + struct integer_printer { + const std::string& print() const { + static const std::string res = "INTEGER"; + return res; + } + }; - template - struct has_type> : has_type> {}; + struct text_printer { + const std::string& print() const { + static const std::string res = "TEXT"; + return res; + } + }; - template - struct has_type> : std::true_type {}; + struct real_printer { + const std::string& print() const { + static const std::string res = "REAL"; + return res; + } + }; - template - using tuple_contains_type = typename has_type::type; - - /** - * HAS_SOME_TYPE type trait - */ - template class TT, typename Tuple> - struct has_some_type; - - template class TT> - struct has_some_type> : std::false_type {}; + struct blob_printer { + const std::string& print() const { + static const std::string res = "BLOB"; + return res; + } + }; - template class TT, typename U, typename... Ts> - struct has_some_type> : has_some_type> {}; + // Note: char, unsigned/signed char are used for storing integer values, not char values. + template + struct type_printer>, + std::is_integral>>> : integer_printer { + }; - template class TT, typename T, typename... Ts> - struct has_some_type, Ts...>> : std::true_type {}; + template + struct type_printer::value>> : real_printer {}; - template class TT, typename Tuple> - using tuple_contains_some_type = typename has_some_type::type; + template + struct type_printer, + std::is_base_of, + std::is_base_of>>> : text_printer {}; - template - struct iterator_impl { + template + struct type_printer::value>> : type_printer {}; - template - void operator()(const std::tuple& tuple, const L& lambda, bool reverse = true) { - if(reverse) { - lambda(std::get(tuple)); - iterator_impl()(tuple, lambda, reverse); - } else { - iterator_impl()(tuple, lambda, reverse); - lambda(std::get(tuple)); - } - } +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct type_printer>> + : type_printer {}; +#endif - template - void operator()(const L& lambda) { - iterator_impl()(lambda); - lambda((const typename std::tuple_element>::type*)nullptr); - } - }; + template<> + struct type_printer, void> : blob_printer {}; +} +#pragma once - template - struct iterator_impl<0, Args...> { +namespace sqlite_orm { - template - void operator()(const std::tuple& tuple, const L& lambda, bool /*reverse*/ = true) { - lambda(std::get<0>(tuple)); - } + namespace internal { - template - void operator()(const L& lambda) { - lambda((const typename std::tuple_element<0, std::tuple>::type*)nullptr); - } + enum class collate_argument { + binary, + nocase, + rtrim, }; + } - template - struct iterator_impl { +} +#pragma once - template - void operator()(const std::tuple<>&, const L&, bool /*reverse*/ = true) { - //.. - } +#include // std::system_error +#include // std::ostream +#include // std::string +#include // std::tuple, std::make_tuple +#include // std::is_base_of, std::false_type, std::true_type - template - void operator()(const L&) { - //.. - } - }; +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "functional/mpl.h" + +/* + * Symbols for 'template metaprogramming' (compile-time template programming), + * inspired by the MPL of Aleksey Gurtovoy and David Abrahams. + * + * Currently, the focus is on facilitating advanced type filtering, + * such as filtering columns by constraints having various traits. + * Hence it contains only a very small subset of a full MPL. + * + * Two key concepts are critical to understanding: + * 1. A 'metafunction' is a class template that represents a function invocable at compile-time. + * 2. A 'metafunction class' is a certain form of metafunction representation that enables higher-order metaprogramming. + * More precisely, it's a class with a nested metafunction called "fn" + * Correspondingly, a metafunction class invocation is defined as invocation of its nested "fn" metafunction. + * 3. A 'metafunction operation' is an alias template that represents a function whose instantiation already yields a type. + * + * Conventions: + * - "Fn" is the name for a metafunction template template parameter. + * - "FnCls" is the name for a metafunction class template parameter. + * - "_fn" is a suffix for a type that accepts metafunctions and turns them into metafunction classes. + * - "higher order" denotes a metafunction that operates on another metafunction (i.e. takes it as an argument). + */ - template - struct iterator_impl2; +#include // std::false_type, std::true_type - template<> - struct iterator_impl2<> { +// #include "cxx_universal.h" - template - void operator()(const L&) const { - //.. - } - }; +// #include "cxx_type_traits_polyfill.h" - template - struct iterator_impl2 { +namespace sqlite_orm { + namespace internal { + namespace mpl { + template class Fn> + struct indirectly_test_metafunction; + + /* + * Determines whether a class template has a nested metafunction `fn`. + * + * Implementation note: the technique of specialiazing on the inline variable must come first because + * of older compilers having problems with the detection of dependent templates [SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE]. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_metafunction_class_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_metafunction_class_v>> = + true; - template - void operator()(const L& lambda) const { - lambda((const H*)nullptr); - iterator_impl2{}(lambda); - } - }; +#ifndef SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE + template + using is_metafunction_class = polyfill::bool_constant>; +#else + template + struct is_metafunction_class : polyfill::bool_constant> {}; +#endif - template - struct iterator; + /* + * Invoke metafunction. + */ + template class Fn, class... Args> + using invoke_fn_t = typename Fn::type; - template - struct iterator> { +#ifndef SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE + /* + * Invoke metafunction operation. + */ + template class Op, class... Args> + using invoke_op_t = Op; +#else + template class Op, class... Args> + struct wrap_op { + using type = Op; + }; - template - void operator()(const L& lambda) const { - iterator_impl2{}(lambda); - } - }; - } + /* + * Invoke metafunction operation. + * + * Note: legacy compilers need an extra layer of indirection, otherwise type replacement may fail + * if alias template `Op` has a dependent expression in it. + */ + template class Op, class... Args> + using invoke_op_t = typename wrap_op::type; +#endif - namespace internal { + /* + * Invoke metafunction class by invoking its nested metafunction. + */ + template + using invoke_t = typename FnCls::template fn::type; - // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer - template - auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(t)...); - } + /* + * Instantiate metafunction class' nested metafunction. + */ + template + using instantiate = typename FnCls::template fn; - template - auto call(Function& f, FunctionPointer functionPointer, Tuple t) { - static constexpr auto size = std::tuple_size::value; - return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); - } + /* + * Wrap given type such that `typename T::type` is valid. + */ + template + struct type_wrap : polyfill::type_identity {}; + template + struct type_wrap> : T {}; + + /* + * Turn metafunction into a metafunction class. + * + * Invocation of the nested metafunction `fn` is SFINAE-friendly (detection idiom). + * This is necessary because `fn` is a proxy to the originally quoted metafunction, + * and the instantiation of the metafunction might be an invalid expression. + */ + template class Fn> + struct quote_fn { + template class, class...> + struct invoke_fn; + + template class F, class... Args> + struct invoke_fn>, F, Args...> { + using type = type_wrap>; + }; - template - auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), move(t)); - } + template + using fn = typename invoke_fn::type; + }; - template - void move_tuple_impl(L& lhs, R& rhs) { - std::get(lhs) = std::move(std::get(rhs)); - internal::static_if{}>([](auto& l, auto& r) { - move_tuple_impl(l, r); - })(lhs, rhs); - } + /* + * Indirection wrapper for higher-order metafunctions, + * specialized on the argument indexes where metafunctions appear. + */ + template + struct higherorder; + + template<> + struct higherorder<0u> { + /* + * Turn higher-order metafunction into a metafunction class. + */ + template class Fn, class... Args2> class HigherFn> + struct quote_fn { + template + struct fn : HigherFn {}; + }; + }; - template - void move_tuple(L& lhs, R& rhs) { - using bool_type = std::integral_constant; - static_if([](auto& l, auto& r) { - move_tuple_impl(l, r); - })(lhs, rhs); - } + /* + * Metafunction class that extracts the nested metafunction of its metafunction class argument, + * quotes the extracted metafunction and passes it on to the next metafunction class + * (kind of the inverse of quoting). + */ + template + struct pass_extracted_fn_to { + template + struct fn : FnCls::template fn {}; + + // extract, quote, pass on + template class Fn, class... Args> + struct fn> : FnCls::template fn> {}; + }; - template - void iterate_tuple(const std::tuple& tuple, const L& lambda) { - using tuple_type = std::tuple; - tuple_helper::iterator_impl::value - 1, Args...>()(tuple, lambda, false); - } + /* + * Metafunction class that invokes the specified metafunction operation, + * and passes its result on to the next metafunction class. + */ + template class Op, class FnCls> + struct pass_result_to { + // call Op, pass on its result + template + struct fn : FnCls::template fn> {}; + }; - template - void iterate_tuple(const L& lambda) { - tuple_helper::iterator{}(lambda); - } + /* + * Bind arguments at the front of a metafunction class. + * Metafunction class equivalent to std::bind_front(). + */ + template + struct bind_front { + template + struct fn : FnCls::template fn {}; + }; - template - using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); + /* + * Bind arguments at the back of a metafunction class. + * Metafunction class equivalent to std::bind_back() + */ + template + struct bind_back { + template + struct fn : FnCls::template fn {}; + }; - template - struct conc_tuple { - using type = tuple_cat_t; - }; - } -} -#pragma once + /* + * Metafunction class equivalent to polyfill::always_false. + * It ignores arguments passed to the metafunction, + * and always returns the given type. + */ + template + struct always { + template + struct fn : type_wrap {}; + }; -#include // std::tuple -#include // std::enable_if + /* + * Unary metafunction class equivalent to std::type_identity. + */ + struct identity { + template + struct fn : type_wrap {}; + }; -namespace sqlite_orm { - namespace internal { + /* + * Metafunction class equivalent to std::negation. + */ + template + struct not_ { + template + struct fn : polyfill::negation> {}; + }; - template class C, class SFINAE = void> - struct find_in_tuple; + /* + * Metafunction class equivalent to std::conjunction + */ + template + struct conjunction { + template + struct fn : polyfill::conjunction...> {}; + }; - template class C> - struct find_in_tuple, C, void> { - using type = void; - }; + /* + * Metafunction class equivalent to std::disjunction. + */ + template + struct disjunction { + template + struct fn : polyfill::disjunction...> {}; + }; - template class C> - struct find_in_tuple, C, typename std::enable_if::value>::type> { - using type = H; - }; +#ifndef SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE + /* + * Metafunction equivalent to std::conjunction. + */ + template class... TraitFn> + using conjunction_fn = conjunction...>; - template class C> - struct find_in_tuple, C, typename std::enable_if::value>::type> { - using type = typename find_in_tuple, C>::type; - }; - } -} -#pragma once + /* + * Metafunction equivalent to std::disjunction. + */ + template class... TraitFn> + using disjunction_fn = disjunction...>; +#else + template class... TraitFn> + struct conjunction_fn : conjunction...> {}; -#include // std::tuple + template class... TraitFn> + struct disjunction_fn : disjunction...> {}; +#endif -namespace sqlite_orm { - namespace internal { + /* + * Convenience template alias for binding arguments at the front of a metafunction. + */ + template class Fn, class... Bound> + using bind_front_fn = bind_front, Bound...>; - template class F> - struct tuple_transformer; + /* + * Convenience template alias for binding arguments at the back of a metafunction. + */ + template class Fn, class... Bound> + using bind_back_fn = bind_back, Bound...>; - template class F> - struct tuple_transformer, F> { - using type = std::tuple::type...>; - }; + /* + * Convenience template alias for binding a metafunction at the front of a higher-order metafunction. + */ + template class Fn, class... Args2> class HigherFn, + template + class BoundFn, + class... Bound> + using bind_front_higherorder_fn = + bind_front::quote_fn, quote_fn, Bound...>; + } } -} -#pragma once -#include // std::tuple + namespace mpl = internal::mpl; -namespace sqlite_orm { + // convenience metafunction classes namespace internal { + /* + * Trait metafunction class that checks if a type has the specified trait. + */ + template class TraitFn> + using check_if = mpl::quote_fn; - template class C> - struct count_tuple; + /* + * Trait metafunction class that checks if a type doesn't have the specified trait. + */ + template class TraitFn> + using check_if_not = mpl::not_>; - template class C> - struct count_tuple, C> { - static constexpr const int value = 0; - }; + /* + * Trait metafunction class that checks if a type (possibly projected) is the same as the specified type. + */ + template class Proj = polyfill::type_identity_t> + using check_if_is_type = mpl::pass_result_to>; - template class C> - struct count_tuple, C> { - static constexpr const int value = C::value + count_tuple, C>::value; - }; + /* + * Trait metafunction class that checks if a type's template matches the specified template + * (similar to `is_specialization_of`). + */ + template class Template> + using check_if_is_template = + mpl::pass_extracted_fn_to>>; } } -#pragma once + +// #include "tuple_helper/same_or_void.h" namespace sqlite_orm { namespace internal { @@ -455,465 +1060,207 @@ namespace sqlite_orm { using type = A; }; - template - struct same_or_void { - using type = void; - }; - template struct same_or_void { using type = A; }; template - struct same_or_void { - using type = typename same_or_void::type; - }; + struct same_or_void : same_or_void {}; } } -#pragma once -#include // std::string -#include // std::shared_ptr, std::unique_ptr -#include // std::vector -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "tuple_helper/tuple_traits.h" -namespace sqlite_orm { +#include // std::is_same +#include - /** - * This class accepts c++ type and transfers it to sqlite name (int -> INTEGER, std::string -> TEXT) - */ - template - struct type_printer; +// #include "../functional/cxx_type_traits_polyfill.h" - struct integer_printer { - inline const std::string& print() { - static const std::string res = "INTEGER"; - return res; - } - }; +// #include "../functional/mpl.h" - struct text_printer { - inline const std::string& print() { - static const std::string res = "TEXT"; - return res; - } - }; +namespace sqlite_orm { + namespace internal { + /* + * Higher-order trait metafunction that checks whether a tuple contains a type with given trait. + */ + template class TraitFn, class Tuple> + struct tuple_has {}; + template class TraitFn, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; - struct real_printer { - inline const std::string& print() { - static const std::string res = "REAL"; - return res; - } - }; + /* + * Trait metafunction class that checks whether a tuple contains a type with given trait. + */ + template class TraitFn> + using check_if_tuple_has = mpl::bind_front_higherorder_fn; - struct blob_printer { - inline const std::string& print() { - static const std::string res = "BLOB"; - return res; - } - }; + /* + * Trait metafunction class that checks whether a tuple doesn't contain a type with given trait. + */ + template class TraitFn> + using check_if_tuple_has_not = mpl::not_>; - // Note unsigned/signed char and simple char used for storing integer values, not char values. - template<> - struct type_printer : public integer_printer {}; + /* + * Metafunction class that checks whether a tuple contains given type. + */ + template class Proj = polyfill::type_identity_t> + using check_if_tuple_has_type = + mpl::bind_front_higherorder_fn::template fn>; - template<> - struct type_printer : public integer_printer {}; + /* + * Metafunction class that checks whether a tuple contains a given template. + * + * Note: we are using 2 small tricks: + * 1. A template template parameter can be treated like a metafunction, so we can just "quote" a 'primary' + * template into the MPL system (e.g. `std::vector`). + * 2. This metafunction class does the opposite of the trait function `is_specialization`: + * `is_specialization` tries to instantiate the primary template template parameter using the + * template parameters of a template type, then compares both instantiated types. + * Here instead, `pass_extracted_fn_to` extracts the template template parameter from a template type, + * then compares the resulting template template parameters. + */ + template class Primary> + using check_if_tuple_has_template = + mpl::bind_front_higherorder_fn::template fn>; + } +} +// #include "tuple_helper/tuple_filter.h" - template<> - struct type_printer : public integer_printer {}; +#include // std::integral_constant, std::index_sequence, std::conditional, std::declval +#include // std::tuple - template<> - struct type_printer : public integer_printer {}; +// #include "../functional/cxx_universal.h" +// ::size_t +// #include "../functional/index_sequence_util.h" - template<> - struct type_printer : public integer_printer {}; +#include // std::index_sequence - template<> - struct type_printer : public integer_printer {}; +// #include "../functional/cxx_universal.h" - template<> - struct type_printer : public integer_printer {}; +namespace sqlite_orm { + namespace internal { + /** + * Get the first value of an index_sequence. + */ + template + SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { + return I; + } - template<> - struct type_printer : public integer_printer {}; + template + struct flatten_idxseq { + using type = std::index_sequence<>; + }; - template<> - struct type_printer : public integer_printer {}; + template + struct flatten_idxseq> { + using type = std::index_sequence; + }; - template<> - struct type_printer : public integer_printer {}; + template + struct flatten_idxseq, std::index_sequence, Seq...> + : flatten_idxseq, Seq...> {}; - template<> - struct type_printer : public integer_printer {}; + template + using flatten_idxseq_t = typename flatten_idxseq::type; + } +} - template<> - struct type_printer : public integer_printer {}; +namespace sqlite_orm { + namespace internal { - template<> - struct type_printer : public text_printer {}; + template + using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); - template<> - struct type_printer : public text_printer {}; + template + struct conc_tuple { + using type = tuple_cat_t; + }; - template<> - struct type_printer : public text_printer {}; + template + struct tuple_from_index_sequence; - template<> - struct type_printer : public real_printer {}; - - template<> - struct type_printer : public real_printer {}; - - template - struct type_printer, void> : public type_printer {}; - - template - struct type_printer, void> : public type_printer {}; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct type_printer, void> : public type_printer {}; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template<> - struct type_printer, void> : public blob_printer {}; -} -#pragma once - -namespace sqlite_orm { - - namespace internal { - - enum class collate_argument { - binary, - nocase, - rtrim, - }; - } - -} -#pragma once - -#include // std::string -#include // std::tuple, std::make_tuple -#include // std::stringstream -#include // std::is_base_of, std::false_type, std::true_type -#include // std::ostream - -// #include "table_type.h" - -#include // std::enable_if, std::is_member_pointer, std::is_member_function_pointer - -// #include "member_traits/getter_traits.h" - -// #include "getters.h" - -namespace sqlite_orm { - namespace internal { - - template - using getter_by_value_const = T (O::*)() const; - - template - using getter_by_value = T (O::*)(); - - template - using getter_by_ref_const = T& (O::*)() const; - - template - using getter_by_ref = T& (O::*)(); - - template - using getter_by_const_ref_const = const T& (O::*)() const; - - template - using getter_by_const_ref = const T& (O::*)(); -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - using getter_by_value_const_noexcept = T (O::*)() const noexcept; - - template - using getter_by_value_noexcept = T (O::*)() noexcept; - - template - using getter_by_ref_const_noexcept = T& (O::*)() const noexcept; - - template - using getter_by_ref_noexcept = T& (O::*)() noexcept; - - template - using getter_by_const_ref_const_noexcept = const T& (O::*)() const noexcept; - - template - using getter_by_const_ref_noexcept = const T& (O::*)() noexcept; -#endif - } -} - -namespace sqlite_orm { - namespace internal { - - template - struct getter_traits; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = false; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = false; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = false; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = false; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; - }; - - template - struct getter_traits> { - using object_type = O; - using field_type = T; - - static constexpr const bool returns_lvalue = true; + template + struct tuple_from_index_sequence> { + using type = std::tuple...>; }; -#endif - } -} - -// #include "member_traits/setter_traits.h" - -// #include "setters.h" - -namespace sqlite_orm { - namespace internal { - - template - using setter_by_value = void (O::*)(T); - - template - using setter_by_ref = void (O::*)(T&); - - template - using setter_by_const_ref = void (O::*)(const T&); -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - using setter_by_value_noexcept = void (O::*)(T) noexcept; - - template - using setter_by_ref_noexcept = void (O::*)(T&) noexcept; - - template - using setter_by_const_ref_noexcept = void (O::*)(const T&) noexcept; -#endif - } -} - -namespace sqlite_orm { - namespace internal { - - template - struct setter_traits; - template - struct setter_traits> { - using object_type = O; - using field_type = T; - }; + template + using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; - template - struct setter_traits> { - using object_type = O; - using field_type = T; - }; + template class Pred, template class Proj, class Seq> + struct filter_tuple_sequence; - template - struct setter_traits> { - using object_type = O; - using field_type = T; - }; -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - struct setter_traits> { - using object_type = O; - using field_type = T; +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : flatten_idxseq>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; +#else + template class Pred, class SFINAE = void> + struct tuple_seq_single { + using type = std::index_sequence<>; }; - template - struct setter_traits> { - using object_type = O; - using field_type = T; + template class Pred> + struct tuple_seq_single::value>> { + using type = std::index_sequence; }; - template - struct setter_traits> { - using object_type = O; - using field_type = T; - }; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : flatten_idxseq>, Pred>::type...> {}; #endif - } -} - -// #include "member_traits/is_getter.h" - -#include // std::false_type, std::true_type - -// #include "getters.h" - -namespace sqlite_orm { - namespace internal { - - template - struct is_getter : std::false_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - template - struct is_getter> : std::true_type {}; -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; + template + class Pred, + template class Proj = polyfill::type_identity_t, + class Seq = std::make_index_sequence::value>> + using filter_tuple_sequence_t = typename filter_tuple_sequence::type; + + template + class Pred, + template class FilterProj = polyfill::type_identity_t, + class Seq = std::make_index_sequence::value>> + using filter_tuple_t = tuple_from_index_sequence_t>; + + template + class Pred, + template class FilterProj = polyfill::type_identity_t> + struct count_tuple : std::integral_constant::size()> {}; - template - struct is_getter> : std::true_type {}; - - template - struct is_getter> : std::true_type {}; -#endif + /* + * Count a tuple, picking only those elements specified in the index sequence. + * + * Implementation note: must be distinct from `count_tuple` because legacy compilers have problems + * with a default Sequence in function template parameters [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION]. + */ + template + class Pred, + class Seq, + template class FilterProj = polyfill::type_identity_t> + struct count_filtered_tuple + : std::integral_constant::size()> {}; } } -// #include "member_traits/is_setter.h" - -// #include "setters.h" - -namespace sqlite_orm { - namespace internal { - - template - struct is_setter : std::false_type {}; - - template - struct is_setter> : std::true_type {}; +// #include "type_traits.h" - template - struct is_setter> : std::true_type {}; +// #include "collate_argument.h" - template - struct is_setter> : std::true_type {}; -#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED - template - struct is_setter> : std::true_type {}; +// #include "error_code.h" - template - struct is_setter> : std::true_type {}; +// #include "table_type_of.h" - template - struct is_setter> : std::true_type {}; -#endif - } -} +#include // std::declval +// #include "functional/cxx_type_traits_polyfill.h" namespace sqlite_orm { @@ -922,56 +1269,72 @@ namespace sqlite_orm { template struct column_pointer; + template + struct indexed_column_t; + /** * Trait class used to define table mapped type by setter/getter/member * T - member pointer * `type` is a type which is mapped. * E.g. - * - `table_type::type` is `User` - * - `table_type::type` is `User` - * - `table_type::type` is `User` + * - `table_type_of::type` is `User` + * - `table_type_of::type` is `User` + * - `table_type_of::type` is `User` */ - template - struct table_type; + template + struct table_type_of; template - struct table_type::value && - !std::is_member_function_pointer::value>::type> { + struct table_type_of { using type = O; }; - template - struct table_type::value>::type> { - using type = typename getter_traits::object_type; + template + struct table_type_of> { + using type = T; }; + template + struct table_type_of> : table_type_of {}; + template - struct table_type::value>::type> { - using type = typename setter_traits::object_type; - }; + using table_type_of_t = typename table_type_of::type; - template - struct table_type, void> { - using type = T; - }; + /* + * This trait can be used to check whether the object type of a member pointer or column pointer matches the target type. + * + * One use case is the ability to create column reference to an aliased table column of a derived object field without explicitly using a column pointer. + * E.g. + * regular: `alias_column>(column(&Base::field))` + * short: `alias_column>(&Base::field)` + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_field_of_v = false; + + /* + * `true` if a pointer-to-member operator is a valid expression for an object of type `T` and a member pointer of type `F O::*`. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_field_of_v().*std::declval())>> = true; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_field_of_v, T, void> = true; } } -// #include "tuple_helper/tuple_helper.h" +// #include "type_printer.h" namespace sqlite_orm { namespace internal { - /** - * AUTOINCREMENT constraint class. - */ - struct autoincrement_t { - - operator std::string() const { - return "AUTOINCREMENT"; - } + enum class conflict_clause_t { + rollback, + abort, + fail, + ignore, + replace, }; struct primary_key_base { @@ -980,48 +1343,88 @@ namespace sqlite_orm { ascending, descending, }; + struct { + order_by asc_option = order_by::unspecified; + conflict_clause_t conflict_clause = conflict_clause_t::rollback; + bool conflict_clause_is_on = false; + } options; + }; - order_by asc_option = order_by::unspecified; + template + struct primary_key_with_autoincrement : T { + using primary_key_type = T; - operator std::string() const { - std::string res = "PRIMARY KEY"; - switch(this->asc_option) { - case order_by::ascending: - res += " ASC"; - break; - case order_by::descending: - res += " DESC"; - break; - default: - break; - } - return res; + const primary_key_type& as_base() const { + return *this; } +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {} +#endif }; /** * PRIMARY KEY constraint class. * Cs is parameter pack which contains columns (member pointers and/or function pointers). Can be empty when - * used withen `make_column` function. + * used within `make_column` function. */ template struct primary_key_t : primary_key_base { + using self = primary_key_t; using order_by = primary_key_base::order_by; using columns_tuple = std::tuple; columns_tuple columns; - primary_key_t(decltype(columns) c) : columns(move(c)) {} + primary_key_t(columns_tuple columns) : columns(std::move(columns)) {} - primary_key_t asc() const { + self asc() const { auto res = *this; - res.asc_option = order_by::ascending; + res.options.asc_option = order_by::ascending; return res; } - primary_key_t desc() const { + self desc() const { auto res = *this; - res.asc_option = order_by::descending; + res.options.asc_option = order_by::descending; + return res; + } + + primary_key_with_autoincrement autoincrement() const { + return {*this}; + } + + self on_conflict_rollback() const { + auto res = *this; + res.options.conflict_clause_is_on = true; + res.options.conflict_clause = conflict_clause_t::rollback; + return res; + } + + self on_conflict_abort() const { + auto res = *this; + res.options.conflict_clause_is_on = true; + res.options.conflict_clause = conflict_clause_t::abort; + return res; + } + + self on_conflict_fail() const { + auto res = *this; + res.options.conflict_clause_is_on = true; + res.options.conflict_clause = conflict_clause_t::fail; + return res; + } + + self on_conflict_ignore() const { + auto res = *this; + res.options.conflict_clause_is_on = true; + res.options.conflict_clause = conflict_clause_t::ignore; + return res; + } + + self on_conflict_replace() const { + auto res = *this; + res.options.conflict_clause_is_on = true; + res.options.conflict_clause = conflict_clause_t::replace; return res; } }; @@ -1041,7 +1444,7 @@ namespace sqlite_orm { columns_tuple columns; - unique_t(columns_tuple columns_) : columns(move(columns_)) {} + unique_t(columns_tuple columns_) : columns(std::move(columns_)) {} }; /** @@ -1082,22 +1485,22 @@ namespace sqlite_orm { inline std::ostream& operator<<(std::ostream& os, foreign_key_action action) { switch(action) { - case decltype(action)::no_action: + case foreign_key_action::no_action: os << "NO ACTION"; break; - case decltype(action)::restrict_: + case foreign_key_action::restrict_: os << "RESTRICT"; break; - case decltype(action)::set_null: + case foreign_key_action::set_null: os << "SET NULL"; break; - case decltype(action)::set_default: + case foreign_key_action::set_default: os << "SET DEFAULT"; break; - case decltype(action)::cascade: + case foreign_key_action::cascade: os << "CASCADE"; break; - case decltype(action)::none: + case foreign_key_action::none: break; } return os; @@ -1180,10 +1583,15 @@ namespace sqlite_orm { } operator bool() const { - return this->_action != decltype(this->_action)::none; + return this->_action != foreign_key_action::none; } }; + template + bool operator==(const on_update_delete_t& lhs, const on_update_delete_t& rhs) { + return lhs._action == rhs._action; + } + template struct foreign_key_t, std::tuple> { using columns_type = std::tuple; @@ -1193,12 +1601,12 @@ namespace sqlite_orm { /** * Holds obect type of all referenced columns. */ - using target_type = typename same_or_void::type...>::type; + using target_type = typename same_or_void...>::type; /** * Holds obect type of all source columns. */ - using source_type = typename same_or_void::type...>::type; + using source_type = typename same_or_void...>::type; columns_type columns; references_type references; @@ -1225,16 +1633,14 @@ namespace sqlite_orm { this->on_delete = {*this, false, other.on_delete._action}; return *this; } - - template - void for_each_column(const L&) {} - - template - constexpr bool has_every() const { - return false; - } }; + template + bool operator==(const foreign_key_t& lhs, const foreign_key_t& rhs) { + return lhs.columns == rhs.columns && lhs.references == rhs.references && lhs.on_update == rhs.on_update && + lhs.on_delete == rhs.on_delete; + } + /** * Cs can be a class member pointer, a getter function member pointer or setter * func member pointer @@ -1246,8 +1652,6 @@ namespace sqlite_orm { tuple_type columns; - foreign_key_intermediate_t(tuple_type columns_) : columns(std::move(columns_)) {} - template foreign_key_t, std::tuple> references(Rs... refs) { return {std::move(this->columns), std::make_tuple(std::forward(refs)...)}; @@ -1256,81 +1660,143 @@ namespace sqlite_orm { #endif struct collate_constraint_t { - internal::collate_argument argument = internal::collate_argument::binary; - - collate_constraint_t(internal::collate_argument argument_) : argument(argument_) {} + collate_argument argument = collate_argument::binary; +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + collate_constraint_t(collate_argument argument) : argument{argument} {} +#endif operator std::string() const { - std::string res = "COLLATE " + this->string_from_collate_argument(this->argument); - return res; + return "COLLATE " + this->string_from_collate_argument(this->argument); } - static std::string string_from_collate_argument(internal::collate_argument argument) { + static std::string string_from_collate_argument(collate_argument argument) { switch(argument) { - case decltype(argument)::binary: + case collate_argument::binary: return "BINARY"; - case decltype(argument)::nocase: + case collate_argument::nocase: return "NOCASE"; - case decltype(argument)::rtrim: + case collate_argument::rtrim: return "RTRIM"; } - throw std::system_error(std::make_error_code(orm_error_code::invalid_collate_argument_enum)); + throw std::system_error{orm_error_code::invalid_collate_argument_enum}; } }; - struct check_string { - operator std::string() const { - return "CHECK"; - } + template + struct check_t { + using expression_type = T; + + expression_type expression; + }; + +#if SQLITE_VERSION_NUMBER >= 3031000 + struct basic_generated_always { + enum class storage_type { + not_specified, + virtual_, + stored, + }; + + bool full = true; + storage_type storage = storage_type::not_specified; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + basic_generated_always(bool full, storage_type storage) : full{full}, storage{storage} {} +#endif }; template - struct check_t : check_string { + struct generated_always_t : basic_generated_always { using expression_type = T; expression_type expression; - check_t(expression_type expression_) : expression(std::move(expression_)) {} + generated_always_t(expression_type expression_, bool full, storage_type storage) : + basic_generated_always{full, storage}, expression(std::move(expression_)) {} + + generated_always_t virtual_() { + return {std::move(this->expression), this->full, storage_type::virtual_}; + } + + generated_always_t stored() { + return {std::move(this->expression), this->full, storage_type::stored}; + } }; +#endif - template - struct is_constraint : std::false_type {}; + struct null_t {}; - template<> - struct is_constraint : std::true_type {}; + struct not_null_t {}; + } - template - struct is_constraint> : std::true_type {}; + namespace internal { - template - struct is_constraint> : std::true_type {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_foreign_key_v = +#if SQLITE_VERSION_NUMBER >= 3006019 + polyfill::is_specialization_of_v; +#else + false; +#endif + + template + using is_foreign_key = polyfill::bool_constant>; template - struct is_constraint> : std::true_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = std::is_base_of::value; - template - struct is_constraint> : std::true_type {}; + template + using is_primary_key = polyfill::bool_constant>; - template<> - struct is_constraint : std::true_type {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = +#if SQLITE_VERSION_NUMBER >= 3031000 + polyfill::is_specialization_of_v; +#else + false; +#endif template - struct is_constraint> : std::true_type {}; + using is_generated_always = polyfill::bool_constant>; - template - struct constraints_size; + /** + * PRIMARY KEY INSERTABLE traits. + */ + template + struct is_primary_key_insertable + : polyfill::disjunction< + mpl::instantiate, + check_if_tuple_has_template>, + constraints_type_t>, + std::is_base_of>>> { - template<> - struct constraints_size<> { - static constexpr const int value = 0; + static_assert(tuple_has>::value, "an unexpected type was passed"); }; - template - struct constraints_size { - static constexpr const int value = is_constraint::value + constraints_size::value; - }; + template + using is_constraint = mpl::instantiate, + check_if, + check_if_is_type, + check_if_is_type, + check_if_is_template, + check_if_is_template, + check_if_is_template, + check_if_is_type, + check_if>, + T>; + } + +#if SQLITE_VERSION_NUMBER >= 3031000 + template + internal::generated_always_t generated_always_as(T expression) { + return {std::move(expression), true, internal::basic_generated_always::storage_type::not_specified}; } + template + internal::generated_always_t as(T expression) { + return {std::move(expression), false, internal::basic_generated_always::storage_type::not_specified}; + } +#endif #if SQLITE_VERSION_NUMBER >= 3006019 /** @@ -1355,10 +1821,6 @@ namespace sqlite_orm { return {{}}; } - inline internal::autoincrement_t autoincrement() { - return {}; - } - template internal::primary_key_t primary_key(Cs... cs) { return {std::make_tuple(std::forward(cs)...)}; @@ -1390,58 +1852,21 @@ namespace sqlite_orm { return {std::move(t)}; } - namespace internal { - - /** - * FOREIGN KEY traits. Common case - */ - template - struct is_foreign_key : std::false_type {}; - - /** - * FOREIGN KEY traits. Specialized case - */ - template - struct is_foreign_key> : std::true_type {}; - - /** - * PRIMARY KEY traits. Common case - */ - template - struct is_primary_key : public std::false_type {}; - - /** - * PRIMARY KEY traits. Specialized case - */ - template - struct is_primary_key> : public std::true_type {}; - - /** - * PRIMARY KEY INSERTABLE traits. - */ - template - struct is_primary_key_insertable { - using field_type = typename T::field_type; - using constraints_type = typename T::constraints_type; - - static_assert((tuple_helper::tuple_contains_type, constraints_type>::value), - "an unexpected type was passed"); - - static constexpr bool value = - (tuple_helper::tuple_contains_some_type::value || - tuple_helper::tuple_contains_type::value || - std::is_base_of>::value); - }; + inline internal::null_t null() { + return {}; } + inline internal::not_null_t not_null() { + return {}; + } } #pragma once -#include // std::false_type, std::true_type +#include // std::false_type, std::true_type, std::enable_if #include // std::shared_ptr, std::unique_ptr -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_type_traits_polyfill.h" namespace sqlite_orm { @@ -1452,155 +1877,272 @@ namespace sqlite_orm { * custom type as `NULL` (for example: boost::optional) you have to create a specialiation * of type_is_nullable for your type and derive from `std::true_type`. */ - template - struct type_is_nullable : public std::false_type { + template + struct type_is_nullable : std::false_type { bool operator()(const T&) const { return true; } }; /** - * This is a specialization for std::shared_ptr. std::shared_ptr is nullable in sqlite_orm. + * This is a specialization for std::shared_ptr, std::unique_ptr, std::optional, which are nullable in sqlite_orm. */ template - struct type_is_nullable> : public std::true_type { - bool operator()(const std::shared_ptr& t) const { + struct type_is_nullable, +#endif + polyfill::is_specialization_of, + polyfill::is_specialization_of>>> : std::true_type { + bool operator()(const T& t) const { return static_cast(t); } }; +} +#pragma once - /** - * This is a specialization for std::unique_ptr. std::unique_ptr is nullable too. - */ - template - struct type_is_nullable> : public std::true_type { - bool operator()(const std::unique_ptr& t) const { - return static_cast(t); - } - }; +#include // std::false_type, std::true_type +#include // std::move -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * This is a specialization for std::optional. std::optional is nullable. - */ - template - struct type_is_nullable> : public std::true_type { - bool operator()(const std::optional& t) const { - return t.has_value(); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "tags.h" -} -#pragma once +// #include "functional/cxx_functional_polyfill.h" -#include // std::unique_ptr -#include // std::string -#include // std::stringstream +#include +#if __cpp_lib_invoke < 201411L +#include // std::enable_if, std::is_member_object_pointer, std::is_member_function_pointer +#endif +#include // std::forward -// #include "constraints.h" +#if __cpp_lib_invoke < 201411L +// #include "cxx_type_traits_polyfill.h" + +#endif +// #include "../member_traits/member_traits.h" -// #include "serializator_context.h" +#include // std::enable_if, std::is_function, std::true_type, std::false_type -namespace sqlite_orm { +// #include "../functional/cxx_universal.h" +// #include "../functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { namespace internal { + // SFINAE friendly trait to get a member object pointer's field type + template + struct object_field_type {}; - struct serializator_context_base { - bool replace_bindable_with_question = false; - bool skip_table_name = true; - bool use_parentheses = true; + template + using object_field_type_t = typename object_field_type::type; - template - const std::string* column_name(F O::*) const { - return nullptr; - } - }; + template + struct object_field_type : std::enable_if::value, F> {}; + + // SFINAE friendly trait to get a member function pointer's field type (i.e. unqualified return type) + template + struct getter_field_type {}; - template - struct serializator_context : serializator_context_base { - using impl_type = I; + template + using getter_field_type_t = typename getter_field_type::type; - const impl_type& impl; + template + struct getter_field_type : getter_field_type {}; - serializator_context(const impl_type& impl_) : impl(impl_) {} + template + struct getter_field_type : polyfill::remove_cvref {}; - template - const std::string* column_name(F O::*m) const { - return this->impl.column_name(m); - } - }; + template + struct getter_field_type : polyfill::remove_cvref {}; - template - struct serializator_context_builder { - using storage_type = S; - using impl_type = typename storage_type::impl_type; +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct getter_field_type : polyfill::remove_cvref {}; - serializator_context_builder(const storage_type& storage_) : storage(storage_) {} + template + struct getter_field_type : polyfill::remove_cvref {}; +#endif - serializator_context operator()() const { - return {this->storage.impl}; - } + // SFINAE friendly trait to get a member function pointer's field type (i.e. unqualified parameter type) + template + struct setter_field_type {}; - const storage_type& storage; - }; + template + using setter_field_type_t = typename setter_field_type::type; - } + template + struct setter_field_type : setter_field_type {}; + + template + struct setter_field_type : polyfill::remove_cvref {}; + +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct setter_field_type : polyfill::remove_cvref {}; +#endif + + template + struct is_getter : std::false_type {}; + template + struct is_getter>> : std::true_type {}; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_getter_v = is_getter::value; + + template + struct is_setter : std::false_type {}; + template + struct is_setter>> : std::true_type {}; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_setter_v = is_setter::value; + + template + struct member_field_type : object_field_type, getter_field_type, setter_field_type {}; + + template + using member_field_type_t = typename member_field_type::type; + + template + struct member_object_type {}; + + template + struct member_object_type : polyfill::type_identity {}; + template + using member_object_type_t = typename member_object_type::type; + } } namespace sqlite_orm { - namespace internal { + namespace polyfill { + // C++20 or later (unfortunately there's no feature test macro). + // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13 and libstd++-v3 10 + // (the latter is used on Linux). + // gcc got it right and reports C++20 only starting with v10. + // The check here doesn't care and checks the library versions in use. + // + // Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges +#if(__cplusplus >= 202002L) && \ + ((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13000) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10)) + using std::identity; +#else + struct identity { + template + constexpr T&& operator()(T&& v) const noexcept { + return std::forward(v); + } - /** - * This class is used in tuple interation to know whether tuple constains `default_value_t` - * constraint class and what it's value if it is - */ - struct default_value_extractor { + using is_transparent = int; + }; +#endif - template - std::unique_ptr operator()(const A&) { - return {}; +#if __cpp_lib_invoke >= 201411L + using std::invoke; +#else + // pointer-to-data-member+object + template, + std::enable_if_t::value, bool> = true> + decltype(auto) invoke(Callable&& callable, Object&& object, Args&&... args) { + return std::forward(object).*callable; } - template - std::unique_ptr operator()(const default_t& t) { - serializator_context_base context; - return std::make_unique(serialize(t.value, context)); + // pointer-to-member-function+object + template, + std::enable_if_t::value, bool> = true> + decltype(auto) invoke(Callable&& callable, Object&& object, Args&&... args) { + return (std::forward(object).*callable)(std::forward(args)...); } - }; + // pointer-to-member+reference-wrapped object (expect `reference_wrapper::*`) + template>, + std::reference_wrapper>>, + bool> = true> + decltype(auto) invoke(Callable&& callable, std::reference_wrapper wrapper, Args&&... args) { + return invoke(std::forward(callable), wrapper.get(), std::forward(args)...); + } + + // functor + template + decltype(auto) invoke(Callable&& callable, Args&&... args) { + return std::forward(callable)(std::forward(args)...); + } +#endif + } } + namespace polyfill = internal::polyfill; } -#pragma once - -#include // std::false_type, std::true_type -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::nullopt -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED -// #include "tags.h" namespace sqlite_orm { namespace internal { struct negatable_t {}; + /** + * Inherit from this class to support arithmetic types overloading + */ + struct arithmetic_t {}; + /** * Inherit from this class if target class can be chained with other conditions with '&&' and '||' operators */ struct condition_t {}; + + /** + * Specialize if a type participates as an argument to overloaded operators (arithmetic, conditional, negation, chaining) + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_operator_argument_v = false; + + template + using is_operator_argument = polyfill::bool_constant>; } } -namespace sqlite_orm { +// #include "serialize_result_type.h" + +// #include "functional/cxx_string_view.h" + +// #include "cxx_core_features.h" + +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif +#if __cpp_lib_string_view >= 201606L +#define SQLITE_ORM_STRING_VIEW_SUPPORTED +#endif + +#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // std::string +#endif + +namespace sqlite_orm { namespace internal { +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + using serialize_result_type = std::string_view; + using serialize_arg_type = std::string_view; +#else + using serialize_result_type = std::string; + using serialize_arg_type = const std::string&; +#endif + } +} - /** - * Inherit this class to support arithmetic types overloading - */ - struct arithmetic_t {}; +namespace sqlite_orm { + + namespace internal { template struct binary_operator : Ds... { @@ -1614,7 +2156,7 @@ namespace sqlite_orm { }; struct conc_string { - operator std::string() const { + serialize_result_type serialize() const { return "||"; } }; @@ -1626,7 +2168,7 @@ namespace sqlite_orm { using conc_t = binary_operator; struct add_string { - operator std::string() const { + serialize_result_type serialize() const { return "+"; } }; @@ -1638,7 +2180,7 @@ namespace sqlite_orm { using add_t = binary_operator; struct sub_string { - operator std::string() const { + serialize_result_type serialize() const { return "-"; } }; @@ -1650,7 +2192,7 @@ namespace sqlite_orm { using sub_t = binary_operator; struct mul_string { - operator std::string() const { + serialize_result_type serialize() const { return "*"; } }; @@ -1662,7 +2204,7 @@ namespace sqlite_orm { using mul_t = binary_operator; struct div_string { - operator std::string() const { + serialize_result_type serialize() const { return "/"; } }; @@ -1674,7 +2216,7 @@ namespace sqlite_orm { using div_t = binary_operator; struct mod_operator_string { - operator std::string() const { + serialize_result_type serialize() const { return "%"; } }; @@ -1686,7 +2228,7 @@ namespace sqlite_orm { using mod_t = binary_operator; struct bitwise_shift_left_string { - operator std::string() const { + serialize_result_type serialize() const { return "<<"; } }; @@ -1698,7 +2240,7 @@ namespace sqlite_orm { using bitwise_shift_left_t = binary_operator; struct bitwise_shift_right_string { - operator std::string() const { + serialize_result_type serialize() const { return ">>"; } }; @@ -1710,7 +2252,7 @@ namespace sqlite_orm { using bitwise_shift_right_t = binary_operator; struct bitwise_and_string { - operator std::string() const { + serialize_result_type serialize() const { return "&"; } }; @@ -1722,7 +2264,7 @@ namespace sqlite_orm { using bitwise_and_t = binary_operator; struct bitwise_or_string { - operator std::string() const { + serialize_result_type serialize() const { return "|"; } }; @@ -1734,7 +2276,7 @@ namespace sqlite_orm { using bitwise_or_t = binary_operator; struct bitwise_not_string { - operator std::string() const { + serialize_result_type serialize() const { return "~"; } }; @@ -1752,7 +2294,7 @@ namespace sqlite_orm { }; struct assign_string { - operator std::string() const { + serialize_result_type serialize() const { return "="; } }; @@ -1774,10 +2316,6 @@ namespace sqlite_orm { */ template struct is_assign_t> : public std::true_type {}; - - template - struct in_t; - } /** @@ -1867,350 +2405,209 @@ namespace sqlite_orm { #include // std::tuple #include // std::string #include // std::unique_ptr -#include // std::true_type, std::false_type, std::is_same, std::enable_if, std::is_member_pointer, std::is_member_function_pointer - -// #include "type_is_nullable.h" - -// #include "tuple_helper/tuple_helper.h" - -// #include "default_value_extractor.h" - -// #include "constraints.h" - -// #include "member_traits/member_traits.h" - -#include // std::enable_if - -// #include "is_field_member_pointer.h" - -#include // std::false_type, std::true_type, std::is_member_pointer, std::is_member_function_pointer - -namespace sqlite_orm { - namespace internal { - - template - struct is_field_member_pointer : std::false_type {}; - - template - struct is_field_member_pointer::value && - !std::is_member_function_pointer::value>::type> - : std::true_type {}; - } -} - -// #include "is_getter.h" - -// #include "field_member_traits.h" - -#include // std::enable_if - -// #include "is_field_member_pointer.h" - -namespace sqlite_orm { - namespace internal { - - template - struct field_member_traits; - - template - struct field_member_traits::value>::type> { - using object_type = O; - using field_type = F; - }; - } -} +#include // std::is_same, std::is_member_object_pointer +#include // std::move -// #include "is_setter.h" +// #include "../functional/cxx_universal.h" -// #include "getter_traits.h" +// #include "../functional/cxx_type_traits_polyfill.h" -// #include "setter_traits.h" +// #include "../tuple_helper/tuple_traits.h" -namespace sqlite_orm { - namespace internal { +// #include "../tuple_helper/tuple_filter.h" - template - struct member_traits; +// #include "../type_traits.h" - template - struct member_traits::value>::type> { - using object_type = typename field_member_traits::object_type; - using field_type = typename field_member_traits::field_type; - }; +// #include "../member_traits/member_traits.h" - template - struct member_traits::value>::type> { - using object_type = typename getter_traits::object_type; - using field_type = typename getter_traits::field_type; - }; +// #include "../type_is_nullable.h" - template - struct member_traits::value>::type> { - using object_type = typename setter_traits::object_type; - using field_type = typename setter_traits::field_type; - }; - } -} +// #include "../constraints.h" namespace sqlite_orm { namespace internal { - struct column_base { + struct column_identifier { /** - * Column name. Specified during construction in `make_column`. + * Column name. */ - const std::string name; + std::string name; }; - /** - * This class stores single column info. column_t is a pair of [column_name:member_pointer] mapped to a storage - * O is a mapped class, e.g. User - * T is a mapped class'es field type, e.g. &User::name - * Op... is a constraints pack, e.g. primary_key_t, autoincrement_t etc + struct empty_setter {}; + + /* + * Encapsulates object member pointers that are used as column fields, + * and whose object is mapped to storage. + * + * G is a member object pointer or member function pointer + * S is a member function pointer or `empty_setter` */ - template - struct column_t : column_base { - using object_type = O; - using field_type = T; - using constraints_type = std::tuple; - using member_pointer_t = field_type object_type::*; - using getter_type = G; + template + struct column_field { + using member_pointer_t = G; using setter_type = S; + using object_type = member_object_type_t; + using field_type = member_field_type_t; /** - * Member pointer used to read/write member + * Member pointer used to read a field value. + * If it is a object member pointer it is also used to write a field value. */ - member_pointer_t member_pointer /* = nullptr*/; + const member_pointer_t member_pointer; /** - * Getter member function pointer to get a value. If member_pointer is null than - * `getter` and `setter` must be not null + * Setter member function to write a field value */ - getter_type getter /* = nullptr*/; - - /** - * Setter member function - */ - setter_type setter /* = nullptr*/; - - /** - * Constraints tuple - */ - constraints_type constraints; - - column_t(std::string name_, - member_pointer_t member_pointer_, - getter_type getter_, - setter_type setter_, - constraints_type constraints_) : - column_base{std::move(name_)}, - member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(constraints_)) {} + SQLITE_ORM_NOUNIQUEADDRESS + const setter_type setter; /** * Simplified interface for `NOT NULL` constraint */ - bool not_null() const { + constexpr bool is_not_null() const { return !type_is_nullable::value; } + }; - template - constexpr bool has() const { - return tuple_helper::tuple_contains_type::value; - } + /* + * Encapsulates a tuple of column constraints. + * + * Op... is a constraints pack, e.g. primary_key_t, unique_t etc + */ + template + struct column_constraints { + using constraints_type = std::tuple; - template - constexpr bool has_every() const { - if(has() && has()) { - return true; - } else { - return has_every(); - } - } + SQLITE_ORM_NOUNIQUEADDRESS + constraints_type constraints; - template - constexpr bool has_every() const { - return has(); + /** + * Checks whether contraints contain specified type. + */ + template class Trait> + constexpr static bool is() { + return tuple_has::value; } /** * Simplified interface for `DEFAULT` constraint * @return string representation of default value if it exists otherwise nullptr */ - std::unique_ptr default_value() const { - std::unique_ptr res; - iterate_tuple(this->constraints, [&res](auto& v) { - auto dft = internal::default_value_extractor()(v); - if(dft) { - res = std::move(dft); - } - }); - return res; - } + std::unique_ptr default_value() const; }; - // we are compelled to wrap all sfinae-implemented traits to prevent "error: type/value mismatch at argument 2 in template parameter list" - namespace sfinae { - /** - * Column with insertable primary key traits. Common case. - */ - template - struct is_column_with_insertable_primary_key : public std::false_type {}; - - /** - * Column with insertable primary key traits. Specialized case case. - */ - template - struct is_column_with_insertable_primary_key< - column_t, - typename std::enable_if<(tuple_helper::tuple_contains_type< - primary_key_t<>, - typename column_t::constraints_type>::value)>::type> { - using column_type = column_t; - static constexpr bool value = is_primary_key_insertable::value; - }; - - /** - * Column with noninsertable primary key traits. Common case. - */ - template - struct is_column_with_noninsertable_primary_key : public std::false_type {}; - - /** - * Column with noninsertable primary key traits. Specialized case case. - */ - template - struct is_column_with_noninsertable_primary_key< - column_t, - typename std::enable_if<(tuple_helper::tuple_contains_type< - primary_key_t<>, - typename column_t::constraints_type>::value)>::type> { - using column_type = column_t; - static constexpr bool value = !is_primary_key_insertable::value; - }; - - } - - /** - * Column traits. Common case. - */ - template - struct is_column : public std::false_type {}; - - /** - * Column traits. Specialized case case. - */ - template - struct is_column> : public std::true_type {}; - /** - * Column with insertable primary key traits. + * Column definition. + * + * It is a composition of orthogonal information stored in different base classes. */ - template - struct is_column_with_insertable_primary_key : public sfinae::is_column_with_insertable_primary_key {}; + template + struct column_t : column_identifier, column_field, column_constraints { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + column_t(std::string name, G memberPointer, S setter, std::tuple op) : + column_identifier{std::move(name)}, column_field{memberPointer, setter}, + column_constraints{std::move(op)} {} +#endif + }; - /** - * Column with noninsertable primary key traits. - */ template - struct is_column_with_noninsertable_primary_key : public sfinae::is_column_with_noninsertable_primary_key {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_column_v = polyfill::is_specialization_of_v; template - struct column_field_type { - using type = void; - }; - - template - struct column_field_type> { - using type = typename column_t::field_type; - }; + using is_column = polyfill::bool_constant>; - template - struct column_constraints_type { - using type = std::tuple<>; - }; + template + using col_index_sequence_with_field_type = + filter_tuple_sequence_t::template fn, + field_type_t, + filter_tuple_sequence_t>; - template - struct column_constraints_type> { - using type = typename column_t::constraints_type; - }; + template class TraitFn> + using col_index_sequence_with = filter_tuple_sequence_t::template fn, + constraints_type_t, + filter_tuple_sequence_t>; + template class TraitFn> + using col_index_sequence_excluding = filter_tuple_sequence_t::template fn, + constraints_type_t, + filter_tuple_sequence_t>; } /** - * Column builder function. You should use it to create columns instead of constructor + * Factory function for a column definition from a member object pointer of the object to be mapped. */ - template::value>::type, - class... Op> - internal::column_t - make_column(const std::string& name, T O::*m, Op... constraints) { - static_assert(internal::template constraints_size::value == std::tuple_size>::value, - "Incorrect constraints pack"); - static_assert(internal::is_field_member_pointer::value, - "second argument expected as a member field pointer, not member function pointer"); - return {name, m, nullptr, nullptr, std::make_tuple(constraints...)}; + template = true> + internal::column_t + make_column(std::string name, M memberPointer, Op... constraints) { + static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + + // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, + // as this will lead to UB with Clang on MinGW! + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}); } /** - * Column builder function with setter and getter. You should use it to create columns instead of constructor + * Factory function for a column definition from "setter" and "getter" member function pointers of the object to be mapped. */ template::value>::type, - typename = typename std::enable_if::value>::type, - class... Op> - internal::column_t::object_type, - typename internal::setter_traits::field_type, - G, - S, - Op...> - make_column(const std::string& name, S setter, G getter, Op... constraints) { - static_assert(std::is_same::field_type, - typename internal::getter_traits::field_type>::value, + class... Op, + internal::satisfies = true, + internal::satisfies = true> + internal::column_t make_column(std::string name, S setter, G getter, Op... constraints) { + static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(internal::template constraints_size::value == std::tuple_size>::value, - "Incorrect constraints pack"); - return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; + static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + + // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, + // as this will lead to UB with Clang on MinGW! + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); } /** - * Column builder function with getter and setter (reverse order). You should use it to create columns instead of - * constructor + * Factory function for a column definition from "getter" and "setter" member function pointers of the object to be mapped. */ template::value>::type, - typename = typename std::enable_if::value>::type, - class... Op> - internal::column_t::object_type, - typename internal::setter_traits::field_type, - G, - S, - Op...> - make_column(const std::string& name, G getter, S setter, Op... constraints) { - static_assert(std::is_same::field_type, - typename internal::getter_traits::field_type>::value, + class... Op, + internal::satisfies = true, + internal::satisfies = true> + internal::column_t make_column(std::string name, G getter, S setter, Op... constraints) { + static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(internal::template constraints_size::value == std::tuple_size>::value, - "Incorrect constraints pack"); - return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; - } + static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, + // as this will lead to UB with Clang on MinGW! + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); + } } #pragma once +#include // std::wstring_convert #include // std::string #include // std::stringstream #include // std::vector -#include // std::nullptr_t #include // std::shared_ptr, std::unique_ptr -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +#ifndef SQLITE_ORM_OMITS_CODECVT +#include // std::codecvt_utf8_utf16 +#endif // SQLITE_ORM_OMITS_CODECVT +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "is_std_ptr.h" namespace sqlite_orm { @@ -2218,12 +2615,32 @@ namespace sqlite_orm { * Is used to print members mapped to objects in storage_t::dump member function. * Other developers can create own specialization to map custom types */ - template - struct field_printer { + template + struct field_printer; + + namespace internal { + template + SQLITE_ORM_INLINE_VAR constexpr bool is_printable_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_printable_v{})>> = true + // Also see implementation note for `is_bindable_v` + ; + +#ifndef SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE + template + using is_printable = polyfill::bool_constant>; +#else + template + struct is_printable : polyfill::bool_constant> {}; +#endif + } + + template + struct field_printer::value>> { std::string operator()(const T& t) const { - std::stringstream stream; - stream << t; - return stream.str(); + std::stringstream ss; + ss << t; + return ss.str(); } }; @@ -2233,9 +2650,9 @@ namespace sqlite_orm { template<> struct field_printer { std::string operator()(const unsigned char& t) const { - std::stringstream stream; - stream << +t; - return stream.str(); + std::stringstream ss; + ss << +t; + return ss.str(); } }; @@ -2245,28 +2662,28 @@ namespace sqlite_orm { template<> struct field_printer { std::string operator()(const signed char& t) const { - std::stringstream stream; - stream << +t; - return stream.str(); + std::stringstream ss; + ss << +t; + return ss.str(); } }; /** - * char is neigher signer char nor unsigned char so it has its own specialization + * char is neither signed char nor unsigned char so it has its own specialization */ template<> struct field_printer { std::string operator()(const char& t) const { - std::stringstream stream; - stream << +t; - return stream.str(); + std::stringstream ss; + ss << +t; + return ss.str(); } }; - template<> - struct field_printer { - std::string operator()(const std::string& t) const { - return t; + template + struct field_printer::value>> { + std::string operator()(std::string string) const { + return string; } }; @@ -2281,10 +2698,21 @@ namespace sqlite_orm { return ss.str(); } }; - +#ifndef SQLITE_ORM_OMITS_CODECVT + /** + * Specialization for std::wstring (UTF-16 assumed). + */ + template + struct field_printer::value>> { + std::string operator()(const std::wstring& wideString) const { + std::wstring_convert> converter; + return converter.to_bytes(wideString); + } + }; +#endif // SQLITE_ORM_OMITS_CODECVT template<> - struct field_printer { - std::string operator()(const std::nullptr_t&) const { + struct field_printer { + std::string operator()(const nullptr_t&) const { return "null"; } }; @@ -2297,35 +2725,34 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct field_printer, void> { - std::string operator()(const std::shared_ptr& t) const { - if(t) { - return field_printer()(*t); - } else { - return field_printer()(nullptr); - } - } - }; + struct field_printer< + T, + std::enable_if_t, + internal::is_printable>>>> { + using unqualified_type = std::remove_cv_t; - template - struct field_printer, void> { - std::string operator()(const std::unique_ptr& t) const { + std::string operator()(const T& t) const { if(t) { - return field_printer()(*t); + return field_printer()(*t); } else { - return field_printer()(nullptr); + return field_printer{}(nullptr); } } }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct field_printer, void> { - std::string operator()(const std::optional& t) const { + struct field_printer< + T, + std::enable_if_t, + internal::is_printable>>>> { + using unqualified_type = std::remove_cv_t; + + std::string operator()(const T& t) const { if(t.has_value()) { - return field_printer()(*t); + return field_printer()(*t); } else { - return field_printer()(nullptr); + return field_printer{}(std::nullopt); } } }; @@ -2334,11 +2761,57 @@ namespace sqlite_orm { #pragma once #include // std::string -#include // std::enable_if, std::is_same +#include // std::enable_if, std::is_same, std::remove_const #include // std::vector -#include // std::tuple, std::tuple_size +#include // std::tuple +#include // std::move, std::forward #include // std::stringstream +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "is_base_of_template.h" + +#include // std::true_type, std::false_type, std::declval + +namespace sqlite_orm { + + namespace internal { + + /* + * This is because of bug in MSVC, for more information, please visit + * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 + */ +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template class Base> + struct is_base_of_template_impl { + template + static constexpr std::true_type test(const Base&); + + static constexpr std::false_type test(...); + }; + + template class C> + using is_base_of_template = decltype(is_base_of_template_impl::test(std::declval())); +#else + template class C, typename... Ts> + std::true_type is_base_of_template_impl(const C&); + + template class C> + std::false_type is_base_of_template_impl(...); + + template class C> + using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); +#endif + + template class C> + SQLITE_ORM_INLINE_VAR constexpr bool is_base_of_template_v = is_base_of_template::value; + } +} + +// #include "type_traits.h" + // #include "collate_argument.h" // #include "constraints.h" @@ -2377,57 +2850,196 @@ namespace sqlite_orm { } } -// #include "tags.h" - -// #include "expression.h" -// #include "operators.h" +// #include "serializer_context.h" namespace sqlite_orm { namespace internal { - template - struct and_condition_t; + struct serializer_context_base { + bool replace_bindable_with_question = false; + bool skip_table_name = true; + bool use_parentheses = true; + bool skip_types_and_constraints = false; + }; - template - struct or_condition_t; + template + struct serializer_context : serializer_context_base { + using db_objects_type = DBOs; - /** - * Is not an operator but a result of c(...) function. Has operator= overloaded which returns assign_t - */ - template - struct expression_t : condition_t { - T value; + const db_objects_type& db_objects; - expression_t(T value_) : value(std::move(value_)) {} + serializer_context(const db_objects_type& dbObjects) : db_objects{dbObjects} {} + }; - template - assign_t operator=(R r) const { - return {this->value, std::move(r)}; - } + template + struct serializer_context_builder { + using storage_type = S; + using db_objects_type = typename storage_type::db_objects_type; - assign_t operator=(std::nullptr_t) const { - return {this->value, nullptr}; - } -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - assign_t operator=(std::nullopt_t) const { - return {this->value, std::nullopt}; - } -#endif - template - in_t in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), false}; - } + serializer_context_builder(const storage_type& storage_) : storage{storage_} {} - template - in_t not_in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), true}; + serializer_context operator()() const { + return {obtain_db_objects(this->storage)}; } - template - and_condition_t and_(R right) const { - return {this->value, std::move(right)}; - } + const storage_type& storage; + }; + } + +} + +// #include "tags.h" + +// #include "alias_traits.h" + +#include // std::remove_const, std::is_base_of, std::is_same +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES +#include +#endif + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "type_traits.h" + +namespace sqlite_orm { + + /** @short Base class for a custom table alias, column alias or expression alias. + */ + struct alias_tag {}; + + namespace internal { + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_alias_v = std::is_base_of::value; + + template + using is_alias = polyfill::bool_constant>; + + /** @short Alias of a column in a record set, see `orm_column_alias`. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = + polyfill::conjunction_v, polyfill::negation>>; + + template + using is_column_alias = is_alias; + + /** @short Alias of any type of record set, see `orm_recordset_alias`. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_recordset_alias_v = + polyfill::conjunction_v, polyfill::is_detected>; + + template + using is_recordset_alias = polyfill::bool_constant>; + + /** @short Alias of a concrete table, see `orm_table_alias`. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< + is_recordset_alias, + polyfill::negation, std::remove_const_t>>>; + + template + using is_table_alias = polyfill::bool_constant>; + } + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + concept orm_alias = std::derived_from; + + /** @short Alias of a column in a record set. + * + * A column alias has the following traits: + * - is derived from `alias_tag` + * - must not have a nested `type` typename + */ + template + concept orm_column_alias = (orm_alias && !orm_names_type); + + /** @short Alias of any type of record set. + * + * A record set alias has the following traits: + * - is derived from `alias_tag`. + * - has a nested `type` typename, which refers to a mapped object. + */ + template + concept orm_recordset_alias = (orm_alias && orm_names_type); + + /** @short Alias of a concrete table. + * + * A concrete table alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + */ + template + concept orm_table_alias = (orm_recordset_alias && !std::same_as>); +#endif +} + +// #include "expression.h" + +#include +#include // std::enable_if +#include // std::move, std::forward, std::declval +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "tags.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct in_t; + + template + struct and_condition_t; + + template + struct or_condition_t; + + /** + * Result of c(...) function. Has operator= overloaded which returns assign_t + */ + template + struct expression_t { + T value; + + template + assign_t operator=(R r) const { + return {this->value, std::move(r)}; + } + + assign_t operator=(nullptr_t) const { + return {this->value, nullptr}; + } +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + assign_t operator=(std::nullopt_t) const { + return {this->value, std::nullopt}; + } +#endif + template + in_t in(Args... args) const { + return {this->value, {std::forward(args)...}, false}; + } + + template + in_t not_in(Args... args) const { + return {this->value, {std::forward(args)...}, true}; + } + + template + and_condition_t and_(R right) const { + return {this->value, std::move(right)}; + } template or_condition_t or_(R right) const { @@ -2435,6 +3047,10 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_operator_argument_v>> = true; + template T get_from_expression(T value) { return std::move(value); @@ -2444,6 +3060,9 @@ namespace sqlite_orm { T get_from_expression(expression_t expression) { return std::move(expression.value); } + + template + using unwrap_expression_t = decltype(get_from_expression(std::declval())); } /** @@ -2456,6 +3075,72 @@ namespace sqlite_orm { } } +// #include "column_pointer.h" + +#include // std::enable_if +#include // std::move + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "tags.h" + +namespace sqlite_orm { + namespace internal { + /** + * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). + * Is useful when mapped type is derived from other type and base class has members mapped to a storage. + */ + template + struct column_pointer { + using type = T; + using field_type = F; + + field_type field; + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; + + template + using is_column_pointer = polyfill::bool_constant>; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_operator_argument_v>> = true; + } + + /** + * Use it like this: + * struct MyType : BaseType { ... }; + * storage.select(column(&BaseType::id)); + */ + template = true> + constexpr internal::column_pointer column(F field) { + return {std::move(field)}; + } +} + +// #include "tags.h" + +// #include "type_printer.h" + +// #include "literal.h" + +namespace sqlite_orm { + namespace internal { + + /* + * Protect an otherwise bindable element so that it is always serialized as a literal value. + */ + template + struct literal_holder { + using type = T; + + type value; + }; + + } +} + namespace sqlite_orm { namespace internal { @@ -2496,10 +3181,7 @@ namespace sqlite_orm { }; template - struct is_offset : std::false_type {}; - - template - struct is_offset> : std::true_type {}; + using is_offset = polyfill::is_specialization_of; /** * Collated something @@ -2571,6 +3253,12 @@ namespace sqlite_orm { binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_binary_condition_v = is_base_of_template_v; + + template + using is_binary_condition = polyfill::bool_constant>; + struct and_condition_string { operator std::string() const { return "AND"; @@ -2587,11 +3275,6 @@ namespace sqlite_orm { using super::super; }; - template - and_condition_t make_and_condition(L left, R right) { - return {std::move(left), std::move(right)}; - } - struct or_condition_string { operator std::string() const { return "OR"; @@ -2608,11 +3291,6 @@ namespace sqlite_orm { using super::super; }; - template - or_condition_t make_or_condition(L left, R right) { - return {std::move(left), std::move(right)}; - } - struct is_equal_string { operator std::string() const { return "="; @@ -2647,13 +3325,21 @@ namespace sqlite_orm { template named_collate collate() const { std::stringstream ss; - ss << C::name(); - auto name = ss.str(); - ss.flush(); - return {*this, std::move(name)}; + ss << C::name() << std::flush; + return {*this, ss.str()}; } }; + template + struct is_equal_with_table_t : negatable_t { + using left_type = L; + using right_type = R; + + right_type rhs; + + is_equal_with_table_t(right_type rhs) : rhs(std::move(rhs)) {} + }; + struct is_not_equal_string { operator std::string() const { return "!="; @@ -2738,7 +3424,7 @@ namespace sqlite_orm { } }; - struct lesser_than_string { + struct less_than_string { operator std::string() const { return "<"; } @@ -2748,10 +3434,10 @@ namespace sqlite_orm { * < operator object. */ template - struct lesser_than_t : binary_condition, negatable_t { - using self = lesser_than_t; + struct less_than_t : binary_condition, negatable_t { + using self = less_than_t; - using binary_condition::binary_condition; + using binary_condition::binary_condition; collate_t collate_binary() const { return {*this, collate_argument::binary}; @@ -2766,7 +3452,7 @@ namespace sqlite_orm { } }; - struct lesser_or_equal_string { + struct less_or_equal_string { operator std::string() const { return "<="; } @@ -2776,10 +3462,10 @@ namespace sqlite_orm { * <= operator object. */ template - struct lesser_or_equal_t : binary_condition, negatable_t { - using self = lesser_or_equal_t; + struct less_or_equal_t : binary_condition, negatable_t { + using self = less_or_equal_t; - using binary_condition::binary_condition; + using binary_condition::binary_condition; collate_t collate_binary() const { return {*this, collate_argument::binary}; @@ -2797,13 +3483,9 @@ namespace sqlite_orm { struct in_base { bool negative = false; // used in not_in - operator std::string() const { - if(!this->negative) { - return "IN"; - } else { - return "NOT IN"; - } - } +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + in_base(bool negative) : negative{negative} {} +#endif }; /** @@ -2869,10 +3551,12 @@ namespace sqlite_orm { int asc_desc = 0; // 1: asc, -1: desc std::string _collate_argument; +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED order_by_base() = default; order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) : - asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {} + asc_desc(asc_desc_), _collate_argument(std::move(_collate_argument_)) {} +#endif }; struct order_by_string { @@ -2893,13 +3577,13 @@ namespace sqlite_orm { order_by_t(expression_type expression_) : order_by_base(), expression(std::move(expression_)) {} - self asc() { + self asc() const { auto res = *this; res.asc_desc = 1; return res; } - self desc() { + self desc() const { auto res = *this; res.asc_desc = -1; return res; @@ -2907,22 +3591,19 @@ namespace sqlite_orm { self collate_binary() const { auto res = *this; - res._collate_argument = - collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::binary); + res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::binary); return res; } self collate_nocase() const { auto res = *this; - res._collate_argument = - collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::nocase); + res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::nocase); return res; } self collate_rtrim() const { auto res = *this; - res._collate_argument = - collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::rtrim); + res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::rtrim); return res; } @@ -2935,10 +3616,8 @@ namespace sqlite_orm { template self collate() const { std::stringstream ss; - ss << C::name(); - auto name = ss.str(); - ss.flush(); - return this->collate(move(name)); + ss << C::name() << std::flush; + return this->collate(ss.str()); } }; @@ -2951,18 +3630,18 @@ namespace sqlite_orm { args_type args; - multi_order_by_t(args_type&& args_) : args(std::move(args_)) {} + multi_order_by_t(args_type args_) : args{std::move(args_)} {} }; struct dynamic_order_by_entry_t : order_by_base { std::string name; dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : - order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} + order_by_base{asc_desc_, std::move(collate_argument_)}, name(std::move(name_)) {} }; /** - * C - serializator context class + * C - serializer context class */ template struct dynamic_order_by_t : order_by_string { @@ -2977,7 +3656,9 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + this->entries.emplace_back(std::move(columnName), + order_by.asc_desc, + std::move(order_by._collate_argument)); } const_iterator begin() const { @@ -2998,39 +3679,13 @@ namespace sqlite_orm { }; template - struct is_order_by : std::false_type {}; - - template - struct is_order_by> : std::true_type {}; - - template - struct is_order_by> : std::true_type {}; - - template - struct is_order_by> : std::true_type {}; - - struct group_by_string { - operator std::string() const { - return "GROUP BY"; - } - }; - - /** - * GROUP BY pack holder. - */ - template - struct group_by_t : group_by_string { - using args_type = std::tuple; - args_type args; - - group_by_t(args_type&& args_) : args(std::move(args_)) {} - }; + SQLITE_ORM_INLINE_VAR constexpr bool is_order_by_v = + polyfill::disjunction_v, + polyfill::is_specialization_of, + polyfill::is_specialization_of>; template - struct is_group_by : std::false_type {}; - - template - struct is_group_by> : std::true_type {}; + using is_order_by = polyfill::bool_constant>; struct between_string { operator std::string() const { @@ -3092,7 +3747,7 @@ namespace sqlite_orm { }; template - struct glob_t : condition_t, glob_string, internal::negatable_t { + struct glob_t : condition_t, glob_string, negatable_t { using self = glob_t; using arg_t = A; using pattern_t = T; @@ -3218,9 +3873,9 @@ namespace sqlite_orm { /** * USING argument holder. */ - template + template struct using_t { - F O::*column = nullptr; + column_pointer column; operator std::string() const { return "USING"; @@ -3248,47 +3903,6 @@ namespace sqlite_orm { inner_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} }; - struct exists_string { - operator std::string() const { - return "EXISTS"; - } - }; - - template - struct exists_t : condition_t, exists_string, internal::negatable_t { - using type = T; - using self = exists_t; - - type t; - - exists_t(T t_) : t(std::move(t_)) {} - }; - - struct having_string { - operator std::string() const { - return "HAVING"; - } - }; - - /** - * HAVING holder. - * T is having argument type. - */ - template - struct having_t : having_string { - using type = T; - - type t; - - having_t(type t_) : t(std::move(t_)) {} - }; - - template - struct is_having : std::false_type {}; - - template - struct is_having> : std::true_type {}; - struct cast_string { operator std::string() const { return "CAST"; @@ -3317,183 +3931,153 @@ namespace sqlite_orm { }; template - struct is_from : std::false_type {}; + using is_from = polyfill::is_specialization_of; - template - struct is_from> : std::true_type {}; + template + using is_constrained_join = polyfill::is_detected; } /** * Explicit FROM function. Usage: * `storage.select(&User::id, from());` */ - template - internal::from_t from() { - static_assert(std::tuple_size>::value > 0, ""); + template + internal::from_t from() { + static_assert(sizeof...(Tables) > 0, ""); return {}; } - template::value>::type> - internal::negated_condition_t operator!(T arg) { - return {std::move(arg)}; - } - +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** - * Cute operators for columns + * Explicit FROM function. Usage: + * `storage.select(&User::id, from<"a"_alias.for_>());` */ - template - internal::lesser_than_t operator<(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; + template + auto from() { + static_assert(sizeof...(tables) > 0); + return internal::from_t...>{}; } +#endif - template - internal::lesser_than_t operator<(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + // Intentionally place operators for types classified as arithmetic or general operator arguments in the internal namespace + // to facilitate ADL (Argument Dependent Lookup) + namespace internal { + template, is_operator_argument>, + bool> = true> + negated_condition_t operator!(T arg) { + return {std::move(arg)}; + } - template - internal::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + less_than_t, unwrap_expression_t> operator<(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + less_or_equal_t, unwrap_expression_t> operator<=(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::greater_than_t operator>(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + greater_than_t, unwrap_expression_t> operator>(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::greater_than_t operator>(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + greater_or_equal_t, unwrap_expression_t> operator>=(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::greater_or_equal_t operator>=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::greater_or_equal_t operator>=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::is_equal_t operator==(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::is_equal_t operator==(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::is_not_equal_t operator!=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::is_not_equal_t operator!=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::conc_t operator||(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::conc_t operator||(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } - - template - internal::add_t operator+(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::add_t operator+(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::add_t operator+(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } - - template - internal::sub_t operator-(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::sub_t operator-(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } - - template - internal::mul_t operator*(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::mul_t operator*(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } - - template - internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } - - template - internal::div_t operator/(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } - - template - internal::div_t operator/(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + is_equal_t, unwrap_expression_t> operator==(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::div_t operator/(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + is_not_equal_t, unwrap_expression_t> operator!=(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::mod_t operator%(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + and_condition_t, unwrap_expression_t> operator&&(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::mod_t operator%(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template< + class L, + class R, + std::enable_if_t, std::is_base_of>, + bool> = true> + or_condition_t, unwrap_expression_t> operator||(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template - internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + // exclude conditions + polyfill::negation, + std::is_base_of>>>, + bool> = true> + conc_t, unwrap_expression_t> operator||(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } } template - internal::using_t using_(F O::*p) { - return {std::move(p)}; + internal::using_t using_(F O::*p) { + return {p}; + } + template + internal::using_t using_(internal::column_pointer cp) { + return {std::move(cp)}; } template @@ -3516,21 +4100,49 @@ namespace sqlite_orm { return {std::move(o)}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + auto left_join(On on) { + return internal::left_join_t, On>{std::move(on)}; + } +#endif + template internal::join_t join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + auto join(On on) { + return internal::join_t, On>{std::move(on)}; + } +#endif + template internal::left_outer_join_t left_outer_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + auto left_outer_join(On on) { + return internal::left_outer_join_t, On>{std::move(on)}; + } +#endif + template internal::inner_join_t inner_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + auto inner_join(On on) { + return internal::inner_join_t, On>{std::move(on)}; + } +#endif + template internal::offset_t offset(T off) { return {std::move(off)}; @@ -3541,9 +4153,8 @@ namespace sqlite_orm { return {std::move(lim)}; } - template - typename std::enable_if::value, internal::limit_t>::type limit(O off, - T lim) { + template = true> + internal::limit_t limit(O off, T lim) { return {std::move(lim), {std::move(off)}}; } @@ -3552,34 +4163,18 @@ namespace sqlite_orm { return {std::move(lim), {std::move(offt.off)}}; } - template::value || - std::is_base_of::value>::type> - auto operator&&(L l, R r) { - using internal::get_from_expression; - return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); - } - template auto and_(L l, R r) { - using internal::get_from_expression; - return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); - } - - template::value || - std::is_base_of::value>::type> - auto operator||(L l, R r) { - using internal::get_from_expression; - return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + using namespace ::sqlite_orm::internal; + return and_condition_t, unwrap_expression_t>{get_from_expression(std::forward(l)), + get_from_expression(std::forward(r))}; } template auto or_(L l, R r) { - using internal::get_from_expression; - return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); + using namespace ::sqlite_orm::internal; + return or_condition_t, unwrap_expression_t>{get_from_expression(std::forward(l)), + get_from_expression(std::forward(r))}; } template @@ -3632,6 +4227,11 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } + template + internal::is_equal_with_table_t is_equal(R rhs) { + return {std::move(rhs)}; + } + template internal::is_not_equal_t is_not_equal(L l, R r) { return {std::move(l), std::move(r)}; @@ -3663,34 +4263,66 @@ namespace sqlite_orm { } template - internal::lesser_than_t lesser_than(L l, R r) { + internal::less_than_t less_than(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * [Deprecation notice] This function is deprecated and will be removed in v1.10. Use the accurately named function `less_than(...)` instead. + */ + template + [[deprecated("Use the accurately named function `less_than(...)` instead")]] internal::less_than_t + lesser_than(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::less_than_t lt(L l, R r) { return {std::move(l), std::move(r)}; } template - internal::lesser_than_t lt(L l, R r) { + internal::less_or_equal_t less_or_equal(L l, R r) { return {std::move(l), std::move(r)}; } + /** + * [Deprecation notice] This function is deprecated and will be removed in v1.10. Use the accurately named function `less_or_equal(...)` instead. + */ template - internal::lesser_or_equal_t lesser_or_equal(L l, R r) { + [[deprecated("Use the accurately named function `less_or_equal(...)` instead")]] internal::less_or_equal_t + lesser_or_equal(L l, R r) { return {std::move(l), std::move(r)}; } template - internal::lesser_or_equal_t le(L l, R r) { + internal::less_or_equal_t le(L l, R r) { return {std::move(l), std::move(r)}; } /** - * ORDER BY column - * Example: storage.select(&User::name, order_by(&User::id)) + * ORDER BY column, column alias or expression + * + * Examples: + * storage.select(&User::name, order_by(&User::id)) + * storage.select(as(&User::name), order_by(get())) */ - template + template> = true> internal::order_by_t order_by(O o) { return {std::move(o)}; } + /** + * ORDER BY positional ordinal + * + * Examples: + * storage.select(&User::name, order_by(1)) + */ + template> = true> + internal::order_by_t> order_by(O o) { + return {{std::move(o)}}; + } + /** * ORDER BY column1, column2 * Example: storage.get_all(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) @@ -3713,21 +4345,12 @@ namespace sqlite_orm { * } */ template - internal::dynamic_order_by_t> + internal::dynamic_order_by_t> dynamic_order_by(const S& storage) { - internal::serializator_context_builder builder(storage); + internal::serializer_context_builder builder(storage); return builder(); } - /** - * GROUP BY column. - * Example: storage.get_all(group_by(&Employee::name)) - */ - template - internal::group_by_t group_by(Args&&... args) { - return {std::make_tuple(std::forward(args)...)}; - } - /** * X BETWEEN Y AND Z * Example: storage.select(between(&User::id, 10, 20)) @@ -3764,28 +4387,6 @@ namespace sqlite_orm { return {std::move(a), std::move(t), {std::move(e)}}; } - /** - * EXISTS(condition). - * Example: storage.select(columns(&Agent::code, &Agent::name, &Agent::workingArea, &Agent::comission), - where(exists(select(asterisk(), - where(is_equal(&Customer::grade, 3) and - is_equal(&Agent::code, &Customer::agentCode))))), - order_by(&Agent::comission)); - */ - template - internal::exists_t exists(T t) { - return {std::move(t)}; - } - - /** - * HAVING(expression). - * Example: storage.get_all(group_by(&Employee::name), having(greater_than(count(&Employee::name), 2))); - */ - template - internal::having_t having(T t) { - return {std::move(t)}; - } - /** * CAST(X AS type). * Example: cast(&User::id) @@ -3797,30 +4398,65 @@ namespace sqlite_orm { } #pragma once -#include // std::enable_if, std::is_base_of, std::is_member_pointer -#include // std::stringstream +#include // std::enable_if, std::is_base_of, std::is_member_pointer, std::remove_const +#include // std::index_sequence, std::make_index_sequence #include // std::string +#include // std::stringstream +#include // std::copy_n -namespace sqlite_orm { +// #include "functional/cxx_universal.h" +// ::size_t +// #include "functional/cxx_type_traits_polyfill.h" - /** - * This is base class for every class which is used as a custom table alias. - * For more information please look through self_join.cpp example - */ - struct alias_tag {}; +// #include "type_traits.h" + +// #include "alias_traits.h" + +// #include "table_type_of.h" + +// #include "tags.h" + +namespace sqlite_orm { namespace internal { +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + /* + * Helper class to facilitate user-defined string literal operator template + */ + template + struct string_identifier_template { + static constexpr size_t size() { + return N - 1; + } + + constexpr string_identifier_template(const char (&id)[N]) { + std::copy_n(id, N, this->id); + } + + char id[N]; + }; + + template class Alias, string_identifier_template t, size_t... Idx> + consteval auto to_alias(std::index_sequence) { + return Alias{}; + } + + template + inline constexpr bool is_operator_argument_v>> = true; +#endif + /** - * This is a common built-in class used for custom single character table aliases. - * Also you can use language aliases `alias_a`, `alias_b` etc. instead + * This is a common built-in class used for character based table aliases. + * For convenience there exist public type aliases `alias_a`, `alias_b`, ... + * The easiest way to create a table alias is using `"z"_alias.for_()`. */ - template - struct table_alias : alias_tag { + template + struct recordset_alias : alias_tag { using type = T; - static char get() { - return A; + static std::string get() { + return {A, X...}; } }; @@ -3833,28 +4469,62 @@ namespace sqlite_orm { using column_type = C; column_type column; + }; - alias_column_t(){}; + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_operator_argument_v>> = true; - alias_column_t(column_type column_) : column(std::move(column_)) {} - }; + struct basic_table; + /* + * Encapsulates extracting the alias identifier of a non-alias. + * + * `extract()` always returns the empty string. + * `as_alias()` is used in contexts where a table might be aliased, and the empty string is returned. + * `as_qualifier()` is used in contexts where a table might be aliased, and the given table's name is returned. + */ template - struct alias_extractor; + struct alias_extractor { + static std::string extract() { + return {}; + } - template - struct alias_extractor::value>::type> { - static std::string get() { + static std::string as_alias() { + return {}; + } + + template + static const std::string& as_qualifier(const X& table) { + return table.name; + } + }; + + /* + * Encapsulates extracting the alias identifier of an alias. + * + * `extract()` always returns the alias identifier. + * `as_alias()` is used in contexts where a table is aliased, and the alias identifier is returned. + * `as_qualifier()` is used in contexts where a table is aliased, and the alias identifier is returned. + */ + template + struct alias_extractor> { + static std::string extract() { std::stringstream ss; - ss << T::get(); + ss << A::get(); return ss.str(); } - }; - template - struct alias_extractor::value>::type> { - static std::string get() { - return {}; + // for column and regular table aliases -> alias identifier + template, A> = true> + static std::string as_alias() { + return alias_extractor::extract(); + } + + // for regular table aliases -> alias identifier + template = true> + static std::string as_qualifier(const basic_table&) { + return alias_extractor::extract(); } }; @@ -3869,255 +4539,290 @@ namespace sqlite_orm { expression_type expression; }; + /** + * Built-in column alias. + * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... + * The easiest way to create a column alias is using `"xyz"_col`. + */ + template + struct column_alias : alias_tag { + static std::string get() { + return {A, X...}; + } + }; + template struct alias_holder { using type = T; + + alias_holder() = default; + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_operator_argument_v>> = true; + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + struct recordset_alias_builder { + template + [[nodiscard]] consteval recordset_alias for_() const { + return {}; + } }; +#endif + } + + /** + * Using a column pointer, create a column reference to an aliased table column. + * + * Example: + * using als = alias_u; + * select(alias_column(column(&User::id))) + */ + template, bool> = true> + constexpr auto alias_column(C field) { + using namespace ::sqlite_orm::internal; + using aliased_type = type_t; + static_assert(is_field_of_v, "Column must be from aliased table"); + + return alias_column_t{std::move(field)}; } /** - * @return column with table alias attached. Place it instead of a column statement in case you need to specify a - * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example + * Using an object member field, create a column reference to an aliased table column. + * + * @note The object member pointer can be from a derived class without explicitly forming a column pointer. + * + * Example: + * using als = alias_u; + * select(alias_column(&User::id)) */ - template - internal::alias_column_t alias_column(C c) { - static_assert(std::is_member_pointer::value, - "alias_column argument must be a member pointer mapped to a storage"); - return {c}; + template, bool> = true> + constexpr auto alias_column(F O::*field) { + using namespace ::sqlite_orm::internal; + using aliased_type = type_t; + static_assert(is_field_of_v, "Column must be from aliased table"); + + using C1 = + std::conditional_t::value, F O::*, column_pointer>; + return alias_column_t{{field}}; } - template - internal::as_t as(E expression) { +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + /** + * Create a column reference to an aliased table column. + * + * @note An object member pointer can be from a derived class without explicitly forming a column pointer. + * + * Example: + * constexpr auto als = "u"_alias.for_(); + * select(alias_column(&User::id)) + */ + template + constexpr auto alias_column(C field) { + using namespace ::sqlite_orm::internal; + using A = std::remove_const_t; + using aliased_type = type_t; + static_assert(is_field_of_v, "Column must be from aliased table"); + + if constexpr(is_column_pointer_v) { + return alias_column_t{std::move(field)}; + } else if constexpr(std::is_same_v, aliased_type>) { + return alias_column_t{field}; + } else { + // wrap in column_pointer + using C1 = column_pointer; + return alias_column_t{{field}}; + } + } + + /** + * Create a column reference to an aliased table column. + * + * @note An object member pointer can be from a derived class without explicitly forming a column pointer. + * + * Example: + * constexpr auto als = "u"_alias.for_(); + * select(als->*&User::id) + */ + template + constexpr auto operator->*(const A& /*tableAlias*/, F field) { + return alias_column(std::move(field)); + } +#endif + + /** + * Alias a column expression. + */ + template = true> + internal::as_t as(E expression) { return {std::move(expression)}; } - template - internal::alias_holder get() { +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + /** + * Alias a column expression. + */ + template + auto as(E expression) { + return internal::as_t, E>{std::move(expression)}; + } + + /** + * Alias a column expression. + */ + template + internal::as_t operator>>=(E expression, const A&) { + return {std::move(expression)}; + } +#endif + + template = true> + internal::alias_holder get() { return {}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + auto get() { + return internal::alias_holder>{}; + } +#endif + template - using alias_a = internal::table_alias; + using alias_a = internal::recordset_alias; template - using alias_b = internal::table_alias; + using alias_b = internal::recordset_alias; template - using alias_c = internal::table_alias; + using alias_c = internal::recordset_alias; template - using alias_d = internal::table_alias; + using alias_d = internal::recordset_alias; template - using alias_e = internal::table_alias; + using alias_e = internal::recordset_alias; template - using alias_f = internal::table_alias; + using alias_f = internal::recordset_alias; template - using alias_g = internal::table_alias; + using alias_g = internal::recordset_alias; template - using alias_h = internal::table_alias; + using alias_h = internal::recordset_alias; template - using alias_i = internal::table_alias; + using alias_i = internal::recordset_alias; template - using alias_j = internal::table_alias; + using alias_j = internal::recordset_alias; template - using alias_k = internal::table_alias; + using alias_k = internal::recordset_alias; template - using alias_l = internal::table_alias; + using alias_l = internal::recordset_alias; template - using alias_m = internal::table_alias; + using alias_m = internal::recordset_alias; template - using alias_n = internal::table_alias; + using alias_n = internal::recordset_alias; template - using alias_o = internal::table_alias; + using alias_o = internal::recordset_alias; template - using alias_p = internal::table_alias; + using alias_p = internal::recordset_alias; template - using alias_q = internal::table_alias; + using alias_q = internal::recordset_alias; template - using alias_r = internal::table_alias; + using alias_r = internal::recordset_alias; template - using alias_s = internal::table_alias; + using alias_s = internal::recordset_alias; template - using alias_t = internal::table_alias; + using alias_t = internal::recordset_alias; template - using alias_u = internal::table_alias; + using alias_u = internal::recordset_alias; template - using alias_v = internal::table_alias; + using alias_v = internal::recordset_alias; template - using alias_w = internal::table_alias; + using alias_w = internal::recordset_alias; template - using alias_x = internal::table_alias; + using alias_x = internal::recordset_alias; template - using alias_y = internal::table_alias; + using alias_y = internal::recordset_alias; template - using alias_z = internal::table_alias; + using alias_z = internal::recordset_alias; + + using colalias_a = internal::column_alias<'a'>; + using colalias_b = internal::column_alias<'b'>; + using colalias_c = internal::column_alias<'c'>; + using colalias_d = internal::column_alias<'d'>; + using colalias_e = internal::column_alias<'e'>; + using colalias_f = internal::column_alias<'f'>; + using colalias_g = internal::column_alias<'g'>; + using colalias_h = internal::column_alias<'h'>; + using colalias_i = internal::column_alias<'i'>; + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = alias<'z'>.for_(); + */ + template + inline constexpr internal::recordset_alias_builder alias{}; + + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = "z"_alias.for_(); + */ + template + [[nodiscard]] consteval auto operator"" _alias() { + return internal::to_alias(std::make_index_sequence{}); + } + + /** @short Create a column alias. + * column_alias<'a'[, ...]> from a string literal. + * E.g. "a"_col, "b"_col + */ + template + [[nodiscard]] consteval auto operator"" _col() { + return internal::to_alias(std::make_index_sequence{}); + } +#endif } #pragma once -// #include "conditions.h" +#include // std::string +#include // std::make_tuple, std::tuple_size +#include // std::forward, std::is_base_of, std::enable_if +#include // std::unique_ptr +#include // std::vector -namespace sqlite_orm { +// #include "functional/cxx_type_traits_polyfill.h" - namespace internal { +// #include "is_base_of_template.h" - template - struct join_iterator; +// #include "tuple_helper/tuple_filter.h" - template<> - struct join_iterator<> { +// #include "conditions.h" - template - void operator()(const L&) const { - //.. - } - }; +// #include "serialize_result_type.h" - template - struct join_iterator : public join_iterator { - using super = join_iterator; +// #include "operators.h" - template - void operator()(const L& l) const { - this->super::operator()(l); - } - }; +// #include "tags.h" - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = cross_join_t; +// #include "ast/into.h" - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; +// #include "../functional/cxx_type_traits_polyfill.h" - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = natural_join_t; +namespace sqlite_orm { + namespace internal { - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_outer_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = inner_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - } -} -#pragma once - -#include // std::string -#include // std::make_tuple, std::tuple_size -#include // std::forward, std::is_base_of, std::enable_if -#include // std::unique_ptr -#include // std::vector - -// #include "conditions.h" - -// #include "operators.h" - -// #include "is_base_of_template.h" - -#include // std::true_type, std::false_type, std::declval - -namespace sqlite_orm { - - namespace internal { - - /* - * This is because of bug in MSVC, for more information, please visit - * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 - */ -#if defined(_MSC_VER) - template class Base, typename Derived> - struct is_base_of_template_impl { - template - static constexpr std::true_type test(const Base*); - - static constexpr std::false_type test(...); - - using type = decltype(test(std::declval())); + template + struct into_t { + using type = T; }; - template class Base> - using is_base_of_template = typename is_base_of_template_impl::type; - -#else - template class C, typename... Ts> - std::true_type is_base_of_template_impl(const C*); - - template class C> - std::false_type is_base_of_template_impl(...); - - template class C> - using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); -#endif + template + using is_into = polyfill::is_specialization_of; } -} - -// #include "serialize_result_type.h" - -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED -#include // string_view -#else -#include // std::string -#endif -namespace sqlite_orm { - namespace internal { -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - using serialize_result_type = std::string_view; -#else - using serialize_result_type = std::string; -#endif + template + internal::into_t into() { + return {}; } } @@ -4128,9 +4833,6 @@ namespace sqlite_orm { namespace internal { - template - struct is_into; - template struct unique_ptr_result_of {}; @@ -4146,13 +4848,43 @@ namespace sqlite_orm { using string_type = S; using args_type = std::tuple; - static constexpr const size_t args_size = std::tuple_size::value; + static constexpr size_t args_size = std::tuple_size::value; args_type args; built_in_function_t(args_type&& args_) : args(std::move(args_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_built_in_function_v = is_base_of_template_v; + + template + using is_built_in_function = polyfill::bool_constant>; + + template + struct filtered_aggregate_function { + using function_type = F; + using where_expression = W; + + function_type function; + where_expression where; + }; + + template + struct where_t; + + template + struct built_in_aggregate_function_t : built_in_function_t { + using super = built_in_function_t; + + using super::super; + + template + filtered_aggregate_function, W> filter(where_t wh) { + return {*this, std::move(wh.expression)}; + } + }; + struct typeof_string { serialize_result_type serialize() const { return "TYPEOF"; @@ -4289,6 +5021,12 @@ namespace sqlite_orm { } }; + struct nullif_string { + serialize_result_type serialize() const { + return "NULLIF"; + } + }; + struct date_string { serialize_result_type serialize() const { return "DATE"; @@ -4363,6 +5101,11 @@ namespace sqlite_orm { template struct count_asterisk_t : count_string { using type = T; + + template + filtered_aggregate_function, W> filter(where_t wh) { + return {*this, std::move(wh.expression)}; + } }; /** @@ -4677,58 +5420,26 @@ namespace sqlite_orm { } }; #endif // SQLITE_ENABLE_JSON1 - } - - /** - * Cute operators for core functions - */ - template::value>::type> - internal::lesser_than_t operator<(F f, R r) { - return {std::move(f), std::move(r)}; - } - template::value>::type> - internal::lesser_or_equal_t operator<=(F f, R r) { - return {std::move(f), std::move(r)}; - } + template + using field_type_or_type_t = polyfill::detected_or_t>; - template::value>::type> - internal::greater_than_t operator>(F f, R r) { - return {std::move(f), std::move(r)}; - } + template + struct highlight_t { + using table_type = T; + using argument0_type = X; + using argument1_type = Y; + using argument2_type = Z; - template::value>::type> - internal::greater_or_equal_t operator>=(F f, R r) { - return {std::move(f), std::move(r)}; - } + argument0_type argument0; + argument1_type argument1; + argument2_type argument2; - template::value>::type> - internal::is_equal_t operator==(F f, R r) { - return {std::move(f), std::move(r)}; + highlight_t(argument0_type argument0, argument1_type argument1, argument2_type argument2) : + argument0(std::move(argument0)), argument1(std::move(argument1)), argument2(std::move(argument2)) {} + }; } - template::value>::type> - internal::is_not_equal_t operator!=(F f, R r) { - return {std::move(f), std::move(r)}; - } #ifdef SQLITE_ENABLE_MATH_FUNCTIONS /** @@ -5722,10 +6433,11 @@ namespace sqlite_orm { /** * REPLACE(X) function https://sqlite.org/lang_corefunc.html#replace */ - template - typename std::enable_if, internal::is_into>::value == 0, - internal::built_in_function_t>::type - replace(X x, Y y, Z z) { + template, internal::is_into>::value == 0, bool> = true> + internal::built_in_function_t replace(X x, Y y, Z z) { return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; } @@ -5767,18 +6479,68 @@ namespace sqlite_orm { /** * COALESCE(X,Y,...) function https://www.sqlite.org/lang_corefunc.html#coalesce */ - template - internal::built_in_function_t coalesce(Args... args) { + template + auto coalesce(Args... args) + -> internal::built_in_function_t::value, + std::common_type...>, + polyfill::type_identity>::type, + internal::coalesce_string, + Args...> { return {std::make_tuple(std::forward(args)...)}; } /** * IFNULL(X,Y) function https://www.sqlite.org/lang_corefunc.html#ifnull */ + template + auto ifnull(X x, Y y) -> internal::built_in_function_t< + typename std::conditional_t< // choose R or common type + std::is_void::value, + std::common_type, internal::field_type_or_type_t>, + polyfill::type_identity>::type, + internal::ifnull_string, + X, + Y> { + return {std::make_tuple(std::move(x), std::move(y))}; + } + + /** + * NULLIF(X,Y) function https://www.sqlite.org/lang_corefunc.html#nullif + */ +#if defined(SQLITE_ORM_OPTIONAL_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) + /** + * NULLIF(X,Y) using common return type of X and Y + */ + template>, + polyfill::is_detected, + internal::field_type_or_type_t>>, + bool> = true> + auto nullif(X x, Y y) { + if constexpr(std::is_void_v) { + using F = internal::built_in_function_t< + std::optional, internal::field_type_or_type_t>>, + internal::nullif_string, + X, + Y>; + + return F{std::make_tuple(std::move(x), std::move(y))}; + } else { + using F = internal::built_in_function_t; + + return F{std::make_tuple(std::move(x), std::move(y))}; + } + } +#else template - internal::built_in_function_t ifnull(X x, Y y) { + internal::built_in_function_t nullif(X x, Y y) { return {std::make_tuple(std::move(x), std::move(y))}; } +#endif /** * DATE(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html @@ -5849,7 +6611,7 @@ namespace sqlite_orm { * SOUNDEX(X) function https://www.sqlite.org/lang_corefunc.html#soundex */ template - internal::core_function_t soundex(X x) { + internal::built_in_function_t soundex(X x) { return {std::tuple{std::forward(x)}}; } #endif @@ -5858,7 +6620,7 @@ namespace sqlite_orm { * TOTAL(X) aggregate function. */ template - internal::built_in_function_t total(X x) { + internal::built_in_aggregate_function_t total(X x) { return {std::tuple{std::forward(x)}}; } @@ -5866,7 +6628,7 @@ namespace sqlite_orm { * SUM(X) aggregate function. */ template - internal::built_in_function_t, internal::sum_string, X> sum(X x) { + internal::built_in_aggregate_function_t, internal::sum_string, X> sum(X x) { return {std::tuple{std::forward(x)}}; } @@ -5874,7 +6636,7 @@ namespace sqlite_orm { * COUNT(X) aggregate function. */ template - internal::built_in_function_t count(X x) { + internal::built_in_aggregate_function_t count(X x) { return {std::tuple{std::forward(x)}}; } @@ -5898,7 +6660,7 @@ namespace sqlite_orm { * AVG(X) aggregate function. */ template - internal::built_in_function_t avg(X x) { + internal::built_in_aggregate_function_t avg(X x) { return {std::tuple{std::forward(x)}}; } @@ -5906,7 +6668,7 @@ namespace sqlite_orm { * MAX(X) aggregate function. */ template - internal::built_in_function_t, internal::max_string, X> max(X x) { + internal::built_in_aggregate_function_t, internal::max_string, X> max(X x) { return {std::tuple{std::forward(x)}}; } @@ -5914,15 +6676,35 @@ namespace sqlite_orm { * MIN(X) aggregate function. */ template - internal::built_in_function_t, internal::min_string, X> min(X x) { + internal::built_in_aggregate_function_t, internal::min_string, X> min(X x) { return {std::tuple{std::forward(x)}}; } + /** + * MAX(X, Y, ...) scalar function. + * The return type is the type of the first argument. + */ + template + internal::built_in_function_t, internal::max_string, X, Y, Rest...> + max(X x, Y y, Rest... rest) { + return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + } + + /** + * MIN(X, Y, ...) scalar function. + * The return type is the type of the first argument. + */ + template + internal::built_in_function_t, internal::min_string, X, Y, Rest...> + min(X x, Y y, Rest... rest) { + return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + } + /** * GROUP_CONCAT(X) aggregate function. */ template - internal::built_in_function_t group_concat(X x) { + internal::built_in_aggregate_function_t group_concat(X x) { return {std::tuple{std::forward(x)}}; } @@ -5930,7 +6712,7 @@ namespace sqlite_orm { * GROUP_CONCAT(X, Y) aggregate function. */ template - internal::built_in_function_t group_concat(X x, Y y) { + internal::built_in_aggregate_function_t group_concat(X x, Y y) { return {std::tuple{std::forward(x), std::forward(y)}}; } #ifdef SQLITE_ENABLE_JSON1 @@ -6054,51 +6836,70 @@ namespace sqlite_orm { internal::built_in_function_t json_group_object(X x, Y y) { return {std::tuple{std::forward(x), std::forward(y)}}; } - #endif // SQLITE_ENABLE_JSON1 - template::value + - std::is_base_of::value > - 0)>::type> - internal::add_t operator+(L l, R r) { - return {std::move(l), std::move(r)}; - } - template::value + - std::is_base_of::value > - 0)>::type> - internal::sub_t operator-(L l, R r) { - return {std::move(l), std::move(r)}; - } + // Intentionally place operators for types classified as arithmetic or general operator arguments in the internal namespace + // to facilitate ADL (Argument Dependent Lookup) + namespace internal { + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + add_t, unwrap_expression_t> operator+(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template::value + - std::is_base_of::value > - 0)>::type> - internal::mul_t operator*(L l, R r) { - return {std::move(l), std::move(r)}; - } + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + sub_t, unwrap_expression_t> operator-(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } - template::value + - std::is_base_of::value > - 0)>::type> - internal::div_t operator/(L l, R r) { - return {std::move(l), std::move(r)}; + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + mul_t, unwrap_expression_t> operator*(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } + + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + div_t, unwrap_expression_t> operator/(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } + + template, + std::is_base_of, + is_operator_argument, + is_operator_argument>, + bool> = true> + mod_t, unwrap_expression_t> operator%(L l, R r) { + return {get_from_expression(std::forward(l)), get_from_expression(std::forward(r))}; + } } - template::value + - std::is_base_of::value > - 0)>::type> - internal::mod_t operator%(L l, R r) { - return {std::move(l), std::move(r)}; + template + internal::highlight_t highlight(X x, Y y, Z z) { + return {std::move(x), std::move(y), std::move(z)}; } } #pragma once @@ -6107,63 +6908,44 @@ namespace sqlite_orm { namespace internal { - /** - * Cute class used to compare setters/getters and member pointers with each other. - */ template - struct typed_comparator { - bool operator()(const L&, const R&) const { - return false; - } - }; - + bool compare_any(const L& /*lhs*/, const R& /*rhs*/) { + return false; + } template - struct typed_comparator { - bool operator()(const O& lhs, const O& rhs) const { - return lhs == rhs; - } - }; - - template - bool compare_any(const L& lhs, const R& rhs) { - return typed_comparator()(lhs, rhs); + bool compare_any(const O& lhs, const O& rhs) { + return lhs == rhs; } } } #pragma once +#include // std::remove_const #include // std::string -#include // std::declval +#include // std::move #include // std::tuple, std::get, std::tuple_size -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" // #include "is_base_of_template.h" -// #include "tuple_helper/tuple_helper.h" +// #include "tuple_helper/tuple_filter.h" // #include "optional_container.h" // #include "ast/where.h" -// #include "../serialize_result_type.h" +#include // std::false_type, std::true_type +#include // std::move -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED -#include // string_view -#else -#include // std::string -#endif +// #include "../functional/cxx_universal.h" -namespace sqlite_orm { - namespace internal { -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - using serialize_result_type = std::string_view; -#else - using serialize_result_type = std::string; -#endif - } -} +// #include "../functional/cxx_type_traits_polyfill.h" + +// #include "../serialize_result_type.h" namespace sqlite_orm { namespace internal { @@ -6189,10 +6971,10 @@ namespace sqlite_orm { }; template - struct is_where : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_where_v = polyfill::is_specialization_of_v; template - struct is_where> : std::true_type {}; + using is_where = polyfill::bool_constant>; } /** @@ -6210,6 +6992,60 @@ namespace sqlite_orm { } } +// #include "ast/group_by.h" + +#include // std::tuple, std::make_tuple +#include // std::true_type, std::false_type +#include // std::forward, std::move + +// #include "../functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + namespace internal { + + template + struct group_by_with_having { + using args_type = std::tuple; + using expression_type = T; + + args_type args; + expression_type expression; + }; + + /** + * GROUP BY pack holder. + */ + template + struct group_by_t { + using args_type = std::tuple; + + args_type args; + + template + group_by_with_having having(T expression) { + return {std::move(this->args), std::move(expression)}; + } + }; + + template + using is_group_by = polyfill::disjunction, + polyfill::is_specialization_of>; + } + + /** + * GROUP BY column. + * Example: storage.get_all(group_by(&Employee::name)) + */ + template + internal::group_by_t group_by(Args&&... args) { + return {std::make_tuple(std::forward(args)...)}; + } +} + +// #include "core_functions.h" + +// #include "alias_traits.h" + namespace sqlite_orm { namespace internal { @@ -6263,75 +7099,21 @@ namespace sqlite_orm { columns_type columns; bool distinct = false; - static constexpr const int count = std::tuple_size::value; - }; - - template - struct is_columns : std::false_type {}; - - template - struct is_columns> : std::true_type {}; + static constexpr int count = std::tuple_size::value; - struct set_string { - operator std::string() const { - return "SET"; - } +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + columns_t(columns_type columns) : columns{std::move(columns)} {} +#endif }; - template - struct set_t : set_string { - using assigns_type = std::tuple; - - assigns_type assigns; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_columns_v = polyfill::is_specialization_of_v; - set_t(assigns_type assigns_) : assigns(move(assigns_)) {} - }; + template + using is_columns = polyfill::bool_constant>; /** - * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). - * Is useful when mapped type is derived from other type and base class has members mapped to a storage. - */ - template - struct column_pointer { - using self = column_pointer; - using type = T; - using field_type = F; - - field_type field; - - template - internal::is_equal_t operator==(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::is_not_equal_t operator!=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_than_t operator<(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_or_equal_t operator<=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_than_t operator>(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_or_equal_t operator>=(R rhs) const { - return {*this, std::move(rhs)}; - } - }; - - /** - * Subselect object type. + * Subselect object type. */ template struct select_t { @@ -6341,13 +7123,18 @@ namespace sqlite_orm { return_type col; conditions_type conditions; bool highest_level = false; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + select_t(return_type col, conditions_type conditions) : + col{std::move(col)}, conditions{std::move(conditions)} {} +#endif }; template - struct is_select : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_select_v = polyfill::is_specialization_of_v; - template - struct is_select> : std::true_type {}; + template + using is_select = polyfill::bool_constant>; /** * Base for UNION, UNION ALL, EXCEPT and INTERSECT @@ -6366,9 +7153,19 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_compound_operator_v = is_base_of_template_v; + + template + using is_compound_operator = polyfill::bool_constant>; + struct union_base { bool all = false; +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + union_base(bool all) : all{all} {} +#endif + operator std::string() const { if(!this->all) { return "UNION"; @@ -6386,10 +7183,10 @@ namespace sqlite_orm { using left_type = typename compound_operator::left_type; using right_type = typename compound_operator::right_type; - union_t(left_type l, right_type r, decltype(all) all_) : - compound_operator(std::move(l), std::move(r)), union_base{all_} {} + union_t(left_type l, right_type r, bool all_) : + compound_operator{std::move(l), std::move(r)}, union_base{all_} {} - union_t(left_type l, right_type r) : union_t(std::move(l), std::move(r), false) {} + union_t(left_type l, right_type r) : union_t{std::move(l), std::move(r), false} {} }; struct except_string { @@ -6443,11 +7240,23 @@ namespace sqlite_orm { template struct asterisk_t { using type = T; + + bool defined_order = false; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + asterisk_t(bool definedOrder) : defined_order{definedOrder} {} +#endif }; template struct object_t { using type = T; + + bool defined_order = false; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + object_t(bool definedOrder) : defined_order{definedOrder} {} +#endif }; template @@ -6489,8 +7298,7 @@ namespace sqlite_orm { simple_case_builder> when(W w, then_t t) { using result_args_type = std::tuple>; std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = - std::tuple_cat(std::move(this->args), std::move(std::make_tuple(newPair))); + result_args_type result_args = std::tuple_cat(std::move(this->args), std::make_tuple(newPair)); std::get::value - 1>(result_args) = std::move(newPair); return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; } @@ -6552,34 +7360,11 @@ namespace sqlite_orm { return cols; } - /** - * SET keyword used in UPDATE ... SET queries. - * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) - */ - template - internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, - "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; - } - template internal::columns_t columns(Args... args) { return {std::make_tuple(std::forward(args)...)}; } - /** - * Use it like this: - * struct MyType : BaseType { ... }; - * storage.select(column(&BaseType::id)); - */ - template - internal::column_pointer column(F f) { - return {std::move(f)}; - } - /** * Public function for subselect query. Is useful in UNION queries. */ @@ -6626,33 +7411,64 @@ namespace sqlite_orm { } /** - * SELECT * FROM T function. - * T is typed mapped to a storage. - * Example: auto rows = storage.select(asterisk()); - * // decltype(rows) is std::vector> - * If you need to fetch result as objects not tuple please use `object` instead. + * `SELECT * FROM T` expression that fetches results as tuples. + * T is a type mapped to a storage, or an alias of it. + * The `definedOrder` parameter denotes the expected order of result columns. + * The default is the implicit order as returned by SQLite, which may differ from the defined order + * if the schema of a table has been changed. + * By specifying the defined order, the columns are written out in the resulting select SQL string. + * + * In pseudo code: + * select(asterisk(false)) -> SELECT * from User + * select(asterisk(true)) -> SELECT id, name from User + * + * Example: auto rows = storage.select(asterisk()); + * // decltype(rows) is std::vector> + * Example: auto rows = storage.select(asterisk(true)); + * // decltype(rows) is std::vector> + * + * If you need to fetch results as objects instead of tuples please use `object()`. */ template - internal::asterisk_t asterisk() { - return {}; + internal::asterisk_t asterisk(bool definedOrder = false) { + return {definedOrder}; + } + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + /** + * Example: + * constexpr auto m = "m"_alias.for_(); + * auto reportingTo = + * storage.select(asterisk(), inner_join(on(m->*&Employee::reportsTo == &Employee::employeeId))); + */ + template + auto asterisk(bool definedOrder = false) { + return internal::asterisk_t>{definedOrder}; } +#endif /** - * SELECT * FROM T function. - * T is typed mapped to a storage. - * Example: auto rows = storage.select(object()); - * // decltype(rows) is std::vector - * If you need to fetch result as tuples not objects please use `asterisk` instead. + * `SELECT * FROM T` expression that fetches results as objects of type T. + * T is a type mapped to a storage, or an alias of it. + * + * Example: auto rows = storage.select(object()); + * // decltype(rows) is std::vector, where the User objects are constructed from columns in implicitly stored order + * Example: auto rows = storage.select(object(true)); + * // decltype(rows) is std::vector, where the User objects are constructed from columns in declared make_table order + * + * If you need to fetch results as tuples instead of objects please use `asterisk()`. */ template - internal::object_t object() { - return {}; + internal::object_t object(bool definedOrder = false) { + return {definedOrder}; } } #pragma once #include // std::string +// #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -6663,6 +7479,7 @@ namespace sqlite_orm { std::string dflt_value; int pk = 0; +#if !defined(SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED) || !defined(SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED) table_info(decltype(cid) cid_, decltype(name) name_, decltype(type) type_, @@ -6670,208 +7487,996 @@ namespace sqlite_orm { decltype(dflt_value) dflt_value_, decltype(pk) pk_) : cid(cid_), - name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), pk(pk_) {} + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), + pk(pk_) {} +#endif }; + struct table_xinfo { + int cid = 0; + std::string name; + std::string type; + bool notnull = false; + std::string dflt_value; + int pk = 0; + int hidden = 0; // different than 0 => generated_always_as() - TODO verify + +#if !defined(SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED) || !defined(SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED) + table_xinfo(decltype(cid) cid_, + decltype(name) name_, + decltype(type) type_, + decltype(notnull) notnull_, + decltype(dflt_value) dflt_value_, + decltype(pk) pk_, + decltype(hidden) hidden_) : + cid(cid_), + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), + pk(pk_), hidden{hidden_} {} +#endif + }; } #pragma once -#include // std::unique_ptr -#include -#include // std::integral_constant +#include +#include +#include +#include -namespace sqlite_orm { +// #include "../functional/cxx_universal.h" - /** - * Guard class which finalizes `sqlite3_stmt` in dtor - */ - using statement_finalizer = - std::unique_ptr>; +// #include "../optional_container.h" -} -#pragma once +// NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? +// (Could be implemented with a normal trigger that insert or update an internal table and then retreive +// the event in the C++ code, to call the C++ user callback, with update hooks: https://www.sqlite.org/c3ref/update_hook.html) +// It could be an interesting feature to bring to sqlite_orm that other libraries don't have ? namespace sqlite_orm { + namespace internal { + enum class trigger_timing { trigger_before, trigger_after, trigger_instead_of }; + enum class trigger_type { trigger_delete, trigger_insert, trigger_update }; - /** - * Helper classes used by statement_binder and row_extractor. - */ - struct int_or_smaller_tag {}; - struct bigint_tag {}; - struct real_tag {}; + /** + * This class is an intermediate SQLite trigger, to be used with + * `make_trigger` to create a full trigger. + * T is the base of the trigger (contains its type, timing and associated table) + * S is the list of trigger statements + */ + template + struct partial_trigger_t { + using statements_type = std::tuple; - template - struct arithmetic_tag { - using type = std::conditional_t::value, - // Integer class - std::conditional_t, - // Floating-point class - real_tag>; - }; + /** + * Base of the trigger (contains its type, timing and associated table) + */ + T base; + /** + * Statements of the triggers (to be executed when the trigger fires) + */ + statements_type statements; - template - using arithmetic_tag_t = typename arithmetic_tag::type; -} -#pragma once + partial_trigger_t(T trigger_base, S... statements) : + base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} -#include -#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type -#include // std::string, std::wstring -#ifndef SQLITE_ORM_OMITS_CODECVT -#include // std::codecvt_utf8_utf16 -#endif // SQLITE_ORM_OMITS_CODECVT -#include // std::vector -#include // std::nullptr_t -#include // std::declval -#include // std::wstring_convert -#include // ::strncpy, ::strlen + partial_trigger_t& end() { + return *this; + } + }; -// #include "is_std_ptr.h" + struct base_trigger { + /** + * Name of the trigger + */ + std::string name; + }; -namespace sqlite_orm { + /** + * This class represent a SQLite trigger + * T is the base of the trigger (contains its type, timing and associated table) + * S is the list of trigger statments + */ + template + struct trigger_t : base_trigger { + using object_type = void; + using elements_type = typename partial_trigger_t::statements_type; - /** - * Specialization for optional type (std::shared_ptr / std::unique_ptr). - */ - template - struct is_std_ptr : std::false_type {}; + /** + * Base of the trigger (contains its type, timing and associated table) + */ + T base; - template - struct is_std_ptr> : std::true_type { - using element_type = T; + /** + * Statements of the triggers (to be executed when the trigger fires) + */ + elements_type elements; - static std::shared_ptr make(const T& v) { - return std::make_shared(v); - } - }; +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + trigger_t(std::string name, T trigger_base, elements_type statements) : + base_trigger{std::move(name)}, base(std::move(trigger_base)), elements(std::move(statements)) {} +#endif + }; - template - struct is_std_ptr> : std::true_type { - using element_type = T; + /** + * Base of a trigger. Contains the trigger type/timming and the table type + * T is the table type + * W is `when` expression type + * Type is the trigger base type (type+timing) + */ + template + struct trigger_base_t { + using table_type = T; + using when_type = W; + using trigger_type_base = Type; - static std::unique_ptr make(const T& v) { - return std::make_unique(v); - } - }; -} + /** + * Contains the trigger type and timing + */ + trigger_type_base type_base; + /** + * Value used to determine if we execute the trigger on each row or on each statement + * (SQLite doesn't support the FOR EACH STATEMENT syntax yet: https://sqlite.org/lang_createtrigger.html#description + * so this value is more of a placeholder for a later update) + */ + bool do_for_each_row = false; + /** + * When expression (if any) + * If a WHEN expression is specified, the trigger will only execute + * if the expression evaluates to true when the trigger is fired + */ + optional_container container_when; -namespace sqlite_orm { + trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - /** - * Helper class used for binding fields to sqlite3 statements. - */ - template - struct statement_binder : std::false_type {}; + trigger_base_t& for_each_row() { + this->do_for_each_row = true; + return *this; + } - /** - * Specialization for arithmetic types. - */ - template - struct statement_binder::value>> { + template + trigger_base_t when(WW expression) { + trigger_base_t res(this->type_base); + res.container_when.field = std::move(expression); + return res; + } - int bind(sqlite3_stmt* stmt, int index, const V& value) const { - return this->bind(stmt, index, value, tag()); - } + template + partial_trigger_t, S...> begin(S... statements) { + return {*this, std::forward(statements)...}; + } + }; - void result(sqlite3_context* context, const V& value) const { - this->result(context, value, tag()); - } + /** + * Contains the trigger type and timing + */ + struct trigger_type_base_t { + /** + * Value indicating if the trigger is run BEFORE, AFTER or INSTEAD OF + * the statement that fired it. + */ + trigger_timing timing; + /** + * The type of the statement that would cause the trigger to fire. + * Can be DELETE, INSERT, or UPDATE. + */ + trigger_type type; - private: - using tag = arithmetic_tag_t; + trigger_type_base_t(trigger_timing timing, trigger_type type) : timing(timing), type(type) {} - int bind(sqlite3_stmt* stmt, int index, const V& value, const int_or_smaller_tag&) const { - return sqlite3_bind_int(stmt, index, static_cast(value)); - } + template + trigger_base_t on() { + return {*this}; + } + }; - void result(sqlite3_context* context, const V& value, const int_or_smaller_tag&) const { - sqlite3_result_int(context, static_cast(value)); - } + /** + * Special case for UPDATE OF (columns) + * Contains the trigger type and timing + */ + template + struct trigger_update_type_t : trigger_type_base_t { + using columns_type = std::tuple; - int bind(sqlite3_stmt* stmt, int index, const V& value, const bigint_tag&) const { - return sqlite3_bind_int64(stmt, index, static_cast(value)); - } + /** + * Contains the columns the trigger is watching. Will only + * trigger if one of theses columns is updated. + */ + columns_type columns; - void result(sqlite3_context* context, const V& value, const bigint_tag&) const { - sqlite3_result_int64(context, static_cast(value)); - } + trigger_update_type_t(trigger_timing timing, trigger_type type, Cs... columns) : + trigger_type_base_t(timing, type), columns(std::make_tuple(std::forward(columns)...)) {} - int bind(sqlite3_stmt* stmt, int index, const V& value, const real_tag&) const { - return sqlite3_bind_double(stmt, index, static_cast(value)); - } + template + trigger_base_t> on() { + return {*this}; + } + }; - void result(sqlite3_context* context, const V& value, const real_tag&) const { - sqlite3_result_double(context, static_cast(value)); - } - }; + struct trigger_timing_t { + trigger_timing timing; - /** - * Specialization for std::string and C-string. - */ - template - struct statement_binder< - V, - std::enable_if_t::value || std::is_same::value>> { + trigger_type_base_t delete_() { + return {timing, trigger_type::trigger_delete}; + } - int bind(sqlite3_stmt* stmt, int index, const V& value) const { - auto stringData = this->string_data(value); - return sqlite3_bind_text(stmt, index, std::get<0>(stringData), std::get<1>(stringData), SQLITE_TRANSIENT); - } + trigger_type_base_t insert() { + return {timing, trigger_type::trigger_insert}; + } - void result(sqlite3_context* context, const V& value) const { - auto stringData = this->string_data(value); - auto stringDataLength = std::get<1>(stringData); - auto dataCopy = new char[stringDataLength + 1]; - auto stringChars = std::get<0>(stringData); - ::strncpy(dataCopy, stringChars, stringDataLength + 1); - sqlite3_result_text(context, dataCopy, stringDataLength, [](void* pointer) { - auto charPointer = (char*)pointer; - delete[] charPointer; - }); - } + trigger_type_base_t update() { + return {timing, trigger_type::trigger_update}; + } - private: - std::tuple string_data(const std::string& s) const { - return {s.c_str(), int(s.size())}; - } + template + trigger_update_type_t update_of(Cs... columns) { + return {timing, trigger_type::trigger_update, std::forward(columns)...}; + } + }; - std::tuple string_data(const char* s) const { - auto length = int(::strlen(s)); - return {s, length}; - } - }; + struct raise_t { + enum class type_t { + ignore, + rollback, + abort, + fail, + }; -#ifndef SQLITE_ORM_OMITS_CODECVT - /** - * Specialization for std::wstring and C-wstring. - */ - template - struct statement_binder< - V, - std::enable_if_t::value || std::is_same::value>> { + type_t type = type_t::ignore; + std::string message; - int bind(sqlite3_stmt* stmt, int index, const V& value) const { - std::wstring_convert> converter; - std::string utf8Str = converter.to_bytes(value); - return statement_binder().bind(stmt, index, utf8Str); - } +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + raise_t(type_t type, std::string message) : type{type}, message{std::move(message)} {} +#endif + }; - void result(sqlite3_context* context, const V& value) const { - sqlite3_result_text16(context, (const void*)value.data(), int(value.length()), nullptr); - } - }; -#endif // SQLITE_ORM_OMITS_CODECVT + template + struct new_t { + using expression_type = T; + + expression_type expression; + }; + + template + struct old_t { + using expression_type = T; + + expression_type expression; + }; + } // NAMESPACE internal + + /** + * NEW.expression function used within TRIGGER expressions + */ + template + internal::new_t new_(T expression) { + return {std::move(expression)}; + } + + /** + * OLD.expression function used within TRIGGER expressions + */ + template + internal::old_t old(T expression) { + return {std::move(expression)}; + } + + /** + * RAISE(IGNORE) expression used within TRIGGER expressions + */ + inline internal::raise_t raise_ignore() { + return {internal::raise_t::type_t::ignore, {}}; + } + + /** + * RAISE(ROLLBACK, %message%) expression used within TRIGGER expressions + */ + inline internal::raise_t raise_rollback(std::string message) { + return {internal::raise_t::type_t::rollback, std::move(message)}; + } + + /** + * RAISE(ABORT, %message%) expression used within TRIGGER expressions + */ + inline internal::raise_t raise_abort(std::string message) { + return {internal::raise_t::type_t::abort, std::move(message)}; + } + + /** + * RAISE(FAIL, %message%) expression used within TRIGGER expressions + */ + inline internal::raise_t raise_fail(std::string message) { + return {internal::raise_t::type_t::fail, std::move(message)}; + } + + template + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::move(part.base), std::move(part.statements)}); + } + + inline internal::trigger_timing_t before() { + return {internal::trigger_timing::trigger_before}; + } + + inline internal::trigger_timing_t after() { + return {internal::trigger_timing::trigger_after}; + } + + inline internal::trigger_timing_t instead_of() { + return {internal::trigger_timing::trigger_instead_of}; + } +} +#pragma once + +#include +#include // std::unique_ptr +#include // std::integral_constant + +namespace sqlite_orm { + + /** + * Guard class which finalizes `sqlite3_stmt` in dtor + */ + using statement_finalizer = + std::unique_ptr>; +} +#pragma once +#include + +namespace sqlite_orm { + + /** + * Helper classes used by statement_binder and row_extractor. + */ + struct int_or_smaller_tag {}; + struct bigint_tag {}; + struct real_tag {}; + + template + using arithmetic_tag_t = + std::conditional_t::value, + // Integer class + std::conditional_t, + // Floating-point class + real_tag>; +} +#pragma once + +#include +#include +#include + +// #include "functional/cxx_universal.h" + +// #include "xdestroy_handling.h" + +#include // std::integral_constant +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#include +#endif + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + + using xdestroy_fn_t = void (*)(void*); + using null_xdestroy_t = std::integral_constant; + SQLITE_ORM_INLINE_VAR constexpr null_xdestroy_t null_xdestroy_f{}; +} + +namespace sqlite_orm { + namespace internal { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + /** + * Constrains a deleter to be state-less. + */ + template + concept stateless_deleter = std::is_empty_v && std::is_default_constructible_v; + + /** + * Constrains a deleter to be an integral function constant. + */ + template + concept integral_fp_c = requires { + typename D::value_type; + D::value; + requires std::is_function_v>; + }; + + /** + * Constrains a deleter to be or to yield a function pointer. + */ + template + concept yields_fp = requires(D d) { + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; +#endif + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + /** + * Yield a deleter's function pointer. + */ + template + struct yield_fp_of { + using type = decltype(+std::declval()); + }; +#else + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = + std::is_empty::value && std::is_default_constructible::value; + + template + struct is_integral_fp_c : std::false_type {}; + template + struct is_integral_fp_c< + D, + polyfill::void_t>::value>>> + : std::true_type {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_integral_fp_c_v = is_integral_fp_c::value; + + template + struct can_yield_fp : std::false_type {}; + template + struct can_yield_fp< + D, + polyfill::void_t< + decltype(+std::declval()), + std::enable_if_t())>>::value>>> + : std::true_type {}; + template + SQLITE_ORM_INLINE_VAR constexpr bool can_yield_fp_v = can_yield_fp::value; + + template> + struct yield_fp_of { + using type = void; + }; + template + struct yield_fp_of { + using type = decltype(+std::declval()); + }; +#endif + template + using yielded_fn_t = typename yield_fp_of::type; + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + template + concept is_unusable_for_xdestroy = + (!stateless_deleter && (yields_fp && !std::convertible_to, xdestroy_fn_t>)); + + /** + * This concept tests whether a deleter yields a function pointer, which is convertible to an xdestroy function pointer. + * Note: We are using 'is convertible' rather than 'is same' because of any exception specification. + */ + template + concept yields_xdestroy = yields_fp && std::convertible_to, xdestroy_fn_t>; + + template + concept needs_xdestroy_proxy = + (stateless_deleter && (!yields_fp || !std::convertible_to, xdestroy_fn_t>)); + + /** + * xDestroy function that constructs and invokes the stateless deleter. + * + * Requires that the deleter can be called with the q-qualified pointer argument; + * it doesn't check so explicitly, but a compiler error will occur. + */ + template + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { + // C-casting `void* -> P*` like statement_binder> + auto o = (P*)p; + // ignoring return code + (void)D{}(o); + } + + /** + * xDestroy function that invokes the integral function pointer constant. + * + * Performs a const-cast of the argument pointer in order to allow for C API functions + * that take a non-const parameter, but user code passes a pointer to a const object. + */ + template + void xdestroy_proxy(void* p) noexcept { + // C-casting `void* -> P*` like statement_binder>, + auto o = (std::remove_cv_t

*)(P*)p; + // ignoring return code + (void)D{}(o); + } +#else + template + SQLITE_ORM_INLINE_VAR constexpr bool is_unusable_for_xdestroy_v = + !is_stateless_deleter_v && + (can_yield_fp_v && !std::is_convertible, xdestroy_fn_t>::value); + + template + SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + + template + SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = + is_stateless_deleter_v && + (!can_yield_fp_v || !std::is_convertible, xdestroy_fn_t>::value); + + template, bool> = true> + void xdestroy_proxy(void* p) noexcept { + // C-casting `void* -> P*` like statement_binder> + auto o = (P*)p; + // ignoring return code + (void)D{}(o); + } + + template, bool> = true> + void xdestroy_proxy(void* p) noexcept { + // C-casting `void* -> P*` like statement_binder>, + auto o = (std::remove_cv_t

*)(P*)p; + // ignoring return code + (void)D{}(o); + } +#endif + } +} + +namespace sqlite_orm { + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + /** + * Prohibits using a yielded function pointer, which is not of type xdestroy_fn_t. + * + * Explicitly declared for better error messages. + */ + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { + static_assert(polyfill::always_false_v, + "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); + return nullptr; + } + + /** + * Obtains a proxy 'xDestroy' function pointer [of type void(*)(void*)] + * for a deleter in a type-safe way. + * + * The deleter can be one of: + * - integral function constant + * - state-less (empty) deleter + * - non-capturing lambda + * + * Type-safety is garanteed by checking whether the deleter or yielded function pointer + * is invocable with the non-q-qualified pointer value. + */ + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { + return internal::xdestroy_proxy; + } + + /** + * Directly obtains a 'xDestroy' function pointer [of type void(*)(void*)] + * from a deleter in a type-safe way. + * + * The deleter can be one of: + * - function pointer of type xdestroy_fn_t + * - structure holding a function pointer + * - integral function constant + * - non-capturing lambda + * ... and yield a function pointer of type xdestroy_fn_t. + * + * Type-safety is garanteed by checking whether the deleter or yielded function pointer + * is invocable with the non-q-qualified pointer value. + */ + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { + return d; + } +#else + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) { + static_assert(polyfill::always_false_v, + "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); + return nullptr; + } + + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept { + return internal::xdestroy_proxy; + } + + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept { + return d; + } +#endif +} + +namespace sqlite_orm { + + /** + * Wraps a pointer and tags it with a pointer type, + * used for accepting function parameters, + * facilitating the 'pointer-passing interface'. + * + * Template parameters: + * - P: The value type, possibly const-qualified. + * - T: An integral constant string denoting the pointer type, e.g. `carray_pvt_name`. + * + */ + template + struct pointer_arg { + + static_assert(std::is_convertible::value, + "`std::integral_constant<>` must be convertible to `const char*`"); + + using tag = T; + P* p_; + + P* ptr() const noexcept { + return p_; + } + + operator P*() const noexcept { + return p_; + } + }; + + /** + * Pointer value with associated deleter function, + * used for returning or binding pointer values + * as part of facilitating the 'pointer-passing interface'. + * + * Template parameters: + * - D: The deleter for the pointer value; + * can be one of: + * - function pointer + * - integral function pointer constant + * - state-less (empty) deleter + * - non-capturing lambda + * - structure implicitly yielding a function pointer + * + * @note Use one of the factory functions to create a pointer binding, + * e.g. bindable_carray_pointer or statically_bindable_carray_pointer(). + * + * @example + * ``` + * int64 rememberedId; + * storage.select(func(&Object::id, statically_bindable_carray_pointer(&rememberedId))); + * ``` + */ + template + class pointer_binding { + + P* p_; + SQLITE_ORM_NOUNIQUEADDRESS + D d_; + + protected: + // Constructing pointer bindings must go through bindable_pointer() + template + friend auto bindable_pointer(P2*, D2) noexcept -> pointer_binding; + template + friend B bindable_pointer(typename B::qualified_type*, typename B::deleter_type) noexcept; + + // Construct from pointer and deleter. + // Transfers ownership of the passed in object. + pointer_binding(P* p, D d = {}) noexcept : p_{p}, d_{std::move(d)} {} + + public: + using qualified_type = P; + using tag = T; + using deleter_type = D; + + pointer_binding(const pointer_binding&) = delete; + pointer_binding& operator=(const pointer_binding&) = delete; + pointer_binding& operator=(pointer_binding&&) = delete; + + pointer_binding(pointer_binding&& other) noexcept : + p_{std::exchange(other.p_, nullptr)}, d_{std::move(other.d_)} {} + + ~pointer_binding() { + if(p_) { + if(auto xDestroy = get_xdestroy()) { + // note: C-casting `P* -> void*` like statement_binder> + xDestroy((void*)p_); + } + } + } + + P* ptr() const noexcept { + return p_; + } + + P* take_ptr() noexcept { + return std::exchange(p_, nullptr); + } + + xdestroy_fn_t get_xdestroy() const noexcept { + return obtain_xdestroy_for(d_, p_); + } + }; + + /** + * Template alias for a static pointer value binding. + * 'Static' means that ownership won't be transferred to sqlite, + * sqlite doesn't delete it, and sqlite assumes the object + * pointed to is valid throughout the lifetime of a statement. + */ + template + using static_pointer_binding = pointer_binding; +} + +namespace sqlite_orm { + + /** + * Wrap a pointer, its type and its deleter function for binding it to a statement. + * + * Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object + * is transferred to the pointer binding, which will delete it through + * the deleter when the statement finishes. + */ + template + auto bindable_pointer(P* p, D d) noexcept -> pointer_binding { + return {p, std::move(d)}; + } + + template + auto bindable_pointer(std::unique_ptr p) noexcept -> pointer_binding { + return bindable_pointer(p.release(), p.get_deleter()); + } + + template + B bindable_pointer(typename B::qualified_type* p, typename B::deleter_type d = {}) noexcept { + return B{p, std::move(d)}; + } + + /** + * Wrap a pointer and its type for binding it to a statement. + * + * Note: 'Static' means that ownership of the pointed-to-object won't be transferred + * and sqlite assumes the object pointed to is valid throughout the lifetime of a statement. + */ + template + auto statically_bindable_pointer(P* p) noexcept -> static_pointer_binding { + return bindable_pointer(p, null_xdestroy_f); + } + + template + B statically_bindable_pointer(typename B::qualified_type* p, + typename B::deleter_type* /*exposition*/ = nullptr) noexcept { + return bindable_pointer(p); + } + + /** + * Forward a pointer value from an argument. + */ + template + auto rebind_statically(const pointer_arg& pv) noexcept -> static_pointer_binding { + return statically_bindable_pointer(pv.ptr()); + } +} +#pragma once + +#include +#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type, std::make_index_sequence, std::index_sequence +#include // std::default_delete +#include // std::string, std::wstring +#include // std::vector +#include // ::strncpy, ::strlen +// #include "functional/cxx_string_view.h" + +#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // ::wcsncpy, ::wcslen +#endif + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "functional/cxx_functional_polyfill.h" + +// #include "is_std_ptr.h" + +// #include "tuple_helper/tuple_filter.h" + +// #include "error_code.h" + +// #include "arithmetic_tag.h" + +// #include "xdestroy_handling.h" + +// #include "pointer_value.h" + +namespace sqlite_orm { + + /** + * Helper class used for binding fields to sqlite3 statements. + */ + template + struct statement_binder; + + namespace internal { + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v())>> = true + // note : msvc 14.0 needs the parentheses constructor, otherwise `is_bindable` isn't recognised. + // The strangest thing is that this is mutually exclusive with `is_printable_v`. + ; + +#ifndef SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE + template + using is_bindable = polyfill::bool_constant>; +#else + template + struct is_bindable : polyfill::bool_constant> {}; +#endif + } + + /** + * Specialization for 'pointer-passing interface'. + */ + template + struct statement_binder, void> { + using V = pointer_binding; + + // ownership of pointed-to-object is left untouched and remains at prepared statement's AST expression + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + // note: C-casting `P* -> void*`, internal::xdestroy_proxy() does the inverse + return sqlite3_bind_pointer(stmt, index, (void*)value.ptr(), T::value, null_xdestroy_f); + } + + // ownership of pointed-to-object is transferred to sqlite + void result(sqlite3_context* context, V& value) const { + // note: C-casting `P* -> void*`, + // row_extractor>::extract() and internal::xdestroy_proxy() do the inverse + sqlite3_result_pointer(context, (void*)value.take_ptr(), T::value, value.get_xdestroy()); + } + }; + + /** + * Specialization for arithmetic types. + */ + template + struct statement_binder::value>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + return this->bind(stmt, index, value, tag()); + } + + void result(sqlite3_context* context, const V& value) const { + this->result(context, value, tag()); + } + + private: + using tag = arithmetic_tag_t; + + int bind(sqlite3_stmt* stmt, int index, const V& value, int_or_smaller_tag) const { + return sqlite3_bind_int(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, int_or_smaller_tag) const { + sqlite3_result_int(context, static_cast(value)); + } + + int bind(sqlite3_stmt* stmt, int index, const V& value, bigint_tag) const { + return sqlite3_bind_int64(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, bigint_tag) const { + sqlite3_result_int64(context, static_cast(value)); + } + + int bind(sqlite3_stmt* stmt, int index, const V& value, real_tag) const { + return sqlite3_bind_double(stmt, index, static_cast(value)); + } + + void result(sqlite3_context* context, const V& value, real_tag) const { + sqlite3_result_double(context, static_cast(value)); + } + }; + + /** + * Specialization for std::string and C-string. + */ + template + struct statement_binder, + std::is_same +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + , + std::is_same +#endif + >>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + auto stringData = this->string_data(value); + return sqlite3_bind_text(stmt, index, stringData.first, stringData.second, SQLITE_TRANSIENT); + } + + void result(sqlite3_context* context, const V& value) const { + auto stringData = this->string_data(value); + auto dataCopy = new char[stringData.second + 1]; + constexpr auto deleter = std::default_delete{}; + ::strncpy(dataCopy, stringData.first, stringData.second + 1); + sqlite3_result_text(context, dataCopy, stringData.second, obtain_xdestroy_for(deleter, dataCopy)); + } + + private: +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + std::pair string_data(const std::string_view& s) const { + return {s.data(), int(s.size())}; + } +#else + std::pair string_data(const std::string& s) const { + return {s.c_str(), int(s.size())}; + } + + std::pair string_data(const char* s) const { + return {s, int(::strlen(s))}; + } +#endif + }; + +#ifndef SQLITE_ORM_OMITS_CODECVT + template + struct statement_binder, + std::is_same +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + , + std::is_same +#endif + >>> { + + int bind(sqlite3_stmt* stmt, int index, const V& value) const { + auto stringData = this->string_data(value); + std::wstring_convert> converter; + std::string utf8Str = converter.to_bytes(stringData.first, stringData.first + stringData.second); + return statement_binder().bind(stmt, index, utf8Str); + } + + void result(sqlite3_context* context, const V& value) const { + auto stringData = this->string_data(value); + sqlite3_result_text16(context, stringData.first, stringData.second, nullptr); + } + + private: +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + std::pair string_data(const std::wstring_view& s) const { + return {s.data(), int(s.size())}; + } +#else + std::pair string_data(const std::wstring& s) const { + return {s.c_str(), int(s.size())}; + } + + std::pair string_data(const wchar_t* s) const { + return {s, int(::wcslen(s))}; + } +#endif + }; +#endif /** - * Specialization for std::nullptr_t. + * Specialization for nullptr_t. */ template<> - struct statement_binder { - int bind(sqlite3_stmt* stmt, int index, const std::nullptr_t&) const { + struct statement_binder { + int bind(sqlite3_stmt* stmt, int index, const nullptr_t&) const { return sqlite3_bind_null(stmt, index); } - void result(sqlite3_context* context, const std::nullptr_t&) const { + void result(sqlite3_context* context, const nullptr_t&) const { sqlite3_result_null(context); } }; @@ -6893,33 +8498,27 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_binder::value>> { - using value_type = typename is_std_ptr::element_type; + struct statement_binder< + V, + std::enable_if_t::value && internal::is_bindable_v>>> { + using unqualified_type = std::remove_cv_t; int bind(sqlite3_stmt* stmt, int index, const V& value) const { if(value) { - return statement_binder().bind(stmt, index, *value); - } else { - return statement_binder().bind(stmt, index, nullptr); - } - } - - void result(sqlite3_context* context, const V& value) const { - if(value) { - statement_binder().result(context, value); + return statement_binder().bind(stmt, index, *value); } else { - statement_binder().result(context, nullptr); + return statement_binder().bind(stmt, index, nullptr); } } }; /** - * Specialization for optional type (std::vector). + * Specialization for binary data (std::vector). */ template<> struct statement_binder, void> { int bind(sqlite3_stmt* stmt, int index, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT); } else { return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT); @@ -6927,7 +8526,7 @@ namespace sqlite_orm { } void result(sqlite3_context* context, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr); } else { sqlite3_result_blob(context, "", 0, nullptr); @@ -6936,93 +8535,106 @@ namespace sqlite_orm { }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_binder, void> { - using value_type = T; + template + struct statement_binder && + internal::is_bindable_v>>> { + using unqualified_type = std::remove_cv_t; - int bind(sqlite3_stmt* stmt, int index, const std::optional& value) const { + int bind(sqlite3_stmt* stmt, int index, const V& value) const { if(value) { - return statement_binder().bind(stmt, index, *value); + return statement_binder().bind(stmt, index, *value); } else { return statement_binder().bind(stmt, index, std::nullopt); } } - - void result(sqlite3_context* context, const std::optional& value) const { - if(value) { - statement_binder().result(context, value); - } else { - statement_binder().result(context, std::nullopt); - } - } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED namespace internal { - template - using is_bindable = std::integral_constant>::value>; - - struct conditional_binder_base { + struct conditional_binder { sqlite3_stmt* stmt = nullptr; - int& index; - - conditional_binder_base(decltype(stmt) stmt_, decltype(index) index_) : stmt(stmt_), index(index_) {} - }; - - template - struct conditional_binder; - - template - struct conditional_binder : conditional_binder_base { + int index = 1; - using conditional_binder_base::conditional_binder_base; + explicit conditional_binder(sqlite3_stmt* stmt) : stmt{stmt} {} - int operator()(const T& t) const { - return statement_binder().bind(this->stmt, this->index++, t); + template = true> + void operator()(const T& t) { + int rc = statement_binder{}.bind(this->stmt, this->index++, t); + if(SQLITE_OK != rc) { + throw_translated_sqlite_error(this->stmt); + } } + + template = true> + void operator()(const T&) const {} }; - template - struct conditional_binder : conditional_binder_base { - using conditional_binder_base::conditional_binder_base; + struct field_value_binder : conditional_binder { + using conditional_binder::conditional_binder; + using conditional_binder::operator(); - int operator()(const T&) const { - return SQLITE_OK; + template = true> + void operator()(const T&) const = delete; + + template + void operator()(const T* value) { + if(!value) { + throw std::system_error{orm_error_code::value_is_null}; + } + (*this)(*value); } }; - template class F, class SFINAE = void> - struct tuple_filter_single; - - template class F> - struct tuple_filter_single::value>::type> { - using type = std::tuple; - }; + struct tuple_value_binder { + sqlite3_stmt* stmt = nullptr; - template class F> - struct tuple_filter_single::value>::type> { - using type = std::tuple<>; - }; + explicit tuple_value_binder(sqlite3_stmt* stmt) : stmt{stmt} {} - template class F> - struct tuple_filter; + template + void operator()(const Tpl& tpl, Projection project) const { + (*this)(tpl, + std::make_index_sequence::value>{}, + std::forward(project)); + } - template class F> - struct tuple_filter, F> { - using type = typename conc_tuple::type...>::type; - }; + private: +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void operator()(const Tpl& tpl, std::index_sequence, Projection project) const { + (this->bind(polyfill::invoke(project, std::get(tpl)), Idx), ...); + } +#else + template + void operator()(const Tpl& tpl, std::index_sequence, Projection project) const { + this->bind(polyfill::invoke(project, std::get(tpl)), I); + (*this)(tpl, std::index_sequence{}, std::forward(project)); + } - template - struct bindable_filter_single : tuple_filter_single {}; + template + void operator()(const Tpl&, std::index_sequence<>, Projection) const {} +#endif - template - struct bindable_filter; + template + void bind(const T& t, size_t idx) const { + int rc = statement_binder{}.bind(this->stmt, int(idx + 1), t); + if(SQLITE_OK != rc) { + throw_translated_sqlite_error(this->stmt); + } + } - template - struct bindable_filter> { - using type = typename conc_tuple::type...>::type; + template + void bind(const T* value, size_t idx) const { + if(!value) { + throw std::system_error{orm_error_code::value_is_null}; + } + (*this)(*value, idx); + } }; + + template + using bindable_filter_t = filter_tuple_t; } } #pragma once @@ -7030,36 +8642,53 @@ namespace sqlite_orm { #include #include // std::enable_if_t, std::is_arithmetic, std::is_same, std::enable_if #include // atof, atoi, atoll +#include // std::system_error #include // std::string, std::wstring #ifndef SQLITE_ORM_OMITS_CODECVT #include // std::wstring_convert, std::codecvt_utf8_utf16 #endif // SQLITE_ORM_OMITS_CODECVT #include // std::vector #include // strlen +#include #include // std::copy #include // std::back_inserter #include // std::tuple, std::tuple_size, std::tuple_element +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#include +#endif + +// #include "functional/cxx_universal.h" // #include "arithmetic_tag.h" +// #include "pointer_value.h" + // #include "journal_mode.h" +#include // std::back_inserter #include // std::string #include // std::unique_ptr #include // std::array #include // std::transform #include // std::toupper -namespace sqlite_orm { - -/** - * Caps case cause of 1) delete keyword; 2) https://www.sqlite.org/pragma.html#pragma_journal_mode original spelling - */ -#ifdef DELETE +#if defined(_WINNT_) +// DELETE is a macro defined in the Windows SDK (winnt.h) +#pragma push_macro("DELETE") #undef DELETE #endif + +namespace sqlite_orm { + + /** + * Caps case because of: + * 1) delete keyword; + * 2) https://www.sqlite.org/pragma.html#pragma_journal_mode original spelling + */ enum class journal_mode : signed char { DELETE = 0, + // An alternate enumeration value when using the Windows SDK that defines DELETE as a macro. + DELETE_ = DELETE, TRUNCATE = 1, PERSIST = 2, MEMORY = 3, @@ -7104,34 +8733,143 @@ namespace sqlite_orm { } } +#if defined(_WINNT_) +#pragma pop_macro("DELETE") +#endif + // #include "error_code.h" +// #include "is_std_ptr.h" + namespace sqlite_orm { /** - * Helper class used to cast values from argv to V class - * which depends from column type. - * + * Helper for casting values originating from SQL to C++ typed values, usually from rows of a result set. + * + * sqlite_orm provides specializations for known C++ types, users may define their custom specialization + * of this helper. + * + * @note (internal): Since row extractors are used in certain contexts with only one purpose at a time + * (e.g., converting a row result set but not function values or column text), + * there are factory functions that perform conceptual checking that should be used + * instead of directly creating row extractors. + * + * */ template struct row_extractor { - // used in sqlite3_exec (select) - V extract(const char* row_value) const; + /* + * Called during one-step query execution (one result row) for each column of a result row. + */ + V extract(const char* columnText) const = delete; + + /* + * Called during multi-step query execution (result set) for each column of a result row. + */ + V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; + + /* + * Called before invocation of user-defined scalar or aggregate functions, + * in order to unbox dynamically typed SQL function values into a tuple of C++ function arguments. + */ + V extract(sqlite3_value* value) const = delete; + }; + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + template + concept orm_column_text_extractable = requires(const row_extractor& extractor, const char* columnText) { + { extractor.extract(columnText) } -> std::same_as; + }; + + template + concept orm_row_value_extractable = + requires(const row_extractor& extractor, sqlite3_stmt* stmt, int columnIndex) { + { extractor.extract(stmt, columnIndex) } -> std::same_as; + }; + + template + concept orm_boxed_value_extractable = requires(const row_extractor& extractor, sqlite3_value* value) { + { extractor.extract(value) } -> std::same_as; + }; +#endif + + namespace internal { + /* + * Make a row extractor to be used for casting SQL column text to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + row_extractor column_text_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for converting a value from a SQL result row set to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + row_extractor row_value_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for unboxing a dynamically typed SQL value to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + row_extractor boxed_value_extractor() { + return {}; + } + } - // used in sqlite_column (iteration, get_all) - V extract(sqlite3_stmt* stmt, int columnIndex) const; + template + int extract_single_value(void* data, int argc, char** argv, char**) { + auto& res = *(R*)data; + if(argc) { + const auto rowExtractor = internal::column_text_extractor(); + res = rowExtractor.extract(argv[0]); + } + return 0; + } + + /** + * Specialization for the 'pointer-passing interface'. + * + * @note The 'pointer-passing' interface doesn't support (and in fact prohibits) + * extracting pointers from columns. + */ + template + struct row_extractor, void> { + using V = pointer_arg; + + V extract(const char* columnText) const = delete; + + V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; - // used in user defined functions - V extract(sqlite3_value* value) const; + V extract(sqlite3_value* value) const { + return {(P*)sqlite3_value_pointer(value, T::value)}; + } }; + /** + * Undefine using pointer_binding<> for querying values + */ + template + struct row_extractor, void>; + /** * Specialization for arithmetic types. */ template struct row_extractor::value>> { - V extract(const char* row_value) const { - return this->extract(row_value, tag()); + V extract(const char* columnText) const { + return this->extract(columnText, tag()); } V extract(sqlite3_stmt* stmt, int columnIndex) const { @@ -7145,8 +8883,8 @@ namespace sqlite_orm { private: using tag = arithmetic_tag_t; - V extract(const char* row_value, const int_or_smaller_tag&) const { - return static_cast(atoi(row_value)); + V extract(const char* columnText, const int_or_smaller_tag&) const { + return static_cast(atoi(columnText)); } V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { @@ -7157,8 +8895,8 @@ namespace sqlite_orm { return static_cast(sqlite3_value_int(value)); } - V extract(const char* row_value, const bigint_tag&) const { - return static_cast(atoll(row_value)); + V extract(const char* columnText, const bigint_tag&) const { + return static_cast(atoll(columnText)); } V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { @@ -7169,8 +8907,8 @@ namespace sqlite_orm { return static_cast(sqlite3_value_int64(value)); } - V extract(const char* row_value, const real_tag&) const { - return static_cast(atof(row_value)); + V extract(const char* columnText, const real_tag&) const { + return static_cast(atof(columnText)); } V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { @@ -7185,17 +8923,17 @@ namespace sqlite_orm { /** * Specialization for std::string. */ - template<> - struct row_extractor { - std::string extract(const char* row_value) const { - if(row_value) { - return row_value; + template + struct row_extractor::value>> { + T extract(const char* columnText) const { + if(columnText) { + return columnText; } else { return {}; } } - std::string extract(sqlite3_stmt* stmt, int columnIndex) const { + T extract(sqlite3_stmt* stmt, int columnIndex) const { if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { return cStr; } else { @@ -7203,7 +8941,7 @@ namespace sqlite_orm { } } - std::string extract(sqlite3_value* value) const { + T extract(sqlite3_value* value) const { if(auto cStr = (const char*)sqlite3_value_text(value)) { return cStr; } else { @@ -7217,10 +8955,10 @@ namespace sqlite_orm { */ template<> struct row_extractor { - std::wstring extract(const char* row_value) const { - if(row_value) { + std::wstring extract(const char* columnText) const { + if(columnText) { std::wstring_convert> converter; - return converter.from_bytes(row_value); + return converter.from_bytes(columnText); } else { return {}; } @@ -7248,29 +8986,44 @@ namespace sqlite_orm { template struct row_extractor::value>> { - using value_type = typename is_std_ptr::element_type; + using unqualified_type = std::remove_cv_t; - V extract(const char* row_value) const { - if(row_value) { - return is_std_ptr::make(row_extractor().extract(row_value)); + V extract(const char* columnText) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(columnText) { + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(columnText)); } else { return {}; } } - V extract(sqlite3_stmt* stmt, int columnIndex) const { + V extract(sqlite3_stmt* stmt, int columnIndex) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(stmt, columnIndex)); } else { return {}; } } - V extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(value)); } else { return {}; } @@ -7278,114 +9031,112 @@ namespace sqlite_orm { }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct row_extractor, void> { - using value_type = T; + template + struct row_extractor>> { + using unqualified_type = std::remove_cv_t; - std::optional extract(const char* row_value) const { - if(row_value) { - return std::make_optional(row_extractor().extract(row_value)); + V extract(const char* columnText) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(columnText) { + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(columnText)); } else { return std::nullopt; } } - std::optional extract(sqlite3_stmt* stmt, int columnIndex) const { + V extract(sqlite3_stmt* stmt, int columnIndex) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(stmt, columnIndex)); } else { return std::nullopt; } } - std::optional extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(value)); } else { return std::nullopt; } } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED + + template<> + struct row_extractor { + nullptr_t extract(const char* /*columnText*/) const { + return nullptr; + } + + nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { + return nullptr; + } + + nullptr_t extract(sqlite3_value*) const { + return nullptr; + } + }; /** * Specialization for std::vector. */ template<> struct row_extractor> { - std::vector extract(const char* row_value) const { - if(row_value) { - auto len = ::strlen(row_value); - return this->go(row_value, len); - } else { - return {}; - } + std::vector extract(const char* columnText) const { + return {columnText, columnText + (columnText ? ::strlen(columnText) : 0)}; } std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); - return this->go(bytes, len); + return {bytes, bytes + len}; } std::vector extract(sqlite3_value* value) const { auto bytes = static_cast(sqlite3_value_blob(value)); auto len = static_cast(sqlite3_value_bytes(value)); - return this->go(bytes, len); - } - - protected: - std::vector go(const char* bytes, size_t len) const { - if(len) { - std::vector res; - res.reserve(len); - std::copy(bytes, bytes + len, std::back_inserter(res)); - return res; - } else { - return {}; - } + return {bytes, bytes + len}; } }; + /** + * Specialization for a tuple. + */ template struct row_extractor> { std::tuple extract(char** argv) const { - std::tuple res; - this->extract::value>(res, argv); - return res; + return this->extract(argv, std::make_index_sequence{}); } std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { - std::tuple res; - this->extract::value>(res, stmt); - return res; + return this->extract(stmt, std::make_index_sequence{}); } protected: - template::type* = nullptr> - void extract(std::tuple& t, sqlite3_stmt* stmt) const { - using tuple_type = typename std::tuple_element>::type; - std::get(t) = row_extractor().extract(stmt, I - 1); - this->extract(t, stmt); - } - - template::type* = nullptr> - void extract(std::tuple&, sqlite3_stmt*) const { - //.. - } - - template::type* = nullptr> - void extract(std::tuple& t, char** argv) const { - using tuple_type = typename std::tuple_element>::type; - std::get(t) = row_extractor().extract(argv[I - 1]); - this->extract(t, argv); + template + std::tuple extract(sqlite3_stmt* stmt, std::index_sequence) const { + return {row_extractor{}.extract(stmt, Idx)...}; } - template::type* = nullptr> - void extract(std::tuple&, char**) const { - //.. + template + std::tuple extract(char** argv, std::index_sequence) const { + return {row_extractor{}.extract(argv[Idx])...}; } }; @@ -7394,15 +9145,15 @@ namespace sqlite_orm { */ template<> struct row_extractor { - journal_mode extract(const char* row_value) const { - if(row_value) { - if(auto res = internal::journal_mode_from_string(row_value)) { + journal_mode extract(const char* columnText) const { + if(columnText) { + if(auto res = internal::journal_mode_from_string(columnText)) { return std::move(*res); } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); + throw std::system_error{orm_error_code::incorrect_journal_mode_string}; } } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); + throw std::system_error{orm_error_code::incorrect_journal_mode_string}; } } @@ -7416,44 +9167,130 @@ namespace sqlite_orm { #include #include // std::string -#include // std::system_error, std::error_code +#include // std::move + +// #include "error_code.h" + +namespace sqlite_orm { + + /** + * Escape the provided character in the given string by doubling it. + * @param str A copy of the original string + * @param char2Escape The character to escape + */ + inline std::string sql_escape(std::string str, char char2Escape) { + for(size_t pos = 0; (pos = str.find(char2Escape, pos)) != str.npos; pos += 2) { + str.replace(pos, 1, 2, char2Escape); + } + + return str; + } + + /** + * Quote the given string value using single quotes, + * escape containing single quotes by doubling them. + */ + inline std::string quote_string_literal(std::string v) { + constexpr char quoteChar = '\''; + return quoteChar + sql_escape(std::move(v), quoteChar) + quoteChar; + } -namespace sqlite_orm { + /** + * Quote the given string value using single quotes, + * escape containing single quotes by doubling them. + */ + inline std::string quote_blob_literal(std::string v) { + constexpr char quoteChar = '\''; + return std::string{char('x'), quoteChar} + std::move(v) + quoteChar; + } + + /** + * Quote the given identifier using double quotes, + * escape containing double quotes by doubling them. + */ + inline std::string quote_identifier(std::string identifier) { + constexpr char quoteChar = '"'; + return quoteChar + sql_escape(std::move(identifier), quoteChar) + quoteChar; + } namespace internal { - inline void perform_step(sqlite3* db, sqlite3_stmt* stmt) { - auto rc = sqlite3_step(stmt); - if(rc == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + // Wrapper to reduce boiler-plate code + inline sqlite3_stmt* reset_stmt(sqlite3_stmt* stmt) { + sqlite3_reset(stmt); + return stmt; + } + + // note: query is deliberately taken by value, such that it is thrown away early + inline sqlite3_stmt* prepare_stmt(sqlite3* db, std::string query) { + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { + throw_translated_sqlite_error(db); } + return stmt; } - static void perform_void_exec(sqlite3* db, const std::string& query) { + inline void perform_void_exec(sqlite3* db, const std::string& query) { int rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(db); } } - template - inline auto call_insert_impl_and_catch_constraint_failed(const T& insert_impl) { - try { - return insert_impl(); - } catch(const std::system_error& e) { - if(e.code() == std::error_code(SQLITE_CONSTRAINT, get_sqlite_error_category())) { - std::stringstream ss; - ss << "Attempting to execute 'insert' request resulted in an error like \"" << e.what() - << "\". Perhaps ordinary 'insert' is not acceptable for this table and you should try " - "'replace' or 'insert' with explicit column listing?"; - throw std::system_error(e.code(), ss.str()); + inline void perform_exec(sqlite3* db, + const char* query, + int (*callback)(void* data, int argc, char** argv, char**), + void* user_data) { + int rc = sqlite3_exec(db, query, callback, user_data, nullptr); + if(rc != SQLITE_OK) { + throw_translated_sqlite_error(db); + } + } + + inline void perform_exec(sqlite3* db, + const std::string& query, + int (*callback)(void* data, int argc, char** argv, char**), + void* user_data) { + return perform_exec(db, query.c_str(), callback, user_data); + } + + template + void perform_step(sqlite3_stmt* stmt) { + int rc = sqlite3_step(stmt); + if(rc != expected) { + throw_translated_sqlite_error(stmt); + } + } + + template + void perform_step(sqlite3_stmt* stmt, L&& lambda) { + switch(int rc = sqlite3_step(stmt)) { + case SQLITE_ROW: { + lambda(stmt); + } break; + case SQLITE_DONE: + break; + default: { + throw_translated_sqlite_error(stmt); } - throw; } } + + template + void perform_steps(sqlite3_stmt* stmt, L&& lambda) { + int rc; + do { + switch(rc = sqlite3_step(stmt)) { + case SQLITE_ROW: { + lambda(stmt); + } break; + case SQLITE_DONE: + break; + default: { + throw_translated_sqlite_error(stmt); + } + } + } while(rc != SQLITE_DONE); + } } } #pragma once @@ -7519,13 +9356,22 @@ namespace sqlite_orm { } #pragma once -#include // std::tuple, std::make_tuple +#include // std::tuple, std::make_tuple, std::declval, std::tuple_element_t #include // std::string #include // std::forward -// #include "indexed_column.h" +// #include "../functional/cxx_universal.h" + +// #include "../tuple_helper/tuple_filter.h" + +// #include "../indexed_column.h" #include // std::string +#include // std::move + +// #include "functional/cxx_universal.h" + +// #include "ast/where.h" namespace sqlite_orm { @@ -7535,8 +9381,10 @@ namespace sqlite_orm { struct indexed_column_t { using column_type = C; +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED indexed_column_t(column_type _column_or_expression) : column_or_expression(std::move(_column_or_expression)) {} +#endif column_type column_or_expression; std::string _collation_name; @@ -7544,7 +9392,7 @@ namespace sqlite_orm { indexed_column_t collate(std::string name) { auto res = std::move(*this); - res._collation_name = move(name); + res._collation_name = std::move(name); return res; } @@ -7562,29 +9410,19 @@ namespace sqlite_orm { }; template - struct indexed_column_maker { - using type = indexed_column_t; - - indexed_column_t operator()(C col) const { - return {std::move(col)}; - } - }; + indexed_column_t make_indexed_column(C col) { + return {std::move(col)}; + } template - struct indexed_column_maker> { - using type = indexed_column_t; - - indexed_column_t operator()(indexed_column_t col) const { - return std::move(col); - } - }; + where_t make_indexed_column(where_t wher) { + return std::move(wher); + } template - auto make_indexed_column(C col) { - indexed_column_maker maker; - return maker(std::move(col)); + indexed_column_t make_indexed_column(indexed_column_t col) { + return std::move(col); } - } /** @@ -7598,6 +9436,8 @@ namespace sqlite_orm { } +// #include "../table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -7605,53 +9445,57 @@ namespace sqlite_orm { struct index_base { std::string name; bool unique = false; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + index_base(std::string name, bool unique) : name{std::move(name)}, unique{unique} {} +#endif }; - template + template struct index_t : index_base { - using columns_type = std::tuple; + using elements_type = std::tuple; using object_type = void; + using table_mapped_type = T; - index_t(std::string name_, bool unique_, columns_type columns_) : - index_base{move(name_), unique_}, columns(move(columns_)) {} +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + index_t(std::string name_, bool unique_, elements_type elements_) : + index_base{std::move(name_), unique_}, elements(std::move(elements_)) {} +#endif - columns_type columns; + elements_type elements; }; } - template - internal::index_t::type...> make_index(const std::string& name, - Cols... cols) { - return {name, false, std::make_tuple(internal::make_indexed_column(cols)...)}; + template + internal::index_t()))...> make_index(std::string name, + Cols... cols) { + using cols_tuple = std::tuple; + static_assert(internal::count_tuple::value <= 1, + "amount of where arguments can be 0 or 1"); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template - internal::index_t::type...> make_unique_index(const std::string& name, - Cols... cols) { - return {name, true, std::make_tuple(internal::make_indexed_column(cols)...)}; + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> + make_index(std::string name, Cols... cols) { + using cols_tuple = std::tuple; + static_assert(internal::count_tuple::value <= 1, + "amount of where arguments can be 0 or 1"); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } -} -#pragma once - -// #include "alias.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * If T is alias than mapped_type_proxy::type is alias::type - * otherwise T is T. - */ - template - struct mapped_type_proxy { - using type = T; - }; - template - struct mapped_type_proxy::value>::type> { - using type = typename T::type; - }; + template + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> + make_unique_index(std::string name, Cols... cols) { + using cols_tuple = std::tuple; + static_assert(internal::count_tuple::value <= 1, + "amount of where arguments can be 0 or 1"); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } } #pragma once @@ -7725,1723 +9569,1721 @@ namespace sqlite_orm { } #pragma once -#include // std::enable_if, std::is_same, std::decay, std::is_arithmetic -#include // std::tuple -#include // std::reference_wrapper +#include // std::string +#include // std::remove_const, std::is_member_pointer, std::true_type, std::false_type +#include // std::vector +#include // std::tuple_element +#include // std::forward, std::move -// #include "core_functions.h" +// #include "../functional/cxx_universal.h" +// ::size_t +// #include "../functional/cxx_type_traits_polyfill.h" -// #include "select_constraints.h" +// #include "../functional/cxx_functional_polyfill.h" -// #include "operators.h" +// #include "../functional/static_magic.h" -// #include "rowid.h" +#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED +#include // std::false_type, std::true_type, std::integral_constant +#endif +#include // std::forward -// #include "alias.h" +namespace sqlite_orm { -// #include "column.h" + // got from here + // https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co + namespace internal { -// #include "storage_traits.h" -#include // std::is_same, std::enable_if, std::true_type, std::false_type, std::integral_constant -#include // std::tuple + template + decltype(auto) empty_callable() { + static auto res = [](auto&&...) -> R { + return R(); + }; + return (res); + } -namespace sqlite_orm { +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + template + decltype(auto) static_if([[maybe_unused]] T&& trueFn, [[maybe_unused]] F&& falseFn) { + if constexpr(B) { + return std::forward(trueFn); + } else { + return std::forward(falseFn); + } + } + + template + decltype(auto) static_if([[maybe_unused]] T&& trueFn) { + if constexpr(B) { + return std::forward(trueFn); + } else { + return empty_callable(); + } + } + + template + void call_if_constexpr([[maybe_unused]] L&& lambda, [[maybe_unused]] Args&&... args) { + if constexpr(B) { + lambda(std::forward(args)...); + } + } +#else + template + decltype(auto) static_if(std::true_type, T&& trueFn, const F&) { + return std::forward(trueFn); + } + + template + decltype(auto) static_if(std::false_type, const T&, F&& falseFn) { + return std::forward(falseFn); + } + + template + decltype(auto) static_if(T&& trueFn, F&& falseFn) { + return static_if(std::integral_constant{}, std::forward(trueFn), std::forward(falseFn)); + } + + template + decltype(auto) static_if(T&& trueFn) { + return static_if(std::integral_constant{}, std::forward(trueFn), empty_callable()); + } + + template + void call_if_constexpr(L&& lambda, Args&&... args) { + static_if(std::forward(lambda))(std::forward(args)...); + } +#endif + } + +} + +// #include "../functional/mpl.h" + +// #include "../functional/index_sequence_util.h" + +// #include "../tuple_helper/tuple_filter.h" + +// #include "../tuple_helper/tuple_traits.h" + +// #include "../tuple_helper/tuple_iteration.h" +#include // std::tuple, std::get, std::tuple_element, std::tuple_size +#include // std::remove_reference, std::index_sequence, std::make_index_sequence, std::forward, std::move +#include // std::forward, std::move + +// #include "../functional/cxx_universal.h" +// ::size_t + +namespace sqlite_orm { namespace internal { - template - struct storage_impl; + // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer + template + auto call(Function& f, FunctionPointer functionPointer, Tpl&& tpl, std::index_sequence) { + return (f.*functionPointer)(std::get(std::forward(tpl))...); + } - template - struct table_t; + template + auto call(Function& f, Tpl&& tpl, std::index_sequence) { + return f(std::get(std::forward(tpl))...); + } - template - struct foreign_key_t; + template + auto call(Function& f, FunctionPointer functionPointer, Tpl&& tpl) { + constexpr size_t size = std::tuple_size>::value; + return call(f, functionPointer, std::forward(tpl), std::make_index_sequence{}); + } - template - struct table_without_rowid_t; + // custom std::apply + template + auto call(Function& f, Tpl&& tpl) { + constexpr size_t size = std::tuple_size>::value; + return call(f, std::forward(tpl), std::make_index_sequence{}); + } - namespace storage_traits { +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + if constexpr(reversed) { + // nifty fold expression trick: make use of guaranteed right-to-left evaluation order when folding over operator= + int sink; + ((lambda(std::get(tpl)), sink) = ... = 0); + } else { + (lambda(std::get(tpl)), ...); + } + } +#else + template + void iterate_tuple(const Tpl& /*tpl*/, std::index_sequence<>, L&& /*lambda*/) {} - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct type_is_mapped_impl; + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + if constexpr(reversed) { +#else + if(reversed) { +#endif + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + lambda(std::get(tpl)); + } else { + lambda(std::get(tpl)); + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + } + } +#endif + template + void iterate_tuple(const Tpl& tpl, L&& lambda) { + iterate_tuple(tpl, + std::make_index_sequence::value>{}, + std::forward(lambda)); + } - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct type_is_mapped : type_is_mapped_impl {}; +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void iterate_tuple(std::index_sequence, L&& lambda) { + (lambda((std::tuple_element_t*)nullptr), ...); + } +#else + template + void iterate_tuple(std::index_sequence<>, L&& /*lambda*/) {} - /** - * Final specialisation - */ - template - struct type_is_mapped_impl, T, void> : std::false_type {}; - - template - struct type_is_mapped_impl< - S, - T, - typename std::enable_if::value>::type> - : std::true_type {}; - - template - struct type_is_mapped_impl< - S, - T, - typename std::enable_if::value>::type> - : type_is_mapped_impl {}; + template + void iterate_tuple(std::index_sequence, L&& lambda) { + lambda((std::tuple_element_t*)nullptr); + iterate_tuple(std::index_sequence{}, std::forward(lambda)); + } +#endif + template + void iterate_tuple(L&& lambda) { + iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); + } - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct storage_columns_count_impl; + template class Base, class L> + struct lambda_as_template_base : L { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + lambda_as_template_base(L&& lambda) : L{std::move(lambda)} {} +#endif + template + decltype(auto) operator()(const Base& object) { + return L::operator()(object); + } + }; - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct storage_columns_count : storage_columns_count_impl {}; + /* + * This method wraps the specified callable in another function object, + * which in turn implicitly casts its single argument to the specified template base class, + * then passes the converted argument to the lambda. + * + * Note: This method is useful for reducing combinatorial instantiation of template lambdas, + * as long as this library supports compilers that do not implement + * explicit template parameters in generic lambdas [SQLITE_ORM_EXPLICIT_GENERIC_LAMBDA_SUPPORTED]. + * Unfortunately it doesn't work with user-defined conversion operators in order to extract + * parts of a class. In other words, the destination type must be a direct template base class. + */ + template class Base, class L> + lambda_as_template_base call_as_template_base(L lambda) { + return {std::move(lambda)}; + } + } +} - /** - * Final specialisation - */ - template - struct storage_columns_count_impl, T, void> : std::integral_constant {}; - - template - struct storage_columns_count_impl< - S, - T, - typename std::enable_if::value>::type> - : std::integral_constant {}; - - template - struct storage_columns_count_impl< - S, - T, - typename std::enable_if::value>::type> - : storage_columns_count_impl {}; +// #include "../tuple_helper/tuple_transformer.h" - /** - * T - table type. - */ - template - struct table_types; +#include // std::remove_reference, std::common_type, std::index_sequence, std::make_index_sequence, std::forward, std::move, std::integral_constant, std::declval +#include // std::tuple_size, std::get - /** - * type is std::tuple of field types of mapped colums. - */ - template - struct table_types> { - using args_tuple = std::tuple; - using columns_tuple = typename tuple_filter::type; +// #include "../functional/cxx_universal.h" +// ::size_t +// #include "../functional/cxx_type_traits_polyfill.h" - using type = typename tuple_transformer::type; - }; +// #include "../functional/cxx_functional_polyfill.h" - /** - * type is std::tuple of field types of mapped colums. - */ - template - struct table_types> { - using args_tuple = std::tuple; - using columns_tuple = typename tuple_filter::type; +// #include "../functional/mpl.h" - using type = typename tuple_transformer::type; - }; +namespace sqlite_orm { + namespace internal { - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct storage_mapped_columns_impl; + template class Op> + struct tuple_transformer; - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct storage_mapped_columns : storage_mapped_columns_impl {}; + template class Pack, class... Types, template class Op> + struct tuple_transformer, Op> { + using type = Pack...>; + }; - /** - * Final specialisation - */ - template - struct storage_mapped_columns_impl, T, void> { - using type = std::tuple<>; - }; + /* + * Transform specified tuple. + * + * `Op` is a metafunction operation. + */ + template class Op> + using transform_tuple_t = typename tuple_transformer::type; - template - struct storage_mapped_columns_impl< - S, - T, - typename std::enable_if::value>::type> { - using table_type = typename S::table_type; - using type = typename table_types::type; - }; +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + /* + * Apply a projection to a tuple's elements filtered by the specified indexes, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, + const Tpl& tpl, + std::index_sequence, + Projector project, + Init initial) { + return combine(initial, polyfill::invoke(project, std::get(tpl))...); + } - template - struct storage_mapped_columns_impl< - S, - T, - typename std::enable_if::value>::type> - : storage_mapped_columns_impl {}; + /* + * Apply a projection to a tuple's elements, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, const Tpl& tpl, Projector project, Init initial) { + return recombine_tuple(std::move(combine), + std::forward(tpl), + std::make_index_sequence::value>{}, + std::move(project), + std::move(initial)); + } - /** - * C is any column type: column_t or constraint type - * O - object type references in FOREIGN KEY - */ - template - struct column_foreign_keys_count : std::integral_constant {}; + /* + * Function object that takes integral constants and returns the sum of their values as an integral constant. + * Because it's a "transparent" functor, it must be called with at least one argument, otherwise it cannot deduce the integral constant type. + */ + struct plus_fold_integrals { + template + constexpr auto operator()(const Integrals&...) const { + using integral_type = std::common_type_t; + return std::integral_constant{}; + } + }; - template - struct column_foreign_keys_count, O> { - using target_type = typename foreign_key_t::target_type; + /* + * Function object that takes a type, applies a projection on it, and returns the tuple size of the projected type (as an integral constant). + * The projection is applied on the argument type, not the argument value/object. + */ + template class NestedProject> + struct project_nested_tuple_size { + template + constexpr auto operator()(const T&) const { + return typename std::tuple_size>::type{}; + } + }; - static constexpr const int value = std::is_same::value ? 1 : 0; - }; + template class NestedProject, class Tpl, class IdxSeq> + using nested_tuple_size_for_t = decltype(recombine_tuple(plus_fold_integrals{}, + std::declval(), + IdxSeq{}, + project_nested_tuple_size{}, + std::integral_constant{})); +#endif - /** - * O - object type references in FOREIGN KEY - * Cs - column types which are stored in table_t::columns_type - */ - template - struct table_foreign_keys_count_impl; + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + } - template - struct table_foreign_keys_count_impl { - static constexpr const int value = 0; - }; + template + R create_from_tuple(Tpl&& tpl, Projection project = {}) { + return create_from_tuple( + std::forward(tpl), + std::make_index_sequence>::value>{}, + std::forward(project)); + } + } +} - template - struct table_foreign_keys_count_impl { - static constexpr const int value = - column_foreign_keys_count::value + table_foreign_keys_count_impl::value; - }; +// #include "../member_traits/member_traits.h" - /** - * T is table_t type - * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User) - */ - template - struct table_foreign_keys_count; +// #include "../typed_comparator.h" - template - struct table_foreign_keys_count, O> { - using table_type = table_t; +// #include "../type_traits.h" - static constexpr const int value = table_foreign_keys_count_impl::value; - }; +// #include "../constraints.h" - /** - * S - storage class - * O - type mapped to S - */ - template - struct storage_foreign_keys_count_impl; +// #include "../table_info.h" - template - struct storage_foreign_keys_count_impl, O> : std::integral_constant {}; +// #include "column.h" - template - struct storage_foreign_keys_count_impl, O> { - static constexpr const int value = table_foreign_keys_count::value + - storage_foreign_keys_count_impl, O>::value; - }; +namespace sqlite_orm { - /** - * S - storage class - * O - type mapped to S - * This class tells how many types mapped to S have foreign keys to O - */ - template - struct storage_foreign_keys_count { - using impl_type = typename S::impl_type; + namespace internal { - static constexpr const int value = storage_foreign_keys_count_impl::value; - }; + struct basic_table { /** - * C is any column type: column_t or constraint type - * O - object type references in FOREIGN KEY + * Table name. */ - template - struct column_fk_references { - using type = std::tuple<>; - }; + std::string name; + }; - template - struct column_fk_references< - foreign_key_t, - O, - typename std::enable_if::target_type>::value>::type> { - using target_type = typename foreign_key_t::source_type; + /** + * Table definition. + */ + template + struct table_t : basic_table { + using object_type = O; + using elements_type = std::tuple; - using type = std::tuple; - }; + static constexpr bool is_without_rowid_v = WithoutRowId; - template - struct column_fk_references< - foreign_key_t, - O, - typename std::enable_if::target_type>::value>::type> { - using type = std::tuple<>; - }; + using is_without_rowid = polyfill::bool_constant; - /** - * O - object type references in FOREIGN KEY - * Cs - column types which are stored in table_t::columns_type - */ - template - struct table_fk_references_impl; + elements_type elements; - template - struct table_fk_references_impl { - using type = std::tuple<>; - }; +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + table_t(std::string name_, elements_type elements_) : + basic_table{std::move(name_)}, elements{std::move(elements_)} {} +#endif - template - struct table_fk_references_impl { - using head_tuple = typename column_fk_references::type; - using tail_tuple = typename table_fk_references_impl::type; - using type = typename conc_tuple::type; - }; + table_t without_rowid() const { + return {this->name, this->elements}; + } - /** - * T is table_t type - * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User) + /* + * Returns the number of elements of the specified type. */ - template - struct table_fk_references; + template class Trait> + static constexpr int count_of() { + using sequence_of = filter_tuple_sequence_t; + return int(sequence_of::size()); + } - template - struct table_fk_references, O> { - using table_type = table_t; + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_with() { + using filtered_index_sequence = col_index_sequence_with; + return int(filtered_index_sequence::size()); + } - using type = typename table_fk_references_impl::type; - }; + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_excluding() { + using excluded_col_index_sequence = col_index_sequence_excluding; + return int(excluded_col_index_sequence::size()); + } /** - * S - storage class - * O - type mapped to S + * Function used to get field value from object by mapped member pointer/setter/getter. + * + * For a setter the corresponding getter has to be searched, + * so the method returns a pointer to the field as returned by the found getter. + * Otherwise the method invokes the member pointer and returns its result. */ - template - struct storage_fk_references_impl; - - template - struct storage_fk_references_impl, O> { - using type = std::tuple<>; - }; + template = true> + decltype(auto) object_field_value(const object_type& object, M memberPointer) const { + return polyfill::invoke(memberPointer, object); + } + + template = true> + const member_field_type_t* object_field_value(const object_type& object, M memberPointer) const { + using field_type = member_field_type_t; + const field_type* res = nullptr; + iterate_tuple(this->elements, + col_index_sequence_with_field_type{}, + call_as_template_base([&res, &memberPointer, &object](const auto& column) { + if(compare_any(column.setter, memberPointer)) { + res = &polyfill::invoke(column.member_pointer, object); + } + })); + return res; + } - template - struct storage_fk_references_impl, O> { - using head_tuple = typename table_fk_references::type; - using tail_tuple = typename storage_fk_references_impl, O>::type; - using type = typename conc_tuple::type; - }; + const basic_generated_always::storage_type* + find_column_generated_storage_type(const std::string& name) const { + const basic_generated_always::storage_type* result = nullptr; +#if SQLITE_VERSION_NUMBER >= 3031000 + iterate_tuple(this->elements, + col_index_sequence_with{}, + [&result, &name](auto& column) { + if(column.name != name) { + return; + } + using generated_op_index_sequence = + filter_tuple_sequence_t, + is_generated_always>; + constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); + result = &get(column.constraints).storage; + }); +#else + (void)name; +#endif + return result; + } /** - * S - storage class - * O - type mapped to S - * type holds `std::tuple` with types that has references to O as foreign keys + * Call passed lambda with all defined primary keys. */ - template - struct storage_fk_references { - using impl_type = typename S::impl_type; - - using type = typename storage_fk_references_impl::type; - }; - - } - } -} + template + void for_each_primary_key(L&& lambda) const { + using pk_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, pk_index_sequence{}, lambda); + } -// #include "function.h" + std::vector composite_key_columns_names() const { + std::vector res; + this->for_each_primary_key([this, &res](auto& primaryKey) { + res = this->composite_key_columns_names(primaryKey); + }); + return res; + } -#include // std::string -#include -#include // std::tuple -#include // std::function + std::vector primary_key_column_names() const { + using pkcol_index_sequence = col_index_sequence_with; -namespace sqlite_orm { + if(pkcol_index_sequence::size() > 0) { + return create_from_tuple>(this->elements, + pkcol_index_sequence{}, + &column_identifier::name); + } else { + return this->composite_key_columns_names(); + } + } - struct arg_values; + template + void for_each_primary_key_column(L&& lambda) const { + iterate_tuple(this->elements, + col_index_sequence_with{}, + call_as_template_base([&lambda](const auto& column) { + lambda(column.member_pointer); + })); + this->for_each_primary_key([&lambda](auto& primaryKey) { + iterate_tuple(primaryKey.columns, lambda); + }); + } - namespace internal { + template + std::vector composite_key_columns_names(const primary_key_t& primaryKey) const { + return create_from_tuple>(primaryKey.columns, + [this, empty = std::string{}](auto& memberPointer) { + if(const std::string* columnName = + this->find_column_name(memberPointer)) { + return *columnName; + } else { + return empty; + } + }); + } - struct function_base { - using func_call = std::function< - void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; - using final_call = std::function; + /** + * Searches column name by class member pointer passed as the first argument. + * @return column name or empty string if nothing found. + */ + template = true> + const std::string* find_column_name(M m) const { + const std::string* res = nullptr; + using field_type = member_field_type_t; + iterate_tuple(this->elements, + col_index_sequence_with_field_type{}, + [&res, m](auto& c) { + if(compare_any(c.member_pointer, m) || compare_any(c.setter, m)) { + res = &c.name; + } + }); + return res; + } - std::string name; - int argumentsCount = 0; - std::function create; - void (*destroy)(int*) = nullptr; + /** + * Call passed lambda with all defined foreign keys. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_foreign_key(L&& lambda) const { + using fk_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, fk_index_sequence{}, lambda); + } - function_base(decltype(name) name_, - decltype(argumentsCount) argumentsCount_, - decltype(create) create_, - decltype(destroy) destroy_) : - name(move(name_)), - argumentsCount(argumentsCount_), create(move(create_)), destroy(destroy_) {} - }; + template + void for_each_foreign_key_to(L&& lambda) const { + using fk_index_sequence = filter_tuple_sequence_t; + using filtered_index_sequence = filter_tuple_sequence_t::template fn, + target_type_t, + fk_index_sequence>; + iterate_tuple(this->elements, filtered_index_sequence{}, lambda); + } - struct scalar_function_t : function_base { - func_call run; + /** + * Call passed lambda with all defined columns. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_column(L&& lambda) const { + using col_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, col_index_sequence{}, lambda); + } - scalar_function_t(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(run) run_, - decltype(destroy) destroy_) : - function_base{move(name_), argumentsCount_, move(create_), destroy_}, - run(move(run_)) {} - }; + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template class OpTraitFn, class L> + void for_each_column_excluding(L&& lambda) const { + iterate_tuple(this->elements, col_index_sequence_excluding{}, lambda); + } - struct aggregate_function_t : function_base { - func_call step; - final_call finalCall; + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template = true> + void for_each_column_excluding(L&& lambda) const { + this->for_each_column_excluding(lambda); + } - aggregate_function_t(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(step) step_, - decltype(finalCall) finalCall_, - decltype(destroy) destroy_) : - function_base{move(name_), argumentsCount_, move(create_), destroy_}, - step(move(step_)), finalCall(move(finalCall_)) {} + std::vector get_table_info() const; }; - // got it from here https://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature - template - struct is_scalar_function_impl { - - template - struct SFINAE; - - template - struct SFINAE {}; - - template - static char test(SFINAE*); - - template - static int test(...); + template + struct is_table : std::false_type {}; - static constexpr bool has = sizeof(test(0)) == sizeof(char); - }; + template + struct is_table> : std::true_type {}; - template - struct is_aggregate_function_impl { + template + struct virtual_table_t : basic_table { + using module_details_type = M; + using object_type = typename module_details_type::object_type; + using elements_type = typename module_details_type::columns_type; - template - struct SFINAE; + static constexpr bool is_without_rowid_v = false; + using is_without_rowid = polyfill::bool_constant; - template - struct SFINAE {}; + module_details_type module_details; - template - static char test(SFINAE*); +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + virtual_table_t(std::string name, module_details_type module_details) : + basic_table{std::move(name)}, module_details{std::move(module_details)} {} +#endif - template - static int test(...); + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template class OpTraitFn, class L> + void for_each_column_excluding(L&& lambda) const { + this->module_details.template for_each_column_excluding(lambda); + } - template - static char test2(SFINAE*); + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template = true> + void for_each_column_excluding(L&& lambda) const { + this->module_details.template for_each_column_excluding(lambda); + } - template - static int test2(...); + /** + * Call passed lambda with all defined columns. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_column(L&& lambda) const { + this->module_details.for_each_column(lambda); + } - static constexpr bool has = sizeof(test(0)) == sizeof(char); - static constexpr bool has2 = sizeof(test2(0)) == sizeof(char); - static constexpr bool has_both = has && has2; + template = true> + const std::string* find_column_name(L m) const { + const std::string* res = nullptr; + for_each_column([&res, m](auto& c) { + if(compare_any(c.member_pointer, m) || compare_any(c.setter, m)) { + res = &c.name; + } + }); + return res; + } }; - template - struct is_scalar_function : std::integral_constant::has> {}; - - template - struct is_aggregate_function : std::integral_constant::has_both> {}; + template + struct is_virtual_table : std::false_type {}; - template - struct scalar_run_member_pointer { - using type = decltype(&F::operator()); - }; + template + struct is_virtual_table> : std::true_type {}; - template - struct aggregate_run_member_pointer { - using step_type = decltype(&F::step); - using fin_type = decltype(&F::fin); - }; + template + struct using_fts5_t { + using object_type = T; + using columns_type = std::tuple; - template - struct member_function_arguments; + columns_type columns; - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple::type...>; - using return_type = R; - }; + using_fts5_t(columns_type columns) : columns(std::move(columns)) {} - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple::type...>; - using return_type = R; - }; + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template class OpTraitFn, class L> + void for_each_column_excluding(L&& lambda) const { + iterate_tuple(this->columns, col_index_sequence_excluding{}, lambda); + } - template - struct callable_arguments_impl; + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template = true> + void for_each_column_excluding(L&& lambda) const { + this->for_each_column_excluding(lambda); + } - template - struct callable_arguments_impl { - using function_member_pointer = typename scalar_run_member_pointer::type; - using args_tuple = typename member_function_arguments::tuple_type; - using return_type = typename member_function_arguments::return_type; - }; + /** + * Call passed lambda with all defined columns. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_column(L&& lambda) const { + using col_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->columns, col_index_sequence{}, lambda); + } + }; + + template + bool exists_in_composite_primary_key(const table_t& table, + const column_field& column) { + bool res = false; + table.for_each_primary_key([&column, &res](auto& primaryKey) { + using colrefs_tuple = decltype(primaryKey.columns); + using same_type_index_sequence = + filter_tuple_sequence_t>::template fn, + member_field_type_t>; + iterate_tuple(primaryKey.columns, same_type_index_sequence{}, [&res, &column](auto& memberPointer) { + if(compare_any(memberPointer, column.member_pointer) || compare_any(memberPointer, column.setter)) { + res = true; + } + }); + }); + return res; + } - template - struct callable_arguments_impl { - using step_function_member_pointer = typename aggregate_run_member_pointer::step_type; - using fin_function_member_pointer = typename aggregate_run_member_pointer::fin_type; - using args_tuple = typename member_function_arguments::tuple_type; - using return_type = typename member_function_arguments::return_type; - }; + template + bool exists_in_composite_primary_key(const virtual_table_t& /*virtualTable*/, + const column_field& /*column*/) { + return false; + } + } - template - struct callable_arguments : callable_arguments_impl::value> {}; + template>::object_type> + internal::using_fts5_t using_fts5(Cs... columns) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(columns)...)}); + } - template - struct function_call { - using function_type = F; - using args_tuple = std::tuple; + template + internal::using_fts5_t using_fts5(Cs... columns) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(columns)...)}); + } - args_tuple args; - }; + /** + * Factory function for a table definition. + * + * The mapped object type is determined implicitly from the first column definition. + */ + template>::object_type> + internal::table_t make_table(std::string name, Cs... args) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::make_tuple(std::forward(args)...)}); } /** - * Used to call user defined function: `func(...);` + * Factory function for a table definition. + * + * The mapped object type is explicitly specified. */ - template - internal::function_call func(Args... args) { - using args_tuple = std::tuple; - using function_args_tuple = typename internal::callable_arguments::args_tuple; - constexpr auto argsCount = std::tuple_size::value; - constexpr auto functionArgsCount = std::tuple_size::value; - static_assert( - (argsCount == functionArgsCount && !std::is_same>::value) || - std::is_same>::value, - "Arguments amount does not match"); - return {std::make_tuple(std::forward(args)...)}; + template + internal::table_t make_table(std::string name, Cs... args) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::make_tuple(std::forward(args)...)}); } + template + internal::virtual_table_t make_virtual_table(std::string name, M module_details) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(module_details)}); + } } +#pragma once -namespace sqlite_orm { - - namespace internal { - - /** - * This is a proxy class used to define what type must have result type depending on select - * arguments (member pointer, aggregate functions, etc). Below you can see specializations - * for different types. E.g. specialization for internal::length_t has `type` int cause - * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals - * c++ SELECT return type for T - * T - C++ type - * SFINAE - sfinae argument - */ - template - struct column_result_t; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct column_result_t, void> { - using type = std::optional::type>; - }; - -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct column_result_t::value && - !std::is_member_function_pointer::value>::type> { - using type = F; - }; +#include // std::string - template - struct column_result_t, void> { - using type = bool; - }; +// #include "functional/cxx_universal.h" +// ::nullptr_t +// #include "functional/static_magic.h" - template - struct column_result_t, void> { - using type = bool; - }; +// #include "tuple_helper/tuple_filter.h" - /** - * Common case for all getter types. Getter types are defined in column.h file - */ - template - struct column_result_t::value>::type> { - using type = typename getter_traits::field_type; - }; +// #include "tuple_helper/tuple_iteration.h" - /** - * Common case for all setter types. Setter types are defined in column.h file - */ - template - struct column_result_t::value>::type> { - using type = typename setter_traits::field_type; - }; +// #include "type_traits.h" - template - struct column_result_t, void> { - using type = R; - }; +// #include "select_constraints.h" - template - struct column_result_t, void> { - using type = typename callable_arguments::return_type; - }; +// #include "storage_lookup.h" - template - struct column_result_t, S, X>, void> { - using type = std::unique_ptr::type>; - }; +#include // std::true_type, std::false_type, std::remove_const, std::enable_if, std::is_base_of, std::is_void +#include +#include // std::index_sequence, std::make_index_sequence - template - struct column_result_t, void> { - using type = int; - }; +// #include "functional/cxx_universal.h" - template - struct column_result_t { - using type = int; - }; +// #include "functional/cxx_type_traits_polyfill.h" - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; +// #include "type_traits.h" - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; +namespace sqlite_orm { + namespace internal { - template - struct column_result_t, void> { - using type = std::string; - }; + template + struct storage_t; - template - struct column_result_t, void> { - using type = double; - }; + template + using db_objects_tuple = std::tuple; - template - struct column_result_t, void> { - using type = double; - }; + template + struct is_storage : std::false_type {}; - template - struct column_result_t, void> { - using type = double; - }; + template + struct is_storage> : std::true_type {}; + template + struct is_storage> : std::true_type {}; - template - struct column_result_t, void> { - using type = double; - }; + template + struct is_db_objects : std::false_type {}; - template - struct column_result_t, void> { - using type = double; - }; + template + struct is_db_objects> : std::true_type {}; + template + struct is_db_objects> : std::true_type {}; - template - struct column_result_t, void> { - using type = int; - }; + /** + * std::true_type if given object is mapped, std::false_type otherwise. + * + * Note: unlike table_t<>, index_t<>::object_type and trigger_t<>::object_type is always void. + */ + template + struct object_type_matches : polyfill::conjunction>>, + std::is_same>> {}; - template - struct column_result_t, void> { - using type = int; - }; + /** + * std::true_type if given lookup type (object) is mapped, std::false_type otherwise. + */ + template + struct lookup_type_matches : polyfill::disjunction> {}; + } - template - struct column_result_t, void> { - using type = int; - }; + // pick/lookup metafunctions + namespace internal { - template - struct column_result_t, void> { - using type = int; - }; + /** + * Indirect enabler for DBO, accepting an index to disambiguate non-unique DBOs + */ + template + struct enable_found_table : std::enable_if::value, DBO> {}; - template - struct column_result_t, void> { - using type = int; - }; + /** + * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. + * + * Lookup - mapped data type + * Seq - index sequence matching the number of DBOs + * DBOs - db_objects_tuple type + */ + template + struct storage_pick_table; - template - struct column_result_t { - using type = int64; - }; + template + struct storage_pick_table, db_objects_tuple> + : enable_found_table... {}; - template - struct column_result_t { - using type = int64; - }; + /** + * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. + * + * Lookup - 'table' type, mapped data type + * DBOs - db_objects_tuple type, possibly const-qualified + */ + template + using storage_pick_table_t = typename storage_pick_table::value>, + std::remove_const_t>::type; - template - struct column_result_t { - using type = int64; - }; + /** + * Find a table definition (`table_t`) from a tuple of database objects; + * `std::nonesuch` if not found. + * + * DBOs - db_objects_tuple type + * Lookup - mapped data type + */ + template + struct storage_find_table : polyfill::detected_or {}; - template - struct column_result_t, void> { - using type = int64; - }; + /** + * Find a table definition (`table_t`) from a tuple of database objects; + * `std::nonesuch` if not found. + * + * DBOs - db_objects_tuple type, possibly const-qualified + * Lookup - mapped data type + */ + template + using storage_find_table_t = typename storage_find_table>::type; + +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct is_mapped : std::false_type {}; + template + struct is_mapped>> : std::true_type {}; +#else + template> + struct is_mapped : std::true_type {}; + template + struct is_mapped : std::false_type {}; +#endif - template - struct column_result_t, void> { - using type = int64; - }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_mapped_v = is_mapped::value; + } +} - template - struct column_result_t, void> { - using type = int64; - }; +// runtime lookup functions +namespace sqlite_orm { + namespace internal { + /** + * Pick the table definition for the specified lookup type from the given tuple of schema objects. + * + * Note: This function requires Lookup to be mapped, otherwise it is removed from the overload resolution set. + */ + template = true> + auto& pick_table(DBOs& dbObjects) { + using table_type = storage_pick_table_t; + return std::get(dbObjects); + } - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; + template = true> + decltype(auto) lookup_table_name(const DBOs& dbObjects); - template - struct column_result_t> : column_result_t {}; + } +} - template - struct column_result_t, void> { - using type = std::tuple::type>::type...>; - }; +// interface functions +namespace sqlite_orm { + namespace internal { - template - struct column_result_t> : column_result_t {}; + template + using tables_index_sequence = filter_tuple_sequence_t; - template - struct column_result_t::value>::type> { - using left_type = typename T::left_type; - using right_type = typename T::right_type; - using left_result = typename column_result_t::type; - using right_result = typename column_result_t::type; - static_assert(std::is_same::value, - "Compound subselect queries must return same types"); - using type = left_result; - }; + template = true> + int foreign_keys_count(const DBOs& dbObjects) { + int res = 0; + iterate_tuple(dbObjects, tables_index_sequence{}, [&res](const auto& table) { + res += table.template count_of(); + }); + return res; + } - template - struct column_result_t::value>::type> { - using type = typename T::result_type; - }; + template> + decltype(auto) lookup_table_name(const DBOs& dbObjects) { + return static_if>( + [](const auto& dbObjects) -> const std::string& { + return pick_table(dbObjects).name; + }, + empty_callable())(dbObjects); + } /** - * Result for the most simple queries like `SELECT 1` + * Find column name by its type and member pointer. */ - template - struct column_result_t::value>::type> { - using type = T; - }; + template = true> + const std::string* find_column_name(const DBOs& dbObjects, F O::*field) { + return pick_table(dbObjects).find_column_name(field); + } /** - * Result for the most simple queries like `SELECT 'ototo'` + * Materialize column pointer: + * 1. by explicit object type and member pointer. */ - template - struct column_result_t { - using type = std::string; - }; + template = true> + constexpr decltype(auto) materialize_column_pointer(const DBOs&, const column_pointer& cp) { + return cp.field; + } - template - struct column_result_t { - using type = std::string; - }; + /** + * Find column name by: + * 1. by explicit object type and member pointer. + */ + template = true> + const std::string* find_column_name(const DBOs& dbObjects, const column_pointer& cp) { + auto field = materialize_column_pointer(dbObjects, cp); + return pick_table(dbObjects).find_column_name(field); + } + } +} +#pragma once - template - struct column_result_t, void> : column_result_t::type, void> {}; +#include // std::string - template - struct column_result_t, void> { - using type = typename storage_traits::storage_mapped_columns::type; - }; +// #include "constraints.h" - template - struct column_result_t, void> { - using type = T; - }; +// #include "serializer_context.h" - template - struct column_result_t, void> { - using type = T; - }; +// #include "storage_lookup.h" - template - struct column_result_t, void> { - using type = R; - }; +namespace sqlite_orm { - template - struct column_result_t, void> { - using type = bool; - }; + namespace internal { - template - struct column_result_t, void> { - using type = bool; - }; + template + std::string serialize(const T& t, const C& context); - template - struct column_result_t, void> { - using type = bool; - }; + /** + * Serialize default value of a column's default valu + */ + template + std::string serialize_default_value(const default_t& dft) { + db_objects_tuple<> dbObjects; + serializer_context> context{dbObjects}; + return serialize(dft.value, context); + } - template - struct column_result_t, void> : column_result_t {}; } + } #pragma once +#include +#include // std::unique_ptr/shared_ptr, std::make_unique/std::make_shared +#include // std::system_error #include // std::string -#include // std::remove_reference, std::is_same, std::is_base_of +#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type +#include // std::identity +#include // std::stringstream +#include // std::map #include // std::vector -#include // std::tuple_size, std::tuple_element -#include // std::reverse, std::find_if +#include // std::tuple_size, std::tuple, std::make_tuple, std::tie +#include // std::forward, std::pair +#include // std::for_each, std::ranges::for_each +// #include "functional/cxx_optional.h" -// #include "column_result.h" +// #include "functional/cxx_universal.h" -// #include "static_magic.h" +// #include "functional/cxx_functional_polyfill.h" -// #include "typed_comparator.h" +// #include "functional/static_magic.h" -// #include "constraints.h" +// #include "functional/mpl.h" -// #include "tuple_helper/tuple_helper.h" +// #include "tuple_helper/tuple_traits.h" -// #include "table_info.h" +// #include "tuple_helper/tuple_filter.h" + +// #include "tuple_helper/tuple_transformer.h" + +// #include "tuple_helper/tuple_iteration.h" + +// #include "type_traits.h" + +// #include "alias.h" + +// #include "error_code.h" // #include "type_printer.h" -// #include "column.h" +// #include "constraints.h" -namespace sqlite_orm { +// #include "field_printer.h" - namespace internal { +// #include "rowid.h" - template - struct table_base { +// #include "operators.h" - /** - * Table name. - */ - std::string name; +// #include "select_constraints.h" - static constexpr const bool is_without_rowid = _without_rowid; - }; +// #include "core_functions.h" - template - struct table_without_rowid_t; +// #include "conditions.h" - /** - * Template for table interface class. - */ - template - struct table_template : table_base<_without_rowid> { - using object_type = T; - using columns_type = std::tuple; - using super = table_base<_without_rowid>; +// #include "statement_binder.h" - static constexpr const int columns_count = static_cast(std::tuple_size::value); +// #include "column_result.h" - using super::name; - columns_type columns; +#include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of +#include // std::tuple +#include // std::reference_wrapper - table_template(std::string name_, columns_type columns_) : - super{std::move(name_)}, columns{std::move(columns_)} {} +// #include "functional/cxx_universal.h" - table_without_rowid_t without_rowid() const { - return {name, columns}; - } +// #include "tuple_helper/tuple_traits.h" - /** - * Function used to get field value from object by mapped member pointer/setter/getter - */ - template - const F* get_object_field_pointer(const object_type& obj, C c) const { - const F* res = nullptr; - this->for_each_column_with_field_type([&res, &c, &obj](auto& col) { - using column_type = typename std::remove_reference::type; - using member_pointer_t = typename column_type::member_pointer_t; - using getter_type = typename column_type::getter_type; - using setter_type = typename column_type::setter_type; - // Make static_if have at least one input as a workaround for GCC bug: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 - if(!res) { - static_if{}>([&res, &obj, &col](const C& c_) { - if(compare_any(col.member_pointer, c_)) { - res = &(obj.*col.member_pointer); - } - })(c); - } - if(!res) { - static_if{}>([&res, &obj, &col](const C& c_) { - if(compare_any(col.getter, c_)) { - res = &((obj).*(col.getter))(); - } - })(c); - } - if(!res) { - static_if{}>([&res, &obj, &col](const C& c_) { - if(compare_any(col.setter, c_)) { - res = &((obj).*(col.getter))(); - } - })(c); - } - }); - return res; - } +// #include "tuple_helper/tuple_fy.h" - /** - * @return vector of column names of table. - */ - std::vector column_names() const { - std::vector res; - this->for_each_column([&res](auto& c) { - res.push_back(c.name); - }); - return res; - } +#include - /** - * Calls **l** with every primary key dedicated constraint - */ - template - void for_each_primary_key(const L& l) const { - iterate_tuple(this->columns, [&l](auto& column) { - using column_type = typename std::decay::type; - static_if{}>(l)(column); - }); - } +namespace sqlite_orm { - std::vector composite_key_columns_names() const { - std::vector res; - this->for_each_primary_key([this, &res](auto& c) { - res = this->composite_key_columns_names(c); - }); - return res; - } + namespace internal { - std::vector primary_key_column_names() const { - std::vector res; - this->for_each_column_with>([&res](auto& c) { - res.push_back(c.name); - }); - if(!res.size()) { - res = this->composite_key_columns_names(); - } - return res; - } + template + struct tuplify { + using type = std::tuple; + }; + template + struct tuplify> { + using type = std::tuple; + }; - template - std::vector composite_key_columns_names(const primary_key_t& pk) const { - std::vector res; - using pk_columns_tuple = decltype(pk.columns); - res.reserve(std::tuple_size::value); - iterate_tuple(pk.columns, [this, &res](auto& v) { - if(auto columnName = this->find_column_name(v)) { - res.push_back(*columnName); - } else { - res.push_back({}); - } - }); - return res; - } + template + using tuplify_t = typename tuplify::type; + } +} - /** - * Searches column name by class member pointer passed as the first argument. - * @return column name or empty string if nothing found. - */ - template::value && - !std::is_member_function_pointer::value>::type> - const std::string* find_column_name(F O::*m) const { - const std::string* res = nullptr; - this->template for_each_column_with_field_type([&res, m](auto& c) { - if(c.member_pointer == m) { - res = &c.name; - } - }); - return res; - } +// #include "tuple_helper/tuple_filter.h" - /** - * Searches column name by class getter function member pointer passed as first argument. - * @return column name or empty string if nothing found. - */ - template - const std::string* find_column_name(G getter, - typename std::enable_if::value>::type* = nullptr) const { - const std::string* res = nullptr; - using field_type = typename getter_traits::field_type; - this->template for_each_column_with_field_type([&res, getter](auto& c) { - if(compare_any(c.getter, getter)) { - res = &c.name; - } - }); - return res; - } +// #include "type_traits.h" - /** - * Searches column name by class setter function member pointer passed as first argument. - * @return column name or empty string if nothing found. - */ - template - const std::string* find_column_name(S setter, - typename std::enable_if::value>::type* = nullptr) const { - const std::string* res = nullptr; - using field_type = typename setter_traits::field_type; - this->template for_each_column_with_field_type([&res, setter](auto& c) { - if(compare_any(c.setter, setter)) { - res = &c.name; - } - }); - return res; - } +// #include "member_traits/member_traits.h" - /** - * Iterates all columns and fires passed lambda. Lambda must have one and only templated argument Otherwise - * code will not compile. Excludes table constraints (e.g. foreign_key_t) at the end of the columns list. To - * iterate columns with table constraints use iterate_tuple(columns, ...) instead. L is lambda type. Do - * not specify it explicitly. - * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} - */ - template - void for_each_column(const L& l) const { - iterate_tuple(this->columns, [&l](auto& column) { - using column_type = typename std::decay::type; - static_if{}>(l)(column); - }); - } +// #include "mapped_type_proxy.h" - template - void for_each_column_with_field_type(const L& l) const { - iterate_tuple(this->columns, [&l](auto& column) { - using column_type = typename std::decay::type; - using field_type = typename column_field_type::type; - static_if{}>(l)(column); - }); - } +#include // std::remove_const - /** - * Iterates all columns that have specified constraints and fires passed lambda. - * Lambda must have one and only templated argument Otherwise code will not compile. - * L is lambda type. Do not specify it explicitly. - * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} - */ - template - void for_each_column_with(const L& l) const { - using tuple_helper::tuple_contains_type; - iterate_tuple(this->columns, [&l](auto& column) { - using column_type = typename std::decay::type; - using constraints_type = typename column_constraints_type::type; - static_if{}>(l)(column); - }); - } +// #include "type_traits.h" - std::vector get_table_info() const { - std::vector res; - res.reserve(size_t(this->columns_count)); - this->for_each_column([&res](auto& col) { - std::string dft; - using field_type = typename std::decay::type::field_type; - if(auto d = col.default_value()) { - dft = *d; - } - table_info i{ - -1, - col.name, - type_printer().print(), - col.not_null(), - dft, - col.template has>(), - }; - res.emplace_back(i); - }); - auto compositeKeyColumnNames = this->composite_key_columns_names(); - for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { - auto& columnName = compositeKeyColumnNames[i]; - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_info& ti) { - return ti.name == columnName; - }); - if(it != res.end()) { - it->pk = static_cast(i + 1); - } - } - return res; - } - }; +// #include "alias_traits.h" - /** - * Table interface class. - */ - template - struct table_t : table_template { - using table_template::table_template; - }; +namespace sqlite_orm { + + namespace internal { /** - * Table interface class with 'without_rowid' tag. + * If T is a recordset alias then the typename mapped_type_proxy::type is the unqualified aliased type, + * otherwise unqualified T. */ - template - struct table_without_rowid_t : table_template { - using table_template::table_template; - }; - } + template + struct mapped_type_proxy : std::remove_const {}; - /** - * Function used for table creation. Do not use table constructor - use this function - * cause table class is templated and its constructing too (just like std::make_unique or std::make_pair). - */ - template>::type::object_type> - internal::table_t make_table(const std::string& name, Cs... args) { - return {name, std::make_tuple(std::forward(args)...)}; - } + template + struct mapped_type_proxy> : std::remove_const> {}; - template - internal::table_t make_table(const std::string& name, Cs... args) { - return {name, std::make_tuple(std::forward(args)...)}; + template + using mapped_type_proxy_t = typename mapped_type_proxy::type; } } -#pragma once - -#include // std::string -#include -#include // std::nullptr_t -#include // std::system_error, std::error_code -#include // std::stringstream -#include // std::atoi -#include // std::forward, std::enable_if, std::is_same, std::remove_reference, std::false_type, std::true_type -#include // std::pair, std::make_pair -#include // std::vector -#include // std::find_if -#include // std::type_index -// #include "error_code.h" +// #include "core_functions.h" -// #include "statement_finalizer.h" +// #include "select_constraints.h" -// #include "row_extractor.h" +// #include "operators.h" -// #include "util.h" +// #include "rowid.h" -// #include "constraints.h" +// #include "alias.h" -// #include "select_constraints.h" +// #include "storage_traits.h" -// #include "field_printer.h" +#include // std::tuple -// #include "table_info.h" +// #include "functional/cxx_type_traits_polyfill.h" -// #include "sync_schema_result.h" +// #include "tuple_helper/tuple_filter.h" -// #include "field_value_holder.h" +// #include "tuple_helper/tuple_transformer.h" -#include // std::enable_if +// #include "type_traits.h" -// #include "column.h" +// #include "storage_lookup.h" namespace sqlite_orm { - namespace internal { - template - struct field_value_holder; + namespace internal { - template - struct field_value_holder::returns_lvalue>::type> { - using type = typename getter_traits::field_type; + namespace storage_traits { - const type& value; - }; + /** + * DBO - db object (table) + */ + template + struct storage_mapped_columns_impl + : tuple_transformer, is_column>, field_type_t> {}; - template - struct field_value_holder::returns_lvalue>::type> { - using type = typename getter_traits::field_type; + template<> + struct storage_mapped_columns_impl { + using type = std::tuple<>; + }; - type value; - }; + /** + * DBOs - db_objects_tuple type + * Lookup - mapped or unmapped data type + */ + template + struct storage_mapped_columns : storage_mapped_columns_impl> {}; + } } } +// #include "function.h" + +#include +#include +#include // std::string +#include // std::tuple +#include // std::function +#include // std::min +#include // std::move, std::forward + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { - namespace internal { + struct arg_values; - struct storage_impl_base { + template + struct pointer_arg; + template + class pointer_binding; - bool table_exists(const std::string& tableName, sqlite3* db) const { - auto result = false; - std::stringstream ss; - ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = '" - << "table" - << "' AND name = '" << tableName << "'"; - auto query = ss.str(); - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void* data, int argc, char** argv, char** /*azColName*/) -> int { - auto& res = *(bool*)data; - if(argc) { - res = !!std::atoi(argv[0]); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } + namespace internal { - void rename_table(sqlite3* db, const std::string& oldName, const std::string& newName) const { - std::stringstream ss; - ss << "ALTER TABLE " << oldName << " RENAME TO " << newName; - perform_void_exec(db, ss.str()); - } + struct user_defined_function_base { + using func_call = std::function< + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; - static bool calculate_remove_add_columns(std::vector& columnsToAdd, - std::vector& storageTableInfo, - std::vector& dbTableInfo) { - bool notEqual = false; + std::string name; + int argumentsCount = 0; + std::function create; + void (*destroy)(int*) = nullptr; - // iterate through storage columns - for(size_t storageColumnInfoIndex = 0; storageColumnInfoIndex < storageTableInfo.size(); - ++storageColumnInfoIndex) { +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + user_defined_function_base(decltype(name) name_, + decltype(argumentsCount) argumentsCount_, + decltype(create) create_, + decltype(destroy) destroy_) : + name(std::move(name_)), + argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} +#endif + }; - // get storage's column info - auto& storageColumnInfo = storageTableInfo[storageColumnInfoIndex]; - auto& columnName = storageColumnInfo.name; + struct user_defined_scalar_function_t : user_defined_function_base { + func_call run; - // search for a column in db eith the same name - auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto& ti) { - return ti.name == columnName; - }); - if(dbColumnInfoIt != dbTableInfo.end()) { - auto& dbColumnInfo = *dbColumnInfoIt; - auto columnsAreEqual = - dbColumnInfo.name == storageColumnInfo.name && - dbColumnInfo.notnull == storageColumnInfo.notnull && - (dbColumnInfo.dflt_value.length() > 0) == (storageColumnInfo.dflt_value.length() > 0) && - dbColumnInfo.pk == storageColumnInfo.pk; - if(!columnsAreEqual) { - notEqual = true; - break; - } - dbTableInfo.erase(dbColumnInfoIt); - storageTableInfo.erase(storageTableInfo.begin() + - static_cast(storageColumnInfoIndex)); - --storageColumnInfoIndex; - } else { - columnsToAdd.push_back(&storageColumnInfo); - } - } - return notEqual; - } + user_defined_scalar_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(run) run_, + decltype(destroy) destroy_) : + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + run(std::move(run_)) {} + }; - std::vector get_table_info(const std::string& tableName, sqlite3* db) const { - std::vector result; - auto query = "PRAGMA table_info('" + tableName + "')"; - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void* data, int argc, char** argv, char**) -> int { - auto& res = *(std::vector*)data; - if(argc) { - auto index = 0; - auto cid = std::atoi(argv[index++]); - std::string name = argv[index++]; - std::string type = argv[index++]; - bool notnull = !!std::atoi(argv[index++]); - std::string dflt_value = argv[index] ? argv[index] : ""; - index++; - auto pk = std::atoi(argv[index++]); - res.push_back(table_info(cid, name, type, notnull, dflt_value, pk)); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } + struct user_defined_aggregate_function_t : user_defined_function_base { + func_call step; + final_call finalCall; + + user_defined_aggregate_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(step) step_, + decltype(finalCall) finalCall_, + decltype(destroy) destroy_) : + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + step(std::move(step_)), finalCall(std::move(finalCall_)) {} }; - /** - * This is a generic implementation. Used as a tail in storage_impl inheritance chain - */ - template - struct storage_impl; + template + using scalar_call_function_t = decltype(&F::operator()); - template - struct storage_impl : public storage_impl { - using table_type = H; - using super = storage_impl; + template + using aggregate_step_function_t = decltype(&F::step); - storage_impl(H h, Ts... ts) : super(std::forward(ts)...), table(std::move(h)) {} + template + using aggregate_fin_function_t = decltype(&F::fin); - table_type table; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v>> = + true; - template - void for_each(const L& l) { - this->super::for_each(l); - l(*this); - } + template + SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v< + F, + polyfill::void_t, + aggregate_fin_function_t, + std::enable_if_t>::value>, + std::enable_if_t>::value>>> = + true; -#if SQLITE_VERSION_NUMBER >= 3006019 + template + struct member_function_arguments; - /** - * Returns foreign keys count in table definition - */ - int foreign_keys_count() { - auto res = 0; - iterate_tuple(this->table.columns, [&res](auto& c) { - if(internal::is_foreign_key::type>::value) { - ++res; - } - }); - return res; - } + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...) const; + using tuple_type = std::tuple...>; + using return_type = R; + }; -#endif + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...); + using tuple_type = std::tuple...>; + using return_type = R; + }; - /** - * Is used to get column name by member pointer to a base class. - * Main difference between `column_name` and `column_name_simple` is that - * `column_name` has SFINAE check for type equality but `column_name_simple` has not. - */ - template - const std::string* column_name_simple(F O::*m) const { - return this->table.find_column_name(m); - } + template + struct callable_arguments_impl; - /** - * Cute function used to find column name by its type and member pointer. Uses SFINAE to - * skip inequal type O. - */ - template - const std::string* column_name(F O::*m, - typename std::enable_if::value>::type* = nullptr) const { - return this->table.find_column_name(m); - } + template + struct callable_arguments_impl>> { + using args_tuple = typename member_function_arguments>::tuple_type; + using return_type = typename member_function_arguments>::return_type; + }; - /** - * Opposite version of function defined above. Just calls same function in superclass. - */ - template - const std::string* - column_name(F O::*m, typename std::enable_if::value>::type* = nullptr) const { - return this->super::column_name(m); - } + template + struct callable_arguments_impl>> { + using args_tuple = typename member_function_arguments>::tuple_type; + using return_type = typename member_function_arguments>::return_type; + }; - template - const std::string* column_name(const column_pointer& c, - typename std::enable_if::value>::type* = nullptr) const { - return this->column_name_simple(c.field); - } + template + struct callable_arguments : callable_arguments_impl {}; - template - const std::string* - column_name(const column_pointer& c, - typename std::enable_if::value>::type* = nullptr) const { - return this->super::column_name(c); - } + template + struct function_call { + using function_type = F; + using args_tuple = std::tuple; - template - const auto& get_impl(typename std::enable_if::value>::type* = nullptr) const { - return *this; - } + args_tuple args; + }; - template - const auto& get_impl(typename std::enable_if::value>::type* = nullptr) const { - return this->super::template get_impl(); - } + template + struct unpacked_arg { + using type = T; + }; + template + struct unpacked_arg> { + using type = typename callable_arguments::return_type; + }; + template + using unpacked_arg_t = typename unpacked_arg::type; - template - auto& get_impl(typename std::enable_if::value>::type* = nullptr) { - return *this; - } + template + SQLITE_ORM_CONSTEVAL bool expected_pointer_value() { + static_assert(polyfill::always_false_v, "Expected a pointer value for I-th argument"); + return false; + } - template - auto& get_impl(typename std::enable_if::value>::type* = nullptr) { - return this->super::template get_impl(); - } + template + constexpr bool is_same_pvt_v = expected_pointer_value(); - template - const auto* find_table(typename std::enable_if::value>::type* = nullptr) const { - return &this->table; - } + // Always allow binding nullptr to a pointer argument + template + constexpr bool is_same_pvt_v> = true; - template - const auto* find_table(typename std::enable_if::value>::type* = nullptr) const { - return this->super::template find_table(); - } +#if __cplusplus >= 201703L // C++17 or later + template + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { + constexpr bool valid = Binding == PointerArg; + static_assert(valid, "Pointer value types of I-th argument do not match"); + return valid; + } - std::string find_table_name(std::type_index ti) const { - std::type_index thisTypeIndex{typeid(typename H::object_type)}; - if(thisTypeIndex == ti) { - return this->table.name; - } else { - return this->super::find_table_name(ti); - } - } + template + constexpr bool + is_same_pvt_v> = + assert_same_pointer_type(); +#else + template + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { + constexpr bool valid = Binding::value == PointerArg::value; + static_assert(valid, "Pointer value types of I-th argument do not match"); + return valid; + } - void add_column(const table_info& ti, sqlite3* db) const { - std::stringstream ss; - ss << "ALTER TABLE " << this->table.name << " ADD COLUMN " << ti.name; - ss << " " << ti.type; - if(ti.pk) { - ss << " PRIMARY KEY"; - } - if(ti.notnull) { - ss << " NOT NULL"; - } - if(ti.dflt_value.length()) { - ss << " DEFAULT " << ti.dflt_value; - } - perform_void_exec(db, ss.str()); - } + template + constexpr bool + is_same_pvt_v> = + assert_same_pointer_type(); +#endif - /** - * Copies current table to another table with a given **name**. - * Performs CREATE TABLE %name% AS SELECT %this->table.columns_names()% FROM &this->table.name%; - */ - void - copy_table(sqlite3* db, const std::string& name, const std::vector& columnsToIgnore) const { - std::stringstream ss; - std::vector columnNames; - this->table.for_each_column([&columnNames, &columnsToIgnore](auto& c) { - auto& columnName = c.name; - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](auto tableInfoPointer) { - return columnName == tableInfoPointer->name; - }); - if(columnToIgnoreIt == columnsToIgnore.end()) { - columnNames.emplace_back(columnName); - } - }); - auto columnNamesCount = columnNames.size(); - ss << "INSERT INTO " << name << " ("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << columnNames[i]; - if(i < columnNamesCount - 1) { - ss << ","; - } - ss << " "; - } - ss << ") "; - ss << "SELECT "; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << columnNames[i]; - if(i < columnNamesCount - 1) { - ss << ", "; - } - } - ss << " FROM '" << this->table.name << "' "; - perform_void_exec(db, ss.str()); - } + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) { + return true; + } + + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) { + return is_same_pvt_v; + } + + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { + return true; + } + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { + using func_arg_t = std::tuple_element_t; + using passed_arg_t = unpacked_arg_t>; + +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED + constexpr bool valid = validate_pointer_value_type, + unpacked_arg_t>>( + polyfill::bool_constant < (polyfill::is_specialization_of_v) || + (polyfill::is_specialization_of_v) > {}); + + return validate_pointer_value_types(polyfill::index_constant{}) && valid; +#else + return validate_pointer_value_types(polyfill::index_constant{}) && + validate_pointer_value_type, + unpacked_arg_t>>( + polyfill::bool_constant < (polyfill::is_specialization_of_v) || + (polyfill::is_specialization_of_v) > {}); +#endif + } + } + + /** + * Used to call user defined function: `func(...);` + */ + template + internal::function_call func(Args... args) { + using args_tuple = std::tuple; + using function_args_tuple = typename internal::callable_arguments::args_tuple; + constexpr auto argsCount = std::tuple_size::value; + constexpr auto functionArgsCount = std::tuple_size::value; + static_assert((argsCount == functionArgsCount && + !std::is_same>::value && + internal::validate_pointer_value_types( + polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || + std::is_same>::value, + "Number of arguments does not match"); + return {std::make_tuple(std::forward(args)...)}; + } + +} - sync_schema_result schema_status(sqlite3* db, bool preserve) const { +// #include "ast/special_keywords.h" + +namespace sqlite_orm { + namespace internal { + struct current_time_t {}; + struct current_date_t {}; + struct current_timestamp_t {}; + } - auto res = sync_schema_result::already_in_sync; + inline internal::current_time_t current_time() { + return {}; + } - // first let's see if table with such name exists.. - auto gottaCreateTable = !this->table_exists(this->table.name, db); - if(!gottaCreateTable) { + inline internal::current_date_t current_date() { + return {}; + } - // get table info provided in `make_table` call.. - auto storageTableInfo = this->table.get_table_info(); + inline internal::current_timestamp_t current_timestamp() { + return {}; + } +} - // now get current table info from db using `PRAGMA table_info` query.. - auto dbTableInfo = this->get_table_info(this->table.name, db); +namespace sqlite_orm { - // this vector will contain pointers to columns that gotta be added.. - std::vector columnsToAdd; + namespace internal { - if(this->calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) { - gottaCreateTable = true; - } + /** + * Obtains the result type of expressions that form the columns of a select statement. + * + * This is a proxy class used to define what type must have result type depending on select + * arguments (member pointer, aggregate functions, etc). Below you can see specializations + * for different types. E.g. specialization for internal::length_t has `type` int cause + * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals + * c++ SELECT return type for T + * DBOs - db_objects_tuple type + * T - C++ type + * SFINAE - sfinae argument + */ + template + struct column_result_t; - if(!gottaCreateTable) { // if all storage columns are equal to actual db columns but there are - // excess columns at the db.. - if(dbTableInfo.size() > 0) { - // extra table columns than storage columns - if(!preserve) { - gottaCreateTable = true; - } else { - res = decltype(res)::old_columns_removed; - } - } - } - if(gottaCreateTable) { - res = decltype(res)::dropped_and_recreated; - } else { - if(columnsToAdd.size()) { - // extra storage columns than table columns - for(auto columnPointer: columnsToAdd) { - if(columnPointer->notnull && columnPointer->dflt_value.empty()) { - gottaCreateTable = true; - break; - } - } - if(!gottaCreateTable) { - if(res == decltype(res)::old_columns_removed) { - res = decltype(res)::new_columns_added_and_old_columns_removed; - } else { - res = decltype(res)::new_columns_added; - } - } else { - res = decltype(res)::dropped_and_recreated; - } - } else { - if(res != decltype(res)::old_columns_removed) { - res = decltype(res)::already_in_sync; - } - } - } - } else { - res = decltype(res)::new_table_created; - } - return res; - } + template + using column_result_of_t = typename column_result_t::type; - private: - using self = storage_impl; +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct column_result_t, void> { + using type = std::optional>; }; - template<> - struct storage_impl<> : storage_impl_base { - - std::string find_table_name(std::type_index) const { - return {}; - } + template + struct column_result_t, void> { + using type = std::optional; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - void for_each(const L&) {} + template + struct column_result_t, void> { + using type = bool; + }; - int foreign_keys_count() { - return 0; - } + template + struct column_result_t, void> { + using type = bool; + }; - template - const void* find_table() const { - return nullptr; - } + template + struct column_result_t { + using type = std::string; }; - template - struct is_storage_impl : std::false_type {}; + template + struct column_result_t { + using type = std::string; + }; - template - struct is_storage_impl> : std::true_type {}; - } -} -#pragma once + template + struct column_result_t { + using type = std::string; + }; -#include // std::unique/shared_ptr, std::make_unique/shared -#include // std::string -#include -#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type -#include // std::ptrdiff_t -#include // std::input_iterator_tag, std::iterator_traits, std::distance -#include // std::function -#include // std::stringstream -#include // std::map -#include // std::vector -#include // std::tuple_size, std::tuple, std::make_tuple -#include // std::forward, std::pair -#include // std::find + template + struct column_result_t> : member_field_type {}; -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct column_result_t, void> { + using type = R; + }; -// #include "alias.h" + template + struct column_result_t, void> { + using type = R; + }; -// #include "row_extractor_builder.h" + template + struct column_result_t, void> { + using type = typename callable_arguments::return_type; + }; -// #include "row_extractor.h" + template + struct column_result_t, S, X, Rest...>, void> { + using type = std::unique_ptr>; + }; -// #include "mapped_row_extractor.h" + template + struct column_result_t, S, X>, void> { + using type = std::unique_ptr>; + }; -#include + template + struct column_result_t, void> { + using type = int; + }; -// #include "object_from_column_builder.h" + template + struct column_result_t { + using type = nullptr_t; + }; -#include + template + struct column_result_t { + using type = int; + }; -// #include "row_extractor.h" + template + struct column_result_t, void> : column_result_t {}; -namespace sqlite_orm { + template + struct column_result_t, void> : column_result_t {}; - namespace internal { + template + struct column_result_t, void> { + using type = std::string; + }; - struct object_from_column_builder_base { - sqlite3_stmt* stmt = nullptr; - mutable int index = 0; + template + struct column_result_t, void> { + using type = double; }; - /** - * This is a cute lambda replacement which is used in several places. - */ - template - struct object_from_column_builder : object_from_column_builder_base { - using object_type = O; + template + struct column_result_t, void> { + using type = double; + }; - object_type& object; + template + struct column_result_t, void> { + using type = double; + }; - object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : - object_from_column_builder_base{stmt_}, object(object_) {} + template + struct column_result_t, void> { + using type = double; + }; - template - void operator()(const C& c) const { - using field_type = typename C::field_type; - auto value = row_extractor().extract(this->stmt, this->index++); - if(c.member_pointer) { - this->object.*c.member_pointer = std::move(value); - } else { - ((this->object).*(c.setter))(std::move(value)); - } - } + template + struct column_result_t, void> { + using type = double; }; - } -} + template + struct column_result_t, void> { + using type = int; + }; -namespace sqlite_orm { + template + struct column_result_t, void> { + using type = int; + }; - namespace internal { + template + struct column_result_t, void> { + using type = int; + }; - /** - * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. - * Main difference from regular `row_extractor` is that this class takes table info which is required - * for constructing objects by member pointers. To construct please use `row_extractor_builder` class - * Type arguments: - * V is value type just like regular `row_extractor` has - * T is table info class `table_t` - */ - template - struct mapped_row_extractor { - using table_info_t = T; + template + struct column_result_t, void> { + using type = int; + }; - mapped_row_extractor(const table_info_t& tableInfo_) : tableInfo(tableInfo_) {} + template + struct column_result_t, void> { + using type = int; + }; - V extract(sqlite3_stmt* stmt, int /*columnIndex*/) { - V res; - object_from_column_builder builder{res, stmt}; - this->tableInfo.for_each_column(builder); - return res; - } + template + struct column_result_t { + using type = int64; + }; - const table_info_t& tableInfo; + template + struct column_result_t { + using type = int64; }; - } + template + struct column_result_t { + using type = int64; + }; -} + template + struct column_result_t, void> { + using type = int64; + }; -namespace sqlite_orm { + template + struct column_result_t, void> { + using type = int64; + }; - namespace internal { + template + struct column_result_t, void> { + using type = int64; + }; - /** - * This builder is used to construct different row extractors depending on type. - * It has two specializations: for mapped to storage types (e.g. User, Visit etc) and - * for non-mapped (e.g. std::string, QString, int etc). For non mapped its operator() returns - * generic `row_extractor`, for mapped it returns `mapped_row_extractor` instance. - */ - template - struct row_extractor_builder; + template + struct column_result_t, void> : column_result_t {}; - template - struct row_extractor_builder { + template + struct column_result_t, void> : column_result_t {}; - row_extractor operator()(const I* /*tableInfo*/) const { - return {}; - } + template + struct column_result_t, void> { + using type = tuple_cat_t>>...>; }; - template - struct row_extractor_builder { + template + struct column_result_t> : column_result_t {}; - mapped_row_extractor operator()(const I* tableInfo) const { - return {*tableInfo}; - } + template + struct column_result_t> { + using left_result = column_result_of_t; + using right_result = column_result_of_t; + static_assert(std::is_same::value, + "Compound subselect queries must return same types"); + using type = left_result; }; - template - auto make_row_extractor(const I* tableInfo) { - using builder_t = row_extractor_builder; - return builder_t{}(tableInfo); - } - - } - -} + template + struct column_result_t> { + using type = typename T::result_type; + }; -// #include "error_code.h" + template + struct column_result_t, void> { + using type = std::string; + }; -// #include "type_printer.h" + /** + * Result for the most simple queries like `SELECT 1` + */ + template + struct column_result_t> { + using type = T; + }; -// #include "tuple_helper/tuple_helper.h" + /** + * Result for the most simple queries like `SELECT 'ototo'` + */ + template + struct column_result_t { + using type = std::string; + }; -// #include "constraints.h" + template + struct column_result_t { + using type = std::string; + }; -// #include "type_is_nullable.h" + template + struct column_result_t, void> : column_result_t> {}; -// #include "field_printer.h" + template + struct column_result_t, void> + : storage_traits::storage_mapped_columns> {}; -// #include "rowid.h" + template + struct column_result_t, void> { + using type = T; + }; -// #include "operators.h" + template + struct column_result_t, void> { + using type = T; + }; -// #include "select_constraints.h" + template + struct column_result_t, void> { + using type = R; + }; -// #include "core_functions.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "conditions.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "statement_binder.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "column_result.h" + template + struct column_result_t, void> : column_result_t {}; + } +} // #include "mapped_type_proxy.h" @@ -9453,41 +11295,86 @@ namespace sqlite_orm { // #include "journal_mode.h" -// #include "field_value_holder.h" - // #include "view.h" -#include // std::shared_ptr +#include #include // std::string #include // std::forward, std::move -#include -#include // std::system_error #include // std::tuple, std::make_tuple // #include "row_extractor.h" +// #include "error_code.h" + +// #include "iterator.h" + +#include +#include // std::shared_ptr, std::unique_ptr, std::make_shared +#include // std::decay +#include // std::move +#include // std::input_iterator_tag +#include // std::system_error +#include // std::bind + +// #include "functional/cxx_universal.h" + // #include "statement_finalizer.h" // #include "error_code.h" -// #include "iterator.h" +// #include "object_from_column_builder.h" + +#include +#include // std::is_member_object_pointer + +// #include "functional/static_magic.h" + +// #include "row_extractor.h" + +namespace sqlite_orm { + + namespace internal { + + struct object_from_column_builder_base { + sqlite3_stmt* stmt = nullptr; + int index = 0; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + object_from_column_builder_base(sqlite3_stmt* stmt) : stmt{stmt} {} +#endif + }; + + /** + * Function object for building an object from a result row. + */ + template + struct object_from_column_builder : object_from_column_builder_base { + using object_type = O; -#include // std::shared_ptr, std::unique_ptr, std::make_shared -#include -#include // std::decay -#include // std::move -#include // std::ptrdiff_t -#include // std::input_iterator_tag -#include // std::system_error -#include // std::make_error_code + object_type& object; -// #include "row_extractor.h" + object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : + object_from_column_builder_base{stmt_}, object(object_) {} -// #include "statement_finalizer.h" + template + void operator()(const column_field& column) { + const auto rowExtractor = row_value_extractor>(); + auto value = rowExtractor.extract(this->stmt, this->index++); + static_if::value>( + [&value, &object = this->object](const auto& column) { + object.*column.member_pointer = std::move(value); + }, + [&value, &object = this->object](const auto& column) { + (object.*column.setter)(std::move(value)); + })(column); + } + }; + } +} -// #include "error_code.h" +// #include "storage_lookup.h" -// #include "object_from_column_builder.h" +// #include "util.h" namespace sqlite_orm { @@ -9500,15 +11387,13 @@ namespace sqlite_orm { protected: /** - * The double-indirection is so that copies of the iterator - * share the same sqlite3_stmt from a sqlite3_prepare_v2() - * call. When one finishes iterating it the pointer - * inside the shared_ptr is nulled out in all copies. + * shared_ptr is used over unique_ptr here + * so that the iterator can be copyable. */ - std::shared_ptr stmt; + std::shared_ptr stmt; // only null for the default constructed iterator - view_type* view; + view_type* view = nullptr; /** * shared_ptr is used over unique_ptr here @@ -9517,60 +11402,45 @@ namespace sqlite_orm { std::shared_ptr current; void extract_value() { - auto& storage = this->view->storage; - auto& impl = storage.template get_impl(); + auto& dbObjects = obtain_db_objects(this->view->storage); this->current = std::make_shared(); - object_from_column_builder builder{*this->current, this->stmt->get()}; - impl.table.for_each_column(builder); + object_from_column_builder builder{*this->current, this->stmt.get()}; + pick_table(dbObjects).for_each_column(builder); + } + + void next() { + this->current.reset(); + if(sqlite3_stmt* stmt = this->stmt.get()) { + perform_step(stmt, std::bind(&iterator_t::extract_value, this)); + if(!this->current) { + this->stmt.reset(); + } + } } public: - using difference_type = std::ptrdiff_t; + using difference_type = ptrdiff_t; using pointer = value_type*; using reference = value_type&; using iterator_category = std::input_iterator_tag; - iterator_t() : view(nullptr){}; + iterator_t(){}; - iterator_t(sqlite3_stmt* stmt_, view_type& view_) : - stmt(std::make_shared(stmt_)), view(&view_) { + iterator_t(statement_finalizer stmt_, view_type& view_) : stmt{std::move(stmt_)}, view{&view_} { next(); } - const value_type& operator*() const { + value_type& operator*() const { if(!this->stmt || !this->current) { - throw std::system_error(std::make_error_code(orm_error_code::trying_to_dereference_null_iterator)); + throw std::system_error{orm_error_code::trying_to_dereference_null_iterator}; } return *this->current; } - const value_type* operator->() const { + value_type* operator->() const { return &(this->operator*()); } - private: - void next() { - this->current.reset(); - if(this->stmt) { - auto statementPointer = this->stmt->get(); - auto ret = sqlite3_step(statementPointer); - switch(ret) { - case SQLITE_ROW: - this->extract_value(); - break; - case SQLITE_DONE: - this->stmt.reset(); - break; - default: { - auto db = this->view->connection.get(); - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - } - - public: iterator_t& operator++() { next(); return *this; @@ -9596,147 +11466,446 @@ namespace sqlite_orm { #include // std::vector #include // std::reference_wrapper +// #include "tuple_helper/tuple_iteration.h" + +// #include "type_traits.h" + // #include "conditions.h" +// #include "alias.h" + +// #include "select_constraints.h" + +// #include "operators.h" + +// #include "core_functions.h" + +// #include "prepared_statement.h" + +#include +#include // std::unique_ptr +#include // std::iterator_traits +#include // std::string +#include // std::integral_constant, std::declval +#include // std::pair + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "functional/cxx_functional_polyfill.h" + +// #include "tuple_helper/tuple_filter.h" + +// #include "connection_holder.h" + +#include +#include +#include // std::string + +// #include "error_code.h" + +namespace sqlite_orm { + + namespace internal { + + struct connection_holder { + + connection_holder(std::string filename_) : filename(std::move(filename_)) {} + + void retain() { + if(1 == ++this->_retain_count) { + auto rc = sqlite3_open(this->filename.c_str(), &this->db); + if(rc != SQLITE_OK) { + throw_translated_sqlite_error(db); + } + } + } + + void release() { + if(0 == --this->_retain_count) { + auto rc = sqlite3_close(this->db); + if(rc != SQLITE_OK) { + throw_translated_sqlite_error(db); + } + } + } + + sqlite3* get() const { + return this->db; + } + + int retain_count() const { + return this->_retain_count; + } + + const std::string filename; + + protected: + sqlite3* db = nullptr; + std::atomic_int _retain_count{}; + }; + + struct connection_ref { + connection_ref(connection_holder& holder_) : holder(holder_) { + this->holder.retain(); + } + + connection_ref(const connection_ref& other) : holder(other.holder) { + this->holder.retain(); + } + + connection_ref(connection_ref&& other) : holder(other.holder) { + this->holder.retain(); + } + + ~connection_ref() { + this->holder.release(); + } + + sqlite3* get() const { + return this->holder.get(); + } + + protected: + connection_holder& holder; + }; + } +} + +// #include "select_constraints.h" + +// #include "values.h" + +#include // std::vector +#include // std::tuple +#include // std::forward + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct values_t { + using args_tuple = std::tuple; + + args_tuple tuple; + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_values_v = polyfill::is_specialization_of_v; + + template + using is_values = polyfill::bool_constant>; + + template + struct dynamic_values_t { + std::vector vector; + }; + + } + + template + internal::values_t values(Args... args) { + return {{std::forward(args)...}}; + } + + template + internal::dynamic_values_t values(std::vector vector) { + return {{std::move(vector)}}; + } + +} + +// #include "mapped_type_proxy.h" + +// #include "ast/upsert_clause.h" + +#if SQLITE_VERSION_NUMBER >= 3024000 +#include // std::tuple +#include // std::forward, std::move +#endif + +// #include "../functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + namespace internal { +#if SQLITE_VERSION_NUMBER >= 3024000 + template + struct upsert_clause; + + template + struct conflict_target { + using args_tuple = std::tuple; + + args_tuple args; + + upsert_clause> do_nothing() { + return {std::move(this->args), {}}; + } + + template + upsert_clause> do_update(ActionsArgs... actions) { + return {std::move(this->args), {std::forward(actions)...}}; + } + }; + + template + struct upsert_clause, std::tuple> { + using target_args_tuple = std::tuple; + using actions_tuple = std::tuple; + + target_args_tuple target_args; + + actions_tuple actions; + }; + + template + using is_upsert_clause = polyfill::is_specialization_of; +#else + template + struct is_upsert_clause : polyfill::bool_constant {}; +#endif + } + +#if SQLITE_VERSION_NUMBER >= 3024000 + /** + * ON CONFLICT upsert clause builder function. + * @example + * storage.insert(into(), + * columns(&Employee::id, &Employee::name, &Employee::age, &Employee::address, &Employee::salary), + * values(std::make_tuple(3, "Sofia", 26, "Madrid", 15000.0), + * std::make_tuple(4, "Doja", 26, "LA", 25000.0)), + * on_conflict(&Employee::id).do_update(set(c(&Employee::name) = excluded(&Employee::name), + * c(&Employee::age) = excluded(&Employee::age), + * c(&Employee::address) = excluded(&Employee::address), + * c(&Employee::salary) = excluded(&Employee::salary)))); + */ + template + internal::conflict_target on_conflict(Args... args) { + return {std::tuple(std::forward(args)...)}; + } +#endif +} + +// #include "ast/set.h" + +#include // std::tuple, std::tuple_size +#include // std::string +#include // std::vector +#include // std::stringstream +#include // std::false_type, std::true_type + +// #include "../table_name_collector.h" + +#include // std::set +#include // std::string +#include // std::pair, std::move + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "type_traits.h" + +// #include "mapped_type_proxy.h" + // #include "select_constraints.h" -// #include "operators.h" - -// #include "tuple_helper/tuple_helper.h" +// #include "alias.h" // #include "core_functions.h" -// #include "prepared_statement.h" +// #include "storage_lookup.h" -#include -#include // std::iterator_traits -#include // std::string -#include // std::true_type, std::false_type -#include // std::pair +namespace sqlite_orm { -// #include "connection_holder.h" + namespace internal { -#include -#include // std::string -#include // std::system_error + struct table_name_collector_base { + using table_name_set = std::set>; -// #include "error_code.h" + table_name_set table_names; + }; -namespace sqlite_orm { + template + struct table_name_collector : table_name_collector_base { + using db_objects_type = DBOs; - namespace internal { + const db_objects_type& db_objects; - struct connection_holder { + table_name_collector() = default; - connection_holder(std::string filename_) : filename(move(filename_)) {} + table_name_collector(const db_objects_type& dbObjects) : db_objects{dbObjects} {} - void retain() { - ++this->_retain_count; - if(1 == this->_retain_count) { - auto rc = sqlite3_open(this->filename.c_str(), &this->db); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), - sqlite3_errmsg(this->db)); - } - } - } + template + void operator()(const T&) const {} - void release() { - --this->_retain_count; - if(0 == this->_retain_count) { - auto rc = sqlite3_close(this->db); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), - sqlite3_errmsg(this->db)); - } - } + template + void operator()(F O::*) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - sqlite3* get() const { - return this->db; + template + void operator()(const column_pointer&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - int retain_count() const { - return this->_retain_count; + template + void operator()(const alias_column_t&) { + // note: instead of accessing the column, we are interested in the type the column is aliased into + auto tableName = lookup_table_name>(this->db_objects); + this->table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } - const std::string filename; - - protected: - sqlite3* db = nullptr; - int _retain_count = 0; - }; + template + void operator()(const count_asterisk_t&) { + auto tableName = lookup_table_name(this->db_objects); + if(!tableName.empty()) { + this->table_names.emplace(std::move(tableName), ""); + } + } - struct connection_ref { - connection_ref(connection_holder& holder_) : holder(holder_) { - this->holder.retain(); + template + void operator()(const asterisk_t&) { + auto tableName = lookup_table_name>(this->db_objects); + table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } - connection_ref(const connection_ref& other) : holder(other.holder) { - this->holder.retain(); + template + void operator()(const object_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - connection_ref(connection_ref&& other) : holder(other.holder) { - this->holder.retain(); + template + void operator()(const table_rowid_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - ~connection_ref() { - this->holder.release(); + template + void operator()(const table_oid_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - sqlite3* get() const { - return this->holder.get(); + template + void operator()(const table__rowid_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } - protected: - connection_holder& holder; + template + void operator()(const highlight_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); + } }; - } -} -// #include "select_constraints.h" + template = true> + table_name_collector make_table_name_collector(const DBOs& dbObjects) { + return {dbObjects}; + } -// #include "values.h" + } -#include // std::vector -#include -#include // std::tuple -#include // std::false_type, std::true_type +} namespace sqlite_orm { namespace internal { + template + void iterate_ast(const T& t, L&& lambda); + template - struct values_t { - using args_tuple = std::tuple; + struct set_t { + using assigns_type = std::tuple; - args_tuple tuple; + assigns_type assigns; }; template - struct is_values : std::false_type {}; + struct is_set : std::false_type {}; template - struct is_values> : std::true_type {}; + struct is_set> : std::true_type {}; - template - struct dynamic_values_t { - std::vector vector; + struct dynamic_set_entry { + std::string serialized_value; + }; + + template + struct dynamic_set_t { + using context_t = C; + using entry_t = dynamic_set_entry; + using const_iterator = typename std::vector::const_iterator; + + dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {} + + dynamic_set_t(const dynamic_set_t& other) = default; + dynamic_set_t(dynamic_set_t&& other) = default; + dynamic_set_t& operator=(const dynamic_set_t& other) = default; + dynamic_set_t& operator=(dynamic_set_t&& other) = default; + + template + void push_back(assign_t assign) { + auto newContext = this->context; + newContext.skip_table_name = true; + iterate_ast(assign, this->collector); + std::stringstream ss; + ss << serialize(assign.lhs, newContext) << ' ' << assign.serialize() << ' ' + << serialize(assign.rhs, context); + this->entries.push_back({ss.str()}); + } + + const_iterator begin() const { + return this->entries.begin(); + } + + const_iterator end() const { + return this->entries.end(); + } + + void clear() { + this->entries.clear(); + this->collector.table_names.clear(); + } + + std::vector entries; + context_t context; + table_name_collector collector; }; + template + struct is_set> : std::true_type {}; + + template + struct is_dynamic_set : std::false_type {}; + + template + struct is_dynamic_set> : std::true_type {}; } + /** + * SET keyword used in UPDATE ... SET queries. + * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) + */ template - internal::values_t values(Args... args) { - return {{std::forward(args)...}}; + internal::set_t set(Args... args) { + using arg_tuple = std::tuple; + static_assert(std::tuple_size::value == + internal::count_tuple::value, + "set function accepts assign operators only"); + return {std::make_tuple(std::forward(args)...)}; } - template - internal::dynamic_values_t values(std::vector vector) { - return {{move(vector)}}; + /** + * SET keyword used in UPDATE ... SET queries. It is dynamic version. It means use can add amount of arguments now known at compilation time but known at runtime. + */ + template + internal::dynamic_set_t> dynamic_set(const S& storage) { + internal::serializer_context_builder builder(storage); + return builder(); } - } namespace sqlite_orm { @@ -9747,20 +11916,19 @@ namespace sqlite_orm { sqlite3_stmt* stmt = nullptr; connection_ref con; +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + prepared_statement_base(sqlite3_stmt* stmt, connection_ref con) : stmt{stmt}, con{std::move(con)} {} +#endif + ~prepared_statement_base() { - if(this->stmt) { - sqlite3_finalize(this->stmt); - this->stmt = nullptr; - } + sqlite3_finalize(this->stmt); } std::string sql() const { - if(this->stmt) { - if(auto res = sqlite3_sql(this->stmt)) { - return res; - } else { - return {}; - } + // note: sqlite3 internally checks for null before calling + // sqlite3_normalized_sql() or sqlite3_expanded_sql(), so check here, too, even if superfluous + if(const char* sql = sqlite3_sql(this->stmt)) { + return sql; } else { return {}; } @@ -9768,14 +11936,10 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3014000 std::string expanded_sql() const { - if(this->stmt) { - if(auto res = sqlite3_expanded_sql(this->stmt)) { - std::string result = res; - sqlite3_free(res); - return result; - } else { - return {}; - } + // note: must check return value due to SQLITE_OMIT_TRACE + using char_ptr = std::unique_ptr>; + if(char_ptr sql{sqlite3_expanded_sql(this->stmt)}) { + return sql.get(); } else { return {}; } @@ -9783,34 +11947,43 @@ namespace sqlite_orm { #endif #if SQLITE_VERSION_NUMBER >= 3026000 and defined(SQLITE_ENABLE_NORMALIZE) std::string normalized_sql() const { - if(this->stmt) { - if(auto res = sqlite3_normalized_sql(this->stmt)) { - return res; - } else { - return {}; - } + if(const char* sql = sqlite3_normalized_sql(this->stmt)) { + return sql; } else { return {}; } } #endif + +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + std::string_view column_name(int index) const { + return sqlite3_column_name(stmt, index); + } +#endif }; template struct prepared_statement_t : prepared_statement_base { using expression_type = T; - expression_type t; + expression_type expression; + + prepared_statement_t(T expression_, sqlite3_stmt* stmt_, connection_ref con_) : + prepared_statement_base{stmt_, std::move(con_)}, expression(std::move(expression_)) {} - prepared_statement_t(T t_, sqlite3_stmt* stmt_, connection_ref con_) : - prepared_statement_base{stmt_, std::move(con_)}, t(std::move(t_)) {} + prepared_statement_t(prepared_statement_t&& prepared_stmt) : + prepared_statement_base{prepared_stmt.stmt, std::move(prepared_stmt.con)}, + expression(std::move(prepared_stmt.expression)) { + prepared_stmt.stmt = nullptr; + } }; template - struct is_prepared_statement : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_prepared_statement_v = + polyfill::is_specialization_of_v; template - struct is_prepared_statement> : std::true_type {}; + using is_prepared_statement = polyfill::bool_constant>; /** * T - type of object to obtain from a database @@ -9847,14 +12020,13 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct update_all_t; - - template - struct update_all_t, Wargs...> { - using set_type = set_t; + template + struct update_all_t { + using set_type = S; using conditions_type = std::tuple; + static_assert(is_set::value, "update_all_t must have set or dynamic set as the first argument"); + set_type set; conditions_type conditions; }; @@ -9897,7 +12069,7 @@ namespace sqlite_orm { struct update_t { using type = T; - type obj; + type object; }; template @@ -9912,14 +12084,14 @@ namespace sqlite_orm { struct insert_t { using type = T; - type obj; + type object; }; template - struct is_insert : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_insert_v = polyfill::is_specialization_of_v; template - struct is_insert> : std::true_type {}; + using is_insert = polyfill::bool_constant>; template struct insert_explicit { @@ -9934,20 +12106,19 @@ namespace sqlite_orm { struct replace_t { using type = T; - type obj; + type object; }; template - struct is_replace : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_replace_v = polyfill::is_specialization_of_v; template - struct is_replace> : std::true_type {}; + using is_replace = polyfill::bool_constant>; - template + template struct insert_range_t { using iterator_type = It; - using container_object_type = typename std::iterator_traits::value_type; - using transformer_type = L; + using transformer_type = Projection; using object_type = O; std::pair range; @@ -9955,16 +12126,15 @@ namespace sqlite_orm { }; template - struct is_insert_range : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_insert_range_v = polyfill::is_specialization_of_v; - template - struct is_insert_range> : std::true_type {}; + template + using is_insert_range = polyfill::bool_constant>; - template + template struct replace_range_t { using iterator_type = It; - using container_object_type = typename std::iterator_traits::value_type; - using transformer_type = L; + using transformer_type = Projection; using object_type = O; std::pair range; @@ -9972,10 +12142,10 @@ namespace sqlite_orm { }; template - struct is_replace_range : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_replace_range_v = polyfill::is_specialization_of_v; - template - struct is_replace_range> : std::true_type {}; + template + using is_replace_range = polyfill::bool_constant>; template struct insert_raw_t { @@ -9985,10 +12155,10 @@ namespace sqlite_orm { }; template - struct is_insert_raw : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_insert_raw_v = polyfill::is_specialization_of_v; - template - struct is_insert_raw> : std::true_type {}; + template + using is_insert_raw = polyfill::bool_constant>; template struct replace_raw_t { @@ -9998,36 +12168,17 @@ namespace sqlite_orm { }; template - struct is_replace_raw : std::false_type {}; - - template - struct is_replace_raw> : std::true_type {}; - - template - struct into_t { - using type = T; - }; - - template - struct is_into : std::false_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_replace_raw_v = polyfill::is_specialization_of_v; template - struct is_into> : std::true_type {}; - - struct default_transformer { - - template - const T& operator()(const T& object) const { - return object; - } - }; + using is_replace_raw = polyfill::bool_constant>; struct default_values_t {}; template - using is_default_values = std::is_same; + using is_default_values = std::is_same; - enum class insert_constraint { + enum class conflict_action { abort, fail, ignore, @@ -10035,31 +12186,36 @@ namespace sqlite_orm { rollback, }; - template - using is_insert_constraint = std::is_same; + struct insert_constraint { + conflict_action action = conflict_action::abort; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + insert_constraint(conflict_action action) : action{action} {} +#endif + }; template - struct is_upsert_clause; + using is_insert_constraint = std::is_same; } inline internal::insert_constraint or_rollback() { - return internal::insert_constraint::rollback; + return {internal::conflict_action::rollback}; } inline internal::insert_constraint or_replace() { - return internal::insert_constraint::replace; + return {internal::conflict_action::replace}; } inline internal::insert_constraint or_ignore() { - return internal::insert_constraint::ignore; + return {internal::conflict_action::ignore}; } inline internal::insert_constraint or_fail() { - return internal::insert_constraint::fail; + return {internal::conflict_action::fail}; } inline internal::insert_constraint or_abort() { - return internal::insert_constraint::abort; + return {internal::conflict_action::abort}; } /** @@ -10074,11 +12230,6 @@ namespace sqlite_orm { return {}; } - template - internal::into_t into() { - return {}; - } - /** * Raw insert statement creation routine. Use this if `insert` with object does not fit you. This insert is designed to be able * to call any type of `INSERT` query with no limitations. @@ -10221,7 +12372,8 @@ namespace sqlite_orm { } /** - * Create a replace range statement + * Create a replace range statement. + * The objects in the range are transformed using the specified projection, which defaults to identity projection. * * @example * ``` @@ -10230,33 +12382,33 @@ namespace sqlite_orm { * auto statement = storage.prepare(replace_range(users.begin(), users.end())); * storage.execute(statement); * ``` - */ - template - internal::replace_range_t::value_type> - replace_range(It from, It to) { - return {{std::move(from), std::move(to)}}; - } - - /** - * Create an replace range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers, - * optionals or whatever. * @example * ``` * std::vector> userPointers; * userPointers.push_back(std::make_unique(1, "Eneli")); - * auto statement = storage.prepare(replace_range(userPointers.begin(), userPointers.end(), [](const std::unique_ptr &userPointer) -> const User & { - * return *userPointer; - * })); + * auto statement = storage.prepare(replace_range(userPointers.begin(), userPointers.end(), &std::unique_ptr::operator*)); * storage.execute(statement); * ``` */ - template - internal::replace_range_t replace_range(It from, It to, L transformer) { - return {{std::move(from), std::move(to)}, std::move(transformer)}; + template + auto replace_range(It from, It to, Projection project = {}) { + using O = std::decay_t(), *std::declval()))>; + return internal::replace_range_t{{std::move(from), std::move(to)}, std::move(project)}; + } + + /* + * Create a replace range statement. + * Overload of `replace_range(It, It, Projection)` with explicit object type template parameter. + */ + template + internal::replace_range_t replace_range(It from, It to, Projection project = {}) { + return {{std::move(from), std::move(to)}, std::move(project)}; } /** - * Create an insert range statement + * Create an insert range statement. + * The objects in the range are transformed using the specified projection, which defaults to identity projection. + * * @example * ``` * std::vector users; @@ -10264,30 +12416,29 @@ namespace sqlite_orm { * auto statement = storage.prepare(insert_range(users.begin(), users.end())); * storage.execute(statement); * ``` - */ - template - internal::insert_range_t::value_type> - insert_range(It from, It to) { - return {{std::move(from), std::move(to)}, internal::default_transformer{}}; - } - - /** - * Create an insert range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers, - * optionals or whatever. * @example * ``` * std::vector> userPointers; * userPointers.push_back(std::make_unique(1, "Eneli")); - * auto statement = storage.prepare(insert_range(userPointers.begin(), userPointers.end(), [](const std::unique_ptr &userPointer) -> const User & { - * return *userPointer; - * })); + * auto statement = storage.prepare(insert_range(userPointers.begin(), userPointers.end(), &std::unique_ptr::operator*)); * storage.execute(statement); * ``` */ - template - internal::insert_range_t insert_range(It from, It to, L transformer) { - return {{std::move(from), std::move(to)}, std::move(transformer)}; + template + auto insert_range(It from, It to, Projection project = {}) { + using O = std::decay_t(), *std::declval()))>; + return internal::insert_range_t{{std::move(from), std::move(to)}, std::move(project)}; } + + /* + * Create an insert range statement. + * Overload of `insert_range(It, It, Projection)` with explicit object type template parameter. + */ + template + internal::insert_range_t insert_range(It from, It to, Projection project = {}) { + return {{std::move(from), std::move(to)}, std::move(project)}; + } + /** * Create a replace statement. * T is an object type mapped to a storage. @@ -10333,7 +12484,7 @@ namespace sqlite_orm { template internal::remove_t remove(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -10356,7 +12507,7 @@ namespace sqlite_orm { template internal::get_t get(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -10367,7 +12518,7 @@ namespace sqlite_orm { template internal::get_pointer_t get_pointer(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -10379,7 +12530,7 @@ namespace sqlite_orm { template internal::get_optional_t get_optional(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED @@ -10393,100 +12544,77 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** * Create a get all statement. * T is an object type mapped to a storage. - * Usage: storage.get_all(...); + * R is a container type. std::vector is default + * Usage: storage.prepare(get_all(...)); */ - template - internal::get_all_t, Args...> get_all(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + template, class... Args> + internal::get_all_t get_all(Args... conditions) { + using conditions_tuple = std::tuple; + internal::validate_conditions(); + return {{std::forward(conditions)...}}; } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** * Create a get all statement. - * T is an object type mapped to a storage. - * R is a container type. std::vector is default - * Usage: storage.get_all(...); - */ - template - internal::get_all_t get_all(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + * `alias` is an explicitly specified table alias of an object to be extracted. + * `R` is the container return type, which must have a `R::push_back(T&&)` method, and defaults to `std::vector` + * Usage: storage.get_all(...); + */ + template>, + class... Args> + auto get_all(Args&&... conditions) { + using expression_type = internal::get_all_t, R, std::decay_t...>; + internal::validate_conditions(); + return expression_type{{std::forward(conditions)...}}; } +#endif /** * Create an update all statement. * Usage: storage.update_all(set(...), ...); */ - template - internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { + template + internal::update_all_t update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; - } - - /** - * Create a get all pointer statement. - * T is an object type mapped to a storage. - * Usage: storage.get_all_pointer(...); - */ - template - internal::get_all_pointer_t>, Args...> get_all_pointer(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - /** - * Create a get all pointer statement. - * T is an object type mapped to a storage. - * R is a container return type. std::vector> is default - * Usage: storage.get_all_pointer(...); - */ - template - internal::get_all_pointer_t get_all_pointer(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * Create a get all optional statement. - * T is an object type mapped to a storage. - * Usage: storage.get_all_optional(...); - */ - template - internal::get_all_optional_t>, Args...> get_all_optional(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(set), std::move(conditions)}; } + /** + * Create a get all pointer statement. + * T is an object type mapped to a storage. + * R is a container return type. std::vector> is default + * Usage: storage.prepare(get_all_pointer(...)); + */ + template>, class... Args> + internal::get_all_pointer_t get_all_pointer(Args... conditions) { + using conditions_tuple = std::tuple; + internal::validate_conditions(); + return {{std::forward(conditions)...}}; + } + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED /** * Create a get all optional statement. * T is an object type mapped to a storage. * R is a container return type. std::vector> is default * Usage: storage.get_all_optional(...); */ - template - internal::get_all_optional_t get_all_optional(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + template>, class... Args> + internal::get_all_optional_t get_all_optional(Args... conditions) { + using conditions_tuple = std::tuple; + internal::validate_conditions(); + return {{std::forward(conditions)...}}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } @@ -10497,6 +12625,8 @@ namespace sqlite_orm { // #include "ast/excluded.h" +#include // std::move + namespace sqlite_orm { namespace internal { @@ -10516,67 +12646,69 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" -#include // std::tuple -#include // std::false_type, std::true_type +// #include "ast/where.h" -namespace sqlite_orm { - namespace internal { +// #include "ast/into.h" - template - struct upsert_clause; +// #include "ast/group_by.h" - template - struct conflict_target { - using args_tuple = std::tuple; +// #include "ast/exists.h" - args_tuple args; +#include // std::move - upsert_clause> do_nothing() { - return {std::move(this->args), {}}; - } +// #include "../tags.h" - template - upsert_clause> do_update(ActionsArgs... actions) { - return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; - } - }; +namespace sqlite_orm { + namespace internal { - template - struct upsert_clause, std::tuple> { - using target_args_tuple = std::tuple; - using actions_tuple = std::tuple; + template + struct exists_t : condition_t, negatable_t { + using expression_type = T; + using self = exists_t; - target_args_tuple target_args; + expression_type expression; - actions_tuple actions; + exists_t(expression_type expression_) : expression(std::move(expression_)) {} }; - - template - struct is_upsert_clause : std::false_type {}; - - template - struct is_upsert_clause> : std::true_type {}; } /** - * ON CONFLICT upsert clause builder function. - * @example - * storage.insert(into(), - * columns(&Employee::id, &Employee::name, &Employee::age, &Employee::address, &Employee::salary), - * values(std::make_tuple(3, "Sofia", 26, "Madrid", 15000.0), - * std::make_tuple(4, "Doja", 26, "LA", 25000.0)), - * on_conflict(&Employee::id).do_update(set(c(&Employee::name) = excluded(&Employee::name), - * c(&Employee::age) = excluded(&Employee::age), - * c(&Employee::address) = excluded(&Employee::address), - * c(&Employee::salary) = excluded(&Employee::salary)))); + * EXISTS(condition). + * Example: storage.select(columns(&Agent::code, &Agent::name, &Agent::workingArea, &Agent::comission), + where(exists(select(asterisk(), + where(is_equal(&Customer::grade, 3) and + is_equal(&Agent::code, &Customer::agentCode))))), + order_by(&Agent::comission)); */ - template - internal::conflict_target on_conflict(Args... args) { - return {std::tuple(std::forward(args)...)}; + template + internal::exists_t exists(T expression) { + return {std::move(expression)}; } } -// #include "ast/where.h" +// #include "ast/set.h" + +// #include "ast/match.h" + +namespace sqlite_orm { + namespace internal { + + template + struct match_t { + using mapped_type = T; + using argument_type = X; + + argument_type argument; + + match_t(argument_type argument) : argument(std::move(argument)) {} + }; + } + + template + internal::match_t match(X argument) { + return {std::move(argument)}; + } +} namespace sqlite_orm { @@ -10587,9 +12719,16 @@ namespace sqlite_orm { * which will be called for any node of provided expression. * E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then * callable object will be called with 5, &User::id and 10. - * ast_iterator is used mostly in finding literals to be bound to - * a statement. To use it just call `iterate_ast(object, callable);` - * T is an ast element. E.g. where_t + * ast_iterator is used in finding literals to be bound to + * a statement, and to collect table names. + * + * Note that not all leaves of the expression tree are always visited: + * Column expressions can be more complex, but are passed as a whole to the callable. + * Examples are `column_pointer<>` and `alias_column_t<>`. + * + * To use `ast_iterator` call `iterate_ast(object, callable);` + * + * `T` is an ast element, e.g. where_t */ template struct ast_iterator { @@ -10599,8 +12738,8 @@ namespace sqlite_orm { * L is a callable type. Mostly is a templated lambda */ template - void operator()(const T& t, const L& l) const { - l(t); + void operator()(const T& t, L& lambda) const { + lambda(t); } }; @@ -10608,9 +12747,9 @@ namespace sqlite_orm { * Simplified API */ template - void iterate_ast(const T& t, const L& l) { + void iterate_ast(const T& t, L&& lambda) { ast_iterator iterator; - iterator(t, l); + iterator(t, lambda); } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -10619,7 +12758,7 @@ namespace sqlite_orm { using node_type = as_optional_t; template - void operator()(const node_type& node, const L& lambda) const { + void operator()(const node_type& node, L& lambda) const { iterate_ast(node.value, lambda); } }; @@ -10630,8 +12769,41 @@ namespace sqlite_orm { using node_type = std::reference_wrapper; template - void operator()(const node_type& r, const L& lambda) const { - iterate_ast(r.get(), lambda); + void operator()(const node_type& expression, L& lambda) const { + iterate_ast(expression.get(), lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = match_t; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.argument, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = group_by_t; + + template + void operator()(const node_type& expression, L& lambda) const { + iterate_ast(expression.args, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = highlight_t; + + template + void operator()(const node_type& expression, L& lambda) const { + lambda(expression); + iterate_ast(expression.argument0, lambda); + iterate_ast(expression.argument1, lambda); + iterate_ast(expression.argument2, lambda); } }; @@ -10640,17 +12812,17 @@ namespace sqlite_orm { using node_type = excluded_t; template - void operator()(const node_type& expression, const L& lambda) const { + void operator()(const node_type& expression, L& lambda) const { iterate_ast(expression.expression, lambda); } }; - template - struct ast_iterator, std::tuple>, void> { - using node_type = upsert_clause, std::tuple>; + template + struct ast_iterator> { + using node_type = T; template - void operator()(const node_type& expression, const L& lambda) const { + void operator()(const node_type& expression, L& lambda) const { iterate_ast(expression.actions, lambda); } }; @@ -10660,19 +12832,19 @@ namespace sqlite_orm { using node_type = where_t; template - void operator()(const node_type& expression, const L& lambda) const { + void operator()(const node_type& expression, L& lambda) const { iterate_ast(expression.expression, lambda); } }; template - struct ast_iterator::value>::type> { + struct ast_iterator> { using node_type = T; template - void operator()(const node_type& binaryCondition, const L& l) const { - iterate_ast(binaryCondition.l, l); - iterate_ast(binaryCondition.r, l); + void operator()(const node_type& binaryCondition, L& lambda) const { + iterate_ast(binaryCondition.l, lambda); + iterate_ast(binaryCondition.r, lambda); } }; @@ -10681,9 +12853,19 @@ namespace sqlite_orm { using node_type = binary_operator; template - void operator()(const node_type& binaryOperator, const C& l) const { - iterate_ast(binaryOperator.lhs, l); - iterate_ast(binaryOperator.rhs, l); + void operator()(const node_type& node, C& lambda) const { + iterate_ast(node.lhs, lambda); + iterate_ast(node.rhs, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = is_equal_with_table_t; + + template + void operator()(const node_type& node, C& lambda) const { + iterate_ast(node.rhs, lambda); } }; @@ -10692,8 +12874,8 @@ namespace sqlite_orm { using node_type = columns_t; template - void operator()(const node_type& cols, const L& l) const { - iterate_ast(cols.columns, l); + void operator()(const node_type& cols, L& lambda) const { + iterate_ast(cols.columns, lambda); } }; @@ -10702,9 +12884,9 @@ namespace sqlite_orm { using node_type = dynamic_in_t; template - void operator()(const node_type& in, const C& l) const { - iterate_ast(in.left, l); - iterate_ast(in.argument, l); + void operator()(const node_type& in, C& lambda) const { + iterate_ast(in.left, lambda); + iterate_ast(in.argument, lambda); } }; @@ -10713,9 +12895,9 @@ namespace sqlite_orm { using node_type = in_t; template - void operator()(const node_type& in, const C& l) const { - iterate_ast(in.left, l); - iterate_ast(in.argument, l); + void operator()(const node_type& in, C& lambda) const { + iterate_ast(in.left, lambda); + iterate_ast(in.argument, lambda); } }; @@ -10724,9 +12906,9 @@ namespace sqlite_orm { using node_type = std::vector; template - void operator()(const node_type& vec, const L& l) const { + void operator()(const node_type& vec, L& lambda) const { for(auto& i: vec) { - iterate_ast(i, l); + iterate_ast(i, lambda); } } }; @@ -10736,19 +12918,19 @@ namespace sqlite_orm { using node_type = std::vector; template - void operator()(const node_type& vec, const L& l) const { - l(vec); + void operator()(const node_type& vec, L& lambda) const { + lambda(vec); } }; template - struct ast_iterator::value>::type> { + struct ast_iterator> { using node_type = T; template - void operator()(const node_type& c, const L& l) const { - iterate_ast(c.left, l); - iterate_ast(c.right, l); + void operator()(const node_type& c, L& lambda) const { + iterate_ast(c.left, lambda); + iterate_ast(c.right, lambda); } }; @@ -10757,7 +12939,7 @@ namespace sqlite_orm { using node_type = into_t; template - void operator()(const node_type& node, const L& l) const { + void operator()(const node_type& /*node*/, L& /*lambda*/) const { //.. } }; @@ -10767,8 +12949,8 @@ namespace sqlite_orm { using node_type = insert_raw_t; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.args, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.args, lambda); } }; @@ -10777,8 +12959,8 @@ namespace sqlite_orm { using node_type = replace_raw_t; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.args, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.args, lambda); } }; @@ -10787,9 +12969,9 @@ namespace sqlite_orm { using node_type = select_t; template - void operator()(const node_type& sel, const L& l) const { - iterate_ast(sel.col, l); - iterate_ast(sel.conditions, l); + void operator()(const node_type& sel, L& lambda) const { + iterate_ast(sel.col, lambda); + iterate_ast(sel.conditions, lambda); } }; @@ -10798,8 +12980,8 @@ namespace sqlite_orm { using node_type = get_all_t; template - void operator()(const node_type& get, const L& l) const { - iterate_ast(get.conditions, l); + void operator()(const node_type& get, L& lambda) const { + iterate_ast(get.conditions, lambda); } }; @@ -10808,8 +12990,8 @@ namespace sqlite_orm { using node_type = get_all_pointer_t; template - void operator()(const node_type& get, const L& l) const { - iterate_ast(get.conditions, l); + void operator()(const node_type& get, L& lambda) const { + iterate_ast(get.conditions, lambda); } }; @@ -10819,20 +13001,20 @@ namespace sqlite_orm { using node_type = get_all_optional_t; template - void operator()(const node_type& get, const L& l) const { - iterate_ast(get.conditions, l); + void operator()(const node_type& get, L& lambda) const { + iterate_ast(get.conditions, lambda); } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct ast_iterator, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; + template + struct ast_iterator, void> { + using node_type = update_all_t; template - void operator()(const node_type& u, const L& l) const { - iterate_ast(u.set, l); - iterate_ast(u.conditions, l); + void operator()(const node_type& u, L& lambda) const { + iterate_ast(u.set, lambda); + iterate_ast(u.conditions, lambda); } }; @@ -10841,8 +13023,8 @@ namespace sqlite_orm { using node_type = remove_all_t; template - void operator()(const node_type& r, const L& l) const { - iterate_ast(r.conditions, l); + void operator()(const node_type& r, L& lambda) const { + iterate_ast(r.conditions, lambda); } }; @@ -10851,8 +13033,18 @@ namespace sqlite_orm { using node_type = set_t; template - void operator()(const node_type& s, const L& l) const { - iterate_ast(s.assigns, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.assigns, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = dynamic_set_t; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.entries, lambda); } }; @@ -10861,20 +13053,21 @@ namespace sqlite_orm { using node_type = std::tuple; template - void operator()(const node_type& tuple, const L& l) const { - iterate_tuple(tuple, [&l](auto& v) { - iterate_ast(v, l); + void operator()(const node_type& node, L& lambda) const { + iterate_tuple(node, [&lambda](auto& v) { + iterate_ast(v, lambda); }); } }; - template - struct ast_iterator, void> { - using node_type = having_t; + template + struct ast_iterator, void> { + using node_type = group_by_with_having; template - void operator()(const node_type& hav, const L& l) const { - iterate_ast(hav.t, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.args, lambda); + iterate_ast(node.expression, lambda); } }; @@ -10883,8 +13076,8 @@ namespace sqlite_orm { using node_type = cast_t; template - void operator()(const node_type& c, const L& l) const { - iterate_ast(c.expression, l); + void operator()(const node_type& c, L& lambda) const { + iterate_ast(c.expression, lambda); } }; @@ -10893,8 +13086,8 @@ namespace sqlite_orm { using node_type = exists_t; template - void operator()(const node_type& e, const L& l) const { - iterate_ast(e.t, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.expression, lambda); } }; @@ -10903,11 +13096,11 @@ namespace sqlite_orm { using node_type = like_t; template - void operator()(const node_type& lk, const L& l) const { - iterate_ast(lk.arg, l); - iterate_ast(lk.pattern, l); - lk.arg3.apply([&l](auto& value) { - iterate_ast(value, l); + void operator()(const node_type& lk, L& lambda) const { + iterate_ast(lk.arg, lambda); + iterate_ast(lk.pattern, lambda); + lk.arg3.apply([&lambda](auto& value) { + iterate_ast(value, lambda); }); } }; @@ -10917,9 +13110,9 @@ namespace sqlite_orm { using node_type = glob_t; template - void operator()(const node_type& lk, const L& l) const { - iterate_ast(lk.arg, l); - iterate_ast(lk.pattern, l); + void operator()(const node_type& lk, L& lambda) const { + iterate_ast(lk.arg, lambda); + iterate_ast(lk.pattern, lambda); } }; @@ -10928,10 +13121,10 @@ namespace sqlite_orm { using node_type = between_t; template - void operator()(const node_type& b, const L& l) const { - iterate_ast(b.expr, l); - iterate_ast(b.b1, l); - iterate_ast(b.b2, l); + void operator()(const node_type& b, L& lambda) const { + iterate_ast(b.expr, lambda); + iterate_ast(b.b1, lambda); + iterate_ast(b.b2, lambda); } }; @@ -10940,8 +13133,8 @@ namespace sqlite_orm { using node_type = named_collate; template - void operator()(const node_type& col, const L& l) const { - iterate_ast(col.expr, l); + void operator()(const node_type& col, L& lambda) const { + iterate_ast(col.expr, lambda); } }; @@ -10950,8 +13143,8 @@ namespace sqlite_orm { using node_type = negated_condition_t; template - void operator()(const node_type& neg, const L& l) const { - iterate_ast(neg.c, l); + void operator()(const node_type& neg, L& lambda) const { + iterate_ast(neg.c, lambda); } }; @@ -10960,8 +13153,8 @@ namespace sqlite_orm { using node_type = is_null_t; template - void operator()(const node_type& i, const L& l) const { - iterate_ast(i.t, l); + void operator()(const node_type& i, L& lambda) const { + iterate_ast(i.t, lambda); } }; @@ -10970,8 +13163,8 @@ namespace sqlite_orm { using node_type = is_not_null_t; template - void operator()(const node_type& i, const L& l) const { - iterate_ast(i.t, l); + void operator()(const node_type& i, L& lambda) const { + iterate_ast(i.t, lambda); } }; @@ -10980,8 +13173,8 @@ namespace sqlite_orm { using node_type = function_call; template - void operator()(const node_type& f, const L& l) const { - iterate_ast(f.args, l); + void operator()(const node_type& f, L& lambda) const { + iterate_ast(f.args, lambda); } }; @@ -10990,58 +13183,61 @@ namespace sqlite_orm { using node_type = built_in_function_t; template - void operator()(const node_type& f, const L& l) const { - iterate_ast(f.args, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.args, lambda); } }; - template - struct ast_iterator, void> { - using node_type = left_join_t; + template + struct ast_iterator, void> { + using node_type = built_in_aggregate_function_t; template - void operator()(const node_type& j, const L& l) const { - iterate_ast(j.constraint, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.args, lambda); } }; - template - struct ast_iterator, void> { - using node_type = on_t; + template + struct ast_iterator, void> { + using node_type = filtered_aggregate_function; template - void operator()(const node_type& o, const L& l) const { - iterate_ast(o.arg, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.function, lambda); + iterate_ast(node.where, lambda); } }; - template - struct ast_iterator, void> { - using node_type = join_t; + template + struct ast_iterator> { + using node_type = Join; template - void operator()(const node_type& j, const L& l) const { - iterate_ast(j.constraint, l); + void operator()(const node_type& join, L& lambda) const { + iterate_ast(join.constraint, lambda); } }; - template - struct ast_iterator, void> { - using node_type = left_outer_join_t; + template + struct ast_iterator, void> { + using node_type = on_t; template - void operator()(const node_type& j, const L& l) const { - iterate_ast(j.constraint, l); + void operator()(const node_type& on, L& lambda) const { + iterate_ast(on.arg, lambda); } }; - template - struct ast_iterator, void> { - using node_type = inner_join_t; + // note: not strictly necessary as there's no binding support for USING; + // we provide it nevertheless, in line with on_t. + template + struct ast_iterator>> { + using node_type = T; template - void operator()(const node_type& j, const L& l) const { - iterate_ast(j.constraint, l); + void operator()(const node_type& o, L& lambda) const { + iterate_ast(o.column, lambda); } }; @@ -11050,16 +13246,16 @@ namespace sqlite_orm { using node_type = simple_case_t; template - void operator()(const node_type& c, const L& l) const { - c.case_expression.apply([&l](auto& c_) { - iterate_ast(c_, l); + void operator()(const node_type& c, L& lambda) const { + c.case_expression.apply([&lambda](auto& c_) { + iterate_ast(c_, lambda); }); - iterate_tuple(c.args, [&l](auto& pair) { - iterate_ast(pair.first, l); - iterate_ast(pair.second, l); + iterate_tuple(c.args, [&lambda](auto& pair) { + iterate_ast(pair.first, lambda); + iterate_ast(pair.second, lambda); }); - c.else_expression.apply([&l](auto& el) { - iterate_ast(el, l); + c.else_expression.apply([&lambda](auto& el) { + iterate_ast(el, lambda); }); } }; @@ -11069,8 +13265,8 @@ namespace sqlite_orm { using node_type = as_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.expression, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.expression, lambda); } }; @@ -11079,8 +13275,8 @@ namespace sqlite_orm { using node_type = limit_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.lim, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.lim, lambda); } }; @@ -11089,10 +13285,10 @@ namespace sqlite_orm { using node_type = limit_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.lim, l); - a.off.apply([&l](auto& value) { - iterate_ast(value, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.lim, lambda); + a.off.apply([&lambda](auto& value) { + iterate_ast(value, lambda); }); } }; @@ -11102,11 +13298,11 @@ namespace sqlite_orm { using node_type = limit_t; template - void operator()(const node_type& a, const L& l) const { - a.off.apply([&l](auto& value) { - iterate_ast(value, l); + void operator()(const node_type& a, L& lambda) const { + a.off.apply([&lambda](auto& value) { + iterate_ast(value, lambda); }); - iterate_ast(a.lim, l); + iterate_ast(a.lim, lambda); } }; @@ -11115,8 +13311,8 @@ namespace sqlite_orm { using node_type = distinct_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.value, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.value, lambda); } }; @@ -11125,8 +13321,8 @@ namespace sqlite_orm { using node_type = all_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.value, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.value, lambda); } }; @@ -11135,8 +13331,8 @@ namespace sqlite_orm { using node_type = bitwise_not_t; template - void operator()(const node_type& a, const L& l) const { - iterate_ast(a.argument, l); + void operator()(const node_type& a, L& lambda) const { + iterate_ast(a.argument, lambda); } }; @@ -11145,8 +13341,8 @@ namespace sqlite_orm { using node_type = values_t; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.tuple, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.tuple, lambda); } }; @@ -11155,8 +13351,32 @@ namespace sqlite_orm { using node_type = dynamic_values_t; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.vector, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.vector, lambda); + } + }; + + /** + * Column alias or literal: skipped + */ + template + struct ast_iterator, + polyfill::is_specialization_of, + is_column_alias>>> { + using node_type = T; + + template + void operator()(const node_type& /*node*/, L& /*lambda*/) const {} + }; + + template + struct ast_iterator, void> { + using node_type = order_by_t; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.expression, lambda); } }; @@ -11165,8 +13385,8 @@ namespace sqlite_orm { using node_type = collate_t; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.expr, l); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.expr, lambda); } }; @@ -11177,6 +13397,8 @@ namespace sqlite_orm { // #include "connection_holder.h" +// #include "util.h" + namespace sqlite_orm { namespace internal { @@ -11203,38 +13425,23 @@ namespace sqlite_orm { view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} - size_t size() { + size_t size() const { return this->storage.template count(); } - bool empty() { + bool empty() const { return !this->size(); } iterator_t begin() { - sqlite3_stmt* stmt = nullptr; - auto db = this->connection.get(); - using context_t = serializator_context; - context_t context{this->storage.impl}; + using context_t = serializer_context; + context_t context{obtain_db_objects(this->storage)}; context.skip_table_name = false; context.replace_bindable_with_question = true; - auto query = serialize(this->args, context); - auto ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr); - if(ret == SQLITE_OK) { - auto index = 1; - iterate_ast(this->args.conditions, [&index, stmt, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - return {stmt, *this}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + + statement_finalizer stmt{prepare_stmt(this->connection.get(), serialize(this->args, context))}; + iterate_ast(this->args.conditions, conditional_binder{stmt.get()}); + return {std::move(stmt), *this}; } iterator_t end() { @@ -11248,35 +13455,438 @@ namespace sqlite_orm { // #include "storage_base.h" -#include // std::function, std::bind #include +#include // std::function, std::bind #include // std::string #include // std::stringstream #include // std::move -#include // std::system_error, std::error_code, std::make_error_code +#include // std::system_error #include // std::vector -#include // std::make_shared, std::shared_ptr +#include // std::make_unique, std::unique_ptr #include // std::map -#include // std::decay, std::is_same -#include // std::iter_swap +#include // std::is_same +#include // std::find_if + +// #include "functional/cxx_universal.h" +// ::size_t +// #include "tuple_helper/tuple_iteration.h" // #include "pragma.h" -#include // std::string #include +#include // std::string #include // std::function #include // std::shared_ptr #include // std::vector +#include + +// #include "error_code.h" + +// #include "row_extractor.h" + +// #include "journal_mode.h" + +// #include "connection_holder.h" + +// #include "util.h" + +// #include "serializing_util.h" + +#include // std::index_sequence +#include +#include +#include +#include +#include // std::exchange, std::tuple_size + +// #include "functional/cxx_universal.h" +// ::size_t +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "tuple_helper/tuple_iteration.h" + +// #include "error_code.h" + +// #include "serializer_context.h" + +// #include "serialize_result_type.h" + +// #include "util.h" + +namespace sqlite_orm { + namespace internal { + template + struct order_by_t; + + template + std::string serialize(const T& t, const C& context); + + template + std::string serialize_order_by(const T&, const Ctx&); + + inline void stream_sql_escaped(std::ostream& os, serialize_arg_type str, char char2Escape) { + for(size_t offset = 0, next; true; offset = next + 1) { + next = str.find(char2Escape, offset); + + if(next == str.npos) { + os.write(str.data() + offset, str.size() - offset); + break; + } + + os.write(str.data() + offset, next - offset + 1); + os.write(&char2Escape, 1); + } + } + + inline void stream_identifier(std::ostream& ss, + serialize_arg_type qualifier, + serialize_arg_type identifier, + serialize_arg_type alias) { + constexpr char quoteChar = '"'; + constexpr char qualified[] = {quoteChar, '.', '\0'}; + constexpr char aliased[] = {' ', quoteChar, '\0'}; + + // note: In practice, escaping double quotes in identifiers is arguably overkill, + // but since the SQLite grammar allows it, it's better to be safe than sorry. + + if(!qualifier.empty()) { + ss << quoteChar; + stream_sql_escaped(ss, qualifier, quoteChar); + ss << qualified; + } + { + ss << quoteChar; + stream_sql_escaped(ss, identifier, quoteChar); + ss << quoteChar; + } + if(!alias.empty()) { + ss << aliased; + stream_sql_escaped(ss, alias, quoteChar); + ss << quoteChar; + } + } + + inline void stream_identifier(std::ostream& ss, const std::string& identifier, const std::string& alias) { + return stream_identifier(ss, "", identifier, alias); + } + + inline void stream_identifier(std::ostream& ss, const std::string& identifier) { + return stream_identifier(ss, "", identifier, ""); + } + + template + void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { + static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); + return stream_identifier(ss, std::get(tpl)...); + } + + template>, bool> = true> + void stream_identifier(std::ostream& ss, const Tpl& tpl) { + return stream_identifier(ss, tpl, std::make_index_sequence::value>{}); + } + + enum class stream_as { + conditions_tuple, + actions_tuple, + expressions_tuple, + dynamic_expressions, + serialized, + identifier, + identifiers, + values_placeholders, + table_columns, + non_generated_columns, + field_values_excluding, + mapped_columns_expressions, + column_constraints, + }; + + template + struct streaming { + template + auto operator()(const Ts&... ts) const { + return std::forward_as_tuple(*this, ts...); + } + + template + constexpr std::index_sequence<1u + Idx...> offset_index(std::index_sequence) const { + return {}; + } + }; + constexpr streaming streaming_conditions_tuple{}; + constexpr streaming streaming_actions_tuple{}; + constexpr streaming streaming_expressions_tuple{}; + constexpr streaming streaming_dynamic_expressions{}; + constexpr streaming streaming_serialized{}; + constexpr streaming streaming_identifier{}; + constexpr streaming streaming_identifiers{}; + constexpr streaming streaming_values_placeholders{}; + constexpr streaming streaming_table_column_names{}; + constexpr streaming streaming_non_generated_column_names{}; + constexpr streaming streaming_field_values_excluding{}; + constexpr streaming streaming_mapped_columns_expressions{}; + constexpr streaming streaming_column_constraints{}; + + // serialize and stream a tuple of condition expressions; + // space + space-separated + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, T, Ctx> tpl) { + const auto& conditions = get<1>(tpl); + auto& context = get<2>(tpl); + + iterate_tuple(conditions, [&ss, &context](auto& c) { + ss << " " << serialize(c, context); + }); + return ss; + } + + // serialize and stream a tuple of action expressions; + // space-separated + template + std::ostream& operator<<(std::ostream& ss, std::tuple&, T, Ctx> tpl) { + const auto& actions = get<1>(tpl); + auto& context = get<2>(tpl); + + iterate_tuple(actions, [&ss, &context, first = true](auto& action) mutable { + constexpr std::array sep = {" ", ""}; + ss << sep[std::exchange(first, false)] << serialize(action, context); + }); + return ss; + } + + // serialize and stream a tuple of expressions; + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, T, Ctx> tpl) { + const auto& args = get<1>(tpl); + auto& context = get<2>(tpl); + + iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] << serialize(arg, context); + }); + return ss; + } + + // serialize and stream multi_order_by arguments; + // comma-separated + template + std::ostream& operator<<( + std::ostream& ss, + std::tuple&, const std::tuple...>&, Ctx> tpl) { + const auto& args = get<1>(tpl); + auto& context = get<2>(tpl); + + iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] << serialize_order_by(arg, context); + }); + return ss; + } + + // serialize and stream a vector or any other STL container of expressions; + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, C, Ctx> tpl) { + const auto& args = get<1>(tpl); + auto& context = get<2>(tpl); + + constexpr std::array sep = {", ", ""}; + bool first = true; + for(auto& argument: args) { + ss << sep[std::exchange(first, false)] << serialize(argument, context); + } + return ss; + } + + // stream a vector of already serialized strings; + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { + const auto& strings = get<1>(tpl); + + constexpr std::array sep = {", ", ""}; + for(size_t i = 0, first = true; i < strings.size(); ++i) { + ss << sep[std::exchange(first, false)] << strings[i]; + } + return ss; + } + + // stream an identifier described by a variadic string pack, which is one of: + // 1. identifier + // 2. identifier, alias + // 3. qualifier, identifier, alias + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, Strings...> tpl) { + stream_identifier(ss, tpl, streaming_identifier.offset_index(std::index_sequence_for{})); + return ss; + } + + // stream a container of identifiers described by a string or a tuple, which is one of: + // 1. identifier + // 1. tuple(identifier) + // 2. tuple(identifier, alias), pair(identifier, alias) + // 3. tuple(qualifier, identifier, alias) + // + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { + const auto& identifiers = get<1>(tpl); + + constexpr std::array sep = {", ", ""}; + bool first = true; + for(auto& identifier: identifiers) { + ss << sep[std::exchange(first, false)]; + stream_identifier(ss, identifier); + } + return ss; + } + + // stream placeholders as part of a values clause + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, Ts...> tpl) { + const size_t& columnsCount = get<1>(tpl); + const ptrdiff_t& valuesCount = get<2>(tpl); + + if(!valuesCount || !columnsCount) { + return ss; + } + + std::string result; + result.reserve((1 + (columnsCount * 1) + (columnsCount * 2 - 2) + 1) * valuesCount + (valuesCount * 2 - 2)); + + constexpr std::array sep = {", ", ""}; + for(ptrdiff_t i = 0, first = true; i < valuesCount; ++i) { + result += sep[std::exchange(first, false)]; + result += "("; + for(size_t i = 0, first = true; i < columnsCount; ++i) { + result += sep[std::exchange(first, false)]; + result += "?"; + } + result += ")"; + } + ss << result; + return ss; + } + + // stream a table's column identifiers, possibly qualified; + // comma-separated + template + std::ostream& + operator<<(std::ostream& ss, + std::tuple&, Table, const std::string&> tpl) { + const auto& table = get<1>(tpl); + const std::string& qualifier = get<2>(tpl); + + table.for_each_column([&ss, &qualifier, first = true](const column_identifier& column) mutable { + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)]; + stream_identifier(ss, qualifier, column.name, std::string{}); + }); + return ss; + } + + // stream a table's non-generated column identifiers, unqualified; + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, Table> tpl) { + const auto& table = get<1>(tpl); + + table.template for_each_column_excluding( + [&ss, first = true](const column_identifier& column) mutable { + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)]; + stream_identifier(ss, column.name); + }); + return ss; + } -// #include "error_code.h" + // stream a table's non-generated column identifiers, unqualified; + // comma-separated + template + std::ostream& + operator<<(std::ostream& ss, + std::tuple&, PredFnCls, L, Ctx, Obj> tpl) { + using check_if_excluded = polyfill::remove_cvref_t>; + auto& excluded = get<2>(tpl); + auto& context = get<3>(tpl); + auto& object = get<4>(tpl); + using object_type = polyfill::remove_cvref_t; + auto& table = pick_table(context.db_objects); + + table.template for_each_column_excluding(call_as_template_base( + [&ss, &excluded, &context, &object, first = true](auto& column) mutable { + if(excluded(column)) { + return; + } -// #include "util.h" + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] + << serialize(polyfill::invoke(column.member_pointer, object), context); + })); + return ss; + } -// #include "row_extractor.h" + // stream a tuple of mapped columns (which are member pointers or column pointers); + // comma-separated + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, T, Ctx> tpl) { + const auto& columns = get<1>(tpl); + auto& context = get<2>(tpl); + + iterate_tuple(columns, [&ss, &context, first = true](auto& colRef) mutable { + const std::string* columnName = find_column_name(context.db_objects, colRef); + if(!columnName) { + throw std::system_error{orm_error_code::column_not_found}; + } -// #include "journal_mode.h" + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)]; + stream_identifier(ss, *columnName); + }); + return ss; + } -// #include "connection_holder.h" + template + std::ostream& operator<<(std::ostream& ss, + std::tuple&, + const column_constraints&, + const bool&, + Ctx> tpl) { + const auto& column = get<1>(tpl); + const bool& isNotNull = get<2>(tpl); + auto& context = get<3>(tpl); + + auto first = true; + constexpr std::array sep = {" ", ""}; + iterate_tuple(column.constraints, [&ss, &context, &first, &sep](auto& constraint) { + ss << sep[std::exchange(first, false)]; + ss << serialize(constraint, context); + }); + using constraints_tuple = decltype(column.constraints); + constexpr bool hasExplicitNullableConstraint = + mpl::invoke_t, check_if_tuple_has_type>, + constraints_tuple>::value; + if(!hasExplicitNullableConstraint) { + ss << sep[std::exchange(first, false)]; + if(isNotNull) { + ss << "NOT NULL"; + } else { + ss << "NULL"; + } + } + + return ss; + } + } +} namespace sqlite_orm { @@ -11284,21 +13894,18 @@ namespace sqlite_orm { struct storage_base; template - int getPragmaCallback(void* data, int argc, char** argv, char**) { - auto& res = *(T*)data; - if(argc) { - res = row_extractor().extract(argv[0]); - } - return 0; + int getPragmaCallback(void* data, int argc, char** argv, char** x) { + return extract_single_value(data, argc, argv, x); } template<> inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { auto& res = *(std::vector*)data; res.reserve(argc); - for(decltype(argc) i = 0; i < argc; ++i) { - auto rowString = row_extractor().extract(argv[i]); - res.push_back(move(rowString)); + const auto rowExtractor = column_text_extractor(); + for(int i = 0; i < argc; ++i) { + auto rowString = rowExtractor.extract(argv[i]); + res.push_back(std::move(rowString)); } return 0; } @@ -11306,7 +13913,11 @@ namespace sqlite_orm { struct pragma_t { using get_connection_t = std::function; - pragma_t(get_connection_t get_connection_) : get_connection(move(get_connection_)) {} + pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} + + std::vector module_list() { + return this->get_pragma>("module_list"); + } void busy_timeout(int value) { this->set_pragma("busy_timeout", value); @@ -11326,6 +13937,20 @@ namespace sqlite_orm { this->_journal_mode = static_cast_journal_mode)>(value); } + /** + * https://www.sqlite.org/pragma.html#pragma_application_id + */ + int application_id() { + return this->get_pragma("application_id"); + } + + /** + * https://www.sqlite.org/pragma.html#pragma_application_id + */ + void application_id(int value) { + this->set_pragma("application_id", value); + } + int synchronous() { return this->get_pragma("synchronous"); } @@ -11358,15 +13983,83 @@ namespace sqlite_orm { template std::vector integrity_check(T table_name) { - std::ostringstream oss; - oss << "integrity_check(" << table_name << ")"; - return this->get_pragma>(oss.str()); + std::ostringstream ss; + ss << "integrity_check(" << table_name << ")" << std::flush; + return this->get_pragma>(ss.str()); } std::vector integrity_check(int n) { - std::ostringstream oss; - oss << "integrity_check(" << n << ")"; - return this->get_pragma>(oss.str()); + std::ostringstream ss; + ss << "integrity_check(" << n << ")" << std::flush; + return this->get_pragma>(ss.str()); + } + + // will include generated columns in response as opposed to table_info + std::vector table_xinfo(const std::string& tableName) const { + auto connection = this->get_connection(); + + std::vector result; + std::ostringstream ss; + ss << "PRAGMA " + "table_xinfo(" + << streaming_identifier(tableName) << ")" << std::flush; + perform_exec( + connection.get(), + ss.str(), + [](void* data, int argc, char** argv, char**) -> int { + auto& res = *(std::vector*)data; + if(argc) { + auto index = 0; + auto cid = std::atoi(argv[index++]); + std::string name = argv[index++]; + std::string type = argv[index++]; + bool notnull = !!std::atoi(argv[index++]); + std::string dflt_value = argv[index] ? argv[index] : ""; + ++index; + auto pk = std::atoi(argv[index++]); + auto hidden = std::atoi(argv[index++]); + res.emplace_back(cid, + std::move(name), + std::move(type), + notnull, + std::move(dflt_value), + pk, + hidden); + } + return 0; + }, + &result); + return result; + } + + std::vector table_info(const std::string& tableName) const { + auto connection = this->get_connection(); + + std::ostringstream ss; + ss << "PRAGMA " + "table_info(" + << streaming_identifier(tableName) << ")" << std::flush; + std::vector result; + perform_exec( + connection.get(), + ss.str(), + [](void* data, int argc, char** argv, char**) -> int { + auto& res = *(std::vector*)data; + if(argc) { + auto index = 0; + auto cid = std::atoi(argv[index++]); + std::string name = argv[index++]; + std::string type = argv[index++]; + bool notnull = !!std::atoi(argv[index++]); + std::string dflt_value = argv[index] ? argv[index] : ""; + ++index; + auto pk = std::atoi(argv[index++]); + res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk); + } + return 0; + }, + &result); + return result; } private: @@ -11379,16 +14072,9 @@ namespace sqlite_orm { template T get_pragma(const std::string& name) { auto connection = this->get_connection(); - auto query = "PRAGMA " + name; T result; - auto db = connection.get(); - auto rc = sqlite3_exec(db, query.c_str(), getPragmaCallback, &result, nullptr); - if(rc == SQLITE_OK) { - return result; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + perform_exec(connection.get(), "PRAGMA " + name, getPragmaCallback, &result); + return result; } /** @@ -11402,8 +14088,8 @@ namespace sqlite_orm { db = con.get(); } std::stringstream ss; - ss << "PRAGMA " << name << " = " << value; - internal::perform_void_exec(db, ss.str()); + ss << "PRAGMA " << name << " = " << value << std::flush; + perform_void_exec(db, ss.str()); } void set_pragma(const std::string& name, const sqlite_orm::journal_mode& value, sqlite3* db = nullptr) { @@ -11412,14 +14098,14 @@ namespace sqlite_orm { db = con.get(); } std::stringstream ss; - ss << "PRAGMA " << name << " = " << internal::to_string(value); - internal::perform_void_exec(db, ss.str()); + ss << "PRAGMA " << name << " = " << to_string(value) << std::flush; + perform_void_exec(db, ss.str()); } }; } } -// #include "limit_accesor.h" +// #include "limit_accessor.h" #include #include // std::map @@ -11432,10 +14118,10 @@ namespace sqlite_orm { namespace internal { - struct limit_accesor { + struct limit_accessor { using get_connection_t = std::function; - limit_accesor(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} + limit_accessor(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} int length() { return this->get(SQLITE_LIMIT_LENGTH); @@ -11562,6 +14248,7 @@ namespace sqlite_orm { // #include "transaction_guard.h" #include // std::function +#include // std::move // #include "connection_holder.h" @@ -11574,6 +14261,9 @@ namespace sqlite_orm { * Has explicit `commit()` and `rollback()` functions. After explicit function is fired * guard won't do anything in d-tor. Also you can set `commit_on_destroy` to true to * make it call `COMMIT` on destroy. + * + * Note: The guard's destructor is explicitly marked as potentially throwing, + * so exceptions that occur during commit or rollback are propagated to the caller. */ struct transaction_guard_t { /** @@ -11588,24 +14278,33 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(std::move(commit_func_)), rollback_func(std::move(rollback_func_)) {} - ~transaction_guard_t() { + transaction_guard_t(transaction_guard_t&& other) : + commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), + commit_func(std::move(other.commit_func)), rollback_func(std::move(other.rollback_func)), + gotta_fire(other.gotta_fire) { + other.gotta_fire = false; + } + + ~transaction_guard_t() noexcept(false) { if(this->gotta_fire) { - if(!this->commit_on_destroy) { - this->rollback_func(); - } else { + if(this->commit_on_destroy) { this->commit_func(); + } else { + this->rollback_func(); } } } + transaction_guard_t& operator=(transaction_guard_t&&) = delete; + /** * Call `COMMIT` explicitly. After this call * guard will not call `COMMIT` or `ROLLBACK` * in its destructor. */ void commit() { - this->commit_func(); this->gotta_fire = false; + this->commit_func(); } /** @@ -11614,8 +14313,8 @@ namespace sqlite_orm { * in its destructor. */ void rollback() { - this->rollback_func(); this->gotta_fire = false; + this->rollback_func(); } protected: @@ -11627,23 +14326,17 @@ namespace sqlite_orm { } } -// #include "statement_finalizer.h" - -// #include "type_printer.h" - -// #include "tuple_helper/tuple_helper.h" - // #include "row_extractor.h" -// #include "util.h" - // #include "connection_holder.h" // #include "backup.h" #include +#include // std::system_error #include // std::string #include +#include // std::move, std::exchange // #include "error_code.h" @@ -11666,21 +14359,19 @@ namespace sqlite_orm { const std::string& zSourceName, std::unique_ptr holder_) : handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())), - to(to_), from(from_), holder(move(holder_)) { + holder(std::move(holder_)), to(to_), from(from_) { if(!this->handle) { - throw std::system_error(std::make_error_code(orm_error_code::failed_to_init_a_backup)); + throw std::system_error{orm_error_code::failed_to_init_a_backup}; } } backup_t(backup_t&& other) : - handle(other.handle), to(other.to), from(other.from), holder(move(other.holder)) { - other.handle = nullptr; - } + handle(std::exchange(other.handle, nullptr)), holder(std::move(other.holder)), to(other.to), + from(other.from) {} ~backup_t() { if(this->handle) { (void)sqlite3_backup_finish(this->handle); - this->handle = nullptr; } } @@ -11707,9 +14398,9 @@ namespace sqlite_orm { protected: sqlite3_backup* handle = nullptr; + std::unique_ptr holder; connection_ref to; connection_ref from; - std::unique_ptr holder; }; } } @@ -11719,7 +14410,10 @@ namespace sqlite_orm { // #include "values_to_tuple.h" #include -#include // std::get, std::tuple_element +#include // std::index_sequence, std::make_index_sequence +#include // std::tuple, std::tuple_size, std::get + +// #include "functional/cxx_universal.h" // #include "row_extractor.h" @@ -11731,6 +14425,8 @@ namespace sqlite_orm { namespace sqlite_orm { + /** @short Wrapper around a dynamically typed value object. + */ struct arg_value { arg_value() : arg_value(nullptr) {} @@ -11739,7 +14435,8 @@ namespace sqlite_orm { template T get() const { - return row_extractor().extract(this->value); + const auto rowExtractor = internal::boxed_value_extractor(); + return rowExtractor.extract(this->value); } bool is_null() const { @@ -11808,7 +14505,7 @@ namespace sqlite_orm { if(this->index < int(this->container.size()) && this->index >= 0) { return this->currentValue; } else { - throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds)); + throw std::system_error{orm_error_code::index_is_out_of_bounds}; } } @@ -11844,10 +14541,10 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - auto valuePointer = this->values[index]; - return {valuePointer}; + sqlite3_value* value = this->values[index]; + return {value}; } else { - throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds)); + throw std::system_error{orm_error_code::index_is_out_of_bounds}; } } @@ -11873,32 +14570,35 @@ namespace sqlite_orm { namespace internal { - /** - * T is a std::tuple type - * I is index to extract value from values C array to tuple. I must me < std::tuple_size::value - */ - template struct values_to_tuple { - - void extract(sqlite3_value** values, T& tuple, int argsCount) const { - using element_type = typename std::tuple_element::type; - std::get(tuple) = row_extractor().extract(values[I]); - - values_to_tuple().extract(values, tuple, argsCount); + template + void operator()(sqlite3_value** values, Tpl& tuple, int /*argsCount*/) const { + (*this)(values, tuple, std::make_index_sequence::value>{}); } - }; - template - struct values_to_tuple { - void extract(sqlite3_value** values, T& tuple, int argsCount) const { - //.. + void operator()(sqlite3_value** values, std::tuple& tuple, int argsCount) const { + std::get<0>(tuple) = arg_values(argsCount, values); } - }; - template<> - struct values_to_tuple, 0> { - void extract(sqlite3_value** values, std::tuple& tuple, int argsCount) const { - std::get<0>(tuple) = arg_values(argsCount, values); + private: +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + (this->extract(values[Idx], std::get(tuple)), ...); + } +#else + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} +#endif + template + void extract(sqlite3_value* value, T& t) const { + const auto rowExtractor = boxed_value_extractor(); + t = rowExtractor.extract(value); } }; } @@ -11906,6 +14606,10 @@ namespace sqlite_orm { // #include "arg_values.h" +// #include "util.h" + +// #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -11915,42 +14619,93 @@ namespace sqlite_orm { std::function on_open; pragma_t pragma; - limit_accesor limit; + limit_accessor limit; transaction_guard_t transaction_guard() { this->begin_transaction(); - auto commitFunc = std::bind(static_cast(&storage_base::commit), this); - auto rollbackFunc = std::bind(static_cast(&storage_base::rollback), this); - return {this->get_connection(), move(commitFunc), move(rollbackFunc)}; + return {this->get_connection(), + std::bind(&storage_base::commit, this), + std::bind(&storage_base::rollback, this)}; } void drop_index(const std::string& indexName) { std::stringstream ss; - ss << "DROP INDEX '" << indexName + "'"; - perform_void_exec(get_connection().get(), ss.str()); + ss << "DROP INDEX " << quote_identifier(indexName) << std::flush; + perform_void_exec(this->get_connection().get(), ss.str()); + } + + void drop_trigger(const std::string& triggerName) { + std::stringstream ss; + ss << "DROP TRIGGER " << quote_identifier(triggerName) << std::flush; + perform_void_exec(this->get_connection().get(), ss.str()); } void vacuum() { - perform_void_exec(get_connection().get(), "VACUUM"); + perform_void_exec(this->get_connection().get(), "VACUUM"); } /** * Drops table with given name. */ void drop_table(const std::string& tableName) { - auto con = this->get_connection(); - this->drop_table_internal(tableName, con.get()); + this->drop_table_internal(this->get_connection().get(), tableName); } /** * Rename table named `from` to `to`. */ void rename_table(const std::string& from, const std::string& to) { + this->rename_table(this->get_connection().get(), from, to); + } + + protected: + void rename_table(sqlite3* db, const std::string& oldName, const std::string& newName) const { + std::stringstream ss; + ss << "ALTER TABLE " << streaming_identifier(oldName) << " RENAME TO " << streaming_identifier(newName) + << std::flush; + perform_void_exec(db, ss.str()); + } + + /** + * Checks whether table exists in db. Doesn't check storage itself - works only with actual database. + * Note: table can be not mapped to a storage + * @return true if table with a given name exists in db, false otherwise. + */ + bool table_exists(const std::string& tableName) { + auto con = this->get_connection(); + return this->table_exists(con.get(), tableName); + } + + bool table_exists(sqlite3* db, const std::string& tableName) const { + bool result = false; std::stringstream ss; - ss << "ALTER TABLE '" << from << "' RENAME TO '" << to << "'"; - perform_void_exec(get_connection().get(), ss.str()); + ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = " << quote_string_literal("table") + << " AND name = " << quote_string_literal(tableName) << std::flush; + perform_exec( + db, + ss.str(), + [](void* data, int argc, char** argv, char** /*azColName*/) -> int { + auto& res = *(bool*)data; + if(argc) { + res = !!std::atoi(argv[0]); + } + return 0; + }, + &result); + return result; + } + + void add_generated_cols(std::vector& columnsToAdd, + const std::vector& storageTableInfo) { + // iterate through storage columns + for(const table_xinfo& storageColumnInfo: storageTableInfo) { + if(storageColumnInfo.hidden) { + columnsToAdd.push_back(&storageColumnInfo); + } + } } + public: /** * sqlite3_changes function. */ @@ -11978,21 +14733,25 @@ namespace sqlite_orm { } /** - * Returns libsqltie3 lib version, not sqlite_orm + * Returns libsqlite3 version, not sqlite_orm */ std::string libversion() { return sqlite3_libversion(); } bool transaction(const std::function& f) { - auto guard = transaction_guard(); - auto shouldCommit = f(); - if(shouldCommit) { - guard.commit(); - } else { - guard.rollback(); - } - return shouldCommit; + auto guard = this->transaction_guard(); + return guard.commit_on_destroy = f(); + } + + std::string current_time() { + auto con = this->get_connection(); + return this->current_time(con.get()); + } + + std::string current_date() { + auto con = this->get_connection(); + return this->current_date(con.get()); } std::string current_timestamp() { @@ -12021,31 +14780,33 @@ namespace sqlite_orm { std::vector table_names() { auto con = this->get_connection(); std::vector tableNames; - std::string sql = "SELECT name FROM sqlite_master WHERE type='table'"; using data_t = std::vector; - auto db = con.get(); - int res = sqlite3_exec( - db, - sql.c_str(), + perform_exec( + con.get(), + "SELECT name FROM sqlite_master WHERE type='table'", [](void* data, int argc, char** argv, char** /*columnName*/) -> int { auto& tableNames_ = *(data_t*)data; - for(int i = 0; i < argc; i++) { + for(int i = 0; i < argc; ++i) { if(argv[i]) { - tableNames_.push_back(argv[i]); + tableNames_.emplace_back(argv[i]); } } return 0; }, - &tableNames, - nullptr); - - if(res != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + &tableNames); + tableNames.shrink_to_fit(); return tableNames; } + /** + * Call it once during storage lifetime to make it keeping its connection opened till dtor call. + * By default if storage is not in-memory it calls `sqlite3_open` only when the connection is really + * needed and closes when it is not needed. This function breaks this rule. In memory storage always + * keeps connection opened so calling this for in-memory storage changes nothing. + * Note about multithreading: in multithreading context avoiding using this function for not in-memory + * storage may lead to data races. If you have data races in such a configuration try to call `open_forever` + * before accessing your storage - it may fix data races. + */ void open_forever() { this->isOpenedForever = true; this->connection->retain(); @@ -12069,41 +14830,42 @@ namespace sqlite_orm { * } * }; * ``` + * + * Note: Currently, a function's name must not contain white-space characters, because it doesn't get quoted. */ template void create_scalar_function() { - static_assert(is_scalar_function::value, "F cannot be a scalar function"); + static_assert(is_scalar_function_v, "F can't be an aggregate function"); std::stringstream ss; - ss << F::name(); + ss << F::name() << std::flush; auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } - this->scalarFunctions.emplace_back(new scalar_function_t{ - move(name), + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); + this->scalarFunctions.emplace_back(new user_defined_scalar_function_t{ + std::move(name), argsCount, []() -> int* { return (int*)(new F()); }, /* call = */ [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) { - auto& functionPointer = *static_cast(functionVoidPointer); + auto& function = *static_cast(functionVoidPointer); args_tuple argsTuple; - using tuple_size = std::tuple_size; - values_to_tuple().extract(values, argsTuple, argsCount); - auto result = call(functionPointer, std::move(argsTuple)); + values_to_tuple{}(values, argsTuple, argsCount); + auto result = call(function, std::move(argsTuple)); statement_binder().result(context, result); }, delete_function_callback, }); if(this->connection->retain_count() > 0) { - auto db = this->connection->get(); - try_to_create_function(db, static_cast(*this->scalarFunctions.back())); + sqlite3* db = this->connection->get(); + try_to_create_function(db, + static_cast(*this->scalarFunctions.back())); } } @@ -12129,47 +14891,49 @@ namespace sqlite_orm { * } * }; * ``` + * + * Note: Currently, a function's name must not contain white-space characters, because it doesn't get quoted. */ template void create_aggregate_function() { - static_assert(is_aggregate_function::value, "F cannot be an aggregate function"); + static_assert(is_aggregate_function_v, "F can't be a scalar function"); std::stringstream ss; - ss << F::name(); + ss << F::name() << std::flush; auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } - this->aggregateFunctions.emplace_back(new aggregate_function_t{ - move(name), + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); + this->aggregateFunctions.emplace_back(new user_defined_aggregate_function_t{ + std::move(name), argsCount, /* create = */ []() -> int* { return (int*)(new F()); }, /* step = */ - [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) { - auto& functionPointer = *static_cast(functionVoidPointer); + [](sqlite3_context*, void* functionVoidPointer, int argsCount, sqlite3_value** values) { + auto& function = *static_cast(functionVoidPointer); args_tuple argsTuple; - using tuple_size = std::tuple_size; - values_to_tuple().extract(values, argsTuple, argsCount); - call(functionPointer, &F::step, move(argsTuple)); + values_to_tuple{}(values, argsTuple, argsCount); + call(function, &F::step, std::move(argsTuple)); }, /* finalCall = */ [](sqlite3_context* context, void* functionVoidPointer) { - auto& functionPointer = *static_cast(functionVoidPointer); - auto result = functionPointer.fin(); + auto& function = *static_cast(functionVoidPointer); + auto result = function.fin(); statement_binder().result(context, result); }, delete_function_callback, }); if(this->connection->retain_count() > 0) { - auto db = this->connection->get(); - try_to_create_function(db, static_cast(*this->aggregateFunctions.back())); + sqlite3* db = this->connection->get(); + try_to_create_function( + db, + static_cast(*this->aggregateFunctions.back())); } } @@ -12178,11 +14942,10 @@ namespace sqlite_orm { */ template void delete_scalar_function() { - static_assert(is_scalar_function::value, "F cannot be a scalar function"); + static_assert(is_scalar_function_v, "F cannot be an aggregate function"); std::stringstream ss; - ss << F::name(); - auto name = ss.str(); - this->delete_function_impl(name, this->scalarFunctions); + ss << F::name() << std::flush; + this->delete_function_impl(ss.str(), this->scalarFunctions); } /** @@ -12190,11 +14953,10 @@ namespace sqlite_orm { */ template void delete_aggregate_function() { - static_assert(is_aggregate_function::value, "F cannot be an aggregate function"); + static_assert(is_aggregate_function_v, "F cannot be a scalar function"); std::stringstream ss; - ss << F::name(); - auto name = ss.str(); - this->delete_function_impl(name, this->aggregateFunctions); + ss << F::name() << std::flush; + this->delete_function_impl(ss.str(), this->aggregateFunctions); } template @@ -12204,32 +14966,29 @@ namespace sqlite_orm { return collatingObject(leftLength, lhs, rightLength, rhs); }; std::stringstream ss; - ss << C::name(); - auto name = ss.str(); - ss.flush(); - this->create_collation(name, move(func)); + ss << C::name() << std::flush; + this->create_collation(ss.str(), std::move(func)); } void create_collation(const std::string& name, collating_function f) { - collating_function* functionPointer = nullptr; + collating_function* function = nullptr; const auto functionExists = bool(f); if(functionExists) { - functionPointer = &(collatingFunctions[name] = std::move(f)); + function = &(collatingFunctions[name] = std::move(f)); } else { collatingFunctions.erase(name); } // create collations if db is open if(this->connection->retain_count() > 0) { - auto db = this->connection->get(); + sqlite3* db = this->connection->get(); auto resultCode = sqlite3_create_collation(db, name.c_str(), SQLITE_UTF8, - functionPointer, + function, functionExists ? collate_callback : nullptr); if(resultCode != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(db); } } } @@ -12237,36 +14996,41 @@ namespace sqlite_orm { template void delete_collation() { std::stringstream ss; - ss << C::name(); - auto name = ss.str(); - ss.flush(); - this->create_collation(name, {}); + ss << C::name() << std::flush; + this->create_collation(ss.str(), {}); } void begin_transaction() { - this->connection->retain(); - if(1 == this->connection->retain_count()) { - this->on_open_internal(this->connection->get()); - } - auto db = this->connection->get(); - perform_void_exec(db, "BEGIN TRANSACTION"); + this->begin_transaction_internal("BEGIN TRANSACTION"); + } + + void begin_deferred_transaction() { + this->begin_transaction_internal("BEGIN DEFERRED TRANSACTION"); + } + + void begin_immediate_transaction() { + this->begin_transaction_internal("BEGIN IMMEDIATE TRANSACTION"); + } + + void begin_exclusive_transaction() { + this->begin_transaction_internal("BEGIN EXCLUSIVE TRANSACTION"); } void commit() { - auto db = this->connection->get(); + sqlite3* db = this->connection->get(); perform_void_exec(db, "COMMIT"); this->connection->release(); if(this->connection->retain_count() < 0) { - throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); + throw std::system_error{orm_error_code::no_active_transaction}; } } void rollback() { - auto db = this->connection->get(); + sqlite3* db = this->connection->get(); perform_void_exec(db, "ROLLBACK"); this->connection->release(); if(this->connection->retain_count() < 0) { - throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); + throw std::system_error{orm_error_code::no_active_transaction}; } } @@ -12293,7 +15057,7 @@ namespace sqlite_orm { backup_t make_backup_to(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {conRef, "main", this->get_connection(), "main", move(holder)}; + return {conRef, "main", this->get_connection(), "main", std::move(holder)}; } backup_t make_backup_to(storage_base& other) { @@ -12303,7 +15067,7 @@ namespace sqlite_orm { backup_t make_backup_from(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {this->get_connection(), "main", conRef, "main", move(holder)}; + return {this->get_connection(), "main", conRef, "main", std::move(holder)}; } backup_t make_backup_from(storage_base& other) { @@ -12322,8 +15086,17 @@ namespace sqlite_orm { return this->connection->retain_count() > 0; } + /* + * returning false when there is a transaction in place + * otherwise true; function is not const because it has to call get_connection() + */ + bool get_autocommit() { + auto con = this->get_connection(); + return sqlite3_get_autocommit(con.get()); + } + int busy_handler(std::function handler) { - _busy_handler = move(handler); + _busy_handler = std::move(handler); if(this->is_opened()) { if(_busy_handler) { return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); @@ -12336,11 +15109,12 @@ namespace sqlite_orm { } protected: - storage_base(const std::string& filename_, int foreignKeysCount) : + storage_base(std::string filename, int foreignKeysCount) : pragma(std::bind(&storage_base::get_connection, this)), limit(std::bind(&storage_base::get_connection, this)), - inMemory(filename_.empty() || filename_ == ":memory:"), - connection(std::make_unique(filename_)), cachedForeignKeysCount(foreignKeysCount) { + inMemory(filename.empty() || filename == ":memory:"), + connection(std::make_unique(std::move(filename))), + cachedForeignKeysCount(foreignKeysCount) { if(this->inMemory) { this->connection->retain(); this->on_open_internal(this->connection->get()); @@ -12367,6 +15141,15 @@ namespace sqlite_orm { } } + void begin_transaction_internal(const std::string& query) { + this->connection->retain(); + if(1 == this->connection->retain_count()) { + this->on_open_internal(this->connection->get()); + } + sqlite3* db = this->connection->get(); + perform_void_exec(db, query); + } + connection_ref get_connection() { connection_ref res{*this->connection}; if(1 == this->connection->retain_count()) { @@ -12379,29 +15162,13 @@ namespace sqlite_orm { void foreign_keys(sqlite3* db, bool value) { std::stringstream ss; - ss << "PRAGMA foreign_keys = " << value; + ss << "PRAGMA foreign_keys = " << value << std::flush; perform_void_exec(db, ss.str()); } bool foreign_keys(sqlite3* db) { - std::string query = "PRAGMA foreign_keys"; - auto result = false; - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void* data, int argc, char** argv, char**) -> int { - auto& res = *(bool*)data; - if(argc) { - res = row_extractor().extract(argv[0]); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + bool result = false; + perform_exec(db, "PRAGMA foreign_keys", extract_single_value, &result); return result; } @@ -12425,8 +15192,7 @@ namespace sqlite_orm { auto resultCode = sqlite3_create_collation(db, p.first.c_str(), SQLITE_UTF8, &p.second, collate_callback); if(resultCode != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(db); } } @@ -12439,11 +15205,11 @@ namespace sqlite_orm { } for(auto& functionPointer: this->scalarFunctions) { - try_to_create_function(db, static_cast(*functionPointer)); + try_to_create_function(db, static_cast(*functionPointer)); } for(auto& functionPointer: this->aggregateFunctions) { - try_to_create_function(db, static_cast(*functionPointer)); + try_to_create_function(db, static_cast(*functionPointer)); } if(this->on_open) { @@ -12452,7 +15218,7 @@ namespace sqlite_orm { } void delete_function_impl(const std::string& name, - std::vector>& functionsVector) const { + std::vector>& functionsVector) const { auto it = find_if(functionsVector.begin(), functionsVector.end(), [&name](auto& functionPointer) { return functionPointer->name == name; }); @@ -12461,7 +15227,7 @@ namespace sqlite_orm { it = functionsVector.end(); if(this->connection->retain_count() > 0) { - auto db = this->connection->get(); + sqlite3* db = this->connection->get(); auto resultCode = sqlite3_create_function_v2(db, name.c_str(), 0, @@ -12472,16 +15238,15 @@ namespace sqlite_orm { nullptr, nullptr); if(resultCode != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(db); } } } else { - throw std::system_error(std::make_error_code(orm_error_code::function_not_found)); + throw std::system_error{orm_error_code::function_not_found}; } } - void try_to_create_function(sqlite3* db, scalar_function_t& function) { + void try_to_create_function(sqlite3* db, user_defined_scalar_function_t& function) { auto resultCode = sqlite3_create_function_v2(db, function.name.c_str(), function.argumentsCount, @@ -12492,12 +15257,11 @@ namespace sqlite_orm { nullptr, nullptr); if(resultCode != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(db); } } - void try_to_create_function(sqlite3* db, aggregate_function_t& function) { + void try_to_create_function(sqlite3* db, user_defined_aggregate_function_t& function) { auto resultCode = sqlite3_create_function(db, function.name.c_str(), function.argumentsCount, @@ -12507,15 +15271,14 @@ namespace sqlite_orm { aggregate_function_step_callback, aggregate_function_final_callback); if(resultCode != SQLITE_OK) { - throw std::system_error(std::error_code(resultCode, get_sqlite_error_category()), - sqlite3_errstr(resultCode)); + throw_translated_sqlite_error(resultCode); } } static void aggregate_function_step_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { auto functionVoidPointer = sqlite3_user_data(context); - auto functionPointer = static_cast(functionVoidPointer); + auto functionPointer = static_cast(functionVoidPointer); auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**)); auto aggregateContextIntPointer = static_cast(aggregateContextVoidPointer); if(*aggregateContextIntPointer == nullptr) { @@ -12526,7 +15289,7 @@ namespace sqlite_orm { static void aggregate_function_final_callback(sqlite3_context* context) { auto functionVoidPointer = sqlite3_user_data(context); - auto functionPointer = static_cast(functionVoidPointer); + auto functionPointer = static_cast(functionVoidPointer); auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**)); auto aggregateContextIntPointer = static_cast(aggregateContextVoidPointer); functionPointer->finalCall(context, *aggregateContextIntPointer); @@ -12535,11 +15298,11 @@ namespace sqlite_orm { static void scalar_function_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { auto functionVoidPointer = sqlite3_user_data(context); - auto functionPointer = static_cast(functionVoidPointer); + auto functionPointer = static_cast(functionVoidPointer); std::unique_ptr callablePointer(functionPointer->create(), functionPointer->destroy); if(functionPointer->argumentsCount != -1 && functionPointer->argumentsCount != argsCount) { - throw std::system_error(std::make_error_code(orm_error_code::arguments_count_does_not_match)); + throw std::system_error{orm_error_code::arguments_count_does_not_match}; } functionPointer->run(context, functionPointer, argsCount, values); } @@ -12551,35 +15314,27 @@ namespace sqlite_orm { delete fPointer; } + std::string current_time(sqlite3* db) { + std::string result; + perform_exec(db, "SELECT CURRENT_TIME", extract_single_value, &result); + return result; + } + + std::string current_date(sqlite3* db) { + std::string result; + perform_exec(db, "SELECT CURRENT_DATE", extract_single_value, &result); + return result; + } + std::string current_timestamp(sqlite3* db) { std::string result; - std::stringstream ss; - ss << "SELECT CURRENT_TIMESTAMP"; - auto query = ss.str(); - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void* data, int argc, char** argv, char**) -> int { - auto& res = *(std::string*)data; - if(argc) { - if(argv[0]) { - res = row_extractor().extract(argv[0]); - } - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + perform_exec(db, "SELECT CURRENT_TIMESTAMP", extract_single_value, &result); return result; } - void drop_table_internal(const std::string& tableName, sqlite3* db) { + void drop_table_internal(sqlite3* db, const std::string& tableName) { std::stringstream ss; - ss << "DROP TABLE '" << tableName + "'"; + ss << "DROP TABLE " << streaming_identifier(tableName) << std::flush; perform_void_exec(db, ss.str()); } @@ -12597,14 +15352,44 @@ namespace sqlite_orm { } } - // returns foreign keys count in storage definition - template - static int foreign_keys_count(T& storageImpl) { - auto res = 0; - storageImpl.for_each([&res](auto& impl) { - res += impl.foreign_keys_count(); - }); - return res; + bool calculate_remove_add_columns(std::vector& columnsToAdd, + std::vector& storageTableInfo, + std::vector& dbTableInfo) const { + bool notEqual = false; + + // iterate through storage columns + for(size_t storageColumnInfoIndex = 0; storageColumnInfoIndex < storageTableInfo.size(); + ++storageColumnInfoIndex) { + + // get storage's column info + auto& storageColumnInfo = storageTableInfo[storageColumnInfoIndex]; + auto& columnName = storageColumnInfo.name; + + // search for a column in db eith the same name + auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto& ti) { + return ti.name == columnName; + }); + if(dbColumnInfoIt != dbTableInfo.end()) { + auto& dbColumnInfo = *dbColumnInfoIt; + auto columnsAreEqual = + dbColumnInfo.name == storageColumnInfo.name && + dbColumnInfo.notnull == storageColumnInfo.notnull && + (!dbColumnInfo.dflt_value.empty()) == (!storageColumnInfo.dflt_value.empty()) && + dbColumnInfo.pk == storageColumnInfo.pk && + (dbColumnInfo.hidden == 0) == (storageColumnInfo.hidden == 0); + if(!columnsAreEqual) { + notEqual = true; + break; + } + dbTableInfo.erase(dbColumnInfoIt); + storageTableInfo.erase(storageTableInfo.begin() + + static_cast(storageColumnInfoIndex)); + --storageColumnInfoIndex; + } else { + columnsToAdd.push_back(&storageColumnInfo); + } + } + return notEqual; } const bool inMemory; @@ -12613,8 +15398,8 @@ namespace sqlite_orm { std::map collatingFunctions; const int cachedForeignKeysCount; std::function _busy_handler; - std::vector> scalarFunctions; - std::vector> aggregateFunctions; + std::vector> scalarFunctions; + std::vector> aggregateFunctions; }; } } @@ -12636,24 +15421,16 @@ namespace sqlite_orm { struct expression_object_type; template - struct expression_object_type> { - using type = typename std::decay::type; - }; + struct expression_object_type> : std::decay {}; template - struct expression_object_type>> { - using type = typename std::decay::type; - }; + struct expression_object_type>> : std::decay {}; template - struct expression_object_type> { - using type = typename std::decay::type; - }; + struct expression_object_type> : std::decay {}; template - struct expression_object_type>> { - using type = typename std::decay::type; - }; + struct expression_object_type>> : std::decay {}; template struct expression_object_type> { @@ -12665,19 +15442,24 @@ namespace sqlite_orm { using type = typename replace_range_t, L, O>::object_type; }; - template - struct expression_object_type> { - using type = typename std::decay::type; + template + struct expression_object_type> { + using type = T; }; - template - struct expression_object_type>> { - using type = typename std::decay::type; + template + struct expression_object_type, Ids...>> { + using type = T; }; + template + struct expression_object_type> : std::decay {}; + + template + struct expression_object_type>> : std::decay {}; + template struct expression_object_type> { - using transformer_type = L; using type = typename insert_range_t::object_type; }; @@ -12687,14 +15469,10 @@ namespace sqlite_orm { }; template - struct expression_object_type> { - using type = typename std::decay::type; - }; + struct expression_object_type> : std::decay {}; template - struct expression_object_type, Cols...>> { - using type = typename std::decay::type; - }; + struct expression_object_type, Cols...>> : std::decay {}; template struct get_ref_t { @@ -12716,7 +15494,7 @@ namespace sqlite_orm { template auto& get_ref(T& t) { - using arg_type = typename std::decay::type; + using arg_type = std::decay_t; get_ref_t g; return g(t); } @@ -12729,7 +15507,7 @@ namespace sqlite_orm { template auto& get_object(T& t) { - using expression_type = typename std::decay::type; + using expression_type = std::decay_t; get_object_t obj; return obj(t); } @@ -12740,7 +15518,7 @@ namespace sqlite_orm { template auto& operator()(O& e) const { - return get_ref(e.obj); + return get_ref(e.object); } }; @@ -12750,7 +15528,7 @@ namespace sqlite_orm { template auto& operator()(O& e) const { - return get_ref(e.obj); + return get_ref(e.object); } }; @@ -12760,152 +15538,114 @@ namespace sqlite_orm { template auto& operator()(O& e) const { - return get_ref(e.obj); + return get_ref(e.object); } }; } } -// #include "statement_serializator.h" +// #include "statement_serializer.h" #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer #include // std::vector #include // std::iter_swap -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +#ifndef SQLITE_ORM_OMITS_CODECVT +#include // std::codecvt_utf8_utf16 +#endif // SQLITE_ORM_OMITS_CODECVT +#include +#include +#include // std::list +// #include "functional/cxx_string_view.h" -// #include "core_functions.h" +// #include "functional/cxx_optional.h" -// #include "constraints.h" +// #include "functional/cxx_universal.h" -// #include "conditions.h" +// #include "functional/cxx_functional_polyfill.h" -// #include "column.h" +// #include "functional/mpl.h" -// #include "rowid.h" +// #include "tuple_helper/tuple_filter.h" -// #include "type_printer.h" +// #include "ast/upsert_clause.h" -// #include "table_name_collector.h" +// #include "ast/excluded.h" -#include // std::set -#include // std::string -#include // std::function -#include // std::type_index +// #include "ast/group_by.h" -// #include "select_constraints.h" +// #include "ast/into.h" -// #include "alias.h" +// #include "ast/match.h" -// #include "core_functions.h" +// #include "ast/rank.h" namespace sqlite_orm { - namespace internal { + struct rank_t {}; + } - struct table_name_collector { - using table_name_set = std::set>; - using find_table_name_t = std::function; - - find_table_name_t find_table_name; - mutable table_name_set table_names; + inline internal::rank_t rank() { + return {}; + } +} - table_name_collector() = default; +// #include "ast/special_keywords.h" - table_name_collector(find_table_name_t _find_table_name) : find_table_name(std::move(_find_table_name)) {} +// #include "core_functions.h" - template - table_name_set operator()(const T&) const { - return {}; - } +// #include "constraints.h" - template - void operator()(F O::*, std::string alias = {}) const { - if(this->find_table_name) { - table_names.insert(std::make_pair(this->find_table_name(typeid(O)), move(alias))); - } - } +// #include "conditions.h" - template - void operator()(const column_pointer&) const { - if(this->find_table_name) { - table_names.insert({this->find_table_name(typeid(T)), ""}); - } - } +// #include "schema/column.h" - template - void operator()(const alias_column_t& a) const { - (*this)(a.column, alias_extractor::get()); - } +// #include "indexed_column.h" - template - void operator()(const count_asterisk_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - if(!tableName.empty()) { - table_names.insert(std::make_pair(move(tableName), "")); - } - } - } +// #include "function.h" - template - void operator()(const asterisk_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } +// #include "prepared_statement.h" - template - void operator()(const object_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } +// #include "rowid.h" - template - void operator()(const table_rowid_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } +// #include "pointer_value.h" - template - void operator()(const table_oid_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } +// #include "type_printer.h" - template - void operator()(const table__rowid_t&) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } - }; +// #include "field_printer.h" - } +// #include "literal.h" -} +// #include "table_name_collector.h" // #include "column_names_getter.h" +#include // std::is_base_of #include // std::string #include // std::vector #include // std::reference_wrapper +#include +#include // std::move + +// #include "tuple_helper/tuple_traits.h" + +// #include "tuple_helper/tuple_iteration.h" // #include "error_code.h" +// #include "mapped_type_proxy.h" + +// #include "alias_traits.h" + // #include "select_constraints.h" +// #include "storage_lookup.h" +// pick_table +// #include "serializer_context.h" + +// #include "util.h" + namespace sqlite_orm { namespace internal { @@ -12913,92 +15653,102 @@ namespace sqlite_orm { template std::string serialize(const T& t, const C& context); - template - struct column_names_getter { - using expression_type = T; - - template - std::vector operator()(const expression_type& t, const C& context) { - auto newContext = context; - newContext.skip_table_name = false; - auto columnName = serialize(t, newContext); - if(columnName.length()) { - return {move(columnName)}; + template + std::vector& collect_table_column_names(std::vector& collectedExpressions, + bool definedOrder, + const Ctx& context) { + if(definedOrder) { + auto& table = pick_table>(context.db_objects); + collectedExpressions.reserve(collectedExpressions.size() + table.template count_of()); + table.for_each_column([qualified = !context.skip_table_name, + &tableName = table.name, + &collectedExpressions](const column_identifier& column) { + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + "." + + quote_identifier(column.name)); + } else if(qualified) { + collectedExpressions.push_back(quote_identifier(tableName) + "." + + quote_identifier(column.name)); + } else { + collectedExpressions.push_back(quote_identifier(column.name)); + } + }); + } else { + collectedExpressions.reserve(collectedExpressions.size() + 1); + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + ".*"); + } else if(!context.skip_table_name) { + const basic_table& table = pick_table>(context.db_objects); + collectedExpressions.push_back(quote_identifier(table.name) + ".*"); } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + collectedExpressions.emplace_back("*"); } } - }; - template - std::vector get_column_names(const T& t, const C& context) { - column_names_getter serializator; - return serializator(t, context); + return collectedExpressions; } - template - struct column_names_getter, void> { - using expression_type = std::reference_wrapper; - - template - std::vector operator()(const expression_type& expression, const C& context) { - return get_column_names(expression.get(), context); + /** @short Column expression collector. + */ + struct column_names_getter { + /** + * The default implementation simply serializes the passed argument. + */ + template + std::vector& operator()(const E& t, const Ctx& context) { + auto columnExpression = serialize(t, context); + if(columnExpression.empty()) { + throw std::system_error{orm_error_code::column_not_found}; + } + collectedExpressions.reserve(collectedExpressions.size() + 1); + collectedExpressions.push_back(std::move(columnExpression)); + return collectedExpressions; } - }; - - template - struct column_names_getter, void> { - using expression_type = asterisk_t; - template - std::vector operator()(const expression_type&, const C&) { - std::vector res; - res.push_back("*"); - return res; + template + std::vector& operator()(const std::reference_wrapper& expression, const Ctx& context) { + return (*this)(expression.get(), context); } - }; - - template - struct column_names_getter, void> { - using expression_type = object_t; - template - std::vector operator()(const expression_type&, const C&) { - std::vector res; - res.push_back("*"); - return res; + template + std::vector& operator()(const asterisk_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); } - }; - template - struct column_names_getter, void> { - using expression_type = columns_t; + template + std::vector& operator()(const object_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); + } - template - std::vector operator()(const expression_type& cols, const C& context) { - std::vector columnNames; - columnNames.reserve(static_cast(cols.count)); - auto newContext = context; - newContext.skip_table_name = false; - iterate_tuple(cols.columns, [&columnNames, &newContext](auto& m) { - auto columnName = serialize(m, newContext); - if(columnName.length()) { - columnNames.push_back(columnName); - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } + template + std::vector& operator()(const columns_t& cols, const Ctx& context) { + collectedExpressions.reserve(collectedExpressions.size() + cols.count); + iterate_tuple(cols.columns, [this, &context](auto& colExpr) { + (*this)(colExpr, context); }); - return columnNames; + // note: `capacity() > size()` can occur in case `asterisk_t<>` does spell out the columns in defined order + if(mpl::instantiate, + typename columns_t::columns_type>::value && + collectedExpressions.capacity() > collectedExpressions.size()) { + collectedExpressions.shrink_to_fit(); + } + return collectedExpressions; } + + std::vector collectedExpressions; }; + template + std::vector get_column_names(const T& t, const Ctx& context) { + column_names_getter serializer; + return serializer(t, context); + } } } -// #include "order_by_serializator.h" +// #include "order_by_serializer.h" #include // std::string -#include // std::vector #include // std::stringstream namespace sqlite_orm { @@ -13006,76 +15756,68 @@ namespace sqlite_orm { namespace internal { template - struct order_by_serializator; + struct order_by_serializer; - template - std::string serialize_order_by(const T& t, const C& context) { - order_by_serializator serializator; - return serializator(t, context); + template + std::string serialize_order_by(const T& t, const Ctx& context) { + order_by_serializer serializer; + return serializer(t, context); } template - struct order_by_serializator, void> { + struct order_by_serializer, void> { using statement_type = order_by_t; - template - std::string operator()(const statement_type& orderBy, const C& context) const { + template + std::string operator()(const statement_type& orderBy, const Ctx& context) const { std::stringstream ss; auto newContext = context; newContext.skip_table_name = false; - auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; - if(orderBy._collate_argument.length()) { - ss << "COLLATE " << orderBy._collate_argument << " "; + + ss << serialize(orderBy.expression, newContext); + if(!orderBy._collate_argument.empty()) { + ss << " COLLATE " << orderBy._collate_argument; } switch(orderBy.asc_desc) { case 1: - ss << "ASC"; + ss << " ASC"; break; case -1: - ss << "DESC"; + ss << " DESC"; break; } return ss.str(); } }; - template - struct order_by_serializator, void> { - using statement_type = dynamic_order_by_t; + template + struct order_by_serializer, void> { + using statement_type = dynamic_order_by_t; - template - std::string operator()(const statement_type& orderBy, const C&) const { - std::vector expressions; - for(auto& entry: orderBy) { - std::string entryString; - { - std::stringstream ss; - ss << entry.name << " "; - if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; - } - switch(entry.asc_desc) { - case 1: - ss << "ASC"; - break; - case -1: - ss << "DESC"; - break; - } - entryString = ss.str(); - } - expressions.push_back(move(entryString)); - }; + template + std::string operator()(const statement_type& orderBy, const Ctx&) const { std::stringstream ss; ss << static_cast(orderBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { + int index = 0; + for(const dynamic_order_by_entry_t& entry: orderBy) { + if(index > 0) { ss << ", "; } - } - ss << " "; + + ss << entry.name; + if(!entry._collate_argument.empty()) { + ss << " COLLATE " << entry._collate_argument; + } + switch(entry.asc_desc) { + case 1: + ss << " ASC"; + break; + case -1: + ss << " DESC"; + break; + } + ++index; + }; return ss.str(); } }; @@ -13083,122 +15825,292 @@ namespace sqlite_orm { } } +// #include "serializing_util.h" + +// #include "statement_binder.h" + // #include "values.h" -// #include "table_type.h" +// #include "schema/triggers.h" -// #include "indexed_column.h" +// #include "table_type_of.h" -// #include "function.h" +// #include "schema/index.h" -// #include "ast/upsert_clause.h" +// #include "schema/table.h" -// #include "ast/excluded.h" +// #include "util.h" namespace sqlite_orm { namespace internal { template - struct statement_serializator; + struct statement_serializer; template std::string serialize(const T& t, const C& context) { - statement_serializator serializator; - return serializator(t, context); + statement_serializer serializer; + return serializer(t, context); } + /** + * Serializer for bindable types. + */ template - struct statement_serializator::value>::type> { + struct statement_serializer> { using statement_type = T; - template - std::string operator()(const statement_type& statement, const C& context) { + template + std::string operator()(const T& statement, const Ctx& context) const { if(context.replace_bindable_with_question) { return "?"; } else { - return field_printer{}(statement); + return this->do_serialize(statement); + } + } + + private: + template && !std::is_base_of::value +#ifndef SQLITE_ORM_OMITS_CODECVT + && !std::is_base_of::value +#endif + , + bool> = true> + std::string do_serialize(const X& c) const { + static_assert(std::is_same::value, ""); + + // implementation detail: utilizing field_printer + return field_printer{}(c); + } + + std::string do_serialize(const std::string& c) const { + // implementation detail: utilizing field_printer + return quote_string_literal(field_printer{}(c)); + } + + std::string do_serialize(const char* c) const { + return quote_string_literal(c); + } +#ifndef SQLITE_ORM_OMITS_CODECVT + std::string do_serialize(const std::wstring& c) const { + // implementation detail: utilizing field_printer + return quote_string_literal(field_printer{}(c)); + } + + std::string do_serialize(const wchar_t* c) const { + std::wstring_convert> converter; + return quote_string_literal(converter.to_bytes(c)); + } +#endif +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + std::string do_serialize(const std::string_view& c) const { + return quote_string_literal(std::string(c)); + } +#ifndef SQLITE_ORM_OMITS_CODECVT + std::string do_serialize(const std::wstring_view& c) const { + std::wstring_convert> converter; + return quote_string_literal(converter.to_bytes(c.data(), c.data() + c.size())); + } +#endif +#endif + /** + * Specialization for binary data (std::vector). + */ + std::string do_serialize(const std::vector& t) const { + return quote_blob_literal(field_printer>{}(t)); + } + + template + std::string do_serialize(const pointer_binding&) const { + // always serialize null (security reasons) + return field_printer{}(nullptr); + } + }; + + template + struct statement_serializer, void> { + using statement_type = table_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) { + return this->serialize(statement, context, statement.name); + } + + template + std::string serialize(const statement_type& statement, const Ctx& context, const std::string& tableName) { + std::stringstream ss; + ss << "CREATE TABLE " << streaming_identifier(tableName) << " ( " + << streaming_expressions_tuple(statement.elements, context) << ")"; + if(statement_type::is_without_rowid_v) { + ss << " WITHOUT ROWID"; } + return ss.str(); + } + }; + + template<> + struct statement_serializer { + using statement_type = current_time_t; + + template + std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) { + return "CURRENT_TIME"; + } + }; + + template<> + struct statement_serializer { + using statement_type = current_date_t; + + template + std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) { + return "CURRENT_DATE"; + } + }; + + template<> + struct statement_serializer { + using statement_type = current_timestamp_t; + + template + std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) { + return "CURRENT_TIMESTAMP"; + } + }; + + template + struct statement_serializer, void> { + using statement_type = highlight_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) { + std::stringstream ss; + auto& tableName = lookup_table_name(context.db_objects); + ss << "HIGHLIGHT (" << streaming_identifier(tableName); + ss << ", " << serialize(statement.argument0, context); + ss << ", " << serialize(statement.argument1, context); + ss << ", " << serialize(statement.argument2, context) << ")"; + return ss.str(); + } + }; + + /** + * Serializer for literal values. + */ + template + struct statement_serializer> { + using statement_type = T; + + template + std::string operator()(const statement_type& literal, const Ctx& context) const { + static_assert(is_bindable_v>, "A literal value must be also bindable"); + + Ctx literalCtx = context; + literalCtx.replace_bindable_with_question = false; + statement_serializer> serializer{}; + return serializer(literal.value, literalCtx); + } + }; + + template + struct statement_serializer, void> { + using statement_type = filtered_aggregate_function; + + template + std::string operator()(const statement_type& statement, const Ctx& context) { + std::stringstream ss; + ss << serialize(statement.function, context); + ss << " FILTER (WHERE " << serialize(statement.where, context) << ")"; + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = excluded_t; - template - std::string operator()(const statement_type& statement, const C& context) { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; ss << "excluded."; - if(auto columnNamePointer = context.impl.column_name(statement.expression)) { - ss << "\"" << *columnNamePointer << "\""; + if(auto* columnName = find_column_name(context.db_objects, statement.expression)) { + ss << streaming_identifier(*columnName); } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + throw std::system_error{orm_error_code::column_not_found}; } return ss.str(); } }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = as_optional_t; - template - std::string operator()(const statement_type& statement, const C& context) { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { return serialize(statement.value, context); } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = std::reference_wrapper; - template - std::string operator()(const statement_type& s, const C& context) { + template + std::string operator()(const statement_type& s, const Ctx& context) const { return serialize(s.get(), context); } }; - template<> - struct statement_serializator { - using statement_type = std::nullptr_t; + template + struct statement_serializer, void> { + using statement_type = alias_holder; - template - std::string operator()(const statement_type&, const C&) { - return "?"; + template + std::string operator()(const statement_type&, const Ctx&) { + std::stringstream ss; + ss << streaming_identifier(T::get()); + return ss.str(); } }; -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template<> - struct statement_serializator { - using statement_type = std::nullopt_t; - template - std::string operator()(const statement_type&, const C&) { - return "?"; + template + struct statement_serializer, void> { + using statement_type = match_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + auto& table = pick_table(context.db_objects); + std::stringstream ss; + ss << streaming_identifier(table.name) << " MATCH " << serialize(statement.argument, context); + return ss.str(); } }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_serializator, void> { - using statement_type = alias_holder; - template - std::string operator()(const statement_type&, const C&) { - return T::get(); + template + struct statement_serializer, void> { + using statement_type = column_alias; + + template + std::string operator()(const statement_type&, const Ctx&) { + std::stringstream ss; + ss << streaming_identifier(statement_type::get()); + return ss.str(); } }; - template - struct statement_serializator, std::tuple>, void> { - using statement_type = upsert_clause, std::tuple>; + template + struct statement_serializer> { + using statement_type = T; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; ss << "ON CONFLICT"; iterate_tuple(statement.target_args, [&ss, &context](auto& value) { - using value_type = typename std::decay::type; + using value_type = std::decay_t; auto needParenthesis = std::is_member_pointer::value; ss << ' '; if(needParenthesis) { @@ -13213,86 +16125,69 @@ namespace sqlite_orm { if(std::tuple_size::value == 0) { ss << " NOTHING"; } else { - ss << " UPDATE"; auto updateContext = context; updateContext.use_parentheses = false; - iterate_tuple(statement.actions, [&ss, &updateContext](auto& value) { - ss << ' ' << serialize(value, updateContext); - }); + ss << " UPDATE " << streaming_actions_tuple(statement.actions, updateContext); } return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = built_in_function_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << statement.serialize() << "("; - std::vector args; - using args_type = typename std::decay::type::args_type; - args.reserve(std::tuple_size::value); - iterate_tuple(statement.args, [&args, &context](auto& v) { - args.push_back(serialize(v, context)); - }); - for(size_t i = 0; i < args.size(); ++i) { - ss << args[i]; - if(i < args.size() - 1) { - ss << ", "; - } + if(context.use_parentheses) { + ss << '('; + } + ss << statement.serialize() << "(" << streaming_expressions_tuple(statement.args, context) << ")"; + if(context.use_parentheses) { + ss << ')'; } - ss << ")"; return ss.str(); } }; + template + struct statement_serializer, void> + : statement_serializer, void> {}; + template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = function_call; - template - std::string operator()(const statement_type& statement, const C& context) const { - using args_tuple = std::tuple; - + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << F::name() << "("; - auto index = 0; - iterate_tuple(statement.args, [&context, &ss, &index](auto& v) { - auto value = serialize(v, context); - ss << value; - if(index < std::tuple_size::value - 1) { - ss << ", "; - } - ++index; - }); - ss << ")"; + ss << F::name() << "(" << streaming_expressions_tuple(statement.args, context) << ")"; return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = as_t; - template - std::string operator()(const statement_type& c, const C& context) const { - auto tableAliasString = alias_extractor::get(); - return serialize(c.expression, context) + " AS " + tableAliasString; + template + std::string operator()(const statement_type& c, const Ctx& context) const { + std::stringstream ss; + ss << serialize(c.expression, context) + " AS " << streaming_identifier(alias_extractor::extract()); + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = alias_column_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << "'" << T::get() << "'."; + ss << streaming_identifier(alias_extractor::extract()) << "."; } auto newContext = context; newContext.skip_table_name = true; @@ -13301,141 +16196,140 @@ namespace sqlite_orm { } }; - template<> - struct statement_serializator { - using statement_type = std::string; + template + struct statement_serializer< + E, + std::enable_if_t, is_column_pointer>>> { + using statement_type = E; - template - std::string operator()(const statement_type& c, const C& context) const { - if(context.replace_bindable_with_question) { - return "?"; + template + std::string operator()(const statement_type& e, const Ctx& context) const { + std::stringstream ss; + if(auto* columnName = find_column_name(context.db_objects, e)) { + ss << streaming_identifier( + !context.skip_table_name ? lookup_table_name>(context.db_objects) : "", + *columnName, + ""); } else { - return "\'" + c + "\'"; + throw std::system_error{orm_error_code::column_not_found}; } + return ss.str(); } }; template<> - struct statement_serializator { - using statement_type = const char*; + struct statement_serializer { + using statement_type = rank_t; - template - std::string operator()(const char* c, const C& context) const { - if(context.replace_bindable_with_question) { - return "?"; - } else { - return std::string("'") + c + "'"; - } - } - }; - - template - struct statement_serializator { - using statement_type = F O::*; - - template - std::string operator()(const statement_type& m, const C& context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "\"" << context.impl.find_table_name(typeid(O)) << "\"."; - } - if(auto columnnamePointer = context.column_name(m)) { - ss << "\"" << *columnnamePointer << "\""; - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - return ss.str(); + template + std::string operator()(const statement_type& /*statement*/, const Ctx&) const { + return "rank"; } }; template<> - struct statement_serializator { + struct statement_serializer { using statement_type = rowid_t; - template - std::string operator()(const statement_type& s, const C&) { - return static_cast(s); + template + std::string operator()(const statement_type& statement, const Ctx&) const { + return static_cast(statement); } }; template<> - struct statement_serializator { + struct statement_serializer { using statement_type = oid_t; - template - std::string operator()(const statement_type& s, const C&) { - return static_cast(s); + template + std::string operator()(const statement_type& statement, const Ctx&) const { + return static_cast(statement); } }; template<> - struct statement_serializator<_rowid_t, void> { + struct statement_serializer<_rowid_t, void> { using statement_type = _rowid_t; - template - std::string operator()(const statement_type& s, const C&) { - return static_cast(s); + template + std::string operator()(const statement_type& statement, const Ctx&) const { + return static_cast(statement); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = table_rowid_t; - template - std::string operator()(const statement_type& s, const C& context) { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; } - ss << static_cast(s); + ss << static_cast(statement); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = table_oid_t; - template - std::string operator()(const statement_type& s, const C& context) { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; } - ss << static_cast(s); + ss << static_cast(statement); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = table__rowid_t; - template - std::string operator()(const statement_type& s, const C& context) { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; + ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; } - ss << static_cast(s); + ss << static_cast(statement); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = is_equal_with_table_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + const auto tableName = lookup_table_name(context.db_objects); + ss << streaming_identifier(tableName); + ss << " = "; + ss << serialize(statement.rhs, context); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = binary_operator; - template - std::string operator()(const statement_type& c, const C& context) const { - auto lhs = serialize(c.lhs, context); - auto rhs = serialize(c.rhs, context); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + auto lhs = serialize(statement.lhs, context); + auto rhs = serialize(statement.rhs, context); std::stringstream ss; if(context.use_parentheses) { ss << '('; } - ss << lhs << " " << static_cast(c) << " " << rhs; + ss << lhs << " " << statement.serialize() << " " << rhs; if(context.use_parentheses) { ss << ')'; } @@ -13444,21 +16338,21 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = count_asterisk_t; - template - std::string operator()(const statement_type&, const C& context) const { + template + std::string operator()(const statement_type&, const Ctx& context) const { return serialize(count_asterisk_without_type{}, context); } }; template<> - struct statement_serializator { + struct statement_serializer { using statement_type = count_asterisk_without_type; - template - std::string operator()(const statement_type& c, const C&) const { + template + std::string operator()(const statement_type& c, const Ctx&) const { std::stringstream ss; auto functionName = c.serialize(); ss << functionName << "(*)"; @@ -13467,11 +16361,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = distinct_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; auto expr = serialize(c.value, context); ss << static_cast(c) << "(" << expr << ")"; @@ -13480,11 +16374,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = all_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; auto expr = serialize(c.value, context); ss << static_cast(c) << "(" << expr << ")"; @@ -13492,31 +16386,12 @@ namespace sqlite_orm { } }; - template - struct statement_serializator, void> { - using statement_type = column_pointer; - - template - std::string operator()(const statement_type& c, const C& context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(T)) << "'."; - } - if(auto columnNamePointer = context.impl.column_name_simple(c.field)) { - ss << "\"" << *columnNamePointer << "\""; - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - return ss.str(); - } - }; - template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = cast_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << static_cast(c) << " ("; ss << serialize(c.expression, context) << " AS " << type_printer().print() << ")"; @@ -13525,12 +16400,11 @@ namespace sqlite_orm { }; template - struct statement_serializator::value>::type> { + struct statement_serializer> { using statement_type = T; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << serialize(c.left, context) << " "; ss << static_cast(c) << " "; @@ -13540,11 +16414,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = simple_case_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << "CASE "; c.case_expression.apply([&ss, context](auto& c_) { @@ -13563,11 +16437,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = is_null_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << serialize(c.t, context) << " " << static_cast(c); return ss.str(); @@ -13575,11 +16449,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = is_not_null_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << serialize(c.t, context) << " " << static_cast(c); return ss.str(); @@ -13587,25 +16461,25 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = bitwise_not_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << static_cast(c) << " "; - auto cString = serialize(c.argument, context); + ss << statement.serialize() << " "; + auto cString = serialize(statement.argument, context); ss << " (" << cString << " )"; return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = negated_condition_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << static_cast(c) << " "; auto cString = serialize(c.c, context); @@ -13615,12 +16489,11 @@ namespace sqlite_orm { }; template - struct statement_serializator::value>::type> { + struct statement_serializer> { using statement_type = T; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { auto leftString = serialize(c.l, context); auto rightString = serialize(c.r, context); std::stringstream ss; @@ -13636,11 +16509,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = named_collate; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { auto newContext = context; newContext.use_parentheses = false; auto res = serialize(c.expr, newContext); @@ -13649,11 +16522,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = collate_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { auto newContext = context; newContext.use_parentheses = false; auto res = serialize(c.expr, newContext); @@ -13661,75 +16534,94 @@ namespace sqlite_orm { } }; - template - struct statement_serializator, void> { - using statement_type = dynamic_in_t; + template + struct statement_serializer< + dynamic_in_t, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using statement_type = dynamic_in_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - auto leftString = serialize(c.left, context); - ss << leftString << " " << static_cast(c) << " "; + auto leftString = serialize(statement.left, context); + ss << leftString << " "; + if(!statement.negative) { + ss << "IN"; + } else { + ss << "NOT IN"; + } + ss << " "; + if(is_compound_operator_v) { + ss << '('; + } auto newContext = context; newContext.use_parentheses = true; - ss << serialize(c.argument, newContext); + ss << serialize(statement.argument, newContext); + if(is_compound_operator_v) { + ss << ')'; + } return ss.str(); } }; - template - struct statement_serializator>, void> { - using statement_type = dynamic_in_t>; + template + struct statement_serializer< + dynamic_in_t, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using statement_type = dynamic_in_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - auto leftString = serialize(c.left, context); - ss << leftString << " " << static_cast(c) << " ("; - for(size_t index = 0; index < c.argument.size(); ++index) { - auto& value = c.argument[index]; - ss << serialize(value, context); - if(index < c.argument.size() - 1) { - ss << ", "; - } + auto leftString = serialize(statement.left, context); + ss << leftString << " "; + if(!statement.negative) { + ss << "IN"; + } else { + ss << "NOT IN"; } - ss << ")"; + ss << " (" << streaming_dynamic_expressions(statement.argument, context) << ")"; return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = in_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - auto leftString = serialize(c.left, context); - ss << leftString << " " << static_cast(c) << " ("; - std::vector args; + auto leftString = serialize(statement.left, context); + ss << leftString << " "; + if(!statement.negative) { + ss << "IN"; + } else { + ss << "NOT IN"; + } + ss << " "; using args_type = std::tuple; - args.reserve(std::tuple_size::value); - iterate_tuple(c.argument, [&args, &context](auto& v) { - args.push_back(serialize(v, context)); - }); - for(size_t i = 0; i < args.size(); ++i) { - ss << args[i]; - if(i < args.size() - 1) { - ss << ", "; - } + constexpr bool theOnlySelect = + std::tuple_size::value == 1 && is_select_v>; + if(!theOnlySelect) { + ss << "("; + } + ss << streaming_expressions_tuple(statement.argument, context); + if(!theOnlySelect) { + ss << ")"; } - ss << ")"; return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = like_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << serialize(c.arg, context) << " "; ss << static_cast(c) << " "; @@ -13742,11 +16634,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = glob_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; ss << serialize(c.arg, context) << " "; ss << static_cast(c) << " "; @@ -13756,11 +16648,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = between_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; auto expr = serialize(c.expr, context); ss << expr << " " << static_cast(c) << " "; @@ -13772,157 +16664,154 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = exists_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << static_cast(c) << " "; - ss << serialize(c.t, context); + auto newContext = context; + newContext.use_parentheses = true; + ss << "EXISTS " << serialize(statement.expression, newContext); return ss.str(); } }; template<> - struct statement_serializator { - using statement_type = autoincrement_t; + struct statement_serializer { + using statement_type = conflict_clause_t; - template - std::string operator()(const statement_type& c, const C&) const { - return static_cast(c); + template + std::string operator()(const statement_type& statement, const Ctx&) const { + switch(statement) { + case conflict_clause_t::rollback: + return "ROLLBACK"; + case conflict_clause_t::abort: + return "ABORT"; + case conflict_clause_t::fail: + return "FAIL"; + case conflict_clause_t::ignore: + return "IGNORE"; + case conflict_clause_t::replace: + return "REPLACE"; + } + return {}; + } + }; + + template + struct statement_serializer, void> { + using statement_type = primary_key_with_autoincrement; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + return serialize(statement.as_base(), context) + " AUTOINCREMENT"; + } + }; + + template<> + struct statement_serializer { + using statement_type = null_t; + + template + std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) const { + return "NULL"; + } + }; + + template<> + struct statement_serializer { + using statement_type = not_null_t; + + template + std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) const { + return "NOT NULL"; } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = primary_key_t; - template - std::string operator()(const statement_type& c, const C& context) const { - auto res = static_cast(c); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "PRIMARY KEY"; + switch(statement.options.asc_option) { + case statement_type::order_by::ascending: + ss << " ASC"; + break; + case statement_type::order_by::descending: + ss << " DESC"; + break; + default: + break; + } + if(statement.options.conflict_clause_is_on) { + ss << " ON CONFLICT " << serialize(statement.options.conflict_clause, context); + } using columns_tuple = typename statement_type::columns_tuple; - auto columnsCount = std::tuple_size::value; + const size_t columnsCount = std::tuple_size::value; if(columnsCount) { - res += "("; - decltype(columnsCount) columnIndex = 0; - iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) { - if(auto columnNamePointer = context.column_name(column)) { - res += *columnNamePointer; - if(columnIndex < columnsCount - 1) { - res += ", "; - } - ++columnIndex; - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - }); - res += ")"; + ss << "(" << streaming_mapped_columns_expressions(statement.columns, context) << ")"; } - return res; + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = unique_t; - template - std::string operator()(const statement_type& c, const C& context) const { - auto res = static_cast(c); + template + std::string operator()(const statement_type& c, const Ctx& context) const { + std::stringstream ss; + ss << static_cast(c); using columns_tuple = typename statement_type::columns_tuple; - auto columnsCount = std::tuple_size::value; + const size_t columnsCount = std::tuple_size::value; if(columnsCount) { - res += "("; - decltype(columnsCount) columnIndex = 0; - iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) { - if(auto columnNamePointer = context.column_name(column)) { - res += *columnNamePointer; - if(columnIndex < columnsCount - 1) { - res += ", "; - } - ++columnIndex; - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - }); - res += ")"; + ss << "(" << streaming_mapped_columns_expressions(c.columns, context) << ")"; } - return res; + return ss.str(); } }; template<> - struct statement_serializator { + struct statement_serializer { using statement_type = collate_constraint_t; - template - std::string operator()(const statement_type& c, const C&) const { + template + std::string operator()(const statement_type& c, const Ctx&) const { return static_cast(c); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = default_t; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& c, const Ctx& context) const { return static_cast(c) + " (" + serialize(c.value, context) + ")"; } }; template - struct statement_serializator, std::tuple>, void> { + struct statement_serializer, std::tuple>, void> { using statement_type = foreign_key_t, std::tuple>; - template - std::string operator()(const statement_type& fk, const C& context) const { + template + std::string operator()(const statement_type& fk, const Ctx& context) const { std::stringstream ss; - std::vector columnNames; - using columns_type_t = typename std::decay::type::columns_type; - constexpr const size_t columnsCount = std::tuple_size::value; - columnNames.reserve(columnsCount); - iterate_tuple(fk.columns, [&columnNames, &context](auto& v) { - if(auto columnNamePointer = context.impl.column_name(v)) { - columnNames.push_back(*columnNamePointer); - } else { - columnNames.push_back({}); - } - }); - ss << "FOREIGN KEY("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "'" << columnNames[i] << "'"; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ") REFERENCES "; - std::vector referencesNames; - using references_type_t = typename std::decay::type::references_type; - constexpr const size_t referencesCount = std::tuple_size::value; - referencesNames.reserve(referencesCount); + ss << "FOREIGN KEY(" << streaming_mapped_columns_expressions(fk.columns, context) << ") REFERENCES "; { - using first_reference_t = typename std::tuple_element<0, references_type_t>::type; - using first_reference_mapped_type = typename internal::table_type::type; - auto refTableName = context.impl.find_table_name(typeid(first_reference_mapped_type)); - ss << '\'' << refTableName << '\''; - } - iterate_tuple(fk.references, [&referencesNames, &context](auto& v) { - if(auto columnNamePointer = context.impl.column_name(v)) { - referencesNames.push_back(*columnNamePointer); - } else { - referencesNames.push_back({}); - } - }); - ss << "("; - for(size_t i = 0; i < referencesNames.size(); ++i) { - ss << "'" << referencesNames[i] << "'"; - if(i < referencesNames.size() - 1) { - ss << ", "; - } + using references_type_t = typename std::decay_t::references_type; + using first_reference_t = std::tuple_element_t<0, references_type_t>; + using first_reference_mapped_type = table_type_of_t; + auto refTableName = lookup_table_name(context.db_objects); + ss << streaming_identifier(refTableName); } - ss << ")"; + ss << "(" << streaming_mapped_columns_expressions(fk.references, context) << ")"; if(fk.on_update) { ss << ' ' << static_cast(fk.on_update) << " " << fk.on_update._action; } @@ -13934,355 +16823,323 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = check_t; - template - std::string operator()(const statement_type& c, const C& context) const { - return static_cast(c) + " " + serialize(c.expression, context); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "CHECK (" << serialize(statement.expression, context) << ")"; + return ss.str(); } }; +#if SQLITE_VERSION_NUMBER >= 3031000 + template + struct statement_serializer, void> { + using statement_type = generated_always_t; - template - struct statement_serializator, void> { - using statement_type = column_t; - - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << "'" << c.name << "' "; - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - using constraints_type = typename column_type::constraints_type; - ss << type_printer().print() << " "; - { - std::vector constraintsStrings; - constexpr const size_t constraintsCount = std::tuple_size::value; - constraintsStrings.reserve(constraintsCount); - int primaryKeyIndex = -1; - int autoincrementIndex = -1; - int tupleIndex = 0; - iterate_tuple( - c.constraints, - [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context](auto& v) { - using constraint_type = typename std::decay::type; - constraintsStrings.push_back(serialize(v, context)); - if(is_primary_key::value) { - primaryKeyIndex = tupleIndex; - } else if(std::is_same::value) { - autoincrementIndex = tupleIndex; - } - ++tupleIndex; - }); - if(primaryKeyIndex != -1 && autoincrementIndex != -1 && autoincrementIndex < primaryKeyIndex) { - iter_swap(constraintsStrings.begin() + primaryKeyIndex, - constraintsStrings.begin() + autoincrementIndex); - } - for(auto& str: constraintsStrings) { - ss << str << ' '; - } + if(statement.full) { + ss << "GENERATED ALWAYS "; + } + ss << "AS ("; + ss << serialize(statement.expression, context) << ")"; + switch(statement.storage) { + case basic_generated_always::storage_type::not_specified: + //.. + break; + case basic_generated_always::storage_type::virtual_: + ss << " VIRTUAL"; + break; + case basic_generated_always::storage_type::stored: + ss << " STORED"; + break; } - if(c.not_null()) { - ss << "NOT NULL "; + return ss.str(); + } + }; +#endif + template + struct statement_serializer, void> { + using statement_type = column_t; + + template + std::string operator()(const statement_type& column, const Ctx& context) const { + using column_type = statement_type; + + std::stringstream ss; + ss << streaming_identifier(column.name); + if(!context.skip_types_and_constraints) { + ss << " " << type_printer>().print(); + ss << " " + << streaming_column_constraints( + call_as_template_base(polyfill::identity{})(column), + column.is_not_null(), + context); } return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = remove_all_t; - template - std::string operator()(const statement_type& rem, const C& context) const { - auto& tImpl = context.impl.template get_impl(); + template + std::string operator()(const statement_type& rem, const Ctx& context) const { + auto& table = pick_table(context.db_objects); + std::stringstream ss; - ss << "DELETE FROM '" << tImpl.table.name << "' "; - iterate_tuple(rem.conditions, [&context, &ss](auto& v) { - ss << serialize(v, context); - }); + ss << "DELETE FROM " << streaming_identifier(table.name) + << streaming_conditions_tuple(rem.conditions, context); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = replace_t; - template - std::string operator()(const statement_type& rep, const C& context) const { - return serialize_replace_range_impl(rep, context, 1); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + using expression_type = std::decay_t; + using object_type = typename expression_object_type::type; + auto& table = pick_table(context.db_objects); + std::stringstream ss; + ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" + << streaming_non_generated_column_names(table) << ")" + << " VALUES (" + << streaming_field_values_excluding(check_if{}, + empty_callable(), // don't exclude + context, + get_ref(statement.object)) + << ")"; + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = insert_explicit; - template - std::string operator()(const statement_type& ins, const C& context) const { - constexpr const size_t colsCount = std::tuple_size>::value; + template + std::string operator()(const statement_type& ins, const Ctx& context) const { + constexpr size_t colsCount = std::tuple_size>::value; static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); - using expression_type = typename std::decay::type; + using expression_type = std::decay_t; using object_type = typename expression_object_type::type; - auto& tImpl = context.impl.template get_impl(); + auto& table = pick_table(context.db_objects); std::stringstream ss; - ss << "INSERT INTO '" << tImpl.table.name << "' "; - std::vector columnNames; - columnNames.reserve(colsCount); - { - auto columnsContext = context; - columnsContext.skip_table_name = true; - iterate_tuple(ins.columns.columns, [&columnNames, &columnsContext](auto& m) { - auto columnName = serialize(m, columnsContext); - if(!columnName.empty()) { - columnNames.push_back(columnName); - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); + ss << "INSERT INTO " << streaming_identifier(table.name) << " "; + ss << "(" << streaming_mapped_columns_expressions(ins.columns.columns, context) << ") " + << "VALUES ("; + iterate_tuple(ins.columns.columns, + [&ss, &context, &object = get_ref(ins.obj), first = true](auto& memberPointer) mutable { + using member_pointer_type = std::decay_t; + static_assert(!is_setter_v, + "Unable to use setter within insert explicit"); + + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] + << serialize(polyfill::invoke(memberPointer, object), context); + }); + ss << ")"; + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = update_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + using expression_type = std::decay_t; + using object_type = typename expression_object_type::type; + auto& table = pick_table(context.db_objects); + + std::stringstream ss; + ss << "UPDATE " << streaming_identifier(table.name) << " SET "; + table.template for_each_column_excluding>( + [&table, &ss, &context, &object = get_ref(statement.object), first = true](auto& column) mutable { + if(exists_in_composite_primary_key(table, column)) { + return; } + + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] << streaming_identifier(column.name) << " = " + << serialize(polyfill::invoke(column.member_pointer, object), context); + }); + ss << " WHERE "; + table.for_each_column( + [&table, &context, &ss, &object = get_ref(statement.object), first = true](auto& column) mutable { + if(!column.template is() && !exists_in_composite_primary_key(table, column)) { + return; + } + + constexpr std::array sep = {" AND ", ""}; + ss << sep[std::exchange(first, false)] << streaming_identifier(column.name) << " = " + << serialize(polyfill::invoke(column.member_pointer, object), context); }); - } - ss << "("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - ss << "VALUES ("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "?"; - if(i < columnNames.size() - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = update_t; - - template - std::string operator()(const statement_type& upd, const C& context) const { - using expression_type = typename std::decay::type; - using object_type = typename expression_object_type::type; - auto& tImpl = context.impl.template get_impl(); + template + struct statement_serializer, void> { + using statement_type = dynamic_set_t; + template + std::string operator()(const statement_type& statement, const Ctx&) const { std::stringstream ss; - ss << "UPDATE '" << tImpl.table.name << "' SET "; - std::vector setColumnNames; - tImpl.table.for_each_column([&setColumnNames](auto& c) { - if(!c.template has>()) { - setColumnNames.emplace_back(c.name); - } - }); - for(size_t i = 0; i < setColumnNames.size(); ++i) { - ss << "\"" << setColumnNames[i] << "\"" - << " = ?"; - if(i < setColumnNames.size() - 1) { - ss << ","; - } - ss << " "; - } - ss << "WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ?"; - if(i < primaryKeyColumnNames.size() - 1) { - ss << " AND"; + ss << "SET "; + int index = 0; + for(const dynamic_set_entry& entry: statement) { + if(index > 0) { + ss << ", "; } - ss << " "; + ss << entry.serialized_value; + ++index; } return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = set_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << static_cast(statement); - auto assignsCount = std::tuple_size::value; - decltype(assignsCount) assignIndex = 0; + ss << "SET "; auto leftContext = context; leftContext.skip_table_name = true; - iterate_tuple(statement.assigns, - [&ss, &context, &leftContext, &assignIndex, assignsCount](auto& value) { - ss << ' ' << serialize(value.lhs, leftContext); - ss << ' ' << static_cast(value) << ' '; - ss << serialize(value.rhs, context); - if(assignIndex < assignsCount - 1) { - ss << ","; - } - ++assignIndex; - }); + iterate_tuple(statement.assigns, [&ss, &context, &leftContext, first = true](auto& value) mutable { + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] << serialize(value.lhs, leftContext) << ' ' + << value.serialize() << ' ' << serialize(value.rhs, context); + }); return ss.str(); } }; - template - struct statement_serializator, Wargs...>, void> { - using statement_type = update_all_t, Wargs...>; + template + std::set> collect_table_names(const set_t& set, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(set, collector); + return std::move(collector.table_names); + } - template - std::string operator()(const statement_type& upd, const C& context) const { - std::stringstream ss; - ss << "UPDATE "; - table_name_collector collector([&context](std::type_index ti) { - return context.impl.find_table_name(ti); - }); - iterate_ast(upd.set.assigns, collector); - if(!collector.table_names.empty()) { - if(collector.table_names.size() == 1) { - ss << " '" << collector.table_names.begin()->first << "' "; - ss << static_cast(upd.set) << " "; - std::vector setPairs; - auto leftContext = context; - leftContext.skip_table_name = true; - iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto& asgn) { - std::stringstream sss; - sss << serialize(asgn.lhs, leftContext); - sss << " " << static_cast(asgn) << " "; - sss << serialize(asgn.rhs, context) << " "; - setPairs.push_back(sss.str()); - }); - auto setPairsCount = setPairs.size(); - for(size_t i = 0; i < setPairsCount; ++i) { - ss << setPairs[i] << " "; - if(i < setPairsCount - 1) { - ss << ", "; - } - } - iterate_tuple(upd.conditions, [&context, &ss](auto& v) { - ss << serialize(v, context); - }); - return ss.str(); - } else { - throw std::system_error(std::make_error_code(orm_error_code::too_many_tables_specified)); - } - } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_set_fields_specified)); - } - } - }; + template + const std::set>& collect_table_names(const dynamic_set_t& set, + const Ctx&) { + return set.collector.table_names; + } - template - std::string serialize_insert_range_impl(const T& /*statement*/, const C& context, const int valuesCount) { - using object_type = typename expression_object_type::type; - auto& tImpl = context.impl.template get_impl(); + template = true> + std::set> collect_table_names(const T& sel, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(sel.col, collector); + iterate_ast(sel.conditions, collector); + return std::move(collector.table_names); + } - std::stringstream ss; - ss << "INSERT INTO '" << tImpl.table.name << "' "; - std::vector columnNames; - auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); - - tImpl.table.for_each_column([&columnNames, &compositeKeyColumnNames](auto& c) { - using table_type = typename std::decay::type; - if(table_type::is_without_rowid || !c.template has>()) { - auto it = find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); - if(it == compositeKeyColumnNames.end()) { - columnNames.emplace_back(c.name); - } - } - }); + template + struct statement_serializer, void> { + using statement_type = update_all_t; - const auto columnNamesCount = columnNames.size(); - if(columnNamesCount) { - ss << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - } else { - ss << "DEFAULT "; - } - ss << "VALUES "; - if(columnNamesCount) { - auto valuesString = [columnNamesCount] { - std::stringstream ss_; - ss_ << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss_ << "?"; - if(i < columnNamesCount - 1) { - ss_ << ", "; - } else { - ss_ << ")"; - } - } - return ss_.str(); - }(); - for(auto i = 0; i < valuesCount; ++i) { - ss << valuesString; - if(i < valuesCount - 1) { - ss << ","; - } - ss << " "; + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + const auto& tableNames = collect_table_names(statement.set, context); + if(tableNames.empty()) { + throw std::system_error{orm_error_code::no_tables_specified}; } - } else if(valuesCount != 1) { - throw std::system_error(std::make_error_code(orm_error_code::cannot_use_default_value)); - } + const std::string& tableName = tableNames.begin()->first; - return ss.str(); - } + std::stringstream ss; + ss << "UPDATE " << streaming_identifier(tableName) << ' ' << serialize(statement.set, context) + << streaming_conditions_tuple(statement.conditions, context); + return ss.str(); + } + }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = insert_t; - template - std::string operator()(const statement_type& statement, const C& context) const { - return serialize_insert_range_impl(statement, context, 1); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + using object_type = typename expression_object_type::type; + auto& table = pick_table(context.db_objects); + using is_without_rowid = typename std::decay_t::is_without_rowid; + + std::vector> columnNames; + table.template for_each_column_excluding< + mpl::conjunction>, + mpl::disjunction_fn>>( + [&table, &columnNames](auto& column) { + if(exists_in_composite_primary_key(table, column)) { + return; + } + + columnNames.push_back(cref(column.name)); + }); + const size_t columnNamesCount = columnNames.size(); + + std::stringstream ss; + ss << "INSERT INTO " << streaming_identifier(table.name) << " "; + if(columnNamesCount) { + ss << "(" << streaming_identifiers(columnNames) << ")"; + } else { + ss << "DEFAULT"; + } + ss << " VALUES"; + if(columnNamesCount) { + ss << " (" + << streaming_field_values_excluding( + mpl::conjunction>, + mpl::disjunction_fn>{}, + [&table](auto& column) { + return exists_in_composite_primary_key(table, column); + }, + context, + get_ref(statement.object)) + << ")"; + } + + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = into_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type&, const Ctx& context) const { + auto& table = pick_table(context.db_objects); + std::stringstream ss; - auto& tImpl = context.impl.template get_impl(); - ss << "INTO " << tImpl.table.name; + ss << "INTO " << streaming_identifier(table.name); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = columns_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - auto index = 0; if(context.use_parentheses) { ss << '('; } - iterate_tuple(statement.columns, [&context, &ss, &index](auto& value) { - ss << serialize(value, context); - if(index < int(std::tuple_size>::value) - 1) { - ss << ", "; - } - ++index; - }); + // note: pass `statement` itself + ss << streaming_serialized(get_column_names(statement, context)); if(context.use_parentheses) { ss << ')'; } @@ -14291,28 +17148,26 @@ namespace sqlite_orm { }; template - struct statement_serializator< - T, - typename std::enable_if::value || is_replace_raw::value>::type> { + struct statement_serializer, is_replace_raw>>> { using statement_type = T; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - if(is_insert_raw::value) { + if(is_insert_raw_v) { ss << "INSERT"; } else { ss << "REPLACE"; } iterate_tuple(statement.args, [&context, &ss](auto& value) { - using value_type = typename std::decay::type; + using value_type = std::decay_t; ss << ' '; - if(is_columns::value) { + if(is_columns_v) { auto newContext = context; newContext.skip_table_name = true; newContext.use_parentheses = true; ss << serialize(value, newContext); - } else if(is_values::value || is_select::value) { + } else if(is_values_v || is_select_v) { auto newContext = context; newContext.use_parentheses = false; ss << serialize(value, newContext); @@ -14325,255 +17180,236 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = remove_t; - template - std::string operator()(const statement_type&, const C& context) const { - auto& tImpl = context.impl.template get_impl(); + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + auto& table = pick_table(context.db_objects); std::stringstream ss; - ss << "DELETE FROM '" << tImpl.table.name << "' "; - ss << "WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ? "; - if(i < primaryKeyColumnNames.size() - 1) { - ss << "AND "; + ss << "DELETE FROM " << streaming_identifier(table.name) << " " + << "WHERE "; + std::vector idsStrings; + idsStrings.reserve(std::tuple_size::value); + iterate_tuple(statement.ids, [&idsStrings, &context](auto& idValue) { + idsStrings.push_back(serialize(idValue, context)); + }); + table.for_each_primary_key_column([&table, &ss, &idsStrings, index = 0](auto& memberPointer) mutable { + auto* columnName = table.find_column_name(memberPointer); + if(!columnName) { + throw std::system_error{orm_error_code::column_not_found}; } - } + + constexpr std::array sep = {" AND ", ""}; + ss << sep[index == 0] << streaming_identifier(*columnName) << " = " << idsStrings[index]; + ++index; + }); return ss.str(); } }; - template - std::string serialize_replace_range_impl(const T& rep, const C& context, const int valuesCount) { - using expression_type = typename std::decay::type; - using object_type = typename expression_object_type::type; - auto& tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "REPLACE INTO '" << tImpl.table.name << "' ("; - auto columnNames = tImpl.table.column_names(); - auto columnNamesCount = columnNames.size(); - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ", "; - } else { - ss << ") "; - } - } - ss << "VALUES "; - auto valuesString = [columnNamesCount] { - std::stringstream ss_; - ss_ << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss_ << "?"; - if(i < columnNamesCount - 1) { - ss_ << ", "; - } else { - ss_ << ")"; - } - } - return ss_.str(); - }(); - for(auto i = 0; i < valuesCount; ++i) { - ss << valuesString; - if(i < valuesCount - 1) { - ss << ","; - } - ss << " "; - } - return ss.str(); - } - template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = replace_range_t; - template - std::string operator()(const statement_type& rep, const C& context) const { - auto valuesCount = static_cast(std::distance(rep.range.first, rep.range.second)); - return serialize_replace_range_impl(rep, context, valuesCount); + template + std::string operator()(const statement_type& rep, const Ctx& context) const { + using expression_type = std::decay_t; + using object_type = typename expression_object_type::type; + auto& table = pick_table(context.db_objects); + + std::stringstream ss; + ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" + << streaming_non_generated_column_names(table) << ")"; + const auto valuesCount = std::distance(rep.range.first, rep.range.second); + const auto columnsCount = table.template count_of_columns_excluding(); + ss << " VALUES " << streaming_values_placeholders(columnsCount, valuesCount); + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = insert_range_t; - template - std::string operator()(const statement_type& statement, const C& context) const { - const auto valuesCount = static_cast(std::distance(statement.range.first, statement.range.second)); - return serialize_insert_range_impl(statement, context, valuesCount); - } - }; + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + using object_type = typename expression_object_type::type; + auto& table = pick_table(context.db_objects); + using is_without_rowid = typename std::decay_t::is_without_rowid; + + std::vector> columnNames; + table.template for_each_column_excluding< + mpl::conjunction>, + mpl::disjunction_fn>>( + [&table, &columnNames](auto& column) { + if(exists_in_composite_primary_key(table, column)) { + return; + } - template - std::string serialize_get_all_impl(const T& get, const C& context) { - using primary_type = typename T::type; + columnNames.push_back(cref(column.name)); + }); + const size_t valuesCount = std::distance(statement.range.first, statement.range.second); + const size_t columnNamesCount = columnNames.size(); - table_name_collector collector; - collector.table_names.insert( - std::make_pair(context.impl.find_table_name(typeid(primary_type)), std::string{})); - iterate_ast(get.conditions, collector); - std::stringstream ss; - ss << "SELECT "; - auto& tImpl = context.impl.template get_impl(); - auto columnNames = tImpl.table.column_names(); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "\"" << tImpl.table.name << "\"." - << "\"" << columnNames[i] << "\""; - if(i < columnNames.size() - 1) { - ss << ", "; + std::stringstream ss; + ss << "INSERT INTO " << streaming_identifier(table.name) << " "; + if(columnNamesCount) { + ss << "(" << streaming_identifiers(columnNames) << ")"; } else { - ss << " "; - } - } - ss << "FROM "; - std::vector> tableNames(collector.table_names.begin(), - collector.table_names.end()); - for(size_t i = 0; i < tableNames.size(); ++i) { - auto& tableNamePair = tableNames[i]; - ss << "'" << tableNamePair.first << "' "; - if(!tableNamePair.second.empty()) { - ss << tableNamePair.second << " "; + ss << "DEFAULT"; } - if(int(i) < int(tableNames.size()) - 1) { - ss << ","; + ss << " VALUES "; + if(columnNamesCount) { + ss << streaming_values_placeholders(columnNamesCount, valuesCount); + } else if(valuesCount != 1) { + throw std::system_error{orm_error_code::cannot_use_default_value}; } - ss << " "; + return ss.str(); } - iterate_tuple(get.conditions, [&context, &ss](auto& v) { - ss << serialize(v, context); - }); + }; + + template + std::string serialize_get_all_impl(const T& getAll, const Ctx& context) { + using table_type = type_t; + using mapped_type = mapped_type_proxy_t; + + auto& table = pick_table(context.db_objects); + + std::stringstream ss; + ss << "SELECT " << streaming_table_column_names(table, alias_extractor::as_qualifier(table)) + << " FROM " << streaming_identifier(table.name, alias_extractor::as_alias()) + << streaming_conditions_tuple(getAll.conditions, context); return ss.str(); } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_all_optional_t; - template - std::string operator()(const statement_type& get, const C& context) const { + template + std::string operator()(const statement_type& get, const Ctx& context) const { return serialize_get_all_impl(get, context); } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_all_pointer_t; - template - std::string operator()(const statement_type& get, const C& context) const { + template + std::string operator()(const statement_type& get, const Ctx& context) const { return serialize_get_all_impl(get, context); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_all_t; - template - std::string operator()(const statement_type& get, const C& context) const { + template + std::string operator()(const statement_type& get, const Ctx& context) const { return serialize_get_all_impl(get, context); } }; - template - std::string serialize_get_impl(const T&, const C& context) { - using primary_type = typename T::type; - auto& tImpl = context.impl.template get_impl(); + template + std::string serialize_get_impl(const T&, const Ctx& context) { + using primary_type = type_t; + auto& table = pick_table(context.db_objects); std::stringstream ss; - ss << "SELECT "; - auto columnNames = tImpl.table.column_names(); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNames.size() - 1) { - ss << ","; - } - ss << " "; + ss << "SELECT " << streaming_table_column_names(table, std::string{}) << " FROM " + << streaming_identifier(table.name) << " WHERE "; + + auto primaryKeyColumnNames = table.primary_key_column_names(); + if(primaryKeyColumnNames.empty()) { + throw std::system_error{orm_error_code::table_has_no_primary_key_column}; } - ss << "FROM '" << tImpl.table.name << "' WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - if(!primaryKeyColumnNames.empty()) { - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ? "; - if(i < primaryKeyColumnNames.size() - 1) { - ss << "AND"; - } - ss << ' '; + + for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { + if(i > 0) { + ss << " AND "; } - return ss.str(); - } else { - throw std::system_error(std::make_error_code(orm_error_code::table_has_no_primary_key_column)); + ss << streaming_identifier(primaryKeyColumnNames[i]) << " = ?"; } + return ss.str(); } template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_t; - template - std::string operator()(const statement_type& get, const C& context) const { + template + std::string operator()(const statement_type& get, const Ctx& context) const { return serialize_get_impl(get, context); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_pointer_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { return serialize_get_impl(statement, context); } }; template<> - struct statement_serializator { - using statement_type = insert_constraint; + struct statement_serializer { + using statement_type = conflict_action; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx&) const { switch(statement) { - case insert_constraint::abort: - return "OR ABORT"; - case insert_constraint::fail: - return "OR FAIL"; - case insert_constraint::ignore: - return "OR IGNORE"; - case insert_constraint::replace: - return "OR REPLACE"; - case insert_constraint::rollback: - return "OR ROLLBACK"; + case conflict_action::replace: + return "REPLACE"; + case conflict_action::abort: + return "ABORT"; + case conflict_action::fail: + return "FAIL"; + case conflict_action::ignore: + return "IGNORE"; + case conflict_action::rollback: + return "ROLLBACK"; } + return {}; + } + }; + + template<> + struct statement_serializer { + using statement_type = insert_constraint; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + return "OR " + serialize(statement.action, context); } }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = get_optional_t; - template - std::string operator()(const statement_type& get, const C& context) const { + template + std::string operator()(const statement_type& get, const Ctx& context) const { return serialize_get_impl(get, context); } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = select_t; - template - std::string operator()(const statement_type& sel, const C& context) const { + template + std::string operator()(const statement_type& sel, Ctx context) const { + context.skip_table_name = false; + std::stringstream ss; - const auto isCompoundOperator = is_base_of_template::value; - if(!isCompoundOperator) { + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << "("; } @@ -14582,49 +17418,27 @@ namespace sqlite_orm { if(get_distinct(sel.col)) { ss << static_cast(distinct(0)) << " "; } - auto columnNames = get_column_names(sel.col, context); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - table_name_collector collector([&context](std::type_index ti) { - return context.impl.find_table_name(ti); - }); - const auto explicitFromItemsCount = count_tuple, is_from>::value; - if(!explicitFromItemsCount) { - iterate_ast(sel.col, collector); - iterate_ast(sel.conditions, collector); - join_iterator()([&collector, &context](const auto& c) { - using original_join_type = typename std::decay::type::join_type::type; - using cross_join_type = typename internal::mapped_type_proxy::type; - auto crossJoinedTableName = context.impl.find_table_name(typeid(cross_join_type)); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias(std::move(crossJoinedTableName), - std::move(tableAliasString)); - collector.table_names.erase(tableNameWithAlias); + ss << streaming_serialized(get_column_names(sel.col, context)); + using conditions_tuple = typename statement_type::conditions_type; + constexpr bool hasExplicitFrom = tuple_has::value; + if(!hasExplicitFrom) { + auto tableNames = collect_table_names(sel, context); + using joins_index_sequence = filter_tuple_sequence_t; + // deduplicate table names of constrained join statements + iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) { + using original_join_type = typename std::decay_t::type; + using cross_join_type = mapped_type_proxy_t; + std::pair tableNameWithAlias{ + lookup_table_name(context.db_objects), + alias_extractor::as_alias()}; + tableNames.erase(tableNameWithAlias); }); - if(!collector.table_names.empty() && !isCompoundOperator) { - ss << " FROM "; - std::vector> tableNames(collector.table_names.begin(), - collector.table_names.end()); - for(size_t i = 0; i < tableNames.size(); ++i) { - auto& tableNamePair = tableNames[i]; - ss << "'" << tableNamePair.first << "'"; - if(!tableNamePair.second.empty()) { - ss << ' ' << tableNamePair.second; - } - if(int(i) < int(tableNames.size()) - 1) { - ss << ", "; - } - } + if(!tableNames.empty() && !is_compound_operator_v) { + ss << " FROM " << streaming_identifiers(tableNames); } } - iterate_tuple(sel.conditions, [&context, &ss](auto& v) { - ss << ' ' << serialize(v, context); - }); - if(!is_base_of_template::value) { + ss << streaming_conditions_tuple(sel.conditions, context); + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << ")"; } @@ -14634,11 +17448,11 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = indexed_column_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; ss << serialize(statement.column_or_expression, context); if(!statement._collation_name.empty()) { @@ -14653,285 +17467,382 @@ namespace sqlite_orm { ss << " ASC"; break; default: - throw std::system_error(std::make_error_code(orm_error_code::incorrect_order)); + throw std::system_error{orm_error_code::incorrect_order}; } } return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = index_t; + template + struct statement_serializer, void> { + using statement_type = using_fts5_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "USING FTS5("; + auto subContext = context; + subContext.skip_types_and_constraints = true; + ss << streaming_expressions_tuple(statement.columns, subContext) << ")"; + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = virtual_table_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "CREATE VIRTUAL TABLE IF NOT EXISTS "; + ss << streaming_identifier(statement.name) << ' '; + ss << serialize(statement.module_details, context); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = index_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; ss << "CREATE "; if(statement.unique) { ss << "UNIQUE "; } - using columns_type = typename std::decay::type::columns_type; - using head_t = typename std::tuple_element<0, columns_type>::type::column_type; - using indexed_type = typename table_type::type; - ss << "INDEX IF NOT EXISTS '" << statement.name << "' ON '" - << context.impl.find_table_name(typeid(indexed_type)) << "' ("; - std::vector columnNames; - iterate_tuple(statement.columns, [&columnNames, &context](auto& v) { - auto columnName = serialize(v, context); - columnNames.push_back(move(columnName)); + using indexed_type = typename std::decay_t::table_mapped_type; + ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " + << streaming_identifier(lookup_table_name(context.db_objects)); + std::vector columnNames; + std::string whereString; + iterate_tuple(statement.elements, [&columnNames, &context, &whereString](auto& value) { + using value_type = std::decay_t; + if(!is_where_v) { + auto newContext = context; + newContext.use_parentheses = false; + auto whereString = serialize(value, newContext); + columnNames.push_back(std::move(whereString)); + } else { + auto columnName = serialize(value, context); + whereString = std::move(columnName); + } + }); + ss << " (" << streaming_serialized(columnNames) << ")"; + if(!whereString.empty()) { + ss << ' ' << whereString; + } + return ss.str(); + } + }; + + template + struct statement_serializer> { + using statement_type = From; + + template + std::string operator()(const statement_type&, const Ctx& context) const { + std::stringstream ss; + ss << "FROM "; + iterate_tuple([&context, &ss, first = true](auto* dummyItem) mutable { + using table_type = std::remove_pointer_t; + + constexpr std::array sep = {", ", ""}; + ss << sep[std::exchange(first, false)] + << streaming_identifier(lookup_table_name>(context.db_objects), + alias_extractor::as_alias()); + }); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = old_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "OLD."; + auto newContext = context; + newContext.skip_table_name = true; + ss << serialize(statement.expression, newContext); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = new_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "NEW."; + auto newContext = context; + newContext.skip_table_name = true; + ss << serialize(statement.expression, newContext); + return ss.str(); + } + }; + + template<> + struct statement_serializer { + using statement_type = raise_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + switch(statement.type) { + case raise_t::type_t::ignore: + return "RAISE(IGNORE)"; + + case raise_t::type_t::rollback: + return "RAISE(ROLLBACK, " + serialize(statement.message, context) + ")"; + + case raise_t::type_t::abort: + return "RAISE(ABORT, " + serialize(statement.message, context) + ")"; + + case raise_t::type_t::fail: + return "RAISE(FAIL, " + serialize(statement.message, context) + ")"; + } + return {}; + } + }; + + template<> + struct statement_serializer { + using statement_type = trigger_timing; + + template + std::string operator()(const statement_type& statement, const Ctx&) const { + switch(statement) { + case trigger_timing::trigger_before: + return "BEFORE"; + case trigger_timing::trigger_after: + return "AFTER"; + case trigger_timing::trigger_instead_of: + return "INSTEAD OF"; + } + return {}; + } + }; + + template<> + struct statement_serializer { + using statement_type = trigger_type; + + template + std::string operator()(const statement_type& statement, const Ctx&) const { + switch(statement) { + case trigger_type::trigger_delete: + return "DELETE"; + case trigger_type::trigger_insert: + return "INSERT"; + case trigger_type::trigger_update: + return "UPDATE"; + } + return {}; + } + }; + + template<> + struct statement_serializer { + using statement_type = trigger_type_base_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + + ss << serialize(statement.timing, context) << " " << serialize(statement.type, context); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = trigger_update_type_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + + ss << serialize(statement.timing, context) << " UPDATE OF " + << streaming_mapped_columns_expressions(statement.columns, context); + return ss.str(); + } + }; + + template + struct statement_serializer, void> { + using statement_type = trigger_base_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + + ss << serialize(statement.type_base, context); + ss << " ON " << streaming_identifier(lookup_table_name(context.db_objects)); + if(statement.do_for_each_row) { + ss << " FOR EACH ROW"; + } + statement.container_when.apply([&ss, &context](auto& value) { + ss << " WHEN " << serialize(value, context); }); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ")"; return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = from_t; - - template - std::string operator()(const statement_type& statement, const C& context) const { - using tuple = std::tuple; + template + struct statement_serializer, void> { + using statement_type = trigger_t; + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << "FROM "; - size_t index = 0; - iterate_tuple([&context, &ss, &index](auto* itemPointer) { - using mapped_type = typename std::remove_pointer::type; - - auto aliasString = alias_extractor::get(); - ss << "'" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) - << "'"; - if(aliasString.length()) { - ss << " '" << aliasString << "'"; - } - if(index < std::tuple_size::value - 1) { - ss << ", "; + ss << "CREATE "; + + ss << "TRIGGER IF NOT EXISTS " << streaming_identifier(statement.name) << " " + << serialize(statement.base, context); + ss << " BEGIN "; + iterate_tuple(statement.elements, [&ss, &context](auto& element) { + using element_type = std::decay_t; + if(is_select_v) { + auto newContext = context; + newContext.use_parentheses = false; + ss << serialize(element, newContext); + } else { + ss << serialize(element, context); } - ++index; + ss << ";"; }); + ss << " END"; + return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = where_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; ss << statement.serialize() << " "; auto whereString = serialize(statement.expression, context); - ss << "( " << whereString << ") "; + ss << '(' << whereString << ')'; return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = order_by_t; - template - std::string operator()(const statement_type& orderBy, const C& context) const { + template + std::string operator()(const statement_type& orderBy, const Ctx& context) const { std::stringstream ss; ss << static_cast(orderBy) << " "; - auto orderByString = serialize_order_by(orderBy, context); - ss << orderByString << " "; + ss << serialize_order_by(orderBy, context); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = dynamic_order_by_t; - template - std::string operator()(const statement_type& orderBy, const CC& context) const { + template + std::string operator()(const statement_type& orderBy, const Ctx& context) const { return serialize_order_by(orderBy, context); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = multi_order_by_t; - template - std::string operator()(const statement_type& orderBy, const C& context) const { + template + std::string operator()(const statement_type& orderBy, const Ctx& context) const { std::stringstream ss; - std::vector expressions; - iterate_tuple(orderBy.args, [&expressions, &context](auto& v) { - auto expression = serialize_order_by(v, context); - expressions.push_back(move(expression)); - }); - ss << static_cast(orderBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { - ss << ", "; - } - } - ss << " "; + ss << static_cast(orderBy) << " " << streaming_expressions_tuple(orderBy.args, context); return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = cross_join_t; + template + struct statement_serializer< + Join, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using statement_type = Join; - template - std::string operator()(const statement_type& c, const C& context) const { + template + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(c) << " "; - ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>(context.db_objects)); return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = inner_join_t; + template + struct statement_serializer> { + using statement_type = Join; - template - std::string operator()(const statement_type& l, const C& context) const { + template + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(l) << " "; - auto aliasString = alias_extractor::get(); - ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; - if(aliasString.length()) { - ss << "'" << aliasString << "' "; - } - ss << serialize(l.constraint, context); + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>>(context.db_objects), + alias_extractor>::as_alias()) + << " " << serialize(join.constraint, context); return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = on_t; - template - std::string operator()(const statement_type& t, const C& context) const { + template + std::string operator()(const statement_type& on, const Ctx& context) const { std::stringstream ss; auto newContext = context; newContext.skip_table_name = false; - ss << static_cast(t) << " " << serialize(t.arg, newContext) << " "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = join_t; - - template - std::string operator()(const statement_type& l, const C& context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - auto aliasString = alias_extractor::get(); - ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; - if(aliasString.length()) { - ss << "'" << aliasString << "' "; - } - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = left_join_t; - - template - std::string operator()(const statement_type& l, const C& context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - auto aliasString = alias_extractor::get(); - ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; - if(aliasString.length()) { - ss << "'" << aliasString << "' "; - } - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = left_outer_join_t; - - template - std::string operator()(const statement_type& l, const C& context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - auto aliasString = alias_extractor::get(); - ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; - if(aliasString.length()) { - ss << "'" << aliasString << "' "; - } - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = natural_join_t; - - template - std::string operator()(const statement_type& c, const C& context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; + ss << static_cast(on) << " " << serialize(on.arg, newContext) << " "; return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = group_by_t; + template + struct statement_serializer, void> { + using statement_type = group_by_with_having; - template - std::string operator()(const statement_type& groupBy, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - std::vector expressions; auto newContext = context; newContext.skip_table_name = false; - iterate_tuple(groupBy.args, [&expressions, &newContext](auto& v) { - auto expression = serialize(v, newContext); - expressions.push_back(expression); - }); - ss << static_cast(groupBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { - ss << ", "; - } - } - ss << " "; + ss << "GROUP BY " << streaming_expressions_tuple(statement.args, newContext) << " HAVING " + << serialize(statement.expression, context); return ss.str(); } }; - template - struct statement_serializator, void> { - using statement_type = having_t; + template + struct statement_serializer, void> { + using statement_type = group_by_t; - template - std::string operator()(const statement_type& hav, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; auto newContext = context; newContext.skip_table_name = false; - ss << static_cast(hav) << " "; - ss << serialize(hav.t, newContext) << " "; + ss << "GROUP BY " << streaming_expressions_tuple(statement.args, newContext); return ss.str(); } }; @@ -14941,11 +17852,11 @@ namespace sqlite_orm { * OI - offset is implicit */ template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = limit_t; - template - std::string operator()(const statement_type& limt, const C& context) const { + template + std::string operator()(const statement_type& limt, const Ctx& context) const { auto newContext = context; newContext.skip_table_name = false; std::stringstream ss; @@ -14971,72 +17882,60 @@ namespace sqlite_orm { }; template<> - struct statement_serializator { + struct statement_serializer { using statement_type = default_values_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type&, const Ctx&) const { return "DEFAULT VALUES"; } }; - template - struct statement_serializator, void> { - using statement_type = using_t; + template + struct statement_serializer, void> { + using statement_type = using_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { auto newContext = context; newContext.skip_table_name = true; - return static_cast(statement) + " (" + serialize(statement.column, newContext) + " )"; + return static_cast(statement) + " (" + serialize(statement.column, newContext) + ")"; } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = std::tuple; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << '('; - auto index = 0; - using TupleSize = std::tuple_size; - iterate_tuple(statement, [&context, &index, &ss](auto& value) { - ss << serialize(value, context); - if(index < TupleSize::value - 1) { - ss << ", "; - } - ++index; - }); - ss << ')'; + if(context.use_parentheses) { + ss << '('; + } + ss << streaming_expressions_tuple(statement, context); + if(context.use_parentheses) { + ss << ')'; + } return ss.str(); } }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = values_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; if(context.use_parentheses) { ss << '('; } ss << "VALUES "; { - auto index = 0; - auto& tuple = statement.tuple; - using tuple_type = typename std::decay::type; - using TupleSize = std::tuple_size; - iterate_tuple(tuple, [&context, &index, &ss](auto& value) { - ss << serialize(value, context); - if(index < TupleSize::value - 1) { - ss << ", "; - } - ++index; - }); + Ctx tupleContext = context; + tupleContext.use_parentheses = true; + ss << streaming_expressions_tuple(statement.tuple, tupleContext); } if(context.use_parentheses) { ss << ')'; @@ -15046,178 +17945,210 @@ namespace sqlite_orm { }; template - struct statement_serializator, void> { + struct statement_serializer, void> { using statement_type = dynamic_values_t; - template - std::string operator()(const statement_type& statement, const C& context) const { + template + std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; if(context.use_parentheses) { ss << '('; } - ss << "VALUES "; - { - auto vectorSize = statement.vector.size(); - for(decltype(vectorSize) index = 0; index < vectorSize; ++index) { - auto& value = statement.vector[index]; - ss << serialize(value, context); - if(index < vectorSize - 1) { - ss << ", "; - } - } - } + ss << "VALUES " << streaming_dynamic_expressions(statement.vector, context); if(context.use_parentheses) { ss << ')'; } return ss.str(); } }; - } } -// #include "table_name_collector.h" +// #include "schema/triggers.h" // #include "object_from_column_builder.h" -// #include "table.h" +// #include "schema/table.h" -// #include "column.h" +// #include "schema/column.h" + +// #include "schema/index.h" + +// #include "util.h" + +// #include "serializing_util.h" namespace sqlite_orm { namespace internal { + template + SQLITE_ORM_INLINE_VAR constexpr bool is_preparable_v = false; + + template + SQLITE_ORM_INLINE_VAR constexpr bool + is_preparable_v().prepare(std::declval()))>> = true; + /** * Storage class itself. Create an instanse to use it as an interfacto to sqlite db by calling `make_storage` * function. */ - template + template struct storage_t : storage_base { - using self = storage_t; - using impl_type = storage_impl; + using self = storage_t; + using db_objects_type = db_objects_tuple; /** * @param filename database filename. - * @param impl_ storage_impl head + * @param dbObjects db_objects_tuple */ - storage_t(const std::string& filename, impl_type impl_) : - storage_base{filename, foreign_keys_count(impl_)}, impl(std::move(impl_)) {} - - storage_t(const storage_t& other) : storage_base(other), impl(other.impl) {} - - protected: - impl_type impl; + storage_t(std::string filename, db_objects_type dbObjects) : + storage_base{std::move(filename), foreign_keys_count(dbObjects)}, db_objects{std::move(dbObjects)} {} - template - friend struct view_t; + private: + db_objects_type db_objects; - template - friend struct dynamic_order_by_t; + /** + * Obtain a storage_t's const db_objects_tuple. + * + * @note Historically, `serializer_context_builder` was declared friend, along with + * a few other library stock objects, in order to limit access to the db_objects_tuple. + * However, one could gain access to a storage_t's db_objects_tuple through + * `serializer_context_builder`, hence leading the whole friend declaration mambo-jumbo + * ad absurdum. + * Providing a free function is way better and cleaner. + * + * Hence, friend was replaced by `obtain_db_objects()` and `pick_const_impl()`. + */ + friend const db_objects_type& obtain_db_objects(const self& storage) noexcept { + return storage.db_objects; + } - template - friend struct iterator_t; + template + void create_table(sqlite3* db, const std::string& tableName, const Table& table) { + using table_type = std::decay_t; + using context_t = serializer_context; - template - friend struct serializator_context_builder; + context_t context{this->db_objects}; + statement_serializer serializer; + const auto sql = serializer.serialize(table, context, tableName); + perform_void_exec(db, sql); + } - template - void create_table(sqlite3* db, const std::string& tableName, const I& tableImpl) { - using table_type = typename std::decay::type; + /** + * Copies sourceTableName to another table with name: destinationTableName + * Performs INSERT INTO %destinationTableName% () SELECT %table.column_names% FROM %sourceTableName% + */ + template + void copy_table(sqlite3* db, + const std::string& sourceTableName, + const std::string& destinationTableName, + const Table& table, + const std::vector& columnsToIgnore) const; + +#if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) + void drop_column(sqlite3* db, const std::string& tableName, const std::string& columnName) { std::stringstream ss; - ss << "CREATE TABLE '" << tableName << "' ( "; - auto columnsCount = tableImpl.table.columns_count; - auto index = 0; - using context_t = serializator_context; - context_t context{this->impl}; - iterate_tuple(tableImpl.table.columns, [columnsCount, &index, &ss, &context](auto& c) { - ss << serialize(c, context); - if(index < columnsCount - 1) { - ss << ", "; - } - index++; - }); - ss << ")"; - if(table_type::is_without_rowid) { - ss << " WITHOUT ROWID "; - } + ss << "ALTER TABLE " << streaming_identifier(tableName) << " DROP COLUMN " + << streaming_identifier(columnName) << std::flush; perform_void_exec(db, ss.str()); } +#endif + + template + void drop_create_with_loss(sqlite3* db, const Table& table) { + // eliminated all transaction handling + this->drop_table_internal(db, table.name); + this->create_table(db, table.name, table); + } - template - void backup_table(sqlite3* db, const I& tableImpl, const std::vector& columnsToIgnore) { + template + void backup_table(sqlite3* db, const Table& table, const std::vector& columnsToIgnore) { // here we copy source table to another with a name with '_backup' suffix, but in case table with such // a name already exists we append suffix 1, then 2, etc until we find a free name.. - auto backupTableName = tableImpl.table.name + "_backup"; - if(tableImpl.table_exists(backupTableName, db)) { + auto backupTableName = table.name + "_backup"; + if(this->table_exists(db, backupTableName)) { int suffix = 1; do { - std::stringstream stream; - stream << suffix; - auto anotherBackupTableName = backupTableName + stream.str(); - if(!tableImpl.table_exists(anotherBackupTableName, db)) { - backupTableName = anotherBackupTableName; + std::stringstream ss; + ss << suffix << std::flush; + auto anotherBackupTableName = backupTableName + ss.str(); + if(!this->table_exists(db, anotherBackupTableName)) { + backupTableName = std::move(anotherBackupTableName); break; } ++suffix; } while(true); } + this->create_table(db, backupTableName, table); - this->create_table(db, backupTableName, tableImpl); - - tableImpl.copy_table(db, backupTableName, columnsToIgnore); + this->copy_table(db, table.name, backupTableName, table, columnsToIgnore); - this->drop_table_internal(tableImpl.table.name, db); + this->drop_table_internal(db, table.name); - tableImpl.rename_table(db, backupTableName, tableImpl.table.name); + this->rename_table(db, backupTableName, table.name); } template void assert_mapped_type() const { - using mapped_types_tuples = std::tuple; - static_assert(tuple_helper::has_type::value, "type is not mapped to a storage"); + static_assert(mpl::invoke_t, db_objects_type>::value, + "type is not mapped to storage"); } template - void assert_insertable_type() const { - auto& tImpl = this->get_impl(); - using table_type = typename std::decay::type; - using columns_type = typename std::decay::type; - - using bool_type = std::integral_constant; + void assert_updatable_type() const { +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + using Table = storage_pick_table_t; + using elements_type = elements_type_t; + using col_index_sequence = filter_tuple_sequence_t; + using pk_index_sequence = filter_tuple_sequence_t; + using pkcol_index_sequence = col_index_sequence_with; + constexpr size_t dedicatedPrimaryKeyColumnsCount = + nested_tuple_size_for_t::value; + + constexpr size_t primaryKeyColumnsCount = + dedicatedPrimaryKeyColumnsCount + pkcol_index_sequence::size(); + constexpr ptrdiff_t nonPrimaryKeysColumnsCount = col_index_sequence::size() - primaryKeyColumnsCount; + static_assert(primaryKeyColumnsCount > 0, "A table without primary keys cannot be updated"); + static_assert( + nonPrimaryKeysColumnsCount > 0, + "A table with only primary keys cannot be updated. You need at least 1 non-primary key column"); +#endif + } - static_if( - [](auto& tImpl) { - std::ignore = tImpl; + template, + std::enable_if_t = true> + void assert_insertable_type() const {} - // all right. it's a "without_rowid" table - }, - [](auto& tImpl) { - std::ignore = tImpl; - static_assert( - count_tuple::value <= 1, - "Attempting to execute 'insert' request into an noninsertable table was detected. " - "Insertable table cannot contain > 1 primary keys. Please use 'replace' instead of " - "'insert', or you can use 'insert' with explicit column listing."); - static_assert( - count_tuple::value == 0, - "Attempting to execute 'insert' request into an noninsertable table was detected. " - "Insertable table cannot contain non-standard primary keys. Please use 'replace' instead " - "of 'insert', or you can use 'insert' with explicit column listing."); - - // unfortunately, this static_assert's can't see an composite keys(( - })(tImpl); + template, + std::enable_if_t = true> + void assert_insertable_type() const { + using elements_type = elements_type_t
; + using pkcol_index_sequence = col_index_sequence_with; + static_assert( + count_filtered_tuple::value <= 1, + "Attempting to execute 'insert' request into an noninsertable table was detected. " + "Insertable table cannot contain > 1 primary keys. Please use 'replace' instead of " + "'insert', or you can use 'insert' with explicit column listing."); + static_assert(count_filtered_tuple::template fn, + pkcol_index_sequence>::value == 0, + "Attempting to execute 'insert' request into an noninsertable table was detected. " + "Insertable table cannot contain non-standard primary keys. Please use 'replace' instead " + "of 'insert', or you can use 'insert' with explicit column listing."); } template - auto& get_impl() const { - return this->impl.template get_impl(); + auto& get_table() const { + return pick_table(this->db_objects); } template - auto& get_impl() { - return this->impl.template get_impl(); + auto& get_table() { + return pick_table(this->db_objects); } public: @@ -15268,8 +18199,10 @@ namespace sqlite_orm { this->execute(statement); } - template - void update_all(internal::set_t set, Wargs... wh) { + template + void update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, + "first argument in update_all can be either set or dynamic_set"); auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); this->execute(statement); } @@ -15280,12 +18213,12 @@ namespace sqlite_orm { this->assert_mapped_type(); std::vector rows; if(y) { - rows = this->select(sqlite_orm::group_concat(m, move(*y)), std::forward(args)...); + rows = this->select(sqlite_orm::group_concat(m, std::move(*y)), std::forward(args)...); } else { rows = this->select(sqlite_orm::group_concat(m), std::forward(args)...); } if(!rows.empty()) { - return move(rows.front()); + return std::move(rows.front()); } else { return {}; } @@ -15295,70 +18228,76 @@ namespace sqlite_orm { /** * SELECT * routine. * O is an object type to be extracted. Must be specified explicitly. - * @return All objects of type O stored in database at the moment in `std::vector`. - * @note If you need to return the result in a different container type then use a different `get_all` function overload `get_all>` - * @example: storage.get_all() - SELECT * FROM users - * @example: storage.get_all(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id - */ - template - auto get_all(Args&&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); - return this->execute(statement); - } - - /** - * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * R is an explicit return type. This type must have `push_back(O &&)` function. + * R is an explicit return type. This type must have `push_back(O &&)` function. Defaults to `std::vector` * @return All objects of type O stored in database at the moment in `R`. * @example: storage.get_all>(); - SELECT * FROM users * @example: storage.get_all>(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id */ - template - auto get_all(Args&&... args) { + template, class... Args> + R get_all(Args&&... args) { this->assert_mapped_type(); auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); return this->execute(statement); } +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * @return All objects of type O as `std::unique_ptr` inside a `std::vector` stored in database at the moment. - * @note If you need to return the result in a different container type then use a different `get_all_pointer` function overload `get_all_pointer>` - * @example: storage.get_all_pointer(); - SELECT * FROM users - * @example: storage.get_all_pointer(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 - */ - template - auto get_all_pointer(Args&&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); + * `alias` is an explicitly specified table alias of an object to be extracted. + * `R` is the container return type, which must have a `R::push_back(O&&)` method, and defaults to `std::vector` + * @return All objects stored in database. + * @example: storage.get_all>(); - SELECT sqlite_schema.* FROM sqlite_master AS sqlite_schema + */ + template>, + class... Args> + R get_all(Args&&... args) { + using A = decltype(alias); + this->assert_mapped_type>(); + auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); return this->execute(statement); } +#endif /** * SELECT * routine. * O is an object type to be extracted. Must be specified explicitly. * R is a container type. std::vector> is default * @return All objects of type O as std::unique_ptr stored in database at the moment. - * @example: storage.get_all_pointer>(); - SELECT * FROM users - * @example: storage.get_all_pointer>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 + * @example: storage.get_all_pointer>>(); - SELECT * FROM users + * @example: storage.get_all_pointer>>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 */ - template + template>, class... Args> auto get_all_pointer(Args&&... args) { this->assert_mapped_type(); auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); return this->execute(statement); } +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + /** + * SELECT * routine. + * O is an object type to be extracted. Must be specified explicitly. + * R is a container type. std::vector> is default + * @return All objects of type O as std::optional stored in database at the moment. + * @example: storage.get_all_optional>>(); - SELECT * FROM users + * @example: storage.get_all_optional>>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 + */ + template>, class... Args> + auto get_all_optional(Args&&... conditions) { + this->assert_mapped_type(); + auto statement = this->prepare(sqlite_orm::get_all_optional(std::forward(conditions)...)); + return this->execute(statement); + } +#endif + /** * Select * by id routine. - * throws std::system_error(orm_error_code::not_found, orm_error_category) if object not found with given + * throws std::system_error{orm_error_code::not_found} if object not found with given * id. throws std::system_error with orm_error_category in case of db error. O is an object type to be * extracted. Must be specified explicitly. * @return Object of type O where id is equal parameter passed or throws - * `std::system_error(orm_error_code::not_found, orm_error_category)` if there is no object with such id. + * `std::system_error{orm_error_code::not_found}` if there is no object with such id. */ template O get(Ids... ids) { @@ -15393,7 +18332,7 @@ namespace sqlite_orm { */ template std::shared_ptr get_no_throw(Ids... ids) { - return std::shared_ptr(get_pointer(std::forward(ids)...)); + return std::shared_ptr(this->get_pointer(std::forward(ids)...)); } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -15413,7 +18352,7 @@ namespace sqlite_orm { * SELECT COUNT(*) https://www.sqlite.org/lang_aggfunc.html#count * @return Number of O object in table. */ - template::type> + template> int count(Args&&... args) { this->assert_mapped_type(); auto rows = this->select(sqlite_orm::count(), std::forward(args)...); @@ -15470,7 +18409,7 @@ namespace sqlite_orm { class O, class... Args, class Tuple = std::tuple, - typename sfinae = typename std::enable_if::value >= 1>::type> + std::enable_if_t::value >= 1, bool> = true> std::string group_concat(F O::*m, Args&&... args) { return this->group_concat_internal(m, {}, std::forward(args)...); } @@ -15483,7 +18422,7 @@ namespace sqlite_orm { template std::string group_concat(F O::*m, std::string y, Args&&... args) { return this->group_concat_internal(m, - std::make_unique(move(y)), + std::make_unique(std::move(y)), std::forward(args)...); } @@ -15495,7 +18434,7 @@ namespace sqlite_orm { } else { str = std::make_unique(); } - return this->group_concat_internal(m, move(str), std::forward(args)...); + return this->group_concat_internal(m, std::move(str), std::forward(args)...); } /** @@ -15503,7 +18442,7 @@ namespace sqlite_orm { * @param m is a class member pointer (the same you passed into make_column). * @return std::unique_ptr with max value or null if sqlite engine returned null. */ - template::type> + template> std::unique_ptr max(F O::*m, Args&&... args) { this->assert_mapped_type(); auto rows = this->select(sqlite_orm::max(m), std::forward(args)...); @@ -15519,7 +18458,7 @@ namespace sqlite_orm { * @param m is a class member pointer (the same you passed into make_column). * @return std::unique_ptr with min value or null if sqlite engine returned null. */ - template::type> + template> std::unique_ptr min(F O::*m, Args&&... args) { this->assert_mapped_type(); auto rows = this->select(sqlite_orm::min(m), std::forward(args)...); @@ -15535,7 +18474,7 @@ namespace sqlite_orm { * @param m is a class member pointer (the same you passed into make_column). * @return std::unique_ptr with sum value or null if sqlite engine returned null. */ - template::type> + template> std::unique_ptr sum(F O::*m, Args&&... args) { this->assert_mapped_type(); std::vector> rows = @@ -15573,57 +18512,59 @@ namespace sqlite_orm { * For a single column use `auto rows = storage.select(&User::id, where(...)); * For multicolumns use `auto rows = storage.select(columns(&User::id, &User::name), where(...)); */ - template::type> + template> std::vector select(T m, Args... args) { - static_assert(!is_base_of_template::value || - std::tuple_size>::value == 0, + static_assert(!is_compound_operator_v || sizeof...(Args) == 0, "Cannot use args with a compound operator"); auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); return this->execute(statement); } - template - typename std::enable_if::value, std::string>::type - dump(const T& preparedStatement) const { - using context_t = serializator_context; - context_t context{this->impl}; - return serialize(preparedStatement.t, context); + template = true> + std::string dump(const T& preparedStatement, bool parametrized = true) const { + return this->dump(preparedStatement.expression, parametrized); + } + + template, + std::enable_if_t && !is_mapped_v, bool> = true> + std::string dump(E&& expression, bool parametrized = false) const { + static_assert(is_preparable_v, "Expression must be a high-level statement"); + + decltype(auto) e2 = static_if>( + [](auto expression) -> auto { + expression.highest_level = true; + return expression; + }, + [](const auto& expression) -> decltype(auto) { + return (expression); + })(std::forward(expression)); + using context_t = serializer_context; + context_t context{this->db_objects}; + context.replace_bindable_with_question = parametrized; + // just like prepare_impl() + context.skip_table_name = false; + return serialize(e2, context); } /** * Returns a string representation of object of a class mapped to the storage. * Type of string has json-like style. */ - template - typename std::enable_if::value, std::string>::type - dump(const O& o) { - auto& tImpl = this->get_impl(); + template = true> + std::string dump(const O& object) const { + auto& table = this->get_table(); std::stringstream ss; ss << "{ "; - using pair = std::pair; - std::vector pairs; - tImpl.table.for_each_column([&pairs, &o](auto& c) { - using column_type = typename std::decay::type; + table.for_each_column([&ss, &object, first = true](auto& column) mutable { + using column_type = std::decay_t; using field_type = typename column_type::field_type; - pair p{c.name, std::string()}; - if(c.member_pointer) { - p.second = field_printer()(o.*c.member_pointer); - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - p.second = field_printer()(valueHolder.value); - } - pairs.push_back(move(p)); + constexpr std::array sep = {", ", ""}; + + ss << sep[std::exchange(first, false)] << column.name << " : '" + << field_printer{}(polyfill::invoke(column.member_pointer, object)) << "'"; }); - for(size_t i = 0; i < pairs.size(); ++i) { - auto& p = pairs[i]; - ss << p.first << " : '" << p.second << "'"; - if(i < pairs.size() - 1) { - ss << ", "; - } else { - ss << " }"; - } - } + ss << " }"; return ss.str(); } @@ -15640,33 +18581,34 @@ namespace sqlite_orm { this->execute(statement); } - template - void replace_range(It from, It to) { - using O = typename std::iterator_traits::value_type; + template + void replace_range(It from, It to, Projection project = {}) { + using O = std::decay_t(), *std::declval()))>; this->assert_mapped_type(); if(from == to) { return; } - auto statement = this->prepare(sqlite_orm::replace_range(from, to)); + auto statement = + this->prepare(sqlite_orm::replace_range(std::move(from), std::move(to), std::move(project))); this->execute(statement); } - template - void replace_range(It from, It to, L transformer) { - this->assert_mapped_type(); + template + void replace_range(It from, It to, Projection project = {}) { + this->assert_mapped_type(); if(from == to) { return; } - auto statement = this->prepare(sqlite_orm::replace_range(from, to, std::move(transformer))); + auto statement = + this->prepare(sqlite_orm::replace_range(std::move(from), std::move(to), std::move(project))); this->execute(statement); } template int insert(const O& o, columns_t cols) { - constexpr const size_t colsCount = std::tuple_size>::value; - static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); + static_assert(cols.count > 0, "Use insert or replace with 1 argument instead"); this->assert_mapped_type(); auto statement = this->prepare(sqlite_orm::insert(std::ref(o), std::move(cols))); return int(this->execute(statement)); @@ -15681,11 +18623,8 @@ namespace sqlite_orm { int insert(const O& o) { this->assert_mapped_type(); this->assert_insertable_type(); - - return call_insert_impl_and_catch_constraint_failed([this, &o]() { - auto statement = this->prepare(sqlite_orm::insert(std::ref(o))); - return int(this->execute(statement)); - }); + auto statement = this->prepare(sqlite_orm::insert(std::ref(o))); + return int(this->execute(statement)); } /** @@ -15762,32 +18701,29 @@ namespace sqlite_orm { this->execute(statement); } - template - void insert_range(It from, It to) { - using O = typename std::iterator_traits::value_type; + template + void insert_range(It from, It to, Projection project = {}) { + using O = std::decay_t(), *std::declval()))>; this->assert_mapped_type(); this->assert_insertable_type(); if(from == to) { return; } - - call_insert_impl_and_catch_constraint_failed([this, from, to]() { - auto statement = this->prepare(sqlite_orm::insert_range(from, to)); - this->execute(statement); - }); + auto statement = + this->prepare(sqlite_orm::insert_range(std::move(from), std::move(to), std::move(project))); + this->execute(statement); } - template - void insert_range(It from, It to, L transformer) { - this->assert_mapped_type(); - this->assert_insertable_type(); + template + void insert_range(It from, It to, Projection project = {}) { + this->assert_mapped_type(); + this->assert_insertable_type(); if(from == to) { return; } - call_insert_impl_and_catch_constraint_failed([this, from, to, transformer = std::move(transformer)]() { - auto statement = this->prepare(sqlite_orm::insert_range(from, to, std::move(transformer))); - this->execute(statement); - }); + auto statement = + this->prepare(sqlite_orm::insert_range(std::move(from), std::move(to), std::move(project))); + this->execute(statement); } /** @@ -15797,8 +18733,8 @@ namespace sqlite_orm { template void rename_table(std::string name) { this->assert_mapped_type(); - auto& tImpl = this->get_impl(); - tImpl.table.name = move(name); + auto& table = this->get_table(); + table.name = std::move(name); } using storage_base::rename_table; @@ -15810,109 +18746,169 @@ namespace sqlite_orm { template const std::string& tablename() const { this->assert_mapped_type(); - auto& tImpl = this->get_impl(); - return tImpl.table.name; + auto& table = this->get_table(); + return table.name; + } + + template + [[deprecated("Use the more accurately named function `find_column_name()`")]] const std::string* + column_name(F O::*memberPointer) const { + return internal::find_column_name(this->db_objects, memberPointer); } template - const std::string* column_name(F O::*memberPointer) const { - return this->impl.column_name(memberPointer); + const std::string* find_column_name(F O::*memberPointer) const { + return internal::find_column_name(this->db_objects, memberPointer); } protected: - template - sync_schema_result schema_status(const storage_impl, Tss...>&, sqlite3*, bool) { + template + sync_schema_result schema_status(const index_t&, sqlite3*, bool, bool*) { return sync_schema_result::already_in_sync; } - template class TTable, class... Tss, class... Cs> - sync_schema_result - schema_status(const storage_impl, Tss...>& tImpl, sqlite3* db, bool preserve) { - return tImpl.schema_status(db, preserve); + template + sync_schema_result schema_status(const table_t& table, + sqlite3* db, + bool preserve, + bool* attempt_to_preserve) { + if(attempt_to_preserve) { + *attempt_to_preserve = true; + } + + auto dbTableInfo = this->pragma.table_xinfo(table.name); + auto res = sync_schema_result::already_in_sync; + + // first let's see if table with such name exists.. + auto gottaCreateTable = !this->table_exists(db, table.name); + if(!gottaCreateTable) { + + // get table info provided in `make_table` call.. + auto storageTableInfo = table.get_table_info(); + + // this vector will contain pointers to columns that gotta be added.. + std::vector columnsToAdd; + + if(calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) { + gottaCreateTable = true; + } + + if(!gottaCreateTable) { // if all storage columns are equal to actual db columns but there are + // excess columns at the db.. + if(!dbTableInfo.empty()) { + // extra table columns than storage columns + if(!preserve) { +#if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) + res = sync_schema_result::old_columns_removed; +#else + gottaCreateTable = true; +#endif + } else { + res = sync_schema_result::old_columns_removed; + } + } + } + if(gottaCreateTable) { + res = sync_schema_result::dropped_and_recreated; + } else { + if(!columnsToAdd.empty()) { + // extra storage columns than table columns + for(const table_xinfo* colInfo: columnsToAdd) { + const basic_generated_always::storage_type* generatedStorageType = + table.find_column_generated_storage_type(colInfo->name); + if(generatedStorageType) { + if(*generatedStorageType == basic_generated_always::storage_type::stored) { + gottaCreateTable = true; + break; + } + // fallback cause VIRTUAL can be added + } else { + if(colInfo->notnull && colInfo->dflt_value.empty()) { + gottaCreateTable = true; + // no matter if preserve is true or false, there is no way to preserve data, so we wont try! + if(attempt_to_preserve) { + *attempt_to_preserve = false; + }; + break; + } + } + } + if(!gottaCreateTable) { + if(res == sync_schema_result::old_columns_removed) { + res = sync_schema_result::new_columns_added_and_old_columns_removed; + } else { + res = sync_schema_result::new_columns_added; + } + } else { + res = sync_schema_result::dropped_and_recreated; + } + } else { + if(res != sync_schema_result::old_columns_removed) { + res = sync_schema_result::already_in_sync; + } + } + } + } else { + res = sync_schema_result::new_table_created; + } + return res; + } + + template + sync_schema_result sync_table(const virtual_table_t& virtualTable, sqlite3* db, bool) { + auto res = sync_schema_result::already_in_sync; + using context_t = serializer_context; + context_t context{this->db_objects}; + auto query = serialize(virtualTable, context); + perform_void_exec(db, query); + return res; } - template - sync_schema_result sync_table(const storage_impl, Tss...>& tableImpl, sqlite3* db, bool) { + template + sync_schema_result sync_table(const index_t& index, sqlite3* db, bool) { auto res = sync_schema_result::already_in_sync; - using context_t = serializator_context; - context_t context{this->impl}; - auto query = serialize(tableImpl.table, context); + using context_t = serializer_context; + context_t context{this->db_objects}; + auto query = serialize(index, context); perform_void_exec(db, query); return res; } - template class TTable, class... Tss, class... Cs> - sync_schema_result - sync_table(const storage_impl, Tss...>& tImpl, sqlite3* db, bool preserve) { - auto res = sync_schema_result::already_in_sync; - - auto schema_stat = tImpl.schema_status(db, preserve); - if(schema_stat != decltype(schema_stat)::already_in_sync) { - if(schema_stat == decltype(schema_stat)::new_table_created) { - this->create_table(db, tImpl.table.name, tImpl); - res = decltype(res)::new_table_created; - } else { - if(schema_stat == sync_schema_result::old_columns_removed || - schema_stat == sync_schema_result::new_columns_added || - schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { - - // get table info provided in `make_table` call.. - auto storageTableInfo = tImpl.table.get_table_info(); - - // now get current table info from db using `PRAGMA table_info` query.. - auto dbTableInfo = tImpl.get_table_info(tImpl.table.name, db); - - // this vector will contain pointers to columns that gotta be added.. - std::vector columnsToAdd; - - tImpl.calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo); - - if(schema_stat == sync_schema_result::old_columns_removed) { - - // extra table columns than storage columns - this->backup_table(db, tImpl, {}); - res = decltype(res)::old_columns_removed; - } + template + sync_schema_result sync_table(const trigger_t& trigger, sqlite3* db, bool) { + auto res = sync_schema_result::already_in_sync; // TODO Change accordingly + using context_t = serializer_context; + context_t context{this->db_objects}; + auto query = serialize(trigger, context); + perform_void_exec(db, query); + return res; + } - if(schema_stat == sync_schema_result::new_columns_added) { - for(auto columnPointer: columnsToAdd) { - tImpl.add_column(*columnPointer, db); - } - res = decltype(res)::new_columns_added; - } + template = true> + sync_schema_result sync_table(const Table& table, sqlite3* db, bool preserve); - if(schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { + template + void add_column(sqlite3* db, const std::string& tableName, const C& column) const { + using context_t = serializer_context; - // remove extra columns - this->backup_table(db, tImpl, columnsToAdd); - res = decltype(res)::new_columns_added_and_old_columns_removed; - } - } else if(schema_stat == sync_schema_result::dropped_and_recreated) { - this->drop_table_internal(tImpl.table.name, db); - this->create_table(db, tImpl.table.name, tImpl); - res = decltype(res)::dropped_and_recreated; - } - } - } - return res; + context_t context{this->db_objects}; + std::stringstream ss; + ss << "ALTER TABLE " << streaming_identifier(tableName) << " ADD COLUMN " << serialize(column, context) + << std::flush; + perform_void_exec(db, ss.str()); } template prepared_statement_t prepare_impl(S statement) { - auto con = this->get_connection(); - sqlite3_stmt* stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; + using context_t = serializer_context; + context_t context{this->db_objects}; context.skip_table_name = false; context.replace_bindable_with_question = true; - auto query = serialize(statement, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return prepared_statement_t{std::forward(statement), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + + auto con = this->get_connection(); + const auto sql = serialize(statement, context); + sqlite3_stmt* stmt = prepare_stmt(con.get(), sql); + return prepared_statement_t{std::forward(statement), stmt, con}; } public: @@ -15928,16 +18924,16 @@ namespace sqlite_orm { * * if there are columns in storage that do not exist in db they will be added using `ALTER TABLE * ... ADD COLUMN ...' command * * if there is any column existing in both db and storage but differs by any of - * properties/constraints (type, pk, notnull, dflt_value) table will be dropped and recreated Be aware that + * properties/constraints (pk, notnull, dflt_value) table will be dropped and recreated. Be aware that * `sync_schema` doesn't guarantee that data will not be dropped. It guarantees only that it will make db * schema the same as you specified in `make_storage` function call. A good point is that if you have no db * file at all it will be created and all tables also will be created with exact tables and columns you - * specified in `make_storage`, `make_table` and `make_column` call. The best practice is to call this + * specified in `make_storage`, `make_table` and `make_column` calls. The best practice is to call this * function right after storage creation. - * @param preserve affects on function behaviour in case it is needed to remove a column. If it is `false` - * so table will be dropped if there is column to remove, if `true` - table is being copied into another - * table, dropped and copied table is renamed with source table name. Warning: sync_schema doesn't check - * foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please + * @param preserve affects function's behaviour in case it is needed to remove a column. If it is `false` + * so table will be dropped if there is column to remove if SQLite version is < 3.35.0 and remove column if SQLite version >= 3.35.0, + * if `true` - table is being copied into another table, dropped and copied table is renamed with source table name. + * Warning: sync_schema doesn't check foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please * submit an issue https://github.com/fnc12/sqlite_orm/issues * @return std::map with std::string key equal table name and `sync_schema_result` as value. * `sync_schema_result` is a enum value that stores table state after syncing a schema. `sync_schema_result` @@ -15946,10 +18942,9 @@ namespace sqlite_orm { std::map sync_schema(bool preserve = false) { auto con = this->get_connection(); std::map result; - auto db = con.get(); - this->impl.for_each([&result, db, preserve, this](auto& tableImpl) { - auto res = this->sync_table(tableImpl, db, preserve); - result.insert({tableImpl.table.name, res}); + iterate_tuple(this->db_objects, [this, db = con.get(), preserve, &result](auto& schemaObject) { + sync_schema_result status = this->sync_table(schemaObject, db, preserve); + result.emplace(schemaObject.name, status); }); return result; } @@ -15962,23 +18957,14 @@ namespace sqlite_orm { std::map sync_schema_simulate(bool preserve = false) { auto con = this->get_connection(); std::map result; - auto db = con.get(); - this->impl.for_each([&result, db, preserve, this](auto& tableImpl) { - auto schemaStatus = this->schema_status(tableImpl, db, preserve); - result.insert({tableImpl.table.name, schemaStatus}); + iterate_tuple(this->db_objects, [this, db = con.get(), preserve, &result](auto& schemaObject) { + sync_schema_result status = this->schema_status(schemaObject, db, preserve, nullptr); + result.emplace(schemaObject.name, status); }); return result; } - /** - * Checks whether table exists in db. Doesn't check storage itself - works only with actual database. - * Note: table can be not mapped to a storage - * @return true if table with a given name exists in db, false otherwise. - */ - bool table_exists(const std::string& tableName) { - auto con = this->get_connection(); - return this->impl.table_exists(tableName, con.get()); - } + using storage_base::table_exists; // now that it is in storage_base make it into overload set template prepared_statement_t> prepare(select_t sel) { @@ -16013,10 +18999,9 @@ namespace sqlite_orm { } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - prepared_statement_t, Wargs...>> - prepare(update_all_t, Wargs...> upd) { - return prepare_impl, Wargs...>>(std::move(upd)); + template + prepared_statement_t> prepare(update_all_t upd) { + return prepare_impl>(std::move(upd)); } template @@ -16042,28 +19027,33 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - prepared_statement_t> prepare(update_t upd) { - return prepare_impl>(std::move(upd)); + prepared_statement_t> prepare(update_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + this->assert_updatable_type(); + return prepare_impl>(std::move(statement)); } template - prepared_statement_t> prepare(remove_t rem) { - return prepare_impl>(std::move(rem)); + prepared_statement_t> prepare(remove_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + return this->prepare_impl>(std::move(statement)); } template - prepared_statement_t> prepare(insert_t ins) { - using object_type = typename expression_object_type::type; + prepared_statement_t> prepare(insert_t statement) { + using object_type = typename expression_object_type::type; this->assert_mapped_type(); this->assert_insertable_type(); - return prepare_impl>(std::move(ins)); + return this->prepare_impl>(std::move(statement)); } template prepared_statement_t> prepare(replace_t rep) { using object_type = typename expression_object_type::type; this->assert_mapped_type(); - return prepare_impl>(std::move(rep)); + return this->prepare_impl>(std::move(rep)); } template @@ -16071,604 +19061,370 @@ namespace sqlite_orm { using object_type = typename expression_object_type::type; this->assert_mapped_type(); this->assert_insertable_type(); - return prepare_impl>(std::move(statement)); + return this->prepare_impl>(std::move(statement)); } template - prepared_statement_t> prepare(replace_range_t rep) { - return prepare_impl>(std::move(rep)); + prepared_statement_t> prepare(replace_range_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + return this->prepare_impl>(std::move(statement)); } template prepared_statement_t> prepare(insert_explicit ins) { using object_type = typename expression_object_type::type; this->assert_mapped_type(); - return prepare_impl>(std::move(ins)); + return this->prepare_impl>(std::move(ins)); } template void execute(const prepared_statement_t>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - sqlite3_reset(stmt); - auto index = 1; - iterate_ast(statement.t.args, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + iterate_ast(statement.expression.args, conditional_binder{statement.stmt}); + perform_step(stmt); } template void execute(const prepared_statement_t>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - sqlite3_reset(stmt); - auto index = 1; - iterate_ast(statement.t.args, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + iterate_ast(statement.expression.args, conditional_binder{stmt}); + perform_step(stmt); } template int64 execute(const prepared_statement_t>& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto& tImpl = this->get_impl(); - auto& o = statement.t.obj; - sqlite3_reset(stmt); - iterate_tuple(statement.t.columns.columns, [&o, &index, &stmt, &tImpl, db](auto& m) { - using column_type = typename std::decay::type; - using field_type = typename column_result_t::type; - const field_type* value = tImpl.table.template get_object_field_pointer(o, m); - if(SQLITE_OK != statement_binder().bind(stmt, index++, *value)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); - return sqlite3_last_insert_rowid(db); + + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + tuple_value_binder{stmt}( + statement.expression.columns.columns, + [&table = this->get_table(), &object = statement.expression.obj](auto& memberPointer) { + return table.object_field_value(object, memberPointer); + }); + perform_step(stmt); + return sqlite3_last_insert_rowid(sqlite3_db_handle(stmt)); } template::value || is_replace::value)>::type* = nullptr> + std::enable_if_t, is_replace_range>, bool> = true> void execute(const prepared_statement_t& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; - auto& tImpl = this->get_impl(); - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - sqlite3_reset(stmt); - - auto processObject = [&index, &stmt, &tImpl, db](auto& o) { - tImpl.table.for_each_column([&](auto& c) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - }); + + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + auto processObject = [&table = this->get_table(), + bindValue = field_value_binder{stmt}](auto& object) mutable { + table.template for_each_column_excluding( + call_as_template_base([&bindValue, &object](auto& column) { + bindValue(polyfill::invoke(column.member_pointer, object)); + })); }; - static_if{}>( - [&processObject](auto& statement) { - auto& transformer = statement.t.transformer; - std::for_each( /// - statement.t.range.first, - statement.t.range.second, - [&processObject, &transformer](auto& object) { - auto& realObject = transformer(object); - processObject(realObject); - }); + static_if>( + [&processObject](auto& expression) { +#if __cpp_lib_ranges >= 201911L + std::ranges::for_each(expression.range.first, + expression.range.second, + std::ref(processObject), + std::ref(expression.transformer)); +#else + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); +#endif }, - [&processObject](auto& statement) { - auto& o = get_object(statement.t); + [&processObject](auto& expression) { + const object_type& o = get_object(expression); processObject(o); - })(statement); - perform_step(db, stmt); + })(statement.expression); + + perform_step(stmt); } - template::value || is_insert::value)>::type* = nullptr> + template, is_insert_range>, bool> = true> int64 execute(const prepared_statement_t& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto& tImpl = this->get_impl(); - auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); - sqlite3_reset(stmt); - auto processObject = [&index, &stmt, &tImpl, &compositeKeyColumnNames, db](auto& o) { - tImpl.table.for_each_column([&](auto& c) { - using table_type = typename std::decay::type; - if(table_type::is_without_rowid || !c.template has>()) { - auto it = std::find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); - if(it == compositeKeyColumnNames.end()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != - statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != - statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } + + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + auto processObject = [&table = this->get_table(), + bindValue = field_value_binder{stmt}](auto& object) mutable { + using is_without_rowid = typename std::decay_t::is_without_rowid; + table.template for_each_column_excluding< + mpl::conjunction>, + mpl::disjunction_fn>>( + call_as_template_base([&table, &bindValue, &object](auto& column) { + if(!exists_in_composite_primary_key(table, column)) { + bindValue(polyfill::invoke(column.member_pointer, object)); } - } - }); + })); }; - static_if{}>( - [&processObject](auto& statement) { - auto& transformer = statement.t.transformer; - std::for_each( /// - statement.t.range.first, - statement.t.range.second, - [&processObject, &transformer](auto& object) { - auto& realObject = transformer(object); - processObject(realObject); - }); + static_if>( + [&processObject](auto& expression) { +#if __cpp_lib_ranges >= 201911L + std::ranges::for_each(expression.range.first, + expression.range.second, + std::ref(processObject), + std::ref(expression.transformer)); +#else + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); +#endif }, - [&processObject](auto& statement) { - auto& o = get_object(statement.t); + [&processObject](auto& expression) { + const object_type& o = get_object(expression); processObject(o); - })(statement); + })(statement.expression); - perform_step(db, stmt); - return sqlite3_last_insert_rowid(db); + perform_step(stmt); + return sqlite3_last_insert_rowid(sqlite3_db_handle(stmt)); } template void execute(const prepared_statement_t>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + iterate_ast(statement.expression.ids, conditional_binder{stmt}); + perform_step(stmt); } template void execute(const prepared_statement_t>& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; - auto con = this->get_connection(); - auto db = con.get(); - auto& tImpl = this->get_impl(); - auto stmt = statement.stmt; - auto index = 1; - auto& o = get_object(statement.t); - sqlite3_reset(stmt); - tImpl.table.for_each_column([&o, stmt, &index, db](auto& c) { - if(!c.template has>()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - auto bind_res = statement_binder().bind(stmt, index++, o.*c.member_pointer); - if(SQLITE_OK != bind_res) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - }); - tImpl.table.for_each_column([&o, stmt, &index, db](auto& c) { - if(c.template has>()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + auto& table = this->get_table(); + + field_value_binder bindValue{stmt}; + auto& object = get_object(statement.expression); + table.template for_each_column_excluding>( + call_as_template_base([&table, &bindValue, &object](auto& column) { + if(!exists_in_composite_primary_key(table, column)) { + bindValue(polyfill::invoke(column.member_pointer, object)); } + })); + table.for_each_column([&table, &bindValue, &object](auto& column) { + if(column.template is() || exists_in_composite_primary_key(table, column)) { + bindValue(polyfill::invoke(column.member_pointer, object)); } }); - perform_step(db, stmt); + perform_step(stmt); } template std::unique_ptr execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression.ids, conditional_binder{stmt}); + + std::unique_ptr res; + perform_step(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + res = std::make_unique(); + object_from_column_builder builder{*res, stmt}; + table.for_each_column(builder); }); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto res = std::make_unique(); - object_from_column_builder builder{*res, stmt}; - tImpl.table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - return {}; - } break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } + return res; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template std::optional execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression.ids, conditional_binder{stmt}); + + std::optional res; + perform_step(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + object_from_column_builder builder{res.emplace(), stmt}; + table.for_each_column(builder); }); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto res = std::make_optional(); - object_from_column_builder builder{res.value(), stmt}; - tImpl.table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - return {}; - } break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } + return res; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template T execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression.ids, conditional_binder{stmt}); + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + std::optional res; + perform_step(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + object_from_column_builder builder{res.emplace(), stmt}; + table.for_each_column(builder); }); + if(!res.has_value()) { + throw std::system_error{orm_error_code::not_found}; + } + return std::move(res).value(); +#else + auto& table = this->get_table(); auto stepRes = sqlite3_step(stmt); switch(stepRes) { case SQLITE_ROW: { T res; object_from_column_builder builder{res, stmt}; - tImpl.table.for_each_column(builder); + table.for_each_column(builder); return res; } break; case SQLITE_DONE: { - throw std::system_error(std::make_error_code(sqlite_orm::orm_error_code::not_found)); + throw std::system_error{orm_error_code::not_found}; } break; default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); + throw_translated_sqlite_error(stmt); } } +#endif } template void execute(const prepared_statement_t>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + iterate_ast(statement.expression.conditions, conditional_binder{stmt}); + perform_step(stmt); } - template - void execute(const prepared_statement_t, Wargs...>>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_tuple(statement.t.set.assigns, [&index, stmt, db](auto& setArg) { - iterate_ast(setArg, [&index, stmt, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - }); - iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - perform_step(db, stmt); + template + void execute(const prepared_statement_t>& statement) { + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + conditional_binder bindNode{stmt}; + iterate_ast(statement.expression.set, bindNode); + iterate_ast(statement.expression.conditions, bindNode); + perform_step(stmt); } - template::type> + template, + satisfies_not = true> std::vector execute(const prepared_statement_t>& statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + std::vector res; - auto tableInfoPointer = this->impl.template find_table(); - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - using table_info_pointer_t = typename std::remove_pointer::type; - using table_info_t = typename std::decay::type; - row_extractor_builder::value, table_info_t> - builder; - auto rowExtractor = builder(tableInfoPointer); - res.push_back(rowExtractor.extract(stmt, 0)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); + perform_steps(stmt, [rowExtractor = row_value_extractor(), &res](sqlite3_stmt* stmt) { + // note: we always pass in the first index, even though a row extractor + // for a tuple ignores it and does its custom iteration of the result row + res.push_back(rowExtractor.extract(stmt, 0)); + }); + res.shrink_to_fit(); return res; } - template - R execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } + template, + satisfies = true> + std::vector execute(const prepared_statement_t>& statement) { + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + + std::vector res; + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); }); + res.shrink_to_fit(); + return res; + } + + template> + R execute(const prepared_statement_t>& statement) { + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T obj; - object_from_column_builder builder{obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(std::move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); + }); +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + if constexpr(polyfill::is_specialization_of_v) { + res.shrink_to_fit(); + } +#endif return res; } template R execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto obj = std::make_unique(); - object_from_column_builder builder{*obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + auto obj = std::make_unique(); + object_from_column_builder builder{*obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); + }); +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + if constexpr(polyfill::is_specialization_of_v) { + res.shrink_to_fit(); + } +#endif return res; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template R execute(const prepared_statement_t>& statement) { - auto& tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto& node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto obj = std::make_optional(); - object_from_column_builder builder{*obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + auto obj = std::make_optional(); + object_from_column_builder builder{*obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); + }); +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + if constexpr(polyfill::is_specialization_of_v) { + res.shrink_to_fit(); + } +#endif return res; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - /*template - bool has_dependent_rows(const O& object) { - auto res = false; - using TupleWithForeignKeyTypes = typename storage_traits::storage_fk_references::type; - iterate_tuple([&res, this](auto *itemPointer){ - using ConstItem = typename std::remove_pointer::type; - using Item = typename std::decay::type; - if(!res) { - auto rows = this->select(count()); - if (!rows.empty()) { - res = rows[0]; - } - } - }); - return res; - }*/ }; // struct storage_t - - template - struct is_storage : std::false_type {}; - - template - struct is_storage> : std::true_type {}; } - template - internal::storage_t make_storage(const std::string& filename, Ts... tables) { - return {filename, internal::storage_impl(std::forward(tables)...)}; + /* + * Factory function for a storage, from a database file and a bunch of database object definitions. + */ + template + internal::storage_t make_storage(std::string filename, DBO... dbObjects) { + return {std::move(filename), internal::db_objects_tuple{std::forward(dbObjects)...}}; } /** @@ -16680,47 +19436,56 @@ namespace sqlite_orm { } #pragma once -#if defined(_MSC_VER) -#if defined(__RESTORE_MIN__) -__pragma(pop_macro("min")) -#undef __RESTORE_MIN__ -#endif -#if defined(__RESTORE_MAX__) - __pragma(pop_macro("max")) -#undef __RESTORE_MAX__ -#endif -#endif // defined(_MSC_VER) -#pragma once +#include // std::is_same, std::decay, std::remove_reference +#include // std::get + +// #include "functional/cxx_universal.h" +// ::size_t +// #include "functional/static_magic.h" + +// #include "prepared_statement.h" + +// #include "ast_iterator.h" +// #include "node_tuple.h" + +#include // std::enable_if #include // std::tuple #include // std::pair #include // std::reference_wrapper -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "tuple_helper/tuple_filter.h" + +// #include "conditions.h" - // #include "conditions.h" +// #include "operators.h" + +// #include "select_constraints.h" - // #include "operators.h" +// #include "prepared_statement.h" - // #include "select_constraints.h" +// #include "optional_container.h" - // #include "prepared_statement.h" +// #include "core_functions.h" - // #include "optional_container.h" +// #include "function.h" - // #include "core_functions.h" +// #include "ast/excluded.h" - // #include "function.h" +// #include "ast/upsert_clause.h" - // #include "ast/excluded.h" +// #include "ast/where.h" - // #include "ast/upsert_clause.h" +// #include "ast/into.h" - // #include "ast/where.h" +// #include "ast/group_by.h" - namespace sqlite_orm { +// #include "ast/match.h" +namespace sqlite_orm { namespace internal { template @@ -16728,50 +19493,87 @@ __pragma(pop_macro("min")) using type = std::tuple; }; + template + using node_tuple_t = typename node_tuple::type; + template<> struct node_tuple { using type = std::tuple<>; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; + struct node_tuple, void> : node_tuple {}; + + template + struct node_tuple, void> : node_tuple> {}; + + template + struct node_tuple, void> { + using args_tuple = node_tuple_t>; + using expression_tuple = node_tuple_t; + using type = tuple_cat_t; + }; + + template + struct node_tuple> : node_tuple {}; + + template + struct node_tuple, void> { + using type = tuple_cat_t...>; }; - template - struct node_tuple, std::tuple>, void> { - using type = typename node_tuple>::type; + template + struct node_tuple, void> { + using x_node_tuple = node_tuple_t; + using y_node_tuple = node_tuple_t; + using z_node_tuple = node_tuple_t; + using type = tuple_cat_t; }; - template - struct node_tuple, void> { - using type = typename conc_tuple::type...>::type; - }; + template + struct node_tuple, void> : node_tuple {}; + + template + struct node_tuple, void> : node_tuple {}; + + template + struct node_tuple, void> : node_tuple {}; + + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; + + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; + /** + * Literal + */ template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; - template - struct node_tuple, void> { - using node_type = where_t; - using type = typename node_tuple::type; - }; + template + struct node_tuple, void> : node_tuple {}; + + template + struct node_tuple, void> : node_tuple {}; template - struct node_tuple::value>::type> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; + using type = tuple_cat_t; }; template @@ -16779,288 +19581,217 @@ __pragma(pop_macro("min")) using node_type = binary_operator; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = columns_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template struct node_tuple, void> { - using node_type = dynamic_in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename conc_tuple::type...>::type; - using type = typename conc_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = tuple_cat_t...>; + using type = tuple_cat_t; }; template - struct node_tuple::value>::type> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = select_t; - using columns_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using type = typename conc_tuple::type; + using columns_tuple = node_tuple_t; + using args_tuple = tuple_cat_t...>; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = insert_raw_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template struct node_tuple, void> { - using node_type = replace_raw_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template - struct node_tuple, void> { - using node_type = into_t; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = values_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template struct node_tuple, void> { - using node_type = std::tuple; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template struct node_tuple, void> { - using node_type = get_all_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template struct node_tuple, void> { - using node_type = get_all_pointer_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, void> { - using node_type = get_all_optional_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; - using set_tuple = typename conc_tuple::type...>::type; - using conditions_tuple = typename conc_tuple::type...>::type; - using type = typename conc_tuple::type; + using set_tuple = tuple_cat_t...>; + using conditions_tuple = tuple_cat_t...>; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = remove_all_t; - using type = typename conc_tuple::type...>::type; - }; - - template - struct node_tuple, void> { - using node_type = having_t; - using type = typename node_tuple::type; + using type = tuple_cat_t...>; }; template - struct node_tuple, void> { - using node_type = cast_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = exists_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = optional_container; - using type = typename node_tuple::type; - }; - - template<> - struct node_tuple, void> { - using node_type = optional_container; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = like_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using escape_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; + using escape_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = glob_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = between_t; - using expression_tuple = typename node_tuple::type; - using lower_tuple = typename node_tuple::type; - using upper_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using expression_tuple = node_tuple_t; + using lower_tuple = node_tuple_t; + using upper_tuple = node_tuple_t; + using type = tuple_cat_t; }; template - struct node_tuple, void> { - using node_type = named_collate; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_not_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = negated_condition_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = built_in_function_t; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; + }; + + template + struct node_tuple, void> { + using type = tuple_cat_t...>; + }; + + template + struct node_tuple, void> { + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = function_call; - using type = typename conc_tuple::type...>::type; + using type = tuple_cat_t...>; }; template - struct node_tuple, void> { - using node_type = left_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = on_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; + + // note: not strictly necessary as there's no binding support for USING; + // we provide it nevertheless, in line with on_t. + template + struct node_tuple, void> : node_tuple> {}; template - struct node_tuple, void> { - using node_type = join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = left_outer_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = inner_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = simple_case_t; - using case_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using else_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using case_tuple = node_tuple_t; + using args_tuple = tuple_cat_t...>; + using else_tuple = node_tuple_t; + using type = tuple_cat_t; }; template struct node_tuple, void> { - using node_type = std::pair; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; + using type = tuple_cat_t; }; template - struct node_tuple, void> { - using node_type = as_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = tuple_cat_t, node_tuple_t>; }; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = tuple_cat_t, node_tuple_t>; }; } } -#pragma once - -#include // std::is_same, std::decay, std::remove_reference - -// #include "prepared_statement.h" - -// #include "ast_iterator.h" - -// #include "static_magic.h" // #include "expression_object_type.h" @@ -17068,132 +19799,134 @@ namespace sqlite_orm { template auto& get(internal::prepared_statement_t>& statement) { - return std::get(statement.t.range); + return std::get(statement.expression.range); } template const auto& get(const internal::prepared_statement_t>& statement) { - return std::get(statement.t.range); + return std::get(statement.expression.range); } template auto& get(internal::prepared_statement_t>& statement) { - return std::get(statement.t.range); + return std::get(statement.expression.range); } template const auto& get(const internal::prepared_statement_t>& statement) { - return std::get(statement.t.range); + return std::get(statement.expression.range); } template auto& get(internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template const auto& get(const internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template auto& get(internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template const auto& get(const internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template auto& get(internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template const auto& get(const internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template auto& get(internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template const auto& get(const internal::prepared_statement_t>& statement) { - return internal::get_ref(std::get(statement.t.ids)); + return internal::get_ref(std::get(statement.expression.ids)); } template auto& get(internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for update statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template const auto& get(const internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for update statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template auto& get(internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.obj); } template const auto& get(const internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.obj); } template auto& get(internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for replace statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template const auto& get(const internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for replace statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template auto& get(internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template const auto& get(const internal::prepared_statement_t>& statement) { static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); + return internal::get_ref(statement.expression.object); } template const auto& get(const internal::prepared_statement_t& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; - using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; - const result_tupe* result = nullptr; - auto index = -1; - internal::iterate_ast(statement.t, [&result, &index](auto& node) { - using node_type = typename std::decay::type; - if(internal::is_bindable::value) { + using node_tuple = internal::node_tuple_t; + using bind_tuple = internal::bindable_filter_t; + using result_type = std::tuple_element_t(N), bind_tuple>; + const result_type* result = nullptr; + internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { + using node_type = std::decay_t; + if(internal::is_bindable_v) { ++index; } if(index == N) { - internal::static_if{}>([](auto& r, auto& n) { - r = const_cast::type>(&n); - })(result, node); + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = &n; + }, + result, + node); } }); return internal::get_ref(*result); @@ -17201,24 +19934,463 @@ namespace sqlite_orm { template auto& get(internal::prepared_statement_t& statement) { - using statement_type = typename std::decay::type; + using statement_type = std::decay_t; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; - using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; - result_tupe* result = nullptr; - auto index = -1; - internal::iterate_ast(statement.t, [&result, &index](auto& node) { - using node_type = typename std::decay::type; - if(internal::is_bindable::value) { + using node_tuple = internal::node_tuple_t; + using bind_tuple = internal::bindable_filter_t; + using result_type = std::tuple_element_t(N), bind_tuple>; + result_type* result = nullptr; + + internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { + using node_type = std::decay_t; + if(internal::is_bindable_v) { ++index; } if(index == N) { - internal::static_if{}>([](auto& r, auto& n) { - r = const_cast::type>(&n); - })(result, node); + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = const_cast>(&n); + }, + result, + node); } }); return internal::get_ref(*result); } } +#pragma once + +/* + * Note: This feature needs constexpr variables with external linkage. + * which can be achieved before C++17's inline variables, but differs from compiler to compiler. + * Hence we make it only available for compilers supporting inline variables. + */ + +#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED +#include // std::integral_constant +#include // std::move + +// #include "functional/cxx_universal.h" + +// #include "pointer_value.h" + +namespace sqlite_orm { + + inline constexpr const char carray_pvt_name[] = "carray"; + using carray_pvt = std::integral_constant; + + template + using carray_pointer_arg = pointer_arg; + template + using carray_pointer_binding = pointer_binding; + template + using static_carray_pointer_binding = static_pointer_binding; + + /** + * Wrap a pointer of type 'carray' and its deleter function for binding it to a statement. + * + * Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object + * is transferred to the pointer binding, which will delete it through + * the deleter when the statement finishes. + */ + template + auto bindable_carray_pointer(P* p, D d) noexcept -> pointer_binding { + return bindable_pointer(p, std::move(d)); + } + + /** + * Wrap a pointer of type 'carray' for binding it to a statement. + * + * Note: 'Static' means that ownership of the pointed-to-object won't be transferred + * and sqlite assumes the object pointed to is valid throughout the lifetime of a statement. + */ + template + auto statically_bindable_carray_pointer(P* p) noexcept -> static_pointer_binding { + return statically_bindable_pointer(p); + } + + /** + * Generalized form of the 'remember' SQL function that is a pass-through for values + * (it returns its argument unchanged using move semantics) but also saves the + * value that is passed through into a bound variable. + */ + template + struct note_value_fn { + P operator()(P&& value, carray_pointer_arg

pv) const { + if(P* observer = pv) { + *observer = value; + } + return std::move(value); + } + + static constexpr const char* name() { + return "note_value"; + } + }; + + /** + * remember(V, $PTR) extension function https://sqlite.org/src/file/ext/misc/remember.c + */ + struct remember_fn : note_value_fn { + static constexpr const char* name() { + return "remember"; + } + }; +} +#endif +#pragma once + +#include // std::string + +// #include "schema/column.h" + +// #include "schema/table.h" + +// #include "alias.h" + +namespace sqlite_orm { + /** + * SQLite's "schema table" that stores the schema for a database. + * + * @note Despite the fact that the schema table was renamed from "sqlite_master" to "sqlite_schema" in SQLite 3.33.0 + * the renaming process was more like keeping the previous name "sqlite_master" and attaching an internal alias "sqlite_schema". + * One can infer this fact from the following SQL statement: + * It qualifies the set of columns, but bails out with error "no such table: sqlite_schema": `SELECT sqlite_schema.* from sqlite_schema`. + * Hence we keep its previous table name `sqlite_master`, and provide `sqlite_schema` as a table alias in sqlite_orm. + */ + struct sqlite_master { + std::string type; + std::string name; + std::string tbl_name; + int rootpage = 0; + std::string sql; + +#ifdef SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED + friend bool operator==(const sqlite_master&, const sqlite_master&) = default; +#endif + }; + + inline auto make_sqlite_schema_table() { + return make_table("sqlite_master", + make_column("type", &sqlite_master::type), + make_column("name", &sqlite_master::name), + make_column("tbl_name", &sqlite_master::tbl_name), + make_column("rootpage", &sqlite_master::rootpage), + make_column("sql", &sqlite_master::sql)); + } + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + inline constexpr auto sqlite_schema = "sqlite_schema"_alias.for_(); +#endif +} +#pragma once + +#ifdef SQLITE_ENABLE_DBSTAT_VTAB +#include // std::string +#endif + +// #include "../schema/column.h" + +// #include "../schema/table.h" + +namespace sqlite_orm { +#ifdef SQLITE_ENABLE_DBSTAT_VTAB + struct dbstat { + std::string name; + std::string path; + int pageno = 0; + std::string pagetype; + int ncell = 0; + int payload = 0; + int unused = 0; + int mx_payload = 0; + int pgoffset = 0; + int pgsize = 0; + }; + + inline auto make_dbstat_table() { + return make_table("dbstat", + make_column("name", &dbstat::name), + make_column("path", &dbstat::path), + make_column("pageno", &dbstat::pageno), + make_column("pagetype", &dbstat::pagetype), + make_column("ncell", &dbstat::ncell), + make_column("payload", &dbstat::payload), + make_column("unused", &dbstat::unused), + make_column("mx_payload", &dbstat::mx_payload), + make_column("pgoffset", &dbstat::pgoffset), + make_column("pgsize", &dbstat::pgsize)); + } +#endif // SQLITE_ENABLE_DBSTAT_VTAB +} +/** @file Mainly existing to disentangle implementation details from circular and cross dependencies + * (e.g. column_t -> default_value_extractor -> serializer_context -> db_objects_tuple -> table_t -> column_t) + * this file is also used to provide definitions of interface methods 'hitting the database'. + */ +#pragma once + +// #include "implementations/column_definitions.h" +/** @file Mainly existing to disentangle implementation details from circular and cross dependencies + * (e.g. column_t -> default_value_extractor -> serializer_context -> db_objects_tuple -> table_t -> column_t) + * this file is also used to provide definitions of interface methods 'hitting the database'. + */ + +#include // std::make_unique + +// #include "../functional/cxx_core_features.h" + +// #include "../functional/static_magic.h" + +// #include "../functional/index_sequence_util.h" + +// #include "../tuple_helper/tuple_filter.h" + +// #include "../tuple_helper/tuple_traits.h" + +// #include "../default_value_extractor.h" + +// #include "../schema/column.h" + +namespace sqlite_orm { + namespace internal { + + template + std::unique_ptr column_constraints::default_value() const { + using default_op_index_sequence = + filter_tuple_sequence_t::template fn>; + + std::unique_ptr value; + call_if_constexpr( + [&value](auto& constraints, auto op_index_sequence) { + using default_op_index_sequence = decltype(op_index_sequence); + constexpr size_t opIndex = first_index_sequence_value(default_op_index_sequence{}); + value = std::make_unique(serialize_default_value(get(constraints))); + }, + this->constraints, + default_op_index_sequence{}); + return value; + } + + } +} + +// #include "implementations/table_definitions.h" +/** @file Mainly existing to disentangle implementation details from circular and cross dependencies + * (e.g. column_t -> default_value_extractor -> serializer_context -> db_objects_tuple -> table_t -> column_t) + * this file is also used to provide definitions of interface methods 'hitting the database'. + */ + +#include // std::decay_t +#include // std::move +#include // std::find_if, std::ranges::find + +// #include "../functional/cxx_universal.h" +// ::size_t +// #include "../type_printer.h" + +// #include "../schema/column.h" + +// #include "../schema/table.h" + +namespace sqlite_orm { + namespace internal { + + template + std::vector table_t::get_table_info() const { + std::vector res; + res.reserve(filter_tuple_sequence_t::size()); + this->for_each_column([&res](auto& column) { + using field_type = field_type_t>; + std::string dft; + if(auto d = column.default_value()) { + dft = std::move(*d); + } + res.emplace_back(-1, + column.name, + type_printer().print(), + column.is_not_null(), + std::move(dft), + column.template is(), + column.template is()); + }); + auto compositeKeyColumnNames = this->composite_key_columns_names(); + for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { + const std::string& columnName = compositeKeyColumnNames[i]; +#if __cpp_lib_ranges >= 201911L + auto it = std::ranges::find(res, columnName, &table_xinfo::name); +#else + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); +#endif + if(it != res.end()) { + it->pk = static_cast(i + 1); + } + } + return res; + } + + } +} + +// #include "implementations/storage_definitions.h" +/** @file Mainly existing to disentangle implementation details from circular and cross dependencies + * this file is also used to separate implementation details from the main header file, + * e.g. usage of the dbstat table. + */ + +#include // std::is_same +#include +#include // std::reference_wrapper, std::cref +#include // std::find_if, std::ranges::find + +// #include "../sqlite_schema_table.h" + +// #include "../eponymous_vtabs/dbstat.h" + +// #include "../type_traits.h" + +// #include "../util.h" + +// #include "../serializing_util.h" + +// #include "../storage.h" + +namespace sqlite_orm { + namespace internal { + + template + template> + sync_schema_result storage_t::sync_table(const Table& table, sqlite3* db, bool preserve) { + if(std::is_same, sqlite_master>::value) { + return sync_schema_result::already_in_sync; + } +#ifdef SQLITE_ENABLE_DBSTAT_VTAB + if(std::is_same, dbstat>::value) { + return sync_schema_result::already_in_sync; + } +#endif // SQLITE_ENABLE_DBSTAT_VTAB + auto res = sync_schema_result::already_in_sync; + bool attempt_to_preserve = true; + + auto schema_stat = this->schema_status(table, db, preserve, &attempt_to_preserve); + if(schema_stat != sync_schema_result::already_in_sync) { + if(schema_stat == sync_schema_result::new_table_created) { + this->create_table(db, table.name, table); + res = sync_schema_result::new_table_created; + } else { + if(schema_stat == sync_schema_result::old_columns_removed || + schema_stat == sync_schema_result::new_columns_added || + schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { + + // get table info provided in `make_table` call.. + auto storageTableInfo = table.get_table_info(); + + // now get current table info from db using `PRAGMA table_xinfo` query.. + auto dbTableInfo = this->pragma.table_xinfo(table.name); // should include generated columns + + // this vector will contain pointers to columns that gotta be added.. + std::vector columnsToAdd; + + this->calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo); + + if(schema_stat == sync_schema_result::old_columns_removed) { +#if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) + for(auto& tableInfo: dbTableInfo) { + this->drop_column(db, table.name, tableInfo.name); + } + res = sync_schema_result::old_columns_removed; +#else + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; +#endif + } + + if(schema_stat == sync_schema_result::new_columns_added) { + for(const table_xinfo* colInfo: columnsToAdd) { + table.for_each_column([this, colInfo, &tableName = table.name, db](auto& column) { + if(column.name != colInfo->name) { + return; + } + this->add_column(db, tableName, column); + }); + } + res = sync_schema_result::new_columns_added; + } + + if(schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { + + auto storageTableInfo = table.get_table_info(); + this->add_generated_cols(columnsToAdd, storageTableInfo); + + // remove extra columns and generated columns + this->backup_table(db, table, columnsToAdd); + res = sync_schema_result::new_columns_added_and_old_columns_removed; + } + } else if(schema_stat == sync_schema_result::dropped_and_recreated) { + // now get current table info from db using `PRAGMA table_xinfo` query.. + auto dbTableInfo = this->pragma.table_xinfo(table.name); // should include generated columns + auto storageTableInfo = table.get_table_info(); + + // this vector will contain pointers to columns that gotta be added.. + std::vector columnsToAdd; + + this->calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo); + + this->add_generated_cols(columnsToAdd, storageTableInfo); + + if(preserve && attempt_to_preserve) { + this->backup_table(db, table, columnsToAdd); + } else { + this->drop_create_with_loss(db, table); + } + res = schema_stat; + } + } + } + return res; + } + + template + template + void storage_t::copy_table( + sqlite3* db, + const std::string& sourceTableName, + const std::string& destinationTableName, + const Table& table, + const std::vector& columnsToIgnore) const { // must ignore generated columns + std::vector> columnNames; + columnNames.reserve(table.template count_of()); + table.for_each_column([&columnNames, &columnsToIgnore](const column_identifier& column) { + auto& columnName = column.name; +#if __cpp_lib_ranges >= 201911L + auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); +#else + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); +#endif + if(columnToIgnoreIt == columnsToIgnore.end()) { + columnNames.push_back(cref(columnName)); + } + }); + + std::stringstream ss; + ss << "INSERT INTO " << streaming_identifier(destinationTableName) << " (" + << streaming_identifiers(columnNames) << ") " + << "SELECT " << streaming_identifiers(columnNames) << " FROM " << streaming_identifier(sourceTableName) + << std::flush; + perform_void_exec(db, ss.str()); + } + } +} + +#pragma once + +#if defined(_MSC_VER) +__pragma(pop_macro("max")) +__pragma(pop_macro("min")) +#endif // defined(_MSC_VER) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0b2aa350..4e0ab3216 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ if (TRUE) endif() +add_definitions(-DSQLITE_ENABLE_FTS5) include_directories(${CMAKE_SOURCE_DIR}/3rdparty/SQLiteCpp/sqlite3) if (NOT CMAKE_NDK_BUILD MATCHES 1) diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index 39bcbeaec..8840c3a85 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -108,7 +108,7 @@ namespace DataExporter { using namespace sqlite_orm; return make_storage(dataBaseFile, make_table("M2", - make_column("id", &DBM2::m2Id, autoincrement(), primary_key()), + make_column("id", &DBM2::m2Id, primary_key().autoincrement()), make_column("fileDataId", &DBM2::fileDataId), make_column("fileName", &DBM2::fileName), make_column("version", &DBM2::version), diff --git a/src/minimapGenerator/storage/CMinimapDataDB.h b/src/minimapGenerator/storage/CMinimapDataDB.h index 826478a4e..abee4e4b2 100644 --- a/src/minimapGenerator/storage/CMinimapDataDB.h +++ b/src/minimapGenerator/storage/CMinimapDataDB.h @@ -51,7 +51,7 @@ namespace CMinimapDataDB { using namespace sqlite_orm; return make_storage(dataBaseFile, make_table("scenarios", - make_column("id", &ScenarioDef::id, autoincrement(), primary_key()), + make_column("id", &ScenarioDef::id, primary_key().autoincrement()), make_column("name", &ScenarioDef::name), make_column("orientation", &ScenarioDef::getOrientation, &ScenarioDef::setOrientation), make_column("close_ocean_color_r", &ScenarioDef::getCloseOceanColor_R, &ScenarioDef::setCloseOceanColor_R), make_column("close_ocean_color_g", &ScenarioDef::getCloseOceanColor_G, &ScenarioDef::setCloseOceanColor_G), @@ -66,7 +66,7 @@ namespace CMinimapDataDB { make_column("folder_to_save", &ScenarioDef::folderToSave) ), make_table("scenario_map_def", - make_column("id", &MapRenderDefDB::id, autoincrement(), primary_key()), + make_column("id", &MapRenderDefDB::id, primary_key().autoincrement()), make_column("map_id", &MapRenderDefDB::mapId), make_column("scenario_id", &MapRenderDefDB::scenarioId), make_column("delta_x", &MapRenderDefDB::deltaX), diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 02737f93a..e637cafc8 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -11,9 +11,12 @@ FileListWindow::FileListWindow(const HApiContainer &api) : m_api(api), m_storage m_storage.pragma.synchronous(0); m_storage.pragma.journal_mode(sqlite_orm::journal_mode::MEMORY); + m_storage.sync_schema(); m_filesTotal = m_storage.count(); + + makeNewSelectStatement(); } bool FileListWindow::draw() { @@ -26,6 +29,13 @@ bool FileListWindow::draw() { if (ImGui::Button("Scan repository...")) { } + if (ImGui::InputText("Filter: ", filterText.data(), filterText.size()-1)) { + filterText[filterText.size()-1] = 0; + filterTextStr = filterText.data(); + filterTextStr = "%"+filterTextStr+"%"; + m_fileRecCache.clear(); + makeNewSelectStatement(); + } if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | @@ -40,6 +50,7 @@ bool FileListWindow::draw() { ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible ImGui::TableHeadersRow(); + FileRecordCache newCache = FileRecordCache(); { ImGuiListClipper clipper; clipper.Begin(m_filesTotal); @@ -47,12 +58,18 @@ bool FileListWindow::draw() { auto f_amount = clipper.DisplayEnd-clipper.DisplayStart; auto f_offset = clipper.DisplayStart; - using namespace sqlite_orm; - auto items = m_storage.get_all( - order_by(&FileListDB::FileRecord::fileDataId), limit(f_offset, f_amount)); + std::vector fileRecords; - for (int i = 0; i < items.size(); i++) { - auto const &fileItem = items[i]; + auto iter = m_fileRecCache.find({f_amount, f_offset}); + if (iter != m_fileRecCache.end()) { + fileRecords = iter->second; + } else { + fileRecords = selectStatement->getFiles(f_offset, f_amount); + } + newCache[{f_amount, f_offset}] = fileRecords; + + for (int i = 0; i < fileRecords.size(); i++) { + auto const &fileItem = fileRecords[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%d", fileItem.fileDataId); @@ -63,6 +80,7 @@ bool FileListWindow::draw() { } } } + m_fileRecCache = newCache; ImGui::EndTable(); } } @@ -100,3 +118,61 @@ void FileListWindow::importCSV() { delete csv; } + +static auto createStatement(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, int &recordsTotal) { + using namespace sqlite_orm; + + recordsTotal = 0; + + auto whereClause = where( + or_( + like(&FileListDB::FileRecord::fileName, searchClause), + like(&FileListDB::FileRecord::fileDataId, searchClause) + ) + ); + + recordsTotal = storage.count(whereClause); + + auto statement = storage.prepare( + get_all( + whereClause, + order_by(&FileListDB::FileRecord::fileDataId), + limit(2, offset(3)) + ) + ); + + //std::cout << statement.sql() << std::endl; +// std::cout << get<0>(statement) << std::endl; +// std::cout << get<1>(statement) << std::endl; +// std::cout << get<2>(statement) << std::endl; +// std::cout << get<3>(statement) << std::endl; + + return statement; +} + +class FileListLambdaInst : public FileListLamda { +public: + FileListLambdaInst(decltype(FileListDB::makeStorage("")) &storage, std::string &searchClause, int &recordsTotal) : m_storage(storage), + m_recordsTotal(recordsTotal), m_statement(createStatement(storage, searchClause, recordsTotal)) + { + + } + + std::vector getFiles(int offset, int limit) override { + using namespace sqlite_orm; + + get<2>(m_statement) = limit; + get<3>(m_statement) = offset; + + return m_storage.execute(m_statement); + }; +private: + int &m_recordsTotal; + decltype(FileListDB::makeStorage("")) &m_storage; + decltype(createStatement(m_storage, "", m_recordsTotal)) m_statement; +}; + +void FileListWindow::makeNewSelectStatement() { + + selectStatement = std::make_unique(m_storage, filterTextStr, m_filesTotal); +} diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index efc7ed694..521b42a49 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -16,9 +16,48 @@ namespace FileListDB { std::string fileType; }; + struct FileRecord_FT5 { + int fileDataId; + std::string fileName; + std::string fileType; + }; + inline static auto makeStorage(const std::string &dataBaseFile) { using namespace sqlite_orm; return make_storage(dataBaseFile, + make_trigger("files_after_insert", + after() + .insert() + .on() + .begin( + insert(into(), + columns(&FileRecord_FT5::fileDataId, + &FileRecord_FT5::fileName), + values(std::make_tuple(new_(&FileRecord::fileDataId), + new_(&FileRecord::fileName) + ) + ) + ) + ) + .end()), + make_trigger("files_after_delete", + after() + .delete_() + .on() + .begin( + remove_all(where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) + ) + .end()), + make_trigger("files_after_update", + after() + .delete_() + .on() + .begin( + update_all(set(assign(&FileRecord_FT5::fileName, &FileRecord::fileName)), + where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) + ) + .end()), + make_virtual_table("files_FT5", using_fts5(make_column("fileName", &FileRecord_FT5::fileName), make_column("fileDataId", &FileRecord_FT5::fileDataId))), make_index("idx_files_name", &FileRecord::fileName), make_index("idx_files_type", &FileRecord::fileType), make_table("files", @@ -30,6 +69,12 @@ namespace FileListDB { }; } +class FileListLamda { +public: + virtual ~FileListLamda() {} + virtual std::vector getFiles(int offset, int limit) = 0; +}; + class FileListWindow { public: FileListWindow(const HApiContainer &api); @@ -39,10 +84,32 @@ class FileListWindow { HApiContainer m_api; bool m_showWindow; - int m_filesTotal; decltype(FileListDB::makeStorage("")) m_storage; + + struct FileRecordCacheKey { + int offset; + int amount; + bool operator==(const FileRecordCacheKey &other) const { + return offset == other.offset && amount == other.amount; + } + }; + struct FileRecordCacheKeyHasher { + std::size_t operator()(const FileRecordCacheKey& k) const { + using std::hash; + return hash{}(k.offset) ^ (hash{}(k.amount) << 12); + }; + }; + + typedef std::unordered_map, FileRecordCacheKeyHasher> FileRecordCache; + FileRecordCache m_fileRecCache; + + int m_filesTotal; + std::unique_ptr selectStatement; + std::array filterText = {0}; + std::string filterTextStr = ""; private: + void makeNewSelectStatement(); void importCSV(); }; From 7da0a82b17c6aa1a5ed6864fe7cfeae2f8af3c7e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 13 Nov 2023 23:50:31 +0200 Subject: [PATCH 151/212] temp commit --- CMakeLists.txt | 3 +- .../fileListWindow/FileListWindow.cpp | 464 +++++++++++++----- .../fileListWindow/FileListWindow.h | 85 +--- 3 files changed, 367 insertions(+), 185 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e0ab3216..52bdc930b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,7 +243,8 @@ set(SOURCE_FILES src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp src/ui/childWindow/textureRenderer/DebugRendererWindow.h src/ui/childWindow/fileListWindow/FileListWindow.cpp - src/ui/childWindow/fileListWindow/FileListWindow.h) + src/ui/childWindow/fileListWindow/FileListWindow.h +) set(SOURCE_FILES_VULKAN diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index e637cafc8..a596989fe 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -5,18 +5,289 @@ #include "FileListWindow.h" #include "../../../database/csvtest/csv.h" -FileListWindow::FileListWindow(const HApiContainer &api) : m_api(api), m_storage(FileListDB::makeStorage("fileList.db3")) { - m_filesTotal = 0; - m_showWindow = true; +namespace FileListDB { + struct FileRecord_FT5 { + int fileDataId; + std::string fileName; + std::string fileType; + }; + + inline static auto makeStorage(const std::string &dataBaseFile) { + using namespace sqlite_orm; + return make_storage(dataBaseFile, + make_trigger("files_after_insert", + after() + .insert() + .on() + .begin( + insert(into(), + columns(&FileRecord_FT5::fileDataId, + &FileRecord_FT5::fileName), + values(std::make_tuple(new_(&FileRecord::fileDataId), + new_(&FileRecord::fileName) + ) + ) + ) + ) + .end()), + make_trigger("files_after_delete", + after() + .delete_() + .on() + .begin( + remove_all(where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) + ) + .end()), + make_trigger("files_after_update", + after() + .delete_() + .on() + .begin( + update_all(set(assign(&FileRecord_FT5::fileName, &FileRecord::fileName)), + where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) + ) + .end()), + make_virtual_table("files_FT5", using_fts5(make_column("fileName", &FileRecord_FT5::fileName), make_column("fileDataId", &FileRecord_FT5::fileDataId))), + make_index("idx_files_name", &FileRecord::fileName), + make_index("idx_files_type", &FileRecord::fileType), + make_table("files", + make_column("fileDataId", &FileRecord::fileDataId, primary_key()), + make_column("fileName", &FileRecord::fileName), + make_column("file_type", &FileRecord::fileType) + ) + ); + }; +} +class StatementHolderAbstract { +public: + virtual ~StatementHolderAbstract() {}; + virtual std::vector execute(decltype(FileListDB::makeStorage("")) &storage, int limit, int offset) = 0; + virtual int getTotal() = 0; +}; + +decltype(FileListDB::makeStorage("")) *u_storage; + +template +>...> +constexpr auto const_abs(T const& x) noexcept +{ + return x < 0 ? -x : x; +} + +template +class StatementHolderA { +public: + std::function calcTotal; + +public: + auto createStatement(decltype(FileListDB::makeStorage("")) &storage, + const std::string &searchClause, bool sortAsc) { + using namespace sqlite_orm; + + auto whereClause = where( + or_( + like(&FileListDB::FileRecord::fileName, searchClause), + like(&FileListDB::FileRecord::fileDataId, searchClause) + ) + ); + + calcTotal = [whereClause, &storage]() { + return storage.count(whereClause); + }; + + calcTotal(); + + + + if constexpr (order == 1) { + return [statement = + storage.prepare(get_all( + whereClause, + !sortAsc ? + order_by(&FileListDB::FileRecord::fileDataId).desc() : + order_by(&FileListDB::FileRecord::fileDataId).asc(), + limit(2, offset(3)) + ))](decltype(storage) &storage, int limit, int offset) mutable { + using namespace sqlite_orm; + + get<2>(statement) = limit; + get<3>(statement) = offset; + + return storage.execute(statement); + }; + } else if constexpr (order == 2) { + return [statement = + storage.prepare(get_all( + whereClause, + !sortAsc ? + order_by(&FileListDB::FileRecord::fileDataId).desc() : + order_by(&FileListDB::FileRecord::fileDataId).asc(), + limit(2, offset(3)) + ))](decltype(storage) &storage, int limit, int offset) mutable { + using namespace sqlite_orm; + + get<2>(statement) = limit; + get<3>(statement) = offset; + + return storage.execute(statement); + }; + } else if constexpr (order == 3) { + return [statement = + storage.prepare(get_all( + whereClause, + !sortAsc ? + order_by(&FileListDB::FileRecord::fileDataId).desc() : + order_by(&FileListDB::FileRecord::fileDataId).asc(), + limit(2, offset(3)) + ))](decltype(storage) &storage, int limit, int offset) mutable { + using namespace sqlite_orm; + + get<2>(statement) = limit; + get<3>(statement) = offset; + + return storage.execute(statement); + }; + } + + //std::cout << statement.sql() << std::endl; +// std::cout << get<0>(statement) << std::endl; +// std::cout << get<1>(statement) << std::endl; +// std::cout << get<2>(statement) << std::endl; +// std::cout << get<3>(statement) << std::endl; + } +}; + +template +class StatementHolder: public StatementHolderAbstract, public StatementHolderA { +private: + decltype(((StatementHolderA *)(nullptr))->createStatement(*u_storage,"", false)) m_statementLambda; +public: + StatementHolder(decltype(FileListDB::makeStorage("")) &storage,const std::string &searchClause, bool sortAsc) : + m_statementLambda(StatementHolderA::createStatement(storage, searchClause, sortAsc)) { + + } + + std::vector execute(decltype(FileListDB::makeStorage("")) &storage, int limit, int offset) override { + return m_statementLambda(storage, limit, offset); + } + int getTotal() override { + return StatementHolderA::calcTotal(); + }; +}; + + + + +std::unique_ptr +statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, int order) { + switch(abs(order)) { + case 2: + return std::make_unique>(storage, searchClause, order > 0); + case 3: + return std::make_unique>(storage, searchClause, order > 0); + case 1: + default: + return std::make_unique>(storage, searchClause, order > 0); + } +} + + +enum class EnumParamsChanged { + OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING +}; + +class FileListLambdaInst : public FileListLamda { +public: + FileListLambdaInst(std::string &searchClause, int &recordsTotal) : m_recordsTotal(recordsTotal) + { + dbThread = std::thread([&]() { + decltype(FileListDB::makeStorage("")) storage = FileListDB::makeStorage("fileList.db3"); + storage.pragma.synchronous(0); + storage.pragma.journal_mode(sqlite_orm::journal_mode::MEMORY); + + storage.sync_schema(); + + std::unique_ptr statement = statementFactory(storage, searchClause, 1); + + auto doQuery = [&storage] (decltype(*statement) &statement, int limit, int offset) mutable { + + }; + + while (!this->m_isTerminating) { + auto stateWasChanged = stateChangeAwaiter.waitForNewInput(); + if (m_isTerminating) + continue; + + switch (stateWasChanged) { + case EnumParamsChanged::OFFSET_LIMIT: + + case EnumParamsChanged::SEARCH_STRING: + calcTotal(); + break; + + case EnumParamsChanged::SORTING: + statement = statementFactory(storage, searchClause, 1); + break; + } + + std::vector results; + { + std::unique_lock lock(paramsChange); + for (auto const & request : m_requests) { + auto &result1 = results.emplace_back(); + result1.offset = 0; + result1.records = statement->execute(storage, request.limit, request.offset); + } + } + setResults(results); + } + }); + } + const std::vector getResults() override{ + std::unique_lock lock(resultsChange); + + return m_results; + } + void makeRequest(const std::vector &newRequest) override { + std::unique_lock lock(paramsChange); + m_requests = newRequest; + }; +private: + + void setResults(const std::vector &results) { + std::unique_lock lock(resultsChange); + + m_results = results; + } + +private: + std::mutex paramsChange; + std::mutex resultsChange; - m_storage.pragma.synchronous(0); - m_storage.pragma.journal_mode(sqlite_orm::journal_mode::MEMORY); + std::thread dbThread; + bool m_isTerminating = false; - m_storage.sync_schema(); + std::function calcTotal; + int &m_recordsTotal; + int m_order; + + std::vector m_results; + std::vector m_requests; + + ProdConsumerIOConnector stateChangeAwaiter = {m_isTerminating}; +}; + +//-------------------------------------- +// FileListWindow +// ------------------------------------- + +FileListWindow::FileListWindow(const HApiContainer &api) : m_api(api) { + m_filesTotal = 0; + m_showWindow = true; - m_filesTotal = m_storage.count(); - makeNewSelectStatement(); + selectStatement = std::make_unique(filterTextStr, m_filesTotal); } bool FileListWindow::draw() { @@ -34,7 +305,6 @@ bool FileListWindow::draw() { filterTextStr = filterText.data(); filterTextStr = "%"+filterTextStr+"%"; m_fileRecCache.clear(); - makeNewSelectStatement(); } if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | @@ -50,7 +320,9 @@ bool FileListWindow::draw() { ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible ImGui::TableHeadersRow(); - FileRecordCache newCache = FileRecordCache(); + auto dbResults = selectStatement->getResults(); + bool needRequest = false; + std::vector newRequests = {}; { ImGuiListClipper clipper; clipper.Begin(m_filesTotal); @@ -59,27 +331,52 @@ bool FileListWindow::draw() { auto f_offset = clipper.DisplayStart; std::vector fileRecords; - - auto iter = m_fileRecCache.find({f_amount, f_offset}); - if (iter != m_fileRecCache.end()) { - fileRecords = iter->second; - } else { - fileRecords = selectStatement->getFiles(f_offset, f_amount); - } - newCache[{f_amount, f_offset}] = fileRecords; - - for (int i = 0; i < fileRecords.size(); i++) { - auto const &fileItem = fileRecords[i]; - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%d", fileItem.fileDataId); - ImGui::TableNextColumn(); - ImGui::Text(fileItem.fileName.c_str()); - ImGui::TableNextColumn(); - ImGui::Text(fileItem.fileType.c_str()); + for (auto &dbResult : dbResults) { + if ((dbResult.offset - f_offset) <= f_amount) { + int pre = std::max(dbResult.offset - f_offset, 0); + int start = std::max(f_offset-dbResult.offset, 0); + int size = f_amount - pre - start; + int post = f_amount - size; + + for (int i = 0; i < pre; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(""); + ImGui::TableNextColumn(); + ImGui::Text("LOADING..."); + ImGui::TableNextColumn(); + ImGui::Text(""); + } + + for (int i = start; i < size; i++) { + auto const &fileItem = fileRecords[i]; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d", fileItem.fileDataId); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileName.c_str()); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileType.c_str()); + } + for (int i = 0; i < post; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(""); + ImGui::TableNextColumn(); + ImGui::Text("LOADING..."); + ImGui::TableNextColumn(); + ImGui::Text(""); + } + + newRequests.emplace_back() + if (pre > 0 || post > 0) needRequest = true; + break; + } } } } + selectStatement->makeRequest(f_offset, f_amount); + m_fileRecCache = newCache; ImGui::EndTable(); } @@ -90,89 +387,32 @@ bool FileListWindow::draw() { } void FileListWindow::importCSV() { - auto csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); - - int currentFileDataId; - std::string currentFileName; - - using namespace sqlite_orm; - auto statement = m_storage.prepare( - select( - columns(&FileListDB::FileRecord::fileType), from(), - where(is_equal(&FileListDB::FileRecord::fileDataId, std::ref(currentFileDataId))) - ) - ); - - while (csv->read_row(currentFileDataId, currentFileName)) { - auto typeFromDB = m_storage.execute(statement); - - std::string fileType = ""; - if (!typeFromDB.empty()) { - fileType = get<0>(typeFromDB[0]); - } - - m_storage.replace(FileListDB::FileRecord({currentFileDataId, currentFileName, fileType})); - } - - m_filesTotal = m_storage.count(); - - delete csv; -} - -static auto createStatement(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, int &recordsTotal) { - using namespace sqlite_orm; - - recordsTotal = 0; - - auto whereClause = where( - or_( - like(&FileListDB::FileRecord::fileName, searchClause), - like(&FileListDB::FileRecord::fileDataId, searchClause) - ) - ); - - recordsTotal = storage.count(whereClause); - - auto statement = storage.prepare( - get_all( - whereClause, - order_by(&FileListDB::FileRecord::fileDataId), - limit(2, offset(3)) - ) - ); - - //std::cout << statement.sql() << std::endl; -// std::cout << get<0>(statement) << std::endl; -// std::cout << get<1>(statement) << std::endl; -// std::cout << get<2>(statement) << std::endl; -// std::cout << get<3>(statement) << std::endl; - - return statement; +// auto csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); +// +// int currentFileDataId; +// std::string currentFileName; +// +// using namespace sqlite_orm; +// auto statement = m_storage.prepare( +// select( +// columns(&FileListDB::FileRecord::fileType), from(), +// where(is_equal(&FileListDB::FileRecord::fileDataId, std::ref(currentFileDataId))) +// ) +// ); +// +// while (csv->read_row(currentFileDataId, currentFileName)) { +// auto typeFromDB = m_storage.execute(statement); +// +// std::string fileType = ""; +// if (!typeFromDB.empty()) { +// fileType = get<0>(typeFromDB[0]); +// } +// +// m_storage.replace(FileListDB::FileRecord({currentFileDataId, currentFileName, fileType})); +// } +// +// m_filesTotal = m_storage.count(); +// +// delete csv; } -class FileListLambdaInst : public FileListLamda { -public: - FileListLambdaInst(decltype(FileListDB::makeStorage("")) &storage, std::string &searchClause, int &recordsTotal) : m_storage(storage), - m_recordsTotal(recordsTotal), m_statement(createStatement(storage, searchClause, recordsTotal)) - { - - } - - std::vector getFiles(int offset, int limit) override { - using namespace sqlite_orm; - - get<2>(m_statement) = limit; - get<3>(m_statement) = offset; - - return m_storage.execute(m_statement); - }; -private: - int &m_recordsTotal; - decltype(FileListDB::makeStorage("")) &m_storage; - decltype(createStatement(m_storage, "", m_recordsTotal)) m_statement; -}; - -void FileListWindow::makeNewSelectStatement() { - - selectStatement = std::make_unique(m_storage, filterTextStr, m_filesTotal); -} diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index 521b42a49..53e79fa3c 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -16,63 +16,24 @@ namespace FileListDB { std::string fileType; }; - struct FileRecord_FT5 { - int fileDataId; - std::string fileName; - std::string fileType; - }; - inline static auto makeStorage(const std::string &dataBaseFile) { - using namespace sqlite_orm; - return make_storage(dataBaseFile, - make_trigger("files_after_insert", - after() - .insert() - .on() - .begin( - insert(into(), - columns(&FileRecord_FT5::fileDataId, - &FileRecord_FT5::fileName), - values(std::make_tuple(new_(&FileRecord::fileDataId), - new_(&FileRecord::fileName) - ) - ) - ) - ) - .end()), - make_trigger("files_after_delete", - after() - .delete_() - .on() - .begin( - remove_all(where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) - ) - .end()), - make_trigger("files_after_update", - after() - .delete_() - .on() - .begin( - update_all(set(assign(&FileRecord_FT5::fileName, &FileRecord::fileName)), - where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) - ) - .end()), - make_virtual_table("files_FT5", using_fts5(make_column("fileName", &FileRecord_FT5::fileName), make_column("fileDataId", &FileRecord_FT5::fileDataId))), - make_index("idx_files_name", &FileRecord::fileName), - make_index("idx_files_type", &FileRecord::fileType), - make_table("files", - make_column("fileDataId", &FileRecord::fileDataId, primary_key()), - make_column("fileName", &FileRecord::fileName), - make_column("file_type", &FileRecord::fileType) - ) - ); - }; } +struct DbRequest { + int offset; + int limit; +}; +struct DBResults { + int offset; + std::vector records; +}; + + class FileListLamda { public: virtual ~FileListLamda() {} - virtual std::vector getFiles(int offset, int limit) = 0; + virtual void makeRequest(const std::vector ¶msChange) = 0; + virtual const std::vector getResults() = 0; }; class FileListWindow { @@ -84,32 +45,12 @@ class FileListWindow { HApiContainer m_api; bool m_showWindow; - decltype(FileListDB::makeStorage("")) m_storage; - - - struct FileRecordCacheKey { - int offset; - int amount; - bool operator==(const FileRecordCacheKey &other) const { - return offset == other.offset && amount == other.amount; - } - }; - struct FileRecordCacheKeyHasher { - std::size_t operator()(const FileRecordCacheKey& k) const { - using std::hash; - return hash{}(k.offset) ^ (hash{}(k.amount) << 12); - }; - }; - - typedef std::unordered_map, FileRecordCacheKeyHasher> FileRecordCache; - FileRecordCache m_fileRecCache; int m_filesTotal; std::unique_ptr selectStatement; std::array filterText = {0}; - std::string filterTextStr = ""; + std::string filterTextStr = "%%"; private: - void makeNewSelectStatement(); void importCSV(); }; From e111f36869b77eeb6b22f290c2da0967b7cf285c Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 14 Nov 2023 01:15:50 +0200 Subject: [PATCH 152/212] list from separate thread works --- .../fileListWindow/FileListWindow.cpp | 79 +++++++++++++------ .../fileListWindow/FileListWindow.h | 1 + 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index a596989fe..7d96a4a61 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -209,10 +209,9 @@ class FileListLambdaInst : public FileListLamda { storage.sync_schema(); std::unique_ptr statement = statementFactory(storage, searchClause, 1); + m_recordsTotal = statement->getTotal(); - auto doQuery = [&storage] (decltype(*statement) &statement, int limit, int offset) mutable { - - }; + //stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); while (!this->m_isTerminating) { auto stateWasChanged = stateChangeAwaiter.waitForNewInput(); @@ -221,22 +220,29 @@ class FileListLambdaInst : public FileListLamda { switch (stateWasChanged) { case EnumParamsChanged::OFFSET_LIMIT: + break; case EnumParamsChanged::SEARCH_STRING: - calcTotal(); + m_recordsTotal = statement->getTotal(); break; case EnumParamsChanged::SORTING: statement = statementFactory(storage, searchClause, 1); + m_recordsTotal = statement->getTotal(); break; } std::vector results; { - std::unique_lock lock(paramsChange); - for (auto const & request : m_requests) { + std::vector l_requests = {}; + { + std::unique_lock lock(paramsChange); + l_requests = m_requests; //make local copy + } + + for (auto const & request : l_requests) { auto &result1 = results.emplace_back(); - result1.offset = 0; + result1.offset = request.offset; result1.records = statement->execute(storage, request.limit, request.offset); } } @@ -244,15 +250,31 @@ class FileListLambdaInst : public FileListLamda { } }); } + ~FileListLambdaInst() { + m_isTerminating = true; + stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); + + dbThread.join(); + } const std::vector getResults() override{ std::unique_lock lock(resultsChange); return m_results; } void makeRequest(const std::vector &newRequest) override { - std::unique_lock lock(paramsChange); - m_requests = newRequest; + { + std::unique_lock lock(paramsChange); + m_requests = newRequest; + } + stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); }; + void searchChanged() override { + std::unique_lock lock(resultsChange); + + m_results = {}; + + stateChangeAwaiter.pushInput(EnumParamsChanged::SEARCH_STRING); + } private: void setResults(const std::vector &results) { @@ -268,7 +290,6 @@ class FileListLambdaInst : public FileListLamda { std::thread dbThread; bool m_isTerminating = false; - std::function calcTotal; int &m_recordsTotal; int m_order; @@ -286,7 +307,6 @@ FileListWindow::FileListWindow(const HApiContainer &api) : m_api(api) { m_filesTotal = 0; m_showWindow = true; - selectStatement = std::make_unique(filterTextStr, m_filesTotal); } @@ -304,7 +324,7 @@ bool FileListWindow::draw() { filterText[filterText.size()-1] = 0; filterTextStr = filterText.data(); filterTextStr = "%"+filterTextStr+"%"; - m_fileRecCache.clear(); + selectStatement->searchChanged(); } if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | @@ -330,13 +350,17 @@ bool FileListWindow::draw() { auto f_amount = clipper.DisplayEnd-clipper.DisplayStart; auto f_offset = clipper.DisplayStart; - std::vector fileRecords; + auto& request = newRequests.emplace_back(); + request.offset = f_offset; + request.limit = f_amount; + + int post = f_amount; for (auto &dbResult : dbResults) { - if ((dbResult.offset - f_offset) <= f_amount) { + if (abs(dbResult.offset - f_offset) <= f_amount) { int pre = std::max(dbResult.offset - f_offset, 0); - int start = std::max(f_offset-dbResult.offset, 0); - int size = f_amount - pre - start; - int post = f_amount - size; + int db_start = std::max(f_offset-dbResult.offset, 0); + int db_end = db_start + std::min(dbResult.records.size() - db_start, f_amount); + post = std::max(f_amount - (db_end-db_start), 0); for (int i = 0; i < pre; i++) { ImGui::TableNextRow(); @@ -348,8 +372,8 @@ bool FileListWindow::draw() { ImGui::Text(""); } - for (int i = start; i < size; i++) { - auto const &fileItem = fileRecords[i]; + for (int i = db_start; i < db_end; i++) { + auto const &fileItem = dbResult.records[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%d", fileItem.fileDataId); @@ -368,16 +392,27 @@ bool FileListWindow::draw() { ImGui::Text(""); } - newRequests.emplace_back() if (pre > 0 || post > 0) needRequest = true; + + post = 0; break; } } + for (int i = 0; i < post; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(""); + ImGui::TableNextColumn(); + ImGui::Text("LOADING..."); + ImGui::TableNextColumn(); + ImGui::Text(""); + } + needRequest = needRequest || post > 0; } } - selectStatement->makeRequest(f_offset, f_amount); + if (needRequest) + selectStatement->makeRequest(newRequests); - m_fileRecCache = newCache; ImGui::EndTable(); } } diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index 53e79fa3c..7f5052a0c 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -33,6 +33,7 @@ class FileListLamda { public: virtual ~FileListLamda() {} virtual void makeRequest(const std::vector ¶msChange) = 0; + virtual void searchChanged() = 0; virtual const std::vector getResults() = 0; }; From d21ee909d80802788f945da279b6dab0d105a1ba Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 14 Nov 2023 19:46:11 +0200 Subject: [PATCH 153/212] - filelist somewhat works --- .../fileListWindow/FileListWindow.cpp | 228 ++++++++++++------ .../src/engine/shader/ShaderDefinitions.h | 222 +++++------------ .../ProdConsumerIOConnector.h | 4 +- 3 files changed, 210 insertions(+), 244 deletions(-) diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 7d96a4a61..d9bd196cd 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -133,7 +133,7 @@ class StatementHolderA { return storage.execute(statement); }; } else if constexpr (order == 3) { - return [statement = + return [&searchClause, statement = storage.prepare(get_all( whereClause, !sortAsc ? @@ -177,8 +177,6 @@ class StatementHolder: public StatementHolderAbstract, public StatementHolderA statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, int order) { switch(abs(order)) { @@ -192,6 +190,59 @@ statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::stri } } +namespace std { + +// partial specialization for reference_wrapper +// is this really necessary? + template + class hash> { + public: + std::size_t operator()(std::reference_wrapper x) const { return std::hash()(x.get()); } + }; +} + +template +class my_container { + // important: this really needs to be a deque and only front + // insertion/deletion is allowed to not get dangling references + typedef std::deque storage; + typedef std::reference_wrapper c_ref_w; + typedef std::reference_wrapper ref_w; +public: + typedef typename storage::value_type value_type; + typedef typename storage::reference reference; + typedef typename storage::const_reference const_reference; + typedef typename storage::size_type size_type; + + my_container(){} + + // no move semantics + void push_back(const T& t) { + auto it = lookup_.find(std::cref(t)); + if(it != end(lookup_)) { + // is already inserted report error + return; + } + store_.push_back(t); + // this is important to not have dangling references + lookup_.insert(store_.back()); + } + + // trivial functions + + bool empty() const { return store_.empty(); } + const T& front() const { return store_.front(); } + T& front() { return store_.front(); } + + void pop_front() { lookup_.erase(store_.front()); store_.pop_front(); } +private: + // look-up mechanism + std::unordered_set lookup_ = std::unordered_set(); + // underlying storage + storage store_; +}; + + enum class EnumParamsChanged { OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING @@ -214,39 +265,37 @@ class FileListLambdaInst : public FileListLamda { //stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); while (!this->m_isTerminating) { - auto stateWasChanged = stateChangeAwaiter.waitForNewInput(); - if (m_isTerminating) - continue; - - switch (stateWasChanged) { - case EnumParamsChanged::OFFSET_LIMIT: - break; - - case EnumParamsChanged::SEARCH_STRING: - m_recordsTotal = statement->getTotal(); - break; - - case EnumParamsChanged::SORTING: - statement = statementFactory(storage, searchClause, 1); - m_recordsTotal = statement->getTotal(); - break; - } + stateChangeAwaiter.waitAndProcess([&](auto & stateWasChanged) { + switch (stateWasChanged) { + case EnumParamsChanged::OFFSET_LIMIT: + break; - std::vector results; - { - std::vector l_requests = {}; - { - std::unique_lock lock(paramsChange); - l_requests = m_requests; //make local copy + case EnumParamsChanged::SEARCH_STRING: + statement = statementFactory(storage, searchClause, 1); + m_recordsTotal = statement->getTotal(); + break; + + case EnumParamsChanged::SORTING: + statement = statementFactory(storage, searchClause, 1); + break; } - for (auto const & request : l_requests) { - auto &result1 = results.emplace_back(); - result1.offset = request.offset; - result1.records = statement->execute(storage, request.limit, request.offset); + std::vector results; + { + std::vector l_requests = {}; + { + std::unique_lock lock(paramsChange); + l_requests = m_requests; //make local copy + } + + for (auto const & request : l_requests) { + auto &result1 = results.emplace_back(); + result1.offset = request.offset; + result1.records = statement->execute(storage, request.limit, request.offset); + } } - } - setResults(results); + setResults(results); + }); } }); } @@ -265,6 +314,12 @@ class FileListLambdaInst : public FileListLamda { { std::unique_lock lock(paramsChange); m_requests = newRequest; + for (auto &request : m_requests) { + if (request.limit > 1) { + request.offset = std::max(request.offset - request.limit, 0); + request.limit = request.limit * 3; + } + } } stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); }; @@ -296,7 +351,7 @@ class FileListLambdaInst : public FileListLamda { std::vector m_results; std::vector m_requests; - ProdConsumerIOConnector stateChangeAwaiter = {m_isTerminating}; + ProdConsumerIOConnector> stateChangeAwaiter = {m_isTerminating}; }; //-------------------------------------- @@ -330,14 +385,15 @@ bool FileListWindow::draw() { if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable | + ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY | ImGuiTableFlags_ScrollX, ImVec2(-1, -1))) { + ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible ImGui::TableSetupColumn("FileDataId", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("FileName", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("FileType", ImGuiTableColumnFlags_None); - ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible ImGui::TableHeadersRow(); auto dbResults = selectStatement->getResults(); @@ -354,50 +410,70 @@ bool FileListWindow::draw() { request.offset = f_offset; request.limit = f_amount; + int maxIndex = -1; + int maxRecordsOverlapped = 0; + for (int i = 0; i < dbResults.size(); i++) { + auto const &dbResult = dbResults[i]; + + int db_start = std::max(f_offset-dbResult.offset, 0); + int recordsOverlapped = std::min(dbResult.records.size() - db_start, f_amount); + + if (recordsOverlapped > maxRecordsOverlapped) { + maxRecordsOverlapped = recordsOverlapped; + maxIndex = i; + } + } + int post = f_amount; - for (auto &dbResult : dbResults) { - if (abs(dbResult.offset - f_offset) <= f_amount) { - int pre = std::max(dbResult.offset - f_offset, 0); - int db_start = std::max(f_offset-dbResult.offset, 0); - int db_end = db_start + std::min(dbResult.records.size() - db_start, f_amount); - post = std::max(f_amount - (db_end-db_start), 0); - - for (int i = 0; i < pre; i++) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text(""); - ImGui::TableNextColumn(); - ImGui::Text("LOADING..."); - ImGui::TableNextColumn(); - ImGui::Text(""); - } - - for (int i = db_start; i < db_end; i++) { - auto const &fileItem = dbResult.records[i]; - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%d", fileItem.fileDataId); - ImGui::TableNextColumn(); - ImGui::Text(fileItem.fileName.c_str()); - ImGui::TableNextColumn(); - ImGui::Text(fileItem.fileType.c_str()); - } - for (int i = 0; i < post; i++) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text(""); - ImGui::TableNextColumn(); - ImGui::Text("LOADING..."); - ImGui::TableNextColumn(); - ImGui::Text(""); - } - - if (pre > 0 || post > 0) needRequest = true; - - post = 0; - break; + if ( maxIndex >= 0 ) { + auto const &dbResult = dbResults[maxIndex]; + int pre = std::max(dbResult.offset - f_offset, 0); + int db_start = std::max(f_offset-dbResult.offset, 0); + int db_end = db_start + std::min(dbResult.records.size() - db_start, f_amount); + post = std::max(f_amount - (db_end-db_start), 0); + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5,0.5,0.5,1.0)); + for (int i = 0; i < pre; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(""); + ImGui::TableNextColumn(); + ImGui::Text("LOADING..."); + ImGui::TableNextColumn(); + ImGui::Text(""); + } + ImGui::PopStyleColor(); + + for (int i = db_start; i < db_end; i++) { + auto const &fileItem = dbResult.records[i]; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d", fileItem.fileDataId); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileName.c_str()); + ImGui::TableNextColumn(); + ImGui::Text(fileItem.fileType.c_str()); } + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5,0.5,0.5,1.0)); + for (int i = 0; i < post; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(""); + ImGui::TableNextColumn(); + ImGui::Text("LOADING..."); + ImGui::TableNextColumn(); + ImGui::Text(""); + } + ImGui::PopStyleColor(); + + if ((pre > 0) || (post > 0)) + needRequest = true; + + post = 0; } + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5,0.5,0.5,1.0)); for (int i = 0; i < post; i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -407,6 +483,8 @@ bool FileListWindow::draw() { ImGui::TableNextColumn(); ImGui::Text(""); } + ImGui::PopStyleColor(); + needRequest = needRequest || post > 0; } } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d40550ab6..258d00f96 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,11 +396,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -507,9 +502,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -676,11 +668,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -866,8 +853,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -906,7 +891,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -947,11 +931,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -969,17 +952,11 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1014,11 +991,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1140,15 +1116,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1171,11 +1138,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1309,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,7 +1530,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -1625,8 +1588,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1666,16 +1627,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1712,7 +1671,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1861,7 +1819,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -2107,17 +2064,12 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2223,11 +2175,8 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 9, { - } - }, - { - 8, { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { @@ -2239,16 +2188,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2729,19 +2629,19 @@ const std::unordered_map #include "../FrameProfile.h" -template +template> class ProdConsumerIOConnector { public: typedef T value_type; @@ -84,7 +84,7 @@ class ProdConsumerIOConnector { bool &m_terminating; std::mutex m_queueMutex; std::condition_variable m_condVar; - std::queue m_queue; + std::queue m_queue = std::queue(); }; From fc3c6513c93922c843b536cc8a98781536155a5c Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 15 Nov 2023 00:17:39 +0200 Subject: [PATCH 154/212] implement file list sort --- .../fileListWindow/FileListWindow.cpp | 42 ++++++++++++++----- .../fileListWindow/FileListWindow.h | 1 + 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index d9bd196cd..15d29ef9b 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -121,8 +121,8 @@ class StatementHolderA { storage.prepare(get_all( whereClause, !sortAsc ? - order_by(&FileListDB::FileRecord::fileDataId).desc() : - order_by(&FileListDB::FileRecord::fileDataId).asc(), + order_by(&FileListDB::FileRecord::fileName).desc() : + order_by(&FileListDB::FileRecord::fileName).asc(), limit(2, offset(3)) ))](decltype(storage) &storage, int limit, int offset) mutable { using namespace sqlite_orm; @@ -137,8 +137,8 @@ class StatementHolderA { storage.prepare(get_all( whereClause, !sortAsc ? - order_by(&FileListDB::FileRecord::fileDataId).desc() : - order_by(&FileListDB::FileRecord::fileDataId).asc(), + order_by(&FileListDB::FileRecord::fileType).desc() : + order_by(&FileListDB::FileRecord::fileType).asc(), limit(2, offset(3)) ))](decltype(storage) &storage, int limit, int offset) mutable { using namespace sqlite_orm; @@ -271,12 +271,12 @@ class FileListLambdaInst : public FileListLamda { break; case EnumParamsChanged::SEARCH_STRING: - statement = statementFactory(storage, searchClause, 1); + statement = statementFactory(storage, searchClause, m_order); m_recordsTotal = statement->getTotal(); break; case EnumParamsChanged::SORTING: - statement = statementFactory(storage, searchClause, 1); + statement = statementFactory(storage, searchClause, m_order); break; } @@ -330,6 +330,10 @@ class FileListLambdaInst : public FileListLamda { stateChangeAwaiter.pushInput(EnumParamsChanged::SEARCH_STRING); } + void setOrder(int order) override { + m_order = order; + stateChangeAwaiter.pushInput(EnumParamsChanged::SORTING); + } private: void setResults(const std::vector &results) { @@ -346,7 +350,7 @@ class FileListLambdaInst : public FileListLamda { bool m_isTerminating = false; int &m_recordsTotal; - int m_order; + int m_order = 1; std::vector m_results; std::vector m_requests; @@ -391,11 +395,29 @@ bool FileListWindow::draw() { ImGuiTableFlags_ScrollX, ImVec2(-1, -1))) { ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible - ImGui::TableSetupColumn("FileDataId", ImGuiTableColumnFlags_None); - ImGui::TableSetupColumn("FileName", ImGuiTableColumnFlags_None); - ImGui::TableSetupColumn("FileType", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("FileDataId", ImGuiTableColumnFlags_None,0,1); + ImGui::TableSetupColumn("FileName", ImGuiTableColumnFlags_None,0,2); + ImGui::TableSetupColumn("FileType", ImGuiTableColumnFlags_None,0,3); ImGui::TableHeadersRow(); + ImGuiTableSortSpecs *sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty && selectStatement) { + int order = 1; + for (int i = 0; i < sorts_specs->SpecsCount; i++) { + auto const &sort_spec = sorts_specs->Specs[i]; + if (sort_spec.SortDirection != ImGuiSortDirection_None ) { + order = sort_spec.ColumnUserID * ( + sort_spec.SortDirection == ImGuiSortDirection_Descending ? -1 : 1 + ); + break; + } + } + + selectStatement->setOrder(order); + sorts_specs->SpecsDirty = false; + } + + auto dbResults = selectStatement->getResults(); bool needRequest = false; std::vector newRequests = {}; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index 7f5052a0c..c122a5866 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -34,6 +34,7 @@ class FileListLamda { virtual ~FileListLamda() {} virtual void makeRequest(const std::vector ¶msChange) = 0; virtual void searchChanged() = 0; + virtual void setOrder(int order) = 0; virtual const std::vector getResults() = 0; }; From 5b29fef732f2959bed29b5f192b0a7cfd1a69a8e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 15 Nov 2023 11:09:48 +0200 Subject: [PATCH 155/212] view BLP files --- src/ui/FrontendUI.cpp | 7 ++- src/ui/childWindow/BLPViewer.cpp | 50 +++++++++++-------- src/ui/childWindow/BLPViewer.h | 5 +- .../fileListWindow/FileListWindow.cpp | 13 ++++- .../fileListWindow/FileListWindow.h | 6 +-- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 1ad0d986d..712744522 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -765,7 +765,12 @@ void FrontendUI::showMainMenu() { if (ImGui::BeginMenu("View")) { if (ImGui::MenuItem("Open File List", "", false, cascOpened)) { if (!m_fileListWindow) - m_fileListWindow = std::make_shared(m_api); + m_fileListWindow = std::make_shared([&](int fileId, const std::string &fileType){ + if (fileType == "blp") { + m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer, true); + m_blpViewerWindow->loadBlp(std::to_string(fileId)); + } + }); } if (ImGui::MenuItem("Open current stats")) { showCurrentStats = true; } ImGui::Separator(); diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index 7e4c1b8ef..cffde25f8 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -6,8 +6,8 @@ #include "imgui.h" #include -BLPViewer::BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer) : - m_api(api), m_uiRenderer(uiRenderer) +BLPViewer::BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer, bool noSearch) : + m_api(api), m_uiRenderer(uiRenderer), m_noSearch(noSearch) { } @@ -16,27 +16,17 @@ bool BLPViewer::draw() { ImGui::Begin("BLP Viewer", &m_showWindow); { - if (ImGui::InputText("BlpName/FileDataId: ", blpName.data(), blpName.size()-1)) { - blpName[blpName.size()-1] = 0; - } - ImGui::SameLine(); - if (ImGui::Button("Load")) { - int fileDataId = 0; - - try{ - fileDataId = std::stoi(blpName.data()); - } catch (...) {} - - if (fileDataId > 0) { - m_blpTexture = m_api->cacheStorage->getTextureCache()->getFileId(fileDataId); - m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); - material = m_uiRenderer->createUIMaterial({m_texture}, true); - } else { - m_blpTexture = m_api->cacheStorage->getTextureCache()->get(blpName.data()); - m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); - material = m_uiRenderer->createUIMaterial({m_texture}, true); + if (!m_noSearch) { + if (ImGui::InputText("BlpName/FileDataId: ", blpName.data(), blpName.size() - 1)) { + blpName[blpName.size() - 1] = 0; + } + ImGui::SameLine(); + if (ImGui::Button("Load")) { + std::string blpNameStr = blpName.data(); + loadBlp(blpNameStr); } } + if (m_blpTexture && m_blpTexture->getStatus() == FileStatus::FSRejected) { ImGui::Text("Failed to load BLP file"); } else @@ -71,3 +61,21 @@ bool BLPViewer::draw() { return m_showWindow; } + +void BLPViewer::loadBlp(const std::string &p_blpName) { + int fileDataId = 0; + + try{ + fileDataId = std::stoi(p_blpName); + } catch (...) {} + + if (fileDataId > 0) { + m_blpTexture = m_api->cacheStorage->getTextureCache()->getFileId(fileDataId); + m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({m_texture}, true); + } else { + m_blpTexture = m_api->cacheStorage->getTextureCache()->get(blpName.data()); + m_texture = m_api->hDevice->createBlpTexture(m_blpTexture, false, false); + material = m_uiRenderer->createUIMaterial({m_texture}, true); + } +} diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h index b6f1364fd..cf37c3a05 100644 --- a/src/ui/childWindow/BLPViewer.h +++ b/src/ui/childWindow/BLPViewer.h @@ -12,8 +12,9 @@ class BLPViewer { public: - BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer); + BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer, bool noSearch = false); + void loadBlp(const std::string &p_blpName); bool draw(); private: bool m_showWindow = true; @@ -26,6 +27,8 @@ class BLPViewer { std::shared_ptr m_blpTexture; HGSamplableTexture m_texture; std::shared_ptr material = nullptr; + + bool m_noSearch; }; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 15d29ef9b..8256a16ce 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -4,6 +4,7 @@ #include "FileListWindow.h" #include "../../../database/csvtest/csv.h" +#include "../../../../wowViewerLib/src/include/string_utils.h" namespace FileListDB { struct FileRecord_FT5 { @@ -362,7 +363,7 @@ class FileListLambdaInst : public FileListLamda { // FileListWindow // ------------------------------------- -FileListWindow::FileListWindow(const HApiContainer &api) : m_api(api) { +FileListWindow::FileListWindow(const std::function &fileOpenCallback) : m_fileOpenCallback(fileOpenCallback) { m_filesTotal = 0; m_showWindow = true; @@ -470,7 +471,15 @@ bool FileListWindow::draw() { auto const &fileItem = dbResult.records[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("%d", fileItem.fileDataId); + if (ImGui::Selectable(std::to_string(fileItem.fileDataId).c_str(), false, + ImGuiSelectableFlags_SpanAllColumns | + ImGuiSelectableFlags_AllowItemOverlap)) { + if (m_fileOpenCallback) { + if (endsWith(fileItem.fileName, ".blp")) { + m_fileOpenCallback(fileItem.fileDataId, "blp"); + } + } + } ImGui::TableNextColumn(); ImGui::Text(fileItem.fileName.c_str()); ImGui::TableNextColumn(); diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index c122a5866..79f7a2141 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -40,14 +40,14 @@ class FileListLamda { class FileListWindow { public: - FileListWindow(const HApiContainer &api); + FileListWindow(const std::function &fileOpenCallback); bool draw(); private: - HApiContainer m_api; - bool m_showWindow; + std::function m_fileOpenCallback; + int m_filesTotal; std::unique_ptr selectStatement; std::array filterText = {0}; From 091117607f07be1d655a0821738a3e962b377fc3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 17 Nov 2023 14:21:19 +0200 Subject: [PATCH 156/212] - update tracy to v10.0 --- wowViewerLib/3rdparty/tracy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wowViewerLib/3rdparty/tracy b/wowViewerLib/3rdparty/tracy index 897aec5b0..37aff70df 160000 --- a/wowViewerLib/3rdparty/tracy +++ b/wowViewerLib/3rdparty/tracy @@ -1 +1 @@ -Subproject commit 897aec5b062664d2485f4f9a213715d2e527e0ca +Subproject commit 37aff70dfa50cf6307b3fee6074d627dc2929143 From 58c92069a22112e258d8755bdda9d506f8e6b67e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 21 Nov 2023 02:56:34 +0200 Subject: [PATCH 157/212] - intermediate commit. mcal alpha loading is faster? --- .../shaders/glsl/visBuffer/adtShader.frag | 2 +- .../src/engine/objects/adt/adtObject.cpp | 35 +++++++---- .../src/engine/objects/scenes/map.cpp | 1 + .../src/engine/objects/wmo/wmoObject.cpp | 38 ++++++++--- .../src/engine/persistance/adtFile.cpp | 63 ++++++++++++++----- wowViewerLib/src/engine/persistance/adtFile.h | 3 +- .../engine/persistance/header/adtFileHeader.h | 6 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 1 - 8 files changed, 107 insertions(+), 42 deletions(-) diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index bc38f77d4..70ed78b09 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -90,7 +90,7 @@ void main() { const float threshold = 1.5; vec2 alphaCoord = vec2(vAlphaCoords); - vec3 alphaBlend = texture( s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], alphaCoord).gba; + vec3 alphaBlend = texture( s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], alphaCoord).rgb; vec2 tcLayer0 = transformUV(vTexCoord, 0, adtMeshWidePS); vec2 tcLayer1 = transformUV(vTexCoord, 1, adtMeshWidePS); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index fd7f1f79c..3f768b024 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -340,7 +340,7 @@ void AdtObject::calcBoundingBoxes() { } void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { - ZoneScoped; + //ZoneScoped; HGDevice device = m_api->hDevice; auto adtFileTex = m_adtFileTex; @@ -460,10 +460,16 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } if (!noLayers) { +// auto mclyIndexes = std::vector (m_adtFileTex->mcnkStructs[i].mclyCnt); +// std::generate(mclyIndexes.begin(), mclyIndexes.end(), [n = 0] () mutable { return n++; }); +// std::sort(mclyIndexes.begin(), mclyIndexes.end(), [mcnk = m_adtFileTex->mcnkStructs[i]](const auto& a, const auto& b) { +// return mcnk.mcly[a].textureId > mcnk.mcly[b].textureId; +// }); + for (int j = 0; j < m_adtFileTex->mcnkStructs[i].mclyCnt; j++) { auto &layerDef = m_adtFileTex->mcnkStructs[i].mcly[j]; - HGSamplableTexture layer_x = getAdtTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); + HGSamplableTexture layer_x = getAdtTexture(layerDef.textureId); // BlpTexture &layer_spec = getAdtSpecularTexture(m_adtFileTex->mcnkStructs[i].mcly[j].textureId); adtMaterialTemplate.textures[j] = layer_x; } @@ -480,19 +486,22 @@ inline uint8_t &getChannel(uint8_t *data, int x, int y, int width, int height, c return data[(width * y + x) * 4 + channel]; }; +constexpr int maxAlphaTexPerChunk = 4; +constexpr int alphaTexSize = 64; + +constexpr int texWidth = alphaTexSize * 16; +constexpr int texHeight = alphaTexSize * 16; + +std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); + void AdtObject::loadAlphaTextures() { ZoneScoped; int chunkCount = m_adtFileTex->mcnkRead+1; - constexpr int maxAlphaTexPerChunk = 4; - constexpr int alphaTexSize = 64; - - constexpr int texWidth = alphaTexSize * 16; - constexpr int texHeight = alphaTexSize * 16; int createdThisRun = 0; alphaTexture = m_api->hDevice->createTexture(false, false); - std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); - memset(bigTexture.data(), 0, bigTexture.size()); + + memset(bigTexture.data(), 0, bigTexture.size()); std::array alphaTextureData; if (chunkCount > 0) @@ -506,11 +515,11 @@ void AdtObject::loadAlphaTextures() { const auto indexY = mapTile.IndexY; memset(alphaTextureData.data(), 0, alphaTextureData.size()); - m_adtFileTex->processTexture(m_wdtFile->mphd->flags, i, alphaTextureData.data(), alphaTextureData.size()); + m_adtFileTex->processTexture(m_wdtFile->mphd->flags, indexY*16+indexX, alphaTextureData.data(), alphaTextureData.size()); - for (int x = 0; x < 64; x++) { - for (int y = 0; y < 64; y++) { - for (char channel = 0; channel < 4; channel++) { + for (int y = 0; y < 64; y++) { + for (int x = 0; x < 64; x++) { + for (uint8_t channel = 0; channel < 4; channel++) { getChannel(bigTexture.data(), indexX * 64 + x, indexY * 64 + y, texWidth, texHeight, channel) = diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 8f90fce46..e5c823197 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1136,6 +1136,7 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat const HMapRenderPlan &mapRenderPlan, M2ObjectListContainer &m2ObjectsCandidates, WMOListContainer &wmoCandidates) { + ZoneScoped; if (m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { //Get visible area that should be checked float minx = 99999, maxx = -99999; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index a2651371a..a5e99ad20 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -571,6 +571,28 @@ bool WmoObject::startTraversingWMOGroup( std::vector ivPerWMOGroup = std::vector(mainGeom->groupsLen); uint32_t portalCount = (uint32_t) std::max(0, this->mainGeom->portalsLen); + + if (portalCount == 0) { + auto exteriorView = viewsHolder.getOrCreateExterior(frustumDataGlobal); + bool result = false; + for (int i = 0; i< mainGeom->groupsLen; i++) { + if ((mainGeom->groups[i].flags.EXTERIOR) > 0 || !m_api->getConfig()->usePortalCulling) { //exterior + if (this->groupObjects[i] != nullptr) { + bool drawDoodads, drawGroup; + this->groupObjects[i]->checkGroupFrustum(drawDoodads, drawGroup, cameraVec4, frustumDataGlobal); + if (drawDoodads) { + exteriorView->wmoGroupArray.addToCheckM2(this->groupObjects[i]); + } + if (drawGroup) { + exteriorView->wmoGroupArray.addToDraw(this->groupObjects[i]); + } + result |= drawGroup; + } + } + } + return result; + } + std::vector transverseVisitedPortals = std::vector(portalCount, false); //CurrentVisibleM2 and visibleWmo is array of global m2 objects, that are visible after frustum @@ -661,13 +683,15 @@ bool WmoObject::startTraversingWMOGroup( if (drawGroup) { exteriorView->wmoGroupArray.addToDraw(this->groupObjects[i]); traverseTempData.atLeastOneGroupIsDrawn = true; - this->traverseGroupWmo( - i, - false, - traverseTempData, - frustumPlanesLocal, - globalLevel, - 0); + if (m_api->getConfig()->usePortalCulling && portalCount > 0) { + this->traverseGroupWmo( + i, + false, + traverseTempData, + frustumPlanesLocal, + globalLevel, + 0); + } } } } diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 6189a3cae..c3d610431 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -98,8 +98,10 @@ chunkDef AdtFile::adtFileTable = { [](AdtFile& file, ChunkData& chunkData){ debuglog("Entered MAMP"); // std::cout << "Found MAMP" << std::endl; - file.mamp_len = chunkData.chunkLen / sizeof(char); - chunkData.readValues(file.mamp, file.mamp_len); +// std::cout << "mamp chunkData.chunkLen = " << chunkData.chunkLen << std::endl; + + chunkData.readValue(file.mamp_val); +// std::cout << "mamp value = " << (int)file.mamp_val << std::endl; } } }, @@ -395,7 +397,7 @@ chunkDef AdtFile::adtFileTable = { { [](AdtFile& file, ChunkData& chunkData){ debuglog("Entered MCAL"); - chunkData.readValue(file.mcnkStructs[file.mcnkRead].mcal); + chunkData.readValues(file.mcnkStructs[file.mcnkRead].mcal, chunkData.chunkLen); } } }, @@ -495,35 +497,56 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *curre assert(mcnkObj.mclyCnt <= 4); if (layers == nullptr || alphaArray == nullptr) return; + int uncompressedIndex = 0; + for (int j = 0; j < mcnkObj.mclyCnt; j++ ) { + if (layers[j].flags.use_alpha_map == 0) { + uncompressedIndex = j; + } + } + +// auto mclyIndexes = std::vector (mcnkStructs[i].mclyCnt); +// std::generate(mclyIndexes.begin(), mclyIndexes.end(), [n = 0] () mutable { return n++; }); +// std::sort(mclyIndexes.begin(), mclyIndexes.end(), [mcnk = mcnkStructs[i]](const auto& a, const auto& b) { +// return mcnk.mcly[a].textureId > mcnk.mcly[b].textureId; +// }); - for (int j = 0; j < mcnkObj.mclyCnt; j++ ) { - int alphaOffs = layers[j].offsetInMCAL; - int offO = j; + for (int j = 1; j < mcnkObj.mclyCnt; j++ ) { + auto &layerDef = layers[j]; + int alphaOffs = layerDef.offsetInMCAL; + int offO = j-1; int readForThisLayer = 0; - if (!layers[j].flags.use_alpha_map) { + if (!layerDef.flags.use_alpha_map) { for (int k = 0; k < 4096; k++) { - currentLayer[offO+k*4] = 255; + currentLayer[offO+k*4] = 0; } - } else if (layers[j].flags.alpha_map_compressed) { + } else if (layerDef.flags.alpha_map_compressed) { //Compressed //http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18 + int readThisRow = 0; while( readForThisLayer < 4096 ) { // fill or copy mode - bool fill = (alphaArray[alphaOffs] & 0x80 ) > 0; - int n = alphaArray[alphaOffs] & 0x7F; - alphaOffs++; + uint8_t codeVal = alphaArray[alphaOffs++]; + bool fill = (codeVal & 0x80 ) != 0; + int n = fill ? + codeVal & 0x7F : + codeVal; - for ( int k = 0; k < n && readForThisLayer < 4096; k++ ) + + for ( int k = 0; k < n && readForThisLayer < 4096; k++) { currentLayer[offO] = alphaArray[alphaOffs]; readForThisLayer++; offO += 4; - if( !fill ) alphaOffs++; + + if (++readThisRow >= 64) { + readThisRow = 0; + break; + } } if( fill ) alphaOffs++; } @@ -554,7 +577,6 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *curre } } } - //Fix alpha depending on flag // if (((wdtObjFlags.adt_has_big_alpha) > 0) || ((wdtObjFlags.adt_has_height_texturing) > 0)) { // int offO = j; @@ -563,6 +585,17 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *curre // } // } } + + if (uncompressedIndex) { + for ( int i = 0; i < 64*64; i++ ) { + uint8_t layer0 = currentLayer[i * 4 + 0]; + uint8_t layer1 = currentLayer[i * 4 + 1]; + uint8_t layer2 = currentLayer[i * 4 + 2]; + uint8_t layer3 = currentLayer[i * 4 + 3]; + + currentLayer[i*4 + uncompressedIndex] = 255 - layer0 - layer1 - layer2 - layer3; + } + } } static bool isHoleLowRes(int hole, int i, int j) { diff --git a/wowViewerLib/src/engine/persistance/adtFile.h b/wowViewerLib/src/engine/persistance/adtFile.h index 58a4cb30d..d0578855c 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.h +++ b/wowViewerLib/src/engine/persistance/adtFile.h @@ -68,8 +68,7 @@ class AdtFile: public PersistentFile { PointerChecker mtxf = mtxf_len; int mtxf_len = 0; - PointerChecker mamp = mamp_len; - int mamp_len = 0; + uint8_t mamp_val = 0; PointerChecker doodadDef = doodadDef_len; int doodadDef_len = 0; diff --git a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h index e5646879a..71e501f4b 100644 --- a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h @@ -256,9 +256,9 @@ struct SMLayer uint32_t animation_speed : 3; uint32_t animation_enabled : 1; uint32_t overbright : 1; // This will make the texture way brighter. Used for lava to make it "glow". - uint32_t use_alpha_map : 1; // set for every layer after the first - uint32_t alpha_map_compressed : 1; // see MCAL chunk description - uint32_t use_cube_map_reflection : 1; // This makes the layer behave like its a reflection of the skybox. See below + uint32_t use_alpha_map : 1; // 0x100, set for every layer after the first + uint32_t alpha_map_compressed : 1; // 0x200, see MCAL chunk description + uint32_t use_cube_map_reflection : 1; // 0x400, This makes the layer behave like its a reflection of the skybox. See below uint32_t unknown_0x800 : 1; // WoD?+ if either of 0x800 or 0x1000 is set, texture effects' texture_scale is applied uint32_t unknown_0x1000 : 1; // WoD?+ see 0x800 uint32_t unused: 19; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 1a48351c3..8072848ef 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -532,7 +532,6 @@ HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) std::shared_ptr MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { - ZoneScoped; auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); auto fragmentData = std::make_shared>(adtBuffers.adtMeshWidePSes); From 8a46d25ccc87b6e69926129ce8f866b9a05d51e2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 22 Nov 2023 14:43:29 +0200 Subject: [PATCH 158/212] - sse interleave for alpha --- .../src/engine/objects/adt/adtObject.cpp | 78 +++++++++---- .../src/engine/persistance/adtFile.cpp | 110 +++++++++--------- wowViewerLib/src/engine/persistance/adtFile.h | 8 +- 3 files changed, 120 insertions(+), 76 deletions(-) diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 3f768b024..f7d12bd0c 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -480,10 +480,18 @@ void AdtObject::fillTextureForMCNK(HGDevice &device, int i, bool noLayers, ADTMa } } +template inline uint8_t &getChannel(uint8_t *data, int x, int y, int width, int height, char channel) { // assert(((width * y + x ) * 4 + channel) < data.size()); - return data[(width * y + x) * 4 + channel]; + return data[(width * y + x) * channelNum + channel]; +}; + +template +inline void *getRowPtr(uint8_t *data, int x, int y, int width, int height, char channel) { + +// assert(((width * y + x ) * 4 + channel) < data.size()); + return (void *) &data[(width * y + x) * channelNum + channel]; }; constexpr int maxAlphaTexPerChunk = 4; @@ -502,34 +510,64 @@ void AdtObject::loadAlphaTextures() { alphaTexture = m_api->hDevice->createTexture(false, false); memset(bigTexture.data(), 0, bigTexture.size()); - std::array alphaTextureData; - - if (chunkCount > 0) - for (int i = 0; i < chunkCount; i++){ -// oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); -// arena.execute([&] { -// oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { -// for (size_t i = r.begin(); i != r.end(); ++i) { + + if (chunkCount > 0) { +// for (int i = 0; i < chunkCount; i++){ + oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); + arena.execute([&] { + oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + ALIGNED_(16) std::array alphaTextureData; + auto const &mapTile = m_adtFile->mapTile[i]; const auto indexX = mapTile.IndexX; const auto indexY = mapTile.IndexY; memset(alphaTextureData.data(), 0, alphaTextureData.size()); - m_adtFileTex->processTexture(m_wdtFile->mphd->flags, indexY*16+indexX, alphaTextureData.data(), alphaTextureData.size()); + auto chunkMcalRuntime = m_adtFileTex->createAlphaTextureRuntime(i); for (int y = 0; y < 64; y++) { - for (int x = 0; x < 64; x++) { - for (uint8_t channel = 0; channel < 4; channel++) { - getChannel(bigTexture.data(), - indexX * 64 + x, indexY * 64 + y, - texWidth, texHeight, channel) = - getChannel(alphaTextureData.data(), x, y, alphaTexSize, alphaTexSize, channel); - } + m_adtFileTex->processAlphaTextureRow(chunkMcalRuntime,m_wdtFile->mphd->flags, i, alphaTextureData.data(), alphaTextureData.size()); + + __m128i *alpha[4] = { + (__m128i *)(alphaTextureData.data() + (0)), + (__m128i *)(alphaTextureData.data() + (64)), + (__m128i *)(alphaTextureData.data() + (64 * 2)), + (__m128i *)(alphaTextureData.data() + (64 * 3)), + }; + + auto texturePtr = (__m128i*)getRowPtr<4>(bigTexture.data(), + indexX * 64 + 0, indexY * 64 + y, + texWidth, texHeight, 0); + + for (int x = 0; x < 64/16; x++) { + //Interleave + __m128i alpha0 = _mm_load_si128(alpha[0]++); //a_1 a_2 a_3 a_4 a_5 a_6 a_7 a_8 a_9 a_10 a_11 a_12 a_13 a_14 a_15 a_16 + __m128i alpha1 = _mm_load_si128(alpha[1]++); //b_1 b_2 b_3 b_4 b_5 b_6 b_7 b_8 b_9 b_10 b_11 b_12 b_13 b_14 b_15 b_16 + __m128i alpha2 = _mm_load_si128(alpha[2]++); //c_1 c_2 c_3 c_4 c_5 c_6 c_7 c_8 c_9 c_10 c_11 c_12 c_13 c_14 c_15 c_16 + __m128i alpha3 = _mm_load_si128(alpha[3]++); //d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10 d_11 d_12 d_13 d_14 d_15 d_16 + + __m128i a_b_low = _mm_unpacklo_epi8(alpha0, alpha1); //a_1 b_1 a_2 b_2 a_3 b_3 a_4 b_4 a_5 b_5 a_6 b_6 a_7 b_7 + __m128i a_b_high = _mm_unpackhi_epi8(alpha0, alpha1); //a_8 b_8 a_9 b_9 a_10 b_10 a_11 b_11 a_12 b_12 a_13 b_13 a_14 b_14 + + __m128i c_d_low = _mm_unpacklo_epi8(alpha2, alpha3); //c_1 d_1 c_2 d_2 c_3 d_3 c_4 d_4 c_5 d_5 c_6 d_6 c_7 d_7 + __m128i c_d_high = _mm_unpackhi_epi8(alpha2, alpha3);//c_8 d_8 c_9 d_9 c_10 d_10 c_11 d_11 c_12 d_12 c_13 d_13 c_14 d_14 + + __m128i a_b_c_d_low_low = _mm_unpacklo_epi16(a_b_low, c_d_low); //a_1 b_1 c_1 d_1 a_2 b_2 c_2 d_2... + __m128i a_b_c_d_low_high = _mm_unpackhi_epi16(a_b_low, c_d_low);//a_4 b_4 c_4 d_4 a_5 b_5 c_5 d_5... + + __m128i a_b_c_d_high_low = _mm_unpacklo_epi16(a_b_high, c_d_high);//a_8 b_8 c_8 d_8 a_9 b_9 c_9 d_9... + __m128i a_b_c_d_high_high = _mm_unpackhi_epi16(a_b_high, c_d_high);//a_11 b_11 c_11 d_11 a_12 b_12 c_12 d_12... + + _mm_store_si128(texturePtr++, a_b_c_d_low_low); + _mm_store_si128(texturePtr++, a_b_c_d_low_high); + _mm_store_si128(texturePtr++, a_b_c_d_high_low); + _mm_store_si128(texturePtr++, a_b_c_d_high_high); } } -// } -// }, tbb::auto_partitioner()); -// }); + } + }, tbb::auto_partitioner()); + }); } alphaTexture->getTexture()->loadData(texWidth, texHeight, &bigTexture[0], ITextureFormat::itRGBA); diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index c3d610431..ed40b22bf 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -488,93 +488,91 @@ chunkDef AdtFile::adtFileTable = { } }; -void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize) { - mcnkStruct_t &mcnkObj = mcnkStructs[i]; - uint8_t* alphaArray = mcnkObj.mcal; - PointerChecker &layers = mcnkObj.mcly; +MCAL_Offsets_Runtime AdtFile::createAlphaTextureRuntime(int mcnkChunkIndex) { + mcnkStruct_t &mcnkObj = mcnkStructs[mcnkChunkIndex]; + uint8_t* mcal = mcnkObj.mcal; + auto &layers = mcnkObj.mcly; - assert(currentLayerSize >= (64*4) * 64); - assert(mcnkObj.mclyCnt <= 4); - if (layers == nullptr || alphaArray == nullptr) return; + MCAL_Offsets_Runtime result; + for (int j = 1; j < mcnkObj.mclyCnt; j++ ) { + auto &layerDef = layers[j]; + int alphaOffs = layerDef.offsetInMCAL; + + result.alphaOffsets[j-1] = &mcal[alphaOffs]; + } - int uncompressedIndex = 0; + result.uncompressedIndex = 0; for (int j = 0; j < mcnkObj.mclyCnt; j++ ) { if (layers[j].flags.use_alpha_map == 0) { - uncompressedIndex = j; + result.uncompressedIndex = j; } } + return result; +} + +void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t textureSize) { + mcnkStruct_t &mcnkObj = mcnkStructs[i]; + uint8_t* mcal = mcnkObj.mcal; + auto &layers = mcnkObj.mcly; + + assert(mcnkObj.mclyCnt <= 4); + if (layers == nullptr || mcal == nullptr) return; -// auto mclyIndexes = std::vector (mcnkStructs[i].mclyCnt); -// std::generate(mclyIndexes.begin(), mclyIndexes.end(), [n = 0] () mutable { return n++; }); -// std::sort(mclyIndexes.begin(), mclyIndexes.end(), [mcnk = mcnkStructs[i]](const auto& a, const auto& b) { -// return mcnk.mcly[a].textureId > mcnk.mcly[b].textureId; -// }); for (int j = 1; j < mcnkObj.mclyCnt; j++ ) { auto &layerDef = layers[j]; - int alphaOffs = layerDef.offsetInMCAL; - int offO = j-1; + + auto &alphaArray = mcalRuntime.alphaOffsets[j-1]; + int readForThisLayer = 0; if (!layerDef.flags.use_alpha_map) { - for (int k = 0; k < 4096; k++) { - currentLayer[offO+k*4] = 0; - } +// for (int k = 0; k < 4096; k++) { +// *currentLayer++ = 0; +// } } else if (layerDef.flags.alpha_map_compressed) { //Compressed //http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18 - int readThisRow = 0; - while( readForThisLayer < 4096 ) + while( readForThisLayer < 64 ) { // fill or copy mode - uint8_t codeVal = alphaArray[alphaOffs++]; + uint8_t codeVal = *alphaArray++; bool fill = (codeVal & 0x80 ) != 0; int n = fill ? codeVal & 0x7F : codeVal; + if (fill) { + uint8_t alphaVal = *alphaArray++; - for ( int k = 0; k < n && readForThisLayer < 4096; k++) - { - currentLayer[offO] = alphaArray[alphaOffs]; - readForThisLayer++; - offO += 4; - - if( !fill ) alphaOffs++; - - if (++readThisRow >= 64) { - readThisRow = 0; - break; + for (int k = 0; k < n && readForThisLayer < 64; k++) { + *currentLayer++ = alphaVal; + readForThisLayer++; + } + } else { + for (int k = 0; k < n && readForThisLayer < 64; k++) { + *currentLayer++ = *alphaArray++; + readForThisLayer++; } } - if( fill ) alphaOffs++; } } else { //Uncompressed if (((wdtObjFlags.adt_has_big_alpha) > 0) || ((wdtObjFlags.adt_has_height_texturing) > 0)) { //Uncompressed (4096) - for (int iX =0; iX < 64; iX++) { for (int iY = 0; iY < 64; iY++){ - currentLayer[offO] = alphaArray[alphaOffs]; - - offO += 4; - readForThisLayer+=1; - alphaOffs++; + *currentLayer++ = *alphaArray++; } - } + } else { //Uncompressed (2048) - for (int iX =0; iX < 64; iX++) { for (int iY = 0; iY < 32; iY++){ //Old world - currentLayer[offO] = (alphaArray[alphaOffs] & 0x0f ) * 17; - offO += 4; - currentLayer[offO] = ((alphaArray[alphaOffs] & 0xf0 ) >> 4) * 17; - offO += 4; - readForThisLayer+=2; alphaOffs++; + uint8_t alphaVal = *alphaArray++; + *currentLayer++ = (alphaVal & 0x0f ) * 17; + *currentLayer++ = ((alphaVal & 0xf0 ) >> 4) * 17; } - } } } //Fix alpha depending on flag @@ -586,14 +584,16 @@ void AdtFile::processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *curre // } } - if (uncompressedIndex) { - for ( int i = 0; i < 64*64; i++ ) { - uint8_t layer0 = currentLayer[i * 4 + 0]; - uint8_t layer1 = currentLayer[i * 4 + 1]; - uint8_t layer2 = currentLayer[i * 4 + 2]; - uint8_t layer3 = currentLayer[i * 4 + 3]; + if (mcalRuntime.uncompressedIndex) { + auto pCurrentLayer = currentLayer; + auto pCurrentLayerInt = (uint32_t *)currentLayer; + for ( int i = 0; i < 64; i++ ) { + uint8_t layer0 = *pCurrentLayer++; + uint8_t layer1 = *pCurrentLayer++; + uint8_t layer2 = *pCurrentLayer++; + uint8_t layer3 = *pCurrentLayer++; - currentLayer[i*4 + uncompressedIndex] = 255 - layer0 - layer1 - layer2 - layer3; + *pCurrentLayerInt++ = 255 - layer0 - layer1 - layer2 - layer3; } } } diff --git a/wowViewerLib/src/engine/persistance/adtFile.h b/wowViewerLib/src/engine/persistance/adtFile.h index d0578855c..5b8669f0a 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.h +++ b/wowViewerLib/src/engine/persistance/adtFile.h @@ -33,12 +33,18 @@ struct mcnkStruct_t { int mcqlLen = 0; }; +struct MCAL_Offsets_Runtime { + int uncompressedIndex = 0; + std::array alphaOffsets = {nullptr,nullptr,nullptr}; +}; + class AdtFile: public PersistentFile { public: AdtFile(std::string fileName){for (auto &mcnk: mcnkMap) {mcnk.fill(-1);}}; AdtFile(int fileDataId){for (auto &mcnk: mcnkMap) {mcnk.fill(-1);}}; - void processTexture(const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize); + MCAL_Offsets_Runtime createAlphaTextureRuntime(int i); + void processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize); void process(HFileContent adtFile, const std::string &fileName) override; void setIsMain(bool isMain) { m_mainAdt = isMain; }; public: From 05039eef8606485ccb9b76ccf2d0ca44fd627fc2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 6 Dec 2023 16:43:49 +0200 Subject: [PATCH 159/212] - adt shader refactor --- src/ui/FrontendUI.cpp | 2 +- .../fileListWindow/FileListWindow.cpp | 49 +++--- .../fileListWindow/FileListWindow.h | 4 +- .../glsl/common/commonADTMaterial.glsl | 151 ++++++++++++++++++ .../glsl/forwardRendering/adtShader.frag | 99 +++--------- .../glsl/forwardRendering/adtShader.vert | 54 +------ .../shaders/glsl/visBuffer/adtShader.frag | 115 ++++--------- .../shaders/glsl/visBuffer/adtShader.vert | 54 +------ .../src/engine/persistance/adtFile.cpp | 6 +- .../src/engine/shader/ShaderDefinitions.h | 24 +-- 10 files changed, 259 insertions(+), 299 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 712744522..de10c54f8 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -765,7 +765,7 @@ void FrontendUI::showMainMenu() { if (ImGui::BeginMenu("View")) { if (ImGui::MenuItem("Open File List", "", false, cascOpened)) { if (!m_fileListWindow) - m_fileListWindow = std::make_shared([&](int fileId, const std::string &fileType){ + m_fileListWindow = std::make_shared(m_api, [&](int fileId, const std::string &fileType){ if (fileType == "blp") { m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer, true); m_blpViewerWindow->loadBlp(std::to_string(fileId)); diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 8256a16ce..a874782c0 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -68,14 +68,6 @@ class StatementHolderAbstract { decltype(FileListDB::makeStorage("")) *u_storage; -template ->...> -constexpr auto const_abs(T const& x) noexcept -{ - return x < 0 ? -x : x; -} - template class StatementHolderA { public: @@ -184,24 +176,29 @@ statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::stri case 2: return std::make_unique>(storage, searchClause, order > 0); case 3: - return std::make_unique>(storage, searchClause, order > 0); + return std::make_unique>(storage, searchClause, order > 0); case 1: default: return std::make_unique>(storage, searchClause, order > 0); } } +enum class EnumParamsChanged { + OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING = 2, SCAN_REPOSITORY = 3 +}; + namespace std { // partial specialization for reference_wrapper // is this really necessary? - template - class hash> { + template + struct hash> { public: - std::size_t operator()(std::reference_wrapper x) const { return std::hash()(x.get()); } + std::size_t operator()(const std::reference_wrapper &x) const { return std::hash()(x.get()); } }; } + template class my_container { // important: this really needs to be a deque and only front @@ -245,13 +242,11 @@ class my_container { -enum class EnumParamsChanged { - OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING -}; + class FileListLambdaInst : public FileListLamda { public: - FileListLambdaInst(std::string &searchClause, int &recordsTotal) : m_recordsTotal(recordsTotal) + FileListLambdaInst(const HApiContainer &api, std::string &searchClause, int &recordsTotal) : m_recordsTotal(recordsTotal), m_api(api) { dbThread = std::thread([&]() { decltype(FileListDB::makeStorage("")) storage = FileListDB::makeStorage("fileList.db3"); @@ -279,6 +274,10 @@ class FileListLambdaInst : public FileListLamda { case EnumParamsChanged::SORTING: statement = statementFactory(storage, searchClause, m_order); break; + + case EnumParamsChanged::SCAN_REPOSITORY: + scanRepository(); + break; } std::vector results; @@ -335,13 +334,20 @@ class FileListLambdaInst : public FileListLamda { m_order = order; stateChangeAwaiter.pushInput(EnumParamsChanged::SORTING); } + void scanFiles() override { + stateChangeAwaiter.pushInput(EnumParamsChanged::SCAN_REPOSITORY); + } + int getCurrentScanningProgress() { return m_currentScanningProgress;} + int getAmountOfFilesInRep() { return m_filesInRepository;} private: - void setResults(const std::vector &results) { std::unique_lock lock(resultsChange); m_results = results; } + void scanRepository() { +// m_api->requestProcessor + } private: std::mutex paramsChange; @@ -350,9 +356,14 @@ class FileListLambdaInst : public FileListLamda { std::thread dbThread; bool m_isTerminating = false; + const HApiContainer m_api; + int &m_recordsTotal; int m_order = 1; + int m_currentScanningProgress = -1; + int m_filesInRepository = -1; + std::vector m_results; std::vector m_requests; @@ -363,11 +374,11 @@ class FileListLambdaInst : public FileListLamda { // FileListWindow // ------------------------------------- -FileListWindow::FileListWindow(const std::function &fileOpenCallback) : m_fileOpenCallback(fileOpenCallback) { +FileListWindow::FileListWindow(const HApiContainer &api, const std::function &fileOpenCallback) : m_api(api), m_fileOpenCallback(fileOpenCallback) { m_filesTotal = 0; m_showWindow = true; - selectStatement = std::make_unique(filterTextStr, m_filesTotal); + selectStatement = std::make_unique(api, filterTextStr, m_filesTotal); } bool FileListWindow::draw() { diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index 79f7a2141..b0266c416 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -35,12 +35,13 @@ class FileListLamda { virtual void makeRequest(const std::vector ¶msChange) = 0; virtual void searchChanged() = 0; virtual void setOrder(int order) = 0; + virtual void scanFiles() = 0; virtual const std::vector getResults() = 0; }; class FileListWindow { public: - FileListWindow(const std::function &fileOpenCallback); + FileListWindow(const HApiContainer &api, const std::function &fileOpenCallback); bool draw(); private: @@ -49,6 +50,7 @@ class FileListWindow { std::function m_fileOpenCallback; int m_filesTotal; + const HApiContainer m_api; std::unique_ptr selectStatement; std::array filterText = {0}; std::string filterTextStr = "%%"; diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl new file mode 100644 index 000000000..9a873a346 --- /dev/null +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -0,0 +1,151 @@ +#ifndef COMMON_ADT_MATERIAL +#define COMMON_ADT_MATERIAL + +//------------------- +// Vertex part +//------------------- + +float fixADTUVBorder(float uvComp, float x) { + const float alphaTextureSize_px = 1024.0; + const float subPixel = 0.5 / alphaTextureSize_px; + + float epsilon = 0.0001; + + if (x < epsilon) + uvComp += subPixel; + if ((1.0 - x) < epsilon) + uvComp -= subPixel; + + return uvComp ; +} + +const float TILESIZE = (1600.0 / 3.0); +const float CHUNKSIZE = TILESIZE / 16.0; +const float UNITSIZE = CHUNKSIZE / 8.0; + +void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords, out vec2 chunkCoords) { + float iX = mod(indexInMCNK, 17.0); + float iY = floor(indexInMCNK/17.0); + + if (iX > 8.01) { + iY = iY + 0.5; + iX = iX - 8.5; + } + + vec2 worldPoint_xy = vec2( + adtMCNKPos.x - iY * UNITSIZE, + adtMCNKPos.y - iX * UNITSIZE + ); + + // Top left point (17058 17063) becomes (0,0) + vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - adtMCNKPos.yx; + // Add half chunk to do little offset before doing floor in next step + coordsInAdtIndexSpace += vec2(CHUNKSIZE/2.0); + + vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); + + + chunkCoords = vec2(iX, iY); + + alphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - worldPoint_xy.yx) / TILESIZE; + alphaCoords.x = fixADTUVBorder(alphaCoords.x, chunkCoords.x/8.0); + alphaCoords.y = fixADTUVBorder(alphaCoords.y, chunkCoords.y/8.0); +} + + +//------------------- +// Fragment part +//------------------- + +const vec2 s_texDir[8] = { + {-1.0, 0.0}, + {-1.0, 1.0}, + {0.0, 1.0}, + {1.0, 1.0}, + {1.0, 0.0}, + {1.0, -1.0}, + {0.0, -1.0}, + {-1.0, -1.0} +}; +const float s_tempTexSpeed[8] = {64.0, 48.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0}; + +float fmod1(float x, float y) { + return x - (y * trunc(x/y)); +} + +vec2 transformADTUV(in vec2 uv, in int layer, in float sceneTime, in ivec4 animation_rotationPerLayer, in ivec4 animation_speedPerLayer, in vec4 scaleFactorPerLayer) { + vec2 translate = vec2(0.0); + int animation_rotation = animation_rotationPerLayer[layer]; + if (animation_rotation >= 0 && animation_rotation < 8) { + vec2 transVector = s_texDir[animation_rotation] * (sceneTime * 0.001); + transVector.xy = transVector.yx; //why? + transVector.x = fmod1(transVector.x, 64); + transVector.y = fmod1(transVector.y, 64); + + translate = transVector * + (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[animation_speedPerLayer[layer]])); + } + return (uv * scaleFactorPerLayer[layer]) + translate; +} + +void calcADTOrigFragMaterial( + in vec2 tcLayer0, in vec2 tcLayer1, in vec2 tcLayer2, in vec2 tcLayer3, + in sampler2D t_Layer0, in sampler2D t_Layer1, in sampler2D t_Layer2, in sampler2D t_Layer3, + in vec2 tcAlpha, + in sampler2D t_alphaTex, + + out vec4 matDiffuse +) { + vec3 alphaBlend = texture( t_alphaTex, tcAlpha).rgb; + + vec4 tex1 = texture(t_Layer0, tcLayer0).rgba; + vec4 tex2 = texture(t_Layer1, tcLayer1).rgba; + vec4 tex3 = texture(t_Layer2, tcLayer2).rgba; + vec4 tex4 = texture(t_Layer2, tcLayer3).rgba; + + matDiffuse = mix(mix(mix(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); +} + +void calcADTHeightFragMaterial( + in vec2 tcLayer0, in vec2 tcLayer1, in vec2 tcLayer2, in vec2 tcLayer3, + in sampler2D t_Layer0, in sampler2D t_Layer1, in sampler2D t_Layer2, in sampler2D t_Layer3, + in sampler2D t_LayerHeight0, in sampler2D t_LayerHeight1, in sampler2D t_LayerHeight2, in sampler2D t_LayerHeight3, + in vec2 tcAlpha, + in sampler2D t_alphaTex, + vec4 heightOffset, + vec4 heightScale, + + out vec4 matDiffuse +) { + vec3 alphaBlend = texture( t_alphaTex, tcAlpha).rgb; + + float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); + vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); + float weightedTexture_x = (minusAlphaBlendSum * ((texture(t_LayerHeight0, tcLayer0).w * heightScale[0]) + heightOffset[0])); + float weightedTexture_y = (weightsVector.y * ((texture(t_LayerHeight1, tcLayer1).w * heightScale[1]) + heightOffset[1])); + float weightedTexture_z = (weightsVector.z * ((texture(t_LayerHeight2, tcLayer2).w * heightScale[2]) + heightOffset[2])); + float weightedTexture_w = (weightsVector.w * ((texture(t_LayerHeight3, tcLayer3).w * heightScale[3]) + heightOffset[3])); + vec4 weights = vec4(weightedTexture_x, weightedTexture_y, weightedTexture_z, weightedTexture_w); + vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); + vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); + + vec4 weightedLayer_0 = (texture(t_Layer0, tcLayer0) * weightsNormalized.x); + vec3 matDiffuse_0 = weightedLayer_0.xyz; + float specBlend_0 = weightedLayer_0.w; + + vec4 weightedLayer_1 = (texture(t_Layer1, tcLayer1) * weightsNormalized.y); + vec3 matDiffuse_1 = (matDiffuse_0 + weightedLayer_1.xyz); + float specBlend_1 = (specBlend_0 + weightedLayer_1.w); + + vec4 weightedLayer_2 = (texture(t_Layer2, tcLayer2) * weightsNormalized.z); + vec3 matDiffuse_2 = (matDiffuse_1 + weightedLayer_2.xyz); + float specBlend_2 = (specBlend_1 + weightedLayer_2.w); + + vec4 weightedLayer_3 = (texture(t_Layer3, tcLayer3) * weightsNormalized.w); + vec3 matDiffuse_3 = (matDiffuse_2 + weightedLayer_3.xyz); + float specBlend_3 = (specBlend_2 + weightedLayer_3.w); + + matDiffuse = vec4(matDiffuse_3, specBlend_3); +} + +#endif \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 073c035b5..8694ac3e1 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -7,6 +7,7 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonADTMaterial.glsl" layout(location = 0) in vec2 vChunkCoords; layout(location = 1) in vec3 vPosition; @@ -48,95 +49,39 @@ const InteriorLightParam intLight = { vec4(0,0,0,1) }; -vec4 mixTextures(vec4 tex0, vec4 tex1, float alpha) { - return (alpha*(tex1-tex0)+tex0); -} - -const vec2 s_texDir[8] = { - {-1.0, 0.0}, - {-1.0, 1.0}, - {0.0, 1.0}, - {1.0, 1.0}, - {1.0, 0.0}, - {1.0, -1.0}, - {0.0, -1.0}, - {-1.0, -1.0} -}; -const float s_tempTexSpeed[8] = {64.0, 48.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0}; - -float fmod1(float x, float y) { - return x - (y * trunc(x/y)); -} - -vec2 transformUV(in vec2 uv, in int layer) { - vec2 translate = vec2(0.0); - int animation_rotation = animation_rotationPerLayer[layer]; - if (animation_rotation >= 0 && animation_rotation < 8) { - vec2 transVector = s_texDir[animation_rotation] * (scene.uViewUpSceneTime.w * 0.001); - transVector.xy = transVector.yx; //why? - transVector.x = fmod1(transVector.x, 64); - transVector.y = fmod1(transVector.y, 64); - - translate = - transVector * - (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[animation_speedPerLayer[layer]])); - } - return (uv * scaleFactorPerLayer[layer]) + translate; -} - void main() { vec2 vTexCoord = vChunkCoords; const float threshold = 1.5; - vec2 alphaCoord = vec2(vAlphaCoords); - vec3 alphaBlend = texture( uAlphaTexture, alphaCoord).gba; - - vec2 tcLayer0 = transformUV(vTexCoord, 0); - vec2 tcLayer1 = transformUV(vTexCoord, 1); - vec2 tcLayer2 = transformUV(vTexCoord, 2); - vec2 tcLayer3 = transformUV(vTexCoord, 3); + float sceneTime = scene.uViewUpSceneTime.w; + vec2 tcLayer0 = transformADTUV(vTexCoord, 0, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer1 = transformADTUV(vTexCoord, 1, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer2 = transformADTUV(vTexCoord, 2, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); vec4 final; if (uUseHeightMixFormula.r > 0) { - float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); - vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); - float weightedTexture_x = (minusAlphaBlendSum * ((texture(uLayerHeight0, tcLayer0).w * uHeightScale[0]) + uHeightOffset[0])); - float weightedTexture_y = (weightsVector.y * ((texture(uLayerHeight1, tcLayer1).w * uHeightScale[1]) + uHeightOffset[1])); - float weightedTexture_z = (weightsVector.z * ((texture(uLayerHeight2, tcLayer2).w * uHeightScale[2]) + uHeightOffset[2])); - float weightedTexture_w = (weightsVector.w * ((texture(uLayerHeight3, tcLayer3).w * uHeightScale[3]) + uHeightOffset[3])); - vec4 weights = vec4(weightedTexture_x, weightedTexture_y, weightedTexture_z, weightedTexture_w); - vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); - vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); - - vec4 weightedLayer_0 = (texture(uLayer0, tcLayer0) * weightsNormalized.x); - vec3 matDiffuse_0 = weightedLayer_0.xyz; - float specBlend_0 = weightedLayer_0.w; - - vec4 weightedLayer_1 = (texture(uLayer1, tcLayer1) * weightsNormalized.y); - vec3 matDiffuse_1 = (matDiffuse_0 + weightedLayer_1.xyz); - float specBlend_1 = (specBlend_0 + weightedLayer_1.w); - - vec4 weightedLayer_2 = (texture(uLayer2, tcLayer2) * weightsNormalized.z); - vec3 matDiffuse_2 = (matDiffuse_1 + weightedLayer_2.xyz); - float specBlend_2 = (specBlend_1 + weightedLayer_2.w); - - vec4 weightedLayer_3 = (texture(uLayer3, tcLayer3) * weightsNormalized.w); - vec3 matDiffuse_3 = (matDiffuse_2 + weightedLayer_3.xyz); - float specBlend_3 = (specBlend_2 + weightedLayer_3.w); - - final = vec4(matDiffuse_3, specBlend_3); + calcADTHeightFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + uLayer0, uLayer1, uLayer2, uLayer3, + uLayerHeight0, uLayerHeight1, uLayerHeight2, uLayerHeight3, + vAlphaCoords, + uAlphaTexture, + uHeightOffset, uHeightScale, + final + ); } else { - vec4 tex1 = texture(uLayer0, tcLayer0).rgba; - vec4 tex2 = texture(uLayer1, tcLayer1).rgba; - vec4 tex3 = texture(uLayer2, tcLayer2).rgba; - vec4 tex4 = texture(uLayer3, tcLayer3).rgba; - - final = mixTextures(mixTextures(mixTextures(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + calcADTOrigFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + uLayer0, uLayer1, uLayer2, uLayer3, + vAlphaCoords, + uAlphaTexture, + final + ); } vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; - vec4 finalColor = vec4( calcLight( matDiffuse, diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index 64a12c452..c72509f37 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -7,6 +7,7 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonADTMaterial.glsl" /* vertex shader code */ layout(location = 0) in vec3 aPos; @@ -38,24 +39,6 @@ layout(location = 3) out vec3 vNormal; layout(location = 4) out vec3 vVertexLighting; layout(location = 5) out vec2 vAlphaCoords; -const float TILESIZE = (1600.0 / 3.0); -const float CHUNKSIZE = TILESIZE / 16.0; -const float UNITSIZE = CHUNKSIZE / 8.0; - -float fixUVBorder(float uvComp, float x) { - const float alphaTextureSize_px = 1024.0; - const float subPixel = 0.5 / alphaTextureSize_px; - - float epsilon = 0.0001; - - if (x < epsilon) - uvComp += subPixel; - if ((1.0 - x) < epsilon) - uvComp -= subPixel; - - return uvComp ; -} - void main() { /* @@ -68,44 +51,17 @@ void main() { //Thus, we first need to get vertexNumber within MCNK int indexInMCNK = gl_VertexIndex % (9 * 9 + 8 * 8); - float iX = mod(indexInMCNK, 17.0); - float iY = floor(indexInMCNK/17.0); - - if (iX > 8.01) { - iY = iY + 0.5; - iX = iX - 8.5; - } -// vec4 worldPoint = vec4( -// uPos.x - iY * UNITSIZE, -// uPos.y - iX * UNITSIZE, -// uPos.z + aHeight, -// 1); + calcAdtAlphaUV(indexInMCNK, uPos.xyz, vAlphaCoords, vChunkCoords); + mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); vec4 worldPoint = vec4(aPos, 1); - vChunkCoords = vec2(iX, iY); - - // Top left point (17058 17063) becomes (0,0) - vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - uPos.yx; - // Add half chunk to do little offset before doing floor in next step - coordsInAdtIndexSpace += vec2(CHUNKSIZE/2.0); - - vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); - - vAlphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - aPos.yx) / TILESIZE; - - vAlphaCoords.x = fixUVBorder(vAlphaCoords.x, vChunkCoords.x/8.0); - vAlphaCoords.y = fixUVBorder(vAlphaCoords.y, vChunkCoords.y/8.0); - vPosition = (scene.uLookAtMat * worldPoint).xyz; + vNormal = normal; vColor = aColor; vVertexLighting = aVertexLighting.rgb; - mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); - vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); - - vNormal = normal; gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; - } diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index 70ed78b09..e6bac2524 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -9,6 +9,7 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonADTMaterial.glsl" #include "../common/commonAdtIndirectDescriptorSet.glsl" layout(location = 0) in vec2 vChunkCoords; @@ -23,20 +24,8 @@ layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; -//layout(set=2, binding=5) uniform sampler2D uLayer0; -//layout(set=2, binding=6) uniform sampler2D uLayer1; -//layout(set=2, binding=7) uniform sampler2D uLayer2; -//layout(set=2, binding=8) uniform sampler2D uLayer3; -//layout(set=2, binding=9) uniform sampler2D uAlphaTexture; -//layout(set=2, binding=10) uniform sampler2D uLayerHeight0; -//layout(set=2, binding=11) uniform sampler2D uLayerHeight1; -//layout(set=2, binding=12) uniform sampler2D uLayerHeight2; -//layout(set=2, binding=13) uniform sampler2D uLayerHeight3; - #include "../common/commonUboSceneData.glsl" - - layout(location = 0) out vec4 outColor; const InteriorLightParam intLight = { @@ -44,42 +33,6 @@ const InteriorLightParam intLight = { vec4(0,0,0,1) }; -vec4 mixTextures(vec4 tex0, vec4 tex1, float alpha) { - return (alpha*(tex1-tex0)+tex0); -} - -const vec2 s_texDir[8] = { - {-1.0, 0.0}, - {-1.0, 1.0}, - {0.0, 1.0}, - {1.0, 1.0}, - {1.0, 0.0}, - {1.0, -1.0}, - {0.0, -1.0}, - {-1.0, -1.0} -}; -const float s_tempTexSpeed[8] = {64.0, 48.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0}; - -float fmod1(float x, float y) { - return x - (y * trunc(x/y)); -} - -vec2 transformUV(in vec2 uv, in int layer, in AdtMeshWidePS adtMeshWidePS) { - vec2 translate = vec2(0.0); - int animation_rotation = adtMeshWidePS.animation_rotationPerLayer[layer]; - if (animation_rotation >= 0 && animation_rotation < 8) { - vec2 transVector = s_texDir[animation_rotation] * (scene.uViewUpSceneTime.w * 0.001); - transVector.xy = transVector.yx; //why? - transVector.x = fmod1(transVector.x, 64); - transVector.y = fmod1(transVector.y, 64); - - translate = - transVector * - (1.0f / ((1.0f / -4.1666665f) * s_tempTexSpeed[adtMeshWidePS.animation_speedPerLayer[layer]])); - } - return (uv * adtMeshWidePS.scaleFactorPerLayer[layer]) + translate; -} - void main() { AdtInstanceData adtInstanceData = adtInstanceDatas[nonuniformEXT(meshIndex)]; AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x)]; @@ -89,13 +42,15 @@ void main() { vec2 vTexCoord = vChunkCoords; const float threshold = 1.5; - vec2 alphaCoord = vec2(vAlphaCoords); - vec3 alphaBlend = texture( s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], alphaCoord).rgb; + ivec4 animation_rotationPerLayer = adtMeshWidePS.animation_rotationPerLayer; + ivec4 animation_speedPerLayer = adtMeshWidePS.animation_speedPerLayer; + vec4 scaleFactorPerLayer = adtMeshWidePS.scaleFactorPerLayer; + float sceneTime = scene.uViewUpSceneTime.w; - vec2 tcLayer0 = transformUV(vTexCoord, 0, adtMeshWidePS); - vec2 tcLayer1 = transformUV(vTexCoord, 1, adtMeshWidePS); - vec2 tcLayer2 = transformUV(vTexCoord, 2, adtMeshWidePS); - vec2 tcLayer3 = transformUV(vTexCoord, 3, adtMeshWidePS); + vec2 tcLayer0 = transformADTUV(vTexCoord, 0, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer1 = transformADTUV(vTexCoord, 1, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer2 = transformADTUV(vTexCoord, 2, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); int layerHeight0 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.x; int layerHeight1 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.y; @@ -112,40 +67,26 @@ void main() { vec4 final; if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { - float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); - vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); - float weightedTexture_x = (minusAlphaBlendSum * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight0)], tcLayer0).w * heightScale[0]) + heightOffset[0])); - float weightedTexture_y = (weightsVector.y * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight1)], tcLayer1).w * heightScale[1]) + heightOffset[1])); - float weightedTexture_z = (weightsVector.z * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight2)], tcLayer2).w * heightScale[2]) + heightOffset[2])); - float weightedTexture_w = (weightsVector.w * ((texture(s_LayerHeightTextures[nonuniformEXT(layerHeight3)], tcLayer3).w * heightScale[3]) + heightOffset[3])); - vec4 weights = vec4(weightedTexture_x, weightedTexture_y, weightedTexture_z, weightedTexture_w); - vec4 weights_temp = (weights * (vec4(1.0) - clamp((vec4(max(max(weightedTexture_x, weightedTexture_y), max(weightedTexture_z, weightedTexture_w))) - weights), 0.0, 1.0))); - vec4 weightsNormalized = (weights_temp / vec4(dot(vec4(1.0), weights_temp))); - - vec4 weightedLayer_0 = (texture(s_LayerTextures[nonuniformEXT(txLayer0)], tcLayer0) * weightsNormalized.x); - vec3 matDiffuse_0 = weightedLayer_0.xyz; - float specBlend_0 = weightedLayer_0.w; - - vec4 weightedLayer_1 = (texture(s_LayerTextures[nonuniformEXT(txLayer1)], tcLayer1) * weightsNormalized.y); - vec3 matDiffuse_1 = (matDiffuse_0 + weightedLayer_1.xyz); - float specBlend_1 = (specBlend_0 + weightedLayer_1.w); - - vec4 weightedLayer_2 = (texture(s_LayerTextures[nonuniformEXT(txLayer2)], tcLayer2) * weightsNormalized.z); - vec3 matDiffuse_2 = (matDiffuse_1 + weightedLayer_2.xyz); - float specBlend_2 = (specBlend_1 + weightedLayer_2.w); - - vec4 weightedLayer_3 = (texture(s_LayerTextures[nonuniformEXT(txLayer3)], tcLayer3) * weightsNormalized.w); - vec3 matDiffuse_3 = (matDiffuse_2 + weightedLayer_3.xyz); - float specBlend_3 = (specBlend_2 + weightedLayer_3.w); - - final = vec4(matDiffuse_3, specBlend_3); + calcADTHeightFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + s_LayerHeightTextures[nonuniformEXT(layerHeight0)], s_LayerHeightTextures[nonuniformEXT(layerHeight1)], + s_LayerHeightTextures[nonuniformEXT(layerHeight2)], s_LayerHeightTextures[nonuniformEXT(layerHeight3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + heightOffset, heightScale, + final + ); } else { - vec4 tex1 = texture(s_LayerTextures[nonuniformEXT(txLayer0)], tcLayer0).rgba; - vec4 tex2 = texture(s_LayerTextures[nonuniformEXT(txLayer1)], tcLayer1).rgba; - vec4 tex3 = texture(s_LayerTextures[nonuniformEXT(txLayer2)], tcLayer2).rgba; - vec4 tex4 = texture(s_LayerTextures[nonuniformEXT(txLayer3)], tcLayer3).rgba; - - final = mix(mix(mix(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + calcADTOrigFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + final + ); } vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert index 5d530bcca..d7e736c54 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert @@ -9,6 +9,7 @@ precision highp int; #include "../common/commonLightFunctions.glsl" #include "../common/commonFogFunctions.glsl" +#include "../common/commonADTMaterial.glsl" /* vertex shader code */ layout(location = 0) in vec3 aPos; @@ -36,23 +37,6 @@ layout(location = 4) out vec3 vVertexLighting; layout(location = 5) out vec2 vAlphaCoords; layout(location = 6) out flat int vMeshIndex; -const float TILESIZE = (1600.0 / 3.0); -const float CHUNKSIZE = TILESIZE / 16.0; -const float UNITSIZE = CHUNKSIZE / 8.0; - -float fixUVBorder(float uvComp, float x) { - const float alphaTextureSize_px = 1024.0; - const float subPixel = 0.5 / alphaTextureSize_px; - - float epsilon = 0.0001; - - if (x < epsilon) - uvComp += subPixel; - if ((1.0 - x) < epsilon) - uvComp -= subPixel; - - return uvComp ; -} void main() { AdtInstanceData adtInstanceData = adtInstanceDatas[gl_InstanceIndex]; AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x]; @@ -67,46 +51,18 @@ void main() { //Thus, we first need to get vertexNumber within MCNK int indexInMCNK = (gl_VertexIndex - gl_BaseVertexARB) % (9 * 9 + 8 * 8); - float iX = mod(indexInMCNK, 17.0); - float iY = floor(indexInMCNK/17.0); - - if (iX > 8.01) { - iY = iY + 0.5; - iX = iX - 8.5; - } - // vChunkCoords = vec2(iX, iY); - -// vec4 worldPoint = vec4( -// uPos.x - iY * UNITSIZE, -// uPos.y - iX * UNITSIZE, -// uPos.z + aHeight, -// 1); + calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords); vec4 worldPoint = vec4(aPos, 1); - vChunkCoords = vec2(iX, iY); - - // Top left point (17058 17063) becomes (0,0) - vec2 coordsInAdtIndexSpace = 32.0f * TILESIZE - adtMeshWideVSPS.uPos.yx; - // Add half chunk to do little offset before doing floor in next step - coordsInAdtIndexSpace += vec2(CHUNKSIZE/2.0); - - vec2 ADTIndex = floor(coordsInAdtIndexSpace / TILESIZE); - - vAlphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - aPos.yx) / TILESIZE; - - vAlphaCoords.x = fixUVBorder(vAlphaCoords.x, vChunkCoords.x/8.0); - vAlphaCoords.y = fixUVBorder(vAlphaCoords.y, vChunkCoords.y/8.0); + mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); vPosition = (scene.uLookAtMat * worldPoint).xyz; + vNormal = normal; vColor = aColor; vVertexLighting = aVertexLighting.rgb; vMeshIndex = gl_InstanceIndex; - mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); - vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); - - vNormal = normal; gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; - } diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index ed40b22bf..34e735f19 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -546,14 +546,12 @@ void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MP if (fill) { uint8_t alphaVal = *alphaArray++; - for (int k = 0; k < n && readForThisLayer < 64; k++) { + for (int k = 0; k < n && readForThisLayer < 64; k++, readForThisLayer++) { *currentLayer++ = alphaVal; - readForThisLayer++; } } else { - for (int k = 0; k < n && readForThisLayer < 64; k++) { + for (int k = 0; k < n && readForThisLayer < 64; k++, readForThisLayer++) { *currentLayer++ = *alphaArray++; - readForThisLayer++; } } } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 258d00f96..0a59d9f87 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -475,9 +475,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,0}, }, { - {3,0, "s_AlphaTextures"}, - {4,0, "s_LayerHeightTextures"}, {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { @@ -1245,8 +1245,8 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {1,1,48}, {0,0,544}, + {1,1,48}, {1,0,64}, }, { @@ -1264,15 +1264,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,4, "uAlphaTexture"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, {2,0, "uLayer0"}, {2,1, "uLayer1"}, {2,2, "uLayer2"}, {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { @@ -2734,6 +2734,10 @@ const std::unordered_map Date: Thu, 14 Dec 2023 21:44:11 +0200 Subject: [PATCH 160/212] - very strange experiments to gain performance part 1 --- .../fileListWindow/FileListWindow.cpp | 26 +- .../3rdparty/arena-allocator/arena_alloc.cc | 250 ++ .../3rdparty/arena-allocator/arena_alloc.hh | 268 ++ wowViewerLib/CMakeLists.txt | 14 +- .../glsl/common/commonADTMaterial.glsl | 1 - .../algorithms/mathHelper_culling_sse.h | 2 + wowViewerLib/src/engine/cache/cache.h | 5 +- .../FrameBasedHeapAllocator.cpp | 127 + .../FrameBasedHeapAllocator.h | 82 + .../FrameBasedStackAllocator.cpp | 127 + .../FrameBasedStackAllocator.h | 82 + .../src/engine/objects/SceneObjectWithID.h | 19 + .../src/engine/objects/adt/adtObject.cpp | 12 +- .../src/engine/objects/adt/adtObject.h | 18 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 21 +- .../objects/scenes/EntityActorsFactory.cpp | 5 + .../objects/scenes/EntityActorsFactory.h | 32 + .../src/engine/objects/scenes/map.cpp | 6 +- .../src/engine/objects/wmo/wmoGroupObject.h | 16 +- .../src/engine/objects/wmo/wmoObject.cpp | 9 +- .../src/engine/objects/wmo/wmoObject.h | 35 +- .../src/engine/persistance/adtFile.cpp | 2 +- wowViewerLib/src/engine/persistance/adtFile.h | 2 +- .../engine/persistance/header/adtFileHeader.h | 4 +- .../src/engine/shader/ShaderDefinitions.h | 1284 +++++---- wowViewerLib/src/gapi/interface/IDevice.h | 4 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 3 +- .../CommandBufferRecorder.cpp | 52 +- .../vulkan/descriptorSets/GDescriptorSet.cpp | 12 +- .../vulkan/descriptorSets/GDescriptorSet.h | 15 +- .../bindless/BindlessTextureHolder.h | 3 +- .../src/gapi/vulkan/utils/MutexLockedVector.h | 6 +- .../src/renderer/mapScene/MapSceneRenderer.h | 6 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 21 +- .../vulkan/MapSceneRenderVisBufferVLK.h | 10 +- wowViewerLib/src/robin_hood.h | 2544 +++++++++++++++++ 36 files changed, 4400 insertions(+), 725 deletions(-) create mode 100644 wowViewerLib/3rdparty/arena-allocator/arena_alloc.cc create mode 100644 wowViewerLib/3rdparty/arena-allocator/arena_alloc.hh create mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp create mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h create mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp create mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h create mode 100644 wowViewerLib/src/engine/objects/SceneObjectWithID.h create mode 100644 wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp create mode 100644 wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h create mode 100644 wowViewerLib/src/robin_hood.h diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index a874782c0..902e21636 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -187,16 +187,16 @@ enum class EnumParamsChanged { OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING = 2, SCAN_REPOSITORY = 3 }; -namespace std { - -// partial specialization for reference_wrapper -// is this really necessary? - template - struct hash> { - public: - std::size_t operator()(const std::reference_wrapper &x) const { return std::hash()(x.get()); } - }; -} +//namespace std { +// +//// partial specialization for reference_wrapper +//// is this really necessary? +// template +// struct hash> { +// public: +// std::size_t operator()(const std::reference_wrapper &x) const { return std::hash()(x.get()); } +// }; +//} template @@ -204,8 +204,6 @@ class my_container { // important: this really needs to be a deque and only front // insertion/deletion is allowed to not get dangling references typedef std::deque storage; - typedef std::reference_wrapper c_ref_w; - typedef std::reference_wrapper ref_w; public: typedef typename storage::value_type value_type; typedef typename storage::reference reference; @@ -216,7 +214,7 @@ class my_container { // no move semantics void push_back(const T& t) { - auto it = lookup_.find(std::cref(t)); + auto it = lookup_.find(t); if(it != end(lookup_)) { // is already inserted report error return; @@ -235,7 +233,7 @@ class my_container { void pop_front() { lookup_.erase(store_.front()); store_.pop_front(); } private: // look-up mechanism - std::unordered_set lookup_ = std::unordered_set(); + std::unordered_set lookup_ = std::unordered_set(); // underlying storage storage store_; }; diff --git a/wowViewerLib/3rdparty/arena-allocator/arena_alloc.cc b/wowViewerLib/3rdparty/arena-allocator/arena_alloc.cc new file mode 100644 index 000000000..cb09ee67d --- /dev/null +++ b/wowViewerLib/3rdparty/arena-allocator/arena_alloc.cc @@ -0,0 +1,250 @@ +#include "arena_alloc.hh" +#include +#include +#include +#include +#include +#ifdef _WIN32 +#define WIN32_MEAN_AND_LEAN +#define NOMINMAX +#include +#else +#include +#endif + +namespace arena +{ +namespace detail +{ + +#ifdef _WIN32 + +static inline char * +allocate_memory (std::size_t n) +{ +// void *p = VirtualAlloc (NULL, n, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + void *p = new char[n]; + if (!p) + { + std::perror (("arena: VirtualAlloc failed: " + std::to_string(GetLastError())) .c_str()); + exit (1); + } + return reinterpret_cast (p); +} + +static inline void +deallocate_memory (char *p, [[maybe_unused]] std::size_t n) +{ +// if (!VirtualFree (reinterpret_cast (p), 0, MEM_RELEASE)) +// { +// std::perror ("arena: VirtualFree failed"); +// exit (1); +// } + delete[](p); +} + +#else + +static inline char * +allocate_memory (std::size_t n) +{ + void *p = mmap (NULL, n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + if (p == reinterpret_cast (-1LL)) + { + std::perror ("arena: mmap failed"); + exit (1); + } + return reinterpret_cast (p); +} + +static inline void +deallocate_memory (char *p, std::size_t n) +{ + if (munmap (reinterpret_cast (p), n)) + { + std::perror ("arena: munmap failed"); + exit (1); + } +} + +#endif + +struct Region +{ + enum : std::size_t { S_capacity = 16384 }; + + Region (std::size_t min_cap) + : M_capacity (std::max (static_cast (S_capacity), min_cap)) + , M_data (allocate_memory (M_capacity)) + , M_size (0) + , M_ref_count (0) + {} + + void destruct () { deallocate_memory (M_data, M_capacity); } + + char * data () { return M_data; } + char * top () { return M_data + M_size; } + char * end () { return M_data + M_capacity; } + void resize (std::ptrdiff_t diff) { M_size += diff; } + void clear () { M_size = 0; } + void ref () { ++M_ref_count; } + void unref () { --M_ref_count; } + bool unused () const { return M_ref_count == 0; } + +private: + const std::size_t M_capacity; + char *M_data; + std::size_t M_size; + unsigned M_ref_count; +}; + +using region_list = std::vector; +using region_iterator = region_list::iterator; + +static region_list *S_regions {}; + +static struct RegionDeleter +{ + RegionDeleter () + { + S_regions = new region_list (); + S_regions->reserve (4); + } + + ~RegionDeleter () + { + for (auto &r : *S_regions) + r.destruct (); + delete S_regions; + S_regions = nullptr; + } +} const S_region_deleter {}; + +static std::mutex S_mutex {}; + +Lock::Lock () +{ + S_mutex.lock (); +} + +Lock::~Lock () +{ + S_mutex.unlock (); +} + +static region_iterator +find_region_containing (const char *p) +{ + const auto end = S_regions->end (); + for (auto it = S_regions->begin (); it != end; ++it) + { + if (p >= it->data () && p < it->top ()) + return it; + } + return end; +} + +static inline std::ptrdiff_t +alignment_offset (const char *ptr, std::size_t alignment) +{ + const auto off = alignment - reinterpret_cast (ptr) % alignment; + return off == alignment ? 0 : off; +} + +static inline bool +fits (const region_iterator region, std::size_t n, std::size_t alignment) +{ + n += alignment_offset (region->top (), alignment); + return region->top () + n < region->end (); +} + +static region_iterator +find_region_fitting (std::size_t n, std::size_t alignment, const char *hint) +{ + const auto end = S_regions->end (); + region_iterator it; + + if (hint) + { + it = find_region_containing (hint); + if ((it != end) && fits (it, n, alignment)) + return it; + } + + for (it = S_regions->begin (); it != end; ++it) + { + if (fits (it, n, alignment)) + return it; + } + return end; +} + +char * +allocate (std::size_t n, std::size_t alignment, const char *hint) +{ + auto it = find_region_fitting (n, alignment, hint); + if (it == S_regions->end ()) + { + S_regions->emplace_back (n); + it = std::prev (S_regions->end ()); + } + it->resize (alignment_offset (it->top (), alignment)); + const auto r = it->top (); + it->resize (n); + it->ref (); + return r; +} + +void +deallocate (char *p, std::size_t n) +{ + if (S_regions == nullptr) + return; + const auto it = find_region_containing (p); + if (it == S_regions->end ()) + return; + it->unref (); + if (it->unused ()) + it->clear (); + else if (it->top () - n == p) + it->resize (0ll - n); +} + +char * +reallocate (char *p, std::size_t from_n, std::size_t to_n, + std::size_t alignment, const char *hint) +{ + if (p == nullptr) + return allocate (to_n, alignment, hint); + const auto it = find_region_containing (p); + if (it == S_regions->end ()) + return nullptr; + if (to_n == 0) + { + deallocate (p, from_n); + return nullptr; + } + const std::ptrdiff_t diff = to_n - from_n; + if (it->top () - from_n == p && it->top () + diff < it->end ()) + { + it->resize (diff); + return p; + } + if (to_n <= from_n) + return p; + char *const new_p = allocate (to_n, alignment, hint); + std::memcpy (new_p, p, from_n); + deallocate (p, from_n); + return new_p; +} + +std::size_t +default_region_size () +{ + return Region::S_capacity; +} + +} // namespace detail + +} // namespace arena diff --git a/wowViewerLib/3rdparty/arena-allocator/arena_alloc.hh b/wowViewerLib/3rdparty/arena-allocator/arena_alloc.hh new file mode 100644 index 000000000..5fd8b3e58 --- /dev/null +++ b/wowViewerLib/3rdparty/arena-allocator/arena_alloc.hh @@ -0,0 +1,268 @@ +#ifndef ARENA_ALLOC_HH +#define ARENA_ALLOC_HH +#include +#include + +namespace arena +{ +namespace detail +{ +struct Lock +{ + Lock (); + ~Lock (); +}; +char * allocate (std::size_t n, std::size_t alignment, const char *hint); +void deallocate (char *p, std::size_t n); +char * reallocate (char *p, std::size_t from_n, std::size_t to_n, + std::size_t alignment, const char *hint); +std::size_t default_region_size (); +} + +/** + * A region-based allocator wrapping ‘std::allocator’. + * + * The allocator is stateless, that is, all instances of the given allocator + * are interchangeable, compare equal and can deallocate memory allocated by + * any other instance of the same allocator type. + * + * The allocator satisfies allocator completeness requirements. + */ +template +struct Allocator +{ + using value_type = T; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + Allocator () { } + template Allocator (const Allocator &) { } + + /** + * @brief allocates uninitialized storage + * + * The pointer ‘hint’ may be used to provide locality of reference: the + * allocator, if possible, will place the new allocation in the same + * region as ‘hint’. + * + * If ‘n’ is zero, a null pointer is returned. + * + * @param n - the number of objects to allocate storage for + * @param hint - pointer to a nearby memory location + * @return Pointer to the first element of an array of ‘n’ objects of type ‘T’ + * whose elements have not been constructed yet + */ + [[nodiscard]] T * + allocate (std::size_t n, const T *hint = nullptr) + { + if (n == 0) + return nullptr; + const detail::Lock lock {}; + return (reinterpret_cast + (detail::allocate (n * sizeof (T), alignof (T), + reinterpret_cast (hint)))); + } + + /** + * @brief deallocates storage + * + * If ‘p’ is a null pointer, no action occurrs. + * + * @param p - pointer obtained from the allocator + * @param n - number of objects allocated + */ + void + deallocate (T *p, std::size_t n) + { + if (p == nullptr) + return; + const detail::Lock lock {}; + detail::deallocate (reinterpret_cast (p), n * sizeof (T)); + } + + /** + * @brief expands or shrinks previously allocated storage + * + * Reallocats the given allocation. + * + * The reallocation is done by either: + * a) expanding or contracting the existing allocation pointed to by ‘p’, + * if possible. The contents of the array remain unchanged up to the + * lesser of the new and old sizes. If the allocation is expanded, the + * contents of the new part of the array are undefined. + * b) doing nothing, if the new size is less than or equal to the old size. + * c) allocating a new array that can hold ‘to_n’ objects, copying ‘from_n’ + * objects, and deallocating the old allocation. + * + * If ‘p’ is a null pointer, the behavior is the same as calling + * ‘allocate (to_n, hint)’. + * + * If ‘to_n’ is zero, a null pointer is returned. + * + * The pointer ‘hint’ may be used to provide locality reference, if a new + * allocation occurrs: the allocator, if possible, will place the new + * allocation in the same region as ‘hint’. + * + * @param p - pointer obtained from the allocator + * @param from_n - number of object allocated + * @param to_n - number of objects to allocate storage for + * @param hint - pointer to a nearby memory location + * @return Pointer to the first element of an array of ‘to_nn’ objects of + * type ‘T’. The lesser of ‘from_n’ and ‘to_n’ objects are + * initialized, the rest are not yet constructed. The returned + * pointer must be deallocated with @ref deallocate(), the original + * pointer is invalidated and should no longer be used (even if + * reallocation was in-place). + */ + [[nodiscard]] T * + reallocate (T *p, std::size_t from_n, std::size_t to_n, const T *hint = nullptr) + { + const detail::Lock lock {}; + return (reinterpret_cast + (detail::reallocate (reinterpret_cast (p), + from_n * sizeof (T), to_n * sizeof (T), + alignof (T), + reinterpret_cast (hint)))); + } + +}; + +template +inline bool +operator== (const Allocator &, const Allocator &) +{ return true; } + +template +inline bool +operator!= (const Allocator &, const Allocator &) +{ return false; } + +} + +#endif // !ARENA_ALLOC_HH + +namespace arena +{ + +#if ((defined (_GLIBCXX_STRING) \ + || defined (_LIBCPP_STRING) \ + || defined (_STRING_)) \ + && !defined (ARENA_HAS_STRING_DEF)) +#define ARENA_HAS_STRING_DEF +template > +using basic_string = std::basic_string>; +using string = basic_string; +using wstring = basic_string; +#if __cplusplus >= 202002L +using u8string = basic_string; +#endif +using u16string = basic_string; +using u32string = basic_string; +#endif + +#if ((defined (_GLIBCXX_SSTREAM) \ + || defined (_LIBCPP_SSTREAM) \ + || defined (_SSTREAM_)) \ + && !defined (ARENA_HAS_SSTREAM_DEF)) +#define ARENA_HAS_SSTREAM_DEF +template > +using basic_stringstream = std::basic_stringstream>; +using stringstream = basic_stringstream; +using wstringstream = basic_stringstream; +// non-standard: +#if __cplusplus >= 202002L +using u8stringstream = basic_stringstream; +#endif +using u16stringstream = basic_stringstream; +using u32stringstream = basic_stringstream; +#endif + +#if ((defined (_GLIBCXX_DEQUE) \ + || defined (_LIBCPP_DEQUE) \ + || defined (_DEQUE_)) \ + && !defined (ARENA_HAS_DEQUE_DEF)) +#define ARENA_HAS_DEQUE_DEF +template +using deque = std::deque>; +#endif + +#if ((defined (_GLIBCXX_VECTOR) \ + || defined (_LIBCPP_VECTOR) \ + || defined (_VECTOR_)) \ + && !defined (ARENA_HAS_VECTOR_DEF)) +#define ARENA_HAS_VECTOR_DEF +template +using vector = std::vector>; +#endif + +#if ((defined (_GLIBCXX_FORWARD_LIST) \ + || defined (_LIBCPP_FORWARD_LIST) \ + || defined (_FORWARD_LIST_)) \ + && !defined (ARENA_HAS_FORWARD_LIST_DEF)) +#define ARENA_HAS_FORWARD_LIST_DEF +template +using forward_list = std::forward_list>; +#endif + +#if ((defined (_GLIBCXX_LIST) \ + || defined (_LIBCPP_LIST) \ + || defined (_LIST_)) \ + && !defined (ARENA_HAS_LIST_DEF)) +#define ARENA_HAS_LIST_DEF +template +using list = std::list>; +#endif + +#if ((defined (_GLIBCXX_SET) \ + || defined (_LIBCPP_SET) \ + || defined (_SET_)) \ + && !defined (ARENA_HAS_SET_DEF)) +#define ARENA_HAS_SET_DEF +template > +using set = std::set>; + +template > +using multiset = std::multiset>; +#endif + +#if ((defined (_GLIBCXX_MAP) \ + || defined (_LIBCPP_MAP) \ + || defined (_MAP_)) \ + && !defined (ARENA_HAS_MAP_DEF)) +#define ARENA_HAS_MAP_DEF +template > +using map = std::map>>; + +template > +using multimap = std::multimap>>; +#endif + +#if ((defined (_GLIBCXX_UNORDERED_SET)\ + || defined (_LIBCPP_UNORDERED_SET) \ + || defined (_UNORDERED_SET_)) \ + && !defined (ARENA_HAS_UNORDERED_SET_DEF)) +#define ARENA_HAS_UNORDERED_SET_DEF +template , class TEqual = std::equal_to> +using unordered_set = std::unordered_set>; + +template , class TEqual = std::equal_to> +using unordered_multiset = std::unordered_multiset>; +#endif + +#if ((defined (_GLIBCXX_UNORDERED_MAP) \ + || defined (_LIBCPP_UNORDERED_MAP) \ + || defined (_UNORDERED_MAP_)) \ + && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) +#define ARENA_HAS_UNORDERED_MAP_DEF +template , class KeyEqual = std::equal_to> +using unordered_map = std::unordered_map>>; + +template , class KeyEqual = std::equal_to> +using unordered_multimap = std::unordered_multimap>>; +#endif + +} + diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 7c0b8ed9e..ec50bf5c3 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -358,8 +358,18 @@ set(SOURCE_FILES src/renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h src/engine/objects/liquid/LiquidInstance.cpp src/engine/objects/liquid/LiquidInstance.h - src/engine/objects/liquid/LiquidDataGetters.h src/renderer/frame/FrameProfile.h src/gapi/interface/buffers/IBufferVersioned.h - src/renderer/mapScene/materials/BindlessTexture.h) + src/engine/objects/liquid/LiquidDataGetters.h + src/renderer/frame/FrameProfile.h src/gapi/interface/buffers/IBufferVersioned.h + src/renderer/mapScene/materials/BindlessTexture.h + src/engine/objects/scenes/EntityActorsFactory.cpp + src/engine/objects/scenes/EntityActorsFactory.cpp + src/engine/objects/scenes/EntityActorsFactory.h + 3rdparty/arena-allocator/arena_alloc.cc + src/engine/objects/SceneObjectWithID.h + src/engine/custom_allocators/FrameBasedStackAllocator.cpp + src/engine/custom_allocators/FrameBasedStackAllocator.h + src/engine/custom_allocators/FrameBasedHeapAllocator.cpp + src/engine/custom_allocators/FrameBasedHeapAllocator.h) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl index 9a873a346..d0170d1f2 100644 --- a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -52,7 +52,6 @@ void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords alphaCoords.y = fixADTUVBorder(alphaCoords.y, chunkCoords.y/8.0); } - //------------------- // Fragment part //------------------- diff --git a/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h b/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h index b9d89bf78..4a3171de4 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h @@ -6,6 +6,8 @@ #define AWEBWOWVIEWERCPP_MATHHELPER_CULLING_SSE_H #include "mathHelper.h" +#include "../custom_allocators/FrameBasedStackAllocator.h" + #if (__AVX__ && __SSE2__) #include #include diff --git a/wowViewerLib/src/engine/cache/cache.h b/wowViewerLib/src/engine/cache/cache.h index 8be8b8645..b567ec41c 100644 --- a/wowViewerLib/src/engine/cache/cache.h +++ b/wowViewerLib/src/engine/cache/cache.h @@ -19,6 +19,7 @@ #include "../stringTrim.h" #include "../../include/iostuff.h" #include "../../include/sharedFile.h" +#include "../../robin_hood.h" struct FileCacheRecord { std::string fileName; @@ -35,8 +36,8 @@ class Cache { std::mutex cacheMapMutex; std::mutex getFileMutex; - std::unordered_map> m_cache; - std::unordered_map> m_cacheFdid; + robin_hood::unordered_flat_map> m_cache; + robin_hood::unordered_flat_map> m_cacheFdid; public: Cache(IFileRequest *fileRequestProcessor, CacheHolderType holderType) : m_fileRequestProcessor(fileRequestProcessor), holderType(holderType){ } diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp new file mode 100644 index 000000000..c23f6a366 --- /dev/null +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp @@ -0,0 +1,127 @@ +// +// Created by Deamon on 12/13/2023. +// + +#include "FrameBasedHeapAllocator.h" +#include +#include +#include + +#include "../../gapi/interface/IDevice.h" +#include +#include + +class FrameHeapRegion { +public: + FrameHeapRegion(size_t size) : m_buffer(size) { + + } + inline int currentAllocationNumber() { return m_currentAllocations; } + + void *allocate(size_t allocSize) { + int offset = atomic_fetch_add(&m_topIndex, allocSize); + if ((offset + allocSize) > m_buffer.size()) { + return nullptr; + } + m_currentAllocations++; + + return &m_buffer[offset]; + } + int getCurrentSize() { return m_buffer.size();} + + bool isThisRegion(void *ptr) { + int index = (uintptr_t)ptr - (uintptr_t)m_buffer.data(); + + return (index > 0) && (index < m_buffer.size()); + } + void deallocate(void *ptr) { + if (!this->isThisRegion(ptr)) { + return; + } + + m_currentAllocations--; + + int index = ((uintptr_t)ptr - (uintptr_t)m_buffer.data()); + int prev_value = m_topIndex; + while(prev_value > index && + !m_topIndex.compare_exchange_weak(prev_value, index)) + {} + } + +private: + std::vector m_buffer; + std::atomic m_topIndex = 0; + std::atomic m_currentAllocations = 0; +}; + + +std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> g_frameHeapList; +//std::array frames; + +static inline uint8_t BitScanMSB2(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} + +void * frameAllocate(size_t size) { + auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto ¤t_list = g_frameHeapList[currentFrame]; + + auto &frameRegion = current_list.back(); + void *ptr = nullptr; + int regionSize = 2048; + if (frameRegion) { + ptr = frameRegion->allocate(size); + regionSize = frameRegion->getCurrentSize(); + } + if (ptr == nullptr) { + size_t currentBufferSize = regionSize; + size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); + + current_list.push_back(std::make_unique(newSize)); + + ptr = current_list.back()->allocate(size); + } + if (ptr == nullptr) { + std::cout << "oops!!!" << std::endl; + } + + return ptr; +} +void frameDeAllocate(void *ptr) { +// auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; +// auto ¤t_list = frames[currentFrame]; + + for (auto &frameList : g_frameHeapList) { + for (auto it = frameList.begin(); it != frameList.end(); ++it) { + auto ®ion = (*it); + if (region->isThisRegion(ptr)) { + region->deallocate(ptr); + + if (region->currentAllocationNumber() == 0) + frameList.erase(it); + + return; + } + } + } + + std::cout << "failed to deallocate" << std::endl; +}; \ No newline at end of file diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h new file mode 100644 index 000000000..26b53204e --- /dev/null +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h @@ -0,0 +1,82 @@ +// +// Created by Deamon on 12/13/2023. +// + +#ifndef AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H +#define AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H + +#undef max + +#include +#include +#include + +void * frameAllocate(size_t); +void frameDeAllocate(void *); + +template +struct FrameBasedHeapAllocator +{ + typedef T value_type; + + FrameBasedHeapAllocator() = default; + + template + constexpr FrameBasedHeapAllocator(const FrameBasedHeapAllocator &) noexcept {} + + [[nodiscard]] T* allocate(std::size_t n) + { + if (n > (std::numeric_limits::max() / sizeof(T))) + throw std::bad_array_new_length(); + + + if (auto p = static_cast(frameAllocate(n * sizeof(T)))) + { +// report(p, n); + return p; + } + + return nullptr; + } + + void deallocate(T* p, std::size_t n) noexcept + { +// report(p, n, 0); + frameDeAllocate(p); + } +private: +// void report(T* p, std::size_t n, bool alloc = true) const +// { +// std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n +// << " bytes at " << std::hex << std::showbase +// << reinterpret_cast(p) << std::dec << '\n'; +// } +}; + +template +bool operator==(const FrameBasedHeapAllocator &, const FrameBasedHeapAllocator &) { return true; } + +template +bool operator!=(const FrameBasedHeapAllocator &, const FrameBasedHeapAllocator &) { return false; } + +namespace framebased { + +#if ((defined (_GLIBCXX_VECTOR) \ + || defined (_LIBCPP_VECTOR) \ + || defined (_VECTOR_))) + #define ARENA_HAS_VECTOR_DEF + template + using vector = std::vector>; +#endif + +#if ((defined (_GLIBCXX_UNORDERED_MAP) \ + || defined (_LIBCPP_UNORDERED_MAP) \ + || defined (_UNORDERED_MAP_)) \ + && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) + #define ARENA_HAS_UNORDERED_MAP_DEF + template , class KeyEqual = std::equal_to> + using unordered_map = std::unordered_map>>; +#endif +} + +#endif //AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp new file mode 100644 index 000000000..5d29ca706 --- /dev/null +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp @@ -0,0 +1,127 @@ +// +// Created by Deamon on 12/13/2023. +// + +#include "FrameBasedStackAllocator.h" +#include +#include +#include + +#include "../../gapi/interface/IDevice.h" +#include +#include + +class FrameRegion { +public: + FrameRegion(size_t size) : m_buffer(size) { + + } + inline int currentAllocationNumber() { return m_currentAllocations; } + + void *allocate(size_t allocSize) { + int offset = atomic_fetch_add(&m_topIndex, allocSize); + if ((offset + allocSize) > m_buffer.size()) { + return nullptr; + } + m_currentAllocations++; + + return &m_buffer[offset]; + } + int getCurrentSize() { return m_buffer.size();} + + bool isThisRegion(void *ptr) { + int index = (uintptr_t)ptr - (uintptr_t)m_buffer.data(); + + return (index > 0) && (index < m_buffer.size()); + } + void deallocate(void *ptr) { + if (!this->isThisRegion(ptr)) { + return; + } + + m_currentAllocations--; + + int index = ((uintptr_t)ptr - (uintptr_t)m_buffer.data()); + int prev_value = m_topIndex; + while(prev_value > index && + !m_topIndex.compare_exchange_weak(prev_value, index)) + {} + } + +private: + std::vector m_buffer; + std::atomic m_topIndex = 0; + std::atomic m_currentAllocations = 0; +}; + + +std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> g_frameStackList; +//std::array frames; + +static inline uint8_t BitScanMSB2(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} + +void * frameAllocate(size_t size) { + auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto ¤t_list = g_frameStackList[currentFrame]; + + auto &frameRegion = current_list.back(); + void *ptr = nullptr; + int regionSize = 2048; + if (frameRegion) { + ptr = frameRegion->allocate(size); + regionSize = frameRegion->getCurrentSize(); + } + if (ptr == nullptr) { + size_t currentBufferSize = regionSize; + size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); + + current_list.push_back(std::make_unique(newSize)); + + ptr = current_list.back()->allocate(size); + } + if (ptr == nullptr) { + std::cout << "oops!!!" << std::endl; + } + + return ptr; +} +void frameDeAllocate(void *ptr) { +// auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; +// auto ¤t_list = frames[currentFrame]; + + for (auto &frameList : g_frameStackList) { + for (auto it = frameList.begin(); it != frameList.end(); ++it) { + auto ®ion = (*it); + if (region->isThisRegion(ptr)) { + region->deallocate(ptr); + + if (region->currentAllocationNumber() == 0) + frameList.erase(it); + + return; + } + } + } + + std::cout << "failed to deallocate" << std::endl; +}; \ No newline at end of file diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h new file mode 100644 index 000000000..a4bf5d417 --- /dev/null +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -0,0 +1,82 @@ +// +// Created by Deamon on 12/13/2023. +// + +#ifndef AWEBWOWVIEWERCPP_FRAMEBASEDSTACKALLOCATOR_H +#define AWEBWOWVIEWERCPP_FRAMEBASEDSTACKALLOCATOR_H + +#undef max + +#include +#include +#include + +void * frameAllocate(size_t); +void frameDeAllocate(void *); + +template +struct FrameBasedStackAllocator +{ + typedef T value_type; + + FrameBasedStackAllocator() = default; + + template + constexpr FrameBasedStackAllocator(const FrameBasedStackAllocator &) noexcept {} + + [[nodiscard]] T* allocate(std::size_t n) + { + if (n > (std::numeric_limits::max() / sizeof(T))) + throw std::bad_array_new_length(); + + + if (auto p = static_cast(frameAllocate(n * sizeof(T)))) + { +// report(p, n); + return p; + } + + return nullptr; + } + + void deallocate(T* p, std::size_t n) noexcept + { +// report(p, n, 0); + frameDeAllocate(p); + } +private: +// void report(T* p, std::size_t n, bool alloc = true) const +// { +// std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n +// << " bytes at " << std::hex << std::showbase +// << reinterpret_cast(p) << std::dec << '\n'; +// } +}; + +template +bool operator==(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return true; } + +template +bool operator!=(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return false; } + +namespace framebased { + +#if ((defined (_GLIBCXX_VECTOR) \ + || defined (_LIBCPP_VECTOR) \ + || defined (_VECTOR_))) +#define ARENA_HAS_VECTOR_DEF + template + using vector = std::vector>; +#endif + +#if ((defined (_GLIBCXX_UNORDERED_MAP) \ + || defined (_LIBCPP_UNORDERED_MAP) \ + || defined (_UNORDERED_MAP_)) \ + && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) +#define ARENA_HAS_UNORDERED_MAP_DEF + template , class KeyEqual = std::equal_to> + using unordered_map = std::unordered_map>>; +#endif +} + +#endif //AWEBWOWVIEWERCPP_FRAMEBASEDSTACKALLOCATOR_H diff --git a/wowViewerLib/src/engine/objects/SceneObjectWithID.h b/wowViewerLib/src/engine/objects/SceneObjectWithID.h new file mode 100644 index 000000000..f5453a341 --- /dev/null +++ b/wowViewerLib/src/engine/objects/SceneObjectWithID.h @@ -0,0 +1,19 @@ +// +// Created by Deamon on 12/6/2023. +// + +#ifndef AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H +#define AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H + +class SceneObjectWithId { +public: + SceneObjectWithId(int id) : m_id(id) { + + } + + int getObjectId() { return m_id;} +private: + int m_id; +}; + +#endif //AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index f7d12bd0c..c07822dba 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -340,7 +340,7 @@ void AdtObject::calcBoundingBoxes() { } void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { - //ZoneScoped; + ZoneScoped; HGDevice device = m_api->hDevice; auto adtFileTex = m_adtFileTex; @@ -516,9 +516,9 @@ void AdtObject::loadAlphaTextures() { oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); arena.execute([&] { oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - ALIGNED_(16) std::array alphaTextureData; + ALIGNED_(16) std::array alphaTextureData; + for (size_t i = r.begin(); i != r.end(); ++i) { auto const &mapTile = m_adtFile->mapTile[i]; const auto indexX = mapTile.IndexX; const auto indexY = mapTile.IndexY; @@ -536,7 +536,7 @@ void AdtObject::loadAlphaTextures() { (__m128i *)(alphaTextureData.data() + (64 * 3)), }; - auto texturePtr = (__m128i*)getRowPtr<4>(bigTexture.data(), + __m128i* __restrict texturePtr = (__m128i*)getRowPtr<4>(bigTexture.data(), indexX * 64 + 0, indexY * 64 + y, texWidth, texHeight, 0); @@ -663,11 +663,12 @@ FileStatus AdtObject::getLoadedStatus() { } -void AdtObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { +bool AdtObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (!m_loaded) { if (getLoadedStatus() == FileStatus::FSLoaded) { this->loadingFinished(sceneRenderer); m_loaded = true; + return true; } } @@ -675,6 +676,7 @@ void AdtObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { createIBOAndBinding(sceneRenderer); createMeshes(sceneRenderer); } + return false; } void AdtObject::update(animTime_t deltaTime ) { m_lastDeltaTime = deltaTime; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 68c28375e..bade8d16a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -49,7 +49,7 @@ class AdtObject { void update(animTime_t deltaTime); void uploadGeneratorBuffers(const HFrameDependantData &frameDependantData); - void doPostLoad(const HMapSceneBufferCreate &sceneRenderer); + bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); int getAreaId(int mcnk_x, int mcnk_y); @@ -114,9 +114,9 @@ class AdtObject { int mostDetailedLod = 0; // 0 = most detailed LOD, 5 = least detailed lod int leastDetiledLod = 0; - std::unordered_map m_requestedTextures; - std::unordered_map m_requestedTexturesHeight; - std::unordered_map m_requestedTexturesSpec; + robin_hood::unordered_flat_map m_requestedTextures; + robin_hood::unordered_flat_map m_requestedTexturesHeight; + robin_hood::unordered_flat_map m_requestedTexturesSpec; std::vector lodCommands; @@ -168,16 +168,6 @@ class AdtObject { HGSamplableTexture getAdtHeightTexture(int textureId); HGSamplableTexture getAdtSpecularTexture(int textureId); -// struct AnimTextures { -// std::array animTexture; -// }; -// struct AnimTrans { -// std::array transVectors; -// }; -// std::vector texturesPerMCNK; -// -// std::vector animationTranslationPerMCNK; - void calcBoundingBoxes(); void loadM2s(); void loadWmos(); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 268baab39..47c95f416 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -312,6 +312,7 @@ class M2Object { }; #include "../../algorithms/mathHelper.h" +#include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" template<> inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { @@ -319,11 +320,13 @@ inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { } class M2ObjectListContainer { +//using vectorContainer = framebased::vector> +using m2Container = std::vector>; private: - std::vector> candidates; - std::vector> drawn; - std::vector> toLoadMain; - std::vector> toLoadGeom; + m2Container candidates; + m2Container drawn; + m2Container toLoadMain; + m2Container toLoadGeom; bool m_locked = false; @@ -332,7 +335,7 @@ class M2ObjectListContainer { bool toLoadMainCanHaveDuplicates = false; bool toLoadGeomCanHaveDuplicates = false; - void inline removeDuplicates(std::vector> &array) { + void inline removeDuplicates(m2Container &array) { if (array.size() < 1000) { std::sort(array.begin(), array.end()); } else { @@ -402,7 +405,7 @@ class M2ObjectListContainer { } - const std::vector> &getCandidates() { + const m2Container &getCandidates() { if (this->candCanHaveDuplicates) { removeDuplicates(candidates); candCanHaveDuplicates = false; @@ -411,7 +414,7 @@ class M2ObjectListContainer { return candidates; } - const std::vector> &getDrawn() { + const m2Container &getDrawn() { if (this->drawnCanHaveDuplicates) { removeDuplicates(drawn); drawnCanHaveDuplicates = false; @@ -420,7 +423,7 @@ class M2ObjectListContainer { return drawn; } - const std::vector> &getToLoadMain() { + const m2Container &getToLoadMain() { if (this->toLoadMainCanHaveDuplicates) { removeDuplicates(toLoadMain); toLoadMainCanHaveDuplicates = false; @@ -429,7 +432,7 @@ class M2ObjectListContainer { return toLoadMain; } - const std::vector> &getToLoadGeom() { + const m2Container &getToLoadGeom() { if (this->toLoadGeomCanHaveDuplicates) { removeDuplicates(toLoadGeom); toLoadGeomCanHaveDuplicates = false; diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp new file mode 100644 index 000000000..937497f44 --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 12/6/2023. +// + +#include "EntityActorsFactory.h" diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h new file mode 100644 index 000000000..70e51b45f --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -0,0 +1,32 @@ +// +// Created by Deamon on 12/6/2023. +// + +#ifndef AWEBWOWVIEWERCPP_ENTITYACTORSFACTORY_H +#define AWEBWOWVIEWERCPP_ENTITYACTORSFACTORY_H + +#include +#include "../m2/m2Object.h" +#include "../wmo/wmoObject.h" + +class EntityActorsFactory { +public: + EntityActorsFactory(const HApiContainer &api) : m_api(api){}; + + std::shared_ptr createM2Object() { + return std::make_shared(m_api); + } + M2Object * getM2ObjectById(int id) { + return m2ObjectCache[id]; + } + +private: + HApiContainer m_api; + + std::vector m2ObjectCache; + std::vector wmoObjectCache; + std::vector wmoGroupObjectCache; +}; + + +#endif //AWEBWOWVIEWERCPP_ENTITYACTORSFACTORY_H diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index e5c823197..40bfdb5b8 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1322,7 +1322,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); m2ProcessedThisFrame++; -// if (m2ProcessedThisFrame > 100) break; + if (m2ProcessedThisFrame > 100) break; } } } @@ -1364,8 +1364,10 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende { ZoneScopedN("Load adt"); + int adtProcessed = 0; for (auto &adtObject: renderPlan->adtArray) { - adtObject->adtObject->doPostLoad(sceneRenderer); + adtProcessed += (adtObject->adtObject->doPostLoad(sceneRenderer)) ? 1 : 0; + if (adtProcessed >= 2) break; } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 4b9865f40..1cc6e4b2a 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -13,6 +13,7 @@ class WMOGroupListContainer; #include "../m2/m2Object.h" #include "../liquid/LiquidInstance.h" #include "../../../gapi/interface/meshes/IMesh.h" +#include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" class WmoGroupObject { @@ -149,10 +150,11 @@ enum liquid_basic_types class WMOGroupListContainer { +using wmoGroupContainer = std::vector>; private: - std::vector> wmoGroupToDraw; - std::vector> wmoGroupToCheckM2; - std::vector> wmoGroupToLoad; + wmoGroupContainer wmoGroupToDraw; + wmoGroupContainer wmoGroupToCheckM2; + wmoGroupContainer wmoGroupToLoad; bool toDrawCanHaveDuplicates = false; bool toCheckM2CanHaveDuplicates = false; @@ -160,7 +162,7 @@ class WMOGroupListContainer { bool m_locked = false; - void inline removeDuplicates(std::vector> &array) { + void inline removeDuplicates(wmoGroupContainer &array) { if (array.size() < 1000) { std::sort(array.begin(), array.end()); } else { @@ -229,7 +231,7 @@ class WMOGroupListContainer { toLoadCanHaveDuplicates = true; } - const std::vector> &getToDraw() { + const wmoGroupContainer &getToDraw() { if (this->toDrawCanHaveDuplicates) { removeDuplicates(wmoGroupToDraw); toDrawCanHaveDuplicates = false; @@ -238,7 +240,7 @@ class WMOGroupListContainer { return wmoGroupToDraw; } - const std::vector> &getToCheckM2() { + const wmoGroupContainer &getToCheckM2() { if (this->toCheckM2CanHaveDuplicates) { removeDuplicates(wmoGroupToCheckM2); toCheckM2CanHaveDuplicates = false; @@ -247,7 +249,7 @@ class WMOGroupListContainer { return wmoGroupToCheckM2; } - const std::vector> &getToLoad() { + const wmoGroupContainer &getToLoad() { if (this->toLoadCanHaveDuplicates) { removeDuplicates(wmoGroupToLoad); toLoadCanHaveDuplicates = false; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index a5e99ad20..c51955f31 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -452,10 +452,8 @@ HGSamplableTexture WmoObject::getTexture(int textureId, bool isSpec) { return nullptr; }; - std::unordered_map &textureCache = diffuseTextures; - if (isSpec) { - textureCache = specularTextures; - } + robin_hood::unordered_flat_map &textureCache = + !isSpec ? diffuseTextures : specularTextures; auto i = textureCache.find(textureId); if (i != textureCache.end()) { @@ -568,8 +566,6 @@ bool WmoObject::startTraversingWMOGroup( if (!m_loaded) return false; - std::vector ivPerWMOGroup = std::vector(mainGeom->groupsLen); - uint32_t portalCount = (uint32_t) std::max(0, this->mainGeom->portalsLen); if (portalCount == 0) { @@ -592,6 +588,7 @@ bool WmoObject::startTraversingWMOGroup( } return result; } + std::vector ivPerWMOGroup = std::vector(mainGeom->groupsLen); std::vector transverseVisitedPortals = std::vector(portalCount, false); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 3d8aecf6e..03c332200 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -22,11 +22,12 @@ class WmoGroupObject; #include "../../persistance/header/wmoFileHeader.h" #include "../ViewsObjects.h" #include "../../../include/database/dbStructs.h" +#include "../SceneObjectWithID.h" -class WmoObject : public IWmoApi { +class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { public: - WmoObject(HApiContainer &api) : m_api(api) { + WmoObject(HApiContainer &api/*, int id*/) : /*SceneObjectWithId(id),*/ m_api(api) { } ~WmoObject(); @@ -73,12 +74,12 @@ class WmoObject : public IWmoApi { std::vector drawGroupWMO; std::vector lodGroupLevelWMO; - std::unordered_map> m_doodadsUnorderedMap; + robin_hood::unordered_flat_map> m_doodadsUnorderedMap; std::shared_ptr skyBox = nullptr; - std::unordered_map diffuseTextures; - std::unordered_map specularTextures; + robin_hood::unordered_flat_map diffuseTextures; + robin_hood::unordered_flat_map specularTextures; std::shared_ptr> m_modelWideChunk; std::vector> m_materialCache; @@ -185,20 +186,12 @@ class WmoObject : public IWmoApi { void createWorldPortals(); }; -struct WMOObjectHasher -{ - size_t operator()(const std::shared_ptr& val)const - { - return std::hash>()(val); - } -}; - -//typedef std::unordered_set, WMOObjectHasher> WMOObjectSetCont; class WMOListContainer { + using wmoContainer = std::vector>; private: - std::vector> wmoCandidates; - std::vector> wmoToLoad; - std::vector> wmoToDrawn; + wmoContainer wmoCandidates; + wmoContainer wmoToLoad; + wmoContainer wmoToDrawn; bool candCanHaveDuplicates = false; bool toLoadCanHaveDuplicates = false; @@ -206,7 +199,7 @@ class WMOListContainer { bool m_locked = false; - void inline removeDuplicates(std::vector> &array) { + void inline removeDuplicates(wmoContainer &array) { if (array.size() < 1000) { std::sort(array.begin(), array.end()); } else { @@ -260,7 +253,7 @@ class WMOListContainer { } } - const std::vector> &getCandidates() { + const wmoContainer &getCandidates() { if (this->candCanHaveDuplicates) { removeDuplicates(wmoCandidates); candCanHaveDuplicates = false; @@ -269,7 +262,7 @@ class WMOListContainer { return wmoCandidates; } - const std::vector> &getToLoad() { + const wmoContainer &getToLoad() { if (this->toLoadCanHaveDuplicates) { removeDuplicates(wmoToLoad); toLoadCanHaveDuplicates = false; @@ -279,7 +272,7 @@ class WMOListContainer { } - const std::vector> &getToDrawn() { + const wmoContainer &getToDrawn() { if (this->toDrawmCanHaveDuplicates) { removeDuplicates(wmoToDrawn); toDrawmCanHaveDuplicates = false; diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 34e735f19..d155d6dcc 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -511,7 +511,7 @@ MCAL_Offsets_Runtime AdtFile::createAlphaTextureRuntime(int mcnkChunkIndex) { return result; } -void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t textureSize) { +void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t* __restrict currentLayer, uint32_t textureSize) { mcnkStruct_t &mcnkObj = mcnkStructs[i]; uint8_t* mcal = mcnkObj.mcal; auto &layers = mcnkObj.mcly; diff --git a/wowViewerLib/src/engine/persistance/adtFile.h b/wowViewerLib/src/engine/persistance/adtFile.h index 5b8669f0a..78db0df83 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.h +++ b/wowViewerLib/src/engine/persistance/adtFile.h @@ -44,7 +44,7 @@ class AdtFile: public PersistentFile { AdtFile(int fileDataId){for (auto &mcnk: mcnkMap) {mcnk.fill(-1);}}; MCAL_Offsets_Runtime createAlphaTextureRuntime(int i); - void processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t *currentLayer, uint32_t currentLayerSize); + void processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t* __restrict currentLayer, uint32_t currentLayerSize); void process(HFileContent adtFile, const std::string &fileName) override; void setIsMain(bool isMain) { m_mainAdt = isMain; }; public: diff --git a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h index 71e501f4b..3ab826eeb 100644 --- a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h @@ -163,13 +163,13 @@ union{ /*0x020*/ uint32_t ofsRefs; /*0x024*/ uint32_t ofsAlpha; /*0x028*/ uint32_t sizeAlpha; -/*0x02C*/ uint32_t ofsShadow; // only with flags.has_mcsh +/*0x02C*/ uint32_t ofsShadow; // only with flags.has_mcsh /*0x030*/ uint32_t sizeShadow; /*0x034*/ uint32_t areaid; // in alpha: both zone id and sub zone id, as uint16s. /*0x038*/ uint32_t nMapObjRefs; /*0x03C*/ uint16_t holes_low_res; /*0x03E*/ uint16_t unknown_but_used; // in alpha: padding -/*0x040*/ uint16_t ReallyLowQualityTextureingMap[8]; // "predTex", It is used to determine which detail doodads to show. Values are an array of two bit unsigned integers, naming the layer. +/*0x040*/ uint16_t ReallyLowQualityTextureingMap[8]; // "predTex", It is used to determine which detail doodads to show. Values are an array of two bit unsigned integers, naming the layer. /*0x050*/ uint64_t noEffectDoodad; // WoD: may be an explicit MCDD chunk /*0x058*/ uint32_t ofsSndEmitters; /*0x05C*/ uint32_t nSndEmitters; // will be set to 0 in the client if ofsSndEmitters doesn't point to MCSE! diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 0a59d9f87..e9fb4a014 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,33 +295,14 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/ribbonShader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,0,84}, }, { { @@ -319,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -334,17 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, - {0,0,544}, + {0,0,144}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -354,16 +355,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -373,15 +372,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -392,16 +391,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -413,13 +409,13 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, - {1,1,16}, + {1,1,48}, + {1,0,64}, }, { { @@ -436,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -451,15 +456,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -470,22 +475,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -493,39 +492,35 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,544}, {1,0,64}, + {0,0,544}, }, { { {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -534,16 +529,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "visBuffer/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, - {1,0,64}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -551,17 +544,25 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -571,17 +572,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,96}, + {0,1,112}, }, { { - {0,0,1}, - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -608,14 +608,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -643,7 +644,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { @@ -662,22 +663,21 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, {1,6,0}, - {1,3,0}, + {1,4,0}, {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -686,15 +686,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -722,15 +722,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { + {0,1,112}, {0,0,544}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -758,15 +759,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -794,14 +795,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,12 +816,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -830,15 +831,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -849,10 +851,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, }, { }, @@ -870,16 +868,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {1,0,16}, }, { { - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -889,17 +887,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -909,15 +904,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -930,11 +925,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -946,18 +940,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {2,0,112}, - {0,0,544}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -968,17 +961,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -987,14 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,16}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1022,16 +1014,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,544}, + {0,1,32}, }, { { - {0,1,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1044,11 +1035,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1059,16 +1051,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {1,0,16}, + {0,1,16}, }, { { + {1,1,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1080,11 +1072,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1095,15 +1089,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1114,18 +1107,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, }, { - {3,0, "s_Textures"}, + {1,0, "Texture"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1134,14 +1125,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,80}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1169,15 +1161,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,80}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1190,11 +1181,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1205,16 +1197,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {1,0,32}, + {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1226,12 +1219,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1241,18 +1237,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, - {1,1,48}, - {1,0,64}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1264,21 +1258,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1288,16 +1273,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,544}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1324,18 +1310,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,544}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {2,2,1}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1346,22 +1338,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1370,17 +1357,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,32}, + {1,2,16384}, + {1,0,64}, + {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { - {1,1,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1391,12 +1385,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1407,15 +1400,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,16}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1443,15 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1462,16 +1454,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1481,17 +1475,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, + {1,1,16}, + {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1519,23 +1514,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "visBuffer/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, {0,0,544}, - {1,0,64}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1544,19 +1533,19 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, - {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1565,9 +1554,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -1584,19 +1573,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1606,15 +1590,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/skyConus.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,8 +1608,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, }, { }, @@ -1644,16 +1625,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { + {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1663,17 +1645,9 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, }, { - {2,0, "s_Textures"}, + {2,0, "uTexture"}, }, { { @@ -1689,16 +1663,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1725,16 +1700,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "visBuffer/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1742,19 +1715,26 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1762,16 +1742,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,0,112}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1782,14 +1770,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1819,6 +1810,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -1836,18 +1828,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {2,0,112}, + {1,5,4096}, + {1,2,16384}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { - {0,1,2}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1858,13 +1856,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1873,14 +1872,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "visBuffer/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {1,1,16}, + {0,0,544}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1888,18 +1889,19 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { + {1,0,4096}, }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1909,17 +1911,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, + {1,2,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1934,12 +1936,18 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1949,7 +1957,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "visBuffer/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -1985,15 +1993,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { + {1,0,64}, + {0,0,544}, + {1,1,16}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2020,15 +2031,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2039,16 +2050,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { - {0,3, "diffuse"}, + {3,0, "s_Textures"}, }, { { - {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2057,18 +2079,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "visBuffer/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,2,16384}, - {1,0,64}, {0,0,544}, }, { { {0,0,1}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2078,14 +2098,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2095,18 +2125,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2116,16 +2144,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {2,0, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2134,7 +2173,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -2153,6 +2192,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -2173,57 +2221,21 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 7, { - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 2, { - {"_1_2_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 5, { - {"_1_5_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 0, { - } - }, - }}, - {"adtLodShader", { + {"drawFrustumShader", { { 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"adtShader", { + {"drawBBShader", { { 1, { - } - }, - { - 3, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { @@ -2259,7 +2271,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, - { - 0, { - } - }, - }}, - {"skyConus", { - }}, - {"m2Shader", { { 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, } }, { - 2, { + 4, { } }, { - 7, { + 2, { + {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, } }, { - 8, { + 3, { } }, { - 9, { + 5, { + {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, } }, + }}, +}; +const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, + }}, + {"adtLodShader", { { - 3, { - {"_1_3_colors[0]", true, 0, 1, 4, 256}, + 0, { + {"_0_0_uViewUp", true, 0, 1, 4, 0}, + {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, + {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, + {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, + {"_0_0_FogColor", true, 64, 1, 4, 0}, + {"_0_0_uNewFormula", false, 80, 1, 1, 0}, } }, + }}, + {"drawDepthShader", { { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, + 2, { + {"_0_2_drawDepth", false, 0, 1, 1, 0}, + {"_0_2_uFarPlane", true, 4, 1, 1, 0}, + {"_0_2_uNearPlane", true, 8, 1, 1, 0}, } }, + }}, + {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2696,25 +2744,30 @@ const std::unordered_map GBufferVLK::getSubmitRecords() { stagingRecords.clear(); } - return MutexLockedVector(dataToBeUploaded, dataToBeUploadedMtx, true); + + return {dataToBeUploaded, dataToBeUploadedMtx, true}; } VkBuffer GBufferVLK::getGPUBuffer() { diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index d085aba7a..986232d32 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -192,23 +192,24 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff if (submitRecords.get().empty()) return; + std::vector barrierVec = {{}}; + const auto &submits = submitRecords.get(); for (int i = 0; i < submits.size(); i++) { auto &submit = submits[i]; if (submit.needsBarrier && !submit.copyRegions.empty()) { - this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, { - { - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - nullptr, - 0, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - submit.src, - submit.copyRegions[0].srcOffset, - submit.copyRegions[0].size - } - }); + barrierVec[0] = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + submit.src, + submit.copyRegions[0].srcOffset, + submit.copyRegions[0].size + }; + this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, barrierVec); } vkCmdCopyBuffer(m_gCmdBuffer.m_cmdBuffer, @@ -218,19 +219,18 @@ void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &buff submit.copyRegions.data()); if (submit.needsBarrier && !submit.copyRegions.empty()) { - this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, { - { - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - nullptr, - 0, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - submit.dst, - submit.copyRegions[0].dstOffset, - submit.copyRegions[0].size - } - }); + barrierVec[0] = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + submit.dst, + submit.copyRegions[0].dstOffset, + submit.copyRegions[0].size + }; + this->recordPipelineBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, barrierVec); } } } diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp index 77ddab14e..6efbd9fa2 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.cpp @@ -53,12 +53,12 @@ void GDescriptorSet::update() { // The operations described by pDescriptorWrites are performed first, followed by the operations described by pDescriptorCopies. // // So, writes first, copies second. T_T -void GDescriptorSet::writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo, std::vector &dynamicBufferIndexes) { +void GDescriptorSet::writeToDescriptorSets(framebased::vector &descriptorWrites, framebased::vector &imageInfo, framebased::vector &dynamicBufferIndexes) { vkUpdateDescriptorSets(m_device->getVkDevice(), static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); m_firstUpdate = false; - m_dynamicBufferIndexes = dynamicBufferIndexes; + m_dynamicBufferIndexes = decltype(m_dynamicBufferIndexes)(dynamicBufferIndexes.begin(), dynamicBufferIndexes.end()); m_dynamicBuffers.resize(m_dynamicBufferIndexes.size()); for (int i = 0; i < m_dynamicBufferIndexes.size(); i++) { m_dynamicBuffers[i] = boundDescriptors[m_dynamicBufferIndexes[i]][0]->buffer.get(); @@ -82,8 +82,8 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture } #endif - auto textureVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getTexture()) : nullptr; - auto samplerVlk = samplableTextureVlk != nullptr ? std::dynamic_pointer_cast(samplableTextureVlk->getSampler()) : nullptr; + auto textureVlk = samplableTextureVlk != nullptr ? ((GTextureVLK *)samplableTextureVlk->getTexture().get()) : nullptr; + auto samplerVlk = samplableTextureVlk != nullptr ? ((GTextureSamplerVLK *)samplableTextureVlk->getSampler().get()) : nullptr; assignBoundDescriptors(bindIndex, samplableTextureVlk, index, DescriptorRecord::DescriptorRecordType::Texture); @@ -95,8 +95,8 @@ GDescriptorSet::SetUpdateHelper::texture(int bindIndex, const HGSamplableTexture if (textureVlk == nullptr || !textureVlk->getIsLoaded()) { auto blackTextureVlk = m_set.m_device->getBlackTexturePixel(); - texture = std::dynamic_pointer_cast(blackTextureVlk->getTexture()); - samplerVlk = std::dynamic_pointer_cast(blackTextureVlk->getSampler()); + texture = (GTextureVLK *) blackTextureVlk->getTexture().get(); + samplerVlk = (GTextureSamplerVLK *) blackTextureVlk->getSampler().get(); } imageInfo.imageView = texture->texture.view; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h index 513070c6a..08d0e0fbe 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSet.h @@ -18,6 +18,7 @@ class GDescriptorPoolVLK; #include "DescriptorRecord.h" #include "../bindable/DSBindable.h" #include "../utils/MutexLockedVector.h" +#include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" class BindlessUpdateAccum { public: @@ -44,7 +45,7 @@ class GDescriptorSet : public std::enable_shared_from_this { ~GDescriptorSet(); void update(); - void writeToDescriptorSets(std::vector &descriptorWrites, std::vector &imageInfo, std::vector &dynamicBufferIndexes); + void writeToDescriptorSets(framebased::vector &descriptorWrites, framebased::vector &imageInfo, framebased::vector &dynamicBufferIndexes); const std::shared_ptr &getDescSetLayout() const { return m_hDescriptorSetLayout;}; VkDescriptorSet getDescSet() const {return m_descriptorSet;} @@ -115,7 +116,7 @@ class GDescriptorSet : public std::enable_shared_from_this { m_boundDescriptors[bindPoint][index] = std::make_unique(descType, object, callback); } } - std::unordered_map &getAccumulatedTypeOverrides() { + framebased::unordered_map &getAccumulatedTypeOverrides() { return typeOverrides; } private: @@ -123,14 +124,14 @@ class GDescriptorSet : public std::enable_shared_from_this { GDescriptorSet &m_set; std::array>, GDescriptorSetLayout::MAX_BINDPOINT_NUMBER> &m_boundDescriptors; - std::vector imageInfos; - std::vector bufferInfos; - std::vector dynamicBufferIndexes; - std::unordered_map typeOverrides; + framebased::vector imageInfos; + framebased::vector bufferInfos; + framebased::vector dynamicBufferIndexes; + framebased::unordered_map typeOverrides; std::shared_ptr m_descriptorSetUpdater; - std::vector updates; + framebased::vector updates; std::bitset m_updateBindPoints = 0; std::function createCallback(int bindPoint, int arrayIndex); diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h index f3acaacf4..2ea4e65aa 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h @@ -12,6 +12,7 @@ #include "../../../../include/custom_container_key.h" #include "../GDescriptorSet.h" #include "../../../../renderer/mapScene/materials/BindlessTexture.h" +#include "../../../../robin_hood.h" class BindlessTextureHolder : public std::enable_shared_from_this { public: @@ -23,7 +24,7 @@ class BindlessTextureHolder : public std::enable_shared_from_this Bindless in array - std::unordered_map>, std::weak_ptr> m_textureMap; + robin_hood::unordered_flat_map>, std::weak_ptr> m_textureMap; }; diff --git a/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h b/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h index 336c86d92..0d7d3bfbe 100644 --- a/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h +++ b/wowViewerLib/src/gapi/vulkan/utils/MutexLockedVector.h @@ -8,10 +8,10 @@ #include #include -template +template > class MutexLockedVector { public: - MutexLockedVector(std::vector &vec, std::mutex &m, bool clearOnDestroy) : m_vec(vec), m_lockGuard(std::lock_guard(m)), m_clearOnDestroy(clearOnDestroy) { + MutexLockedVector(Vec &vec, std::mutex &m, bool clearOnDestroy) : m_vec(vec), m_lockGuard(std::lock_guard(m)), m_clearOnDestroy(clearOnDestroy) { } ~MutexLockedVector() { @@ -23,7 +23,7 @@ class MutexLockedVector { } private: bool m_clearOnDestroy; - std::vector &m_vec; + Vec &m_vec; std::lock_guard m_lockGuard; }; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index a8a1186f0..90bc66ca5 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -87,6 +87,12 @@ static std::vector drawPortalBindings = {{ {+drawPortalShader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, 12, 0}, // 0 }}; +struct MeshCount { + int commonMesh = 0; + int m2Mesh = 0; + int wmoMesh = 0; + int adtMesh = 0; +}; class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 8072848ef..e65e32654 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -532,6 +532,7 @@ HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) std::shared_ptr MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { + ZoneScoped; auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); auto fragmentData = std::make_shared>(adtBuffers.adtMeshWidePSes); @@ -955,6 +956,13 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ commonMeshes.reserve(1000); m2DrawVec.reserve(5000); wmoDrawVec.reserve(5000); + adtDrawVec.reserve(1000); + } + COpaqueMeshCollectorBindlessVLK(MapSceneRenderVisBufferVLK &rendererVlk, MeshCount &lastMeshCount) : m_renderer(rendererVlk) { + commonMeshes.reserve(lastMeshCount.commonMesh); + m2DrawVec.reserve(lastMeshCount.m2Mesh); + wmoDrawVec.reserve(lastMeshCount.wmoMesh); + adtDrawVec.reserve(lastMeshCount.adtMesh); } private: MapSceneRenderVisBufferVLK &m_renderer; @@ -967,7 +975,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ uint32_t vertexOffset; }; - typedef std::unordered_map, std::vector> MeshMap; + typedef robin_hood::unordered_flat_map, std::vector> MeshMap; std::vector m2DrawVec; std::vector wmoDrawVec; @@ -1122,6 +1130,12 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ } } } + void fillMeshCount(MeshCount &meshCount) { + meshCount.adtMesh = adtDrawVec.size(); + meshCount.m2Mesh = m2DrawVec.size(); + meshCount.wmoMesh = wmoDrawVec.size(); + meshCount.commonMesh = commonMeshes.size(); + } }; @@ -1135,10 +1149,12 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s //Create meshes - std::unique_ptr u_collector = std::make_unique(*this); + std::unique_ptr u_collector = std::make_unique(*this, lastMeshCount); std::unique_ptr u_skyCollector = std::make_unique(*this); auto transparentMeshes = std::make_shared>(); + + auto skyTransparentMeshes = std::make_shared>(); framePlan->m2Array.lock(); framePlan->wmoArray.lock(); @@ -1152,6 +1168,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // [&]() { collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); + u_collector->fillMeshCount(lastMeshCount); // } // ); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index c4e2be44e..bc16be446 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -127,8 +127,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { (hash{}(k.colorMask) << 18); }; }; - std::unordered_map, PipelineTemplateHasher> m_m2StaticMaterials; - std::unordered_map, PipelineTemplateHasher> m_wmoStaticMaterials; + robin_hood::unordered_flat_map, PipelineTemplateHasher> m_m2StaticMaterials; + robin_hood::unordered_flat_map, PipelineTemplateHasher> m_wmoStaticMaterials; private: HGDeviceVLK m_device; @@ -239,6 +239,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr defaultView; + MeshCount lastMeshCount; + void createM2GlobalMaterialData(); void createWMOGlobalMaterialData(); void createADTGlobalMaterialData(); @@ -249,8 +251,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator //and seed it with entropy. std::uniform_int_distribution idDistr; - std::unordered_map> m_m2MatCacheId; - std::unordered_map> m_wmoMatCacheId; + robin_hood::unordered_flat_map> m_m2MatCacheId; + robin_hood::unordered_flat_map> m_wmoMatCacheId; uint32_t generateUniqueWMOMatId() { uint32_t random; diff --git a/wowViewerLib/src/robin_hood.h b/wowViewerLib/src/robin_hood.h new file mode 100644 index 000000000..0af031f5f --- /dev/null +++ b/wowViewerLib/src/robin_hood.h @@ -0,0 +1,2544 @@ +// ______ _____ ______ _________ +// ______________ ___ /_ ___(_)_______ ___ /_ ______ ______ ______ / +// __ ___/_ __ \__ __ \__ / __ __ \ __ __ \_ __ \_ __ \_ __ / +// _ / / /_/ /_ /_/ /_ / _ / / / _ / / // /_/ // /_/ // /_/ / +// /_/ \____/ /_.___/ /_/ /_/ /_/ ________/_/ /_/ \____/ \____/ \__,_/ +// _/_____/ +// +// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20 +// https://github.com/martinus/robin-hood-hashing +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2018-2021 Martin Ankerl +// +// 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. + +#ifndef ROBIN_HOOD_H_INCLUDED +#define ROBIN_HOOD_H_INCLUDED + +// see https://semver.org/ +#define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes +#define ROBIN_HOOD_VERSION_MINOR 11 // for adding functionality in a backwards-compatible manner +#define ROBIN_HOOD_VERSION_PATCH 5 // for backwards-compatible bug fixes + +#include +#include +#include +#include +#include +#include // only to support hash of smart pointers +#include +#include +#include +#include +#if __cplusplus >= 201703L +# include +#endif + +// #define ROBIN_HOOD_LOG_ENABLED +#ifdef ROBIN_HOOD_LOG_ENABLED +# include +# define ROBIN_HOOD_LOG(...) \ + std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl; +#else +# define ROBIN_HOOD_LOG(x) +#endif + +// #define ROBIN_HOOD_TRACE_ENABLED +#ifdef ROBIN_HOOD_TRACE_ENABLED +# include +# define ROBIN_HOOD_TRACE(...) \ + std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl; +#else +# define ROBIN_HOOD_TRACE(x) +#endif + +// #define ROBIN_HOOD_COUNT_ENABLED +#ifdef ROBIN_HOOD_COUNT_ENABLED +# include +# define ROBIN_HOOD_COUNT(x) ++counts().x; +namespace robin_hood { +struct Counts { + uint64_t shiftUp{}; + uint64_t shiftDown{}; +}; +inline std::ostream& operator<<(std::ostream& os, Counts const& c) { + return os << c.shiftUp << " shiftUp" << std::endl << c.shiftDown << " shiftDown" << std::endl; +} + +static Counts& counts() { + static Counts counts{}; + return counts; +} +} // namespace robin_hood +#else +# define ROBIN_HOOD_COUNT(x) +#endif + +// all non-argument macros should use this facility. See +// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/ +#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x() + +// mark unused members with this macro +#define ROBIN_HOOD_UNUSED(identifier) + +// bitness +#if SIZE_MAX == UINT32_MAX +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32 +#elif SIZE_MAX == UINT64_MAX +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64 +#else +# error Unsupported bitness +#endif + +// endianess +#ifdef _MSC_VER +# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1 +# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0 +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#endif + +// inline +#ifdef _MSC_VER +# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline) +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline)) +#endif + +// exceptions +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0 +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1 +#endif + +// count leading/trailing bits +#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS) +# ifdef _MSC_VER +# if ROBIN_HOOD(BITNESS) == 32 +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64 +# endif +# include +# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD)) +# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \ + [](size_t mask) noexcept -> int { \ + unsigned long index; \ + return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast(index) \ + : ROBIN_HOOD(BITNESS); \ + }(x) +# else +# if ROBIN_HOOD(BITNESS) == 32 +# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl +# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll +# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll +# endif +# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS)) +# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS)) +# endif +#endif + +// fallthrough +#ifndef __has_cpp_attribute // For backwards compatibility +# define __has_cpp_attribute(x) 0 +#endif +#if __has_cpp_attribute(clang::fallthrough) +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]] +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() +#endif + +// likely/unlikely +#ifdef _MSC_VER +# define ROBIN_HOOD_LIKELY(condition) condition +# define ROBIN_HOOD_UNLIKELY(condition) condition +#else +# define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1) +# define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0) +#endif + +// detect if native wchar_t type is availiable in MSVC +#ifdef _MSC_VER +# ifdef _NATIVE_WCHAR_T_DEFINED +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1 +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0 +# endif +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1 +#endif + +// detect if MSVC supports the pair(std::piecewise_construct_t,...) consructor being constexpr +#ifdef _MSC_VER +# if _MSC_VER <= 1900 +# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1 +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0 +# endif +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0 +#endif + +// workaround missing "is_trivially_copyable" in g++ < 5.0 +// See https://stackoverflow.com/a/31798726/48181 +#if defined(__GNUC__) && __GNUC__ < 5 +# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__) +#else +# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value +#endif + +// helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L + +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17) +# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]] +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() +#endif + +namespace robin_hood { + +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14) +# define ROBIN_HOOD_STD std +#else + +// c++11 compatibility layer +namespace ROBIN_HOOD_STD { +template +struct alignment_of + : std::integral_constant::type)> {}; + +template +class integer_sequence { +public: + using value_type = T; + static_assert(std::is_integral::value, "not integral type"); + static constexpr std::size_t size() noexcept { + return sizeof...(Ints); + } +}; +template +using index_sequence = integer_sequence; + +namespace detail_ { +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)"); + + template + struct IntSeqCombiner; + + template + struct IntSeqCombiner, integer_sequence> { + using TResult = integer_sequence; + }; + + using TResult = + typename IntSeqCombiner::TResult, + typename IntSeqImpl::TResult>::TResult; +}; + +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; +}; + +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; +}; +} // namespace detail_ + +template +using make_integer_sequence = typename detail_::IntSeqImpl::TResult; + +template +using make_index_sequence = make_integer_sequence; + +template +using index_sequence_for = make_index_sequence; + +} // namespace ROBIN_HOOD_STD + +#endif + +namespace detail { + +// make sure we static_cast to the correct type for hash_int +#if ROBIN_HOOD(BITNESS) == 64 +using SizeT = uint64_t; +#else +using SizeT = uint32_t; +#endif + +template +T rotr(T x, unsigned k) { + return (x >> k) | (x << (8U * sizeof(T) - k)); +} + +// This cast gets rid of warnings like "cast from 'uint8_t*' {aka 'unsigned char*'} to +// 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type". Use with +// care! +template +inline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept { + return reinterpret_cast(ptr); +} + +template +inline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept { + return reinterpret_cast(ptr); +} + +// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other +// inlinings more difficult. Throws are also generally the slow path. +template +[[noreturn]] ROBIN_HOOD(NOINLINE) +#if ROBIN_HOOD(HAS_EXCEPTIONS) + void doThrow(Args&&... args) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) + throw E(std::forward(args)...); +} +#else + void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) { + abort(); +} +#endif + +template +T* assertNotNull(T* t, Args&&... args) { + if (ROBIN_HOOD_UNLIKELY(nullptr == t)) { + doThrow(std::forward(args)...); + } + return t; +} + +template +inline T unaligned_load(void const* ptr) noexcept { + // using memcpy so we don't get into unaligned load problems. + // compiler should optimize this very well anyways. + T t; + std::memcpy(&t, ptr, sizeof(T)); + return t; +} + +// Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor, +// and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a +// pointer. +template +class BulkPoolAllocator { +public: + BulkPoolAllocator() noexcept = default; + + // does not copy anything, just creates a new allocator. + BulkPoolAllocator(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept + : mHead(nullptr) + , mListForFree(nullptr) {} + + BulkPoolAllocator(BulkPoolAllocator&& o) noexcept + : mHead(o.mHead) + , mListForFree(o.mListForFree) { + o.mListForFree = nullptr; + o.mHead = nullptr; + } + + BulkPoolAllocator& operator=(BulkPoolAllocator&& o) noexcept { + reset(); + mHead = o.mHead; + mListForFree = o.mListForFree; + o.mListForFree = nullptr; + o.mHead = nullptr; + return *this; + } + + BulkPoolAllocator& + // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp) + operator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept { + // does not do anything + return *this; + } + + ~BulkPoolAllocator() noexcept { + reset(); + } + + // Deallocates all allocated memory. + void reset() noexcept { + while (mListForFree) { + T* tmp = *mListForFree; + ROBIN_HOOD_LOG("std::free") + std::free(mListForFree); + mListForFree = reinterpret_cast_no_cast_align_warning(tmp); + } + mHead = nullptr; + } + + // allocates, but does NOT initialize. Use in-place new constructor, e.g. + // T* obj = pool.allocate(); + // ::new (static_cast(obj)) T(); + T* allocate() { + T* tmp = mHead; + if (!tmp) { + tmp = performAllocation(); + } + + mHead = *reinterpret_cast_no_cast_align_warning(tmp); + return tmp; + } + + // does not actually deallocate but puts it in store. + // make sure you have already called the destructor! e.g. with + // obj->~T(); + // pool.deallocate(obj); + void deallocate(T* obj) noexcept { + *reinterpret_cast_no_cast_align_warning(obj) = mHead; + mHead = obj; + } + + // Adds an already allocated block of memory to the allocator. This allocator is from now on + // responsible for freeing the data (with free()). If the provided data is not large enough to + // make use of, it is immediately freed. Otherwise it is reused and freed in the destructor. + void addOrFree(void* ptr, const size_t numBytes) noexcept { + // calculate number of available elements in ptr + if (numBytes < ALIGNMENT + ALIGNED_SIZE) { + // not enough data for at least one element. Free and return. + ROBIN_HOOD_LOG("std::free") + std::free(ptr); + } else { + ROBIN_HOOD_LOG("add to buffer") + add(ptr, numBytes); + } + } + + void swap(BulkPoolAllocator& other) noexcept { + using std::swap; + swap(mHead, other.mHead); + swap(mListForFree, other.mListForFree); + } + +private: + // iterates the list of allocated memory to calculate how many to alloc next. + // Recalculating this each time saves us a size_t member. + // This ignores the fact that memory blocks might have been added manually with addOrFree. In + // practice, this should not matter much. + ROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept { + auto tmp = mListForFree; + size_t numAllocs = MinNumAllocs; + + while (numAllocs * 2 <= MaxNumAllocs && tmp) { + auto x = reinterpret_cast(tmp); + tmp = *x; + numAllocs *= 2; + } + + return numAllocs; + } + + // WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree(). + void add(void* ptr, const size_t numBytes) noexcept { + const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE; + + auto data = reinterpret_cast(ptr); + + // link free list + auto x = reinterpret_cast(data); + *x = mListForFree; + mListForFree = data; + + // create linked list for newly allocated data + auto* const headT = + reinterpret_cast_no_cast_align_warning(reinterpret_cast(ptr) + ALIGNMENT); + + auto* const head = reinterpret_cast(headT); + + // Visual Studio compiler automatically unrolls this loop, which is pretty cool + for (size_t i = 0; i < numElements; ++i) { + *reinterpret_cast_no_cast_align_warning(head + i * ALIGNED_SIZE) = + head + (i + 1) * ALIGNED_SIZE; + } + + // last one points to 0 + *reinterpret_cast_no_cast_align_warning(head + (numElements - 1) * ALIGNED_SIZE) = + mHead; + mHead = headT; + } + + // Called when no memory is available (mHead == 0). + // Don't inline this slow path. + ROBIN_HOOD(NOINLINE) T* performAllocation() { + size_t const numElementsToAlloc = calcNumElementsToAlloc(); + + // alloc new memory: [prev |T, T, ... T] + size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc; + ROBIN_HOOD_LOG("std::malloc " << bytes << " = " << ALIGNMENT << " + " << ALIGNED_SIZE + << " * " << numElementsToAlloc) + add(assertNotNull(std::malloc(bytes)), bytes); + return mHead; + } + + // enforce byte alignment of the T's +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14) + static constexpr size_t ALIGNMENT = + (std::max)(std::alignment_of::value, std::alignment_of::value); +#else + static const size_t ALIGNMENT = + (ROBIN_HOOD_STD::alignment_of::value > ROBIN_HOOD_STD::alignment_of::value) + ? ROBIN_HOOD_STD::alignment_of::value + : +ROBIN_HOOD_STD::alignment_of::value; // the + is for walkarround +#endif + + static constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT; + + static_assert(MinNumAllocs >= 1, "MinNumAllocs"); + static_assert(MaxNumAllocs >= MinNumAllocs, "MaxNumAllocs"); + static_assert(ALIGNED_SIZE >= sizeof(T*), "ALIGNED_SIZE"); + static_assert(0 == (ALIGNED_SIZE % sizeof(T*)), "ALIGNED_SIZE mod"); + static_assert(ALIGNMENT >= sizeof(T*), "ALIGNMENT"); + + T* mHead{nullptr}; + T** mListForFree{nullptr}; +}; + +template +struct NodeAllocator; + +// dummy allocator that does nothing +template +struct NodeAllocator { + + // we are not using the data, so just free it. + void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept { + ROBIN_HOOD_LOG("std::free") + std::free(ptr); + } +}; + +template +struct NodeAllocator : public BulkPoolAllocator {}; + +// c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making +// my own here. +namespace swappable { +#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17) +using std::swap; +template +struct nothrow { + static const bool value = noexcept(swap(std::declval(), std::declval())); +}; +#else +template +struct nothrow { + static const bool value = std::is_nothrow_swappable::value; +}; +#endif +} // namespace swappable + +} // namespace detail + +struct is_transparent_tag {}; + +// A custom pair implementation is used in the map because std::pair is not is_trivially_copyable, +// which means it would not be allowed to be used in std::memcpy. This struct is copyable, which is +// also tested. +template +struct pair { + using first_type = T1; + using second_type = T2; + + template ::value && + std::is_default_constructible::value>::type> + constexpr pair() noexcept(noexcept(U1()) && noexcept(U2())) + : first() + , second() {} + + // pair constructors are explicit so we don't accidentally call this ctor when we don't have to. + explicit constexpr pair(std::pair const& o) noexcept( + noexcept(T1(std::declval())) && noexcept(T2(std::declval()))) + : first(o.first) + , second(o.second) {} + + // pair constructors are explicit so we don't accidentally call this ctor when we don't have to. + explicit constexpr pair(std::pair&& o) noexcept(noexcept( + T1(std::move(std::declval()))) && noexcept(T2(std::move(std::declval())))) + : first(std::move(o.first)) + , second(std::move(o.second)) {} + + constexpr pair(T1&& a, T2&& b) noexcept(noexcept( + T1(std::move(std::declval()))) && noexcept(T2(std::move(std::declval())))) + : first(std::move(a)) + , second(std::move(b)) {} + + template + constexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward( + std::declval()))) && noexcept(T2(std::forward(std::declval())))) + : first(std::forward(a)) + , second(std::forward(b)) {} + + template + // MSVC 2015 produces error "C2476: ‘constexpr’ constructor does not initialize all members" + // if this constructor is constexpr +#if !ROBIN_HOOD(BROKEN_CONSTEXPR) + constexpr +#endif + pair(std::piecewise_construct_t /*unused*/, std::tuple a, + std::tuple + b) noexcept(noexcept(pair(std::declval&>(), + std::declval&>(), + ROBIN_HOOD_STD::index_sequence_for(), + ROBIN_HOOD_STD::index_sequence_for()))) + : pair(a, b, ROBIN_HOOD_STD::index_sequence_for(), + ROBIN_HOOD_STD::index_sequence_for()) { + } + + // constructor called from the std::piecewise_construct_t ctor + template + pair(std::tuple& a, std::tuple& b, ROBIN_HOOD_STD::index_sequence /*unused*/, ROBIN_HOOD_STD::index_sequence /*unused*/) noexcept( + noexcept(T1(std::forward(std::get( + std::declval&>()))...)) && noexcept(T2(std:: + forward(std::get( + std::declval&>()))...))) + : first(std::forward(std::get(a))...) + , second(std::forward(std::get(b))...) { + // make visual studio compiler happy about warning about unused a & b. + // Visual studio's pair implementation disables warning 4100. + (void)a; + (void)b; + } + + void swap(pair& o) noexcept((detail::swappable::nothrow::value) && + (detail::swappable::nothrow::value)) { + using std::swap; + swap(first, o.first); + swap(second, o.second); + } + + T1 first; // NOLINT(misc-non-private-member-variables-in-classes) + T2 second; // NOLINT(misc-non-private-member-variables-in-classes) +}; + +template +inline void swap(pair& a, pair& b) noexcept( + noexcept(std::declval&>().swap(std::declval&>()))) { + a.swap(b); +} + +template +inline constexpr bool operator==(pair const& x, pair const& y) { + return (x.first == y.first) && (x.second == y.second); +} +template +inline constexpr bool operator!=(pair const& x, pair const& y) { + return !(x == y); +} +template +inline constexpr bool operator<(pair const& x, pair const& y) noexcept(noexcept( + std::declval() < std::declval()) && noexcept(std::declval() < + std::declval())) { + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +inline constexpr bool operator>(pair const& x, pair const& y) { + return y < x; +} +template +inline constexpr bool operator<=(pair const& x, pair const& y) { + return !(x > y); +} +template +inline constexpr bool operator>=(pair const& x, pair const& y) { + return !(x < y); +} + +inline size_t hash_bytes(void const* ptr, size_t len) noexcept { + static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995); + static constexpr uint64_t seed = UINT64_C(0xe17a1465); + static constexpr unsigned int r = 47; + + auto const* const data64 = static_cast(ptr); + uint64_t h = seed ^ (len * m); + + size_t const n_blocks = len / 8; + for (size_t i = 0; i < n_blocks; ++i) { + auto k = detail::unaligned_load(data64 + i); + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + auto const* const data8 = reinterpret_cast(data64 + n_blocks); + switch (len & 7U) { + case 7: + h ^= static_cast(data8[6]) << 48U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 6: + h ^= static_cast(data8[5]) << 40U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 5: + h ^= static_cast(data8[4]) << 32U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 4: + h ^= static_cast(data8[3]) << 24U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 3: + h ^= static_cast(data8[2]) << 16U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 2: + h ^= static_cast(data8[1]) << 8U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 1: + h ^= static_cast(data8[0]); + h *= m; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + default: + break; + } + + h ^= h >> r; + + // not doing the final step here, because this will be done by keyToIdx anyways + // h *= m; + // h ^= h >> r; + return static_cast(h); +} + +inline size_t hash_int(uint64_t x) noexcept { + // tried lots of different hashes, let's stick with murmurhash3. It's simple, fast, well tested, + // and doesn't need any special 128bit operations. + x ^= x >> 33U; + x *= UINT64_C(0xff51afd7ed558ccd); + x ^= x >> 33U; + + // not doing the final step here, because this will be done by keyToIdx anyways + // x *= UINT64_C(0xc4ceb9fe1a85ec53); + // x ^= x >> 33U; + return static_cast(x); +} + +// A thin wrapper around std::hash, performing an additional simple mixing step of the result. +template +struct hash : public std::hash { + size_t operator()(T const& obj) const + noexcept(noexcept(std::declval>().operator()(std::declval()))) { + // call base hash + auto result = std::hash::operator()(obj); + // return mixed of that, to be save against identity has + return hash_int(static_cast(result)); + } +}; + +template +struct hash> { + size_t operator()(std::basic_string const& str) const noexcept { + return hash_bytes(str.data(), sizeof(CharT) * str.size()); + } +}; + +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17) +template +struct hash> { + size_t operator()(std::basic_string_view const& sv) const noexcept { + return hash_bytes(sv.data(), sizeof(CharT) * sv.size()); + } +}; +#endif + +template +struct hash { + size_t operator()(T* ptr) const noexcept { + return hash_int(reinterpret_cast(ptr)); + } +}; + +template +struct hash> { + size_t operator()(std::unique_ptr const& ptr) const noexcept { + return hash_int(reinterpret_cast(ptr.get())); + } +}; + +template +struct hash> { + size_t operator()(std::shared_ptr const& ptr) const noexcept { + return hash_int(reinterpret_cast(ptr.get())); + } +}; + +template +struct hash::value>::type> { + size_t operator()(Enum e) const noexcept { + using Underlying = typename std::underlying_type::type; + return hash{}(static_cast(e)); + } +}; + +#define ROBIN_HOOD_HASH_INT(T) \ + template <> \ + struct hash { \ + size_t operator()(T const& obj) const noexcept { \ + return hash_int(static_cast(obj)); \ + } \ + } + +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wuseless-cast" +#endif +// see https://en.cppreference.com/w/cpp/utility/hash +ROBIN_HOOD_HASH_INT(bool); +ROBIN_HOOD_HASH_INT(char); +ROBIN_HOOD_HASH_INT(signed char); +ROBIN_HOOD_HASH_INT(unsigned char); +ROBIN_HOOD_HASH_INT(char16_t); +ROBIN_HOOD_HASH_INT(char32_t); +#if ROBIN_HOOD(HAS_NATIVE_WCHART) +ROBIN_HOOD_HASH_INT(wchar_t); +#endif +ROBIN_HOOD_HASH_INT(short); +ROBIN_HOOD_HASH_INT(unsigned short); +ROBIN_HOOD_HASH_INT(int); +ROBIN_HOOD_HASH_INT(unsigned int); +ROBIN_HOOD_HASH_INT(long); +ROBIN_HOOD_HASH_INT(long long); +ROBIN_HOOD_HASH_INT(unsigned long); +ROBIN_HOOD_HASH_INT(unsigned long long); +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif +namespace detail { + +template +struct void_type { + using type = void; +}; + +template +struct has_is_transparent : public std::false_type {}; + +template +struct has_is_transparent::type> + : public std::true_type {}; + +// using wrapper classes for hash and key_equal prevents the diamond problem when the same type +// is used. see https://stackoverflow.com/a/28771920/48181 +template +struct WrapHash : public T { + WrapHash() = default; + explicit WrapHash(T const& o) noexcept(noexcept(T(std::declval()))) + : T(o) {} +}; + +template +struct WrapKeyEqual : public T { + WrapKeyEqual() = default; + explicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval()))) + : T(o) {} +}; + +// A highly optimized hashmap implementation, using the Robin Hood algorithm. +// +// In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but +// be about 2x faster in most cases and require much less allocations. +// +// This implementation uses the following memory layout: +// +// [Node, Node, ... Node | info, info, ... infoSentinel ] +// +// * Node: either a DataNode that directly has the std::pair as member, +// or a DataNode with a pointer to std::pair. Which DataNode representation to use +// depends on how fast the swap() operation is. Heuristically, this is automatically choosen +// based on sizeof(). there are always 2^n Nodes. +// +// * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes. +// Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the +// corresponding node contains data. Set to 2 means the corresponding Node is filled, but it +// actually belongs to the previous position and was pushed out because that place is already +// taken. +// +// * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the +// need for a idx variable. +// +// According to STL, order of templates has effect on throughput. That's why I've moved the +// boolean to the front. +// https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/ +template +class Table + : public WrapHash, + public WrapKeyEqual, + detail::NodeAllocator< + typename std::conditional< + std::is_void::value, Key, + robin_hood::pair::type, T>>::type, + 4, 16384, IsFlat> { +public: + static constexpr bool is_flat = IsFlat; + static constexpr bool is_map = !std::is_void::value; + static constexpr bool is_set = !is_map; + static constexpr bool is_transparent = + has_is_transparent::value && has_is_transparent::value; + + using key_type = Key; + using mapped_type = T; + using value_type = typename std::conditional< + is_set, Key, + robin_hood::pair::type, T>>::type; + using size_type = size_t; + using hasher = Hash; + using key_equal = KeyEqual; + using Self = Table; + +private: + static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100, + "MaxLoadFactor100 needs to be >10 && < 100"); + + using WHash = WrapHash; + using WKeyEqual = WrapKeyEqual; + + // configuration defaults + + // make sure we have 8 elements, needed to quickly rehash mInfo + static constexpr size_t InitialNumElements = sizeof(uint64_t); + static constexpr uint32_t InitialInfoNumBits = 5; + static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits; + static constexpr size_t InfoMask = InitialInfoInc - 1U; + static constexpr uint8_t InitialInfoHashShift = 0; + using DataPool = detail::NodeAllocator; + + // type needs to be wider than uint8_t. + using InfoType = uint32_t; + + // DataNode //////////////////////////////////////////////////////// + + // Primary template for the data node. We have special implementations for small and big + // objects. For large objects it is assumed that swap() is fairly slow, so we allocate these + // on the heap so swap merely swaps a pointer. + template + class DataNode {}; + + // Small: just allocate on the stack. + template + class DataNode final { + public: + template + explicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept( + noexcept(value_type(std::forward(args)...))) + : mData(std::forward(args)...) {} + + DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode&& n) noexcept( + std::is_nothrow_move_constructible::value) + : mData(std::move(n.mData)) {} + + // doesn't do anything + void destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {} + void destroyDoNotDeallocate() noexcept {} + + value_type const* operator->() const noexcept { + return &mData; + } + value_type* operator->() noexcept { + return &mData; + } + + const value_type& operator*() const noexcept { + return mData; + } + + value_type& operator*() noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() noexcept { + return mData.first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type + getFirst() const noexcept { + return mData.first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() const noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getSecond() noexcept { + return mData.second; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getSecond() const noexcept { + return mData.second; + } + + void swap(DataNode& o) noexcept( + noexcept(std::declval().swap(std::declval()))) { + mData.swap(o.mData); + } + + private: + value_type mData; + }; + + // big object: allocate on heap. + template + class DataNode { + public: + template + explicit DataNode(M& map, Args&&... args) + : mData(map.allocate()) { + ::new (static_cast(mData)) value_type(std::forward(args)...); + } + + DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode&& n) noexcept + : mData(std::move(n.mData)) {} + + void destroy(M& map) noexcept { + // don't deallocate, just put it into list of datapool. + mData->~value_type(); + map.deallocate(mData); + } + + void destroyDoNotDeallocate() noexcept { + mData->~value_type(); + } + + value_type const* operator->() const noexcept { + return mData; + } + + value_type* operator->() noexcept { + return mData; + } + + const value_type& operator*() const { + return *mData; + } + + value_type& operator*() { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() noexcept { + return mData->first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() noexcept { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type + getFirst() const noexcept { + return mData->first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getFirst() const noexcept { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getSecond() noexcept { + return mData->second; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::type getSecond() const noexcept { + return mData->second; + } + + void swap(DataNode& o) noexcept { + using std::swap; + swap(mData, o.mData); + } + + private: + value_type* mData; + }; + + using Node = DataNode; + + // helpers for insertKeyPrepareEmptySpot: extract first entry (only const required) + ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept { + return n.getFirst(); + } + + // in case we have void mapped_type, we are not using a pair, thus we just route k through. + // No need to disable this because it's just not used if not applicable. + ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept { + return k; + } + + // in case we have non-void mapped_type, we have a standard robin_hood::pair + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, key_type const&>::type + getFirstConst(value_type const& vt) const noexcept { + return vt.first; + } + + // Cloner ////////////////////////////////////////////////////////// + + template + struct Cloner; + + // fast path: Just copy data, without allocating anything. + template + struct Cloner { + void operator()(M const& source, M& target) const { + auto const* const src = reinterpret_cast(source.mKeyVals); + auto* tgt = reinterpret_cast(target.mKeyVals); + auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1); + std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt); + } + }; + + template + struct Cloner { + void operator()(M const& s, M& t) const { + auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1); + std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo); + + for (size_t i = 0; i < numElementsWithBuffer; ++i) { + if (t.mInfo[i]) { + ::new (static_cast(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]); + } + } + } + }; + + // Destroyer /////////////////////////////////////////////////////// + + template + struct Destroyer {}; + + template + struct Destroyer { + void nodes(M& m) const noexcept { + m.mNumElements = 0; + } + + void nodesDoNotDeallocate(M& m) const noexcept { + m.mNumElements = 0; + } + }; + + template + struct Destroyer { + void nodes(M& m) const noexcept { + m.mNumElements = 0; + // clear also resets mInfo to 0, that's sometimes not necessary. + auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1); + + for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) { + if (0 != m.mInfo[idx]) { + Node& n = m.mKeyVals[idx]; + n.destroy(m); + n.~Node(); + } + } + } + + void nodesDoNotDeallocate(M& m) const noexcept { + m.mNumElements = 0; + // clear also resets mInfo to 0, that's sometimes not necessary. + auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1); + for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) { + if (0 != m.mInfo[idx]) { + Node& n = m.mKeyVals[idx]; + n.destroyDoNotDeallocate(); + n.~Node(); + } + } + } + }; + + // Iter //////////////////////////////////////////////////////////// + + struct fast_forward_tag {}; + + // generic iterator for both const_iterator and iterator. + template + // NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions) + class Iter { + private: + using NodePtr = typename std::conditional::type; + + public: + using difference_type = std::ptrdiff_t; + using value_type = typename Self::value_type; + using reference = typename std::conditional::type; + using pointer = typename std::conditional::type; + using iterator_category = std::forward_iterator_tag; + + // default constructed iterator can be compared to itself, but WON'T return true when + // compared to end(). + Iter() = default; + + // Rule of zero: nothing specified. The conversion constructor is only enabled for + // iterator to const_iterator, so it doesn't accidentally work as a copy ctor. + + // Conversion constructor from iterator to const_iterator. + template ::type> + // NOLINTNEXTLINE(hicpp-explicit-conversions) + Iter(Iter const& other) noexcept + : mKeyVals(other.mKeyVals) + , mInfo(other.mInfo) {} + + Iter(NodePtr valPtr, uint8_t const* infoPtr) noexcept + : mKeyVals(valPtr) + , mInfo(infoPtr) {} + + Iter(NodePtr valPtr, uint8_t const* infoPtr, + fast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept + : mKeyVals(valPtr) + , mInfo(infoPtr) { + fastForward(); + } + + template ::type> + Iter& operator=(Iter const& other) noexcept { + mKeyVals = other.mKeyVals; + mInfo = other.mInfo; + return *this; + } + + // prefix increment. Undefined behavior if we are at end()! + Iter& operator++() noexcept { + mInfo++; + mKeyVals++; + fastForward(); + return *this; + } + + Iter operator++(int) noexcept { + Iter tmp = *this; + ++(*this); + return tmp; + } + + reference operator*() const { + return **mKeyVals; + } + + pointer operator->() const { + return &**mKeyVals; + } + + template + bool operator==(Iter const& o) const noexcept { + return mKeyVals == o.mKeyVals; + } + + template + bool operator!=(Iter const& o) const noexcept { + return mKeyVals != o.mKeyVals; + } + + private: + // fast forward to the next non-free info byte + // I've tried a few variants that don't depend on intrinsics, but unfortunately they are + // quite a bit slower than this one. So I've reverted that change again. See map_benchmark. + void fastForward() noexcept { + size_t n = 0; + while (0U == (n = detail::unaligned_load(mInfo))) { + mInfo += sizeof(size_t); + mKeyVals += sizeof(size_t); + } +#if defined(ROBIN_HOOD_DISABLE_INTRINSICS) + // we know for certain that within the next 8 bytes we'll find a non-zero one. + if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load(mInfo))) { + mInfo += 4; + mKeyVals += 4; + } + if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load(mInfo))) { + mInfo += 2; + mKeyVals += 2; + } + if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) { + mInfo += 1; + mKeyVals += 1; + } +#else +# if ROBIN_HOOD(LITTLE_ENDIAN) + auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8; +# else + auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8; +# endif + mInfo += inc; + mKeyVals += inc; +#endif + } + + friend class Table; + NodePtr mKeyVals{nullptr}; + uint8_t const* mInfo{nullptr}; + }; + + //////////////////////////////////////////////////////////////////// + + // highly performance relevant code. + // Lower bits are used for indexing into the array (2^n size) + // The upper 1-5 bits need to be a reasonable good hash, to save comparisons. + template + void keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const { + // In addition to whatever hash is used, add another mul & shift so we get better hashing. + // This serves as a bad hash prevention, if the given data is + // badly mixed. + auto h = static_cast(WHash::operator()(key)); + + h *= mHashMultiplier; + h ^= h >> 33U; + + // the lower InitialInfoNumBits are reserved for info. + *info = mInfoInc + static_cast((h & InfoMask) >> mInfoHashShift); + *idx = (static_cast(h) >> InitialInfoNumBits) & mMask; + } + + // forwards the index by one, wrapping around at the end + void next(InfoType* info, size_t* idx) const noexcept { + *idx = *idx + 1; + *info += mInfoInc; + } + + void nextWhileLess(InfoType* info, size_t* idx) const noexcept { + // unrolling this by hand did not bring any speedups. + while (*info < mInfo[*idx]) { + next(info, idx); + } + } + + // Shift everything up by one element. Tries to move stuff around. + void + shiftUp(size_t startIdx, + size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable::value) { + auto idx = startIdx; + ::new (static_cast(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1])); + while (--idx != insertion_idx) { + mKeyVals[idx] = std::move(mKeyVals[idx - 1]); + } + + idx = startIdx; + while (idx != insertion_idx) { + ROBIN_HOOD_COUNT(shiftUp) + mInfo[idx] = static_cast(mInfo[idx - 1] + mInfoInc); + if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + --idx; + } + } + + void shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable::value) { + // until we find one that is either empty or has zero offset. + // TODO(martinus) we don't need to move everything, just the last one for the same + // bucket. + mKeyVals[idx].destroy(*this); + + // until we find one that is either empty or has zero offset. + while (mInfo[idx + 1] >= 2 * mInfoInc) { + ROBIN_HOOD_COUNT(shiftDown) + mInfo[idx] = static_cast(mInfo[idx + 1] - mInfoInc); + mKeyVals[idx] = std::move(mKeyVals[idx + 1]); + ++idx; + } + + mInfo[idx] = 0; + // don't destroy, we've moved it + // mKeyVals[idx].destroy(*this); + mKeyVals[idx].~Node(); + } + + // copy of find(), except that it returns iterator instead of const_iterator. + template + ROBIN_HOOD(NODISCARD) + size_t findIdx(Other const& key) const { + size_t idx{}; + InfoType info{}; + keyToIdx(key, &idx, &info); + + do { + // unrolling this twice gives a bit of a speedup. More unrolling did not help. + if (info == mInfo[idx] && + ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) { + return idx; + } + next(&info, &idx); + if (info == mInfo[idx] && + ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) { + return idx; + } + next(&info, &idx); + } while (info <= mInfo[idx]); + + // nothing found! + return mMask == 0 ? 0 + : static_cast(std::distance( + mKeyVals, reinterpret_cast_no_cast_align_warning(mInfo))); + } + + void cloneData(const Table& o) { + Cloner()(o, *this); + } + + // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized. + // @return True on success, false if something went wrong + void insert_move(Node&& keyval) { + // we don't retry, fail if overflowing + // don't need to check max num elements + if (0 == mMaxNumElementsAllowed && !try_increase_info()) { + throwOverflowError(); + } + + size_t idx{}; + InfoType info{}; + keyToIdx(keyval.getFirst(), &idx, &info); + + // skip forward. Use <= because we are certain that the element is not there. + while (info <= mInfo[idx]) { + idx = idx + 1; + info += mInfoInc; + } + + // key not found, so we are now exactly where we want to insert it. + auto const insertion_idx = idx; + auto const insertion_info = static_cast(info); + if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + + // find an empty spot + while (0 != mInfo[idx]) { + next(&info, &idx); + } + + auto& l = mKeyVals[insertion_idx]; + if (idx == insertion_idx) { + ::new (static_cast(&l)) Node(std::move(keyval)); + } else { + shiftUp(idx, insertion_idx); + l = std::move(keyval); + } + + // put at empty spot + mInfo[insertion_idx] = insertion_info; + + ++mNumElements; + } + +public: + using iterator = Iter; + using const_iterator = Iter; + + Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual())) + : WHash() + , WKeyEqual() { + ROBIN_HOOD_TRACE(this) + } + + // Creates an empty hash map. Nothing is allocated yet, this happens at the first insert. + // This tremendously speeds up ctor & dtor of a map that never receives an element. The + // penalty is payed at the first insert, and not before. Lookup of this empty map works + // because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the + // standard, but we can ignore it. + explicit Table( + size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{}, + const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal))) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this) + } + + template + Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, + const Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{}) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this) + insert(first, last); + } + + Table(std::initializer_list initlist, + size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{}, + const KeyEqual& equal = KeyEqual{}) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this) + insert(initlist.begin(), initlist.end()); + } + + Table(Table&& o) noexcept + : WHash(std::move(static_cast(o))) + , WKeyEqual(std::move(static_cast(o))) + , DataPool(std::move(static_cast(o))) { + ROBIN_HOOD_TRACE(this) + if (o.mMask) { + mHashMultiplier = std::move(o.mHashMultiplier); + mKeyVals = std::move(o.mKeyVals); + mInfo = std::move(o.mInfo); + mNumElements = std::move(o.mNumElements); + mMask = std::move(o.mMask); + mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed); + mInfoInc = std::move(o.mInfoInc); + mInfoHashShift = std::move(o.mInfoHashShift); + // set other's mask to 0 so its destructor won't do anything + o.init(); + } + } + + Table& operator=(Table&& o) noexcept { + ROBIN_HOOD_TRACE(this) + if (&o != this) { + if (o.mMask) { + // only move stuff if the other map actually has some data + destroy(); + mHashMultiplier = std::move(o.mHashMultiplier); + mKeyVals = std::move(o.mKeyVals); + mInfo = std::move(o.mInfo); + mNumElements = std::move(o.mNumElements); + mMask = std::move(o.mMask); + mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed); + mInfoInc = std::move(o.mInfoInc); + mInfoHashShift = std::move(o.mInfoHashShift); + WHash::operator=(std::move(static_cast(o))); + WKeyEqual::operator=(std::move(static_cast(o))); + DataPool::operator=(std::move(static_cast(o))); + + o.init(); + + } else { + // nothing in the other map => just clear us. + clear(); + } + } + return *this; + } + + Table(const Table& o) + : WHash(static_cast(o)) + , WKeyEqual(static_cast(o)) + , DataPool(static_cast(o)) { + ROBIN_HOOD_TRACE(this) + if (!o.empty()) { + // not empty: create an exact copy. it is also possible to just iterate through all + // elements and insert them, but copying is probably faster. + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1); + auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer); + + ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal(" + << numElementsWithBuffer << ")") + mHashMultiplier = o.mHashMultiplier; + mKeyVals = static_cast( + detail::assertNotNull(std::malloc(numBytesTotal))); + // no need for calloc because clonData does memcpy + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + mNumElements = o.mNumElements; + mMask = o.mMask; + mMaxNumElementsAllowed = o.mMaxNumElementsAllowed; + mInfoInc = o.mInfoInc; + mInfoHashShift = o.mInfoHashShift; + cloneData(o); + } + } + + // Creates a copy of the given map. Copy constructor of each entry is used. + // Not sure why clang-tidy thinks this doesn't handle self assignment, it does + // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp) + Table& operator=(Table const& o) { + ROBIN_HOOD_TRACE(this) + if (&o == this) { + // prevent assigning of itself + return *this; + } + + // we keep using the old allocator and not assign the new one, because we want to keep + // the memory available. when it is the same size. + if (o.empty()) { + if (0 == mMask) { + // nothing to do, we are empty too + return *this; + } + + // not empty: destroy what we have there + // clear also resets mInfo to 0, that's sometimes not necessary. + destroy(); + init(); + WHash::operator=(static_cast(o)); + WKeyEqual::operator=(static_cast(o)); + DataPool::operator=(static_cast(o)); + + return *this; + } + + // clean up old stuff + Destroyer::value>{}.nodes(*this); + + if (mMask != o.mMask) { + // no luck: we don't have the same array size allocated, so we need to realloc. + if (0 != mMask) { + // only deallocate if we actually have data! + ROBIN_HOOD_LOG("std::free") + std::free(mKeyVals); + } + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1); + auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer); + ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal(" + << numElementsWithBuffer << ")") + mKeyVals = static_cast( + detail::assertNotNull(std::malloc(numBytesTotal))); + + // no need for calloc here because cloneData performs a memcpy. + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + // sentinel is set in cloneData + } + WHash::operator=(static_cast(o)); + WKeyEqual::operator=(static_cast(o)); + DataPool::operator=(static_cast(o)); + mHashMultiplier = o.mHashMultiplier; + mNumElements = o.mNumElements; + mMask = o.mMask; + mMaxNumElementsAllowed = o.mMaxNumElementsAllowed; + mInfoInc = o.mInfoInc; + mInfoHashShift = o.mInfoHashShift; + cloneData(o); + + return *this; + } + + // Swaps everything between the two maps. + void swap(Table& o) { + ROBIN_HOOD_TRACE(this) + using std::swap; + swap(o, *this); + } + + // Clears all data, without resizing. + void clear() { + ROBIN_HOOD_TRACE(this) + if (empty()) { + // don't do anything! also important because we don't want to write to + // DummyInfoByte::b, even though we would just write 0 to it. + return; + } + + Destroyer::value>{}.nodes(*this); + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + // clear everything, then set the sentinel again + uint8_t const z = 0; + std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z); + mInfo[numElementsWithBuffer] = 1; + + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + // Destroys the map and all it's contents. + ~Table() { + ROBIN_HOOD_TRACE(this) + destroy(); + } + + // Checks if both tables contain the same entries. Order is irrelevant. + bool operator==(const Table& other) const { + ROBIN_HOOD_TRACE(this) + if (other.size() != size()) { + return false; + } + for (auto const& otherEntry : other) { + if (!has(otherEntry)) { + return false; + } + } + + return true; + } + + bool operator!=(const Table& other) const { + ROBIN_HOOD_TRACE(this) + return !operator==(other); + } + + template + typename std::enable_if::value, Q&>::type operator[](const key_type& key) { + ROBIN_HOOD_TRACE(this) + auto idxAndState = insertKeyPrepareEmptySpot(key); + switch (idxAndState.second) { + case InsertionState::key_found: + break; + + case InsertionState::new_node: + ::new (static_cast(&mKeyVals[idxAndState.first])) + Node(*this, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple()); + break; + + case InsertionState::overwrite_node: + mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct, + std::forward_as_tuple(key), std::forward_as_tuple()); + break; + + case InsertionState::overflow_error: + throwOverflowError(); + } + + return mKeyVals[idxAndState.first].getSecond(); + } + + template + typename std::enable_if::value, Q&>::type operator[](key_type&& key) { + ROBIN_HOOD_TRACE(this) + auto idxAndState = insertKeyPrepareEmptySpot(key); + switch (idxAndState.second) { + case InsertionState::key_found: + break; + + case InsertionState::new_node: + ::new (static_cast(&mKeyVals[idxAndState.first])) + Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)), + std::forward_as_tuple()); + break; + + case InsertionState::overwrite_node: + mKeyVals[idxAndState.first] = + Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)), + std::forward_as_tuple()); + break; + + case InsertionState::overflow_error: + throwOverflowError(); + } + + return mKeyVals[idxAndState.first].getSecond(); + } + + template + void insert(Iter first, Iter last) { + for (; first != last; ++first) { + // value_type ctor needed because this might be called with std::pair's + insert(value_type(*first)); + } + } + + void insert(std::initializer_list ilist) { + for (auto&& vt : ilist) { + insert(std::move(vt)); + } + } + + template + std::pair emplace(Args&&... args) { + ROBIN_HOOD_TRACE(this) + Node n{*this, std::forward(args)...}; + auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n)); + switch (idxAndState.second) { + case InsertionState::key_found: + n.destroy(*this); + break; + + case InsertionState::new_node: + ::new (static_cast(&mKeyVals[idxAndState.first])) Node(*this, std::move(n)); + break; + + case InsertionState::overwrite_node: + mKeyVals[idxAndState.first] = std::move(n); + break; + + case InsertionState::overflow_error: + n.destroy(*this); + throwOverflowError(); + break; + } + + return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first), + InsertionState::key_found != idxAndState.second); + } + + template + iterator emplace_hint(const_iterator position, Args&&... args) { + (void)position; + return emplace(std::forward(args)...).first; + } + + template + std::pair try_emplace(const key_type& key, Args&&... args) { + return try_emplace_impl(key, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& key, Args&&... args) { + return try_emplace_impl(std::move(key), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& key, Args&&... args) { + (void)hint; + return try_emplace_impl(key, std::forward(args)...).first; + } + + template + iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) { + (void)hint; + return try_emplace_impl(std::move(key), std::forward(args)...).first; + } + + template + std::pair insert_or_assign(const key_type& key, Mapped&& obj) { + return insertOrAssignImpl(key, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& key, Mapped&& obj) { + return insertOrAssignImpl(std::move(key), std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, const key_type& key, Mapped&& obj) { + (void)hint; + return insertOrAssignImpl(key, std::forward(obj)).first; + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) { + (void)hint; + return insertOrAssignImpl(std::move(key), std::forward(obj)).first; + } + + std::pair insert(const value_type& keyval) { + ROBIN_HOOD_TRACE(this) + return emplace(keyval); + } + + iterator insert(const_iterator hint, const value_type& keyval) { + (void)hint; + return emplace(keyval).first; + } + + std::pair insert(value_type&& keyval) { + return emplace(std::move(keyval)); + } + + iterator insert(const_iterator hint, value_type&& keyval) { + (void)hint; + return emplace(std::move(keyval)).first; + } + + // Returns 1 if key is found, 0 otherwise. + size_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + auto kv = mKeyVals + findIdx(key); + if (kv != reinterpret_cast_no_cast_align_warning(mInfo)) { + return 1; + } + return 0; + } + + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::type count(const OtherKey& key) const { + ROBIN_HOOD_TRACE(this) + auto kv = mKeyVals + findIdx(key); + if (kv != reinterpret_cast_no_cast_align_warning(mInfo)) { + return 1; + } + return 0; + } + + bool contains(const key_type& key) const { // NOLINT(modernize-use-nodiscard) + return 1U == count(key); + } + + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::type contains(const OtherKey& key) const { + return 1U == count(key); + } + + // Returns a reference to the value found for key. + // Throws std::out_of_range if element cannot be found + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::value, Q&>::type at(key_type const& key) { + ROBIN_HOOD_TRACE(this) + auto kv = mKeyVals + findIdx(key); + if (kv == reinterpret_cast_no_cast_align_warning(mInfo)) { + doThrow("key not found"); + } + return kv->getSecond(); + } + + // Returns a reference to the value found for key. + // Throws std::out_of_range if element cannot be found + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::value, Q const&>::type at(key_type const& key) const { + ROBIN_HOOD_TRACE(this) + auto kv = mKeyVals + findIdx(key); + if (kv == reinterpret_cast_no_cast_align_warning(mInfo)) { + doThrow("key not found"); + } + return kv->getSecond(); + } + + const_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return const_iterator{mKeyVals + idx, mInfo + idx}; + } + + template + const_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const { + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return const_iterator{mKeyVals + idx, mInfo + idx}; + } + + template + typename std::enable_if::type // NOLINT(modernize-use-nodiscard) + find(const OtherKey& key) const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return const_iterator{mKeyVals + idx, mInfo + idx}; + } + + iterator find(const key_type& key) { + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return iterator{mKeyVals + idx, mInfo + idx}; + } + + template + iterator find(const OtherKey& key, is_transparent_tag /*unused*/) { + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return iterator{mKeyVals + idx, mInfo + idx}; + } + + template + typename std::enable_if::type find(const OtherKey& key) { + ROBIN_HOOD_TRACE(this) + const size_t idx = findIdx(key); + return iterator{mKeyVals + idx, mInfo + idx}; + } + + iterator begin() { + ROBIN_HOOD_TRACE(this) + if (empty()) { + return end(); + } + return iterator(mKeyVals, mInfo, fast_forward_tag{}); + } + const_iterator begin() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return cbegin(); + } + const_iterator cbegin() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + if (empty()) { + return cend(); + } + return const_iterator(mKeyVals, mInfo, fast_forward_tag{}); + } + + iterator end() { + ROBIN_HOOD_TRACE(this) + // no need to supply valid info pointer: end() must not be dereferenced, and only node + // pointer is compared. + return iterator{reinterpret_cast_no_cast_align_warning(mInfo), nullptr}; + } + const_iterator end() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return cend(); + } + const_iterator cend() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return const_iterator{reinterpret_cast_no_cast_align_warning(mInfo), nullptr}; + } + + iterator erase(const_iterator pos) { + ROBIN_HOOD_TRACE(this) + // its safe to perform const cast here + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + return erase(iterator{const_cast(pos.mKeyVals), const_cast(pos.mInfo)}); + } + + // Erases element at pos, returns iterator to the next element. + iterator erase(iterator pos) { + ROBIN_HOOD_TRACE(this) + // we assume that pos always points to a valid entry, and not end(). + auto const idx = static_cast(pos.mKeyVals - mKeyVals); + + shiftDown(idx); + --mNumElements; + + if (*pos.mInfo) { + // we've backward shifted, return this again + return pos; + } + + // no backward shift, return next element + return ++pos; + } + + size_t erase(const key_type& key) { + ROBIN_HOOD_TRACE(this) + size_t idx{}; + InfoType info{}; + keyToIdx(key, &idx, &info); + + // check while info matches with the source idx + do { + if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) { + shiftDown(idx); + --mNumElements; + return 1; + } + next(&info, &idx); + } while (info <= mInfo[idx]); + + // nothing found to delete + return 0; + } + + // reserves space for the specified number of elements. Makes sure the old data fits. + // exactly the same as reserve(c). + void rehash(size_t c) { + // forces a reserve + reserve(c, true); + } + + // reserves space for the specified number of elements. Makes sure the old data fits. + // Exactly the same as rehash(c). Use rehash(0) to shrink to fit. + void reserve(size_t c) { + // reserve, but don't force rehash + reserve(c, false); + } + + // If possible reallocates the map to a smaller one. This frees the underlying table. + // Does not do anything if load_factor is too large for decreasing the table's size. + void compact() { + ROBIN_HOOD_TRACE(this) + auto newSize = InitialNumElements; + while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) { + newSize *= 2; + } + if (ROBIN_HOOD_UNLIKELY(newSize == 0)) { + throwOverflowError(); + } + + ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1") + + // only actually do anything when the new size is bigger than the old one. This prevents to + // continuously allocate for each reserve() call. + if (newSize < mMask + 1) { + rehashPowerOfTwo(newSize, true); + } + } + + size_type size() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return mNumElements; + } + + size_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return static_cast(-1); + } + + ROBIN_HOOD(NODISCARD) bool empty() const noexcept { + ROBIN_HOOD_TRACE(this) + return 0 == mNumElements; + } + + float max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return MaxLoadFactor100 / 100.0F; + } + + // Average number of elements per bucket. Since we allow only 1 per bucket + float load_factor() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this) + return static_cast(size()) / static_cast(mMask + 1); + } + + ROBIN_HOOD(NODISCARD) size_t mask() const noexcept { + ROBIN_HOOD_TRACE(this) + return mMask; + } + + ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept { + if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits::max)() / 100)) { + return maxElements * MaxLoadFactor100 / 100; + } + + // we might be a bit inprecise, but since maxElements is quite large that doesn't matter + return (maxElements / 100) * MaxLoadFactor100; + } + + ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept { + // we add a uint64_t, which houses the sentinel (first byte) and padding so we can load + // 64bit types. + return numElements + sizeof(uint64_t); + } + + ROBIN_HOOD(NODISCARD) + size_t calcNumElementsWithBuffer(size_t numElements) const noexcept { + auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements); + return numElements + (std::min)(maxNumElementsAllowed, (static_cast(0xFF))); + } + + // calculation only allowed for 2^n values + ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const { +#if ROBIN_HOOD(BITNESS) == 64 + return numElements * sizeof(Node) + calcNumBytesInfo(numElements); +#else + // make sure we're doing 64bit operations, so we are at least safe against 32bit overflows. + auto const ne = static_cast(numElements); + auto const s = static_cast(sizeof(Node)); + auto const infos = static_cast(calcNumBytesInfo(numElements)); + + auto const total64 = ne * s + infos; + auto const total = static_cast(total64); + + if (ROBIN_HOOD_UNLIKELY(static_cast(total) != total64)) { + throwOverflowError(); + } + return total; +#endif + } + +private: + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, bool>::type has(const value_type& e) const { + ROBIN_HOOD_TRACE(this) + auto it = find(e.first); + return it != end() && it->second == e.second; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, bool>::type has(const value_type& e) const { + ROBIN_HOOD_TRACE(this) + return find(e) != end(); + } + + void reserve(size_t c, bool forceRehash) { + ROBIN_HOOD_TRACE(this) + auto const minElementsAllowed = (std::max)(c, mNumElements); + auto newSize = InitialNumElements; + while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) { + newSize *= 2; + } + if (ROBIN_HOOD_UNLIKELY(newSize == 0)) { + throwOverflowError(); + } + + ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1") + + // only actually do anything when the new size is bigger than the old one. This prevents to + // continuously allocate for each reserve() call. + if (forceRehash || newSize > mMask + 1) { + rehashPowerOfTwo(newSize, false); + } + } + + // reserves space for at least the specified number of elements. + // only works if numBuckets if power of two + // True on success, false otherwise + void rehashPowerOfTwo(size_t numBuckets, bool forceFree) { + ROBIN_HOOD_TRACE(this) + + Node* const oldKeyVals = mKeyVals; + uint8_t const* const oldInfo = mInfo; + + const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + + // resize operation: move stuff + initData(numBuckets); + if (oldMaxElementsWithBuffer > 1) { + for (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) { + if (oldInfo[i] != 0) { + // might throw an exception, which is really bad since we are in the middle of + // moving stuff. + insert_move(std::move(oldKeyVals[i])); + // destroy the node but DON'T destroy the data. + oldKeyVals[i].~Node(); + } + } + + // this check is not necessary as it's guarded by the previous if, but it helps + // silence g++'s overeager "attempt to free a non-heap object 'map' + // [-Werror=free-nonheap-object]" warning. + if (oldKeyVals != reinterpret_cast_no_cast_align_warning(&mMask)) { + // don't destroy old data: put it into the pool instead + if (forceFree) { + std::free(oldKeyVals); + } else { + DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer)); + } + } + } + } + + ROBIN_HOOD(NOINLINE) void throwOverflowError() const { +#if ROBIN_HOOD(HAS_EXCEPTIONS) + throw std::overflow_error("robin_hood::map overflow"); +#else + abort(); +#endif + } + + template + std::pair try_emplace_impl(OtherKey&& key, Args&&... args) { + ROBIN_HOOD_TRACE(this) + auto idxAndState = insertKeyPrepareEmptySpot(key); + switch (idxAndState.second) { + case InsertionState::key_found: + break; + + case InsertionState::new_node: + ::new (static_cast(&mKeyVals[idxAndState.first])) Node( + *this, std::piecewise_construct, std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); + break; + + case InsertionState::overwrite_node: + mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); + break; + + case InsertionState::overflow_error: + throwOverflowError(); + break; + } + + return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first), + InsertionState::key_found != idxAndState.second); + } + + template + std::pair insertOrAssignImpl(OtherKey&& key, Mapped&& obj) { + ROBIN_HOOD_TRACE(this) + auto idxAndState = insertKeyPrepareEmptySpot(key); + switch (idxAndState.second) { + case InsertionState::key_found: + mKeyVals[idxAndState.first].getSecond() = std::forward(obj); + break; + + case InsertionState::new_node: + ::new (static_cast(&mKeyVals[idxAndState.first])) Node( + *this, std::piecewise_construct, std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(obj))); + break; + + case InsertionState::overwrite_node: + mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(obj))); + break; + + case InsertionState::overflow_error: + throwOverflowError(); + break; + } + + return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first), + InsertionState::key_found != idxAndState.second); + } + + void initData(size_t max_elements) { + mNumElements = 0; + mMask = max_elements - 1; + mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements); + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements); + + // malloc & zero mInfo. Faster than calloc everything. + auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer); + ROBIN_HOOD_LOG("std::calloc " << numBytesTotal << " = calcNumBytesTotal(" + << numElementsWithBuffer << ")") + mKeyVals = reinterpret_cast( + detail::assertNotNull(std::malloc(numBytesTotal))); + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer * sizeof(Node)); + + // set sentinel + mInfo[numElementsWithBuffer] = 1; + + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + enum class InsertionState { overflow_error, key_found, new_node, overwrite_node }; + + // Finds key, and if not already present prepares a spot where to pot the key & value. + // This potentially shifts nodes out of the way, updates mInfo and number of inserted + // elements, so the only operation left to do is create/assign a new node at that spot. + template + std::pair insertKeyPrepareEmptySpot(OtherKey&& key) { + for (int i = 0; i < 256; ++i) { + size_t idx{}; + InfoType info{}; + keyToIdx(key, &idx, &info); + nextWhileLess(&info, &idx); + + // while we potentially have a match + while (info == mInfo[idx]) { + if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) { + // key already exists, do NOT insert. + // see http://en.cppreference.com/w/cpp/container/unordered_map/insert + return std::make_pair(idx, InsertionState::key_found); + } + next(&info, &idx); + } + + // unlikely that this evaluates to true + if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) { + if (!increase_size()) { + return std::make_pair(size_t(0), InsertionState::overflow_error); + } + continue; + } + + // key not found, so we are now exactly where we want to insert it. + auto const insertion_idx = idx; + auto const insertion_info = info; + if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + + // find an empty spot + while (0 != mInfo[idx]) { + next(&info, &idx); + } + + if (idx != insertion_idx) { + shiftUp(idx, insertion_idx); + } + // put at empty spot + mInfo[insertion_idx] = static_cast(insertion_info); + ++mNumElements; + return std::make_pair(insertion_idx, idx == insertion_idx + ? InsertionState::new_node + : InsertionState::overwrite_node); + } + + // enough attempts failed, so finally give up. + return std::make_pair(size_t(0), InsertionState::overflow_error); + } + + bool try_increase_info() { + ROBIN_HOOD_LOG("mInfoInc=" << mInfoInc << ", numElements=" << mNumElements + << ", maxNumElementsAllowed=" + << calcMaxNumElementsAllowed(mMask + 1)) + if (mInfoInc <= 2) { + // need to be > 2 so that shift works (otherwise undefined behavior!) + return false; + } + // we got space left, try to make info smaller + mInfoInc = static_cast(mInfoInc >> 1U); + + // remove one bit of the hash, leaving more space for the distance info. + // This is extremely fast because we can operate on 8 bytes at once. + ++mInfoHashShift; + auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + + for (size_t i = 0; i < numElementsWithBuffer; i += 8) { + auto val = unaligned_load(mInfo + i); + val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f); + std::memcpy(mInfo + i, &val, sizeof(val)); + } + // update sentinel, which might have been cleared out! + mInfo[numElementsWithBuffer] = 1; + + mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1); + return true; + } + + // True if resize was possible, false otherwise + bool increase_size() { + // nothing allocated yet? just allocate InitialNumElements + if (0 == mMask) { + initData(InitialNumElements); + return true; + } + + auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1); + if (mNumElements < maxNumElementsAllowed && try_increase_info()) { + return true; + } + + ROBIN_HOOD_LOG("mNumElements=" << mNumElements << ", maxNumElementsAllowed=" + << maxNumElementsAllowed << ", load=" + << (static_cast(mNumElements) * 100.0 / + (static_cast(mMask) + 1))) + + if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) { + // we have to resize, even though there would still be plenty of space left! + // Try to rehash instead. Delete freed memory so we don't steadyily increase mem in case + // we have to rehash a few times + nextHashMultiplier(); + rehashPowerOfTwo(mMask + 1, true); + } else { + // we've reached the capacity of the map, so the hash seems to work nice. Keep using it. + rehashPowerOfTwo((mMask + 1) * 2, false); + } + return true; + } + + void nextHashMultiplier() { + // adding an *even* number, so that the multiplier will always stay odd. This is necessary + // so that the hash stays a mixing function (and thus doesn't have any information loss). + mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54); + } + + void destroy() { + if (0 == mMask) { + // don't deallocate! + return; + } + + Destroyer::value>{} + .nodesDoNotDeallocate(*this); + + // This protection against not deleting mMask shouldn't be needed as it's sufficiently + // protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise + // reports a compile error: attempt to free a non-heap object 'fm' + // [-Werror=free-nonheap-object] + if (mKeyVals != reinterpret_cast_no_cast_align_warning(&mMask)) { + ROBIN_HOOD_LOG("std::free") + std::free(mKeyVals); + } + } + + void init() noexcept { + mKeyVals = reinterpret_cast_no_cast_align_warning(&mMask); + mInfo = reinterpret_cast(&mMask); + mNumElements = 0; + mMask = 0; + mMaxNumElementsAllowed = 0; + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + // members are sorted so no padding occurs + uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53); // 8 byte 8 + Node* mKeyVals = reinterpret_cast_no_cast_align_warning(&mMask); // 8 byte 16 + uint8_t* mInfo = reinterpret_cast(&mMask); // 8 byte 24 + size_t mNumElements = 0; // 8 byte 32 + size_t mMask = 0; // 8 byte 40 + size_t mMaxNumElementsAllowed = 0; // 8 byte 48 + InfoType mInfoInc = InitialInfoInc; // 4 byte 52 + InfoType mInfoHashShift = InitialInfoHashShift; // 4 byte 56 + // 16 byte 56 if NodeAllocator +}; + +} // namespace detail + +// map + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_flat_map = detail::Table; + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_node_map = detail::Table; + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_map = + detail::Table) <= sizeof(size_t) * 6 && + std::is_nothrow_move_constructible>::value && + std::is_nothrow_move_assignable>::value, + MaxLoadFactor100, Key, T, Hash, KeyEqual>; + +// set + +template , typename KeyEqual = std::equal_to, + size_t MaxLoadFactor100 = 80> +using unordered_flat_set = detail::Table; + +template , typename KeyEqual = std::equal_to, + size_t MaxLoadFactor100 = 80> +using unordered_node_set = detail::Table; + +template , typename KeyEqual = std::equal_to, + size_t MaxLoadFactor100 = 80> +using unordered_set = detail::Table::value && + std::is_nothrow_move_assignable::value, + MaxLoadFactor100, Key, void, Hash, KeyEqual>; + +} // namespace robin_hood + +#endif From a59db17c87851dd6c849b50a51a7839626902fea Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 16 Jan 2024 20:43:38 +0200 Subject: [PATCH 161/212] - some blp viewing for fileviewer - experiments on different container on a frequently allocated vectors --- src/ui/FrontendUI.cpp | 15 +- src/ui/FrontendUI.h | 1 + src/ui/childWindow/BLPViewer.cpp | 4 +- src/ui/childWindow/BLPViewer.h | 1 + .../fileListWindow/FileListWindow.cpp | 11 +- .../fileListWindow/FileListWindow.h | 2 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 2 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 + wowViewerLib/CMakeLists.txt | 4 +- .../src/engine/algorithms/grahamScan.cpp | 2 +- .../src/engine/algorithms/grahamScan.h | 5 +- .../src/engine/algorithms/mathHelper.cpp | 45 +- .../src/engine/algorithms/mathHelper.h | 25 +- .../algorithms/mathHelper_culling_sse.h | 6 +- .../FrameBasedHeapAllocator.cpp | 127 -- .../FrameBasedHeapAllocator.h | 82 - .../FrameBasedStackAllocator.cpp | 116 +- .../FrameBasedStackAllocator.h | 54 +- .../src/engine/managers/CRibbonEmitter.cpp | 2 +- .../src/engine/managers/CRibbonEmitter.h | 2 +- .../managers/particles/particleEmitter.cpp | 2 +- .../managers/particles/particleEmitter.h | 2 +- .../src/engine/objects/SceneObjectWithID.h | 10 +- .../src/engine/objects/ViewsObjects.cpp | 6 +- .../src/engine/objects/ViewsObjects.h | 10 +- .../src/engine/objects/adt/adtObject.cpp | 2 +- .../src/engine/objects/adt/adtObject.h | 2 +- wowViewerLib/src/engine/objects/iWmoApi.h | 1 + .../engine/objects/liquid/LiquidInstance.cpp | 3 +- .../engine/objects/liquid/LiquidInstance.h | 3 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 8 +- .../objects/scenes/EntityActorsFactory.h | 61 +- .../src/engine/objects/scenes/map.cpp | 4 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.h | 5 +- .../src/engine/objects/wmo/wmoObject.cpp | 26 +- .../src/engine/objects/wmo/wmoObject.h | 10 +- .../src/engine/shader/ShaderDefinitions.h | 1446 ++++++++--------- .../src/gapi/interface/meshes/IMesh.h | 7 +- .../src/gapi/vulkan/meshes/GMeshVLK.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 4 +- .../src/renderer/mapScene/MapSceneRenderer.h | 4 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 28 +- .../vulkan/MapSceneRenderForwardVLK.h | 3 + .../vulkan/MapSceneRenderVisBufferVLK.cpp | 39 +- .../vulkan/MapSceneRenderVisBufferVLK.h | 3 + 47 files changed, 955 insertions(+), 1249 deletions(-) delete mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp delete mode 100644 wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index de10c54f8..3741cc75f 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -134,6 +134,7 @@ void FrontendUI::composeUI() { showCurrentStatsDialog(); showMinimapGenerationSettingsDialog(); showBlpViewer(); + if (m_debugRenderWindow) m_debugRenderWindow->draw(); @@ -361,11 +362,13 @@ void FrontendUI::showBlpViewer() { } void FrontendUI::showFileList() { - if (!m_fileListWindow) return; - - if (!m_fileListWindow->draw()) { + if (m_fileListWindow && !m_fileListWindow->draw()) { m_fileListWindow = nullptr; } + + if (m_blpFileViewerWindow && !m_blpFileViewerWindow->draw()) { + m_blpFileViewerWindow = nullptr; + } } @@ -767,8 +770,10 @@ void FrontendUI::showMainMenu() { if (!m_fileListWindow) m_fileListWindow = std::make_shared(m_api, [&](int fileId, const std::string &fileType){ if (fileType == "blp") { - m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer, true); - m_blpViewerWindow->loadBlp(std::to_string(fileId)); + if (m_blpFileViewerWindow == nullptr) + m_blpFileViewerWindow = std::make_shared(m_api, m_uiRenderer, true); + + m_blpFileViewerWindow->loadBlp(std::to_string(fileId)); } }); } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 62360e6ba..f7fafae30 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -194,6 +194,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_minimapGenerationWindow = nullptr; std::shared_ptr m_blpViewerWindow = nullptr; + std::shared_ptr m_blpFileViewerWindow = nullptr; std::shared_ptr m_fileListWindow = nullptr; std::shared_ptr m_debugRenderWindow; diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index cffde25f8..f6fb82149 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -7,14 +7,14 @@ #include BLPViewer::BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer, bool noSearch) : - m_api(api), m_uiRenderer(uiRenderer), m_noSearch(noSearch) + m_api(api), m_uiRenderer(uiRenderer), m_noSearch(noSearch), windowName(std::string("BLP Viewer")+(noSearch ? "_no_search" : "")) { } bool BLPViewer::draw() { - ImGui::Begin("BLP Viewer", &m_showWindow); + ImGui::Begin(windowName.c_str(), &m_showWindow); { if (!m_noSearch) { if (ImGui::InputText("BlpName/FileDataId: ", blpName.data(), blpName.size() - 1)) { diff --git a/src/ui/childWindow/BLPViewer.h b/src/ui/childWindow/BLPViewer.h index cf37c3a05..ed44c4cd9 100644 --- a/src/ui/childWindow/BLPViewer.h +++ b/src/ui/childWindow/BLPViewer.h @@ -29,6 +29,7 @@ class BLPViewer { std::shared_ptr material = nullptr; bool m_noSearch; + std::string windowName; }; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 902e21636..2b816178d 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -247,10 +247,14 @@ class FileListLambdaInst : public FileListLamda { FileListLambdaInst(const HApiContainer &api, std::string &searchClause, int &recordsTotal) : m_recordsTotal(recordsTotal), m_api(api) { dbThread = std::thread([&]() { - decltype(FileListDB::makeStorage("")) storage = FileListDB::makeStorage("fileList.db3"); + decltype(FileListDB::makeStorage("")) storage = FileListDB::makeStorage(":memory:"); + storage.pragma.synchronous(0); storage.pragma.journal_mode(sqlite_orm::journal_mode::MEMORY); + const std::string fileListDB = "fileList.db3"; + storage.backup_from(fileListDB); + storage.sync_schema(); std::unique_ptr statement = statementFactory(storage, searchClause, 1); @@ -295,6 +299,8 @@ class FileListLambdaInst : public FileListLamda { setResults(results); }); } + + storage.backup_to(fileListDB); }); } ~FileListLambdaInst() { @@ -480,9 +486,10 @@ bool FileListWindow::draw() { auto const &fileItem = dbResult.records[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (ImGui::Selectable(std::to_string(fileItem.fileDataId).c_str(), false, + if (ImGui::Selectable(std::to_string(fileItem.fileDataId).c_str(), lastSelectedFiledataId == fileItem.fileDataId, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { + lastSelectedFiledataId = fileItem.fileDataId; if (m_fileOpenCallback) { if (endsWith(fileItem.fileName, ".blp")) { m_fileOpenCallback(fileItem.fileDataId, "blp"); diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index b0266c416..bbe1779a8 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -54,6 +54,8 @@ class FileListWindow { std::unique_ptr selectStatement; std::array filterText = {0}; std::string filterTextStr = "%%"; + + int lastSelectedFiledataId = -1; private: void importCSV(); }; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index db79b3072..3c13d8aef 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -81,7 +81,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const } HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); + return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } std::unique_ptr FrontendUIRenderForwardVLK::update( diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index adabfca21..0696a13db 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -14,6 +14,7 @@ #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" #include "../../../../../wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h" +#include "../../../../../wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: @@ -33,6 +34,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { private: HGDeviceVLK m_device; + std::shared_ptr> meshFactory = std::make_shared>(); std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator //and seed it with entropy. diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index ec50bf5c3..f72382afd 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -368,8 +368,7 @@ set(SOURCE_FILES src/engine/objects/SceneObjectWithID.h src/engine/custom_allocators/FrameBasedStackAllocator.cpp src/engine/custom_allocators/FrameBasedStackAllocator.h - src/engine/custom_allocators/FrameBasedHeapAllocator.cpp - src/engine/custom_allocators/FrameBasedHeapAllocator.h) +) if (LINK_OGL2) set(OPENGL20_IMPLEMENTATION @@ -720,6 +719,7 @@ endif() target_link_libraries(WoWViewerLib ${GLEW_LIBRARIES}) target_link_libraries(WoWViewerLib TBB::tbb ) +target_link_libraries(WoWViewerLib TBB::tbbmalloc ) if (UNIX AND NOT EMSCRIPTEN) target_link_libraries(WoWViewerLib Threads::Threads) endif() diff --git a/wowViewerLib/src/engine/algorithms/grahamScan.cpp b/wowViewerLib/src/engine/algorithms/grahamScan.cpp index 633a26907..fbc8c2cda 100644 --- a/wowViewerLib/src/engine/algorithms/grahamScan.cpp +++ b/wowViewerLib/src/engine/algorithms/grahamScan.cpp @@ -68,7 +68,7 @@ Point nextToTop(stack &S) return res; } -stack grahamScan(std::vector &points) { +stack grahamScan(framebased::vector &points) { stack hull; // Find the bottommost point float ymin = points[0].y; diff --git a/wowViewerLib/src/engine/algorithms/grahamScan.h b/wowViewerLib/src/engine/algorithms/grahamScan.h index 4a7312c25..09b86a28b 100644 --- a/wowViewerLib/src/engine/algorithms/grahamScan.h +++ b/wowViewerLib/src/engine/algorithms/grahamScan.h @@ -6,10 +6,11 @@ #define WOWVIEWERLIB_GRAHAMSCAN_H #include "../persistance/header/commonFileStructs.h" -#include #include +#include +#include "../custom_allocators/FrameBasedStackAllocator.h" typedef mathfu::vec3 Point; -std::stack grahamScan(std::vector &points); +std::stack grahamScan(framebased::vector &points); #endif //WOWVIEWERLIB_GRAHAMSCAN_H diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.cpp b/wowViewerLib/src/engine/algorithms/mathHelper.cpp index d660bd1a9..b962a1764 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.cpp +++ b/wowViewerLib/src/engine/algorithms/mathHelper.cpp @@ -63,8 +63,8 @@ CAaBox MathHelper::transformAABBWithMat4(const mathfu::mat4 &mat4, const mathfu: return CAaBox(bb_min_packed, bb_max_packed); } -std::vector MathHelper::transformPlanesWithMat(const std::vector &planes, const mathfu::mat4 &mat) { - auto newPlanes = std::vector(planes.size()); +framebased::vector MathHelper::transformPlanesWithMat(const framebased::vector &planes, const mathfu::mat4 &mat) { + auto newPlanes = framebased::vector(planes.size()); for (int i = 0; i < planes.size(); i++) { newPlanes[i] = (mat) * planes[i]; } @@ -72,13 +72,13 @@ std::vector MathHelper::transformPlanesWithMat(const std::vector MathHelper::getFrustumClipsFromMatrix(const mathfu::mat4 &mat) { +framebased::vector MathHelper::getFrustumClipsFromMatrix(const mathfu::mat4 &mat) { #define el(x, y) (((y)-1) + 4*((x) - 1)) //The order of planes is changed to make it easier to get intersections in getIntersectionPointsFromPlanes //And to be in line of how planes are created for portal verticies in portal culling - std::vector planes(6); + framebased::vector planes(6); // Right clipping plane. planes[0] = mathfu::vec4(mat[el(1,4)] + mat[el(1,1)], mat[el(2,4)] + mat[el(2,1)], @@ -119,7 +119,7 @@ std::vector MathHelper::getFrustumClipsFromMatrix(const mathfu::ma return planes; } -std::vector MathHelper::calculateFrustumPointsFromMat(mathfu::mat4 &perspectiveViewMat) { +framebased::vector MathHelper::calculateFrustumPointsFromMat(mathfu::mat4 &perspectiveViewMat) { mathfu::mat4 perspectiveViewMatInv = perspectiveViewMat.Inverse(); static mathfu::vec4 vertices[] = { @@ -133,7 +133,7 @@ std::vector MathHelper::calculateFrustumPointsFromMat(mathfu::mat4 {1, -1, 1, 1}, //7 }; - std::vector points(8); + framebased::vector points(8); for (int i = 0; i < 8; i++) { mathfu::vec4 &vert = vertices[i]; @@ -173,17 +173,17 @@ bool hullSort(mathfu::vec3 &a, mathfu::vec3 &b, mathfu::vec2 ¢er) { return d1 > d2; } -std::vector MathHelper::getHullPoints(std::vector &points){ +framebased::vector MathHelper::getHullPoints(framebased::vector &points){ if (points.empty()) return {}; std::stack hullPoints = grahamScan(points); if (hullPoints.size() <= 2) { - return std::vector(0); + return framebased::vector(0); } // mathfu::vec3* end = &hullPoints.top() + 1; // mathfu::vec3* begin = end - hullPoints.size(); - std::vector hullPointsArr; + framebased::vector hullPointsArr; hullPointsArr.reserve(hullPoints.size()); while(!hullPoints.empty()) { hullPointsArr.push_back(hullPoints.top()); @@ -226,10 +226,10 @@ std::vector MathHelper::getHullPoints(std::vector &p return hullPointsArr; } -std::vector MathHelper::getHullLines(std::vector &points){ - std::vector hullPointsArr = MathHelper::getHullPoints(points); +framebased::vector MathHelper::getHullLines(framebased::vector &points){ + framebased::vector hullPointsArr = MathHelper::getHullPoints(points); - std::vector hullLines; + framebased::vector hullLines; hullLines.reserve(hullPointsArr.size()); if (hullPointsArr.size() > 2) { @@ -420,9 +420,6 @@ bool MathHelper::checkFrustum(const std::vector &frustums, cons } bool MathHelper::checkFrustum2D(const std::vector &frustums, const CAaBox &box) { - - //var maxLines = window.lines != null ? window.lines : 1; - //for (var i = 0; i < Math.min(num_planes, maxLines); i++) { for (auto &planeUndPoints : frustums) { auto const &planes = planeUndPoints.hullLines; @@ -463,9 +460,9 @@ mathfu::vec4 MathHelper::planeLineIntersection(mathfu::vec4 &plane, mathfu::vec4 } //Points should be sorted against center by this point -bool MathHelper::planeCull(std::vector &points, std::vector &planes) { +bool MathHelper::planeCull(framebased::vector &points, framebased::vector &planes) { // check box outside/inside of frustum - std::vector vec4Points(points.size()); + framebased::vector vec4Points(points.size()); const float epsilon = 0.0001; @@ -488,7 +485,7 @@ bool MathHelper::planeCull(std::vector &points, std::vector resultPoints; + framebased::vector resultPoints; resultPoints.reserve(vec4Points.size() + (vec4Points.size() >> 1)); for (int j = 0; j < vec4Points.size(); j++) { @@ -515,10 +512,10 @@ bool MathHelper::planeCull(std::vector &points, std::vector(resultPoints.begin(), resultPoints.end()); + vec4Points = framebased::vector(resultPoints.begin(), resultPoints.end()); } - points = std::vector(vec4Points.size()); + points = framebased::vector(vec4Points.size()); for (int j = 0; j < vec4Points.size(); j++) { points[j] = vec4Points[j].xyz(); } @@ -527,7 +524,7 @@ bool MathHelper::planeCull(std::vector &points, std::vector &thisPortalVertices, +void MathHelper::sortVec3ArrayAgainstPlane(framebased::vector &thisPortalVertices, const mathfu::vec4 &plane) { mathfu::vec3 center(0, 0, 0); for (int j = 0; j < thisPortalVertices.size(); j++) { @@ -1004,9 +1001,9 @@ MathHelper::hsv MathHelper::rgb2hsv(const mathfu::vec3 &in) { return out; } -std::vector -MathHelper::getIntersectionPointsFromPlanes(const std::vector &planes) { - std::vector points; +framebased::vector +MathHelper::getIntersectionPointsFromPlanes(const framebased::vector &planes) { + framebased::vector points; //For far and near plane for (int x = planes.size()-2; x < planes.size(); x++) { //Look for intersection for of any two planes other planes with two planes above diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index a3e0dc9cd..82e7b6b5d 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -8,6 +8,7 @@ #include "../persistance/header/commonFileStructs.h" #include "mathfu/glsl_mappings.h" #include +#include "../custom_allocators/FrameBasedStackAllocator.h" #include template @@ -26,9 +27,9 @@ class MathHelper { static const constexpr float UNITSIZE = CHUNKSIZE / 8.0f; struct PlanesUndPoints { - std::vector planes; - std::vector points; - std::vector hullLines; + framebased::vector planes; + framebased::vector points; + framebased::vector hullLines; }; typedef struct { @@ -53,22 +54,22 @@ class MathHelper { static mathfu::vec2 convertV69ToV2(vector_2fp_6_9 &fp69); static CAaBox transformAABBWithMat4(const mathfu::mat4 &matrix, const mathfu::vec4 &min, const mathfu::vec4 &max); - static std::vector transformPlanesWithMat(const std::vector &planes, const mathfu::mat4 &mat); - static std::vector getIntersectionPointsFromPlanes(const std::vector &planes); - static std::vector getFrustumClipsFromMatrix(const mathfu::mat4 &mat); - static void fixNearPlane(std::vector &planes, mathfu::vec4 &camera) { + static framebased::vector transformPlanesWithMat(const framebased::vector &planes, const mathfu::mat4 &mat); + static framebased::vector getIntersectionPointsFromPlanes(const framebased::vector &planes); + static framebased::vector getFrustumClipsFromMatrix(const mathfu::mat4 &mat); + static void fixNearPlane(framebased::vector &planes, mathfu::vec4 &camera) { mathfu::vec4 &nearPlane = planes[5]; mathfu::vec4 cameraVec4 = mathfu::vec4(camera[0], camera[1], camera[2], 1); float dist = mathfu::dot(nearPlane, cameraVec4); nearPlane[3] -= dist; } - static std::vector calculateFrustumPointsFromMat(mathfu::mat4 &perspectiveViewMat); + static framebased::vector calculateFrustumPointsFromMat(mathfu::mat4 &perspectiveViewMat); static bool checkFrustum(const MathHelper::FrustumCullingData &frustumData, const CAaBox &box); static bool checkFrustum(const std::vector &frustums, const CAaBox &box); static bool checkFrustum2D(const std::vector &frustums, const CAaBox &box); - static std::vector getHullPoints(std::vector &points); - static std::vector getHullLines(std::vector &points); + static framebased::vector getHullPoints(framebased::vector &points); + static framebased::vector getHullLines(framebased::vector &points); @@ -107,9 +108,9 @@ class MathHelper { } // - static bool planeCull(std::vector &points, std::vector &planes); + static bool planeCull(framebased::vector &points, framebased::vector &planes); - static void sortVec3ArrayAgainstPlane(std::vector &thisPortalVertices, const mathfu::vec4 &plane); + static void sortVec3ArrayAgainstPlane(framebased::vector &thisPortalVertices, const mathfu::vec4 &plane); static mathfu::vec4 createPlaneFromEyeAndVertexes( const mathfu::vec3 &eye, const mathfu::vec3 &vertex1, diff --git a/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h b/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h index 4a3171de4..58bbe0277 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper_culling_sse.h @@ -35,7 +35,7 @@ class ObjectCullingSEE { static const void culling_aabb_see_template(const MathHelper::PlanesUndPoints &frustum, const int start, const int end, - const std::vector &objects, + const framebased::vector &objects, std::vector &culling_res) { __m128 frustum_planes_x[N]; @@ -131,12 +131,12 @@ class ObjectCullingSEE { static void cull(const MathHelper::FrustumCullingData &cullingData, const int start, const int end, - const std::vector &objects, + const framebased::vector &objects, std::vector &culling_res) { static const auto lut2 = make_lut<15, std::function &objects, + const framebased::vector &objects, std::vector &culling_res)>>(); //Culling res: 0xFFFFFFFF - do not render // res: 0 - render diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp deleted file mode 100644 index c23f6a366..000000000 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// Created by Deamon on 12/13/2023. -// - -#include "FrameBasedHeapAllocator.h" -#include -#include -#include - -#include "../../gapi/interface/IDevice.h" -#include -#include - -class FrameHeapRegion { -public: - FrameHeapRegion(size_t size) : m_buffer(size) { - - } - inline int currentAllocationNumber() { return m_currentAllocations; } - - void *allocate(size_t allocSize) { - int offset = atomic_fetch_add(&m_topIndex, allocSize); - if ((offset + allocSize) > m_buffer.size()) { - return nullptr; - } - m_currentAllocations++; - - return &m_buffer[offset]; - } - int getCurrentSize() { return m_buffer.size();} - - bool isThisRegion(void *ptr) { - int index = (uintptr_t)ptr - (uintptr_t)m_buffer.data(); - - return (index > 0) && (index < m_buffer.size()); - } - void deallocate(void *ptr) { - if (!this->isThisRegion(ptr)) { - return; - } - - m_currentAllocations--; - - int index = ((uintptr_t)ptr - (uintptr_t)m_buffer.data()); - int prev_value = m_topIndex; - while(prev_value > index && - !m_topIndex.compare_exchange_weak(prev_value, index)) - {} - } - -private: - std::vector m_buffer; - std::atomic m_topIndex = 0; - std::atomic m_currentAllocations = 0; -}; - - -std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> g_frameHeapList; -//std::array frames; - -static inline uint8_t BitScanMSB2(uint32_t mask) -{ -#ifdef _MSC_VER - unsigned long pos; - if (_BitScanReverse(&pos, mask)) - return static_cast(pos); -#elif defined __GNUC__ || defined __clang__ - if (mask) - return 31 - static_cast(__builtin_clz(mask)); -#else - uint8_t pos = 31; - uint32_t bit = 1UL << 31; - do - { - if (mask & bit) - return pos; - bit >>= 1; - } while (pos-- > 0); -#endif - return UINT8_MAX; -} - -void * frameAllocate(size_t size) { - auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - auto ¤t_list = g_frameHeapList[currentFrame]; - - auto &frameRegion = current_list.back(); - void *ptr = nullptr; - int regionSize = 2048; - if (frameRegion) { - ptr = frameRegion->allocate(size); - regionSize = frameRegion->getCurrentSize(); - } - if (ptr == nullptr) { - size_t currentBufferSize = regionSize; - size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); - - current_list.push_back(std::make_unique(newSize)); - - ptr = current_list.back()->allocate(size); - } - if (ptr == nullptr) { - std::cout << "oops!!!" << std::endl; - } - - return ptr; -} -void frameDeAllocate(void *ptr) { -// auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; -// auto ¤t_list = frames[currentFrame]; - - for (auto &frameList : g_frameHeapList) { - for (auto it = frameList.begin(); it != frameList.end(); ++it) { - auto ®ion = (*it); - if (region->isThisRegion(ptr)) { - region->deallocate(ptr); - - if (region->currentAllocationNumber() == 0) - frameList.erase(it); - - return; - } - } - } - - std::cout << "failed to deallocate" << std::endl; -}; \ No newline at end of file diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h deleted file mode 100644 index 26b53204e..000000000 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedHeapAllocator.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Created by Deamon on 12/13/2023. -// - -#ifndef AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H -#define AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H - -#undef max - -#include -#include -#include - -void * frameAllocate(size_t); -void frameDeAllocate(void *); - -template -struct FrameBasedHeapAllocator -{ - typedef T value_type; - - FrameBasedHeapAllocator() = default; - - template - constexpr FrameBasedHeapAllocator(const FrameBasedHeapAllocator &) noexcept {} - - [[nodiscard]] T* allocate(std::size_t n) - { - if (n > (std::numeric_limits::max() / sizeof(T))) - throw std::bad_array_new_length(); - - - if (auto p = static_cast(frameAllocate(n * sizeof(T)))) - { -// report(p, n); - return p; - } - - return nullptr; - } - - void deallocate(T* p, std::size_t n) noexcept - { -// report(p, n, 0); - frameDeAllocate(p); - } -private: -// void report(T* p, std::size_t n, bool alloc = true) const -// { -// std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n -// << " bytes at " << std::hex << std::showbase -// << reinterpret_cast(p) << std::dec << '\n'; -// } -}; - -template -bool operator==(const FrameBasedHeapAllocator &, const FrameBasedHeapAllocator &) { return true; } - -template -bool operator!=(const FrameBasedHeapAllocator &, const FrameBasedHeapAllocator &) { return false; } - -namespace framebased { - -#if ((defined (_GLIBCXX_VECTOR) \ - || defined (_LIBCPP_VECTOR) \ - || defined (_VECTOR_))) - #define ARENA_HAS_VECTOR_DEF - template - using vector = std::vector>; -#endif - -#if ((defined (_GLIBCXX_UNORDERED_MAP) \ - || defined (_LIBCPP_UNORDERED_MAP) \ - || defined (_UNORDERED_MAP_)) \ - && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) - #define ARENA_HAS_UNORDERED_MAP_DEF - template , class KeyEqual = std::equal_to> - using unordered_map = std::unordered_map>>; -#endif -} - -#endif //AWEBWOWVIEWERCPP_FRAMEBASEDHEAPALLOCATOR_H diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp index 5d29ca706..1c9411988 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp @@ -8,120 +8,6 @@ #include #include "../../gapi/interface/IDevice.h" +#include "../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" #include #include - -class FrameRegion { -public: - FrameRegion(size_t size) : m_buffer(size) { - - } - inline int currentAllocationNumber() { return m_currentAllocations; } - - void *allocate(size_t allocSize) { - int offset = atomic_fetch_add(&m_topIndex, allocSize); - if ((offset + allocSize) > m_buffer.size()) { - return nullptr; - } - m_currentAllocations++; - - return &m_buffer[offset]; - } - int getCurrentSize() { return m_buffer.size();} - - bool isThisRegion(void *ptr) { - int index = (uintptr_t)ptr - (uintptr_t)m_buffer.data(); - - return (index > 0) && (index < m_buffer.size()); - } - void deallocate(void *ptr) { - if (!this->isThisRegion(ptr)) { - return; - } - - m_currentAllocations--; - - int index = ((uintptr_t)ptr - (uintptr_t)m_buffer.data()); - int prev_value = m_topIndex; - while(prev_value > index && - !m_topIndex.compare_exchange_weak(prev_value, index)) - {} - } - -private: - std::vector m_buffer; - std::atomic m_topIndex = 0; - std::atomic m_currentAllocations = 0; -}; - - -std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> g_frameStackList; -//std::array frames; - -static inline uint8_t BitScanMSB2(uint32_t mask) -{ -#ifdef _MSC_VER - unsigned long pos; - if (_BitScanReverse(&pos, mask)) - return static_cast(pos); -#elif defined __GNUC__ || defined __clang__ - if (mask) - return 31 - static_cast(__builtin_clz(mask)); -#else - uint8_t pos = 31; - uint32_t bit = 1UL << 31; - do - { - if (mask & bit) - return pos; - bit >>= 1; - } while (pos-- > 0); -#endif - return UINT8_MAX; -} - -void * frameAllocate(size_t size) { - auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - auto ¤t_list = g_frameStackList[currentFrame]; - - auto &frameRegion = current_list.back(); - void *ptr = nullptr; - int regionSize = 2048; - if (frameRegion) { - ptr = frameRegion->allocate(size); - regionSize = frameRegion->getCurrentSize(); - } - if (ptr == nullptr) { - size_t currentBufferSize = regionSize; - size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); - - current_list.push_back(std::make_unique(newSize)); - - ptr = current_list.back()->allocate(size); - } - if (ptr == nullptr) { - std::cout << "oops!!!" << std::endl; - } - - return ptr; -} -void frameDeAllocate(void *ptr) { -// auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; -// auto ¤t_list = frames[currentFrame]; - - for (auto &frameList : g_frameStackList) { - for (auto it = frameList.begin(); it != frameList.end(); ++it) { - auto ®ion = (*it); - if (region->isThisRegion(ptr)) { - region->deallocate(ptr); - - if (region->currentAllocationNumber() == 0) - frameList.erase(it); - - return; - } - } - } - - std::cout << "failed to deallocate" << std::endl; -}; \ No newline at end of file diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index a4bf5d417..5746752ed 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -10,54 +10,8 @@ #include #include #include - -void * frameAllocate(size_t); -void frameDeAllocate(void *); - -template -struct FrameBasedStackAllocator -{ - typedef T value_type; - - FrameBasedStackAllocator() = default; - - template - constexpr FrameBasedStackAllocator(const FrameBasedStackAllocator &) noexcept {} - - [[nodiscard]] T* allocate(std::size_t n) - { - if (n > (std::numeric_limits::max() / sizeof(T))) - throw std::bad_array_new_length(); - - - if (auto p = static_cast(frameAllocate(n * sizeof(T)))) - { -// report(p, n); - return p; - } - - return nullptr; - } - - void deallocate(T* p, std::size_t n) noexcept - { -// report(p, n, 0); - frameDeAllocate(p); - } -private: -// void report(T* p, std::size_t n, bool alloc = true) const -// { -// std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n -// << " bytes at " << std::hex << std::showbase -// << reinterpret_cast(p) << std::dec << '\n'; -// } -}; - -template -bool operator==(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return true; } - -template -bool operator!=(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return false; } +#include "tbb/tbb.h" +#include "tbb/scalable_allocator.h" namespace framebased { @@ -66,7 +20,7 @@ namespace framebased { || defined (_VECTOR_))) #define ARENA_HAS_VECTOR_DEF template - using vector = std::vector>; + using vector = std::vector; #endif #if ((defined (_GLIBCXX_UNORDERED_MAP) \ @@ -75,7 +29,7 @@ namespace framebased { && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) #define ARENA_HAS_UNORDERED_MAP_DEF template , class KeyEqual = std::equal_to> - using unordered_map = std::unordered_map>>; + using unordered_map = std::unordered_map; #endif } diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index ca1f96585..7eb5ce931 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -839,7 +839,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV this->m_ribbonEmitterflags.m_initialized = 1; } -void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { +void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; if (currFrame.isDead) return; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index ecc68e154..3986e8c01 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -122,7 +122,7 @@ class CRibbonEmitter { //CTexture **SetTexture(unsigned int a2, CTexture *a3); //int ReplaceTexture(unsigned int a2, CTexture *a3); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 8019b63ad..18c68146c 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -1114,7 +1114,7 @@ ParticleEmitter::BuildQuadT3( } -void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { +void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 3a0af43ed..c579cb634 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -68,7 +68,7 @@ class ParticleEmitter { CParticleGenerator * getGenerator(){ return generator; } - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/SceneObjectWithID.h b/wowViewerLib/src/engine/objects/SceneObjectWithID.h index f5453a341..08e8b6c5f 100644 --- a/wowViewerLib/src/engine/objects/SceneObjectWithID.h +++ b/wowViewerLib/src/engine/objects/SceneObjectWithID.h @@ -5,15 +5,19 @@ #ifndef AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H #define AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H -class SceneObjectWithId { +class ObjectWithId { + template friend class EntityFactory; public: - SceneObjectWithId(int id) : m_id(id) { + ObjectWithId() { } + virtual ~ObjectWithId() = default; int getObjectId() { return m_id;} private: - int m_id; + void setId(int id) {m_id = id;}; + + int m_id = -1; }; #endif //AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 9656a349e..9bcd9763e 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -12,7 +12,7 @@ #endif #include "../algorithms/mathHelper_culling.h" -void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) { +void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) { if (renderADT) { for (auto const &adtMesh : this->m_adtOpaqueMeshes ) { opaqueMeshCollector.addADTMesh(adtMesh); @@ -29,7 +29,7 @@ void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool rend } -void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) { +void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) { if (renderWMO) { for (auto &wmoGroup: wmoGroupArray.getToDraw()) { wmoGroup->collectMeshes(opaqueMeshCollector, transparentMeshes, renderOrder); @@ -162,7 +162,7 @@ void GeneralView::produceTransformedPortalMeshes(const HMapSceneBufferCreate &sc } } -void GeneralView::collectPortalMeshes(std::vector &transparentMeshes) { +void GeneralView::collectPortalMeshes(framebased::vector &transparentMeshes) { for (auto const &mesh : m_portalMeshes) { transparentMeshes.push_back(mesh); } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 327d6daab..b4f17da10 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -50,14 +50,14 @@ class GeneralView { HGVertexBufferBindings m_bindings; }; - std::vector m_portalMeshes = {}; + framebased::vector m_portalMeshes = {}; std::vector portals; - std::vector liquidMeshes = {}; + framebased::vector liquidMeshes = {}; - virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes); - void collectPortalMeshes(std::vector &transparentMeshes); + virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); + void collectPortalMeshes(framebased::vector &transparentMeshes); virtual void setM2Lights(std::shared_ptr &m2Object); void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, @@ -77,7 +77,7 @@ class ExteriorView : public GeneralView { std::vector> drawnADTs = {}; std::vector m_adtOpaqueMeshes = {}; public: - void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes) override; + void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) override; }; class FrameViewsHolder { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index c07822dba..8f9456fcb 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -577,7 +577,7 @@ void AdtObject::loadAlphaTextures() { -void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder) { +void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, framebased::vector &transparentMeshes, int renderOrder) { if (m_freeStrategy != nullptr) m_freeStrategy(false, true, m_mapApi->getCurrentSceneTime()); if (!m_loaded) return; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index bade8d16a..54ff7c250 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -44,7 +44,7 @@ class AdtObject { FileStatus getLoadedStatus(); - void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, framebased::vector &transparentMeshes, int renderOrder); void collectMeshesLod(std::vector &renderedThisFrame); void update(animTime_t deltaTime); diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index 8a642f140..fad85126f 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -299,6 +299,7 @@ static const struct { +WmoVertexShader::MapObjParallax, +WmoPixelShader::MapObjParallax, }, + //23 { +WmoVertexShader::MapObjDiffuse_T1, +WmoPixelShader::MapObjDFShader, diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index be4afb700..3d677c3e6 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -7,6 +7,7 @@ #include "../../algorithms/mathHelper.h" #include "../iMapApi.h" + LiquidInstance::LiquidInstance(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, const SMLiquidInstance &liquidInstance, @@ -293,7 +294,7 @@ void LiquidInstance::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector) { } } -void LiquidInstance::collectMeshes(std::vector &transparentMeshes) { +void LiquidInstance::collectMeshes(framebased::vector &transparentMeshes) { //TODO: Get time and right mesh instance for animation if (m_api->getConfig()->renderLiquid) { transparentMeshes.push_back(m_liquidMeshes[0]); diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index abc364676..d13491cc9 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -8,6 +8,7 @@ class IMapApi; #include "../../ApiContainer.h" +#include "../../custom_allocators/FrameBasedStackAllocator.h" class LiquidInstance { public: @@ -28,7 +29,7 @@ class LiquidInstance { void updateLiquidMaterials(const HFrameDependantData &frameDependantData, animTime_t mapCurrentTime); void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector); - void collectMeshes(std::vector &transparentMeshes); + void collectMeshes(framebased::vector &transparentMeshes); private: const HApiContainer &m_api; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 06053f6ed..0c3f6d899 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1639,7 +1639,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index return m2Mesh; } -void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { +void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; @@ -1916,7 +1916,7 @@ int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { return -1; } -void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { +void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { // return; // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 47c95f416..e706fd10c 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -245,7 +245,7 @@ class M2Object { mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { if (m_useLocalDiffuseColor == -1) { @@ -289,7 +289,7 @@ class M2Object { m_ambientColorOverride = ambientColor; } - void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); + void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); void createVertexBindings(const HMapSceneBufferCreate &sceneRenderer); @@ -320,8 +320,8 @@ inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { } class M2ObjectListContainer { -//using vectorContainer = framebased::vector> -using m2Container = std::vector>; +using m2Container = framebased::vector>; +//using m2Container = std::vector>; private: m2Container candidates; m2Container drawn; diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index 70e51b45f..d1cece954 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -6,26 +6,63 @@ #define AWEBWOWVIEWERCPP_ENTITYACTORSFACTORY_H #include -#include "../m2/m2Object.h" -#include "../wmo/wmoObject.h" +#include +#include "../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" -class EntityActorsFactory { +template +class EntityFactory : public std::enable_shared_from_this>{ +static constexpr int initSize = 1000; public: - EntityActorsFactory(const HApiContainer &api) : m_api(api){}; + explicit EntityFactory() { + objectCache.resize(initSize); + }; - std::shared_ptr createM2Object() { - return std::make_shared(m_api); + template + std::shared_ptr createObject(_Args&&... __args) { + OffsetAllocator::Allocation offsetData; + T * entity = nullptr; + + { + std::unique_lock lock(m_mutex); + offsetData = allocator.allocate(1); + if (offsetData.offset == OffsetAllocator::Allocation::NO_SPACE) { + constexpr int growSize = 1000; + + allocator.growSize(growSize); + offsetData = allocator.allocate(1); + objectCache.resize(objectCache.size() + growSize); + } + + entity = new T(std::forward(__args)...); + entity->setId(offsetData.offset); + objectCache[offsetData.offset] = entity; + } + + auto weakPtr = this->weak_from_this(); + return std::shared_ptr(entity, [offsetData, weakPtr](T *ls) -> void { + auto shared = weakPtr.lock(); + if (shared != nullptr) + shared->deallocate(offsetData); + }); } - M2Object * getM2ObjectById(int id) { - return m2ObjectCache[id]; + T * getObjectById(int id) { + return objectCache[id]; + } + + void deallocate(const OffsetAllocator::Allocation &alloc) { + std::unique_lock lock(m_mutex); + + delete objectCache[alloc.offset]; + + objectCache[alloc.offset] = nullptr; + allocator.free(alloc); } private: - HApiContainer m_api; + std::mutex m_mutex; - std::vector m2ObjectCache; - std::vector wmoObjectCache; - std::vector wmoGroupObjectCache; + OffsetAllocator::Allocator allocator = OffsetAllocator::Allocator(initSize); + std::vector objectCache; }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 40bfdb5b8..c36cb6678 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1177,8 +1177,6 @@ void Map::getCandidatesEntities(const MathHelper::FrustumCullingData &frustumDat int adt_y_min = std::max(std::floor(worldCoordinateToAdtIndexF(maxx)), 0); int adt_y_max = std::min(std::ceil(worldCoordinateToAdtIndexF(minx)), 63); - - if (!m_wdtfile->mphd->flags.wdt_uses_global_map_obj) { for (int i = adt_x_min; i <= adt_x_max; i++) { for (int j = adt_y_min; j <= adt_y_max; j++) { @@ -1222,7 +1220,7 @@ void Map::checkADTCulling(int i, int j, return; } - auto adtObject = mapTiles[i][j]; + auto &adtObject = mapTiles[i][j]; if (adtObject != nullptr) { std::shared_ptr adtFrustRes = std::make_shared(); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index d1da1c60e..4a672fabc 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -746,7 +746,7 @@ void WmoGroupObject::setModelFileId(int fileId) { m_modelFileId = fileId; } -void WmoGroupObject::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder) { +void WmoGroupObject::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { if (!m_loaded) return; for (auto const &i : this->m_meshArray) { opaqueMeshCollector.addWMOMesh(i); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 1cc6e4b2a..64e903618 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -46,7 +46,7 @@ class WmoGroupObject { void setModelFileName(std::string modelName); void setModelFileId(int fileId); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, std::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; @@ -150,7 +150,8 @@ enum liquid_basic_types class WMOGroupListContainer { -using wmoGroupContainer = std::vector>; +using wmoGroupContainer = framebased::vector>; +//using wmoGroupContainer = std::vector>; private: wmoGroupContainer wmoGroupToDraw; wmoGroupContainer wmoGroupToCheckM2; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index c51955f31..486d7954d 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -267,12 +267,12 @@ void WmoObject::createWorldPortals() { ); mathfu::mat4 viewMatInv = viewMat.Inverse(); - std::vector portalTransformed(portalVecs.size()); + framebased::vector portalTransformed(portalVecs.size()); for (int k = 0; k < portalVecs.size(); k++) { portalTransformed[k] = (viewMat * mathfu::vec4(portalVecs[k], 1.0)).xyz(); } - std::vector hulled = MathHelper::getHullPoints(portalTransformed); + framebased::vector hulled = MathHelper::getHullPoints(portalTransformed); portalVecs.clear(); for (int k = 0; k < hulled.size(); k++) { @@ -588,9 +588,9 @@ bool WmoObject::startTraversingWMOGroup( } return result; } - std::vector ivPerWMOGroup = std::vector(mainGeom->groupsLen); + framebased::vector ivPerWMOGroup = framebased::vector(mainGeom->groupsLen); - std::vector transverseVisitedPortals = std::vector(portalCount, false); + framebased::vector transverseVisitedPortals = framebased::vector(portalCount, false); //CurrentVisibleM2 and visibleWmo is array of global m2 objects, that are visible after frustum mathfu::vec4 cameraLocal = this->m_placementInvertMatrix * cameraVec4; @@ -602,8 +602,8 @@ bool WmoObject::startTraversingWMOGroup( mathfu::mat4 MVPMat = frustumDataGlobal.perspectiveMat*frustumDataGlobal.viewMat*this->m_placementMatrix; mathfu::mat4 MVPMatInv = MVPMat.Inverse(); - std::vector frustumPointsLocal = MathHelper::calculateFrustumPointsFromMat(MVPMat); - std::vector frustumPlanesLocal = MathHelper::getFrustumClipsFromMatrix(MVPMat); + framebased::vector frustumPointsLocal = MathHelper::calculateFrustumPointsFromMat(MVPMat); + framebased::vector frustumPlanesLocal = MathHelper::getFrustumClipsFromMatrix(MVPMat); // mathfu::vec4 headOfPyramidLocal = mathfu::vec4(MathHelper::getIntersection( // frustumPointsLocal[4], frustumPointsLocal[7], // frustumPointsLocal[3], frustumPointsLocal[0] @@ -777,7 +777,7 @@ void WmoObject::traverseGroupWmo( int groupId, bool traversingStartedFromInterior, PortalTraverseTempData &traverseTempData, - std::vector &localFrustumPlanes, + framebased::vector &localFrustumPlanes, int globalLevel, int localLevel ) { @@ -873,7 +873,7 @@ void WmoObject::traverseGroupWmo( if (portalInfo->index_count < 4) continue; //2.2 Check if Portal BB made from portal vertexes intersects frustum - std::vector portalVerticesVec; + framebased::vector portalVerticesVec; std::transform( geometryPerPortal[relation->portal_index].sortedVericles.begin(), geometryPerPortal[relation->portal_index].sortedVericles.end(), @@ -890,13 +890,13 @@ void WmoObject::traverseGroupWmo( int lastFrustumPlanesLen = localFrustumPlanes.size(); //3. Construct frustum planes for this portal - std::vector thisPortalPlanes; + framebased::vector thisPortalPlanes; thisPortalPlanes.reserve(lastFrustumPlanesLen); if (hackCondition) { //Transform portal vertexes into clip space (this code should allow to use this logic with both Perspective and Ortho) - std::vector portalVerticesClip(portalVerticesVec.size()); - std::vector portalVerticesClipNearPlane(portalVerticesVec.size()); + framebased::vector portalVerticesClip(portalVerticesVec.size()); + framebased::vector portalVerticesClipNearPlane(portalVerticesVec.size()); for (int i = 0; i < portalVerticesVec.size(); i++) { portalVerticesClip[i] = traverseTempData.MVPMat * mathfu::vec4(portalVerticesVec[i], 1.0f); @@ -948,8 +948,8 @@ void WmoObject::traverseGroupWmo( //Transform local planes into world planes to use with frustum culling of M2Objects MathHelper::PlanesUndPoints worldSpaceFrustum; - worldSpaceFrustum.planes = std::vector(thisPortalPlanes.size()); - worldSpaceFrustum.points = std::vector(); + worldSpaceFrustum.planes = framebased::vector(thisPortalPlanes.size()); + worldSpaceFrustum.points = framebased::vector(); worldSpaceFrustum.points.reserve(thisPortalPlanes.size()); for (int x = 0; x < thisPortalPlanes.size(); x++) { diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 03c332200..3cb96235b 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -36,13 +36,13 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { FrameViewsHolder &viewsHolder; bool exteriorWasCreatedBeforeTraversing; mathfu::vec4 farPlane; - std::vector &ivPerWMOGroup; + framebased::vector &ivPerWMOGroup; mathfu::vec4 &cameraVec4; mathfu::vec4 &cameraLocal; mathfu::mat4 &transposeInverseModelMat; mathfu::mat4 &MVPMat; mathfu::mat4 &MVPMatInv; - std::vector &transverseVisitedPortals; + framebased::vector &transverseVisitedPortals; bool atLeastOneGroupIsDrawn = false; }; @@ -170,7 +170,7 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { int groupId, bool traversingStartedFromInterior, PortalTraverseTempData &traverseTempData, - std::vector &localFrustumPlanes, + framebased::vector &localFrustumPlanes, int globalLevel, int localLevel ); @@ -187,7 +187,8 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { }; class WMOListContainer { - using wmoContainer = std::vector>; + using wmoContainer = framebased::vector>; +// using wmoContainer = std::vector>; private: wmoContainer wmoCandidates; wmoContainer wmoToLoad; @@ -215,6 +216,7 @@ class WMOListContainer { WMOListContainer() { wmoCandidates.reserve(3000); wmoToLoad.reserve(3000); + wmoToDrawn.reserve(3000); } void addCand(const std::shared_ptr &toDraw) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index e9fb4a014..f3daaa1a5 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,14 +276,33 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,544}, }, { { @@ -319,12 +319,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +334,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "visBuffer/ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {1,1,16}, + {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -355,14 +354,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,4096}, }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,15 +373,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -391,13 +392,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,13 +418,13 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/wmoShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, - {1,1,48}, {1,0,64}, + {0,0,544}, + {1,1,16}, }, { { @@ -432,21 +441,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,15 +456,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "visBuffer/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -475,16 +475,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -492,35 +498,42 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { - {1,0,64}, + {2,0,112}, + {1,5,4096}, + {1,2,16384}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { {0,0,1}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { }, { + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -529,16 +542,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -548,21 +562,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -572,16 +579,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,544}, + {1,0,96}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -608,15 +616,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -644,7 +651,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "visBuffer/waterfallShader.vert.spv", { ShaderStage::Vertex, { @@ -663,21 +670,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, {1,6,0}, - {1,4,0}, + {1,3,0}, {1,1,0}, {1,2,0}, - {1,3,0}, + {1,4,0}, {1,5,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -686,15 +699,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -722,16 +735,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -759,15 +771,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,15 +807,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -816,11 +827,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -831,16 +843,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -851,6 +862,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -868,15 +885,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,0,16}, + {0,0,544}, }, { { - {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -884,17 +900,22 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -904,15 +925,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -925,10 +946,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -940,17 +963,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {2,0,112}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -961,15 +991,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { - {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +1010,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,16}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1014,15 +1046,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,32}, + {0,1,112}, + {0,0,544}, }, { { - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,12 +1068,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1051,16 +1083,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {1,0,16}, }, { { - {1,1,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1072,13 +1104,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, }, { { {0,0,0}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,14 +1119,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "visBuffer/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1107,16 +1138,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {1,0, "Texture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1125,15 +1167,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,80}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1161,14 +1203,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,80}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1181,12 +1224,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1197,16 +1239,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, - {0,0,544}, + {0,0,144}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1214,20 +1254,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1237,16 +1275,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, + {1,1,48}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1258,12 +1298,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1273,17 +1322,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,96}, + {0,0,84}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1295,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1310,24 +1360,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, + {1,2,32}, {0,0,544}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1338,17 +1382,22 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, + {0,8,9}, {0,0,0}, - {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1357,24 +1406,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,2,16384}, - {1,0,64}, - {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, + {0,1,32}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1385,11 +1427,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1400,14 +1443,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { + {0,0,16}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1479,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,16}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1454,18 +1498,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, - {1,1,0}, }, { - {2,0, "s_Textures"}, + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, + {0,1,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1475,18 +1517,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, + {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {0,1,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1514,17 +1555,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,544}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1533,19 +1581,19 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1554,9 +1602,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -1573,14 +1621,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1590,14 +1645,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "visBuffer/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1608,14 +1664,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,17 +1685,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,9 +1704,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { - {2,0, "uTexture"}, + {2,0, "s_Textures"}, }, { { @@ -1663,16 +1731,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, - {1,0,64}, + {0,0,128}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1680,6 +1746,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -1700,16 +1767,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,0,64}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1719,22 +1787,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1742,24 +1804,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { ShaderStage::Fragment, { - {2,0,112}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1770,17 +1824,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {1,0, "Texture"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1828,24 +1879,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,1,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1856,14 +1901,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1872,16 +1916,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {0,0,544}, + {0,1,112}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1889,19 +1931,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1911,17 +1952,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, + {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1936,18 +1977,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1957,7 +1992,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1993,18 +2028,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {1,0,64}, - {0,0,544}, - {1,1,16}, }, { { - {0,0,1}, - {0,1,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2031,15 +2063,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2050,27 +2082,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2079,17 +2100,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,2,16384}, + {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2098,24 +2126,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2125,16 +2143,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,1,16}, + {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2144,24 +2164,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "uTexture"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -2169,11 +2177,12 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -2192,15 +2201,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -2221,140 +2221,75 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 9, { } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 8, { } }, { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + 7, { } }, - }}, - {"adtShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, } }, { 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { 2, { } }, - }}, - {"drawLinesShader", { + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, { 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"drawPoints", { + {"adtLodShader", { { 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + } + }, + }}, + {"adtShader", { + { + 2, { } }, { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, } }, - }}, - {"drawQuad", { { - 0, { - {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, + 3, { } }, - }}, - {"drawPortalShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2388,19 +2323,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { + } + }, + { + 7, { } }, { 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, } }, { 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 2, { - {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, } }, { - 3, { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, + 0, { } }, }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"skyConus", { + }}, + {"m2Shader", { + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 7, { + } + }, + { + 8, { + } + }, + { + 9, { + } + }, { 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, } }, - }}, - {"drawBBShader", { + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, - }}, - {"drawDepthShader", { { - 2, { - {"_0_2_drawDepth", false, 0, 1, 1, 0}, - {"_0_2_uFarPlane", true, 4, 1, 1, 0}, - {"_0_2_uNearPlane", true, 8, 1, 1, 0}, + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, } }, - }}, - {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2744,30 +2796,25 @@ const std::unordered_map #include "../IDevice.h" +#include "../../../engine/objects/SceneObjectWithID.h" enum class MeshType { eGeneralMesh = 0, @@ -66,7 +67,7 @@ class gMeshTemplate { }; -class IMesh { +class IMesh : public ObjectWithId { friend class IDevice; public: @@ -87,7 +88,9 @@ class IMesh { public: - virtual ~IMesh() = default; + ~IMesh() override { + 1 + 1; + }; virtual bool getIsTransparent() = 0; virtual MeshType getMeshType() = 0; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h index 981451d56..5c539e595 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h @@ -10,6 +10,7 @@ #include "../GDeviceVulkan.h" #include "../descriptorSets/GDescriptorSet.h" #include "../materials/ISimpleMaterialVLK.h" +#include "../../../engine/objects/SceneObjectWithID.h" class GMeshVLK : public IM2Mesh { friend class GDeviceVLK; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index a88f38ca1..95ac4d41b 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -21,8 +21,8 @@ MapSceneRenderer::processCulling(const std::shared_ptr &renderPlan, COpaqueMeshCollector &opaqueMeshCollector, COpaqueMeshCollector &skyOpaqueMeshCollector, - const std::shared_ptr> &htransparentMeshes, - const std::shared_ptr> &hSkyTransparentMeshes) { + const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hSkyTransparentMeshes) { ZoneScoped; auto &transparentMeshes = *htransparentMeshes; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 90bc66ca5..c645babc8 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -104,8 +104,8 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public void collectMeshes(const std::shared_ptr &renderPlan, COpaqueMeshCollector &opaqueMeshCollector, COpaqueMeshCollector &skyOpaqueMeshCollector, - const std::shared_ptr> &htransparentMeshes, - const std::shared_ptr> &hSkyTransparentMeshes); + const std::shared_ptr> &htransparentMeshes, + const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, const std::vector &renderingMatrices, diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 0447b057b..74b73a42d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -613,25 +613,27 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha //Create meshes std::unique_ptr u_collector = std::make_unique(); std::unique_ptr u_skyCollector = std::make_unique(); - auto transparentMeshes = std::make_shared>(); + auto transparentMeshes = std::make_shared>(); - auto skyTransparentMeshes = std::make_shared>(); + auto skyTransparentMeshes = std::make_shared>(); framePlan->m2Array.lock(); framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); -// TracyMessageL("collect meshes created"); + + + mapScene->update(framePlan); + mapScene->updateBuffers(l_this, framePlan); + + // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); // } // ); - mapScene->update(framePlan); - mapScene->updateBuffers(l_this, framePlan); - std::vector renderingMatricess; for (auto &rt : frameInputParams->frameParameters->renderTargets) { renderingMatricess.push_back(rt.cameraMatricesForRendering); @@ -815,16 +817,16 @@ std::shared_ptr MapSceneRenderForwardVLK::getLastCreatedPlan() { } HGMesh MapSceneRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); + return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } HGSortableMesh MapSceneRenderForwardVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } HGMesh MapSceneRenderForwardVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); return mesh; }; @@ -832,22 +834,22 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); return mesh; } HGSortableMesh MapSceneRenderForwardVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } HGMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index f18ebafb9..849557099 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -12,6 +12,7 @@ #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" #include "view/RenderViewForwardVLK.h" +#include "../../../engine/objects/scenes/EntityActorsFactory.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { public: @@ -110,6 +111,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; + std::shared_ptr> meshFactory = std::shared_ptr>(); + HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboM2RibbonBuffer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index e65e32654..a1c4a2dc5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -977,11 +977,11 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ typedef robin_hood::unordered_flat_map, std::vector> MeshMap; - std::vector m2DrawVec; - std::vector wmoDrawVec; + framebased::vector m2DrawVec; + framebased::vector wmoDrawVec; MeshMap waterMeshMap; - std::vector adtDrawVec; - std::vector commonMeshes; + framebased::vector adtDrawVec; + framebased::vector commonMeshes; inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { const auto &meshVlk = (GMeshVLK*) mesh.get(); @@ -1004,8 +1004,10 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ drawCommand.vertexOffset = 0; } } - inline static void addDrawCommand(std::vector &drawVec, const HGMesh &mesh) { - const auto &meshVlk = (GMeshVLK*) mesh.get(); + inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { + auto meshId = mesh->getObjectId(); + auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); +// const auto &meshVlk = (GMeshVLK*) mesh->getObjectId(); auto const matId = meshVlk->material()->getMaterialId(); auto &drawCommand = drawVec.emplace_back(); @@ -1151,24 +1153,20 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s //Create meshes std::unique_ptr u_collector = std::make_unique(*this, lastMeshCount); std::unique_ptr u_skyCollector = std::make_unique(*this); - auto transparentMeshes = std::make_shared>(); + auto transparentMeshes = std::make_shared>(); - auto skyTransparentMeshes = std::make_shared>(); + auto skyTransparentMeshes = std::make_shared>(); framePlan->m2Array.lock(); framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - //The portal meshes are created here. Need to call doPostLoad before CollectMeshes -// mapScene->doPostLoad(l_this, framePlan); // TracyMessageL("collect meshes created"); // std::future collectMeshAsync = std::async(std::launch::async, // [&]() { - collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); - u_collector->fillMeshCount(lastMeshCount); // } // ); @@ -1187,6 +1185,9 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s mapScene->getCurrentSceneTime()); + collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); + u_collector->fillMeshCount(lastMeshCount); + // { // ZoneScopedN("collect meshes wait"); // collectMeshAsync.wait(); @@ -1383,11 +1384,11 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getLastCreatedPlan() } HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0,0); + return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); return mesh; } @@ -1396,7 +1397,7 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTe meshTemplate.bindings = m_emptyWaterVAO; auto _material = std::dynamic_pointer_cast(material); - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); mesh->instanceIndex = _material->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); @@ -1412,7 +1413,7 @@ MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const st auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyADTVAO; - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1425,7 +1426,7 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyM2VAO; - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1453,7 +1454,7 @@ HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, co c_perMeshData->save(); } - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); mesh->instanceIndex = c_perMeshData->getIndex(); mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1462,7 +1463,7 @@ HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, co HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = std::make_shared(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index bc16be446..ab8911470 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -14,6 +14,7 @@ #include "../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" +#include "../../../engine/objects/scenes/EntityActorsFactory.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { friend class COpaqueMeshCollectorBindlessVLK; @@ -111,6 +112,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr createRenderView(int width, int height, bool createOutput) override; + std::shared_ptr> meshFactory = std::make_shared>(); private: std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); @@ -137,6 +139,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::unique_ptr glowPass; + HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboM2RibbonBuffer; From f17a1cb6353a6d075e23f28dbd0bf2b335a46dd2 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 22 Jan 2024 01:51:39 +0200 Subject: [PATCH 162/212] - iteration over file list for file detection implemented --- src/persistance/CascRequestProcessor.cpp | 62 +- src/persistance/CascRequestProcessor.h | 5 + src/persistance/RequestProcessor.cpp | 19 + src/persistance/RequestProcessor.h | 20 + .../fileListWindow/FileListWindow.cpp | 173 +- .../fileListWindow/FileListWindow.h | 9 +- .../src/engine/shader/ShaderDefinitions.h | 1450 ++++++++--------- 7 files changed, 946 insertions(+), 792 deletions(-) diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 29a9617fd..345f88ab8 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -182,16 +182,29 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache return; } + HFileContent fileContent = readFileContent(fileName, fileDataId); + + if (!(fileContent == nullptr)) { + toBeProcessed--; + processResult(perstFile, fileContent, fileName); + } else { + if (fileDataId > 0) { + std::cout << "Could read fileDataId " << fileDataId << std::endl << std::flush; + } else { + std::cout << "Could read file " << fileName << std::endl << std::flush; + } + toBeProcessed--; + this->m_fileRequester->rejectFile(holderType, fileName.c_str()); + } +} + +HFileContent CascRequestProcessor::readFileContent(const std::string &fileName, uint32_t fileDataId) { std::string fileNameFixed = fileName; std::replace( fileNameFixed.begin(), fileNameFixed.end(), '/', '\\'); void *fileNameToPass = (void *) fileNameFixed.c_str(); DWORD openFlags = CASC_OPEN_BY_NAME; - if (fileNameFixed.find("File") == 0) { - if (fileDataId == 0) { - return; - } - + if (fileDataId > 0) { fileNameToPass = reinterpret_cast(fileDataId); openFlags = CASC_OPEN_BY_FILEID; } @@ -200,9 +213,9 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache HFileContent fileContent = nullptr; - fileContent = this->tryGetFileFromOverrides(fileDataId); - if (this->m_storage != nullptr && fileContent == nullptr) { - fileContent = this->tryGetFile(this->m_storage, fileNameToPass, openFlags); + fileContent = tryGetFileFromOverrides(fileDataId); + if (m_storage != nullptr && fileContent == nullptr) { + fileContent = tryGetFile(m_storage, fileNameToPass, openFlags); if (fileContent == nullptr) { if (fileDataId > 0) { std::cout << "Could not read fileDataId " << fileDataId << " from local " << std::endl << std::flush; @@ -211,8 +224,8 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache } } } - if (this->m_storageOnline != nullptr && fileContent == nullptr) { - fileContent = this->tryGetFile(this->m_storageOnline, fileNameToPass, openFlags); + if (m_storageOnline != nullptr && fileContent == nullptr) { + fileContent = tryGetFile(m_storageOnline, fileNameToPass, openFlags); if (fileContent == nullptr) { if (fileDataId > 0) { std::cout << "Could read fileDataId " << fileDataId << " from online " << std::endl << std::flush; @@ -221,18 +234,25 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache } } } + return fileContent; +} - if (!(fileContent == nullptr)) { - toBeProcessed--; - processResult(perstFile, fileContent, fileName); - } else { - if (fileDataId > 0) { - std::cout << "Could read fileDataId " << fileDataId << std::endl << std::flush; - } else { - std::cout << "Could read file " << fileName << std::endl << std::flush; - } - toBeProcessed--; - this->m_fileRequester->rejectFile(holderType, fileName.c_str()); +void CascRequestProcessor::iterateFilesInternal( + std::function &process, + std::function &callback) { + + CASC_FIND_DATA findData; + auto searchHandle = CascFindFirstFile(m_storage, nullptr, &findData, nullptr); + if (searchHandle != INVALID_HANDLE_VALUE ) { + do { + if (!process(findData.dwFileDataId, findData.szFileName)) continue; + + auto fileContent = readFileContent(findData.szFileName, findData.dwFileDataId); + if (fileContent) { + callback(findData.dwFileDataId, fileContent); + } + } while(CascFindNextFile(searchHandle, &findData)); + CascFindClose(searchHandle); } } diff --git a/src/persistance/CascRequestProcessor.h b/src/persistance/CascRequestProcessor.h index 8f8b03cbb..df07583e4 100644 --- a/src/persistance/CascRequestProcessor.h +++ b/src/persistance/CascRequestProcessor.h @@ -25,9 +25,14 @@ class CascRequestProcessor : public RequestProcessor { void* m_storageOnline = nullptr; protected: void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) override; + void iterateFilesInternal( + std::function &process, + std::function &callback) override; private: HFileContent tryGetFile(void *cascStorage, void *fileNameToPass, uint32_t openFlags); HFileContent tryGetFileFromOverrides(int fileDataId); + + HFileContent readFileContent(const std::string &fileName, uint32_t fileDataId); }; diff --git a/src/persistance/RequestProcessor.cpp b/src/persistance/RequestProcessor.cpp index 926976bf6..b898dbed5 100644 --- a/src/persistance/RequestProcessor.cpp +++ b/src/persistance/RequestProcessor.cpp @@ -35,14 +35,31 @@ RequestProcessor::requestFile(std::string &fileName, CacheHolderType holderType, m_requestQueue->pushInput({fileName, holderType, s_file}); toBeProcessed++; } +void RequestProcessor::iterateAllFiles( std::unique_ptr &iterateFilesRequest ) { + m_iterateFilesRequest = std::move(iterateFilesRequest); + + m_requestQueue->pushInput({}); +} void RequestProcessor::processRequests (int limit) { using namespace std::chrono_literals; // critical section (exclusive access to std::cout signaled by locking lck): std::unique_lock setLck (setProcessingMtx,std::defer_lock); + if (m_iterateFilesRequest != nullptr) { +// std::cout << "m_iterateFilesRequest lol " << std::endl; +// std::this_thread::sleep_for(10000ms); + + iterateFilesInternal(m_iterateFilesRequest->process, m_iterateFilesRequest->callback); + + m_iterateFilesRequest = nullptr; +// std::cout << "m_iterateFilesRequest destroyed" << std::endl; + } + if (m_threaded) { m_requestQueue->waitAndProcess([&](const RequestStruct &it) { + if (it.fileName == "") return; + this->processFileRequest(it.fileName, it.holderType, it.s_file); setLck.lock(); @@ -51,6 +68,8 @@ void RequestProcessor::processRequests (int limit) { }); } else { m_requestQueue->blockProcessWithoutWait(limit, [&](const RequestStruct &it) { + if (it.fileName == "") return; + this->processFileRequest(it.fileName, it.holderType, it.s_file); setLck.lock(); diff --git a/src/persistance/RequestProcessor.h b/src/persistance/RequestProcessor.h index 13b90b862..4cdc205f0 100644 --- a/src/persistance/RequestProcessor.h +++ b/src/persistance/RequestProcessor.h @@ -15,6 +15,19 @@ #include #include +struct IterateFilesRequest { + IterateFilesRequest(std::unique_lock &a, + std::function b, + std::function c) : m(std::move(a)){ + process = b; + callback = c; + } + + std::unique_lock m; + std::function process; + std::function callback; +}; + class RequestProcessor : public IFileRequest { protected: RequestProcessor() : toBeProcessed(0){ @@ -65,15 +78,22 @@ class RequestProcessor : public IFileRequest { bool m_threaded = false; bool dumb_boolean_always_false = false; + + std::unique_ptr m_iterateFilesRequest; public: void processRequests(int limit); bool completedAllJobs() { return (m_requestQueue->empty()) && (m_resultQueue.empty()) && (toBeProcessed == 0); }; + void iterateAllFiles( std::unique_ptr &iterateFilesRequest ); + protected: std::atomic toBeProcessed; void processResult(const std::shared_ptr &s_file, const HFileContent &content, const std::string &fileName); + virtual void iterateFilesInternal( + std::function &process, + std::function &callback) {}; }; typedef std::shared_ptr HRequestProcessor; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 2b816178d..15bc40142 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -63,6 +63,8 @@ class StatementHolderAbstract { public: virtual ~StatementHolderAbstract() {}; virtual std::vector execute(decltype(FileListDB::makeStorage("")) &storage, int limit, int offset) = 0; + virtual FileListDB::FileRecord getOrCreateFile(decltype(FileListDB::makeStorage("")) &storage, int fileDataId, const std::string &fileName) = 0; + virtual void setFileType(decltype(FileListDB::makeStorage("")) &storage, int fileDataId, const std::string &filetype) = 0; virtual int getTotal() = 0; }; @@ -70,6 +72,10 @@ decltype(FileListDB::makeStorage("")) *u_storage; template class StatementHolderA { +private: + int refFileDataId = 0; + std::string refFileName = ""; + std::string refFileType = ""; public: std::function calcTotal; @@ -91,8 +97,6 @@ class StatementHolderA { calcTotal(); - - if constexpr (order == 1) { return [statement = storage.prepare(get_all( @@ -149,24 +153,80 @@ class StatementHolderA { // std::cout << get<2>(statement) << std::endl; // std::cout << get<3>(statement) << std::endl; } + auto createCheckFileOrCreate(decltype(FileListDB::makeStorage("")) &storage) { + using namespace sqlite_orm; + + return [&, statement = storage.prepare(select( + columns(&FileListDB::FileRecord::fileDataId, &FileListDB::FileRecord::fileName, &FileListDB::FileRecord::fileType), + where( + (c(&FileListDB::FileRecord::fileDataId) == std::ref(refFileDataId)) || + (c(&FileListDB::FileRecord::fileName) == std::ref(refFileName)) + ) + )) + ](decltype(storage) &storage, int fileDataId, const std::string &fileName) { + this->refFileDataId = fileDataId; + this->refFileName = fileName; + auto records = storage.execute(statement); + if (!records.empty()) { + auto &record = records[0]; + return FileListDB::FileRecord({get<0>(record), get<1>(record), get<2>(record)}); + }; + + FileListDB::FileRecord newFile; + newFile.fileDataId = fileDataId; + newFile.fileName = fileName; + + storage.replace(newFile); + + return newFile; + }; + } + + auto createSetFileType(decltype(FileListDB::makeStorage("")) &storage) { + using namespace sqlite_orm; + + return [&, statement = storage.prepare(update_all( + set(assign(&FileListDB::FileRecord::fileType, std::ref(refFileType))), + where( + (c(&FileListDB::FileRecord::fileDataId) == std::ref(refFileDataId)) + ) + )) + ](decltype(storage) &storage, int fileDataId, const std::string &fileType) { + this->refFileDataId = fileDataId; + this->refFileType = fileType; + + storage.execute(statement); + }; + } }; template class StatementHolder: public StatementHolderAbstract, public StatementHolderA { private: decltype(((StatementHolderA *)(nullptr))->createStatement(*u_storage,"", false)) m_statementLambda; + decltype(((StatementHolderA *)(nullptr))->createCheckFileOrCreate(*u_storage)) m_checkFileOrCreate; + decltype(((StatementHolderA *)(nullptr))->createSetFileType(*u_storage)) m_setFileType; public: StatementHolder(decltype(FileListDB::makeStorage("")) &storage,const std::string &searchClause, bool sortAsc) : - m_statementLambda(StatementHolderA::createStatement(storage, searchClause, sortAsc)) { + m_statementLambda(StatementHolderA::createStatement(storage, searchClause, sortAsc)), + m_checkFileOrCreate(StatementHolderA::createCheckFileOrCreate(storage)), + m_setFileType(StatementHolderA::createSetFileType(storage)) { } std::vector execute(decltype(FileListDB::makeStorage("")) &storage, int limit, int offset) override { return m_statementLambda(storage, limit, offset); } + int getTotal() override { return StatementHolderA::calcTotal(); }; + FileListDB::FileRecord getOrCreateFile(decltype(FileListDB::makeStorage("")) &storage, int fileDataId, const std::string &fileName) override { + return m_checkFileOrCreate(storage, fileDataId, fileName); + } + void setFileType(decltype(FileListDB::makeStorage("")) &storage, int fileDataId, const std::string &filetype) override { + m_setFileType(storage, fileDataId, filetype); + }; }; @@ -184,7 +244,7 @@ statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::stri } enum class EnumParamsChanged { - OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING = 2, SCAN_REPOSITORY = 3 + OFFSET_LIMIT = 0, SEARCH_STRING = 1, SORTING = 2, SCAN_REPOSITORY = 3, LOAD_CSV_FILE = 4 }; //namespace std { @@ -277,8 +337,35 @@ class FileListLambdaInst : public FileListLamda { statement = statementFactory(storage, searchClause, m_order); break; - case EnumParamsChanged::SCAN_REPOSITORY: - scanRepository(); + case EnumParamsChanged::SCAN_REPOSITORY: { + std::mutex scanMutex; + + { + auto lock = std::unique_lock(scanMutex); + auto r_unq = std::make_unique( + lock, + [&statement, &storage](int fileDataId, const std::string &fileName) -> bool { + auto fileRecord = statement->getOrCreateFile(storage, fileDataId, fileName); + + return fileRecord.fileType.empty(); + }, + [&statement, &storage](int fileDataId, const HFileContent &fileData) -> void { + statement->setFileType(storage, fileDataId, "unk"); + } + ); + + m_api->requestProcessor->iterateAllFiles(r_unq); + } + std::unique_lock waitLock(scanMutex); + + std::cout << "code after wait lock " << std::endl; + + break; + } + + + case EnumParamsChanged::LOAD_CSV_FILE: + importCSVInternal(storage); break; } @@ -341,6 +428,10 @@ class FileListLambdaInst : public FileListLamda { void scanFiles() override { stateChangeAwaiter.pushInput(EnumParamsChanged::SCAN_REPOSITORY); } + void importCSV() override { + stateChangeAwaiter.pushInput(EnumParamsChanged::LOAD_CSV_FILE); + } + int getCurrentScanningProgress() { return m_currentScanningProgress;} int getAmountOfFilesInRep() { return m_filesInRepository;} private: @@ -349,8 +440,32 @@ class FileListLambdaInst : public FileListLamda { m_results = results; } - void scanRepository() { -// m_api->requestProcessor + void importCSVInternal(decltype(FileListDB::makeStorage("")) &storage) { + auto csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); + + int currentFileDataId; + std::string currentFileName; + + using namespace sqlite_orm; + auto statement = storage.prepare( + select( + columns(&FileListDB::FileRecord::fileType), from(), + where(is_equal(&FileListDB::FileRecord::fileDataId, std::ref(currentFileDataId))) + ) + ); + + while (csv->read_row(currentFileDataId, currentFileName)) { + auto typeFromDB = storage.execute(statement); + + std::string fileType = ""; + if (!typeFromDB.empty()) { + fileType = get<0>(typeFromDB[0]); + } + + storage.replace(FileListDB::FileRecord({currentFileDataId, currentFileName, fileType})); + } + + delete csv; } private: @@ -382,7 +497,7 @@ FileListWindow::FileListWindow(const HApiContainer &api, const std::function(api, filterTextStr, m_filesTotal); + flInterface = std::make_unique(api, filterTextStr, m_filesTotal); } bool FileListWindow::draw() { @@ -393,13 +508,13 @@ bool FileListWindow::draw() { } ImGui::SameLine(); if (ImGui::Button("Scan repository...")) { - + flInterface->scanFiles(); } if (ImGui::InputText("Filter: ", filterText.data(), filterText.size()-1)) { filterText[filterText.size()-1] = 0; filterTextStr = filterText.data(); filterTextStr = "%"+filterTextStr+"%"; - selectStatement->searchChanged(); + flInterface->searchChanged(); } if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | @@ -417,7 +532,7 @@ bool FileListWindow::draw() { ImGui::TableHeadersRow(); ImGuiTableSortSpecs *sorts_specs = ImGui::TableGetSortSpecs(); - if (sorts_specs && sorts_specs->SpecsDirty && selectStatement) { + if (sorts_specs && sorts_specs->SpecsDirty && flInterface) { int order = 1; for (int i = 0; i < sorts_specs->SpecsCount; i++) { auto const &sort_spec = sorts_specs->Specs[i]; @@ -429,12 +544,12 @@ bool FileListWindow::draw() { } } - selectStatement->setOrder(order); + flInterface->setOrder(order); sorts_specs->SpecsDirty = false; } - auto dbResults = selectStatement->getResults(); + auto dbResults = flInterface->getResults(); bool needRequest = false; std::vector newRequests = {}; { @@ -536,7 +651,7 @@ bool FileListWindow::draw() { } } if (needRequest) - selectStatement->makeRequest(newRequests); + flInterface->makeRequest(newRequests); ImGui::EndTable(); } @@ -547,32 +662,6 @@ bool FileListWindow::draw() { } void FileListWindow::importCSV() { -// auto csv = new io::CSVReader<2, io::trim_chars<' '>, io::no_quote_escape<';'>>("listfile.csv"); -// -// int currentFileDataId; -// std::string currentFileName; -// -// using namespace sqlite_orm; -// auto statement = m_storage.prepare( -// select( -// columns(&FileListDB::FileRecord::fileType), from(), -// where(is_equal(&FileListDB::FileRecord::fileDataId, std::ref(currentFileDataId))) -// ) -// ); -// -// while (csv->read_row(currentFileDataId, currentFileName)) { -// auto typeFromDB = m_storage.execute(statement); -// -// std::string fileType = ""; -// if (!typeFromDB.empty()) { -// fileType = get<0>(typeFromDB[0]); -// } -// -// m_storage.replace(FileListDB::FileRecord({currentFileDataId, currentFileName, fileType})); -// } -// -// m_filesTotal = m_storage.count(); -// -// delete csv; + flInterface->importCSV(); } diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index bbe1779a8..77c246f9f 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -11,9 +11,9 @@ namespace FileListDB { struct FileRecord { - int fileDataId; - std::string fileName; - std::string fileType; + int fileDataId = 0; + std::string fileName = ""; + std::string fileType = ""; }; @@ -36,6 +36,7 @@ class FileListLamda { virtual void searchChanged() = 0; virtual void setOrder(int order) = 0; virtual void scanFiles() = 0; + virtual void importCSV() = 0; virtual const std::vector getResults() = 0; }; @@ -51,7 +52,7 @@ class FileListWindow { int m_filesTotal; const HApiContainer m_api; - std::unique_ptr selectStatement; + std::unique_ptr flInterface; std::array filterText = {0}; std::string filterTextStr = "%%"; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f3daaa1a5..e9fb4a014 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,75 +72,75 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct adtLodShader { +struct drawFrustumShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct adtShader { +struct adtLodShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; -struct drawBBShader { +struct adtShader { enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct waterShader { +struct drawLinesShader { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct m2ParticleShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct drawFrustumShader { +struct drawQuad { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct drawPoints { +struct drawPortalShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawQuad { +struct m2Shader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct m2Shader { +struct waterShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawPortalShader { +struct m2ParticleShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct imguiShader { +struct skyConus { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct drawLinesShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterfallShader", +{ "drawBBShader", + { + { "aPosition", 0}, + } +}, +{ "drawFrustumShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,9 +201,41 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawBBShader", +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, +{ "drawQuad", + { + { "position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, { "waterShader", @@ -222,19 +254,16 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "drawFrustumShader", +{ "renderFrameBufferShader", { - { "aPosition", 0}, + { "a_position", 0}, } }, -{ "drawPoints", +{ "ribbonShader", { { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, { "skyConus", @@ -242,7 +271,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "m2Shader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -252,16 +281,6 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, { "wmoShader", { { "aPosition", 0}, @@ -276,33 +295,14 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/ribbonShader.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,0,84}, }, { { @@ -319,10 +319,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -334,17 +336,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, - {0,0,544}, + {0,0,144}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -354,16 +355,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -373,15 +372,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -392,21 +391,13 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { + {0,3, "diffuse"}, }, { { - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -418,13 +409,13 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, - {1,1,16}, + {1,1,48}, + {1,0,64}, }, { { @@ -441,12 +432,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,15 +456,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -475,22 +475,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -498,42 +492,35 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, + {0,0,544}, }, { { {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -542,17 +529,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "visBuffer/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, - {1,0,64}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -562,14 +548,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -579,17 +572,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,96}, + {0,1,112}, }, { { - {0,0,1}, - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -616,14 +608,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -651,7 +644,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { @@ -670,27 +663,21 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, {1,6,0}, - {1,3,0}, + {1,4,0}, {1,1,0}, {1,2,0}, - {1,4,0}, + {1,3,0}, {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -699,15 +686,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -735,15 +722,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { + {0,1,112}, {0,0,544}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -771,15 +759,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -807,14 +795,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -827,12 +816,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -843,15 +831,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -862,12 +851,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -885,16 +868,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {1,0,16}, }, { { - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -904,18 +887,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, - {1,1,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -925,15 +904,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,168}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -946,12 +925,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -963,24 +940,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { ShaderStage::Fragment, { - {2,0,112}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, + {0,2,168}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {2,2,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -991,17 +961,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1010,15 +978,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,16}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,16 +1014,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,544}, + {0,1,32}, }, { { - {0,1,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1068,11 +1035,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1083,16 +1051,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {1,0,16}, + {0,1,16}, }, { { + {1,1,1}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1104,11 +1072,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1119,15 +1089,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1138,27 +1107,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {1,0, "Texture"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1167,15 +1125,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,80}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1203,15 +1161,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,80}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1224,11 +1181,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1239,16 +1197,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {1,0,32}, + {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1260,12 +1219,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1275,18 +1237,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, - {1,1,48}, - {1,0,64}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1298,21 +1258,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1322,16 +1273,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,544}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1295,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1360,18 +1310,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,544}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {2,2,1}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1382,22 +1338,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1406,17 +1357,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,32}, + {1,2,16384}, + {1,0,64}, + {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { - {1,1,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1427,12 +1385,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1443,15 +1400,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,16}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1479,15 +1435,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1498,16 +1454,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1517,17 +1475,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, + {1,1,16}, + {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1555,45 +1514,38 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "visBuffer/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, {0,0,544}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, }, { { - {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, - {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1602,9 +1554,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -1621,21 +1573,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,15 +1590,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/skyConus.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1664,18 +1608,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1685,16 +1625,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { + {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1704,18 +1645,9 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, + {2,0, "uTexture"}, }, { { @@ -1731,16 +1663,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/waterShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1767,17 +1700,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "visBuffer/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1787,16 +1719,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1804,16 +1742,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {2,0,112}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1824,14 +1770,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1879,18 +1828,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {2,0,112}, + {1,5,4096}, + {1,2,16384}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { - {0,1,2}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1901,13 +1856,14 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1916,14 +1872,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "visBuffer/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {1,1,16}, + {0,0,544}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1931,18 +1889,19 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { + {1,0,4096}, }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1952,17 +1911,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, + {1,2,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1977,12 +1936,18 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1992,7 +1957,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "visBuffer/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -2028,15 +1993,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { + {1,0,64}, + {0,0,544}, + {1,1,16}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2063,15 +2031,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2082,16 +2050,27 @@ const std::unordered_map shaderMetaInfo = { } }, { - }, - { - {0,3, "diffuse"}, - }, - { - { - {3,3,1}, - {0,0,0}, + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, + }, + { + {3,0, "s_Textures"}, + }, + { + { + {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2100,40 +2079,43 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "visBuffer/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,2,16384}, - {1,0,64}, {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, }, { { - {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2143,18 +2125,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "visBuffer/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2164,16 +2144,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {2,0, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2182,7 +2173,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -2201,6 +2192,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -2221,75 +2221,140 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"drawFrustumShader", { { - 9, { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, + }}, + {"drawBBShader", { { - 8, { + 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, + {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, + {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, + {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, + {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, + {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, + {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, + {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, + {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, + {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, + {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, } }, + }}, + {"adtLodShader", { { - 7, { + 0, { + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, } }, + }}, + {"adtShader", { { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, + {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, + {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, + {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, + {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, + {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, + {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, + {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, + {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, + {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, + {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, } }, { 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { 2, { } }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 0, { - } - }, }}, - {"adtLodShader", { + {"drawLinesShader", { { 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"adtShader", { + {"drawPoints", { { - 2, { + 0, { + {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, { 1, { + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, } }, + }}, + {"drawQuad", { { - 3, { + 0, { + {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, } }, + }}, + {"drawPortalShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2323,7 +2388,19 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { - { - 9, { - } - }, { - 8, { - } - }, - { - 7, { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, } }, { 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 2, { + {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, } }, { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + 3, { } }, { - 0, { + 5, { + {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, } }, }}, - {"skyConus", { - }}, - {"m2Shader", { - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 7, { - } - }, - { - 8, { - } - }, - { - 9, { - } - }, +}; +const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"drawFrustumShader", { { 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, + }}, + {"drawBBShader", { { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, + {"_0_1_uBBScale", true, 64, 1, 4, 0}, + {"_0_1_uBBCenter", true, 80, 1, 4, 0}, + {"_0_1_uColor", true, 96, 1, 4, 0}, } }, + }}, + {"adtLodShader", { { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + 0, { + {"_0_0_uViewUp", true, 0, 1, 4, 0}, + {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, + {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, + {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, + {"_0_0_FogColor", true, 64, 1, 4, 0}, + {"_0_0_uNewFormula", false, 80, 1, 1, 0}, } }, + }}, + {"drawDepthShader", { { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, + 2, { + {"_0_2_drawDepth", false, 0, 1, 1, 0}, + {"_0_2_uFarPlane", true, 4, 1, 1, 0}, + {"_0_2_uNearPlane", true, 8, 1, 1, 0}, } }, + }}, + {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2796,25 +2744,30 @@ const std::unordered_map Date: Tue, 23 Jan 2024 13:59:51 +0200 Subject: [PATCH 163/212] - load m2/wmo/wdt/blp from filelist --- src/persistance/CascRequestProcessor.cpp | 12 +- src/ui/FrontendUI.cpp | 8 +- src/ui/FrontendUI.h | 2 +- src/ui/childWindow/BLPViewer.cpp | 2 +- .../fileListWindow/FileListWindow.cpp | 250 +++++++++++++----- .../fileListWindow/FileListWindow.h | 3 + .../FrameBasedStackAllocator.h | 4 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/m2Scene.h | 4 +- 11 files changed, 212 insertions(+), 85 deletions(-) diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 345f88ab8..8ac1f9f02 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -245,13 +245,19 @@ void CascRequestProcessor::iterateFilesInternal( auto searchHandle = CascFindFirstFile(m_storage, nullptr, &findData, nullptr); if (searchHandle != INVALID_HANDLE_VALUE ) { do { + if (findData.dwFileDataId == CASC_INVALID_ID) continue; + if (findData.dwContentFlags == CASC_INVALID_ID) continue; + if (!process(findData.dwFileDataId, findData.szFileName)) continue; - auto fileContent = readFileContent(findData.szFileName, findData.dwFileDataId); - if (fileContent) { - callback(findData.dwFileDataId, fileContent); + if (findData.bFileAvailable) { + auto fileContent = readFileContent(findData.szFileName, findData.dwFileDataId); + if (fileContent) { + callback(findData.dwFileDataId, fileContent); + } } } while(CascFindNextFile(searchHandle, &findData)); + CascFindClose(searchHandle); } } diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 3741cc75f..b5ccd6450 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -774,6 +774,12 @@ void FrontendUI::showMainMenu() { m_blpFileViewerWindow = std::make_shared(m_api, m_uiRenderer, true); m_blpFileViewerWindow->loadBlp(std::to_string(fileId)); + } else if (fileType == "m2") { + openM2SceneByfdid(fileId, {}); + } else if (fileType == "wmo") { + openWMOSceneByfdid(fileId); + } else if (fileType == "wdt") { + openMapByIdAndWDTId(0, fileId, 0,0,0); } }); } @@ -1872,7 +1878,7 @@ void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, m_api->camera->setCameraPos(x,y,z); m_api->camera->setMovementSpeed(movementSpeed); } -void FrontendUI::openM2SceneByfdid(int m2Fdid, std::vector &replacementTextureIds) { +void FrontendUI::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2Fdid); m_currentScene = m2Scene; diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index f7fafae30..7957dfcca 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -79,7 +79,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &replacementTextureIds); + void openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds); void openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds); void getCameraPos(float &cameraX,float &cameraY,float &cameraZ); diff --git a/src/ui/childWindow/BLPViewer.cpp b/src/ui/childWindow/BLPViewer.cpp index f6fb82149..0191cbe13 100644 --- a/src/ui/childWindow/BLPViewer.cpp +++ b/src/ui/childWindow/BLPViewer.cpp @@ -7,7 +7,7 @@ #include BLPViewer::BLPViewer(const HApiContainer &api, const std::shared_ptr &uiRenderer, bool noSearch) : - m_api(api), m_uiRenderer(uiRenderer), m_noSearch(noSearch), windowName(std::string("BLP Viewer")+(noSearch ? "_no_search" : "")) + m_api(api), m_uiRenderer(uiRenderer), m_noSearch(noSearch), windowName(std::string("BLP Viewer")+(noSearch ? "##no_search" : "")) { } diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 15bc40142..5a905d5c1 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -7,48 +7,9 @@ #include "../../../../wowViewerLib/src/include/string_utils.h" namespace FileListDB { - struct FileRecord_FT5 { - int fileDataId; - std::string fileName; - std::string fileType; - }; - inline static auto makeStorage(const std::string &dataBaseFile) { using namespace sqlite_orm; return make_storage(dataBaseFile, - make_trigger("files_after_insert", - after() - .insert() - .on() - .begin( - insert(into(), - columns(&FileRecord_FT5::fileDataId, - &FileRecord_FT5::fileName), - values(std::make_tuple(new_(&FileRecord::fileDataId), - new_(&FileRecord::fileName) - ) - ) - ) - ) - .end()), - make_trigger("files_after_delete", - after() - .delete_() - .on() - .begin( - remove_all(where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) - ) - .end()), - make_trigger("files_after_update", - after() - .delete_() - .on() - .begin( - update_all(set(assign(&FileRecord_FT5::fileName, &FileRecord::fileName)), - where(is_equal(old(&FileRecord::fileDataId), &FileRecord_FT5::fileDataId))) - ) - .end()), - make_virtual_table("files_FT5", using_fts5(make_column("fileName", &FileRecord_FT5::fileName), make_column("fileDataId", &FileRecord_FT5::fileDataId))), make_index("idx_files_name", &FileRecord::fileName), make_index("idx_files_type", &FileRecord::fileType), make_table("files", @@ -81,14 +42,13 @@ class StatementHolderA { public: auto createStatement(decltype(FileListDB::makeStorage("")) &storage, - const std::string &searchClause, bool sortAsc) { + const std::string &searchClause, const std::string &fileType, bool sortAsc) { using namespace sqlite_orm; auto whereClause = where( - or_( - like(&FileListDB::FileRecord::fileName, searchClause), - like(&FileListDB::FileRecord::fileDataId, searchClause) - ) + (like(&FileListDB::FileRecord::fileName, searchClause) || + like(&FileListDB::FileRecord::fileDataId, searchClause)) || + like(&FileListDB::FileRecord::fileType, fileType) ); calcTotal = [whereClause, &storage]() { @@ -108,8 +68,8 @@ class StatementHolderA { ))](decltype(storage) &storage, int limit, int offset) mutable { using namespace sqlite_orm; - get<2>(statement) = limit; - get<3>(statement) = offset; + get<3>(statement) = limit; + get<4>(statement) = offset; return storage.execute(statement); }; @@ -124,8 +84,8 @@ class StatementHolderA { ))](decltype(storage) &storage, int limit, int offset) mutable { using namespace sqlite_orm; - get<2>(statement) = limit; - get<3>(statement) = offset; + get<3>(statement) = limit; + get<4>(statement) = offset; return storage.execute(statement); }; @@ -140,8 +100,8 @@ class StatementHolderA { ))](decltype(storage) &storage, int limit, int offset) mutable { using namespace sqlite_orm; - get<2>(statement) = limit; - get<3>(statement) = offset; + get<3>(statement) = limit; + get<4>(statement) = offset; return storage.execute(statement); }; @@ -203,12 +163,12 @@ class StatementHolderA { template class StatementHolder: public StatementHolderAbstract, public StatementHolderA { private: - decltype(((StatementHolderA *)(nullptr))->createStatement(*u_storage,"", false)) m_statementLambda; + decltype(((StatementHolderA *)(nullptr))->createStatement(*u_storage,"", "", false)) m_statementLambda; decltype(((StatementHolderA *)(nullptr))->createCheckFileOrCreate(*u_storage)) m_checkFileOrCreate; decltype(((StatementHolderA *)(nullptr))->createSetFileType(*u_storage)) m_setFileType; public: - StatementHolder(decltype(FileListDB::makeStorage("")) &storage,const std::string &searchClause, bool sortAsc) : - m_statementLambda(StatementHolderA::createStatement(storage, searchClause, sortAsc)), + StatementHolder(decltype(FileListDB::makeStorage("")) &storage,const std::string &searchClause, const std::string &fileType, bool sortAsc) : + m_statementLambda(StatementHolderA::createStatement(storage, searchClause, fileType, sortAsc)), m_checkFileOrCreate(StatementHolderA::createCheckFileOrCreate(storage)), m_setFileType(StatementHolderA::createSetFileType(storage)) { @@ -231,15 +191,15 @@ class StatementHolder: public StatementHolderAbstract, public StatementHolderA -statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, int order) { +statementFactory(decltype(FileListDB::makeStorage("")) &storage, const std::string &searchClause, const std::string &fileType, int order) { switch(abs(order)) { case 2: - return std::make_unique>(storage, searchClause, order > 0); + return std::make_unique>(storage, searchClause, fileType, order > 0); case 3: - return std::make_unique>(storage, searchClause, order > 0); + return std::make_unique>(storage, searchClause, fileType, order > 0); case 1: default: - return std::make_unique>(storage, searchClause, order > 0); + return std::make_unique>(storage, searchClause, fileType, order > 0); } } @@ -299,12 +259,130 @@ class my_container { }; +std::string detectFileType(const HFileContent &fileContent) { + std::string fileType = "unk"; + + if (fileContent == nullptr) return fileType; + + if (fileContent->size() < 4) + return fileType; + + uint32_t magic = *(uint32_t *)fileContent->data(); + magic = ntohl(magic); +// if (magic[0] == 0 || magic[0] == 4) +// { +// if (bin.BaseStream.Length >= 8) +// { +// var wwfMagic = bin.ReadUInt32(); +// switch (wwfMagic) +// { +// case 0x932C64B4: // WWFParticulateGroup +// type = "wwf"; +// break; +// } +// } +// +// bin.BaseStream.Position = 4; +// } + + switch (magic) + { + case 'MD21': + case 'MD20': + fileType = "m2"; + break; + case 'SKIN': + fileType = "skin"; + break; + case 'OggS': + fileType = "ogg"; + break; + case 'BLP2': + fileType = "blp"; + break; + case 'REVM': { + uint8_t *fptr = fileContent->data(); + fptr += 4; + + uint32_t length = *(uint32_t *) fptr; fptr += 4; + if ((fptr - fileContent->data()) + length >= fileContent->size()) return fileType; + + fptr += length; + + uint32_t subChunkMagic = *(uint32_t *) fptr; fptr += 4; + subChunkMagic = ntohl(subChunkMagic); + switch (subChunkMagic) { + case 'RDHM': // ADT root + case 'FDDM': // ADT OBJ + case 'DDLM': // ADT OBJ + case 'DFLM': // ADT OBJ + case 'XDMM': // ADT OBJ (old) + case 'DHLM': // ADT LOD + case 'PMAM': // ADT TEX + fileType = "adt"; + break; + case 'DHOM': // WMO root + fileType = "wmo"; + break; + case 'PGOM': // WMO GROUP + fileType = "gwmo"; + break; + case 'DHPM': // WDT root + fileType = "wdt"; + break; + case 'IOAM': // WDT OCC/LGT + fileType = "wdt_sec"; + break; + default: + fileType = "chUNK"; + break; + } + break; + } + case 'RVXT': + fileType = "tex"; + break; + case 'AFM2': + case 'AFSA': + case 'AFSB': + fileType = "anim"; + break; + case 'WDC5': + case 'WDC4': + case 'WDC3': + fileType = "db2"; + break; + case 'RIFF': + fileType = "avi"; + break; + case 'HSXG': + fileType = "bls"; + break; + case 'SKL1': + fileType = "skel"; + break; + case 'SYHP': + fileType = "phys"; + break; + case 'TAFG': + fileType = "gfat"; + break; + default: + break; + } + +/* + if (magicString.StartsWith("ID3")) + fileType = "mp3"; +*/ + return fileType; +} class FileListLambdaInst : public FileListLamda { public: - FileListLambdaInst(const HApiContainer &api, std::string &searchClause, int &recordsTotal) : m_recordsTotal(recordsTotal), m_api(api) + FileListLambdaInst(const HApiContainer &api, std::string &searchClause, std::string &fileType, int &recordsTotal) : m_recordsTotal(recordsTotal), m_api(api) { dbThread = std::thread([&]() { decltype(FileListDB::makeStorage("")) storage = FileListDB::makeStorage(":memory:"); @@ -317,7 +395,7 @@ class FileListLambdaInst : public FileListLamda { storage.sync_schema(); - std::unique_ptr statement = statementFactory(storage, searchClause, 1); + std::unique_ptr statement = statementFactory(storage, searchClause, fileType, 1); m_recordsTotal = statement->getTotal(); //stateChangeAwaiter.pushInput(EnumParamsChanged::OFFSET_LIMIT); @@ -329,28 +407,32 @@ class FileListLambdaInst : public FileListLamda { break; case EnumParamsChanged::SEARCH_STRING: - statement = statementFactory(storage, searchClause, m_order); + statement = statementFactory(storage, searchClause, fileType, m_order); m_recordsTotal = statement->getTotal(); break; case EnumParamsChanged::SORTING: - statement = statementFactory(storage, searchClause, m_order); + statement = statementFactory(storage, searchClause, fileType, m_order); break; case EnumParamsChanged::SCAN_REPOSITORY: { std::mutex scanMutex; + m_currentScanningProgress = 0; { + auto &l_currentScanningProgress = m_currentScanningProgress; auto lock = std::unique_lock(scanMutex); auto r_unq = std::make_unique( lock, - [&statement, &storage](int fileDataId, const std::string &fileName) -> bool { + [&statement, &storage, &l_currentScanningProgress](int fileDataId, const std::string &fileName) -> bool { + l_currentScanningProgress++; auto fileRecord = statement->getOrCreateFile(storage, fileDataId, fileName); return fileRecord.fileType.empty(); }, [&statement, &storage](int fileDataId, const HFileContent &fileData) -> void { - statement->setFileType(storage, fileDataId, "unk"); + auto fileType = detectFileType(fileData); + statement->setFileType(storage, fileDataId, fileType); } ); @@ -358,7 +440,7 @@ class FileListLambdaInst : public FileListLamda { } std::unique_lock waitLock(scanMutex); - std::cout << "code after wait lock " << std::endl; + m_currentScanningProgress = -1; break; } @@ -432,7 +514,7 @@ class FileListLambdaInst : public FileListLamda { stateChangeAwaiter.pushInput(EnumParamsChanged::LOAD_CSV_FILE); } - int getCurrentScanningProgress() { return m_currentScanningProgress;} + int getCurrentScanningProgress() override { return m_currentScanningProgress;} int getAmountOfFilesInRep() { return m_filesInRepository;} private: void setResults(const std::vector &results) { @@ -497,12 +579,22 @@ FileListWindow::FileListWindow(const HApiContainer &api, const std::function(api, filterTextStr, m_filesTotal); + flInterface = std::make_unique(api, filterTextStr, fileType, m_filesTotal); } bool FileListWindow::draw() { + auto fileScanned = flInterface->getCurrentScanningProgress(); + ImGui::Begin("File list", &m_showWindow); { + bool disableUI = fileScanned >= 0; + + if (disableUI) + { + ImGui::BeginDisabled(); +// ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::Button("Import filelist.csv...")) { importCSV(); } @@ -513,10 +605,20 @@ bool FileListWindow::draw() { if (ImGui::InputText("Filter: ", filterText.data(), filterText.size()-1)) { filterText[filterText.size()-1] = 0; filterTextStr = filterText.data(); + fileType = filterTextStr; filterTextStr = "%"+filterTextStr+"%"; flInterface->searchChanged(); } + if (disableUI) { +// ImGui::PopStyleVar(ImGuiStyleVar_Alpha); + + ImGui::BeginChild("Scanning Region", ImVec2(-1, -1)); + ImGui::Text("Scanning Files %d", fileScanned); + ImGui::EndChild(); + +// ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } else if (ImGui::BeginTable("FileListTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable | @@ -606,8 +708,13 @@ bool FileListWindow::draw() { ImGuiSelectableFlags_AllowItemOverlap)) { lastSelectedFiledataId = fileItem.fileDataId; if (m_fileOpenCallback) { - if (endsWith(fileItem.fileName, ".blp")) { - m_fileOpenCallback(fileItem.fileDataId, "blp"); + std::string fileType = + (fileItem.fileType != "" && fileItem.fileType != "unk") ? fileItem.fileType : + endsWith(fileItem.fileName, ".blp") ? "blp" : + "unk"; + + if (fileType != "unk") { + m_fileOpenCallback(fileItem.fileDataId, fileType); } } } @@ -655,10 +762,15 @@ bool FileListWindow::draw() { ImGui::EndTable(); } + + if (disableUI) { +// ImGui::PopStyleVar(ImGuiStyleVar_Alpha); + ImGui::EndDisabled(); + } } ImGui::End(); - return m_showWindow; + return m_showWindow || fileScanned >= 0; } void FileListWindow::importCSV() { diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.h b/src/ui/childWindow/fileListWindow/FileListWindow.h index 77c246f9f..c628d3db6 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.h +++ b/src/ui/childWindow/fileListWindow/FileListWindow.h @@ -37,6 +37,8 @@ class FileListLamda { virtual void setOrder(int order) = 0; virtual void scanFiles() = 0; virtual void importCSV() = 0; + + virtual int getCurrentScanningProgress() = 0; virtual const std::vector getResults() = 0; }; @@ -55,6 +57,7 @@ class FileListWindow { std::unique_ptr flInterface; std::array filterText = {0}; std::string filterTextStr = "%%"; + std::string fileType = ""; int lastSelectedFiledataId = -1; private: diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index 5746752ed..bd4a4cde5 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -20,7 +20,7 @@ namespace framebased { || defined (_VECTOR_))) #define ARENA_HAS_VECTOR_DEF template - using vector = std::vector; + using vector = std::vector>; #endif #if ((defined (_GLIBCXX_UNORDERED_MAP) \ @@ -29,7 +29,7 @@ namespace framebased { && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) #define ARENA_HAS_UNORDERED_MAP_DEF template , class KeyEqual = std::equal_to> - using unordered_map = std::unordered_map; + using unordered_map = std::unordered_map>>; #endif } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 0c3f6d899..f8352ea4a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -2056,14 +2056,14 @@ void M2Object::updateDynamicMeshes() { // std::cout << "Saved " << skinSection->vertexCount << " vertices " << "at update frame =" << frameNum << std::endl; } } -void M2Object::setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextures) { +void M2Object::setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextures) { m_replaceTextures = replaceTextures; if (m_loaded) { createMeshes(sceneRenderer); // recreate meshes } } -void M2Object::setMeshIds(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) { +void M2Object::setMeshIds(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) { m_meshIds = meshIds; if (m_loaded) { diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index e706fd10c..ec9f3b9f0 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -200,8 +200,8 @@ class M2Object { void setLoadParams(int skinNum, std::vector meshIds, std::vector replaceTextures); - void setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextures); - void setMeshIds(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds); + void setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextures); + void setMeshIds(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds); void setReplaceParticleColors(std::array, 3> &particleColorReplacement); void resetReplaceParticleColor(); bool getReplaceParticleColors(std::array, 3> &particleColorReplacement); diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 1994473c2..1689eebb2 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -54,7 +54,7 @@ extern "C" { extern void offerFileAsDownload(std::string filename, std::string mime); } -void M2Scene::setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextureArray) { +void M2Scene::setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextureArray) { //std::cout << "replaceTextureArray.size == " << replaceTextureArray.size() << std::endl; //std::cout << "m_m2Object == " << m_m2Object << std::endl; if (m_m2Object == nullptr) return; @@ -76,7 +76,7 @@ void M2Scene::setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, m_m2Object->setReplaceTextures(sceneRenderer, replaceTextures); } -void M2Scene::setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) { +void M2Scene::setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) { m_m2Object->setMeshIds(sceneRenderer, meshIds); } diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index c5be386e4..402e8ab13 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -40,8 +40,8 @@ class M2Scene : public Map { } - void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &replaceTextureArray) ; - void setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, std::vector &meshIds) ; + void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextureArray) ; + void setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) ; void setReplaceParticleColors(std::array, 3> &particleColorReplacement) ; void resetReplaceParticleColor() ; From 99c1fbcefa277c7e0f6d34642961302ce92fd462 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 6 Feb 2024 03:14:40 +0200 Subject: [PATCH 164/212] - add WDC5 support --- .gitmodules | 3 + 3rdparty/imgui-notify | 1 + CMakeLists.txt | 3 + .../dataExporter/DataExporterClass.cpp | 6 +- .../dataExporter/DataExporterClass.h | 1 + src/main.cpp | 3 - src/ui/FrontendUI.cpp | 21 +- .../DatabaseUpdateWorkflow.cpp | 5 +- .../childWindow/sceneWindow/SceneWindow.cpp | 13 + src/ui/childWindow/sceneWindow/SceneWindow.h | 17 + wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 1446 ++++++++--------- wowViewerLib/src/logger/viewerLogger.h | 11 + 13 files changed, 796 insertions(+), 736 deletions(-) create mode 160000 3rdparty/imgui-notify create mode 100644 src/ui/childWindow/sceneWindow/SceneWindow.cpp create mode 100644 src/ui/childWindow/sceneWindow/SceneWindow.h create mode 100644 wowViewerLib/src/logger/viewerLogger.h diff --git a/.gitmodules b/.gitmodules index 71a05eaca..62074d7d2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -50,3 +50,6 @@ [submodule "wowViewerLib/3rdparty/tracy"] path = wowViewerLib/3rdparty/tracy url = https://github.com/wolfpld/tracy.git +[submodule "3rdparty/imgui-notify"] + path = 3rdparty/imgui-notify + url = https://github.com/patrickcjk/imgui-notify.git diff --git a/3rdparty/imgui-notify b/3rdparty/imgui-notify new file mode 160000 index 000000000..ad18ef80c --- /dev/null +++ b/3rdparty/imgui-notify @@ -0,0 +1 @@ +Subproject commit ad18ef80cb78852f8b1823a362694113b87e3665 diff --git a/CMakeLists.txt b/CMakeLists.txt index 52bdc930b..16b51db2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,8 @@ set(SOURCE_FILES src/ui/childWindow/textureRenderer/DebugRendererWindow.h src/ui/childWindow/fileListWindow/FileListWindow.cpp src/ui/childWindow/fileListWindow/FileListWindow.h + src/ui/childWindow/sceneWindow/SceneWindow.cpp + src/ui/childWindow/sceneWindow/SceneWindow.h ) @@ -304,6 +306,7 @@ target_include_directories(AWebWoWViewerCpp PUBLIC ${PROJECT_SOURCE_DIR}/WoWView #target_compile_options(AWebWoWViewerCpp PRIVATE "-static") target_compile_definitions(AWebWoWViewerCpp PUBLIC -DIMGUI_USER_CONFIG=) target_include_directories(AWebWoWViewerCpp PUBLIC src/ui/imguiLib) +target_include_directories(AWebWoWViewerCpp PUBLIC 3rdparty/imgui-notify/example/src) add_dependencies(AWebWoWViewerCpp WoWViewerLib) #add_dependencies(AWebWoWViewerCpp storm) diff --git a/src/exporters/dataExporter/DataExporterClass.cpp b/src/exporters/dataExporter/DataExporterClass.cpp index 7bab29bb7..b405870b2 100644 --- a/src/exporters/dataExporter/DataExporterClass.cpp +++ b/src/exporters/dataExporter/DataExporterClass.cpp @@ -5,7 +5,7 @@ #include "DataExporterClass.h" #include "../../../wowViewerLib/src/include/string_utils.h" -DataExporter::DataExporterClass::DataExporterClass(HApiContainer apiContainer) : m_storage(DataExporter::makeStorage("dataExport.db3")) { +DataExporter::DataExporterClass::DataExporterClass(HApiContainer apiContainer) : m_storage(DataExporter::makeStorage(":memory:")) { m_apiContainer = apiContainer; processedFiles = 0; outputLog.open ("m2Log.txt"); @@ -242,3 +242,7 @@ void DataExporter::DataExporterClass::exportDBSkin(int id) { m_storage.insert(dbm2SkinSection); } } + +DataExporter::DataExporterClass::~DataExporterClass() { + m_storage.backup_to("dataExport.db3"); +} diff --git a/src/exporters/dataExporter/DataExporterClass.h b/src/exporters/dataExporter/DataExporterClass.h index 8840c3a85..d51230cd7 100644 --- a/src/exporters/dataExporter/DataExporterClass.h +++ b/src/exporters/dataExporter/DataExporterClass.h @@ -227,6 +227,7 @@ namespace DataExporter { class DataExporterClass { public: DataExporterClass(HApiContainer apiContainer); + ~DataExporterClass(); void process(); bool isDone() { return finished; diff --git a/src/main.cpp b/src/main.cpp index fcaef1301..7872ef7e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -481,9 +481,6 @@ int main(){ frontendUI->newFrame(); stopMouse = frontendUI->getStopMouse(); stopKeyboard = frontendUI->getStopKeyboard(); -// if (stopMouse || stopKeyboard) { -// apiContainer->camera->stopAllMovement(); -// } glfwPollEvents(); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index b5ccd6450..61af72c60 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -36,6 +36,7 @@ #include "../../wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.h" #include "wheelCapture/wheelCapture.h" #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" +#include "imgui_notify.h" FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { m_api = api; @@ -121,9 +122,8 @@ void FrontendUI::composeUI() { m_databaseUpdateWorkflow->render(); } } - if (m_keyUpdateWorkFlow != nullptr) { - if (!m_keyUpdateWorkFlow->render()) - m_keyUpdateWorkFlow = nullptr; + if (m_keyUpdateWorkFlow != nullptr && !m_keyUpdateWorkFlow->render()) { + m_keyUpdateWorkFlow = nullptr; } showSettingsDialog(); @@ -135,6 +135,8 @@ void FrontendUI::composeUI() { showMinimapGenerationSettingsDialog(); showBlpViewer(); + ImGui::RenderNotifications(); + if (m_debugRenderWindow) m_debugRenderWindow->draw(); @@ -784,6 +786,9 @@ void FrontendUI::showMainMenu() { }); } if (ImGui::MenuItem("Open current stats")) { showCurrentStats = true; } + if (ImGui::MenuItem("Test notification")) { + ImGui::InsertNotification({ ImGuiToastType_Info, 3000, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation" }); + } ImGui::Separator(); if (ImGui::MenuItem("Open settings")) {showSettings = true;} if (ImGui::MenuItem("Open QuickLinks")) {showQuickLinks = true;} @@ -796,13 +801,15 @@ void FrontendUI::showMainMenu() { m_blpViewerWindow = std::make_shared(m_api, m_uiRenderer); } + /* if (ImGui::MenuItem("Test export")) { if (m_currentScene != nullptr) { exporter = std::make_shared("./gltf/"); -// currentScene->exportScene(exporter.get()); +// m_currentScene->exportScene(exporter.get()); exporterFramesReady = 0; } } + */ if (ImGui::MenuItem("Test data export")) { m_dataExporter = std::make_shared(m_api); } @@ -1915,9 +1922,9 @@ void FrontendUI::unloadScene() { int FrontendUI::getCameraNumCallback() { -// if (currentScene != nullptr) { -// return currentScene->getCameraNum(); -// } + if (m_currentScene != nullptr) { +// return m_currentScene->getCameraNum(); + } return 0; } diff --git a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp index 9c007400b..b3bd7da16 100644 --- a/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp +++ b/src/ui/childWindow/databaseUpdateWorkflow/DatabaseUpdateWorkflow.cpp @@ -12,6 +12,7 @@ #include "../../../../3rdparty/DBImporter/fileReaders/DBD/DBDFileStorage.h" #include "../../../../3rdparty/DBImporter/exporters/sqlite/CSQLLiteExporter.h" #include "../../../../3rdparty/DBImporter/importers/WDC3/WDC3Importer.h" +#include "../../../../3rdparty/DBImporter/fileReaders/WDC5/DB2Ver5.h" struct RequiredTableStruct { int fileDataId; @@ -197,7 +198,9 @@ void DatabaseUpdateWorkflow::db2UpdateLogic() { addTableLambda = [fileDBDStorage, csqlLiteExporter](std::string tableName, std::shared_ptr db2File) -> bool { std::shared_ptr db2Base = nullptr; - if (*(uint32_t *)db2File->getContent()->data() == '4CDW') { + if (*(uint32_t *)db2File->getContent()->data() == '5CDW') { + db2Base = std::make_shared(); + } else if (*(uint32_t *)db2File->getContent()->data() == '4CDW') { db2Base = std::make_shared(); } else { db2Base = std::make_shared(); diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp new file mode 100644 index 000000000..36c7dd6da --- /dev/null +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -0,0 +1,13 @@ +// +// Created by Deamon on 1/29/2024. +// + +#include "SceneWindow.h" + +SceneWindow::SceneWindow() { + +} + +bool SceneWindow::draw() { + return false; +} diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h new file mode 100644 index 000000000..23ae2975d --- /dev/null +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -0,0 +1,17 @@ +// +// Created by Deamon on 1/29/2024. +// + +#ifndef AWEBWOWVIEWERCPP_SCENEWINDOW_H +#define AWEBWOWVIEWERCPP_SCENEWINDOW_H + + +class SceneWindow { +public: + SceneWindow(); + bool draw(); + +}; + + +#endif //AWEBWOWVIEWERCPP_SCENEWINDOW_H diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index ec9f3b9f0..47aa7680b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -28,7 +28,7 @@ class M2ObjectListContainer; #include "../../../gapi/UniformBufferStructures.h" -class M2Object { +class M2Object : public ObjectWithId { public: friend class IExporter; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index e9fb4a014..f3daaa1a5 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,15 +72,9 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct waterfallShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; @@ -96,51 +90,57 @@ struct adtShader { }; }; -struct drawLinesShader { +struct drawBBShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawBBShaderAttributeEnd }; }; -struct drawPoints { +struct waterShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct drawPortalShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct m2Shader { +struct drawPoints { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct imguiShader { +struct drawQuad { enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct waterShader { +struct skyConus { enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct m2ParticleShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd }; }; @@ -150,41 +150,41 @@ struct renderFrameBufferShader { }; }; -struct ribbonShader { +struct wmoShader { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; -struct skyConus { +struct imguiShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct waterfallShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct wmoShader { +struct ribbonShader { enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "drawFrustumShader", +{ "waterfallShader", { { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, } }, { "adtLodShader", @@ -201,41 +201,9 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "drawBBShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, } }, { "waterShader", @@ -254,16 +222,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "drawFrustumShader", { - { "a_position", 0}, + { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, + } +}, +{ "drawQuad", + { + { "position", 0}, } }, { "skyConus", @@ -271,7 +242,7 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -281,6 +252,16 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -295,14 +276,33 @@ const std::unordered_map> attributesPe { "wmoAmbient", 9}, } }, +{ "imguiShader", + { + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, + } +}, +{ "drawLinesShader", + { + { "aPosition", 0}, + } +}, +{ "ribbonShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + } +}, }; const std::unordered_map shaderMetaInfo = { -{ "forwardRendering/adtLodShader.frag.spv", +{ "visBuffer/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,544}, }, { { @@ -319,12 +319,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -336,16 +334,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "visBuffer/ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {1,1,16}, + {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -355,14 +354,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,4096}, }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -372,15 +373,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "visBuffer/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -391,13 +392,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -409,13 +418,13 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "forwardRendering/wmoShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, - {1,1,48}, {1,0,64}, + {0,0,544}, + {1,1,16}, }, { { @@ -432,21 +441,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -456,15 +456,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "visBuffer/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -475,16 +475,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -492,35 +498,42 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { - {1,0,64}, + {2,0,112}, + {1,5,4096}, + {1,2,16384}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { {0,0,1}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { }, { + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -529,16 +542,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.frag.spv", +{ "forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -548,21 +562,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -572,16 +579,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,544}, + {1,0,96}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -608,15 +616,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -644,7 +651,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "visBuffer/waterfallShader.vert.spv", { ShaderStage::Vertex, { @@ -663,21 +670,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, {1,6,0}, - {1,4,0}, + {1,3,0}, {1,1,0}, {1,2,0}, - {1,3,0}, + {1,4,0}, {1,5,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -686,15 +699,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -722,16 +735,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -759,15 +771,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,128}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -795,15 +807,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -816,11 +827,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -831,16 +843,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "visBuffer/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -851,6 +862,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -868,15 +885,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "visBuffer/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,0,16}, + {0,0,544}, }, { { - {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -884,17 +900,22 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -904,15 +925,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -925,10 +946,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -940,17 +963,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {2,0,112}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -961,15 +991,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { - {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -978,15 +1010,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,16}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1014,15 +1046,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,32}, + {0,1,112}, + {0,0,544}, }, { { - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1035,12 +1068,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1051,16 +1083,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "forwardRendering/drawPortalShader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {1,0,16}, }, { { - {1,1,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1072,13 +1104,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, }, { { {0,0,0}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,14 +1119,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "visBuffer/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1107,16 +1138,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {1,0, "Texture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1125,15 +1167,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "forwardRendering/drawFrustumShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,80}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1161,14 +1203,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,80}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1181,12 +1224,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1197,16 +1239,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, - {0,0,544}, + {0,0,144}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1214,20 +1254,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1237,16 +1275,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, + {1,1,48}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1258,12 +1298,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1273,17 +1322,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "forwardRendering/adtLodShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,96}, + {0,0,84}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1295,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1310,24 +1360,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, + {1,2,32}, {0,0,544}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1338,17 +1382,22 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, + {0,8,9}, {0,0,0}, - {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1357,24 +1406,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,2,16384}, - {1,0,64}, - {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, + {0,1,32}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1385,11 +1427,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1400,14 +1443,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { + {0,0,16}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1435,15 +1479,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,16}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1454,18 +1498,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, - {1,1,0}, }, { - {2,0, "s_Textures"}, + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, + {0,1,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1475,18 +1517,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, + {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {0,1,2}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1514,17 +1555,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,544}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1533,19 +1581,19 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1554,9 +1602,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "visBuffer/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -1573,14 +1621,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1590,14 +1645,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "visBuffer/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1608,14 +1664,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,17 +1685,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "visBuffer/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,9 +1704,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { - {2,0, "uTexture"}, + {2,0, "s_Textures"}, }, { { @@ -1663,16 +1731,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, - {1,0,64}, + {0,0,128}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1680,6 +1746,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { @@ -1700,16 +1767,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,0,64}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1719,22 +1787,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1742,24 +1804,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { ShaderStage::Fragment, { - {2,0,112}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1770,17 +1824,14 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {1,0, "Texture"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1828,24 +1879,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,1,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1856,14 +1901,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1872,16 +1916,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.frag.spv", +{ "forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {0,0,544}, + {0,1,112}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1889,19 +1931,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1911,17 +1952,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, + {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1936,18 +1977,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1957,7 +1992,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.vert.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1993,18 +2028,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {1,0,64}, - {0,0,544}, - {1,1,16}, }, { { - {0,0,1}, - {0,1,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2031,15 +2063,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2050,27 +2082,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2079,17 +2100,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,2,16384}, + {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2098,24 +2126,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2125,16 +2143,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,1,16}, + {1,0,4096}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2144,24 +2164,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "uTexture"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -2169,11 +2177,12 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -2192,15 +2201,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -2221,140 +2221,75 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawFrustumShader", { + {"waterfallShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 9, { } }, - }}, - {"drawBBShader", { { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + 8, { } }, { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + 7, { } }, - }}, - {"adtShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, } }, { 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { 2, { } }, - }}, - {"drawLinesShader", { + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, { 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, } }, }}, - {"drawPoints", { + {"adtLodShader", { { 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_uPos", true, 0, 1, 3, 0}, + {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, + {"_0_0_uPMatrix", true, 80, 4, 4, 0}, + } + }, + }}, + {"adtShader", { + { + 2, { } }, { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, } }, - }}, - {"drawQuad", { { - 0, { - {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, + 3, { } }, - }}, - {"drawPortalShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2388,19 +2323,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"waterfallShader", { { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { + } + }, + { + 7, { } }, { 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, } }, { 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { 2, { - {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, } }, { - 3, { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, + 0, { } }, }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"drawFrustumShader", { + {"skyConus", { + }}, + {"m2Shader", { + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 7, { + } + }, + { + 8, { + } + }, + { + 9, { + } + }, { 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, } }, - }}, - {"drawBBShader", { + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, { 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, - }}, - {"adtLodShader", { { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, - }}, - {"drawDepthShader", { { - 2, { - {"_0_2_drawDepth", false, 0, 1, 1, 0}, - {"_0_2_uFarPlane", true, 4, 1, 1, 0}, - {"_0_2_uNearPlane", true, 8, 1, 1, 0}, + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, } }, - }}, - {"adtShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2744,30 +2796,25 @@ const std::unordered_map + +class IMessLogger { +public: + enum class MessageType : int { + INFO, ERROR, WARNING, DEBUG + }; + + virtual void log(const std::string &message) = 0; +}; \ No newline at end of file From 039a2d5052bf62b20d648f40c0c974d8dd24a645 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 6 Feb 2024 03:28:27 +0200 Subject: [PATCH 165/212] - update DBImporter --- 3rdparty/DBImporter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index 279e61a78..8c06020a5 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit 279e61a789d34446b44033b5d63dfa3c1c5292d4 +Subproject commit 8c06020a5332796a5399583c5f6f18a917b6c555 From cf9c728927d3c74e7d9bc48d0d19e33f4de60868 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 7 Feb 2024 11:39:07 +0200 Subject: [PATCH 166/212] - refactoring UI: untie scene stuff from main class --- CMakeLists.txt | 2 + src/main.cpp | 2 +- src/ui/FrontendUI.cpp | 280 +++-------------- src/ui/FrontendUI.h | 17 +- src/ui/childWindow/m2Window/M2Window.cpp | 5 + src/ui/childWindow/m2Window/M2Window.h | 20 ++ .../childWindow/sceneWindow/SceneWindow.cpp | 284 +++++++++++++++++- src/ui/childWindow/sceneWindow/SceneWindow.h | 49 ++- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.h | 2 +- .../src/engine/shader/ShaderDefinitions.h | 222 ++++---------- wowViewerLib/src/renderer/IRenderParameters.h | 11 +- 12 files changed, 470 insertions(+), 426 deletions(-) create mode 100644 src/ui/childWindow/m2Window/M2Window.cpp create mode 100644 src/ui/childWindow/m2Window/M2Window.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 16b51db2b..b12592567 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,8 @@ set(SOURCE_FILES src/ui/childWindow/fileListWindow/FileListWindow.h src/ui/childWindow/sceneWindow/SceneWindow.cpp src/ui/childWindow/sceneWindow/SceneWindow.h + src/ui/childWindow/m2Window/M2Window.cpp + src/ui/childWindow/m2Window/M2Window.h ) diff --git a/src/main.cpp b/src/main.cpp index 7872ef7e4..c5e0f4ba6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -418,7 +418,7 @@ int main(){ SceneComposer sceneComposer = SceneComposer(apiContainer); - frontendUI = std::make_shared(apiContainer, nullptr); + frontendUI = std::make_shared(apiContainer); glfwSetWindowUserPointer(window, &apiContainer); glfwSetKeyCallback(window, onKey); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 61af72c60..4450e90fd 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -38,7 +38,7 @@ #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "imgui_notify.h" -FrontendUI::FrontendUI(HApiContainer api, HRequestProcessor processor) { +FrontendUI::FrontendUI(HApiContainer api) : SceneWindow(api) { m_api = api; this->createDatabaseHandler(); @@ -223,8 +223,8 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); } - if (m_sceneRenderer) { - auto mapPlan = m_sceneRenderer->getLastCreatedPlan(); + if (SceneWindow::hasRenderer()) { + auto mapPlan = SceneWindow::getLastPlan(); if (mapPlan) { auto &cullStageData = mapPlan; @@ -920,47 +920,6 @@ bool FrontendUI::getStopKeyboard() { return io.WantCaptureKeyboard; } -std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneType, const std::string& name, int cameraNum) { - apiContainer->camera = std::make_shared(); - if (sceneType == -1) { - return std::make_shared(); - } else if (sceneType == 0) { -// m_usePlanarCamera = cameraNum == -1; - - - return std::make_shared(apiContainer, name); - } else if (sceneType == 1) { - return std::make_shared(apiContainer, name); - } else if (sceneType == 2) { - auto &adtFileName = name; - - size_t lastSlashPos = adtFileName.find_last_of("/"); - size_t underscorePosFirst = adtFileName.find_last_of("_"); - size_t underscorePosSecond = adtFileName.find_last_of("_", underscorePosFirst-1); - std::string mapName = adtFileName.substr(lastSlashPos+1, underscorePosSecond-lastSlashPos-1); - - int i = std::stoi(adtFileName.substr(underscorePosSecond+1, underscorePosFirst-underscorePosSecond-1)); - int j = std::stoi(adtFileName.substr(underscorePosFirst+1, adtFileName.size()-underscorePosFirst-5)); - - float adt_x_min = AdtIndexToWorldCoordinate(j); - float adt_x_max = AdtIndexToWorldCoordinate(j+1); - - float adt_y_min = AdtIndexToWorldCoordinate(i); - float adt_y_max = AdtIndexToWorldCoordinate(i+1); - - apiContainer->camera = std::make_shared(); - apiContainer->camera->setCameraPos( - (adt_x_min+adt_x_max) / 2.0, - (adt_y_min+adt_y_max) / 2.0, - 200 - ); - - return std::make_shared(apiContainer, adtFileName, i, j, mapName); - } - - return nullptr; -} - void FrontendUI::showQuickLinksDialog() { if (!showQuickLinks) return; std::vector replacementTextureFDids = {}; @@ -1000,9 +959,7 @@ void FrontendUI::showQuickLinksDialog() { openWMOSceneByfdid(4638404); } if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, "world/wmo/dungeon/az_karazahn/karazhan.wmo"); - m_api->camera->setCameraPos(0, 0, 0); + openWMOSceneByFilename("world/wmo/dungeon/az_karazahn/karazhan.wmo"); } if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { openWMOSceneByfdid(4419436); @@ -1263,7 +1220,7 @@ void FrontendUI::showQuickLinksDialog() { openM2SceneByfdid(3732303, replacementTextureFDids); } if (ImGui::Button("Bugged ADT (SL)", ImVec2(-1, 0))) { - m_currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); +// m_currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); } ImGui::Separator(); ImGui::Text("Models for billboard checking"); @@ -1458,8 +1415,8 @@ void FrontendUI::showSettingsDialog() { m_debugRenderView = nullptr; } } - if (useDoubleCameraDebug && (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) && m_sceneRenderer != nullptr) { - m_debugRenderView = m_sceneRenderer->createRenderView(640, 480, true); + if (useDoubleCameraDebug && (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) && SceneWindow::hasRenderer()) { + m_debugRenderView = SceneWindow::createRenderView(); m_debugRenderWindow = std::make_shared(m_api, m_uiRenderer, m_debugRenderView); } @@ -1501,9 +1458,7 @@ void FrontendUI::showSettingsDialog() { } if (ImGui::CollapsingHeader("Light options")) { - auto mapPlan = (m_sceneRenderer != nullptr) ? - m_sceneRenderer->getLastCreatedPlan() : - nullptr; + auto mapPlan = SceneWindow::getLastPlan(); switch(m_api->getConfig()->globalLighting) { case EParameterSource::eDatabase: { @@ -1680,65 +1635,6 @@ void FrontendUI::showMakeScreenshotDialog() { } } -mathfu::mat4 getInfZMatrix(float f, float aspect) { - return mathfu::mat4( - f / aspect, 0.0f, 0.0f, 0.0f, - 0.0f, f, 0.0f, 0.0f, - 0.0f, 0.0f, 1, -1.0f, - 0.0f, 0.0f, 1, 0.0f); -} - -struct RenderTargetParameters { - std::shared_ptr camera; - ViewPortDimensions dimensions; - std::shared_ptr target; -}; - -HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, - float fov, - const std::vector &renderTargetParams, - const std::shared_ptr ¤tScene) { - - auto result = std::make_shared(); - result->scene = currentScene; - - float farPlaneRendering = apiContainer.getConfig()->farPlane; - float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; - - float nearPlane = 1.0; - float fovR = toRadian(fov); - - { - auto width = renderTargetParams[0].dimensions.maxs[0]; - auto height = renderTargetParams[0].dimensions.maxs[1]; - float canvasAspect = (float) width / (float) height; - - result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, - farPlaneCulling); - } - - bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); - auto assignInfiniteZ = [&](auto renderTarget, auto canvasAspect) { - float f = 1.0f / tan(fovR / 2.0f); - renderTarget.cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); - }; - - for (auto &targetParam : renderTargetParams) { - auto width = targetParam.dimensions.maxs[0]; - auto height = targetParam.dimensions.maxs[1]; - float canvasAspect = (float)width / (float)height; - - auto &renderTarget = result->renderTargets.emplace_back(); - renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling);; - renderTarget.viewPortDimensions = targetParam.dimensions; - renderTarget.target = targetParam.target; - if (isInfZSupported) assignInfiniteZ(renderTarget, canvasAspect); - } - - result->clearColor = apiContainer.getConfig()->clearColor; - - return result; -} HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, double deltaTime) { ZoneScoped ; @@ -1747,7 +1643,10 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do } auto l_device = m_api->hDevice; auto processingFrame = l_device->getFrameNumber(); - auto updateFrameNumberLambda = [l_device](unsigned int frame) -> void {l_device->setCurrentProcessingFrameNumber(frame);}; + std::function updateFrameNumberLambda = [l_device, frame = processingFrame]() -> uint32_t { + l_device->setCurrentProcessingFrameNumber(frame); + return frame; + }; HFrameScenario scenario = std::make_shared(); @@ -1756,82 +1655,32 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do {0, 0}, {static_cast(canvWidth), static_cast(canvHeight)} }; - ViewPortDimensions debugViewDimension = dimension; - - if (m_sceneRenderer != nullptr) { - auto wowSceneFrameInput = std::make_shared>(); - wowSceneFrameInput->delta = deltaTime * (1000.0f); - - std::shared_ptr target = nullptr; - std::shared_ptr debugTarget = nullptr; - if (m_api->debugCamera && m_api->getConfig()->doubleCameraDebug && m_debugRenderView) { - debugTarget = m_debugRenderView; - - debugViewDimension = { - {0, 0}, - {static_cast(m_debugRenderWindow->getWidth()), - static_cast(m_debugRenderWindow->getHeight())} - }; - - if (m_api->getConfig()->swapMainAndDebug) { - std::swap(target, debugTarget); - std::swap(dimension, debugViewDimension); - } - } - std::vector renderTargetParams = { - { - m_api->camera, - dimension, - target - } - }; - if (m_api->getConfig()->doubleCameraDebug) { - auto &debugParams = renderTargetParams.emplace_back(); - debugParams.camera = m_api->debugCamera; - debugParams.dimensions = debugViewDimension; - debugParams.target = debugTarget; - } + uint32_t debugWidth = 0; uint32_t debugHeight = 0; + if (m_debugRenderWindow) { + debugWidth = m_debugRenderWindow->getWidth(); + debugHeight = m_debugRenderWindow->getHeight(); + } - wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, - fov, - renderTargetParams, - m_currentScene); - scenario->cullFunctions.push_back( - m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput, processingFrame, updateFrameNumberLambda)); - - //---------------------- - // Screenshot part - //---------------------- - - if (needToMakeScreenshot) { - auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight, true); - auto wowSceneScreenshotFrameInput = std::make_shared>(); - wowSceneScreenshotFrameInput->delta = 0; - - wowSceneScreenshotFrameInput->frameParameters = createMapSceneParams( - *m_api, - fov, - {{ - m_api->camera, - { - {0, 0}, - {static_cast(screenShotWidth), static_cast(screenShotHeight)} - }, - screenShotRenderView - }}, - m_currentScene - ); - scenario->onFinish.push_back([screenShotRenderView, this, processingFrame]() { - saveDataFromDrawStage([screenShotRenderView, processingFrame](int x, int y, int width, int height, uint8_t* data){ - screenShotRenderView->readRGBAPixels(processingFrame, x, y, width, height, data); - }, screenshotFilename, screenShotWidth, screenShotHeight); - }); - needToMakeScreenshot = false; - - scenario->cullFunctions.push_back( - m_sceneRenderer->createCullUpdateRenderChain(wowSceneScreenshotFrameInput, processingFrame, updateFrameNumberLambda)); - } + SceneWindow::render(deltaTime, fov, scenario, dimension, + updateFrameNumberLambda, + m_debugRenderView, + debugWidth, + debugHeight + ); + + //---------------------- + // Screenshot part + //---------------------- + + if (needToMakeScreenshot) { + SceneWindow::makeScreenshot(fov, + screenShotWidth, screenShotHeight, + screenshotFilename, + scenario, + updateFrameNumberLambda); + + needToMakeScreenshot = false; } auto uiFrameInput = std::make_shared>(); @@ -1840,7 +1689,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do auto clearColor = m_api->getConfig()->clearColor; - scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput, processingFrame, updateFrameNumberLambda)); + scenario->cullFunctions.push_back(m_uiRenderer->createCullUpdateRenderChain(uiFrameInput, updateFrameNumberLambda)); } return scenario; @@ -1864,67 +1713,22 @@ bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { return true; } -void FrontendUI::openWMOSceneByfdid(int WMOFdid) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, WMOFdid); - m_api->camera->setCameraPos(0, 0, 0); -} -void FrontendUI::openMapByIdAndFilename(int mapId, std::string mapName, float x, float y, float z) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, mapId, mapName); - - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(x,y,z); - m_api->camera->setMovementSpeed(movementSpeed); -} -void FrontendUI::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, mapId, wdtFileId); - - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(x,y,z); - m_api->camera->setMovementSpeed(movementSpeed); -} -void FrontendUI::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - auto m2Scene = std::make_shared(m_api, m2Fdid); - m_currentScene = m2Scene; - m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); - - m_api->camera = std::make_shared(); - m_api->camera->setMovementSpeed(movementSpeed); - m_api->getConfig()->BCLightHack = false; -// - m_api->camera->setCameraPos(0, 0, 0); -} - -void FrontendUI::openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds) { - m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - - auto m2Scene = std::make_shared(m_api, m2FileName); - m_currentScene = m2Scene; - m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); - - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(0, 0, 0); - m_api->camera->setMovementSpeed(movementSpeed); -} void FrontendUI::unloadScene() { if (m_api->cacheStorage) { m_api->cacheStorage->actuallDropCache(); } - m_sceneRenderer = nullptr; - m_currentScene = std::make_shared(); + + SceneWindow::unload(); } int FrontendUI::getCameraNumCallback() { - if (m_currentScene != nullptr) { -// return m_currentScene->getCameraNum(); - } +// if (m_currentScene != nullptr) { +//// return m_currentScene->getCameraNum(); +// } return 0; } diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 7957dfcca..70fd797d5 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -29,14 +29,15 @@ #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "childWindow/textureRenderer/DebugRendererWindow.h" #include "childWindow/fileListWindow/FileListWindow.h" +#include "childWindow/sceneWindow/SceneWindow.h" -class FrontendUI : public IScene, public std::enable_shared_from_this { +class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_from_this { public: void createDefaultprocessor(); void createDatabaseHandler(); - FrontendUI(HApiContainer api, HRequestProcessor processor); + FrontendUI(HApiContainer api); ~FrontendUI() override { fileDialog.Close(); createFileDialog.Close(); @@ -73,14 +74,11 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_sceneRenderer = nullptr; - std::shared_ptr m_currentScene = nullptr; + bool tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef); - void openWMOSceneByfdid(int WMOFdid); - void openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds); - void openM2SceneByName(std::string m2FileName, std::vector &replacementTextureIds); + void getCameraPos(float &cameraX,float &cameraY,float &cameraZ); void getDebugCameraPos(float &cameraX,float &cameraY,float &cameraZ); @@ -143,7 +141,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &renderTargetParams, + const std::shared_ptr ¤tScene) { + + auto result = std::make_shared(); + result->scene = currentScene; + + float farPlaneRendering = apiContainer.getConfig()->farPlane; + float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; + + float nearPlane = 1.0; + float fovR = toRadian(fov); + + { + auto width = renderTargetParams[0].dimensions.maxs[0]; + auto height = renderTargetParams[0].dimensions.maxs[1]; + float canvasAspect = (float) width / (float) height; + + result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, + farPlaneCulling); + } + + bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); + auto assignInfiniteZ = [&](auto renderTarget, auto canvasAspect) { + float f = 1.0f / tan(fovR / 2.0f); + renderTarget.cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); + }; + + for (auto &targetParam : renderTargetParams) { + auto width = targetParam.dimensions.maxs[0]; + auto height = targetParam.dimensions.maxs[1]; + float canvasAspect = (float)width / (float)height; + auto &renderTarget = result->renderTargets.emplace_back(); + renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling);; + renderTarget.viewPortDimensions = targetParam.dimensions; + renderTarget.target = targetParam.target; + if (isInfZSupported) assignInfiniteZ(renderTarget, canvasAspect); + } + + result->clearColor = apiContainer.getConfig()->clearColor; + + return result; +} + +SceneWindow::SceneWindow(HApiContainer api) : m_api(api) { } bool SceneWindow::draw() { return false; +}; + +std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneType, const std::string& name, int cameraNum) { + apiContainer->camera = std::make_shared(); + if (sceneType == -1) { + return std::make_shared(); + } else if (sceneType == 0) { +// m_usePlanarCamera = cameraNum == -1; + + + return std::make_shared(apiContainer, name); + } else if (sceneType == 1) { + return std::make_shared(apiContainer, name); + } else if (sceneType == 2) { + auto &adtFileName = name; + + size_t lastSlashPos = adtFileName.find_last_of("/"); + size_t underscorePosFirst = adtFileName.find_last_of("_"); + size_t underscorePosSecond = adtFileName.find_last_of("_", underscorePosFirst-1); + std::string mapName = adtFileName.substr(lastSlashPos+1, underscorePosSecond-lastSlashPos-1); + + int i = std::stoi(adtFileName.substr(underscorePosSecond+1, underscorePosFirst-underscorePosSecond-1)); + int j = std::stoi(adtFileName.substr(underscorePosFirst+1, adtFileName.size()-underscorePosFirst-5)); + + float adt_x_min = AdtIndexToWorldCoordinate(j); + float adt_x_max = AdtIndexToWorldCoordinate(j+1); + + float adt_y_min = AdtIndexToWorldCoordinate(i); + float adt_y_max = AdtIndexToWorldCoordinate(i+1); + + apiContainer->camera = std::make_shared(); + apiContainer->camera->setCameraPos( + (adt_x_min+adt_x_max) / 2.0, + (adt_y_min+adt_y_max) / 2.0, + 200 + ); + + return std::make_shared(apiContainer, adtFileName, i, j, mapName); + } + + return nullptr; +} + +void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + m_currentScene = std::make_shared(m_api, mapId, wdtFileId); + + m_api->camera = std::make_shared(); + m_api->camera->setCameraPos(x,y,z); + m_api->camera->setMovementSpeed(movementSpeed); +} +void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + auto m2Scene = std::make_shared(m_api, m2Fdid); + m_currentScene = m2Scene; + m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); + + + m_api->camera = std::make_shared(); + m_api->camera->setMovementSpeed(movementSpeed); + m_api->getConfig()->BCLightHack = false; +// + m_api->camera->setCameraPos(0, 0, 0); +} + + + +void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::vector &replacementTextureIds) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + + auto m2Scene = std::make_shared(m_api, m2FileName); + m_currentScene = m2Scene; + m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); + + m_api->camera = std::make_shared(); + m_api->camera->setCameraPos(0, 0, 0); + m_api->camera->setMovementSpeed(movementSpeed); +} + +void SceneWindow::openWMOSceneByfdid(int WMOFdid) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + m_currentScene = std::make_shared(m_api, WMOFdid); + m_api->camera->setCameraPos(0, 0, 0); +} +void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + m_currentScene = std::make_shared(m_api, wmoFileName); + m_api->camera->setCameraPos(0, 0, 0); +} + +void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z) { + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); + m_currentScene = std::make_shared(m_api, mapId, mapName); + + m_api->camera = std::make_shared(); + m_api->camera->setCameraPos(x,y,z); + m_api->camera->setMovementSpeed(movementSpeed); +} + + + +void SceneWindow::unload() { + m_sceneRenderer = nullptr; + m_currentScene = std::make_shared(); +} + +std::shared_ptr SceneWindow::getLastPlan() { + return (m_sceneRenderer) ? m_sceneRenderer->getLastCreatedPlan() : nullptr; +} + +bool SceneWindow::hasRenderer() { + return m_sceneRenderer != nullptr; +} + +std::shared_ptr SceneWindow::createRenderView() { + if (m_sceneRenderer == nullptr) return nullptr; + + return m_sceneRenderer->createRenderView(640, 480, true); +} + +void +SceneWindow::render(double deltaTime, + float fov, + const HFrameScenario &scenario, + const ViewPortDimensions &dimension, + const std::function &updateFrameNumberLambda, + const std::shared_ptr &debugRenderView, + uint32_t debugViewWidth, + uint32_t debugViewHeight) +{ + if (!hasRenderer()) return; + + auto wowSceneFrameInput = std::make_shared>(); + wowSceneFrameInput->delta = deltaTime * (1000.0f); + + std::shared_ptr target = nullptr; + std::shared_ptr debugTarget = nullptr; + + ViewPortDimensions l_dimension = dimension; + ViewPortDimensions debugViewDimension = dimension; + if (debugRenderView) { + debugTarget = debugRenderView; + + ViewPortDimensions debugViewDimension = { + {0, 0}, + {static_cast(debugViewWidth), + static_cast(debugViewHeight)} + }; + + if (m_api->getConfig()->swapMainAndDebug) { + std::swap(target, debugTarget); + std::swap(l_dimension, debugViewDimension); + } + } + + std::vector renderTargetParams = { + { + m_api->camera, + dimension, + target + } + }; + + if (m_api->getConfig()->doubleCameraDebug) { + auto &debugParams = renderTargetParams.emplace_back(); + debugParams.camera = m_api->debugCamera; + debugParams.dimensions = debugViewDimension; + debugParams.target = debugTarget; + } + + wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, + fov, + renderTargetParams, + m_currentScene); + + scenario->cullFunctions.push_back( + m_sceneRenderer->createCullUpdateRenderChain(wowSceneFrameInput, updateFrameNumberLambda) + ); +} + +void +SceneWindow::makeScreenshot(float fov, + uint32_t screenShotWidth, uint32_t screenShotHeight, + const std::string &screenshotFilename, + const HFrameScenario &scenario, + const std::function &updateFrameNumberLambda) +{ + auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight, true); + auto wowSceneScreenshotFrameInput = std::make_shared>(); + wowSceneScreenshotFrameInput->delta = 0; + + wowSceneScreenshotFrameInput->frameParameters = createMapSceneParams( + *m_api, + fov, + {{ + m_api->camera, + { + {0, 0}, + {static_cast(screenShotWidth), static_cast(screenShotHeight)} + }, + screenShotRenderView + }}, + m_currentScene + ); + + auto processingFrame = updateFrameNumberLambda(); + + scenario->cullFunctions.push_back( + m_sceneRenderer->createCullUpdateRenderChain(wowSceneScreenshotFrameInput, updateFrameNumberLambda) + ); + + scenario->onFinish.push_back([screenShotRenderView, screenShotWidth, screenShotHeight, screenshotFilename, processingFrame]() { + saveDataFromDrawStage([screenShotRenderView, processingFrame](int x, int y, int width, int height, uint8_t* data){ + screenShotRenderView->readRGBAPixels(processingFrame, x, y, width, height, data); + }, screenshotFilename, screenShotWidth, screenShotHeight); + }); + + + scenario->onFinish.push_back([screenShotRenderView, screenShotWidth, screenShotHeight, screenshotFilename, processingFrame]() { + saveDataFromDrawStage([screenShotRenderView, processingFrame](int x, int y, int width, int height, uint8_t* data){ + screenShotRenderView->readRGBAPixels(processingFrame, x, y, width, height, data); + }, screenshotFilename, screenShotWidth, screenShotHeight); + }); } diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 23ae2975d..e39984671 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -5,12 +5,59 @@ #ifndef AWEBWOWVIEWERCPP_SCENEWINDOW_H #define AWEBWOWVIEWERCPP_SCENEWINDOW_H +#include +#include +#include +#include "../../../../wowViewerLib/src/engine/ApiContainer.h" +#include "../../../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" +#include "../../../../wowViewerLib/src/engine/objects/iScene.h" +#include "../../../../wowViewerLib/src/renderer/frame/SceneScenario.h" + +struct RenderTargetParameters { + std::shared_ptr camera; + ViewPortDimensions dimensions; + std::shared_ptr target; +}; class SceneWindow { public: - SceneWindow(); + SceneWindow(HApiContainer api); bool draw(); + void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); + void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); + + void openWMOSceneByfdid(int WMOFdid); + void openWMOSceneByFilename(const std::string &wmoFileName); + void openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds); + void openM2SceneByName(const std::string &m2FileName, const std::vector &replacementTextureIds); + + void unload(); + + std::shared_ptr getLastPlan(); + + bool hasRenderer(); + std::shared_ptr createRenderView(); + void render(double deltaTime, float fov, const HFrameScenario &scenario, + const ViewPortDimensions &dimension, + const std::function &updateFrameNumberLambda, + const std::shared_ptr &debugRenderView, + uint32_t debugViewWidth, + uint32_t debugViewHeight); + + void makeScreenshot(float fov, + uint32_t screenShotWidth, uint32_t screenShotHeight, + const std::string &screenshotFilename, + const HFrameScenario &scenario, + const std::function &updateFrameNumberLambda); + +private: + std::shared_ptr m_sceneRenderer = nullptr; + std::shared_ptr m_currentScene = nullptr; + HApiContainer m_api; +protected: + float movementSpeed = 1; + }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 4a672fabc..e607aa272 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -810,7 +810,7 @@ void AdjustLighting(const mathfu::vec3 color_in, mathfu::vec3 &color_out_0, uint } } -void WmoGroupObject::assignInteriorParams(std::shared_ptr m2Object) { +void WmoGroupObject::assignInteriorParams(const std::shared_ptr &m2Object) { mathfu::vec4 ambientColor = getAmbientColor(); if (!m2Object->setUseLocalLighting(true)) return; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index 64e903618..bc2b267d8 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -58,7 +58,7 @@ class WmoGroupObject { const MathHelper::FrustumCullingData &frustumData); mathfu::vec4 getAmbientColor(); - void assignInteriorParams(std::shared_ptr m2Object); + void assignInteriorParams(const std::shared_ptr &m2Object); bool checkIfInsideGroup(mathfu::vec4 &cameraVec4, mathfu::vec4 &cameraLocal, diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f3daaa1a5..0a59d9f87 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,11 +396,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -507,9 +502,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -676,11 +668,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -866,8 +853,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -906,7 +891,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -947,11 +931,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -969,17 +952,11 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1014,11 +991,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1140,15 +1116,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1171,11 +1138,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1309,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,7 +1530,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -1625,8 +1588,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1666,16 +1627,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1712,7 +1671,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1861,7 +1819,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -2107,17 +2064,12 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2223,11 +2175,8 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 9, { - } - }, - { - 8, { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { @@ -2239,16 +2188,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2729,19 +2629,19 @@ const std::unordered_map getLastCreatedPlan() = 0; CullLambda createCullUpdateRenderChain(const std::shared_ptr> &frameInputParams, - int currentFrame, std::function updateProcessingFrame) { + std::function updateProcessingFrame) { auto this_s = this->shared_from_this(); - auto l_currentFrame = currentFrame; auto l_updateProcessingFrame = std::move(updateProcessingFrame); - return [frameInputParams, this_s, l_currentFrame, l_updateProcessingFrame]() -> SceneUpdateLambda { - l_updateProcessingFrame(l_currentFrame); + return [frameInputParams, this_s, l_updateProcessingFrame]() -> SceneUpdateLambda { + auto l_currentFrame = l_updateProcessingFrame(); TracyMessageStr(("Culling stage frame = " + std::to_string(l_currentFrame))); std::shared_ptr framePlan = this_s->processCulling(frameInputParams); - return [framePlan, frameInputParams, this_s, l_currentFrame, l_updateProcessingFrame]() -> std::unique_ptr { - l_updateProcessingFrame(l_currentFrame); + return [framePlan, frameInputParams, this_s, l_updateProcessingFrame]() -> std::unique_ptr { + auto l_currentFrame = l_updateProcessingFrame(); auto renderFunc = this_s->update(frameInputParams, framePlan); renderFunc->setProcessingFrame(l_currentFrame); From 1f2b67f9df74675a42de7c4261d054aea4424a85 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 8 Feb 2024 12:35:01 +0200 Subject: [PATCH 167/212] - rendering of scene in separate window --- src/ui/FrontendUI.cpp | 29 ++- src/ui/FrontendUI.h | 3 + src/ui/childWindow/m2Window/M2Window.cpp | 70 ++++++ src/ui/childWindow/m2Window/M2Window.h | 23 +- .../childWindow/sceneWindow/SceneWindow.cpp | 15 +- src/ui/childWindow/sceneWindow/SceneWindow.h | 9 +- .../textureRenderer/DebugRendererWindow.cpp | 32 +++ .../textureRenderer/DebugRendererWindow.h | 2 + src/ui/renderer/uiScene/FrontendUIRenderer.h | 1 + .../uiScene/IFrontendUIBufferCreate.h | 1 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 34 +++ .../vulkan/FrontendUIRenderForwardVLK.h | 1 + .../forwardRendering/imguiShaderDepth.frag | 16 ++ .../src/engine/shader/ShaderDefinitions.h | 222 +++++++++++++----- .../src/gapi/interface/textures/ITexture.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 3 + .../src/gapi/vulkan/textures/GTextureVLK.h | 3 + 19 files changed, 396 insertions(+), 73 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/forwardRendering/imguiShaderDepth.frag diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 4450e90fd..e3c9627ba 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -38,7 +38,7 @@ #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "imgui_notify.h" -FrontendUI::FrontendUI(HApiContainer api) : SceneWindow(api) { +FrontendUI::FrontendUI(HApiContainer api) : SceneWindow(api, true) { m_api = api; this->createDatabaseHandler(); @@ -50,6 +50,11 @@ FrontendUI::FrontendUI(HApiContainer api) : SceneWindow(api) { void FrontendUI::composeUI() { ZoneScoped; + { + auto processingFrame = m_api->hDevice->getFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + m_api->hDevice->setCurrentProcessingFrameNumber(processingFrame); + } + if (m_dataExporter != nullptr) { m_dataExporter->process(); if (m_dataExporter->isDone()) @@ -134,12 +139,19 @@ void FrontendUI::composeUI() { showCurrentStatsDialog(); showMinimapGenerationSettingsDialog(); showBlpViewer(); + showM2Viewer(); ImGui::RenderNotifications(); if (m_debugRenderWindow) m_debugRenderWindow->draw(); + //Test hack + if (cascOpened && m_m2Window == nullptr) { + m_m2Window = std::make_shared(m_api, m_uiRenderer); + m_m2Window->openWMOSceneByfdid(113992); + }; + // Rendering ImGui::Render(); } @@ -363,6 +375,14 @@ void FrontendUI::showBlpViewer() { } } +void FrontendUI::showM2Viewer() { + if (!m_m2Window) return; + + if (!m_m2Window->draw()) { + m_m2Window = nullptr; + } +} + void FrontendUI::showFileList() { if (m_fileListWindow && !m_fileListWindow->draw()) { m_fileListWindow = nullptr; @@ -1270,7 +1290,7 @@ void FrontendUI::showSettingsDialog() { int cameraNum = getCameraNumCallback(); { - std::string caption = "First person"; + const std::string caption = "First person"; if (ImGui::Selectable(caption.c_str(), currentCameraNum == -1)) { setNewCameraCallback(-1); currentCameraNum = -1; @@ -1642,7 +1662,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do m_minimapGenerationWindow->process(); } auto l_device = m_api->hDevice; - auto processingFrame = l_device->getFrameNumber(); + auto processingFrame = l_device->getFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; std::function updateFrameNumberLambda = [l_device, frame = processingFrame]() -> uint32_t { l_device->setCurrentProcessingFrameNumber(frame); return frame; @@ -1669,6 +1689,9 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do debugHeight ); + if (m_m2Window) + m_m2Window->render(deltaTime, scenario, updateFrameNumberLambda); + //---------------------- // Screenshot part //---------------------- diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 70fd797d5..324984d04 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -30,6 +30,7 @@ #include "childWindow/textureRenderer/DebugRendererWindow.h" #include "childWindow/fileListWindow/FileListWindow.h" #include "childWindow/sceneWindow/SceneWindow.h" +#include "childWindow/m2Window/M2Window.h" class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_from_this { @@ -193,6 +194,7 @@ class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_ std::shared_ptr m_minimapGenerationWindow = nullptr; std::shared_ptr m_blpViewerWindow = nullptr; std::shared_ptr m_blpFileViewerWindow = nullptr; + std::shared_ptr m_m2Window = nullptr; std::shared_ptr m_fileListWindow = nullptr; std::shared_ptr m_debugRenderWindow; @@ -239,6 +241,7 @@ class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_ void showCurrentStatsDialog(); void showBlpViewer(); + void showM2Viewer(); void showFileList(); void restartMinimapGenPreview(); diff --git a/src/ui/childWindow/m2Window/M2Window.cpp b/src/ui/childWindow/m2Window/M2Window.cpp index 8e78f8483..ad7deaa40 100644 --- a/src/ui/childWindow/m2Window/M2Window.cpp +++ b/src/ui/childWindow/m2Window/M2Window.cpp @@ -3,3 +3,73 @@ // #include "M2Window.h" +#include "imgui.h" + +M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer) : SceneWindow(api, false), m_uiRenderer(renderer) { + + openWMOSceneByfdid(113992); +} + +M2Window::~M2Window() { + if (m_renderView) { + m_renderView->eraseOnUpdate(iteratorUnique); + } +} + +bool M2Window::draw() { + if (iteratorUnique == nullptr && m_renderView ) { + auto l_weak = this->weak_from_this(); + iteratorUnique = m_renderView->addOnUpdate([l_weak] { + auto shared = l_weak.lock(); + if (shared) { + shared->createMaterials(); + } + }); + } + + if (ImGui::Begin("M2Window", &m_showWindow)) + { + auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + + float sizeX = 0, sizeY = 0; + auto windowSize = ImGui::GetContentRegionAvail(); + sizeX = windowSize.x; + sizeY = windowSize.y; + + if (m_width != sizeX || m_height != sizeY) { + m_width = sizeX > 0 ? sizeX : 1; + m_height = sizeY > 0 ? sizeY : 1; + } + + auto const ¤tMaterial = materials[currentFrame]; + if (currentMaterial) { + ImGui::Image(currentMaterial->uniqueId, {sizeX, sizeY}); + } + + ImGui::End(); + } + + return m_showWindow; +} + +void M2Window::createMaterials() { + m_renderView->iterateOverOutputTextures([&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, + const std::string &name, ITextureFormat textureFormat) { + if (textureFormat == ITextureFormat::itRGBA) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + materials[i] = m_uiRenderer->createUIMaterial(textures[i]); + } + } + }); +} + +void M2Window::render(double deltaTime, const HFrameScenario &scenario, + const std::function &updateFrameNumberLambda) { + + ViewPortDimensions dimensions = { + {0,0}, + {m_width, m_height} + }; + + SceneWindow::render(deltaTime, 60, scenario, dimensions, updateFrameNumberLambda, nullptr, 0,0); +} diff --git a/src/ui/childWindow/m2Window/M2Window.h b/src/ui/childWindow/m2Window/M2Window.h index 37695302a..19076617e 100644 --- a/src/ui/childWindow/m2Window/M2Window.h +++ b/src/ui/childWindow/m2Window/M2Window.h @@ -7,13 +7,32 @@ #include "../sceneWindow/SceneWindow.h" +#include "../../renderer/uiScene/materials/UIMaterial.h" +#include "../../renderer/uiScene/FrontendUIRenderer.h" -class M2Window : public SceneWindow { +class M2Window : public SceneWindow, public std::enable_shared_from_this { public: + M2Window(HApiContainer api, const std::shared_ptr &renderer); + ~M2Window(); bool draw(); + void render(double deltaTime, + const HFrameScenario &scenario, + const std::function &updateFrameNumberLambda); private: - bool m_showWindow; + void createMaterials(); +private: + bool m_showWindow = true; + + uint16_t m_width = 640; + uint16_t m_height = 480; + + std::shared_ptr m_uiRenderer; + + typedef std::list>::const_iterator OnUpdateIter; + std::unique_ptr iteratorUnique = nullptr; + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> materials = {nullptr}; }; diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index b1d52a765..e9ae54c38 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -64,13 +64,9 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, return result; } -SceneWindow::SceneWindow(HApiContainer api) : m_api(api) { +SceneWindow::SceneWindow(HApiContainer api, bool renderToSwapChain) : m_api(api), m_renderToSwapChain(renderToSwapChain){ } -bool SceneWindow::draw() { - return false; -}; - std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneType, const std::string& name, int cameraNum) { apiContainer->camera = std::make_shared(); if (sceneType == -1) { @@ -199,12 +195,17 @@ SceneWindow::render(double deltaTime, uint32_t debugViewWidth, uint32_t debugViewHeight) { - if (!hasRenderer()) return; + if (!hasRenderer()) return; + if (!m_renderToSwapChain && !m_renderView) { + m_renderView = m_sceneRenderer->createRenderView( + dimension.maxs[0] - dimension.mins[0], + dimension.maxs[1] - dimension.mins[1], true); + } auto wowSceneFrameInput = std::make_shared>(); wowSceneFrameInput->delta = deltaTime * (1000.0f); - std::shared_ptr target = nullptr; + std::shared_ptr target = m_renderView; std::shared_ptr debugTarget = nullptr; ViewPortDimensions l_dimension = dimension; diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index e39984671..25e578bd7 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -21,8 +21,7 @@ struct RenderTargetParameters { class SceneWindow { public: - SceneWindow(HApiContainer api); - bool draw(); + SceneWindow(HApiContainer api, bool renderToSwapChain); void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); @@ -54,10 +53,12 @@ class SceneWindow { private: std::shared_ptr m_sceneRenderer = nullptr; std::shared_ptr m_currentScene = nullptr; - HApiContainer m_api; + bool m_renderToSwapChain = true; + protected: float movementSpeed = 1; - + HApiContainer m_api; + std::shared_ptr m_renderView = nullptr; }; diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp index 142bfd327..fd6bc0b9e 100644 --- a/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.cpp @@ -32,6 +32,8 @@ void DebugRendererWindow::draw() { ImGui::Begin("Debug Render Window"); { +// drawSelection(); + float sizeX = 0, sizeY = 0; auto windowSize = ImGui::GetContentRegionAvail(); sizeX = windowSize.x; @@ -64,7 +66,37 @@ void DebugRendererWindow::createMaterials() { record.materials[i] = this->m_renderer->createUIMaterial(textures[i]); } } +// else if (textureFormat == ITextureFormat::itDepth32) { +// for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { +// if (textures[i]->getTexture()->getIsSamplable()) { +// record.materials[i] = this->m_renderer->createUIMaterial(textures[i], true); +// } +// } +// } }); if (currentSelectionIndex > m_selections.size()) currentSelectionIndex = 0; } + +void DebugRendererWindow::drawSelection() { + std::string comboName = + (currentSelectionIndex < m_selections.size()) ? + m_selections[currentSelectionIndex].name : + ""; + + if (ImGui::BeginCombo("##combo", comboName.c_str())) // The second parameter is the label previewed before opening the combo. + { + for (int n = 0; n < m_selections.size(); n++) + { + bool is_selected = (currentSelectionIndex == n); // You can store your selection however you want, outside or inside your objects + std::string selectionName = m_selections[n].name; + if (ImGui::Selectable(selectionName.c_str(), is_selected)) { + currentSelectionIndex = n; + } + + if (is_selected) + ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support) + } + ImGui::EndCombo(); + } +} diff --git a/src/ui/childWindow/textureRenderer/DebugRendererWindow.h b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h index ba9b2a799..cfea39318 100644 --- a/src/ui/childWindow/textureRenderer/DebugRendererWindow.h +++ b/src/ui/childWindow/textureRenderer/DebugRendererWindow.h @@ -38,6 +38,8 @@ class DebugRendererWindow : public std::enable_shared_from_this> m_imguiUbo = nullptr; diff --git a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h index 463fb895f..ad5128f99 100644 --- a/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h +++ b/src/ui/renderer/uiScene/IFrontendUIBufferCreate.h @@ -19,6 +19,7 @@ class IFrontendUIBufferCreate { virtual HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) = 0; virtual std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture, bool opaque = false) = 0; + virtual std::shared_ptr createUIMaterialDepth(const HGSamplableTexture &hgtexture) = 0; }; typedef std::shared_ptr HFrontendUIBufferCreate; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 3c13d8aef..c7e336cad 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -80,6 +80,40 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const return material; } +std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterialDepth(const HGSamplableTexture &hgtexture) { + auto weakTexture = std::weak_ptr(hgtexture); + auto &materialCache = m_materialDepthCache ; + auto i = materialCache.find(weakTexture); + if (i != materialCache.end()) { + if (!i->second.expired()) { + return i->second.lock(); + } else { + materialCache.erase(i); + } + } + + auto &l_imguiUbo = m_imguiUbo; + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering"}) + .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) + .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, *l_imguiUbo); + }) + .createDescriptorSet(1, [&hgtexture](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(0, hgtexture); + }) + .toMaterial([&] (IUIMaterial *uiMat){ + uiMat->uniqueId = this->generateUniqueMatId(); + }); + + auto weakPtr = material; + materialCache[weakTexture] = weakPtr; + m_materialCacheIdMap[material->uniqueId] = std::dynamic_pointer_cast(material); + + return material; +} + HGMesh FrontendUIRenderForwardVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 0696a13db..0172a7e83 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -29,6 +29,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { HGVertexBufferBindings createVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) override;; HGMesh createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) override; std::shared_ptr createUIMaterial(const HGSamplableTexture &hgtexture, bool opaque = false) override; + std::shared_ptr createUIMaterialDepth(const HGSamplableTexture &hgtexture) override; uint32_t generateUniqueMatId(); private: diff --git a/wowViewerLib/shaders/glsl/forwardRendering/imguiShaderDepth.frag b/wowViewerLib/shaders/glsl/forwardRendering/imguiShaderDepth.frag new file mode 100644 index 000000000..1a4d7c960 --- /dev/null +++ b/wowViewerLib/shaders/glsl/forwardRendering/imguiShaderDepth.frag @@ -0,0 +1,16 @@ +#version 450 + +precision highp float; +precision highp int; + +layout(location=0) in vec2 Frag_UV; +layout(location=1) in vec4 Frag_Color; + +layout(set=1,binding=0) uniform sampler2D Texture; + +layout (location = 0) out vec4 Out_Color; + +void main() +{ + Out_Color = Frag_Color * vec4(texture(Texture, Frag_UV.st).rgb, 1.0); +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 0a59d9f87..f3daaa1a5 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,6 +396,11 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -502,6 +507,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { @@ -668,6 +676,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -853,6 +866,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -891,6 +906,7 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, @@ -931,10 +947,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -952,11 +969,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -991,10 +1014,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,6 +1140,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1138,10 +1171,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1309,10 +1343,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1530,6 +1566,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -1588,6 +1625,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1627,14 +1666,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1671,6 +1712,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1819,6 +1861,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -2064,12 +2107,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2175,8 +2223,11 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { } }, { @@ -2188,6 +2239,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2628,10 +2728,6 @@ const std::unordered_map blpTexturesVulkanLoaded; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 7a8022394..ecc3f920e 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index c53565587..1493f0f3e 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -169,7 +169,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, fbDepthFormat, sampleCountToVkSampleCountFlagBits(multiSampleCnt), 1, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT )); m_depthTexture = h_depthTexture; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index 87b756b5e..c80500c64 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -22,6 +22,8 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, m_width = width; m_height = height; + m_samplable = (imageUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) > 0; + createVulkanImageObject( isDepthTexture, textureFormatGPU, @@ -45,6 +47,7 @@ GTextureVLK::GTextureVLK(IDeviceVulkan &device, //This image is used as holder for framebuffer data (swapchain framebuffer one) texture.image = image; texture.view = imageView; + m_samplable = false; //this is texture for use in framebuffer, that's why it is set as initialized m_loaded = true; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h index e23236874..95f8667d8 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.h @@ -35,6 +35,7 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this&)> &onUpdateCallback); @@ -107,6 +108,8 @@ class GTextureVLK : public ITexture, public std::enable_shared_from_this Date: Sat, 10 Feb 2024 15:26:25 +0200 Subject: [PATCH 168/212] - rendering in windows first tests --- src/main.cpp | 41 +-- src/minimapGenerator/minimapGenerator.cpp | 13 +- src/ui/FrontendUI.cpp | 293 ++++++++++-------- src/ui/FrontendUI.h | 18 +- src/ui/childWindow/m2Window/M2Window.cpp | 43 ++- src/ui/childWindow/m2Window/M2Window.h | 8 +- .../childWindow/sceneWindow/SceneWindow.cpp | 169 +++++++--- src/ui/childWindow/sceneWindow/SceneWindow.h | 19 +- wowViewerLib/src/engine/ApiContainer.h | 2 - .../src/engine/camera/CameraInterface.h | 1 + .../src/engine/camera/firstPersonCamera.cpp | 4 +- .../src/engine/camera/firstPersonCamera.h | 2 +- .../camera/firstPersonOrthoStaticCamera.h | 1 + .../firstPersonOrthoStaticTopDownCamera.h | 1 + wowViewerLib/src/engine/camera/m2TiedCamera.h | 1 + .../src/engine/camera/planarCamera.cpp | 3 + wowViewerLib/src/engine/camera/planarCamera.h | 2 +- .../src/engine/objects/scenes/m2Scene.cpp | 72 +---- .../src/engine/objects/scenes/m2Scene.h | 10 +- .../src/gapi/interface/meshes/IMesh.h | 8 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../CommandBufferRecorder.cpp | 11 +- .../src/renderer/mapScene/MapSceneRenderer.h | 2 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 6 +- .../vulkan/MapSceneRenderVisBufferVLK.h | 2 +- .../vulkan/view/RenderViewForwardVLK.cpp | 7 +- 28 files changed, 422 insertions(+), 323 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c5e0f4ba6..866dedd6b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,12 +61,10 @@ std::shared_ptr frontendUI = nullptr; static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos){ if (stopMouse) return; HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); - auto controllable = apiContainer->camera; - if (apiContainer->getConfig()->doubleCameraDebug && - apiContainer->getConfig()->controlSecondCamera && - apiContainer->debugCamera != nullptr) { - controllable = apiContainer->debugCamera; - } + auto currentActiveScene = frontendUI->getCurrentActiveScene(); + auto controllable = currentActiveScene ? currentActiveScene->getCamera() : nullptr; + + if (!controllable) return; // if (!pointerIsLocked) { if (mleft_pressed == 1) { @@ -114,12 +112,10 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) static void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) { HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); - auto controllable = apiContainer->camera; - if (apiContainer->getConfig()->doubleCameraDebug && - apiContainer->getConfig()->controlSecondCamera && - apiContainer->debugCamera != nullptr) { - controllable = apiContainer->debugCamera; - } + auto currentActiveScene = frontendUI->getCurrentActiveScene(); + auto controllable = currentActiveScene ? currentActiveScene->getCamera() : nullptr; + + if (!controllable) return; if ( action == GLFW_PRESS) { if (stopKeyboard) return; @@ -174,15 +170,12 @@ static void onKey(GLFWwindow* window, int key, int scancode, int action, int mod void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - if (stopMouse) return; + auto currentActiveScene = frontendUI->getCurrentActiveScene(); + auto controllable = currentActiveScene ? currentActiveScene->getCamera() : nullptr; + + if (!controllable) return; HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); - auto controllable = apiContainer->camera; - if (apiContainer->getConfig()->doubleCameraDebug && - apiContainer->getConfig()->controlSecondCamera && - apiContainer->debugCamera != nullptr) { - controllable = apiContainer->debugCamera; - } controllable->zoomInFromMouseScroll(-yoffset/2.0f); } @@ -414,7 +407,6 @@ int main(){ auto hdevice = IDeviceFactory::createDevice(rendererName, &callback); apiContainer->databaseHandler = std::make_shared() ; apiContainer->hDevice = hdevice; - apiContainer->camera = std::make_shared(); SceneComposer sceneComposer = SceneComposer(apiContainer); @@ -488,15 +480,6 @@ int main(){ currentFrame = glfwGetTime(); // seconds double deltaTime = currentFrame - lastFrame; - apiContainer->camera->tick(deltaTime*(1000.0f)); - if (apiContainer->debugCamera != nullptr) { - apiContainer->debugCamera->tick(deltaTime * (1000.0f)); - } - - if (apiContainer->getConfig()->pauseAnimation) { - deltaTime = 0.0; - } - frontendUI->composeUI(); auto sceneScenario = frontendUI->createFrameScenario(canvWidth, canvHeight, deltaTime); diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index 6085025eb..b8c45ddb6 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -19,7 +19,8 @@ MinimapGenerator::MinimapGenerator(HWoWFilesCacheStorage cacheStorage, const HGD m_apiContainer->hDevice = hDevice; m_apiContainer->cacheStorage = cacheStorage; - m_apiContainer->camera = std::make_shared(); + //TODO: +// m_apiContainer->camera = std::make_shared(); m_apiContainer->databaseHandler = dbhandler; m_processor = processor; @@ -256,10 +257,11 @@ void MinimapGenerator::setupScenarioData() { m_height = currentScenario.imageHeight; + //TODO: if (currentScenario.orientation == ScenarioOrientation::soTopDownOrtho) { - m_apiContainer->camera = std::make_shared(); +// m_apiContainer->camera = std::make_shared(); } else { - m_apiContainer->camera = std::make_shared(); +// m_apiContainer->camera = std::make_shared(); } if (!loadMaps()) @@ -534,9 +536,10 @@ void MinimapGenerator::setZoom(float zoom) { void MinimapGenerator::setLookAtPoint(float x, float y) { mathfu::vec3 lookAtPoint2D = mathfu::vec3(x, y, 0); - setupCamera(lookAtPoint2D, m_apiContainer->camera); + //TODO: +// setupCamera(lookAtPoint2D, m_apiContainer->camera); - m_apiContainer->camera->tick(0); +// m_apiContainer->camera->tick(0); } void diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index e3c9627ba..ce22bdf72 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -38,13 +38,14 @@ #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "imgui_notify.h" -FrontendUI::FrontendUI(HApiContainer api) : SceneWindow(api, true) { +FrontendUI::FrontendUI(HApiContainer api) { m_api = api; this->createDatabaseHandler(); m_uiRenderer = FrontendUIRendererFactory::createForwardRenderer(m_api->hDevice); //this->createDefaultprocessor(); + m_backgroundScene = std::make_shared(api, true); } void FrontendUI::composeUI() { @@ -150,6 +151,9 @@ void FrontendUI::composeUI() { if (cascOpened && m_m2Window == nullptr) { m_m2Window = std::make_shared(m_api, m_uiRenderer); m_m2Window->openWMOSceneByfdid(113992); + + m_m2Window2 = std::make_shared(m_api, m_uiRenderer, "test"); + m_m2Window2->openWMOSceneByfdid(1120838); }; // Rendering @@ -235,8 +239,8 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); } - if (SceneWindow::hasRenderer()) { - auto mapPlan = SceneWindow::getLastPlan(); + if (m_currentActiveScene && m_currentActiveScene->hasRenderer()) { + auto mapPlan = m_currentActiveScene->getLastPlan(); if (mapPlan) { auto &cullStageData = mapPlan; @@ -376,11 +380,13 @@ void FrontendUI::showBlpViewer() { } void FrontendUI::showM2Viewer() { - if (!m_m2Window) return; - - if (!m_m2Window->draw()) { + if (m_m2Window && !m_m2Window->draw()) { m_m2Window = nullptr; } + + if (m_m2Window2 && !m_m2Window2->draw()) { + m_m2Window2 = nullptr; + } } void FrontendUI::showFileList() { @@ -535,9 +541,9 @@ void FrontendUI::showAdtSelectionMinimap() { if (ImGui::Button("Go")) { if (prevMapRec.WdtFileID > 0) { - openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, worldPosX, worldPosY, 200); + m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, worldPosX, worldPosY, 200); } else { - openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, worldPosX, worldPosY, 200); + m_backgroundScene->openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, worldPosX, worldPosY, 200); } showSelectMap = false; @@ -738,10 +744,10 @@ void FrontendUI::showMapSelectionDialog() { worldPosY = 0; if (ImGui::Button("Open WMO Map", ImVec2(-1, 0))) { if (prevMapRec.WdtFileID > 0) { - openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0); + m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0); } else { //Try to open map by fileName - openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, 17066.6641f, 17066.67380f, + m_backgroundScene->openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, 17066.6641f, 17066.67380f, 0); } showSelectMap = false; @@ -797,11 +803,11 @@ void FrontendUI::showMainMenu() { m_blpFileViewerWindow->loadBlp(std::to_string(fileId)); } else if (fileType == "m2") { - openM2SceneByfdid(fileId, {}); + m_backgroundScene->openM2SceneByfdid(fileId, {}); } else if (fileType == "wmo") { - openWMOSceneByfdid(fileId); + m_backgroundScene->openWMOSceneByfdid(fileId); } else if (fileType == "wdt") { - openMapByIdAndWDTId(0, fileId, 0,0,0); + m_backgroundScene->openMapByIdAndWDTId(0, fileId, 0,0,0); } }); } @@ -897,7 +903,7 @@ void FrontendUI::initImgui( ImGuiIO &io = ImGui::GetIO(); (void) io; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls +// io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style @@ -947,82 +953,82 @@ void FrontendUI::showQuickLinksDialog() { ImGui::Begin("Quick Links", &showQuickLinks); if (ImGui::Button("model without skin", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - openM2SceneByfdid(5099010, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(5099010, replacementTextureFDids); } if (ImGui::Button("crystal song bush", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - openM2SceneByfdid(194418, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(194418, replacementTextureFDids); } if (ImGui::Button("bugged decal", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - openM2SceneByfdid(946969, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(946969, replacementTextureFDids); } if (ImGui::Button("Some model", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 4952373; replacementTextureFDids[12] = 4952379; - openM2SceneByfdid(4870631, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4870631, replacementTextureFDids); } if (ImGui::Button("nightborne model", ImVec2(-1, 0))) { - openM2SceneByfdid(1810676, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1810676, replacementTextureFDids); } if (ImGui::Button("Tomb of sargares hall", ImVec2(-1, 0))) { - openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); + m_backgroundScene->openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); } if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { - openWMOSceneByfdid(1120838); + m_backgroundScene->openWMOSceneByfdid(1120838); } if (ImGui::Button("8du_zuldazarraid_antiportal01.wmo", ImVec2(-1, 0))) { - openWMOSceneByfdid(2574165); + m_backgroundScene->openWMOSceneByfdid(2574165); } if (ImGui::Button("someShip.wmo", ImVec2(-1, 0))) { - openWMOSceneByfdid(4638404); + m_backgroundScene->openWMOSceneByfdid(4638404); } if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { - openWMOSceneByFilename("world/wmo/dungeon/az_karazahn/karazhan.wmo"); + m_backgroundScene->openWMOSceneByFilename("world/wmo/dungeon/az_karazahn/karazhan.wmo"); } if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { - openWMOSceneByfdid(4419436); + m_backgroundScene->openWMOSceneByfdid(4419436); } if (ImGui::Button("14654.wmo (parallax)", ImVec2(-1, 0))) { - openWMOSceneByfdid(4222547); + m_backgroundScene->openWMOSceneByfdid(4222547); } if (ImGui::Button("10.0 Raid WMO", ImVec2(-1, 0))) { - openWMOSceneByfdid(4282557); + m_backgroundScene->openWMOSceneByfdid(4282557); } if (ImGui::Button("(WMO) Model with broken portal culling", ImVec2(-1, 0))) { - openWMOSceneByfdid(4217818); + m_backgroundScene->openWMOSceneByfdid(4217818); } if (ImGui::Button("(WMO) NPE Ship with waterfall model", ImVec2(-1, 0))) { - openWMOSceneByfdid(3314067); + m_backgroundScene->openWMOSceneByfdid(3314067); } if (ImGui::Button("(WMO) Gazebo 590182", ImVec2(-1, 0))) { - openWMOSceneByfdid(590182); + m_backgroundScene->openWMOSceneByfdid(590182); } if (ImGui::Button("Hearthstone Tavern", ImVec2(-1, 0))) { - openWMOSceneByfdid(2756726); + m_backgroundScene->openWMOSceneByfdid(2756726); } if (ImGui::Button("Original WVF1 model", ImVec2(-1, 0))) { - openM2SceneByfdid(2445860, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(2445860, replacementTextureFDids); } if (ImGui::Button("Stormwind mage portal", ImVec2(-1, 0))) { - openM2SceneByfdid(2394711, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(2394711, replacementTextureFDids); } if (ImGui::Button("kodobeasttame", ImVec2(-1, 0))) { - openM2SceneByfdid(124697, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(124697, replacementTextureFDids); } // if (ImGui::Button("Azeroth map: Lion's Rest (Legion)", ImVec2(-1, 0))) { // openMapByIdAndFilename(0, "azeroth", -8739, 944, 200); // } if (ImGui::Button("Nyalotha map", ImVec2(-1, 0))) { - openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260); + m_backgroundScene->openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260); } if (ImGui::Button("WMO 1247268", ImVec2(-1, 0))) { - openWMOSceneByfdid(1247268); + m_backgroundScene->openWMOSceneByfdid(1247268); } if (ImGui::Button("Ironforge.wmo", ImVec2(-1, 0))) { - openWMOSceneByfdid(113992); + m_backgroundScene->openWMOSceneByfdid(113992); } if (ImGui::Button("Some item", ImVec2(-1, 0))) { @@ -1031,27 +1037,27 @@ void FrontendUI::showQuickLinksDialog() { for (auto &fdid: replacementTextureFDids) { fdid = 1029337; } - openM2SceneByfdid(1029334, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1029334, replacementTextureFDids); } if (ImGui::Button("IGC Anduin", ImVec2(-1, 0))) { - openM2SceneByfdid(3849312, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3849312, replacementTextureFDids); } if (ImGui::Button("Steamscale mount", ImVec2(-1, 0))) { - openM2SceneByfdid(2843110, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(2843110, replacementTextureFDids); } if (ImGui::Button("Spline emitter", ImVec2(-1, 0))) { - openM2SceneByfdid(1536145, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1536145, replacementTextureFDids); } if (ImGui::Button("Nether collector top", ImVec2(-1, 0))) { - openM2SceneByfdid(193157, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(193157, replacementTextureFDids); } if (ImGui::Button("Сollector top", ImVec2(-1, 0))) { - openWMOSceneByfdid(113540); + m_backgroundScene->openWMOSceneByfdid(113540); } if (ImGui::Button("10.0 unk model", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - openM2SceneByfdid(4519090, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4519090, replacementTextureFDids); } if (ImGui::Button("10.0 strange shoulders", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); @@ -1060,176 +1066,176 @@ void FrontendUI::showQuickLinksDialog() { - openM2SceneByfdid(4614814, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4614814, replacementTextureFDids); } if (ImGui::Button("DF chicken", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 4007136; - openM2SceneByfdid(4005446, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4005446, replacementTextureFDids); } if (ImGui::Button("Fox", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 3071379; + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 3071379; - openM2SceneByfdid(3071370, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3071370, replacementTextureFDids); } if (ImGui::Button("COT hourglass", ImVec2(-1, 0))) { - openM2SceneByfdid(190850, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(190850, replacementTextureFDids); } if (ImGui::Button("Gryphon roost", ImVec2(-1, 0))) { - openM2SceneByfdid(198261, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(198261, replacementTextureFDids); } if (ImGui::Button("Northrend Human Inn", ImVec2(-1, 0))) { - openWMOSceneByfdid(114998); + m_backgroundScene->openWMOSceneByfdid(114998); } if (ImGui::Button("Strange WMO", ImVec2(-1, 0))) { - openWMOSceneByfdid(2342637); + m_backgroundScene->openWMOSceneByfdid(2342637); } if (ImGui::Button("Flyingsprite", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); + replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 3059000; - openM2SceneByfdid(3024835, replacementTextureFDids); + replacementTextureFDids[11] = 3059000; + m_backgroundScene->openM2SceneByfdid(3024835, replacementTextureFDids); } if (ImGui::Button("maldraxxusflyer", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 3196375; - openM2SceneByfdid(3196372, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 3196375; + m_backgroundScene->openM2SceneByfdid(3196372, replacementTextureFDids); } if (ImGui::Button("ridingphoenix", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); + replacementTextureFDids = std::vector(17); - openM2SceneByfdid(125644, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(125644, replacementTextureFDids); } if (ImGui::Button("Upright Orc", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[1] = 3844710; - openM2SceneByfdid(1968587, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[1] = 3844710; + m_backgroundScene->openM2SceneByfdid(1968587, replacementTextureFDids); } if (ImGui::Button("quillboarbrute.m2", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 1786107; - openM2SceneByfdid(1784020, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 1786107; + m_backgroundScene->openM2SceneByfdid(1784020, replacementTextureFDids); } if (ImGui::Button("WMO With Horde Symbol", ImVec2(-1, 0))) { - openWMOSceneByfdid(1846142); + m_backgroundScene->openWMOSceneByfdid(1846142); } if (ImGui::Button("WMO 3565693", ImVec2(-1, 0))) { - openWMOSceneByfdid(3565693); + m_backgroundScene->openWMOSceneByfdid(3565693); } if (ImGui::Button("Vanilla login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(131970, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(131970, replacementTextureFDids); } if (ImGui::Button("BC login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(131982, replacementTextureFDids); - // auto ambient = mathfu::vec4(0.3929412066936493f, 0.26823532581329346f, 0.3082353174686432f, 0); - m_api->getConfig()->BCLightHack = true; + m_backgroundScene->openM2SceneByfdid(131982, replacementTextureFDids); + // auto ambient = mathfu::vec4(0.3929412066936493f, 0.26823532581329346f, 0.3082353174686432f, 0); + m_api->getConfig()->BCLightHack = true; } if (ImGui::Button("Wrath login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(236122, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(236122, replacementTextureFDids); } if (ImGui::Button("Cataclysm login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(466614, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(466614, replacementTextureFDids); } if (ImGui::Button("Panda login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(631713, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(631713, replacementTextureFDids); } if (ImGui::Button("Draenor login screen", ImVec2(-1, 0))) { - openM2SceneByName("interface/glues/models/ui_mainmenu_warlords/ui_mainmenu_warlords.m2", replacementTextureFDids); + m_backgroundScene->openM2SceneByName("interface/glues/models/ui_mainmenu_warlords/ui_mainmenu_warlords.m2", replacementTextureFDids); } if (ImGui::Button("Legion Login Screen", ImVec2(-1, 0))) { - openM2SceneByfdid(1396280, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1396280, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("BfA login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(2021650, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(2021650, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("Shadowlands login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(3846560, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3846560, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("DragonLands login screen", ImVec2(-1, 0))) { - openM2SceneByfdid(4684877, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4684877, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("Shadowlands clouds", ImVec2(-1, 0))) { - openM2SceneByfdid(3445776, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3445776, replacementTextureFDids); } if (ImGui::Button("Pink serpent", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); + replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 2905480; - replacementTextureFDids[12] = 2905481; - replacementTextureFDids[13] = 577442; - openM2SceneByfdid(577443, replacementTextureFDids); + replacementTextureFDids[11] = 2905480; + replacementTextureFDids[12] = 2905481; + replacementTextureFDids[13] = 577442; + m_backgroundScene->openM2SceneByfdid(577443, replacementTextureFDids); } if (ImGui::Button("Wolf", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); + replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 126494; - replacementTextureFDids[12] = 126495; - replacementTextureFDids[13] = 0; - openM2SceneByfdid(126487, replacementTextureFDids); + replacementTextureFDids[11] = 126494; + replacementTextureFDids[12] = 126495; + replacementTextureFDids[13] = 0; + m_backgroundScene->openM2SceneByfdid(126487, replacementTextureFDids); } if (ImGui::Button("Aggramar", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 1599776; - openM2SceneByfdid(1599045, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 1599776; + m_backgroundScene->openM2SceneByfdid(1599045, replacementTextureFDids); } if (ImGui::Button("M2 3087468", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 3087540; - openM2SceneByfdid(3087468, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 3087540; + m_backgroundScene->openM2SceneByfdid(3087468, replacementTextureFDids); } if (ImGui::Button("Nagrand skybox", ImVec2(-1, 0))) { - openM2SceneByfdid(130575, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(130575, replacementTextureFDids); } if (ImGui::Button("Torghast raid skybox", ImVec2(-1, 0))) { - openM2SceneByfdid(4001212, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(4001212, replacementTextureFDids); } if (ImGui::Button("3445776 PBR cloud sky in Maw", ImVec2(-1, 0))) { - openM2SceneByfdid(3445776, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3445776, replacementTextureFDids); } if (ImGui::Button("M2 3572296", ImVec2(-1, 0))) { - openM2SceneByfdid(3572296, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3572296, replacementTextureFDids); } if (ImGui::Button("M2 3487959", ImVec2(-1, 0))) { - openM2SceneByfdid(3487959, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3487959, replacementTextureFDids); } if (ImGui::Button("M2 1729717 waterfall", ImVec2(-1, 0))) { - openM2SceneByfdid(1729717, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1729717, replacementTextureFDids); } if (ImGui::Button("Maw jailer", ImVec2(-1, 0))) { // 3096499,3096495 replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3096499; replacementTextureFDids[12] = 3096495; - openM2SceneByfdid(3095966, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3095966, replacementTextureFDids); } if (ImGui::Button("Creature with colors", ImVec2(-1, 0))) { // 3096499,3096495 - openM2SceneByfdid(1612576, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(1612576, replacementTextureFDids); } if (ImGui::Button("IC new sky", ImVec2(-1, 0))) { - openM2SceneByfdid(3159936, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3159936, replacementTextureFDids); } if (ImGui::Button("vampire candle", ImVec2(-1, 0))) { - openM2SceneByfdid(3184581, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3184581, replacementTextureFDids); } if (ImGui::Button("Bog Creature", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); @@ -1237,7 +1243,7 @@ void FrontendUI::showQuickLinksDialog() { replacementTextureFDids[12] = 3732360; replacementTextureFDids[13] = 3732368; - openM2SceneByfdid(3732303, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(3732303, replacementTextureFDids); } if (ImGui::Button("Bugged ADT (SL)", ImVec2(-1, 0))) { // m_currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); @@ -1246,16 +1252,16 @@ void FrontendUI::showQuickLinksDialog() { ImGui::Text("Models for billboard checking"); ImGui::NewLine(); if (ImGui::Button("Dalaran dome", ImVec2(-1, 0))) { - openM2SceneByfdid(203598, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(203598, replacementTextureFDids); } if (ImGui::Button("Gift of Nzoth", ImVec2(-1, 0))) { - openM2SceneByfdid(2432705, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(2432705, replacementTextureFDids); } if (ImGui::Button("Plagueheart Shoulderpad", ImVec2(-1, 0))) { - openM2SceneByfdid(143343, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(143343, replacementTextureFDids); } if (ImGui::Button("Dalaran eye", ImVec2(-1, 0))) { - openM2SceneByfdid(243044, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(243044, replacementTextureFDids); } if (ImGui::Button("Hand weapon", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); @@ -1263,7 +1269,7 @@ void FrontendUI::showQuickLinksDialog() { for (auto &fdid: replacementTextureFDids) { fdid = 528801; } - openM2SceneByfdid(528797, replacementTextureFDids); + m_backgroundScene->openM2SceneByfdid(528797, replacementTextureFDids); } ImGui::End(); @@ -1350,8 +1356,14 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->currentTime = currentTime; } - if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { - m_api->camera->setMovementSpeed(movementSpeed); + { + auto camera = (m_currentActiveScene) ? m_currentActiveScene->getCamera() : nullptr; + float movementSpeed = (camera) ? camera->getMovementSpeed() : 1.0; + if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { + if (camera) { + camera->setMovementSpeed(movementSpeed); + } + } } auto fogDensityIncreaser = m_api->getConfig()->fogDensityIncreaser; if (ImGui::SliderFloat("Fog Density", &fogDensityIncreaser, -4, 4)) { @@ -1435,12 +1447,12 @@ void FrontendUI::showSettingsDialog() { m_debugRenderView = nullptr; } } - if (useDoubleCameraDebug && (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) && SceneWindow::hasRenderer()) { - m_debugRenderView = SceneWindow::createRenderView(); + if (useDoubleCameraDebug && (m_debugRenderWindow == nullptr || m_debugRenderView == nullptr) && m_backgroundScene->hasRenderer()) { + m_debugRenderView = m_backgroundScene->createRenderView(); m_debugRenderWindow = std::make_shared(m_api, m_uiRenderer, m_debugRenderView); } - + /* if (useDoubleCameraDebug) { if (m_api->debugCamera == nullptr) { m_api->debugCamera = std::make_shared(); @@ -1466,6 +1478,7 @@ void FrontendUI::showSettingsDialog() { } else { m_api->debugCamera = nullptr; } + */ pauseAnimation = m_api->getConfig()->pauseAnimation; if (ImGui::Checkbox("Pause animation", &pauseAnimation)) { @@ -1478,7 +1491,7 @@ void FrontendUI::showSettingsDialog() { } if (ImGui::CollapsingHeader("Light options")) { - auto mapPlan = SceneWindow::getLastPlan(); + auto mapPlan = m_currentActiveScene ? m_currentActiveScene->getLastPlan() : nullptr; switch(m_api->getConfig()->globalLighting) { case EParameterSource::eDatabase: { @@ -1675,6 +1688,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do {0, 0}, {static_cast(canvWidth), static_cast(canvHeight)} }; + m_backgroundScene->setViewPortDimensions(dimension); uint32_t debugWidth = 0; uint32_t debugHeight = 0; if (m_debugRenderWindow) { @@ -1682,22 +1696,35 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do debugHeight = m_debugRenderWindow->getHeight(); } - SceneWindow::render(deltaTime, fov, scenario, dimension, - updateFrameNumberLambda, - m_debugRenderView, - debugWidth, - debugHeight + m_backgroundScene->render( + deltaTime, fov, scenario, + /* + m_debugRenderView, + debugWidth, + debugHeight + */ nullptr, + updateFrameNumberLambda ); + m_currentActiveScene = m_backgroundScene; - if (m_m2Window) + if (m_m2Window) { m_m2Window->render(deltaTime, scenario, updateFrameNumberLambda); + m_currentActiveScene = m_m2Window->isActive() ? m_m2Window : m_currentActiveScene; + } + + if (m_m2Window2) { + m_m2Window2->render(deltaTime, scenario, updateFrameNumberLambda); + m_currentActiveScene = m_m2Window2->isActive() ? m_m2Window2 : m_currentActiveScene; + } + + //---------------------- // Screenshot part //---------------------- if (needToMakeScreenshot) { - SceneWindow::makeScreenshot(fov, + m_backgroundScene->makeScreenshot(fov, screenShotWidth, screenShotHeight, screenshotFilename, scenario, @@ -1743,7 +1770,7 @@ void FrontendUI::unloadScene() { m_api->cacheStorage->actuallDropCache(); } - SceneWindow::unload(); + m_backgroundScene->unload(); } @@ -1776,12 +1803,14 @@ void FrontendUI::resetAnimationCallback() { } void FrontendUI::getCameraPos(float &cameraX, float &cameraY, float &cameraZ) { - if (m_api->camera == nullptr) { + auto camera = m_currentActiveScene ? m_currentActiveScene->getCamera() : nullptr; + + if (camera == nullptr) { cameraX = 0; cameraY = 0; cameraZ = 0; return; } float currentCameraPos[4] = {0,0,0,0}; - m_api->camera->getCameraPosition(¤tCameraPos[0]); + camera->getCameraPosition(¤tCameraPos[0]); cameraX = currentCameraPos[0]; cameraY = currentCameraPos[1]; cameraZ = currentCameraPos[2]; @@ -1789,6 +1818,9 @@ void FrontendUI::getCameraPos(float &cameraX, float &cameraY, float &cameraZ) { void FrontendUI::getDebugCameraPos(float &cameraX, float &cameraY, float &cameraZ) { + //TODO: + /* + auto camera = m_currentActiveScene ? m_currentActiveScene->getCamera() : nullptr; if (m_api->debugCamera == nullptr) { cameraX = 0; cameraY = 0; cameraZ = 0; return; @@ -1798,6 +1830,7 @@ void FrontendUI::getDebugCameraPos(float &cameraX, float &cameraY, float &camera cameraX = currentCameraPos[0]; cameraY = currentCameraPos[1]; cameraZ = currentCameraPos[2]; + */ } inline bool fileExistsNotNull (const std::string& name) { diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index 324984d04..f5066f216 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -33,7 +33,7 @@ #include "childWindow/m2Window/M2Window.h" -class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_from_this { +class FrontendUI : public IScene, public std::enable_shared_from_this { public: void createDefaultprocessor(); void createDatabaseHandler(); @@ -44,12 +44,7 @@ class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_ createFileDialog.Close(); ImGui::DestroyContext(this->imguiContext); }; - std::shared_ptr getShared() - { - return shared_from_this(); - } -// void produceDrawStage(HDrawStage &resultDrawStage); HFrameScenario createFrameScenario(int canvWidth, int canvHeight, double deltaTime); void setUIScale(float scale) { @@ -65,17 +60,21 @@ class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_ windowWidth = width; windowHeight = height; } + + std::shared_ptr getCurrentActiveScene() { + return m_currentActiveScene; + }; private: ImGuiContext* imguiContext = nullptr; std::shared_ptr m_uiRenderer; std::shared_ptr fontMat; -// HCullStage m_lastCullstage = {}; - - float uiScale = 1; + std::shared_ptr m_backgroundScene = nullptr; + std::shared_ptr m_currentActiveScene = nullptr; + float uiScale = 1; bool tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef); @@ -195,6 +194,7 @@ class FrontendUI : public IScene, public SceneWindow, public std::enable_shared_ std::shared_ptr m_blpViewerWindow = nullptr; std::shared_ptr m_blpFileViewerWindow = nullptr; std::shared_ptr m_m2Window = nullptr; + std::shared_ptr m_m2Window2 = nullptr; std::shared_ptr m_fileListWindow = nullptr; std::shared_ptr m_debugRenderWindow; diff --git a/src/ui/childWindow/m2Window/M2Window.cpp b/src/ui/childWindow/m2Window/M2Window.cpp index ad7deaa40..03d2db8bc 100644 --- a/src/ui/childWindow/m2Window/M2Window.cpp +++ b/src/ui/childWindow/m2Window/M2Window.cpp @@ -4,8 +4,10 @@ #include "M2Window.h" #include "imgui.h" +#include "imgui_internal.h" -M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer) : SceneWindow(api, false), m_uiRenderer(renderer) { +M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix) : SceneWindow(api, false), m_uiRenderer(renderer) { + m_windowName = "M2Window##" + nameSuffix; openWMOSceneByfdid(113992); } @@ -17,18 +19,27 @@ M2Window::~M2Window() { } bool M2Window::draw() { + this->m_isActive = false; + if (iteratorUnique == nullptr && m_renderView ) { auto l_weak = this->weak_from_this(); iteratorUnique = m_renderView->addOnUpdate([l_weak] { auto shared = l_weak.lock(); if (shared) { - shared->createMaterials(); + shared->m_needToUpdateMaterials = true; } }); } - if (ImGui::Begin("M2Window", &m_showWindow)) + if (m_needToUpdateMaterials) { + this->createMaterials(); + m_needToUpdateMaterials = false; + } + + if (ImGui::Begin(m_windowName.c_str(), &m_showWindow)) { + ImGui::Button("Just a test Button"); + auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; float sizeX = 0, sizeY = 0; @@ -41,11 +52,31 @@ bool M2Window::draw() { m_height = sizeY > 0 ? sizeY : 1; } + + auto const ¤tMaterial = materials[currentFrame]; if (currentMaterial) { - ImGui::Image(currentMaterial->uniqueId, {sizeX, sizeY}); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,1.0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0,0,0,1.0)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0,0,0,1.0)); + + ImGui::ImageButton("ModelScene", currentMaterial->uniqueId, {sizeX, sizeY}); + + if (ImGui::GetCurrentWindow()->GetID("ModelScene") == ImGui::GetFocusID()) { + ImGui::SetNextFrameWantCaptureKeyboard(false); + ImGui::SetNextFrameWantCaptureMouse(false); +// static uint32_t itsActive = 0; +// std::cout << "it's active" << itsActive++ << std::endl; + this->m_isActive = true; + } + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(3); } + ImGui::End(); } @@ -66,10 +97,10 @@ void M2Window::createMaterials() { void M2Window::render(double deltaTime, const HFrameScenario &scenario, const std::function &updateFrameNumberLambda) { - ViewPortDimensions dimensions = { + m_dimension = { {0,0}, {m_width, m_height} }; - SceneWindow::render(deltaTime, 60, scenario, dimensions, updateFrameNumberLambda, nullptr, 0,0); + SceneWindow::render(deltaTime, 60, scenario, nullptr, updateFrameNumberLambda); } diff --git a/src/ui/childWindow/m2Window/M2Window.h b/src/ui/childWindow/m2Window/M2Window.h index 19076617e..40d08a49b 100644 --- a/src/ui/childWindow/m2Window/M2Window.h +++ b/src/ui/childWindow/m2Window/M2Window.h @@ -12,17 +12,23 @@ class M2Window : public SceneWindow, public std::enable_shared_from_this { public: - M2Window(HApiContainer api, const std::shared_ptr &renderer); + M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix = ""); ~M2Window(); bool draw(); void render(double deltaTime, const HFrameScenario &scenario, const std::function &updateFrameNumberLambda); + + bool isActive() const {return m_isActive;}; private: void createMaterials(); private: + std::string m_windowName = ""; bool m_showWindow = true; + bool m_isActive = false; + + bool m_needToUpdateMaterials = false; uint16_t m_width = 640; uint16_t m_height = 480; diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index e9ae54c38..c35e92a18 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -10,6 +10,51 @@ #include "../../../../wowViewerLib/src/engine/objects/scenes/NullScene.h" #include "../../../screenshots/screenshotMaker.h" + +void updateCameraPosOnLoad(const std::shared_ptr &m2Object, const std::shared_ptr &camera) { + if (m2Object->isMainDataLoaded()) { + CAaBox aabb = m2Object->getColissionAABB(); + if ((mathfu::vec3(aabb.max) - mathfu::vec3(aabb.min)).LengthSquared() < 0.001 ) { + aabb = m2Object->getAABB(); + } + + auto max = aabb.max; + auto min = aabb.min; + + if ((mathfu::vec3(aabb.max) - mathfu::vec3(aabb.min)).LengthSquared() < 20000) { + + mathfu::vec3 modelCenter = mathfu::vec3( + ((max.x + min.x) / 2.0f), + ((max.y + min.y) / 2.0f), + ((max.z + min.z) / 2.0f) + ); + + if ((max.z - modelCenter.z) > (max.y - modelCenter.y)) { + camera->setCameraPos((max.z - modelCenter.z) / tan(M_PI * 19.0f / 180.0f), 0, 0); + + } else { + camera->setCameraPos((max.y - modelCenter.y) / tan(M_PI * 19.0f / 180.0f), 0, 0); + } + camera->setCameraLookAt(0,0,0); + camera->setCameraOffset(modelCenter.x, modelCenter.y, modelCenter.z); + } else { + camera->setCameraPos(1.0,0,0); + camera->setCameraOffset(0,0,0); + } +#ifdef __EMSCRIPTEN__ + std::vector availableAnimations; + m2Object->getAvailableAnimation(availableAnimations); + + supplyAnimationList(&availableAnimations[0], availableAnimations.size()); + + std::vector meshIds; + m2Object->getMeshIds(meshIds); + + supplyMeshIds(&meshIds[0], meshIds.size()); +#endif + } +} + mathfu::mat4 getInfZMatrix(float f, float aspect) { return mathfu::mat4( f / aspect, 0.0f, 0.0f, 0.0f, @@ -18,7 +63,8 @@ mathfu::mat4 getInfZMatrix(float f, float aspect) { 0.0f, 0.0f, 1, 0.0f); } -HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, +inline HMapSceneParams createMapSceneParams(const HApiContainer &apiContainer, + const std::shared_ptr &camera, float fov, const std::vector &renderTargetParams, const std::shared_ptr ¤tScene) { @@ -26,8 +72,8 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, auto result = std::make_shared(); result->scene = currentScene; - float farPlaneRendering = apiContainer.getConfig()->farPlane; - float farPlaneCulling = apiContainer.getConfig()->farPlaneForCulling; + float farPlaneRendering = apiContainer->getConfig()->farPlane; + float farPlaneCulling = apiContainer->getConfig()->farPlaneForCulling; float nearPlane = 1.0; float fovR = toRadian(fov); @@ -37,11 +83,11 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, auto height = renderTargetParams[0].dimensions.maxs[1]; float canvasAspect = (float) width / (float) height; - result->matricesForCulling = apiContainer.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, + result->matricesForCulling = camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); } - bool isInfZSupported = apiContainer.camera->isCompatibleWithInfiniteZ(); + bool isInfZSupported = camera->isCompatibleWithInfiniteZ(); auto assignInfiniteZ = [&](auto renderTarget, auto canvasAspect) { float f = 1.0f / tan(fovR / 2.0f); renderTarget.cameraMatricesForRendering->perspectiveMat = getInfZMatrix(f, canvasAspect); @@ -53,20 +99,21 @@ HMapSceneParams createMapSceneParams(ApiContainer &apiContainer, float canvasAspect = (float)width / (float)height; auto &renderTarget = result->renderTargets.emplace_back(); - renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling);; + renderTarget.cameraMatricesForRendering = targetParam.camera->getCameraMatrices(fovR, canvasAspect, nearPlane, farPlaneCulling); renderTarget.viewPortDimensions = targetParam.dimensions; renderTarget.target = targetParam.target; if (isInfZSupported) assignInfiniteZ(renderTarget, canvasAspect); } - result->clearColor = apiContainer.getConfig()->clearColor; + result->clearColor = apiContainer->getConfig()->clearColor; return result; } -SceneWindow::SceneWindow(HApiContainer api, bool renderToSwapChain) : m_api(api), m_renderToSwapChain(renderToSwapChain){ +SceneWindow::SceneWindow(const HApiContainer &api, bool renderToSwapChain) : m_api(api), m_renderToSwapChain(renderToSwapChain){ } +/* std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneType, const std::string& name, int cameraNum) { apiContainer->camera = std::make_shared(); if (sceneType == -1) { @@ -107,14 +154,15 @@ std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneTyp return nullptr; } +*/ void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, wdtFileId); - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(x,y,z); - m_api->camera->setMovementSpeed(movementSpeed); + m_camera = std::make_shared(); + m_camera->setCameraPos(x,y,z); + m_camera->setMovementSpeed(movementSpeed); } void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); @@ -122,15 +170,20 @@ void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacem m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); - - m_api->camera = std::make_shared(); - m_api->camera->setMovementSpeed(movementSpeed); + m_camera = std::make_shared(); + m_camera->setMovementSpeed(movementSpeed); m_api->getConfig()->BCLightHack = false; // - m_api->camera->setCameraPos(0, 0, 0); -} - + m_camera->setCameraPos(0, 0, 0); + { + //Post load event for m2 + auto m2Object = m2Scene->getSceneM2(); + m2Object->addPostLoadEvent([m2Object, l_camera = m_camera]() { + updateCameraPosOnLoad(m2Object, l_camera); + }); + } +} void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::vector &replacementTextureIds) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); @@ -139,29 +192,41 @@ void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::ve m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(0, 0, 0); - m_api->camera->setMovementSpeed(movementSpeed); + m_camera = std::make_shared(); + m_camera->setCameraPos(0, 0, 0); + m_camera->setMovementSpeed(movementSpeed); + + { + //Post load event for m2 + auto m2Object = m2Scene->getSceneM2(); + m2Object->addPostLoadEvent([m2Object, l_camera = m_camera]() { + updateCameraPosOnLoad(m2Object, l_camera); + }); + } } void SceneWindow::openWMOSceneByfdid(int WMOFdid) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, WMOFdid); - m_api->camera->setCameraPos(0, 0, 0); + + m_camera = std::make_shared(); + m_camera->setCameraPos(0, 0, 0); } void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, wmoFileName); - m_api->camera->setCameraPos(0, 0, 0); + + m_camera = std::make_shared(); + m_camera->setCameraPos(0, 0, 0); } void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z) { m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, mapName); - m_api->camera = std::make_shared(); - m_api->camera->setCameraPos(x,y,z); - m_api->camera->setMovementSpeed(movementSpeed); + m_camera = std::make_shared(); + m_camera->setCameraPos(x,y,z); + m_camera->setMovementSpeed(movementSpeed); } @@ -174,6 +239,9 @@ void SceneWindow::unload() { std::shared_ptr SceneWindow::getLastPlan() { return (m_sceneRenderer) ? m_sceneRenderer->getLastCreatedPlan() : nullptr; } +const std::shared_ptr SceneWindow::getCamera() { + return m_camera; +} bool SceneWindow::hasRenderer() { return m_sceneRenderer != nullptr; @@ -182,24 +250,27 @@ bool SceneWindow::hasRenderer() { std::shared_ptr SceneWindow::createRenderView() { if (m_sceneRenderer == nullptr) return nullptr; - return m_sceneRenderer->createRenderView(640, 480, true); + return m_sceneRenderer->createRenderView(true); } void SceneWindow::render(double deltaTime, float fov, const HFrameScenario &scenario, - const ViewPortDimensions &dimension, - const std::function &updateFrameNumberLambda, - const std::shared_ptr &debugRenderView, - uint32_t debugViewWidth, - uint32_t debugViewHeight) + const std::shared_ptr &debugWindow, + const std::function &updateFrameNumberLambda + ) { if (!hasRenderer()) return; + if (!m_camera) return; if (!m_renderToSwapChain && !m_renderView) { - m_renderView = m_sceneRenderer->createRenderView( - dimension.maxs[0] - dimension.mins[0], - dimension.maxs[1] - dimension.mins[1], true); + m_renderView = m_sceneRenderer->createRenderView(true); + } + + m_camera->tick(deltaTime * 1000.0f); + + if (m_api->getConfig()->pauseAnimation) { + deltaTime = 0.0; } auto wowSceneFrameInput = std::make_shared>(); @@ -208,16 +279,12 @@ SceneWindow::render(double deltaTime, std::shared_ptr target = m_renderView; std::shared_ptr debugTarget = nullptr; - ViewPortDimensions l_dimension = dimension; - ViewPortDimensions debugViewDimension = dimension; - if (debugRenderView) { - debugTarget = debugRenderView; + ViewPortDimensions l_dimension = m_dimension; + ViewPortDimensions debugViewDimension = m_dimension; + if (debugWindow && debugWindow->m_renderView) { + debugTarget = debugWindow->m_renderView; - ViewPortDimensions debugViewDimension = { - {0, 0}, - {static_cast(debugViewWidth), - static_cast(debugViewHeight)} - }; + debugViewDimension = debugWindow->m_dimension; if (m_api->getConfig()->swapMainAndDebug) { std::swap(target, debugTarget); @@ -227,20 +294,21 @@ SceneWindow::render(double deltaTime, std::vector renderTargetParams = { { - m_api->camera, - dimension, + m_camera, + l_dimension, target } }; if (m_api->getConfig()->doubleCameraDebug) { auto &debugParams = renderTargetParams.emplace_back(); - debugParams.camera = m_api->debugCamera; + debugParams.camera = debugWindow->m_camera; debugParams.dimensions = debugViewDimension; debugParams.target = debugTarget; } - wowSceneFrameInput->frameParameters = createMapSceneParams(*m_api, + wowSceneFrameInput->frameParameters = createMapSceneParams(m_api, + m_camera, fov, renderTargetParams, m_currentScene); @@ -257,15 +325,16 @@ SceneWindow::makeScreenshot(float fov, const HFrameScenario &scenario, const std::function &updateFrameNumberLambda) { - auto screenShotRenderView = m_sceneRenderer->createRenderView(screenShotWidth, screenShotHeight, true); + auto screenShotRenderView = m_sceneRenderer->createRenderView(true); auto wowSceneScreenshotFrameInput = std::make_shared>(); wowSceneScreenshotFrameInput->delta = 0; wowSceneScreenshotFrameInput->frameParameters = createMapSceneParams( - *m_api, + m_api, + m_camera, fov, {{ - m_api->camera, + m_camera, { {0, 0}, {static_cast(screenShotWidth), static_cast(screenShotHeight)} diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 25e578bd7..3e5a41e1f 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -21,7 +21,7 @@ struct RenderTargetParameters { class SceneWindow { public: - SceneWindow(HApiContainer api, bool renderToSwapChain); + SceneWindow(const HApiContainer &api, bool renderToSwapChain); void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); @@ -34,15 +34,15 @@ class SceneWindow { void unload(); std::shared_ptr getLastPlan(); + const std::shared_ptr getCamera(); bool hasRenderer(); std::shared_ptr createRenderView(); - void render(double deltaTime, float fov, const HFrameScenario &scenario, - const ViewPortDimensions &dimension, - const std::function &updateFrameNumberLambda, - const std::shared_ptr &debugRenderView, - uint32_t debugViewWidth, - uint32_t debugViewHeight); + void render(double deltaTime, + float fov, + const HFrameScenario &scenario, + const std::shared_ptr &debugWindow, + const std::function &updateFrameNumberLambda); void makeScreenshot(float fov, uint32_t screenShotWidth, uint32_t screenShotHeight, @@ -50,6 +50,9 @@ class SceneWindow { const HFrameScenario &scenario, const std::function &updateFrameNumberLambda); + void setViewPortDimensions(const ViewPortDimensions &dimensions) { + m_dimension = dimensions; + } private: std::shared_ptr m_sceneRenderer = nullptr; std::shared_ptr m_currentScene = nullptr; @@ -58,6 +61,8 @@ class SceneWindow { protected: float movementSpeed = 1; HApiContainer m_api; + ViewPortDimensions m_dimension = {{0,0}, {0,0}}; + std::shared_ptr m_camera = nullptr; std::shared_ptr m_renderView = nullptr; }; diff --git a/wowViewerLib/src/engine/ApiContainer.h b/wowViewerLib/src/engine/ApiContainer.h index 637de70b3..ffe604ae3 100644 --- a/wowViewerLib/src/engine/ApiContainer.h +++ b/wowViewerLib/src/engine/ApiContainer.h @@ -25,8 +25,6 @@ class ApiContainer { HRequestProcessor requestProcessor = nullptr; HGDevice hDevice = nullptr; std::shared_ptr databaseHandler = nullptr; - std::shared_ptr camera = nullptr; - std::shared_ptr debugCamera = nullptr; Config *getConfig() { return &config; diff --git a/wowViewerLib/src/engine/camera/CameraInterface.h b/wowViewerLib/src/engine/camera/CameraInterface.h index 0a54be3e8..4db014ac7 100644 --- a/wowViewerLib/src/engine/camera/CameraInterface.h +++ b/wowViewerLib/src/engine/camera/CameraInterface.h @@ -21,6 +21,7 @@ class ICamera : public IControllable { float farPlane) = 0; virtual void tick(animTime_t timeDelta) = 0; + virtual float getMovementSpeed() = 0; virtual void setMovementSpeed(float value) = 0; virtual void setCameraOffset(float x, float y, float z) {}; diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp index 9d9e26d54..4d1ec637a 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.cpp +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.cpp @@ -67,7 +67,9 @@ void FirstPersonCamera::stopAllMovement() { MDVerticalMinus = 0; } - +float FirstPersonCamera::getMovementSpeed() { + return this->m_moveSpeed; +} void FirstPersonCamera::setMovementSpeed(float value) { this->m_moveSpeed = value; }; diff --git a/wowViewerLib/src/engine/camera/firstPersonCamera.h b/wowViewerLib/src/engine/camera/firstPersonCamera.h index 82f08f040..dd9adf96d 100644 --- a/wowViewerLib/src/engine/camera/firstPersonCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonCamera.h @@ -69,7 +69,7 @@ class FirstPersonCamera: public ICamera { position[1] = camera.y; position[2] = camera.z; } - + float getMovementSpeed() override; void setMovementSpeed(float value) override; public: diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h index 7aff7c9ac..6a75d1f41 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticCamera.h @@ -41,6 +41,7 @@ class FirstPersonOrthoStaticCamera: public ICamera { void zoomInFromMouseScroll(float val) override {}; void zoomInFromTouch(float val) override {}; void addCameraViewOffset(float x, float y) override {}; + float getMovementSpeed() override {return 0.0f;}; void setMovementSpeed(float value) override {}; void getCameraPosition(float *position) override { diff --git a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h index 8722cbcb8..85b388b57 100644 --- a/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h +++ b/wowViewerLib/src/engine/camera/firstPersonOrthoStaticTopDownCamera.h @@ -43,6 +43,7 @@ class FirstPersonOrthoStaticTopDownCamera: public ICamera { void zoomInFromMouseScroll(float val) override {}; void zoomInFromTouch(float val) override {}; void addCameraViewOffset(float x, float y) override {}; + float getMovementSpeed() override {return 0.0f;}; void setMovementSpeed(float value) override {}; void getCameraPosition(float *position) override { diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.h b/wowViewerLib/src/engine/camera/m2TiedCamera.h index bf4fcbe1e..8c95e6588 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.h +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.h @@ -56,6 +56,7 @@ class m2TiedCamera : public ICamera { float farPlane) override; void tick(animTime_t timeDelta) override ; + float getMovementSpeed() override {return 0.0f;} ; void setMovementSpeed(float value) override {}; void setCameraOffset(float x, float y, float z) override {}; diff --git a/wowViewerLib/src/engine/camera/planarCamera.cpp b/wowViewerLib/src/engine/camera/planarCamera.cpp index 416ba2e1d..64ffc717d 100644 --- a/wowViewerLib/src/engine/camera/planarCamera.cpp +++ b/wowViewerLib/src/engine/camera/planarCamera.cpp @@ -68,6 +68,9 @@ void PlanarCamera::stopAllMovement() { MDVerticalMinus = 0; } +float PlanarCamera::getMovementSpeed() { + return this->m_moveSpeed; +}; void PlanarCamera::setMovementSpeed(float value) { this->m_moveSpeed = value; }; diff --git a/wowViewerLib/src/engine/camera/planarCamera.h b/wowViewerLib/src/engine/camera/planarCamera.h index b0dea49d6..c973ed365 100644 --- a/wowViewerLib/src/engine/camera/planarCamera.h +++ b/wowViewerLib/src/engine/camera/planarCamera.h @@ -74,7 +74,7 @@ class PlanarCamera: public ICamera { position[1] = camera.y; position[2] = camera.z; } - + float getMovementSpeed() override; void setMovementSpeed(float value) override; public: diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 1689eebb2..89ab5d32b 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -28,7 +28,7 @@ void M2Scene::getCandidatesEntities(const MathHelper::FrustumCullingData &frustu void M2Scene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) { - Config* config = this->m_api->getConfig(); + const Config* config = this->m_api->getConfig(); Map::updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); if (config->globalLighting == EParameterSource::eM2) { auto ambient = m_m2Object->getM2SceneAmbientLight(); @@ -36,13 +36,13 @@ void M2Scene::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, if (ambient.Length() < 0.0001) ambient = mathfu::vec4(1.0,1.0,1.0,1.0); - auto frameDepedantData = mapRenderPlan->frameDependentData; + auto frameDependantData = mapRenderPlan->frameDependentData; - frameDepedantData->colors.exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->colors.exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); - frameDepedantData->colors.exteriorDirectColor = mathfu::vec4(0.0,0.0,0.0,0.0); - frameDepedantData->exteriorDirectColorDir = mathfu::vec3(0.0,0.0,0.0); + frameDependantData->colors.exteriorAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorHorizontAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorGroundAmbientColor = mathfu::vec4(ambient.x, ambient.y, ambient.z, 1.0); + frameDependantData->colors.exteriorDirectColor = mathfu::vec4(0.0, 0.0, 0.0, 0.0); + frameDependantData->exteriorDirectColorDir = mathfu::vec3(0.0, 0.0, 0.0); } auto frameDepedantData = mapRenderPlan->frameDependentData; frameDepedantData->FogDataFound = false; @@ -92,51 +92,9 @@ std::shared_ptr M2Scene::createCamera(int cameraNum) { return std::make_shared(m_m2Object, cameraNum); } -void updateCameraPosOnLoad(const HApiContainer &m_api, const std::shared_ptr &m2Object) { - if (m2Object->isMainDataLoaded()) { - CAaBox aabb = m2Object->getColissionAABB(); - if ((mathfu::vec3(aabb.max) - mathfu::vec3(aabb.min)).LengthSquared() < 0.001 ) { - aabb = m2Object->getAABB(); - } - - auto max = aabb.max; - auto min = aabb.min; - - if ((mathfu::vec3(aabb.max) - mathfu::vec3(aabb.min)).LengthSquared() < 20000) { - - mathfu::vec3 modelCenter = mathfu::vec3( - ((max.x + min.x) / 2.0f), - ((max.y + min.y) / 2.0f), - ((max.z + min.z) / 2.0f) - ); - - if ((max.z - modelCenter.z) > (max.y - modelCenter.y)) { - m_api->camera->setCameraPos((max.z - modelCenter.z) / tan(M_PI * 19.0f / 180.0f), 0, 0); - - } else { - m_api->camera->setCameraPos((max.y - modelCenter.y) / tan(M_PI * 19.0f / 180.0f), 0, 0); - } - m_api->camera->setCameraOffset(modelCenter.x, modelCenter.y, modelCenter.z); - } else { - m_api->camera->setCameraPos(1.0,0,0); - m_api->camera->setCameraOffset(0,0,0); - } -#ifdef __EMSCRIPTEN__ - std::vector availableAnimations; - m2Object->getAvailableAnimation(availableAnimations); - supplyAnimationList(&availableAnimations[0], availableAnimations.size()); - std::vector meshIds; - m2Object->getMeshIds(meshIds); - - supplyMeshIds(&meshIds[0], meshIds.size()); - -#endif - } -} - -M2Scene::M2Scene(HApiContainer api, std::string m2Model) { +M2Scene::M2Scene(const HApiContainer &api, const std::string &m2Model) { m_api = api; m_m2Model = m2Model; m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; @@ -151,15 +109,11 @@ M2Scene::M2Scene(HApiContainer api, std::string m2Model) { m2Object->calcWorldPosition(); m_m2Object = m2Object; - auto l_api = m_api; - m_m2Object->addPostLoadEvent([m2Object, l_api]() { - updateCameraPosOnLoad(l_api, m2Object); - }); api->getConfig()->globalFog = EParameterSource::eConfig; } -M2Scene::M2Scene(HApiContainer api, int fileDataId) { +M2Scene::M2Scene(const HApiContainer &api, int fileDataId) { m_api = api; m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; @@ -173,10 +127,6 @@ M2Scene::M2Scene(HApiContainer api, int fileDataId) { m2Object->calcWorldPosition(); m_m2Object = m2Object; - auto l_api = m_api; - m_m2Object->addPostLoadEvent([m2Object, l_api]() { - updateCameraPosOnLoad(l_api, m2Object); - }); api->getConfig()->globalFog = EParameterSource::eConfig; } @@ -192,3 +142,7 @@ void M2Scene::resetReplaceParticleColor() { void M2Scene::exportScene(IExporter* exporter) { exporter->addM2Object(m_m2Object); } + +std::shared_ptr M2Scene::getSceneM2() { + return m_m2Object; +} diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index 402e8ab13..4d907fd83 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -32,13 +32,11 @@ class M2Scene : public Map { StateForConditions &stateForConditions, const AreaRecord &areaRecord) override; public: - explicit M2Scene(HApiContainer api, std::string m2Model); - explicit M2Scene(HApiContainer api, int fileDataId); + explicit M2Scene(const HApiContainer &api, const std::string &m2Model); + explicit M2Scene(const HApiContainer &api, int fileDataId); - ~M2Scene() override { - - } + ~M2Scene() override {} void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextureArray) ; void setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) ; @@ -49,6 +47,8 @@ class M2Scene : public Map { int getCameraNum() ; std::shared_ptr createCamera(int cameraNum); void exportScene(IExporter* exporter); + std::shared_ptr getSceneM2(); + }; diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 0d3c0430f..98c2ad8e7 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -71,8 +71,8 @@ class IMesh : public ObjectWithId { friend class IDevice; public: - auto start() -> int& { return m_start; } - auto end() -> int& { return m_end; } + auto start() -> uint32_t& { return m_start; } + auto end() -> uint32_t& { return m_end; } // auto textureCount() -> int { return m_texture.size(); } auto bindings() const -> const HGVertexBufferBindings& { return m_bindings; } @@ -82,8 +82,8 @@ class IMesh : public ObjectWithId { int instanceIndex = -1; protected: HGVertexBufferBindings m_bindings; - int m_start; - int m_end; + uint32_t m_start; + uint32_t m_end; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index ecc3f920e..7a8022394 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 986232d32..cc732c6a2 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -65,8 +65,13 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( throw std::runtime_error("tried to start render pass with another pass being active already"); } - createViewPortTypes(areaOffset, areaSize, renderPassVlk->getInvertZ()); - createDefaultScissors(areaOffset, areaSize); + std::array fixedAreasSize = { + std::max(1, areaSize[0]), + std::max(1, areaSize[1]) + }; + + createViewPortTypes(areaOffset, fixedAreasSize, renderPassVlk->getInvertZ()); + createDefaultScissors(areaOffset, fixedAreasSize); m_currentRenderPass = renderPassVlk; @@ -81,7 +86,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( auto renderPass = RenderPassHelper( *this, isAboutToExecSecondaryCMD, - renderPassVlk, frameBuffer, areaOffset, areaSize, colorClearColor, depthClear + renderPassVlk, frameBuffer, areaOffset, fixedAreasSize, colorClearColor, depthClear ); setDefaultScissors(); return renderPass; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index c645babc8..e78971f98 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -113,7 +113,7 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public bool isVulkan, animTime_t sceneTime); - virtual std::shared_ptr createRenderView(int width, int height, bool createOutput) = 0; + virtual std::shared_ptr createRenderView(bool createOutput) = 0; private: Config *m_config; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 74b73a42d..ca430ba58 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -853,7 +853,7 @@ HGMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, cons return mesh; } -std::shared_ptr MapSceneRenderForwardVLK::createRenderView(int width, int height, bool createOutput) { +std::shared_ptr MapSceneRenderForwardVLK::createRenderView(bool createOutput) { return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 849557099..c9d630c7a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -106,7 +106,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { // RenderView //-------------------------------------- - std::shared_ptr createRenderView(int width, int height, bool createOutput) override; + std::shared_ptr createRenderView(bool createOutput) override; private: HGDeviceVLK m_device; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index a1c4a2dc5..9d2de2d98 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -1235,8 +1235,8 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // Upload stuff // --------------------- { - ZoneScopedN("submit buffers"); - VkZone(uploadCmd, "submit buffers") +// ZoneScopedN("submit buffers"); +// VkZone(uploadCmd, "submit buffers") uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); @@ -1468,6 +1468,6 @@ HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTe return mesh; } -std::shared_ptr MapSceneRenderVisBufferVLK::createRenderView(int width, int height, bool createOutput) { +std::shared_ptr MapSceneRenderVisBufferVLK::createRenderView(bool createOutput) { return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index ab8911470..f4ee927aa 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -110,7 +110,7 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { // RenderView //-------------------------------------- - std::shared_ptr createRenderView(int width, int height, bool createOutput) override; + std::shared_ptr createRenderView(bool createOutput) override; std::shared_ptr> meshFactory = std::make_shared>(); private: diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp index 498940e06..89aca5fe4 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -65,9 +65,12 @@ void RenderViewForwardVLK::createFrameBuffers() { } void RenderViewForwardVLK::update(int width, int height, float glow) { + width = std::max(1, width); + height = std::max(1, height); + if (width != m_width || height != m_height) { - m_width = width; - m_height = height; + m_width = std::max(1, width); + m_height = std::max(1, height); this->createFrameBuffers(); From 78cebcdacc2414e0936ecb2034018d9fcd35ecf3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 11 Feb 2024 07:09:04 +0200 Subject: [PATCH 169/212] - stuff seem to work. the camera no longer changes when the window is dragged --- CMakeLists.txt | 2 + src/main.cpp | 22 +- src/ui/FrontendUI.cpp | 43 +- src/ui/FrontendUI.h | 2 +- src/ui/childWindow/m2Window/M2Window.cpp | 23 +- src/ui/imguiLib/hasFocus/imguiHasFocus.cpp | 10 + src/ui/imguiLib/hasFocus/imguiHasFocus.h | 17 + .../src/engine/shader/ShaderDefinitions.h | 426 ++++++++---------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 + 9 files changed, 276 insertions(+), 271 deletions(-) create mode 100644 src/ui/imguiLib/hasFocus/imguiHasFocus.cpp create mode 100644 src/ui/imguiLib/hasFocus/imguiHasFocus.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b12592567..6f6f6ce11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,6 +248,8 @@ set(SOURCE_FILES src/ui/childWindow/sceneWindow/SceneWindow.h src/ui/childWindow/m2Window/M2Window.cpp src/ui/childWindow/m2Window/M2Window.h + src/ui/imguiLib/hasFocus/imguiHasFocus.cpp + src/ui/imguiLib/hasFocus/imguiHasFocus.h ) diff --git a/src/main.cpp b/src/main.cpp index 866dedd6b..b01841756 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,12 +59,20 @@ bool stopKeyboard = false; std::shared_ptr frontendUI = nullptr; static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos){ - if (stopMouse) return; + if (stopMouse) { + mleft_pressed = 0; + mright_pressed = 0; + return; + }; HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); auto currentActiveScene = frontendUI->getCurrentActiveScene(); auto controllable = currentActiveScene ? currentActiveScene->getCamera() : nullptr; - if (!controllable) return; + if (!controllable) { + mleft_pressed = 0; + mright_pressed = 0; + return; + }; // if (!pointerIsLocked) { if (mleft_pressed == 1) { @@ -86,6 +94,16 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) // addCameraViewOffset if (stopMouse) return; + HApiContainer apiContainer = *(HApiContainer *)glfwGetWindowUserPointer(window); + auto currentActiveScene = frontendUI->getCurrentActiveScene(); + auto controllable = currentActiveScene ? currentActiveScene->getCamera() : nullptr; + + if (!controllable) { + mleft_pressed = 0; + mright_pressed = 0; + return; + }; + if (action == GLFW_PRESS) { if (button == GLFW_MOUSE_BUTTON_LEFT) { mleft_pressed = 1; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index ce22bdf72..dbde165b4 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -37,6 +37,7 @@ #include "wheelCapture/wheelCapture.h" #include "childWindow/keysUpdateWorkflow/KeysUpdateWorkflow.h" #include "imgui_notify.h" +#include "hasFocus/imguiHasFocus.h" FrontendUI::FrontendUI(HApiContainer api) { m_api = api; @@ -117,8 +118,8 @@ void FrontendUI::composeUI() { static bool show_demo_window = true; -// if (show_demo_window) -// ImGui::ShowDemoWindow(&show_demo_window); + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); if (m_databaseUpdateWorkflow != nullptr) { if (m_databaseUpdateWorkflow->isDatabaseUpdated()) { @@ -152,10 +153,26 @@ void FrontendUI::composeUI() { m_m2Window = std::make_shared(m_api, m_uiRenderer); m_m2Window->openWMOSceneByfdid(113992); - m_m2Window2 = std::make_shared(m_api, m_uiRenderer, "test"); - m_m2Window2->openWMOSceneByfdid(1120838); +// m_m2Window2 = std::make_shared(m_api, m_uiRenderer, "test"); +// m_m2Window2->openWMOSceneByfdid(1120838); }; + m_currentActiveScene = nullptr; + if (!ImGui::HasFocus()) + m_currentActiveScene = m_backgroundScene; + + if (m_m2Window) { + m_currentActiveScene = m_m2Window->isActive() ? m_m2Window : m_currentActiveScene; + } + + if (m_m2Window2) { + m_currentActiveScene = m_m2Window2->isActive() ? m_m2Window2 : m_currentActiveScene; + } + + if (m_currentActiveScene) { + m_lastActiveScene = m_currentActiveScene; + } + // Rendering ImGui::Render(); } @@ -239,8 +256,9 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current blp vulkan textures %f MB", l_blpTexturesVulkanSizeLoaded); } - if (m_currentActiveScene && m_currentActiveScene->hasRenderer()) { - auto mapPlan = m_currentActiveScene->getLastPlan(); + auto activeScene = m_lastActiveScene.lock(); + if (activeScene && activeScene->hasRenderer()) { + auto mapPlan = activeScene->getLastPlan(); if (mapPlan) { auto &cullStageData = mapPlan; @@ -1357,7 +1375,8 @@ void FrontendUI::showSettingsDialog() { } { - auto camera = (m_currentActiveScene) ? m_currentActiveScene->getCamera() : nullptr; + auto activeScene = m_lastActiveScene.lock(); + auto camera = (activeScene) ? activeScene->getCamera() : nullptr; float movementSpeed = (camera) ? camera->getMovementSpeed() : 1.0; if (ImGui::SliderFloat("Movement Speed", &movementSpeed, 0.3, 100)) { if (camera) { @@ -1491,7 +1510,8 @@ void FrontendUI::showSettingsDialog() { } if (ImGui::CollapsingHeader("Light options")) { - auto mapPlan = m_currentActiveScene ? m_currentActiveScene->getLastPlan() : nullptr; + auto activeScene = m_lastActiveScene.lock(); + auto mapPlan = activeScene ? activeScene->getLastPlan() : nullptr; switch(m_api->getConfig()->globalLighting) { case EParameterSource::eDatabase: { @@ -1705,20 +1725,16 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do */ nullptr, updateFrameNumberLambda ); - m_currentActiveScene = m_backgroundScene; if (m_m2Window) { m_m2Window->render(deltaTime, scenario, updateFrameNumberLambda); - m_currentActiveScene = m_m2Window->isActive() ? m_m2Window : m_currentActiveScene; } if (m_m2Window2) { m_m2Window2->render(deltaTime, scenario, updateFrameNumberLambda); - m_currentActiveScene = m_m2Window2->isActive() ? m_m2Window2 : m_currentActiveScene; } - //---------------------- // Screenshot part //---------------------- @@ -1803,7 +1819,8 @@ void FrontendUI::resetAnimationCallback() { } void FrontendUI::getCameraPos(float &cameraX, float &cameraY, float &cameraZ) { - auto camera = m_currentActiveScene ? m_currentActiveScene->getCamera() : nullptr; + auto activeScene = m_lastActiveScene.lock(); + auto camera = activeScene ? activeScene->getCamera() : nullptr; if (camera == nullptr) { cameraX = 0; cameraY = 0; cameraZ = 0; diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index f5066f216..b42a42490 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -72,7 +72,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_backgroundScene = nullptr; std::shared_ptr m_currentActiveScene = nullptr; - + std::weak_ptr m_lastActiveScene; float uiScale = 1; diff --git a/src/ui/childWindow/m2Window/M2Window.cpp b/src/ui/childWindow/m2Window/M2Window.cpp index 03d2db8bc..38643c437 100644 --- a/src/ui/childWindow/m2Window/M2Window.cpp +++ b/src/ui/childWindow/m2Window/M2Window.cpp @@ -38,10 +38,19 @@ bool M2Window::draw() { if (ImGui::Begin(m_windowName.c_str(), &m_showWindow)) { - ImGui::Button("Just a test Button"); - auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto imguiContent = ImGui::GetCurrentContext(); + ImGui::Text("FocusID == %d LastActiveId == %d GetActiveID == %d", ImGui::GetFocusID(), imguiContent->LastActiveId, ImGui::GetActiveID()); +// std::cout +// << " FocusID == " << ImGui::GetFocusID() +// << " LastActiveId == " << imguiContent->LastActiveId +// << " GetActiveID == " << ImGui::GetActiveID() +// << std::endl; + + + + float sizeX = 0, sizeY = 0; auto windowSize = ImGui::GetContentRegionAvail(); sizeX = windowSize.x; @@ -52,8 +61,6 @@ bool M2Window::draw() { m_height = sizeY > 0 ? sizeY : 1; } - - auto const ¤tMaterial = materials[currentFrame]; if (currentMaterial) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); @@ -65,7 +72,12 @@ bool M2Window::draw() { ImGui::ImageButton("ModelScene", currentMaterial->uniqueId, {sizeX, sizeY}); - if (ImGui::GetCurrentWindow()->GetID("ModelScene") == ImGui::GetFocusID()) { + auto modelSceneId = ImGui::GetCurrentWindow()->GetID("ModelScene"); + + + if (modelSceneId == ImGui::GetFocusID() && + modelSceneId == imguiContent->LastActiveId && + (modelSceneId == ImGui::GetActiveID() || 0 == ImGui::GetActiveID())) { ImGui::SetNextFrameWantCaptureKeyboard(false); ImGui::SetNextFrameWantCaptureMouse(false); // static uint32_t itsActive = 0; @@ -77,6 +89,7 @@ bool M2Window::draw() { } + ImGui::End(); } diff --git a/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp b/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp new file mode 100644 index 000000000..9adb254e0 --- /dev/null +++ b/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp @@ -0,0 +1,10 @@ +// +// Created by Deamon on 2/11/2024. +// + +#include "imguiHasFocus.h" +#include "imgui_internal.h" + +bool ImGui::HasFocus() { + return ImGui::GetFocusID() != 0; +} \ No newline at end of file diff --git a/src/ui/imguiLib/hasFocus/imguiHasFocus.h b/src/ui/imguiLib/hasFocus/imguiHasFocus.h new file mode 100644 index 000000000..c237f54f3 --- /dev/null +++ b/src/ui/imguiLib/hasFocus/imguiHasFocus.h @@ -0,0 +1,17 @@ +// +// Created by Deamon on 2/11/2024. +// + +#ifndef AWEBWOWVIEWERCPP_IMGUIHASFOCUS_H +#define AWEBWOWVIEWERCPP_IMGUIHASFOCUS_H + + +namespace ImGui { + //The standart imgui button ties to user_texture_id as id. Thus it cant detect clicks, + // when user_texture_id is different in every frame (like when that texture is from framebuffer) + bool HasFocus(); +} + + + +#endif //AWEBWOWVIEWERCPP_IMGUIHASFOCUS_H diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f3daaa1a5..780d81036 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,11 +396,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -507,9 +502,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -651,6 +643,42 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "forwardRendering/ribbonShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/waterfallShader.vert.spv", { ShaderStage::Vertex, @@ -676,11 +704,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -866,8 +889,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -906,7 +927,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -947,11 +967,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -969,17 +988,11 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1014,11 +1027,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1140,15 +1152,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1171,11 +1174,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1343,12 +1345,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,7 +1566,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -1602,6 +1601,42 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "forwardRendering/imguiShaderDepth.frag.spv", + { + ShaderStage::Fragment, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {1,0, "Texture"}, + }, + { + { + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "visBuffer/wmoShader.frag.spv", { ShaderStage::Fragment, @@ -1625,8 +1660,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1666,16 +1699,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1712,7 +1743,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1861,7 +1891,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -2107,17 +2136,12 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2182,52 +2206,13 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 9, { - } - }, - { - 8, { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, } }, { @@ -2239,16 +2224,6 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2729,19 +2665,19 @@ const std::unordered_map Date: Mon, 12 Feb 2024 07:55:01 +0200 Subject: [PATCH 170/212] - rendering in separate window of quick links - fix of soring of non-opaque meshes --- src/database/CSqliteDB.cpp | 4 +- src/ui/FrontendUI.cpp | 312 +++++++++--------- src/ui/FrontendUI.h | 12 +- src/ui/childWindow/m2Window/M2Window.cpp | 10 +- .../childWindow/sceneWindow/SceneWindow.cpp | 38 ++- src/ui/childWindow/sceneWindow/SceneWindow.h | 13 + src/ui/imguiLib/hasFocus/imguiHasFocus.cpp | 4 +- .../src/engine/camera/CameraInterface.h | 18 + .../src/engine/camera/m2TiedCamera.cpp | 13 +- .../src/engine/objects/scenes/map.cpp | 15 +- .../src/engine/objects/wmo/wmoObject.cpp | 7 +- .../src/engine/objects/wmo/wmoObject.h | 2 + .../src/engine/shader/ShaderDefinitions.h | 222 ++++++++++--- wowViewerLib/src/include/config.h | 2 - .../src/renderer/mapScene/MapScenePlan.h | 2 + .../vulkan/MapSceneRenderForwardVLK.cpp | 8 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 8 +- 17 files changed, 435 insertions(+), 255 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 8a9e5d18c..453512b60 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -54,7 +54,7 @@ const std::string getMapByIDSQL_classic = "select m.ID, m.Directory, m.MapName_lang, m.MapType from Map m"; const std::string getWmoAreaAreaNameSQL = R"===( - select wat.AreaName_lang as wmoAreaName, at.AreaName_lang, at.ID, at.ParentAreaID, at.Ambient_multiplier from WMOAreaTable wat + select wat.AreaName_lang as wmoAreaName, at.AreaName_lang as areaName, at.ID as ID, at.ParentAreaID as ParentAreaID, at.Ambient_multiplier as Ambient_multiplier from WMOAreaTable wat left join AreaTable at on at.id = wat.AreaTableID where wat.WMOID = ? and wat.NameSetID = ? and (wat.WMOGroupID = -1 or wat.WMOGroupID = ?) ORDER BY wat.WMOGroupID DESC )==="; @@ -234,7 +234,7 @@ AreaRecord CSqliteDB::getWmoArea(int wmoId, int nameId, int groupId) { while (getWmoAreaAreaName.execute()) { std::string wmoAreaName = getWmoAreaAreaName.getField("wmoAreaName").getString(); - std::string areaName = getWmoAreaAreaName.getField("AreaName_lang").getString(); + std::string areaName = getWmoAreaAreaName.getField("areaName").getString(); if (wmoAreaName == "") { diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index dbde165b4..746a454c3 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -148,25 +148,14 @@ void FrontendUI::composeUI() { if (m_debugRenderWindow) m_debugRenderWindow->draw(); - //Test hack - if (cascOpened && m_m2Window == nullptr) { - m_m2Window = std::make_shared(m_api, m_uiRenderer); - m_m2Window->openWMOSceneByfdid(113992); - -// m_m2Window2 = std::make_shared(m_api, m_uiRenderer, "test"); -// m_m2Window2->openWMOSceneByfdid(1120838); - }; - m_currentActiveScene = nullptr; if (!ImGui::HasFocus()) m_currentActiveScene = m_backgroundScene; - if (m_m2Window) { - m_currentActiveScene = m_m2Window->isActive() ? m_m2Window : m_currentActiveScene; - } - - if (m_m2Window2) { - m_currentActiveScene = m_m2Window2->isActive() ? m_m2Window2 : m_currentActiveScene; + for (auto &window : m_m2Windows) { + if (window && window->isActive()) { + m_currentActiveScene = window; + } } if (m_currentActiveScene) { @@ -239,7 +228,6 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); // if(getCurrentAreaName) { - ImGui::Text("Current area name: %s", getCurrentAreaName().c_str()); ImGui::Text("Uniform data for GPU: %.3f MB", m_api->hDevice->getUploadSize() / (1024.0f * 1024.0f)); @@ -261,6 +249,29 @@ void FrontendUI::showCurrentStatsDialog() { auto mapPlan = activeScene->getLastPlan(); if (mapPlan) { auto &cullStageData = mapPlan; + if (ImGui::CollapsingHeader("Current Scene Data")) { + ImGui::Text("Current area id: %d", mapPlan->areaId); + ImGui::Text("Current parent area id: %d", mapPlan->parentAreaId); + ImGui::Text("Current adt area id: %d", mapPlan->adtAreadId); + ImGui::Text("Current area name: %s", mapPlan->areaName.c_str()); + ImGui::Separator(); + + { + int modelFdid = 0; + std::string modelFileName = ""; + if (mapPlan->m_currentWMO != nullptr) { + modelFdid = mapPlan->m_currentWMO->getModelFileId(); + modelFileName = mapPlan->m_currentWMO->getModelFileName(); + } + if (modelFileName.empty()) { + ImGui::Text("Current WMO: %d", modelFdid); + } else { + ImGui::Text("Current WMO: %s", modelFileName.c_str()); + } + } + + ImGui::Text("Current WMO group: %d", mapPlan->m_currentWmoGroup); + } if (ImGui::CollapsingHeader("Objects Drawn/Culled")) { auto &adtArray = mapPlan->adtArray; @@ -398,12 +409,11 @@ void FrontendUI::showBlpViewer() { } void FrontendUI::showM2Viewer() { - if (m_m2Window && !m_m2Window->draw()) { - m_m2Window = nullptr; - } - if (m_m2Window2 && !m_m2Window2->draw()) { - m_m2Window2 = nullptr; + for (auto &window : m_m2Windows) { + if (window && !window->draw()) { + window = nullptr; + } } } @@ -821,11 +831,11 @@ void FrontendUI::showMainMenu() { m_blpFileViewerWindow->loadBlp(std::to_string(fileId)); } else if (fileType == "m2") { - m_backgroundScene->openM2SceneByfdid(fileId, {}); + getOrCreateWindow()->openM2SceneByfdid(fileId, {}); } else if (fileType == "wmo") { - m_backgroundScene->openWMOSceneByfdid(fileId); + getOrCreateWindow()->openWMOSceneByfdid(fileId); } else if (fileType == "wdt") { - m_backgroundScene->openMapByIdAndWDTId(0, fileId, 0,0,0); + getOrCreateWindow()->openMapByIdAndWDTId(0, fileId, 0,0,0); } }); } @@ -971,111 +981,111 @@ void FrontendUI::showQuickLinksDialog() { ImGui::Begin("Quick Links", &showQuickLinks); if (ImGui::Button("model without skin", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - m_backgroundScene->openM2SceneByfdid(5099010, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(5099010, replacementTextureFDids); } if (ImGui::Button("crystal song bush", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - m_backgroundScene->openM2SceneByfdid(194418, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(194418, replacementTextureFDids); } if (ImGui::Button("bugged decal", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - m_backgroundScene->openM2SceneByfdid(946969, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(946969, replacementTextureFDids); } if (ImGui::Button("Some model", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 4952373; replacementTextureFDids[12] = 4952379; - m_backgroundScene->openM2SceneByfdid(4870631, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4870631, replacementTextureFDids); } if (ImGui::Button("nightborne model", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(1810676, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1810676, replacementTextureFDids); } if (ImGui::Button("Tomb of sargares hall", ImVec2(-1, 0))) { - m_backgroundScene->openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); + getOrCreateWindow()->openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); } if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(1120838); + getOrCreateWindow()->openWMOSceneByfdid(1120838); } if (ImGui::Button("8du_zuldazarraid_antiportal01.wmo", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(2574165); + getOrCreateWindow()->openWMOSceneByfdid(2574165); } if (ImGui::Button("someShip.wmo", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(4638404); + getOrCreateWindow()->openWMOSceneByfdid(4638404); } if (ImGui::Button("Vanilla karazhan", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByFilename("world/wmo/dungeon/az_karazahn/karazhan.wmo"); + getOrCreateWindow()->openWMOSceneByFilename("world/wmo/dungeon/az_karazahn/karazhan.wmo"); } if (ImGui::Button("10xt_exterior_glacialspike01.wmo (parallax)", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(4419436); + getOrCreateWindow()->openWMOSceneByfdid(4419436); } if (ImGui::Button("14654.wmo (parallax)", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(4222547); + getOrCreateWindow()->openWMOSceneByfdid(4222547); } if (ImGui::Button("10.0 Raid WMO", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(4282557); + getOrCreateWindow()->openWMOSceneByfdid(4282557); } if (ImGui::Button("(WMO) Model with broken portal culling", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(4217818); + getOrCreateWindow()->openWMOSceneByfdid(4217818); } if (ImGui::Button("(WMO) NPE Ship with waterfall model", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(3314067); + getOrCreateWindow()->openWMOSceneByfdid(3314067); } if (ImGui::Button("(WMO) Gazebo 590182", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(590182); + getOrCreateWindow()->openWMOSceneByfdid(590182); } if (ImGui::Button("Hearthstone Tavern", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(2756726); + getOrCreateWindow()->openWMOSceneByfdid(2756726); } if (ImGui::Button("Original WVF1 model", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(2445860, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(2445860, replacementTextureFDids); } if (ImGui::Button("Stormwind mage portal", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(2394711, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(2394711, replacementTextureFDids); } if (ImGui::Button("kodobeasttame", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(124697, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(124697, replacementTextureFDids); } // if (ImGui::Button("Azeroth map: Lion's Rest (Legion)", ImVec2(-1, 0))) { // openMapByIdAndFilename(0, "azeroth", -8739, 944, 200); // } if (ImGui::Button("Nyalotha map", ImVec2(-1, 0))) { - m_backgroundScene->openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260); + getOrCreateWindow()->openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260); } if (ImGui::Button("WMO 1247268", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(1247268); + getOrCreateWindow()->openWMOSceneByfdid(1247268); } if (ImGui::Button("Ironforge.wmo", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(113992); + getOrCreateWindow()->openWMOSceneByfdid(113992); } if (ImGui::Button("Some item", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[1] = 528801; - for (auto &fdid: replacementTextureFDids) { - fdid = 1029337; - } - m_backgroundScene->openM2SceneByfdid(1029334, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[1] = 528801; + for (auto &fdid: replacementTextureFDids) { + fdid = 1029337; + } + getOrCreateWindow()->openM2SceneByfdid(1029334, replacementTextureFDids); } if (ImGui::Button("IGC Anduin", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3849312, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3849312, replacementTextureFDids); } if (ImGui::Button("Steamscale mount", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(2843110, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(2843110, replacementTextureFDids); } if (ImGui::Button("Spline emitter", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(1536145, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1536145, replacementTextureFDids); } if (ImGui::Button("Nether collector top", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(193157, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(193157, replacementTextureFDids); } if (ImGui::Button("Сollector top", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(113540); + getOrCreateWindow()->openWMOSceneByfdid(113540); } if (ImGui::Button("10.0 unk model", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - m_backgroundScene->openM2SceneByfdid(4519090, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4519090, replacementTextureFDids); } if (ImGui::Button("10.0 strange shoulders", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); @@ -1084,106 +1094,106 @@ void FrontendUI::showQuickLinksDialog() { - m_backgroundScene->openM2SceneByfdid(4614814, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4614814, replacementTextureFDids); } if (ImGui::Button("DF chicken", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 4007136; - m_backgroundScene->openM2SceneByfdid(4005446, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4005446, replacementTextureFDids); } if (ImGui::Button("Fox", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3071379; - m_backgroundScene->openM2SceneByfdid(3071370, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3071370, replacementTextureFDids); } if (ImGui::Button("COT hourglass", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(190850, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(190850, replacementTextureFDids); } if (ImGui::Button("Gryphon roost", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(198261, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(198261, replacementTextureFDids); } if (ImGui::Button("Northrend Human Inn", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(114998); + getOrCreateWindow()->openWMOSceneByfdid(114998); } if (ImGui::Button("Strange WMO", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(2342637); + getOrCreateWindow()->openWMOSceneByfdid(2342637); } if (ImGui::Button("Flyingsprite", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3059000; - m_backgroundScene->openM2SceneByfdid(3024835, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3024835, replacementTextureFDids); } if (ImGui::Button("maldraxxusflyer", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3196375; - m_backgroundScene->openM2SceneByfdid(3196372, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3196372, replacementTextureFDids); } if (ImGui::Button("ridingphoenix", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); - m_backgroundScene->openM2SceneByfdid(125644, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(125644, replacementTextureFDids); } if (ImGui::Button("Upright Orc", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[1] = 3844710; - m_backgroundScene->openM2SceneByfdid(1968587, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1968587, replacementTextureFDids); } if (ImGui::Button("quillboarbrute.m2", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 1786107; - m_backgroundScene->openM2SceneByfdid(1784020, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1784020, replacementTextureFDids); } if (ImGui::Button("WMO With Horde Symbol", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(1846142); + getOrCreateWindow()->openWMOSceneByfdid(1846142); } if (ImGui::Button("WMO 3565693", ImVec2(-1, 0))) { - m_backgroundScene->openWMOSceneByfdid(3565693); + getOrCreateWindow()->openWMOSceneByfdid(3565693); } if (ImGui::Button("Vanilla login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(131970, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(131970, replacementTextureFDids); } if (ImGui::Button("BC login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(131982, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(131982, replacementTextureFDids); // auto ambient = mathfu::vec4(0.3929412066936493f, 0.26823532581329346f, 0.3082353174686432f, 0); m_api->getConfig()->BCLightHack = true; } if (ImGui::Button("Wrath login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(236122, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(236122, replacementTextureFDids); } if (ImGui::Button("Cataclysm login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(466614, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(466614, replacementTextureFDids); } if (ImGui::Button("Panda login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(631713, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(631713, replacementTextureFDids); } if (ImGui::Button("Draenor login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByName("interface/glues/models/ui_mainmenu_warlords/ui_mainmenu_warlords.m2", replacementTextureFDids); + getOrCreateWindow()->openM2SceneByName("interface/glues/models/ui_mainmenu_warlords/ui_mainmenu_warlords.m2", replacementTextureFDids); } if (ImGui::Button("Legion Login Screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(1396280, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1396280, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("BfA login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(2021650, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(2021650, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("Shadowlands login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3846560, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3846560, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("DragonLands login screen", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(4684877, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4684877, replacementTextureFDids); // m_api->getConfig()->setBCLightHack(true); } if (ImGui::Button("Shadowlands clouds", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3445776, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3445776, replacementTextureFDids); } if (ImGui::Button("Pink serpent", ImVec2(-1, 0))) { @@ -1192,7 +1202,7 @@ void FrontendUI::showQuickLinksDialog() { replacementTextureFDids[11] = 2905480; replacementTextureFDids[12] = 2905481; replacementTextureFDids[13] = 577442; - m_backgroundScene->openM2SceneByfdid(577443, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(577443, replacementTextureFDids); } if (ImGui::Button("Wolf", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); @@ -1200,68 +1210,68 @@ void FrontendUI::showQuickLinksDialog() { replacementTextureFDids[11] = 126494; replacementTextureFDids[12] = 126495; replacementTextureFDids[13] = 0; - m_backgroundScene->openM2SceneByfdid(126487, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(126487, replacementTextureFDids); } if (ImGui::Button("Aggramar", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 1599776; - m_backgroundScene->openM2SceneByfdid(1599045, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1599045, replacementTextureFDids); } if (ImGui::Button("M2 3087468", ImVec2(-1, 0))) { replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3087540; - m_backgroundScene->openM2SceneByfdid(3087468, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3087468, replacementTextureFDids); } if (ImGui::Button("Nagrand skybox", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(130575, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(130575, replacementTextureFDids); } if (ImGui::Button("Torghast raid skybox", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(4001212, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(4001212, replacementTextureFDids); } if (ImGui::Button("3445776 PBR cloud sky in Maw", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3445776, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3445776, replacementTextureFDids); } if (ImGui::Button("M2 3572296", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3572296, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3572296, replacementTextureFDids); } if (ImGui::Button("M2 3487959", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3487959, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3487959, replacementTextureFDids); } if (ImGui::Button("M2 1729717 waterfall", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(1729717, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1729717, replacementTextureFDids); } if (ImGui::Button("Maw jailer", ImVec2(-1, 0))) { // 3096499,3096495 replacementTextureFDids = std::vector(17); replacementTextureFDids[11] = 3096499; replacementTextureFDids[12] = 3096495; - m_backgroundScene->openM2SceneByfdid(3095966, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3095966, replacementTextureFDids); } if (ImGui::Button("Creature with colors", ImVec2(-1, 0))) { // 3096499,3096495 - m_backgroundScene->openM2SceneByfdid(1612576, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(1612576, replacementTextureFDids); } if (ImGui::Button("IC new sky", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3159936, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3159936, replacementTextureFDids); } if (ImGui::Button("vampire candle", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(3184581, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3184581, replacementTextureFDids); } if (ImGui::Button("Bog Creature", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[11] = 3732358; - replacementTextureFDids[12] = 3732360; - replacementTextureFDids[13] = 3732368; + replacementTextureFDids = std::vector(17); + replacementTextureFDids[11] = 3732358; + replacementTextureFDids[12] = 3732360; + replacementTextureFDids[13] = 3732368; - m_backgroundScene->openM2SceneByfdid(3732303, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(3732303, replacementTextureFDids); } if (ImGui::Button("Bugged ADT (SL)", ImVec2(-1, 0))) { // m_currentScene = setScene(m_api, 2, "world/maps/2363/2363_31_31.adt", 0); @@ -1270,24 +1280,24 @@ void FrontendUI::showQuickLinksDialog() { ImGui::Text("Models for billboard checking"); ImGui::NewLine(); if (ImGui::Button("Dalaran dome", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(203598, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(203598, replacementTextureFDids); } if (ImGui::Button("Gift of Nzoth", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(2432705, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(2432705, replacementTextureFDids); } if (ImGui::Button("Plagueheart Shoulderpad", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(143343, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(143343, replacementTextureFDids); } if (ImGui::Button("Dalaran eye", ImVec2(-1, 0))) { - m_backgroundScene->openM2SceneByfdid(243044, replacementTextureFDids); + getOrCreateWindow()->openM2SceneByfdid(243044, replacementTextureFDids); } if (ImGui::Button("Hand weapon", ImVec2(-1, 0))) { - replacementTextureFDids = std::vector(17); - replacementTextureFDids[1] = 528801; - for (auto &fdid: replacementTextureFDids) { - fdid = 528801; - } - m_backgroundScene->openM2SceneByfdid(528797, replacementTextureFDids); + replacementTextureFDids = std::vector(17); + replacementTextureFDids[1] = 528801; + for (auto &fdid: replacementTextureFDids) { + fdid = 528801; + } + getOrCreateWindow()->openM2SceneByfdid(528797, replacementTextureFDids); } ImGui::End(); @@ -1298,8 +1308,13 @@ static HGTexture blpText = nullptr; void FrontendUI::showSettingsDialog() { if(showSettings) { ImGui::Begin("Settings", &showSettings); + + //Camera Selection + auto activeScene = m_lastActiveScene.lock(); + if (activeScene) { std::string currentCamera; + auto currentCameraNum = activeScene->getCurrentCameraIndex(); if (currentCameraNum == -1) { currentCamera = "First person"; } else { @@ -1311,12 +1326,11 @@ void FrontendUI::showSettingsDialog() { ImGui::SameLine(); if (ImGui::BeginCombo("##combo", currentCamera.c_str())) // The second parameter is the label previewed before opening the combo. { - int cameraNum = getCameraNumCallback(); - + int cameraNum = activeScene->getCurrentCameraCount(); { const std::string caption = "First person"; if (ImGui::Selectable(caption.c_str(), currentCameraNum == -1)) { - setNewCameraCallback(-1); + activeScene->setCurrentCameraIndex(-1); currentCameraNum = -1; } } @@ -1326,9 +1340,7 @@ void FrontendUI::showSettingsDialog() { bool is_selected = (currentCameraNum == n); // You can store your selection however you want, outside or inside your objects std::string caption = "Camera Num " + std::to_string(n); if (ImGui::Selectable(caption.c_str(), is_selected)) { - if (setNewCameraCallback(n)) { - currentCameraNum = n; - } + activeScene->setCurrentCameraIndex(n); } if (is_selected) @@ -1652,11 +1664,6 @@ bool FrontendUI::fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists) { return true; } -std::string FrontendUI::getCurrentAreaName() { - auto conf = m_api->getConfig(); - return conf->areaName; -} - void FrontendUI::showMakeScreenshotDialog() { if (showMakeScreenshot) { ImGui::Begin("Make screenshot", &showMakeScreenshot); @@ -1725,16 +1732,12 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do */ nullptr, updateFrameNumberLambda ); - - if (m_m2Window) { - m_m2Window->render(deltaTime, scenario, updateFrameNumberLambda); - } - - if (m_m2Window2) { - m_m2Window2->render(deltaTime, scenario, updateFrameNumberLambda); + for (auto &window : m_m2Windows) { + if (window) { + window->render(deltaTime, scenario, updateFrameNumberLambda); + } } - //---------------------- // Screenshot part //---------------------- @@ -1789,31 +1792,6 @@ void FrontendUI::unloadScene() { m_backgroundScene->unload(); } - - -int FrontendUI::getCameraNumCallback() { -// if (m_currentScene != nullptr) { -//// return m_currentScene->getCameraNum(); -// } - - return 0; -} - -bool FrontendUI::setNewCameraCallback(int cameraNum) { - return false; -// if (currentScene == nullptr) return false; -// -// auto newCamera = currentScene->createCamera(cameraNum); -// if (newCamera == nullptr) { -// m_api->camera = std::make_shared(); -// m_api->camera->setMovementSpeed(movementSpeed); -// return false; -// } -// -// m_api->camera = newCamera; -// return true; -} - void FrontendUI::resetAnimationCallback() { // currentScene->resetAnimation(); } @@ -1935,3 +1913,23 @@ void FrontendUI::createFontTexture() { io.Fonts->TexID = fontMat->uniqueId; } +std::shared_ptr FrontendUI::getOrCreateWindow() { + //If shift key is pressed -> create a new window + ImGuiIO& io = ImGui::GetIO(); + if (io.KeyShift) { + for (int i = 0; i < m_m2Windows.size(); i++) { + if (m_m2Windows[i] == nullptr) { + m_m2Windows[i] = std::make_shared(m_api, m_uiRenderer, std::to_string(i)); + return m_m2Windows[i]; + } + } + // Create entry, cause there are no empty space + auto newWindow = std::make_shared(m_api, m_uiRenderer, std::to_string(m_m2Windows.size())); + m_m2Windows.push_back(newWindow); + return newWindow; + } + + //Return usual background otherwise + return m_backgroundScene; +} + diff --git a/src/ui/FrontendUI.h b/src/ui/FrontendUI.h index b42a42490..d7f676b9b 100644 --- a/src/ui/FrontendUI.h +++ b/src/ui/FrontendUI.h @@ -87,13 +87,11 @@ class FrontendUI : public IScene, public std::enable_shared_from_this &mapList); - std::string getCurrentAreaName(); - bool fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists); + bool fillAdtSelectionminimap(bool &isWMOMap, bool &wdtFileExists); + std::shared_ptr getOrCreateWindow(); void unloadScene(); - int getCameraNumCallback(); - bool setNewCameraCallback(int cameraNum); void resetAnimationCallback(); std::array, 64> adtSelectionMinimapTextures; @@ -157,7 +155,7 @@ class FrontendUI : public IScene, public std::enable_shared_from_this m_minimapGenerationWindow = nullptr; std::shared_ptr m_blpViewerWindow = nullptr; std::shared_ptr m_blpFileViewerWindow = nullptr; - std::shared_ptr m_m2Window = nullptr; - std::shared_ptr m_m2Window2 = nullptr; + std::vector> m_m2Windows = {}; + std::shared_ptr m_fileListWindow = nullptr; std::shared_ptr m_debugRenderWindow; diff --git a/src/ui/childWindow/m2Window/M2Window.cpp b/src/ui/childWindow/m2Window/M2Window.cpp index 38643c437..773da202e 100644 --- a/src/ui/childWindow/m2Window/M2Window.cpp +++ b/src/ui/childWindow/m2Window/M2Window.cpp @@ -8,8 +8,6 @@ M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix) : SceneWindow(api, false), m_uiRenderer(renderer) { m_windowName = "M2Window##" + nameSuffix; - - openWMOSceneByfdid(113992); } M2Window::~M2Window() { @@ -41,15 +39,15 @@ bool M2Window::draw() { auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto imguiContent = ImGui::GetCurrentContext(); - ImGui::Text("FocusID == %d LastActiveId == %d GetActiveID == %d", ImGui::GetFocusID(), imguiContent->LastActiveId, ImGui::GetActiveID()); + { +// auto imguiContent = ImGui::GetCurrentContext(); +// ImGui::Text("FocusID == %d LastActiveId == %d GetActiveID == %d", ImGui::GetFocusID(), imguiContent->LastActiveId, ImGui::GetActiveID()); // std::cout // << " FocusID == " << ImGui::GetFocusID() // << " LastActiveId == " << imguiContent->LastActiveId // << " GetActiveID == " << ImGui::GetActiveID() // << std::endl; - - - + } float sizeX = 0, sizeY = 0; auto windowSize = ImGui::GetContentRegionAvail(); diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index c35e92a18..2b9e2d0f8 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -9,9 +9,10 @@ #include "../../../../wowViewerLib/src/engine/objects/scenes/wmoScene.h" #include "../../../../wowViewerLib/src/engine/objects/scenes/NullScene.h" #include "../../../screenshots/screenshotMaker.h" +#include "../../../../wowViewerLib/src/engine/camera/m2TiedCamera.h" -void updateCameraPosOnLoad(const std::shared_ptr &m2Object, const std::shared_ptr &camera) { +void updateCameraPosOnLoad(const std::shared_ptr &m2Object, const std::shared_ptr &camera, std::vector> &cameraList) { if (m2Object->isMainDataLoaded()) { CAaBox aabb = m2Object->getColissionAABB(); if ((mathfu::vec3(aabb.max) - mathfu::vec3(aabb.min)).LengthSquared() < 0.001 ) { @@ -41,6 +42,16 @@ void updateCameraPosOnLoad(const std::shared_ptr &m2Object, const std: camera->setCameraPos(1.0,0,0); camera->setCameraOffset(0,0,0); } + + //Create cameras + { + auto cameraNum = m2Object->getCameraNum(); + for (int i = 0; i < cameraNum; i++) { + auto newCamera = std::make_shared(m2Object, i); + cameraList.push_back(newCamera); + } + } + #ifdef __EMSCRIPTEN__ std::vector availableAnimations; m2Object->getAvailableAnimation(availableAnimations); @@ -179,8 +190,8 @@ void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacem { //Post load event for m2 auto m2Object = m2Scene->getSceneM2(); - m2Object->addPostLoadEvent([m2Object, l_camera = m_camera]() { - updateCameraPosOnLoad(m2Object, l_camera); + m2Object->addPostLoadEvent([m2Object, l_camera = m_camera, &l_cameraList = m_cameraList]() { + updateCameraPosOnLoad(m2Object, l_camera, l_cameraList); }); } } @@ -199,8 +210,8 @@ void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::ve { //Post load event for m2 auto m2Object = m2Scene->getSceneM2(); - m2Object->addPostLoadEvent([m2Object, l_camera = m_camera]() { - updateCameraPosOnLoad(m2Object, l_camera); + m2Object->addPostLoadEvent([m2Object, l_camera = m_camera, &l_cameraList = m_cameraList]() { + updateCameraPosOnLoad(m2Object, l_camera, l_cameraList); }); } } @@ -240,6 +251,10 @@ std::shared_ptr SceneWindow::getLastPlan() { return (m_sceneRenderer) ? m_sceneRenderer->getLastCreatedPlan() : nullptr; } const std::shared_ptr SceneWindow::getCamera() { + if (m_currentCameraIndex >= 0 && m_currentCameraIndex <= m_cameraList.size()) { + return m_cameraList[m_currentCameraIndex]; + } + return m_camera; } @@ -262,12 +277,15 @@ SceneWindow::render(double deltaTime, ) { if (!hasRenderer()) return; - if (!m_camera) return; + + auto currentCamera = getCamera(); + if (!currentCamera) return; + if (!m_renderToSwapChain && !m_renderView) { m_renderView = m_sceneRenderer->createRenderView(true); } - m_camera->tick(deltaTime * 1000.0f); + currentCamera->tick(deltaTime * 1000.0f); if (m_api->getConfig()->pauseAnimation) { deltaTime = 0.0; @@ -294,7 +312,7 @@ SceneWindow::render(double deltaTime, std::vector renderTargetParams = { { - m_camera, + currentCamera, l_dimension, target } @@ -302,13 +320,13 @@ SceneWindow::render(double deltaTime, if (m_api->getConfig()->doubleCameraDebug) { auto &debugParams = renderTargetParams.emplace_back(); - debugParams.camera = debugWindow->m_camera; + debugParams.camera = debugWindow->getCamera(); debugParams.dimensions = debugViewDimension; debugParams.target = debugTarget; } wowSceneFrameInput->frameParameters = createMapSceneParams(m_api, - m_camera, + currentCamera, fov, renderTargetParams, m_currentScene); diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 3e5a41e1f..202acdd4d 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -53,6 +53,15 @@ class SceneWindow { void setViewPortDimensions(const ViewPortDimensions &dimensions) { m_dimension = dimensions; } + + int getCurrentCameraIndex() {return m_currentCameraIndex;} + int getCurrentCameraCount() {return m_cameraList.size();} + void setCurrentCameraIndex(int i) { + if (i < m_cameraList.size()) + m_currentCameraIndex = i; + else + m_currentCameraIndex = -1; + } private: std::shared_ptr m_sceneRenderer = nullptr; std::shared_ptr m_currentScene = nullptr; @@ -63,6 +72,10 @@ class SceneWindow { HApiContainer m_api; ViewPortDimensions m_dimension = {{0,0}, {0,0}}; std::shared_ptr m_camera = nullptr; + + int m_currentCameraIndex = -1; + std::vector> m_cameraList; + std::shared_ptr m_renderView = nullptr; }; diff --git a/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp b/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp index 9adb254e0..a3ebff3df 100644 --- a/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp +++ b/src/ui/imguiLib/hasFocus/imguiHasFocus.cpp @@ -6,5 +6,7 @@ #include "imgui_internal.h" bool ImGui::HasFocus() { - return ImGui::GetFocusID() != 0; + auto context = ImGui::GetCurrentContext(); + ImGuiWindow* window = context->NavWindow; + return window != nullptr; } \ No newline at end of file diff --git a/wowViewerLib/src/engine/camera/CameraInterface.h b/wowViewerLib/src/engine/camera/CameraInterface.h index 4db014ac7..85bd2baa8 100644 --- a/wowViewerLib/src/engine/camera/CameraInterface.h +++ b/wowViewerLib/src/engine/camera/CameraInterface.h @@ -28,6 +28,24 @@ class ICamera : public IControllable { virtual bool isCompatibleWithInfiniteZ() { return true; } + + static inline mathfu::mat4 persectiveInvertZ(float aspectRatio, float fovy, float n, float f) + { + mathfu::mat4 result; + + float s = aspectRatio; + float g = 1.0f / std::tan(fovy * static_cast(.5)); + float A = n / (f - n); + float B = f*n / (f - n); + + result = mathfu::mat4(g/s , 0.0f, 0.0f, 0.0f, + 0.0f, g , 0.0f, 0.0f, + 0.0f, 0.0f, A , -1.0f , + 0.0f, 0.0f, B, 0.0f); + + return result; + } + }; #endif //WOWVIEWERLIB_CAMERAINTERFACE_H diff --git a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp index 67a91d1ef..2a4d7739a 100644 --- a/wowViewerLib/src/engine/camera/m2TiedCamera.cpp +++ b/wowViewerLib/src/engine/camera/m2TiedCamera.cpp @@ -35,11 +35,14 @@ HCameraMatrices m2TiedCamera::getCameraMatrices(float fov, float canvasAspect, f fov = m_lastCameraResult.diagFov / sqrt(1.0f + canvasAspect*canvasAspect); HCameraMatrices cameraMatrices = std::make_shared(); - cameraMatrices->perspectiveMat = mathfu::mat4::Perspective( - fov, - canvasAspect, - nearPlane, - farPlane); +// cameraMatrices->perspectiveMat = mathfu::mat4::Perspective( +// fov, +// canvasAspect, +// nearPlane, +// farPlane); + + cameraMatrices->perspectiveMat = persectiveInvertZ(canvasAspect, fov, nearPlane, farPlane); + cameraMatrices->lookAtMat = lookAtMat4; auto invViewMat = lookAtMat4.Inverse(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index c36cb6678..03abe9c70 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -422,7 +422,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams } - m_api->getConfig()->areaName = areaRecord.areaName; + mapRenderPlan->areaName = areaRecord.areaName; stateForConditions.currentAreaId = areaRecord.areaId; stateForConditions.currentParentAreaId = areaRecord.parentAreaId; @@ -573,6 +573,14 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } } + bool drawDefaultSkybox = true; + for (auto &_light : lightResults) { + if (!_light.isDefault && _light.blendCoef > 0.99999f) { + drawDefaultSkybox = false; + } + } + + //Delete skyboxes that are not in light array std::unordered_map> perFdidMap; auto modelIt = m_exteriorSkyBoxes.begin(); @@ -580,6 +588,8 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp bool found = false; for (auto &_light : lightResults) { if (_light.skyBoxFdid == (*modelIt)->getModelFileId()) { + if (!drawDefaultSkybox && _light.isDefault) continue; + found = true; break; } @@ -594,6 +604,9 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } m_skyConeAlpha = 1.0; + + + for (auto &_light : lightResults) { if (_light.skyBoxFdid == 0 || _light.lightSkyboxId == 0) continue; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 486d7954d..ba2f22642 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1093,10 +1093,15 @@ bool WmoObject::getGroupWmoThatCameraIsInside (mathfu::vec4 cameraVec4, WmoGroup return result; } +std::string WmoObject::getModelFileName() { + return m_modelName; +} void WmoObject::setModelFileName(std::string modelName) { m_modelName = modelName; } - +int WmoObject::getModelFileId() { + return m_modelFileId; +} void WmoObject::setModelFileId(int fileId) { useFileId = true; m_modelFileId = fileId; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 3cb96235b..a75b5a34f 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -98,7 +98,9 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { void setLoadingParam( SMMapObjDef &mapObjDef); void setLoadingParam( SMMapObjDefObj1 &mapObjDef); + std::string getModelFileName(); void setModelFileName(std::string modelName); + int getModelFileId(); void setModelFileId(int fileId); void startLoading(); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 780d81036..29eea141b 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -396,6 +396,11 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -502,6 +507,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { @@ -704,6 +712,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -889,6 +902,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -927,6 +942,7 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, @@ -967,10 +983,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -988,11 +1005,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1027,10 +1050,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,6 +1176,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1174,10 +1207,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1345,10 +1379,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1566,6 +1602,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -1660,6 +1697,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1699,14 +1738,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1743,6 +1784,7 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,6,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1891,6 +1933,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -2136,12 +2179,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2211,8 +2259,11 @@ const std::unordered_map shaderMetaInfo = { const std::unordered_map>> fieldDefMapPerShaderNameVert = { {"waterfallShader", { { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + 9, { + } + }, + { + 8, { } }, { @@ -2224,6 +2275,16 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"waterfallShader", { + { + 9, { + } + }, + { + 8, { + } + }, + { + 7, { + } + }, + { + 6, { + {"_1_6_textureMatrix", true, 0, 4, 4, 0}, + } + }, + { + 5, { + {"_1_5_textureWeight", true, 0, 1, 4, 0}, + } + }, + { + 4, { + {"_1_4_colors", true, 0, 1, 4, 0}, + } + }, + { + 3, { + {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, { 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, } }, { @@ -2664,10 +2764,6 @@ const std::unordered_mapcreateObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } @@ -834,18 +834,18 @@ HGM2Mesh MapSceneRenderForwardVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); return mesh; } HGM2Mesh MapSceneRenderForwardVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); return mesh; } HGSortableMesh MapSceneRenderForwardVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } HGMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index 9d2de2d98..ed3a42d62 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -1388,7 +1388,7 @@ HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const } HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } @@ -1397,7 +1397,7 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTe meshTemplate.bindings = m_emptyWaterVAO; auto _material = std::dynamic_pointer_cast(material); - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, 0); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); mesh->instanceIndex = _material->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); @@ -1426,7 +1426,7 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyM2VAO; - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1463,7 +1463,7 @@ HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, co HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), priorityPlane, layer); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } From c6dc76c197e20ff3e3dbe05f2f5fee7f352ece6b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 12 Feb 2024 19:52:34 +0200 Subject: [PATCH 171/212] - wmo area stuff --- src/database/CEmptySqliteDB.h | 2 +- src/database/CSqliteDB.cpp | 17 ++++++++--------- src/database/CSqliteDB.h | 2 +- src/ui/FrontendUI.cpp | 2 +- wowViewerLib/src/engine/objects/scenes/map.cpp | 17 ++++++++++++----- wowViewerLib/src/include/databaseHandler.h | 2 +- .../src/renderer/mapScene/MapScenePlan.h | 1 + 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/database/CEmptySqliteDB.h b/src/database/CEmptySqliteDB.h index 71b2f127d..df3c341d0 100644 --- a/src/database/CEmptySqliteDB.h +++ b/src/database/CEmptySqliteDB.h @@ -13,7 +13,7 @@ class CEmptySqliteDB : public IClientDatabase { void getMapArray(std::vector &mapRecords) override {}; bool getMapById(int mapId, MapRecord &mapRecord) override {return false;}; AreaRecord getArea(int areaId) override { return {}; }; - AreaRecord getWmoArea(int wmoId, int nameId, int groupId) override { return {}; }; + bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) override {return false;}; void getLightById(int lightId, int time, LightResult &lightResult, float zFar) override {}; void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float zFar) override {}; void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 453512b60..57b73bd33 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -227,8 +227,7 @@ AreaRecord CSqliteDB::getArea(int areaId) { return areaRecord; } -AreaRecord CSqliteDB::getWmoArea(int wmoId, int nameId, int groupId) { - AreaRecord areaRecord; +bool CSqliteDB::getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) { getWmoAreaAreaName.setInputs( wmoId, nameId, groupId); @@ -238,18 +237,18 @@ AreaRecord CSqliteDB::getWmoArea(int wmoId, int nameId, int groupId) { if (wmoAreaName == "") { - areaRecord.areaName = areaName; + result.areaName = areaName; } else { - areaRecord.areaName = wmoAreaName; + result.areaName = wmoAreaName; } - areaRecord.areaId = getWmoAreaAreaName.getField("ID").getInt(); - areaRecord.parentAreaId = getWmoAreaAreaName.getField("ParentAreaID").getInt(); - areaRecord.ambientMultiplier= getWmoAreaAreaName.getField("Ambient_multiplier").getDouble(); + result.areaId = getWmoAreaAreaName.getField("ID").getInt(); + result.parentAreaId = getWmoAreaAreaName.getField("ParentAreaID").getInt(); + result.ambientMultiplier= getWmoAreaAreaName.getField("Ambient_multiplier").getDouble(); - break; + return true; } - return areaRecord; + return false; } template diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index 79ab3be8a..b3c2892ad 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -19,7 +19,7 @@ class CSqliteDB : public IClientDatabase { void getMapArray(std::vector &mapRecords) override; bool getMapById(int mapId, MapRecord &mapRecord) override; AreaRecord getArea(int areaId) override; - AreaRecord getWmoArea(int wmoId, int nameId, int groupId) override; + bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) override; void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) override; void getLightById(int lightId, int time, LightResult &lightResult, float farClip) override; diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 746a454c3..a4a6332fc 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -227,7 +227,6 @@ void FrontendUI::showCurrentStatsDialog() { if (ImGui::CollapsingHeader("General statistics")) { ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); -// if(getCurrentAreaName) { ImGui::Text("Uniform data for GPU: %.3f MB", m_api->hDevice->getUploadSize() / (1024.0f * 1024.0f)); @@ -253,6 +252,7 @@ void FrontendUI::showCurrentStatsDialog() { ImGui::Text("Current area id: %d", mapPlan->areaId); ImGui::Text("Current parent area id: %d", mapPlan->parentAreaId); ImGui::Text("Current adt area id: %d", mapPlan->adtAreadId); + ImGui::Text("Current wmo area name: %s", mapPlan->wmoAreaName.c_str()); ImGui::Text("Current area name: %s", mapPlan->areaName.c_str()); ImGui::Separator(); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 03abe9c70..13a90878f 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -404,24 +404,31 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams //7. Get AreaId and Area Name StateForConditions stateForConditions; - AreaRecord areaRecord; + AreaRecord wmoAreaRecord; + bool wmoAreaFound = false; if (mapRenderPlan->m_currentWMO != nullptr) { auto nameId = mapRenderPlan->m_currentWMO->getNameSet(); auto wmoId = mapRenderPlan->m_currentWMO->getWmoId(); auto groupId = mapRenderPlan->m_currentWMO->getWmoGroupId(mapRenderPlan->m_currentWmoGroup); if (m_api->databaseHandler != nullptr) { - areaRecord = m_api->databaseHandler->getWmoArea(wmoId, nameId, groupId); + wmoAreaFound = m_api->databaseHandler->getWmoArea(wmoId, nameId, groupId, wmoAreaRecord); } } - if (areaRecord.areaId == 0) { - if (mapRenderPlan->adtAreadId > 0 && (m_api->databaseHandler != nullptr)) { - areaRecord = m_api->databaseHandler->getArea(mapRenderPlan->adtAreadId); + AreaRecord areaRecord; + if ((m_api->databaseHandler != nullptr)) { + if (wmoAreaRecord.areaId == 0) { + if (mapRenderPlan->adtAreadId > 0) { + areaRecord = m_api->databaseHandler->getArea(mapRenderPlan->adtAreadId); + } + } else { + areaRecord = m_api->databaseHandler->getArea(wmoAreaRecord.areaId); } } + mapRenderPlan->wmoAreaName = wmoAreaRecord.areaName; mapRenderPlan->areaName = areaRecord.areaName; stateForConditions.currentAreaId = areaRecord.areaId; stateForConditions.currentParentAreaId = areaRecord.parentAreaId; diff --git a/wowViewerLib/src/include/databaseHandler.h b/wowViewerLib/src/include/databaseHandler.h index 2089e14c5..802a76a0d 100644 --- a/wowViewerLib/src/include/databaseHandler.h +++ b/wowViewerLib/src/include/databaseHandler.h @@ -14,7 +14,7 @@ class IClientDatabase { virtual void getMapArray(std::vector &mapRecords) = 0; virtual bool getMapById(int mapId, MapRecord &mapRecord) = 0; virtual AreaRecord getArea(int areaId) = 0; - virtual AreaRecord getWmoArea(int wmoId, int nameId, int groupId) = 0; + virtual bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) = 0; virtual void getLightById(int lightId, int time, LightResult &lightResult, float farClip) = 0; virtual void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) = 0; virtual void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index fc5c10fe0..004c28676 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -16,6 +16,7 @@ struct MapRenderPlan { int parentAreaId = -1; std::string areaName = ""; + std::string wmoAreaName = ""; animTime_t deltaTime; HCameraMatrices renderingMatrices; From fe6f6650c706b88c6dbf2950f5a58328b7eb8cc5 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 15 Feb 2024 19:54:34 +0200 Subject: [PATCH 172/212] - first steps on road to GBuffer --- wowViewerLib/CMakeLists.txt | 2 + .../glsl/common/commonADTMaterial.glsl | 4 +- .../shaders/glsl/visBuffer/adtShader.frag | 7 + .../glsl/visBuffer/m2ParticleShader.frag | 5 + .../glsl/visBuffer/m2ParticleShader.vert | 43 +++ .../visBuffer/m2ParticleShader_nonopaq.frag | 7 + .../glsl/visBuffer/m2ParticleShader_text.glsl | 105 ++++++ .../shaders/glsl/visBuffer/m2Shader.frag | 187 +---------- .../glsl/visBuffer/m2Shader_nonopaq.frag | 7 + .../shaders/glsl/visBuffer/m2shader_text.glsl | 199 ++++++++++++ .../shaders/glsl/visBuffer/ribbonShader.frag | 14 +- .../shaders/glsl/visBuffer/waterShader.frag | 4 +- .../glsl/visBuffer/waterfallShader.frag | 15 +- .../shaders/glsl/visBuffer/wmoShader.frag | 10 +- .../src/engine/managers/animationManager.cpp | 8 +- .../src/engine/managers/animationManager.h | 20 +- .../src/engine/objects/m2/m2Object.cpp | 12 + .../src/engine/shader/ShaderDefinitions.h | 301 +++++++++++++++++- .../src/gapi/interface/textures/ITexture.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 23 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 6 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 65 +++- .../src/gapi/vulkan/GFrameBufferVLK.h | 10 +- .../src/gapi/vulkan/GRenderPassVLK.cpp | 42 ++- wowViewerLib/src/gapi/vulkan/GRenderPassVLK.h | 23 +- .../CommandBufferRecorder.cpp | 4 +- .../CommandBufferRecorder.h | 2 +- .../RenderPassHelper.cpp | 4 +- .../commandBufferRecorder/RenderPassHelper.h | 2 +- .../src/gapi/vulkan/pipeline/GPipelineVLK.cpp | 45 ++- .../vulkan/MapSceneRenderForwardVLK.cpp | 2 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 79 +++-- .../vulkan/MapSceneRenderVisBufferVLK.h | 18 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 8 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 222 +++++++++++++ .../vulkan/view/RenderViewDeferredVLK.h | 54 ++++ .../vulkan/view/RenderViewForwardVLK.cpp | 5 +- 37 files changed, 1251 insertions(+), 314 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag create mode 100644 wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index f72382afd..c344ef588 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -585,6 +585,8 @@ if (LINK_VULKAN) src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h + src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp + src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.cpp src/gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h ) diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl index d0170d1f2..2d603c7d8 100644 --- a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -72,7 +72,9 @@ float fmod1(float x, float y) { return x - (y * trunc(x/y)); } -vec2 transformADTUV(in vec2 uv, in int layer, in float sceneTime, in ivec4 animation_rotationPerLayer, in ivec4 animation_speedPerLayer, in vec4 scaleFactorPerLayer) { +vec2 transformADTUV(in vec2 uv, in int layer, in float sceneTime, in ivec4 animation_rotationPerLayer, + in ivec4 animation_speedPerLayer, in vec4 scaleFactorPerLayer) +{ vec2 translate = vec2(0.0); int animation_rotation = animation_rotationPerLayer[layer]; if (animation_rotation >= 0 && animation_rotation < 8) { diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag index e6bac2524..5fc897555 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag @@ -27,6 +27,9 @@ layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; #include "../common/commonUboSceneData.glsl" layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; const InteriorLightParam intLight = { vec4(0,0,0,0), @@ -119,5 +122,9 @@ void main() { vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); finalColor.a = 1.0; + outColor = finalColor; + outNormal = vec4(normalize(vNormal), 0); + outViewPos = vec4(vPosition, 0); + outMatProps = 0; } diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag new file mode 100644 index 000000000..a76d9d621 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag @@ -0,0 +1,5 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#include "m2ParticleShader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert new file mode 100644 index 000000000..9b7b1155a --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert @@ -0,0 +1,43 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require + + +precision highp float; +precision highp int; + +layout(location = 0) in vec3 aPosition; +layout(location = 1) in vec4 aColor; +layout(location = 2) in vec2 aTexcoord0; +layout(location = 3) in vec2 aTexcoord1; +layout(location = 4) in vec2 aTexcoord2; +layout(location = 5) in float aAlphaCutoff; + + +layout(location = 0) out vec3 vPosition; +layout(location = 1) out vec4 vColor; +layout(location = 2) out vec2 vTexcoord0; +layout(location = 3) out vec2 vTexcoord1; +layout(location = 4) out vec2 vTexcoord2; +layout(location = 5) out float vAlphaCutoff; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" + +#include "../common/commonUboSceneData.glsl" + + +void main() { + vec4 aPositionVec4 = vec4(aPosition, 1); + + vColor = aColor; + vTexcoord0 = aTexcoord0; + vTexcoord1 = aTexcoord1; + vTexcoord2 = aTexcoord2; + + vec4 vertexViewSpace = (scene.uLookAtMat * aPositionVec4); + + vPosition = vertexViewSpace.xyz; + vAlphaCutoff = aAlphaCutoff; + + gl_Position = scene.uPMatrix * vertexViewSpace; +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag new file mode 100644 index 000000000..6eb3b82a6 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define NON_OPAQ_SHADER + +#include "m2ParticleShader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl new file mode 100644 index 000000000..daef08bc6 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl @@ -0,0 +1,105 @@ + +precision highp float; +precision highp int; + +layout(location = 0) in vec3 vPosition; +layout(location = 1) in vec4 vColor; +layout(location = 2) in vec2 vTexcoord0; +layout(location = 3) in vec2 vTexcoord1; +layout(location = 4) in vec2 vTexcoord2; +layout(location = 5) in float alphaCutoff; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonUboSceneData.glsl" + + + +//Individual meshes +layout(std140, set=1, binding=0) uniform meshWideBlockPS { + vec4 uAlphaTest_alphaMult_colorMult; + ivec4 uPixelShaderBlendModev; +}; + +layout(set=2,binding=0) uniform sampler2D uTexture; +layout(set=2,binding=1) uniform sampler2D uTexture2; +layout(set=2,binding=2) uniform sampler2D uTexture3; + +layout(location = 0) out vec4 outputColor; + +void main() { + vec4 tex = texture(uTexture, vTexcoord0).rgba; + vec4 tex2 = texture(uTexture2, vTexcoord1).rgba; + vec4 tex3 = texture(uTexture3, vTexcoord2).rgba; + + float uAlphaTest = uAlphaTest_alphaMult_colorMult.x; + float alphaMult = uAlphaTest_alphaMult_colorMult.y; + float colorMult = uAlphaTest_alphaMult_colorMult.z; + + if(tex.a < uAlphaTest) + discard; + + vec4 finalColor = vec4((tex * vColor ).rgb, tex.a*vColor.a ); + int uNonOptPixelShader = uPixelShaderBlendModev.x; + if (uNonOptPixelShader == 0) { //particle_mod + vec3 matDiffuse = vColor.xyz * tex.rgb; + + finalColor = vec4(matDiffuse.rgb, tex.a*vColor.a); + } else if (uNonOptPixelShader == 1) {//particle_2colortex_3alphatex + vec4 textureMod = tex*tex2; + float texAlpha = (textureMod.w * tex3.w); + float opacity = texAlpha*vColor.a; + + + vec3 matDiffuse = vColor.xyz * textureMod.rgb; + finalColor = vec4(matDiffuse.rgb, opacity); + } else if (uNonOptPixelShader == 2) { //particle_3colortex_3alphatex + vec4 textureMod = tex*tex2*tex3; + float texAlpha = (textureMod.w); + float opacity = texAlpha*vColor.a; + + + vec3 matDiffuse = vColor.xyz * textureMod.rgb; + finalColor = vec4(matDiffuse.rgb, opacity); + } else if (uNonOptPixelShader == 3) { //Particle_3ColorTex_3AlphaTex_UV + //TODO: incorrect implementation, because the original shader is too complicated + vec4 textureMod = tex*tex2*tex3; + float texAlpha = (textureMod.w); + float opacity = texAlpha*vColor.a; + + vec3 matDiffuse = vColor.xyz * textureMod.rgb; + finalColor = vec4(matDiffuse.rgb, opacity); + } else if (uNonOptPixelShader == 4) { //Refraction + discard; + float t0_973 = tex.x; + float t1_978 = tex2.y; + float t2_983 = tex3.z; + float textureMod_986 = (((t0_973 * t1_978) * t2_983) * 4.0); + float depthScale_991 = (1.0 - clamp((vPosition.z * 0.00999999978), 0, 1)); + float textureMod_992 = (textureMod_986 * depthScale_991); + float height_995 = (textureMod_992 * vColor.x); + float alpha_997 = (textureMod_992 * vColor.w); + finalColor = vec4(height_995, 0.0, 0.0, alpha_997); + } + + finalColor = vec4(finalColor.rgb * colorMult, finalColor.a * alphaMult); + + if(finalColor.a < uAlphaTest) + discard; + + if(finalColor.a < alphaCutoff) + discard; + + // vec3 sunDir = + // mix( + // scene.uInteriorSunDir, + // scene.extLight.uExteriorDirectColorDir, + // interiorExteriorBlend.x + // ) + // .xyz; + vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); + + outputColor.rgba = finalColor ; +} diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag index 9d4f9e5e7..88a4e81fd 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag @@ -3,189 +3,4 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier : require -precision highp float; -precision highp int; - -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonM2Material.glsl" - -layout(location=0) in vec2 vTexCoord; -layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec3 vNormal; -layout(location=3) in vec4 vPosition_EdgeFade; -layout(location=4) in flat int vMeshIndex; - -layout(location=0) out vec4 outputColor; - -#include "../common/commonUboSceneData.glsl" - -//Whole model -#include "../common/commonM2IndirectDescriptorSet.glsl" - -layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; - -void main() { - /* Animation support */ - vec2 texCoord = vTexCoord.xy; - vec2 texCoord2 = vTexCoord2.xy; - vec2 texCoord3 = vTexCoord2.xy; - - vec4 finalColor = vec4(0); - - meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[vMeshIndex]; - meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; - - int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; - M2InstanceRecordBindless m2Instance = instances[nonuniformEXT(instanceIndex)]; - - modelWideBlockPSStruct modelWide = modelWides[m2Instance.textureMatricesInd_modelFragmentDatasInd.y]; - - - int placementMatrixInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; - int textureWeightsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.w; - int m2ColorsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.z; - int textureMatricesInd = m2Instance.textureMatricesInd_modelFragmentDatasInd.x; - - vec3 uTexSampleAlpha = vec3( - meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], - meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], - meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] - ); - - vec4 vMeshColorAlpha = vec4( - meshWide.colorIndex_applyWeight.x < 0 ? - vec4(1.0,1.0,1.0,1.0) : - colors[m2ColorsInd + meshWide.colorIndex_applyWeight.x] - ); - if (meshWide.colorIndex_applyWeight.y > 0) - vMeshColorAlpha.a *= - meshWide.textureWeightIndexes.x < 0 ? - 1.0 : - textureWeight[textureWeightsInd + meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; - - vec3 l_Normal = vNormal; - - //Accumulate and apply lighting - - vec3 meshResColor = vMeshColorAlpha.rgb; - - vec3 accumLight = vec3(0.0); - - if ((meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { - mat4 placementMat = uPlacementMats[placementMatrixInd]; - - vec3 vPos3 = vPosition_EdgeFade.xyz; - vec3 vNormal3 = normalize(l_Normal.xyz); - vec3 lightColor = vec3(0.0); - int count = int(modelWide.pc_lights[0].attenuation.w); - - for (int index = 0; index < 4; index++) - { - if (index >= modelWide.lightCountAndBcHack.x) break; - - LocalLight lightRecord = modelWide.pc_lights[index]; - vec3 vectorToLight = ((scene.uLookAtMat * (placementMat * lightRecord.position)).xyz - vPos3); - float distanceToLightSqr = dot(vectorToLight, vectorToLight); - float distanceToLightInv = inversesqrt(distanceToLightSqr); - float distanceToLight = (distanceToLightSqr * distanceToLightInv); - float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); - vec4 attenuationRec = lightRecord.attenuation; - - float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); - - vec3 attenuatedColor = attenuation * lightRecord.color.xyz; - lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); - } - - meshResColor.rgb = clamp(lightColor , 0.0, 1.0); - accumLight = mix(lightColor.rgb, meshResColor.rgb, modelWide.lightCountAndBcHack.y); - //finalColor.rgb = finalColor.rgb * lightColor; - } - -//---------------------- -// Calc Diffuse and Specular -//--------------------- - int uVertexShader = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; - - mat4 textMat[2]; - int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; - int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; - - textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex1]; - textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex2]; - float edgeFade = 1.0; - - calcM2VertexMat(uVertexShader, - vPosition_EdgeFade.xyz, l_Normal, - vTexCoord, vTexCoord2, - textMat, edgeFade, - texCoord, texCoord2, texCoord3); - - vMeshColorAlpha *= edgeFade; - - float finalOpacity = 0.0; - vec3 matDiffuse; - vec3 specular; - - int uPixelShader = meshWide.PixelShader_UnFogged_blendMode.x; - int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; - - bool doDiscard = false; - - - calcM2FragMaterial(uPixelShader, - s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.x)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.y)], - s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.z)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.w)], - texCoord, texCoord2, texCoord3, - vMeshColorAlpha.rgb, vMeshColorAlpha.a, - uTexSampleAlpha.rgb, - blendMode, - matDiffuse, specular, finalOpacity, doDiscard - ); - - if (doDiscard) - discard; - -// ------------------------------ -// Apply lighting -// ------------------------------ - -// specular *= vMeshColorAlpha.rgb; - - finalColor = vec4( - calcLight( - matDiffuse, - l_Normal, - meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, - modelWide.interiorExteriorBlend.x, - scene, - modelWide.intLight, - accumLight, - vec3(0.0), - specular, - vec3(0.0) - ) , - finalOpacity - ); - -// ------------------------------ -// Apply Fog -// ------------------------------ - - int uUnFogged = meshWide.PixelShader_UnFogged_blendMode.y; - if (uUnFogged == 0) { - vec3 sunDir = - mix( - scene.uInteriorSunDir, - scene.extLight.uExteriorDirectColorDir, - modelWide.interiorExteriorBlend.x - ) - .xyz; - - finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, meshWide.PixelShader_UnFogged_blendMode.z); - } - - //Forward rendering without lights - outputColor = finalColor; -} +#include "m2shader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag b/wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag new file mode 100644 index 000000000..d62526f5b --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define NON_OPAQ_SHADER + +#include "m2shader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl b/wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl new file mode 100644 index 000000000..aa8489061 --- /dev/null +++ b/wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl @@ -0,0 +1,199 @@ +precision highp float; +precision highp int; + +#include "../common/commonLightFunctions.glsl" +#include "../common/commonFogFunctions.glsl" +#include "../common/commonM2Material.glsl" + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec3 vNormal; +layout(location=3) in vec4 vPosition_EdgeFade; +layout(location=4) in flat int vMeshIndex; + +layout(location = 0) out vec4 outColor; +#ifndef NON_OPAQ_SHADER +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; +#endif + + +#include "../common/commonUboSceneData.glsl" + +//Whole model +#include "../common/commonM2IndirectDescriptorSet.glsl" + +layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; + +void main() { + /* Animation support */ + vec2 texCoord = vTexCoord.xy; + vec2 texCoord2 = vTexCoord2.xy; + vec2 texCoord3 = vTexCoord2.xy; + + vec4 finalColor = vec4(0); + + meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[vMeshIndex]; + meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; + + int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; + M2InstanceRecordBindless m2Instance = instances[nonuniformEXT(instanceIndex)]; + + modelWideBlockPSStruct modelWide = modelWides[m2Instance.textureMatricesInd_modelFragmentDatasInd.y]; + + + int placementMatrixInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + int textureWeightsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.w; + int m2ColorsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.z; + int textureMatricesInd = m2Instance.textureMatricesInd_modelFragmentDatasInd.x; + + vec3 uTexSampleAlpha = vec3( + meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], + meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], + meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] + ); + + vec4 vMeshColorAlpha = vec4( + meshWide.colorIndex_applyWeight.x < 0 ? + vec4(1.0,1.0,1.0,1.0) : + colors[m2ColorsInd + meshWide.colorIndex_applyWeight.x] + ); + if (meshWide.colorIndex_applyWeight.y > 0) + vMeshColorAlpha.a *= + meshWide.textureWeightIndexes.x < 0 ? + 1.0 : + textureWeight[textureWeightsInd + meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; + + vec3 l_Normal = vNormal; + + //Accumulate and apply lighting + + vec3 meshResColor = vMeshColorAlpha.rgb; + + vec3 accumLight = vec3(0.0); + + if ((meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { + mat4 placementMat = uPlacementMats[placementMatrixInd]; + + vec3 vPos3 = vPosition_EdgeFade.xyz; + vec3 vNormal3 = normalize(l_Normal.xyz); + vec3 lightColor = vec3(0.0); + int count = int(modelWide.pc_lights[0].attenuation.w); + + for (int index = 0; index < 4; index++) + { + if (index >= modelWide.lightCountAndBcHack.x) break; + + LocalLight lightRecord = modelWide.pc_lights[index]; + vec3 vectorToLight = ((scene.uLookAtMat * (placementMat * lightRecord.position)).xyz - vPos3); + float distanceToLightSqr = dot(vectorToLight, vectorToLight); + float distanceToLightInv = inversesqrt(distanceToLightSqr); + float distanceToLight = (distanceToLightSqr * distanceToLightInv); + float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); + vec4 attenuationRec = lightRecord.attenuation; + + float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); + + vec3 attenuatedColor = attenuation * lightRecord.color.xyz; + lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); + } + + meshResColor.rgb = clamp(lightColor , 0.0, 1.0); + accumLight = mix(lightColor.rgb, meshResColor.rgb, modelWide.lightCountAndBcHack.y); + //finalColor.rgb = finalColor.rgb * lightColor; + } + + //---------------------- + // Calc Diffuse and Specular + //--------------------- + int uVertexShader = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; + + mat4 textMat[2]; + int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; + int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; + + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex2]; + float edgeFade = 1.0; + + calcM2VertexMat(uVertexShader, + vPosition_EdgeFade.xyz, l_Normal, + vTexCoord, vTexCoord2, + textMat, edgeFade, + texCoord, texCoord2, texCoord3); + + vMeshColorAlpha *= edgeFade; + + float finalOpacity = 0.0; + vec3 matDiffuse; + vec3 specular; + + int uPixelShader = meshWide.PixelShader_UnFogged_blendMode.x; + int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; + + bool doDiscard = false; + + + calcM2FragMaterial(uPixelShader, + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.x)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.y)], + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.z)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.w)], + texCoord, texCoord2, texCoord3, + vMeshColorAlpha.rgb, vMeshColorAlpha.a, + uTexSampleAlpha.rgb, + blendMode, + matDiffuse, specular, finalOpacity, doDiscard + ); + + if (doDiscard) + discard; + + // ------------------------------ + // Apply lighting + // ------------------------------ + + // specular *= vMeshColorAlpha.rgb; + + finalColor = vec4( + calcLight( + matDiffuse, + l_Normal, + meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, + modelWide.interiorExteriorBlend.x, + scene, + modelWide.intLight, + accumLight, + vec3(0.0), + specular, + vec3(0.0) + ) , + finalOpacity + ); + + // ------------------------------ + // Apply Fog + // ------------------------------ + + int uUnFogged = meshWide.PixelShader_UnFogged_blendMode.y; + if (uUnFogged == 0) { + vec3 sunDir = + mix( + scene.uInteriorSunDir, + scene.extLight.uExteriorDirectColorDir, + modelWide.interiorExteriorBlend.x + ).xyz; + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, + finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, + meshWide.PixelShader_UnFogged_blendMode.z + ); + } + + //Forward rendering without lights + outColor = finalColor; + #ifndef NON_OPAQ_SHADER + outNormal = vec4(normalize(vNormal), 0); + outViewPos = vec4(vPosition_EdgeFade.xyz, 0); + outMatProps = 0; + #endif +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag index 969df2c16..136f28176 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag @@ -25,7 +25,12 @@ layout(std140, set=1, binding=1) uniform meshWideBlockPS { layout(set=2, binding=0) uniform sampler2D uTexture; -layout(location = 0) out vec4 outputColor; +layout(location = 0) out vec4 outColor; +#ifndef NON_OPAQ_SHADER +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; +#endif void main() { int textureTransformIndex = uPixelShader_BlendMode_TextureTransformIndex.z; @@ -46,5 +51,10 @@ void main() { finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); - outputColor = finalColor; + outColor = finalColor; +#ifndef NON_OPAQ_SHADER + outNormal = vec4(0,0,0,0); + outViewPos = vec4(vPosition, 0); + outMatProps = 0; +#endif } diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag index 97367213e..06b507555 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag @@ -17,7 +17,7 @@ layout(location=3) in flat int meshInd; #include "../common/commonUboSceneData.glsl" #include "../common/commonWaterIndirect.glsl" -layout(location=0) out vec4 outputColor; +layout(location = 0) out vec4 outColor; const InteriorLightParam intLight = { vec4(0,0,0,0), @@ -137,5 +137,5 @@ void main() { //BlendMode is always GxBlend_Alpha finalColor.rgb = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 2).rgb; - outputColor = vec4(finalColor.rgb, 0.7); + outColor = vec4(finalColor.rgb, 0.7); } diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag index 3c76c2ead..ac7f6d040 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag @@ -18,7 +18,13 @@ layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; layout(location=5) flat in int meshInd; -layout(location=0) out vec4 outputColor; +layout(location = 0) out vec4 outColor; +#ifndef NON_OPAQ_SHADER +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; +#endif + @@ -114,5 +120,10 @@ void main() { finalColor = makeFog2(fogData,/*int(scene.extLight.adtSpecMult_fogCount.y),*/ finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); - outputColor = finalColor; + outColor = finalColor; +#ifndef NON_OPAQ_SHADER + outNormal = vec4(normalize(vNormal), 0); + outViewPos = vec4(vPosition, 0); + outMatProps = 0; +#endif } diff --git a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag index 22ca68c6b..344dcba79 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag @@ -32,7 +32,10 @@ layout(location=9) in flat int vMeshIndex; layout(set=2, binding=0) uniform sampler2D s_Textures[]; -layout (location = 0) out vec4 outputColor; +layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; void main() { WMOPerMeshData perMeshData = perMeshDatas[nonuniformEXT(vMeshIndex)]; @@ -96,5 +99,8 @@ void main() { vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); finalColor.a = 1.0; - outputColor = finalColor; + outColor = finalColor; + outNormal = vec4(normalize(vNormal), 0.0); + outViewPos = vec4(vPosition.xyz, 0.0); + outMatProps = 0; } diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index a93b8d30d..a322e4f08 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -9,7 +9,7 @@ #include "../persistance/header/M2FileHeader.h" #include "mathfu/glsl_mappings.h" -AnimationManager::AnimationManager(HApiContainer api, std::shared_ptr boneMasterData, bool hasExp2) { +AnimationManager::AnimationManager(const HApiContainer &api, const std::shared_ptr &boneMasterData, bool hasExp2) { this->m_api = api; this->boneMasterData = boneMasterData; @@ -39,6 +39,8 @@ AnimationManager::AnimationManager(HApiContainer api, std::shared_ptrsetAnimationId(0, false)) { // try Stand(0) animation this->setAnimationId(147, false); // otherwise try Closed(147) animation } + + this->m_needToUpdateBB = true; } void AnimationManager::initBonesIsCalc() { @@ -158,6 +160,7 @@ bool AnimationManager::setAnimationId(int animationId, bool reset) { this->animationInfo.nextSubAnimation.mainVariationRecord = nullptr; this->firstCalc = true; + this->m_needToUpdateBB = true; deferredLoadingStarted = false; } @@ -737,7 +740,6 @@ void AnimationManager::update( std::vector> &particleEmitters, std::vector> &ribbonEmitters) { - auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; auto &bones = *boneMasterData->getSkelData()->m_m2CompBones; @@ -863,7 +865,7 @@ void AnimationManager::update( this->animationInfo.currentAnimation = this->animationInfo.nextSubAnimation; //Update bounding box - + this->m_needToUpdateBB = true; this->firstCalc = true; diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index 63b7050db..4185168d5 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -23,6 +23,8 @@ class AnimationManager { bool firstCalc = true; bool deferredLoadingStarted = false; + bool m_needToUpdateBB = false; + bool isMirrored = false; bool m_hasExp2 = false; @@ -43,11 +45,8 @@ class AnimationManager { void calcAnimMatrixes (std::vector &textAnimMatrices); void calcAnimRepetition(AnimationStruct &animationStruct); - - - public: - AnimationManager(HApiContainer api, std::shared_ptr boneMasterData, bool hasExp2); + AnimationManager(const HApiContainer &api, const std::shared_ptr &boneMasterData, bool hasExp2); void resetCurrentAnimation(); bool setAnimationId(int animationId, bool reset); @@ -80,8 +79,17 @@ class AnimationManager { void calcTransparencies(std::vector &transparencies); - bool getIsFirstCalc() { - return firstCalc; + bool isNeedUpdateBB() { + return m_needToUpdateBB; + } + + M2Bounds getAnimatinonBB() { + m_needToUpdateBB = false; + + if (this->animationInfo.currentAnimation.animationRecord != nullptr) + return this->animationInfo.currentAnimation.animationRecord->bounds; + + return {}; } void calcLights(std::vector &lights, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index f8352ea4a..198c08960 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -980,6 +980,18 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v this->ribbonEmitters ); + if (m_animationManager->isNeedUpdateBB()) { + auto bounds = m_animationManager->getAnimatinonBB(); + + CAaBox worldAABB = MathHelper::transformAABBWithMat4(m_placementMatrix, + mathfu::vec4(mathfu::vec3(bounds.extent.min), 1.0f), + mathfu::vec4(mathfu::vec3(bounds.extent.max), 1.0f)); + + this->aabb = worldAABB; + + } + + int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 29eea141b..72b43497a 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -298,7 +298,46 @@ const std::unordered_map> attributesPe }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/ribbonShader.vert.spv", +{ "visBuffer/ribbonShader.frag.spv", + { + ShaderStage::Fragment, + { + {1,1,16}, + {0,0,544}, + }, + { + { + {0,0,1}, + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,0,4096}, + }, + { + {2,0, "uTexture"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "visBuffer/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -317,6 +356,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -334,17 +382,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.frag.spv", +{ "visBuffer/m2ParticleShader_nonopaq.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, + {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -354,26 +402,63 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, }, { {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, + {0,2,3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "visBuffer/ribbonShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + }, + { + { {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "visBuffer/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -392,15 +477,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -843,6 +919,46 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/m2ParticleShader.frag.spv", + { + ShaderStage::Fragment, + { + {1,0,32}, + {0,0,544}, + }, + { + { + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,2,3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, @@ -1082,6 +1198,52 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "visBuffer/m2Shader_nonopaq.frag.spv", + { + ShaderStage::Fragment, + { + {0,0,544}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, + }, + { + {2,0, "s_Textures"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, @@ -2709,6 +2871,40 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"m2ParticleShader_nonopaq", { + { + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, + {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, + {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, + {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, + {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, + {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, + {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, + {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, + {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, + {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, + {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + } + }, + }}, {"waterfallShader", { { 9, { @@ -2910,6 +3106,81 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -631,7 +631,7 @@ void GDeviceVLK::createSwapChainRenderPass(VkFormat swapChainImageFormat) { std::vector({swapChainImageFormat}), findDepthFormat(), VK_SAMPLE_COUNT_1_BIT, - false, true); + false, true, true, true); } void GDeviceVLK::createFramebuffers(std::vector &swapChainTextures, VkExtent2D &extent) { @@ -641,6 +641,7 @@ void GDeviceVLK::createFramebuffers(std::vector &swapChainTextures swapChainFramebuffers[i] = std::make_shared( *this, swapChainTextures[i], + nullptr, extent.width, extent.height, swapchainRenderPass @@ -1110,8 +1111,7 @@ RenderPassHelper GDeviceVLK::beginSwapChainRenderPass(uint32_t imageIndex, CmdBu swapChainFramebuffers[imageIndex], {0,0}, {swapChainExtent.width, swapChainExtent.height}, - {0.117647, 0.207843, 0.392157}, - 0.0f + {0.117647, 0.207843, 0.392157} ); } @@ -1385,7 +1385,9 @@ std::shared_ptr GDeviceVLK::getRenderPass( ITextureFormat depthAttachment, VkSampleCountFlagBits sampleCountFlagBits, bool invertZ, - bool isSwapChainPass + bool isSwapChainPass, + bool clearColor, + bool clearDepth ) { for (auto &renderPassAvalability : m_createdRenderPasses) { if (renderPassAvalability.attachments.size() == textureAttachments.size() && @@ -1393,7 +1395,10 @@ std::shared_ptr GDeviceVLK::getRenderPass( renderPassAvalability.sampleCountFlagBits == sampleCountFlagBits && renderPassAvalability.sampleCountFlagBits == sampleCountFlagBits && renderPassAvalability.isSwapChainPass == isSwapChainPass && - renderPassAvalability.invertZ == invertZ) + renderPassAvalability.invertZ == invertZ && + renderPassAvalability.clearColor == clearColor && + renderPassAvalability.clearDepth == clearDepth + ) { //Check frame definition bool notEqual = false; @@ -1416,7 +1421,9 @@ std::shared_ptr GDeviceVLK::getRenderPass( depthAttachment, sampleCountFlagBits, invertZ, - false + false, + clearColor, + clearDepth ); RenderPassAvalabilityStruct avalabilityStruct; @@ -1425,6 +1432,8 @@ std::shared_ptr GDeviceVLK::getRenderPass( avalabilityStruct.renderPass = renderPass; avalabilityStruct.sampleCountFlagBits = sampleCountFlagBits; avalabilityStruct.isSwapChainPass = isSwapChainPass; + avalabilityStruct.clearColor = clearColor; + avalabilityStruct.clearDepth = clearDepth; m_createdRenderPasses.push_back(avalabilityStruct); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 11ce813f7..67f272fb7 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -136,7 +136,9 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getSwapChainRenderPass(); @@ -382,6 +384,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this m_createdRenderPasses; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index 1493f0f3e..f29cdb9e3 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -21,8 +21,12 @@ void GFrameBufferVLK::iterateOverAttachments(const std::vector & textureFormat = VK_FORMAT_R8G8B8A8_UNORM; break; + case ITextureFormat::itInt: + textureFormat = VK_FORMAT_R32_UINT; + break; + case ITextureFormat::itRGBAFloat32: - textureFormat = VK_FORMAT_R16G16B16_SFLOAT; + textureFormat = VK_FORMAT_R32G32B32A32_SFLOAT; break; } @@ -46,6 +50,7 @@ inline void GFrameBufferVLK::initSamplableTextures() { //Support for swapchain framebuffer GFrameBufferVLK::GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, + const HGTexture &depthBuffer, int width, int height, const std::shared_ptr &renderPass) : mdevice(dynamic_cast(device)), @@ -54,6 +59,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, initSampler(mdevice); + if (!depthBuffer) { // Find a suitable depth format VkFormat fbDepthFormat = mdevice.findDepthFormat(); @@ -80,6 +86,8 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, // << " alignment. " // << " Size allocated by VMA " << std::dynamic_pointer_cast(m_depthTexture)->imageAllocationInfo.size // << std::endl; + } else { + m_depthTexture = depthBuffer; } std::vector attachments = { @@ -110,7 +118,9 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, bool invertZ, int width, int height) : mdevice(dynamic_cast(device)), m_height(height), m_width(width), - m_multiSampleCnt(multiSampleCnt){ + m_multiSampleCnt(multiSampleCnt), + m_textureAttachments(textureAttachments), + m_depthAttachment(depthAttachment){ initSampler(mdevice); @@ -187,7 +197,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, attachments.push_back(h_depthTexture->texture.view); } - m_renderPass = mdevice.getRenderPass(textureAttachments, depthAttachment, sampleCountToVkSampleCountFlagBits(multiSampleCnt), invertZ, false); + m_renderPass = mdevice.getRenderPass(textureAttachments, depthAttachment, sampleCountToVkSampleCountFlagBits(multiSampleCnt), invertZ, false, true, true); VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; fbufCreateInfo.pNext = nullptr; @@ -212,6 +222,55 @@ GFrameBufferVLK::~GFrameBufferVLK() { }); } +GFrameBufferVLK::GFrameBufferVLK(const GFrameBufferVLK *toCopy, + const std::vector &attachmentToCopy, + const std::shared_ptr &renderPass) : mdevice(toCopy->mdevice), m_renderPass(renderPass){ + m_multiSampleCnt = toCopy->m_multiSampleCnt; + m_height = toCopy->m_height; + m_width = toCopy->m_width; + + + + std::vector attachments; + int j = 0; + for (int i = 0; i < toCopy->m_attachmentFormats.size(); i++) { + if (attachmentToCopy[j] != i) continue; + j++; + + uint32_t attIndex = (m_multiSampleCnt > 0) ? + 2*i : i; + + m_attachmentFormats.push_back(toCopy->m_attachmentFormats[i]); + m_textureAttachments.push_back(toCopy->m_textureAttachments[i]); + + attachments.push_back(std::dynamic_pointer_cast(toCopy->m_attachmentTextures[attIndex])->texture.view); + m_attachmentTexturesSampled.push_back(toCopy->m_attachmentTexturesSampled[attIndex]); + if (m_multiSampleCnt > 0) { + attachments.push_back(std::dynamic_pointer_cast(toCopy->m_attachmentTextures[attIndex+1])->texture.view); + m_attachmentTexturesSampled.push_back(toCopy->m_attachmentTexturesSampled[attIndex + 1]); + } + } + m_depthAttachment = toCopy->m_depthAttachment; + m_depthTexture = toCopy->m_depthTexture; + if (m_depthTexture) { + attachments.push_back( + std::dynamic_pointer_cast(m_depthTexture)->texture.view); + } + + + VkFramebufferCreateInfo fbufCreateInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + fbufCreateInfo.pNext = nullptr; + fbufCreateInfo.flags = 0; + fbufCreateInfo.renderPass = m_renderPass->getRenderPass(); + fbufCreateInfo.attachmentCount = attachments.size(); + fbufCreateInfo.pAttachments = attachments.data(); + fbufCreateInfo.width = m_width; + fbufCreateInfo.height = m_height; + fbufCreateInfo.layers = 1; + + ERR_GUARD_VULKAN(vkCreateFramebuffer(mdevice.getVkDevice(), &fbufCreateInfo, nullptr, &m_frameBuffer)); +} + void GFrameBufferVLK::readRGBAPixels(int x, int y, int width, int height, void *outputdata) { if (m_attachmentFormats.empty()) { //Cant read from swapchain framebuffer diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index b071c1ff4..ad865725d 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -13,10 +13,14 @@ class GFrameBufferVLK : public IFrameBuffer { public: GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, bool invertZ, int width, int height); - GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, + GFrameBufferVLK(IDevice &device, + const HGTexture &colorImage, + const HGTexture &depthBuffer, int width, int height, const std::shared_ptr &renderPass); + GFrameBufferVLK(const GFrameBufferVLK *toCopy, const std::vector &attachmentToCopy, const std::shared_ptr &renderPass); + ~GFrameBufferVLK() override; void readRGBAPixels(int x, int y, int width, int height, void *data) override; @@ -47,6 +51,10 @@ class GFrameBufferVLK : public IFrameBuffer { //Used only in readRGBAPixels function std::vector m_attachmentFormats; + //Stored for copying + std::vector m_textureAttachments; + ITextureFormat m_depthAttachment = ITextureFormat::itNone; + int m_multiSampleCnt; int m_width = 0; diff --git a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp index 2324a80e7..6395d4db5 100644 --- a/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GRenderPassVLK.cpp @@ -13,7 +13,9 @@ GRenderPassVLK::GRenderPassVLK(IDevice &device, ITextureFormat depthAttachmentFormat, VkSampleCountFlagBits sampleCountBit, bool invertZ, - bool isSwapChainPass) : m_invertZ(invertZ) { + bool isSwapChainPass, + bool clearColor, + bool clearDepth) : m_invertZ(invertZ) { auto &deviceVlk = dynamic_cast(device); @@ -29,19 +31,26 @@ GRenderPassVLK::GRenderPassVLK(IDevice &device, sampleCountBit, isSwapChainPass, deviceVlk.getVkDevice(), attachmentFormats, - availableDepth); + availableDepth, + clearColor, + clearDepth); } GRenderPassVLK::GRenderPassVLK(VkDevice vkDevice, const std::vector &textureAttachments, VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, bool invertZ, - bool isSwapChainPass) : m_invertZ(invertZ) { + bool isSwapChainPass, + bool clearColor, + bool clearDepth) : m_invertZ(invertZ) { + createRenderPass(ITextureFormat::itDepth32, sampleCountBit, isSwapChainPass, vkDevice, textureAttachments, - depthAttachment); + depthAttachment, + clearColor, + clearDepth); } @@ -49,7 +58,9 @@ void GRenderPassVLK::createRenderPass(const ITextureFormat &depthAttachmentForma const VkSampleCountFlagBits &sampleCountBit, bool isSwapChainPass, VkDevice vkDevice, const std::vector &attachmentFormats, - const VkFormat &availableDepth) { + const VkFormat &availableDepth, + bool clearColor, + bool clearDepth) { m_sampleCountBit = sampleCountBit; @@ -60,15 +71,16 @@ void GRenderPassVLK::createRenderPass(const ITextureFormat &depthAttachmentForma std::vector colorResolveReferences; int attachmentIndex = 0; + this->colorAttachmentCount = attachmentFormats.size(); for (int i = 0; i < attachmentFormats.size(); i++) { VkAttachmentDescription colorAttachment = {}; colorAttachment.format = attachmentFormats[i]; colorAttachment.samples = sampleCountBit; - colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.loadOp = clearColor ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.initialLayout = clearColor ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; colorAttachment.finalLayout = isSwapChainPass ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; attachments.push_back(colorAttachment); @@ -116,11 +128,11 @@ void GRenderPassVLK::createRenderPass(const ITextureFormat &depthAttachmentForma VkAttachmentDescription depthAttachment = {}; depthAttachment.format = availableDepth; depthAttachment.samples = sampleCountBit; - depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.loadOp = clearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.initialLayout = clearDepth ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments.push_back(depthAttachment); @@ -188,15 +200,15 @@ void GRenderPassVLK::createRenderPass(const ITextureFormat &depthAttachmentForma } } -VkSampleCountFlagBits GRenderPassVLK::getSampleCountBit() { +VkSampleCountFlagBits GRenderPassVLK::getSampleCountBit() const { return m_sampleCountBit; } -VkRenderPass GRenderPassVLK::getRenderPass() { +VkRenderPass GRenderPassVLK::getRenderPass() const { return renderPass; } -std::vector GRenderPassVLK::produceClearColorVec(std::array colorClearColor, float depthClear) { +std::vector GRenderPassVLK::produceClearColorVec(std::array colorClearColor) { std::vector result; for(int i = 0; i < attachmentTypes.size(); i++) { VkClearValue clearValue; @@ -212,3 +224,7 @@ std::vector GRenderPassVLK::produceClearColorVec(std::array &textureAttachments, VkFormat depthAttachment, VkSampleCountFlagBits sampleCountBit, bool invertZ, - bool isSwapChainPass); + bool isSwapChainPass, + bool clearColor, + bool clearDepth); - VkSampleCountFlagBits getSampleCountBit(); - VkRenderPass getRenderPass(); + VkSampleCountFlagBits getSampleCountBit() const; + uint8_t getColorAttachmentsCount() const; + VkRenderPass getRenderPass() const; - std::vector produceClearColorVec(std::array colorClearColor, float depthClear); - bool getInvertZ() { + std::vector produceClearColorVec(std::array colorClearColor); + bool getInvertZ() const { return m_invertZ; } @@ -39,6 +44,8 @@ class GRenderPassVLK { VkSampleCountFlagBits m_sampleCountBit; VkRenderPass renderPass; + uint32_t colorAttachmentCount = 0; + bool m_invertZ = false; enum class AttachmentType { @@ -54,7 +61,9 @@ class GRenderPassVLK { const VkSampleCountFlagBits &sampleCountBit, bool isSwapChainPass, VkDevice vkDevice, const std::vector &attachmentFormats, - const VkFormat &availableDepth); + const VkFormat &availableDepth, + bool clearColor, + bool clearDepth); }; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index cc732c6a2..778236a23 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -59,7 +59,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( const std::shared_ptr &frameBuffer, const std::array &areaOffset, const std::array &areaSize, - const std::array &colorClearColor, float depthClear + const std::array &colorClearColor ) { if (m_currentRenderPass != nullptr) { throw std::runtime_error("tried to start render pass with another pass being active already"); @@ -86,7 +86,7 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( auto renderPass = RenderPassHelper( *this, isAboutToExecSecondaryCMD, - renderPassVlk, frameBuffer, areaOffset, fixedAreasSize, colorClearColor, depthClear + renderPassVlk, frameBuffer, areaOffset, fixedAreasSize, colorClearColor ); setDefaultScissors(); return renderPass; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index f830edead..a5be62217 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -48,7 +48,7 @@ class CmdBufRecorder { const std::shared_ptr &frameBuffer, const std::array &areaOffset, const std::array &areaSize, - const std::array &colorClearColor, float depthClear); + const std::array &colorClearColor); void bindMaterial(const std::shared_ptr &material); void bindVertexBindings(const std::shared_ptr &vertexBufferBindings); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp index dd1dc627f..05d8654fb 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.cpp @@ -17,10 +17,10 @@ RenderPassHelper::RenderPassHelper(CmdBufRecorder &cmdBufRecorder, const std::shared_ptr &frameBuffer, const std::array &areaOffset, const std::array &areaSize, - const std::array &colorClearColor, float depthClear + const std::array &colorClearColor ) : m_cmdBufRecorder(cmdBufRecorder) { - auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor, depthClear); + auto clearValues = renderPassVlk->produceClearColorVec(colorClearColor); VkRenderPassBeginInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h index 733d0f0d2..ff1ed11f6 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/RenderPassHelper.h @@ -16,7 +16,7 @@ class RenderPassHelper { const std::shared_ptr &frameBuffer, const std::array &areaOffset, const std::array &areaSize, - const std::array &colorClearColor, float depthClear); + const std::array &colorClearColor); ~RenderPassHelper(); private: diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp index 58a5cb111..97625dc0d 100644 --- a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp @@ -185,23 +185,44 @@ void GPipelineVLK::createPipeline( multisampling.sampleShadingEnable = VK_FALSE; multisampling.rasterizationSamples = renderPass->getSampleCountBit(); - VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = blendModesVLK[(char) m_blendMode].blendModeEnable ? VK_TRUE : VK_FALSE; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcColorBlendFactor = blendModesVLK[(char) m_blendMode].SrcColor; - colorBlendAttachment.dstColorBlendFactor = blendModesVLK[(char) m_blendMode].DestColor; - colorBlendAttachment.srcAlphaBlendFactor = blendModesVLK[(char) m_blendMode].SrcAlpha; - colorBlendAttachment.dstAlphaBlendFactor = blendModesVLK[(char) m_blendMode].DestAlpha; + std::vector colorBlendAttachments = {}; + + //Color attachment 0 + { + auto &colorBlendAttachment = colorBlendAttachments.emplace_back(); + colorBlendAttachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = blendModesVLK[(char) m_blendMode].blendModeEnable ? VK_TRUE : VK_FALSE; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcColorBlendFactor = blendModesVLK[(char) m_blendMode].SrcColor; + colorBlendAttachment.dstColorBlendFactor = blendModesVLK[(char) m_blendMode].DestColor; + colorBlendAttachment.srcAlphaBlendFactor = blendModesVLK[(char) m_blendMode].SrcAlpha; + colorBlendAttachment.dstAlphaBlendFactor = blendModesVLK[(char) m_blendMode].DestAlpha; + } + + for (size_t i = 1; i < renderPass->getColorAttachmentsCount(); i++) { + //Do not blend attachments other than in 0 + auto &colorBlendAttachment = colorBlendAttachments.emplace_back(); + colorBlendAttachment.blendEnable = VK_FALSE; + + colorBlendAttachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_FALSE; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcColorBlendFactor = blendModesVLK[(char) 0].SrcColor; + colorBlendAttachment.dstColorBlendFactor = blendModesVLK[(char) 0].DestColor; + colorBlendAttachment.srcAlphaBlendFactor = blendModesVLK[(char) 0].SrcAlpha; + colorBlendAttachment.dstAlphaBlendFactor = blendModesVLK[(char) 0].DestAlpha; + } VkPipelineColorBlendStateCreateInfo colorBlending = {}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.logicOpEnable = VK_FALSE; colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.attachmentCount = colorBlendAttachments.size(); + colorBlending.pAttachments = colorBlendAttachments.data(); colorBlending.blendConstants[0] = 0.0f; colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 4a7986315..f072a305a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -93,7 +93,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, // VK_SAMPLE_COUNT_1_BIT, sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), - true, false); + true, false, true, true); defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index ed3a42d62..cd391a0b2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -16,6 +16,7 @@ #include "../../frame/FrameProfile.h" #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" +#include "view/RenderViewDeferredVLK.h" #include static const ShaderConfig forwardShaderConfig = { @@ -193,14 +194,12 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; - m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itDepth32, -// VK_SAMPLE_COUNT_1_BIT, - sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), - true, false); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); - glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); + m_opaqueRenderPass = defaultView->getOpaqueRenderPass(); + m_nonOpaquerenderPass = defaultView->getNonOpaqueRenderPass(); - defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); { //Create SceneWide descriptor @@ -220,6 +219,14 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic createWaterGlobalMaterialData(); } +std::shared_ptr MapSceneRenderVisBufferVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { + if (pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_Opaque && pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_AlphaKey) { + return m_nonOpaquerenderPass; + } else { + return m_opaqueRenderPass; + } +} + void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -235,7 +242,7 @@ void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtVisShaderConfig) - .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyADTVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -265,7 +272,7 @@ void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { //Create global water descriptor for bindless textures g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) - .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { ds->beginUpdate() @@ -291,7 +298,7 @@ void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { //Create global wmo descriptor for bindless textures g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) - .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -320,7 +327,7 @@ void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() { //Create global m2 descriptor for bindless textures g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -364,10 +371,13 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater return i->second; } + bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || + pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; + auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isOpaq ? "m2Shader" : "m2Shader_nonopaq"}, m2VisShaderConfig) .setMaterialId(generateUniqueM2MatId()) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) .bindDescriptorSet(2, m2TextureDS) @@ -388,7 +398,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMate auto staticMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) .setMaterialId(generateUniqueWMOMatId()) - .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, wmoBufferOneDS) .bindDescriptorSet(2, wmoTexturesDS) @@ -660,7 +670,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Waterf auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallVisShaderConfig) .overridePipelineLayout({{1, m2BufferOneDS}}) - .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) .bindDescriptorSet(2, m2WaterfallBufferDS) @@ -708,8 +718,11 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Particl auto &l_sceneWideChunk = sceneWideChunk; auto l_fragmentData = std::make_shared>(uboBuffer); ; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) - .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) + bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || + pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", isOpaq ? "m2ParticleShader" : "m2ParticleShader_nonopaq"}, visShaderConfig) + .createPipeline(m_emptyM2ParticleVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() @@ -736,7 +749,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMat auto &l_m2ModelData = m2ModelData; auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, visShaderConfig) - .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyM2RibbonVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() @@ -818,7 +831,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial( auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) - .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) .bindDescriptorSet(2, waterTexturesDS) @@ -862,7 +875,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMater auto skyColors = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) - .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptySkyVAO, m_nonOpaquerenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() @@ -880,7 +893,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria auto materialPS = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) - .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) + .createPipeline(m_emptyPortalVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() @@ -1203,7 +1216,7 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s mapScene->doPostLoad(l_this, framePlan); for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { - auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); if (!updatingTarget) updatingTarget = l_this->defaultView; updatingTarget->update( @@ -1301,18 +1314,24 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s auto currentView = renderTarget.target == nullptr ? l_this->defaultView : - std::dynamic_pointer_cast(renderTarget.target); + std::dynamic_pointer_cast(renderTarget.target); { - auto passHelper = currentView->beginPass(frameBufCmd, l_this->m_renderPass, - false, - frameInputParams->frameParameters->clearColor); + //Opaque part + { + auto passHelper = currentView->beginOpaquePass(frameBufCmd, false, + frameInputParams->frameParameters->clearColor); - { - ZoneScopedN("submit opaque"); - VkZone(frameBufCmd, "render opaque") - l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + { + ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") + l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + } } + currentView->doOpaqueNonOpaqueBarrier(frameBufCmd); + + auto passHelper = currentView->beginNonOpaquePass(frameBufCmd, false, + frameInputParams->frameParameters->clearColor); { //Sky opaque if (renderSky && skyMesh) @@ -1469,5 +1488,5 @@ HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTe } std::shared_ptr MapSceneRenderVisBufferVLK::createRenderView(bool createOutput) { - return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); + return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h index f4ee927aa..2667b1f6f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h @@ -15,6 +15,7 @@ #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" #include "../../../engine/objects/scenes/EntityActorsFactory.h" +#include "view/RenderViewDeferredVLK.h" class MapSceneRenderVisBufferVLK : public MapSceneRenderer { friend class COpaqueMeshCollectorBindlessVLK; @@ -227,7 +228,8 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { std::shared_ptr waterTexturesDS = nullptr; std::shared_ptr waterTextureHolder = nullptr; - std::shared_ptr m_renderPass; + std::shared_ptr m_opaqueRenderPass; + std::shared_ptr m_nonOpaquerenderPass; std::shared_ptr m_lastCreatedPlan = nullptr; @@ -240,7 +242,9 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWMOVAO = nullptr; HGVertexBufferBindings m_emptyWaterVAO = nullptr; - std::shared_ptr defaultView; + + using RendererViewClass = RenderViewDeferredVLK; + std::shared_ptr defaultView; MeshCount lastMeshCount; @@ -281,10 +285,12 @@ class MapSceneRenderVisBufferVLK : public MapSceneRenderer { const std::shared_ptr &getGlobalWMOMaterial() const {return g_wmoMaterial;}; const std::shared_ptr &getGlobalWaterMaterial() const {return g_waterMaterial;}; - const HGVertexBufferBindings getDefaultADTVao() {return m_emptyADTVAO;}; - const HGVertexBufferBindings getDefaultM2Vao() {return m_emptyM2VAO;}; - const HGVertexBufferBindings getDefaultWMOVao() {return m_emptyWMOVAO;}; - const HGVertexBufferBindings getDefaultWaterVao() {return m_emptyWaterVAO;}; + HGVertexBufferBindings getDefaultADTVao() const {return m_emptyADTVAO;}; + HGVertexBufferBindings getDefaultM2Vao() const {return m_emptyM2VAO;}; + HGVertexBufferBindings getDefaultWMOVao() const {return m_emptyWMOVAO;}; + HGVertexBufferBindings getDefaultWaterVao() const {return m_emptyWaterVAO;}; + + std::shared_ptr chooseRenderPass(const PipelineTemplate &pipelineTemplate); }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index a4e7f76a1..ca57f2caf 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -22,7 +22,7 @@ FFXGlowPassVLK::FFXGlowPassVLK(const HGDeviceVLK &device, const HGBufferVLK &ubo m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, VK_SAMPLE_COUNT_1_BIT, // sampleCountToVkSampleCountFlagBits(hDevice->getMaxSamplesCnt()), - true, false); + true, false, true, true); } { @@ -136,8 +136,7 @@ void FFXGlowPassVLK::doPass(CmdBufRecorder &frameBufCmd) { getTargetFrameBuffer(i, currentFrame), {0,0}, {m_width >> 2, m_height >> 2}, - {0, 0, 0},//todo - true + {0, 0, 0}//todo ); frameBufCmd.setViewPort(CmdBufRecorder::ViewportType::vp_usual); frameBufCmd.setDefaultScissors(); @@ -161,8 +160,7 @@ void FFXGlowPassVLK::doFinalPass(CmdBufRecorder &finalBufCmd, const std::shared_ frameBuff, {0,0}, {static_cast(frameBuff->getWidth()), static_cast(frameBuff->getHeight())}, - {0, 0, 0},//todo - true + {0, 0, 0}//todo ); doFinalDraw(finalBufCmd); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp new file mode 100644 index 000000000..7c919f689 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -0,0 +1,222 @@ +// +// Created by Deamon on 10/5/2023. +// + +#include "RenderViewDeferredVLK.h" + +/* + * RenderViewDeferredVLK + */ + +RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, + const HGBufferVLK &uboBuffer, + const HGVertexBufferBindings &quadVAO, + bool createOutputFBO) : m_device(device), m_createOutputFBO(createOutputFBO) { + glowPass = std::make_unique(m_device, uboBuffer, quadVAO); + + createFrameBuffers(); + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); + } +} + +void RenderViewDeferredVLK::createFrameBuffers() { + { + auto const dataFormat = { + ITextureFormat::itRGBA, //Diffuse + ITextureFormat::itRGBA, //Normal + ITextureFormat::itRGBAFloat32, //ViewPos + ITextureFormat::itInt //MatProps + }; + + auto depthFormat = ITextureFormat::itDepth32; + bool invertZ = true; + + m_opaqueRenderPass = m_device->getRenderPass(dataFormat, + depthFormat, + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + invertZ, false, + true, true); + + m_nonOpaqueRenderPass = m_device->getRenderPass({ITextureFormat::itRGBA}, + depthFormat, + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + invertZ, false, + false, false); + + for (auto &colorFrameBuffer: m_colorFrameBuffers) { + colorFrameBuffer = std::make_shared( + *m_device, + dataFormat, + depthFormat, + m_device->getMaxSamplesCnt(), + invertZ, + m_width, m_height + ); + } + + std::vector attachmentsToCopy = {0}; + for (int i = 0; i < m_colorNonOpaqFrameBuffers.size(); i++) { + m_colorNonOpaqFrameBuffers[i] = std::make_shared( + m_colorFrameBuffers[i].get(), + attachmentsToCopy, + m_nonOpaqueRenderPass + ); + + } + + + } + if (m_createOutputFBO) { + auto const dataFormat = {ITextureFormat::itRGBA}; + bool invertZ = false; + + m_outputRenderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, + VK_SAMPLE_COUNT_1_BIT, + invertZ, false, true, true); + + for (auto &outputFrameBuffer: m_outputFrameBuffers) { + outputFrameBuffer = std::make_shared( + *m_device, + dataFormat, + ITextureFormat::itNone, + 1, + invertZ, + m_width, m_height + ); + } + } + +} + +void RenderViewDeferredVLK::update(int width, int height, float glow) { + width = std::max(1, width); + height = std::max(1, height); + + if (width != m_width || height != m_height) { + m_width = std::max(1, width); + m_height = std::max(1, height); + + this->createFrameBuffers(); + + { + std::vector> inputColorTextures; + for (int i = 0; i < m_colorFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + } + + glowPass->updateDimensions(m_width, m_height, + inputColorTextures, + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); + } + + this->executeOnChange(); + } + glowPass->assignFFXGlowUBOConsts(glow); +} + +static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { + return {vec[0], vec[1], vec[2]}; +} + +RenderPassHelper RenderViewDeferredVLK::beginOpaquePass(CmdBufRecorder &frameBufCmd, + bool willExecuteSecondaryBuffs, + mathfu::vec4 &clearColor) { + return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, + m_opaqueRenderPass, + m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + {0,0}, + {m_width, m_height}, + vec4ToArr3(clearColor)); +} +void RenderViewDeferredVLK::doOpaqueNonOpaqueBarrier(CmdBufRecorder &frameBufCmd) { + auto const &fb = m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + + VkImageSubresourceRange subresourceRange = {}; + // Image only contains color data + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // Start at first mip level + subresourceRange.baseMipLevel = 0; + // We will transition on all mip levels + subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + // The 2D texture only has one layer + subresourceRange.layerCount = 1; + + VkImageMemoryBarrier imgBarrier{}; + imgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imgBarrier.subresourceRange = subresourceRange; + imgBarrier.image = std::dynamic_pointer_cast(fb->getAttachment(0)->getTexture())->texture.image; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + + frameBufCmd.recordPipelineImageBarrier( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + { + imgBarrier + } + ); +} + +RenderPassHelper RenderViewDeferredVLK::beginNonOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor) { + return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, + m_nonOpaqueRenderPass, + m_colorNonOpaqFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + {0,0}, + {m_width, m_height}, + vec4ToArr3(clearColor)); +} + +void RenderViewDeferredVLK::doOutputPass(CmdBufRecorder &frameBufCmd) { + auto frameBuff = m_outputFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + + glowPass->doFinalPass(frameBufCmd, frameBuff); +} + +void RenderViewDeferredVLK::doPostGlow(CmdBufRecorder &frameBufCmd) { + glowPass->doPass(frameBufCmd); +} + +void RenderViewDeferredVLK::doPostFinal(CmdBufRecorder &bufCmd) { + glowPass->doFinalDraw(bufCmd); +} + +void RenderViewDeferredVLK::iterateOverOutputTextures( + std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &, + const std::string &, ITextureFormat)> callback) { + + //1. Color output + if (m_createOutputFBO) { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> colorTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + colorTextures[i] = m_outputFrameBuffers[i]->getAttachment(0); + + callback(colorTextures, "Color Texture", ITextureFormat::itRGBA); + } + + //2. Depth buffer + { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + depthTextures[i] = m_device->createSampledTexture(m_colorFrameBuffers[i]->getDepthTexture(), false, false); + + callback(depthTextures, "Depth buffer", ITextureFormat::itDepth32); + } + +} + +void +RenderViewDeferredVLK::readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata) { + if (m_createOutputFBO) { + m_outputFrameBuffers[frameNumber % IDevice::MAX_FRAMES_IN_FLIGHT]->readRGBAPixels(x,y,width,height,outputdata); + } +} \ No newline at end of file diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h new file mode 100644 index 000000000..66520703f --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h @@ -0,0 +1,54 @@ +// +// Created by Deamon on 10/5/2023. +// + +#ifndef AWEBWOWVIEWERCPP_RENDERVIEWDEFERREDVLK_H +#define AWEBWOWVIEWERCPP_RENDERVIEWDEFERREDVLK_H + +#include "../../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../MapSceneParams.h" +#include "../passes/FFXGlowPassVLK.h" + +class RenderViewDeferredVLK : public IRenderView { +public: + RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); + ~RenderViewDeferredVLK() override = default; + + void update(int width, int height, float glow); + + std::shared_ptr getOpaqueRenderPass() {return m_opaqueRenderPass;} + std::shared_ptr getNonOpaqueRenderPass() {return m_nonOpaqueRenderPass;} + + RenderPassHelper beginOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + RenderPassHelper beginNonOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + + void doOpaqueNonOpaqueBarrier(CmdBufRecorder &frameBufCmd); + + void doOutputPass(CmdBufRecorder &frameBufCmd); + + void doPostGlow(CmdBufRecorder &frameBufCmd); + void doPostFinal(CmdBufRecorder &bufCmd); + + void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; + void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata); +private: + uint32_t m_width = 640; + uint32_t m_height = 480; + + HGDeviceVLK m_device; + bool m_createOutputFBO; + + std::shared_ptr m_opaqueRenderPass; + std::shared_ptr m_nonOpaqueRenderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorNonOpaqFrameBuffers; + std::unique_ptr glowPass; + + std::shared_ptr m_outputRenderPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; + + void createFrameBuffers(); + std::vector> onUpdates; +}; + +#endif //AWEBWOWVIEWERCPP_RENDERVIEWDEFERREDVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp index 89aca5fe4..e83899b6b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -48,7 +48,7 @@ void RenderViewForwardVLK::createFrameBuffers() { m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, VK_SAMPLE_COUNT_1_BIT, - invertZ, false); + invertZ, false, true, true); for (auto &outputFrameBuffer: m_outputFrameBuffers) { outputFrameBuffer = std::make_shared( @@ -103,8 +103,7 @@ RenderPassHelper RenderViewForwardVLK::beginPass(CmdBufRecorder &frameBufCmd, m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], {0,0}, {m_width, m_height}, - vec4ToArr3(clearColor), - true); + vec4ToArr3(clearColor)); } void RenderViewForwardVLK::doOutputPass(CmdBufRecorder &frameBufCmd) { From e6e24dbfd070cad64698dc37769e829c8644f1a9 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 17 Feb 2024 18:49:14 +0200 Subject: [PATCH 173/212] - rename visbuffer to bindless --- visibilityBuffer.txt | 6 + wowViewerLib/CMakeLists.txt | 2 +- wowViewerLib/shaders/CMakeLists.txt | 2 +- .../{visBuffer => bindless}/adtShader.frag | 36 +- .../{visBuffer => bindless}/adtShader.vert | 0 .../m2ParticleShader.frag | 0 .../m2ParticleShader.vert | 0 .../m2ParticleShader_nonopaq.frag | 0 .../m2ParticleShader_text.glsl | 0 .../{visBuffer => bindless}/m2Shader.frag | 0 .../{visBuffer => bindless}/m2Shader.vert | 0 .../m2Shader_nonopaq.frag | 0 .../m2shader_text.glsl | 40 +- .../{visBuffer => bindless}/ribbonShader.frag | 0 .../{visBuffer => bindless}/ribbonShader.vert | 0 .../{visBuffer => bindless}/waterShader.frag | 0 .../{visBuffer => bindless}/waterShader.vert | 0 .../waterfallShader.frag | 0 .../waterfallShader.vert | 0 .../{visBuffer => bindless}/wmoShader.frag | 39 +- .../{visBuffer => bindless}/wmoShader.vert | 0 .../src/engine/shader/ShaderDefinitions.h | 518 +++++++++--------- .../mapScene/MapSceneRendererFactory.cpp | 4 +- ...ufferVLK.h => MapSceneRenderBindlessVLK.h} | 10 +- .../vulkan/MapSceneRenderVisBufferVLK.cpp | 182 +++--- 25 files changed, 425 insertions(+), 414 deletions(-) create mode 100644 visibilityBuffer.txt rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/adtShader.frag (88%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/adtShader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2ParticleShader.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2ParticleShader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2ParticleShader_nonopaq.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2ParticleShader_text.glsl (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2Shader.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2Shader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2Shader_nonopaq.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/m2shader_text.glsl (90%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/ribbonShader.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/ribbonShader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/waterShader.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/waterShader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/waterfallShader.frag (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/waterfallShader.vert (100%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/wmoShader.frag (81%) rename wowViewerLib/shaders/glsl/{visBuffer => bindless}/wmoShader.vert (100%) rename wowViewerLib/src/renderer/mapScene/vulkan/{MapSceneRenderVisBufferVLK.h => MapSceneRenderBindlessVLK.h} (97%) diff --git a/visibilityBuffer.txt b/visibilityBuffer.txt new file mode 100644 index 000000000..3f274b96a --- /dev/null +++ b/visibilityBuffer.txt @@ -0,0 +1,6 @@ +What needs to be inside the buffer: +1) gl_InstanceIndex = meshIndex/drawCall +2) triangleIndex + +type: m2, WMO, ADT, Liquid, Particle, Ribbon -> can be stored in stencil + diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index c344ef588..94eeff729 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -526,7 +526,7 @@ if (LINK_VULKAN) src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp - src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h + src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index d593308e9..45545cf09 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -183,7 +183,7 @@ endmacro(configure_filesVLK) configure_filesVLK( ${PROJECT_SOURCE_DIR}/shaders/glsl/ ${PROJECT_SOURCE_DIR}/shaders/glsl/common - "forwardRendering;visBuffer" + "forwardRendering;bindless" ${GLSL_TARGET_FOLDER}/spirv ${GLSL_TARGET_FOLDER}/glsl/glsl20/ ${GLSL_TARGET_FOLDER}/glsl/glsl3.3/) diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adtShader.frag similarity index 88% rename from wowViewerLib/shaders/glsl/visBuffer/adtShader.frag rename to wowViewerLib/shaders/glsl/bindless/adtShader.frag index 5fc897555..d80914ed7 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/adtShader.frag @@ -95,21 +95,23 @@ void main() { vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; - vec4 finalColor = vec4( - calcLight( - matDiffuse, - vNormal, - true, - 0.0, - scene, - intLight, - vVertexLighting.rgb, /* accumLight */ - vec3(0.0), /*precomputedLight*/ - vec3(0.0), /* specular */ - vec3(0.0) /* emissive */ - ), - 1.0 - ); +// vec4 finalColor = vec4( +// calcLight( +// matDiffuse, +// vNormal, +// true, +// 0.0, +// scene, +// intLight, +// vVertexLighting.rgb, /* accumLight */ +// vec3(0.0), /*precomputedLight*/ +// vec3(0.0), /* specular */ +// vec3(0.0) /* emissive */ +// ), +// 1.0 +// ); + + vec4 finalColor = vec4(matDiffuse, 1.0); //Spec part float specBlend = final.a; @@ -118,8 +120,8 @@ void main() { vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; finalColor.rgb += specTerm; - finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, - vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); +// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, +// vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); finalColor.a = 1.0; diff --git a/wowViewerLib/shaders/glsl/visBuffer/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adtShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/adtShader.vert rename to wowViewerLib/shaders/glsl/bindless/adtShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.frag rename to wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader.vert rename to wowViewerLib/shaders/glsl/bindless/m2ParticleShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_nonopaq.frag rename to wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_text.glsl similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2ParticleShader_text.glsl rename to wowViewerLib/shaders/glsl/bindless/m2ParticleShader_text.glsl diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag b/wowViewerLib/shaders/glsl/bindless/m2Shader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2Shader.frag rename to wowViewerLib/shaders/glsl/bindless/m2Shader.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert b/wowViewerLib/shaders/glsl/bindless/m2Shader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2Shader.vert rename to wowViewerLib/shaders/glsl/bindless/m2Shader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag b/wowViewerLib/shaders/glsl/bindless/m2Shader_nonopaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/m2Shader_nonopaq.frag rename to wowViewerLib/shaders/glsl/bindless/m2Shader_nonopaq.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl similarity index 90% rename from wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl rename to wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl index aa8489061..2b37ed558 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl @@ -154,21 +154,23 @@ void main() { // specular *= vMeshColorAlpha.rgb; - finalColor = vec4( - calcLight( - matDiffuse, - l_Normal, - meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, - modelWide.interiorExteriorBlend.x, - scene, - modelWide.intLight, - accumLight, - vec3(0.0), - specular, - vec3(0.0) - ) , - finalOpacity - ); +// finalColor = vec4( +// calcLight( +// matDiffuse, +// l_Normal, +// meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, +// modelWide.interiorExteriorBlend.x, +// scene, +// modelWide.intLight, +// accumLight, +// vec3(0.0), +// specular, +// vec3(0.0) +// ) , +// finalOpacity +// ); + + finalColor = vec4(matDiffuse, finalOpacity); // ------------------------------ // Apply Fog @@ -183,10 +185,10 @@ void main() { modelWide.interiorExteriorBlend.x ).xyz; - finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, - finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, - meshWide.PixelShader_UnFogged_blendMode.z - ); +// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, +// finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, +// meshWide.PixelShader_UnFogged_blendMode.z +// ); } //Forward rendering without lights diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag b/wowViewerLib/shaders/glsl/bindless/ribbonShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/ribbonShader.frag rename to wowViewerLib/shaders/glsl/bindless/ribbonShader.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert b/wowViewerLib/shaders/glsl/bindless/ribbonShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/ribbonShader.vert rename to wowViewerLib/shaders/glsl/bindless/ribbonShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.frag b/wowViewerLib/shaders/glsl/bindless/waterShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/waterShader.frag rename to wowViewerLib/shaders/glsl/bindless/waterShader.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterShader.vert b/wowViewerLib/shaders/glsl/bindless/waterShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/waterShader.vert rename to wowViewerLib/shaders/glsl/bindless/waterShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag b/wowViewerLib/shaders/glsl/bindless/waterfallShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/waterfallShader.frag rename to wowViewerLib/shaders/glsl/bindless/waterfallShader.frag diff --git a/wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert b/wowViewerLib/shaders/glsl/bindless/waterfallShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/waterfallShader.vert rename to wowViewerLib/shaders/glsl/bindless/waterfallShader.vert diff --git a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag b/wowViewerLib/shaders/glsl/bindless/wmoShader.frag similarity index 81% rename from wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag rename to wowViewerLib/shaders/glsl/bindless/wmoShader.frag index 344dcba79..39c3e8f4d 100644 --- a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/wmoShader.frag @@ -79,25 +79,26 @@ void main() { intLight.uInteriorDirectColorAndApplyExteriorLight = vec4(0, 0, 0, 1.0f); vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); - finalColor = vec4( - calcLight( - matDiffuse, - vNormal, - wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, - vColor.w, - scene, - intLight, - vec3(0.0) /*accumLight*/, - vColor.rgb, - spec, /* specular */ - emissive - ), - finalOpacity - ); - - finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, - vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); - finalColor.a = 1.0; +// finalColor = vec4( +// calcLight( +// matDiffuse, +// vNormal, +// wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, +// vColor.w, +// scene, +// intLight, +// vec3(0.0) /*accumLight*/, +// vColor.rgb, +// spec, /* specular */ +// emissive +// ), +// finalOpacity +// ); + finalColor.rgb = matDiffuse; + +// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, +// vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); +// finalColor.a = 1.0; outColor = finalColor; outNormal = vec4(normalize(vNormal), 0.0); diff --git a/wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert b/wowViewerLib/shaders/glsl/bindless/wmoShader.vert similarity index 100% rename from wowViewerLib/shaders/glsl/visBuffer/wmoShader.vert rename to wowViewerLib/shaders/glsl/bindless/wmoShader.vert diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 72b43497a..d0c71b344 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -298,17 +298,16 @@ const std::unordered_map> attributesPe }; const std::unordered_map shaderMetaInfo = { -{ "visBuffer/ribbonShader.frag.spv", +{ "bindless/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -318,17 +317,27 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { - {2,0, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -337,9 +346,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader.vert.spv", +{ "bindless/waterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -356,24 +365,27 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, + {2,1,0}, + {2,0,0}, {1,1,0}, {1,2,0}, + {1,3,0}, {1,4,0}, {1,5,0}, {1,6,0}, + {1,7,0}, {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -382,17 +394,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2ParticleShader_nonopaq.frag.spv", +{ "bindless/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -404,15 +415,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -422,7 +430,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/ribbonShader.vert.spv", +{ "bindless/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -441,6 +449,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -458,7 +475,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2ParticleShader.vert.spv", +{ "bindless/waterShader.vert.spv", { ShaderStage::Vertex, { @@ -477,14 +494,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -494,18 +515,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "bindless/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, - {1,1,16}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -515,14 +534,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -532,16 +561,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.frag.spv", +{ "bindless/m2ParticleShader_nonopaq.frag.spv", { ShaderStage::Fragment, { + {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -551,22 +581,57 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, + {0,2,3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/wmoShader.vert.spv", + { + ShaderStage::Vertex, + { + {1,0,64}, + {0,0,544}, + {1,1,16}, + }, + { + { {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,1,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -727,9 +792,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "bindless/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -746,14 +811,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, + {1,1,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -763,7 +832,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -782,27 +851,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -811,15 +868,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "bindless/m2Shader_nonopaq.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -830,14 +887,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -847,15 +914,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -883,11 +950,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,544}, }, { { @@ -919,17 +986,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2ParticleShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, - {0,0,544}, + {0,0,128}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -941,15 +1007,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -959,15 +1022,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "bindless/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { + {1,0,32}, + {0,0,544}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -979,13 +1044,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -995,15 +1062,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/wmoShader.vert.spv", +{ "forwardRendering/imguiShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1014,19 +1080,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1037,7 +1098,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.frag.spv", +{ "bindless/wmoShader.frag.spv", { ShaderStage::Fragment, { @@ -1056,9 +1117,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1198,52 +1262,6 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/m2Shader_nonopaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, - }, - { - {2,0, "s_Textures"}, - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, { "forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, @@ -1317,7 +1335,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterfallShader.frag.spv", +{ "bindless/adtShader.frag.spv", { ShaderStage::Fragment, { @@ -1336,28 +1354,22 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, + {1,3,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1558,6 +1570,45 @@ const std::unordered_map shaderMetaInfo = { } } }, +{ "bindless/adtShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,3,0}, + {1,1,0}, + {1,2,0}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, { "forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, @@ -1800,45 +1851,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShaderDepth.frag.spv", +{ "bindless/wmoShader.vert.spv", { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "Texture"}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "visBuffer/wmoShader.frag.spv", - { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -1857,19 +1872,18 @@ const std::unordered_map shaderMetaInfo = { { {1,6,0}, {1,4,0}, - {1,3,0}, - {1,5,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1879,15 +1893,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/waterShader.vert.spv", +{ "forwardRendering/imguiShaderDepth.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1898,16 +1911,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {1,0, "Texture"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1915,15 +1924,16 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "visBuffer/m2Shader.frag.spv", +{ "forwardRendering/drawFrustumShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, }, { { @@ -1938,24 +1948,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1965,16 +1965,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {1,0,64}, + {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2001,17 +2002,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, - {0,0,544}, }, { { - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2023,11 +2022,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2038,14 +2038,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "forwardRendering/drawPoints.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, + {0,1,64}, }, { { - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2058,12 +2060,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2074,15 +2075,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "visBuffer/adtShader.vert.spv", +{ "forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2093,9 +2094,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { }, @@ -2113,17 +2111,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {1,0,32}, + {0,0,544}, }, { { - {0,1,2}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2135,12 +2133,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2150,15 +2151,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2186,17 +2187,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "bindless/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, + {1,1,16}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2206,17 +2207,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,4096}, }, { {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2226,7 +2226,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "bindless/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index e15689e38..d73786717 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -4,7 +4,7 @@ #include "MapSceneRendererFactory.h" #include "vulkan/MapSceneRenderForwardVLK.h" -#include "vulkan/MapSceneRenderVisBufferVLK.h" +#include "vulkan/MapSceneRenderBindlessVLK.h" std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { @@ -13,7 +13,7 @@ std::shared_ptr MapSceneRendererFactory::createForwardRenderer return std::make_shared(std::dynamic_pointer_cast(device), config); } else { - return std::make_shared(std::dynamic_pointer_cast(device), config); + return std::make_shared(std::dynamic_pointer_cast(device), config); } default: return std::make_shared(std::dynamic_pointer_cast(device), config); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h similarity index 97% rename from wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h rename to wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 2667b1f6f..ac0cccce9 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -2,8 +2,8 @@ // Created by Deamon on 12/1/2022. // -#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H -#define AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSVLK_H #include "../MapSceneRenderer.h" @@ -17,11 +17,11 @@ #include "../../../engine/objects/scenes/EntityActorsFactory.h" #include "view/RenderViewDeferredVLK.h" -class MapSceneRenderVisBufferVLK : public MapSceneRenderer { +class MapSceneRenderBindlessVLK : public MapSceneRenderer { friend class COpaqueMeshCollectorBindlessVLK; public: - explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); - ~MapSceneRenderVisBufferVLK() override = default; + explicit MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderBindlessVLK() override = default; std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; inline static void drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp index cd391a0b2..9e3d678cd 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp @@ -2,7 +2,7 @@ // Created by Deamon on 12/1/2022. // -#include "MapSceneRenderVisBufferVLK.h" +#include "MapSceneRenderBindlessVLK.h" #include "../../vulkan/IRenderFunctionVLK.h" #include "../../../engine/objects/scenes/map.h" #include "../../../gapi/vulkan/materials/MaterialBuilderVLK.h" @@ -34,7 +34,7 @@ const int adtTexturesBindlessCount = 4096; const int waterTexturesBindlessCount = 1024; static const ShaderConfig m2VisShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -47,7 +47,7 @@ static const ShaderConfig m2VisShaderConfig = { }} }}; static const ShaderConfig visShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -55,7 +55,7 @@ static const ShaderConfig visShaderConfig = { }}; static const ShaderConfig m2WaterfallVisShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -66,7 +66,7 @@ static const ShaderConfig m2WaterfallVisShaderConfig = { }}; static const ShaderConfig wmoVisShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -77,7 +77,7 @@ static const ShaderConfig wmoVisShaderConfig = { }}; static const ShaderConfig adtVisShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -94,7 +94,7 @@ static const ShaderConfig adtVisShaderConfig = { }}; static const ShaderConfig waterVisShaderConfig = { - "visBuffer", + "bindless", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -104,7 +104,7 @@ static const ShaderConfig waterVisShaderConfig = { }} }}; -MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config) : +MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { std::cout << "Create Bindless scene renderer " << std::endl; @@ -219,7 +219,7 @@ MapSceneRenderVisBufferVLK::MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevic createWaterGlobalMaterialData(); } -std::shared_ptr MapSceneRenderVisBufferVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { if (pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_Opaque && pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_AlphaKey) { return m_nonOpaquerenderPass; } else { @@ -227,7 +227,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::chooseRenderPass(con } } -void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { +void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtAlphaTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -262,7 +262,7 @@ void MapSceneRenderVisBufferVLK::createADTGlobalMaterialData() { } } -void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { +void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = true; @@ -288,7 +288,7 @@ void MapSceneRenderVisBufferVLK::createWaterGlobalMaterialData() { waterTextureHolder = std::make_shared(waterTexturesBindlessCount); } -void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { +void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = true; @@ -317,7 +317,7 @@ void MapSceneRenderVisBufferVLK::createWMOGlobalMaterialData() { wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); } -void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() { +void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { PipelineTemplate pipelineTemplate; pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = true; @@ -348,7 +348,7 @@ void MapSceneRenderVisBufferVLK::createM2GlobalMaterialData() { }).toMaterial(); m2TextureHolder = std::make_shared(m2TexturesBindlessCount); } -void MapSceneRenderVisBufferVLK::createM2WaterfallGlobalMaterialData() { +void MapSceneRenderBindlessVLK::createM2WaterfallGlobalMaterialData() { MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallVisShaderConfig) .overridePipelineLayout({{1, m2BufferOneDS}}) .createDescriptorSet(2, [&](std::shared_ptr &ds) { @@ -365,7 +365,7 @@ void MapSceneRenderVisBufferVLK::createM2WaterfallGlobalMaterialData() { m2WaterfallTextureHolder = std::make_shared(m2WaterfallTexturesBindlessCount); } -std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_m2StaticMaterials.find(pipelineTemplate); if (i != m_m2StaticMaterials.end()) { return i->second; @@ -389,7 +389,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getM2StaticMater return staticMaterial; } -std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate) { auto i = m_wmoStaticMaterials.find(pipelineTemplate); if (i != m_wmoStaticMaterials.end()) { return i->second; @@ -414,7 +414,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::getWMOStaticMate // Buffer creation // ------------------ -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto adtVAO = m_device->createVertexBufferBindings(); adtVAO->addVertexBufferBinding(vertexBuffer, adtVertexBufferBinding); @@ -423,7 +423,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createADTVAO(HGVertexBuffer v return adtVAO; }; -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto wmoVAO = m_device->createVertexBufferBindings(); @@ -432,7 +432,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWmoVAO(HGVertexBuffer v return wmoVAO; } -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto m2VAO = m_device->createVertexBufferBindings(); m2VAO->addVertexBufferBinding(vertexBuffer, staticM2Bindings); @@ -440,7 +440,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2VAO(HGVertexBuffer ve return m2VAO; } -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto m2ParticleVAO = m_device->createVertexBufferBindings(); m2ParticleVAO->addVertexBufferBinding(vertexBuffer, staticM2ParticleBindings); @@ -449,7 +449,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2ParticleVAO(HGVertexB return m2ParticleVAO; } -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto m2RibbonVAO = m_device->createVertexBufferBindings(); m2RibbonVAO->addVertexBufferBinding(vertexBuffer, staticM2RibbonBindings); @@ -458,7 +458,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createM2RibbonVAO(HGVertexBuf return m2RibbonVAO; }; -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto waterVAO = m_device->createVertexBufferBindings(); waterVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); @@ -467,7 +467,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createWaterVAO(HGVertexBuffer return waterVAO; }; -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto skyVAO = m_device->createVertexBufferBindings(); skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(skyConusBinding.begin(), skyConusBinding.end())); @@ -476,7 +476,7 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createSkyVAO(HGVertexBuffer v return skyVAO; } -HGVertexBufferBindings MapSceneRenderVisBufferVLK::createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { +HGVertexBufferBindings MapSceneRenderBindlessVLK::createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers auto portalVAO = m_device->createVertexBufferBindings(); portalVAO->addVertexBufferBinding(vertexBuffer, std::vector(drawPortalBindings.begin(), drawPortalBindings.end())); @@ -485,63 +485,63 @@ HGVertexBufferBindings MapSceneRenderVisBufferVLK::createPortalVAO(HGVertexBuffe return portalVAO; }; -HGVertexBuffer MapSceneRenderVisBufferVLK::createPortalVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createPortalVertexBuffer(int sizeInBytes) { return vboPortalBuffer->getSubBuffer(sizeInBytes); }; -HGIndexBuffer MapSceneRenderVisBufferVLK::createPortalIndexBuffer(int sizeInBytes){ +HGIndexBuffer MapSceneRenderBindlessVLK::createPortalIndexBuffer(int sizeInBytes){ return iboBuffer->getSubBuffer(sizeInBytes); }; -HGVertexBuffer MapSceneRenderVisBufferVLK::createM2VertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createM2VertexBuffer(int sizeInBytes) { return vboM2Buffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createM2ParticleVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createM2ParticleVertexBuffer(int sizeInBytes) { return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createM2RibbonVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createM2RibbonVertexBuffer(int sizeInBytes) { return vboM2RibbonBuffer->getSubBuffer(sizeInBytes); } -HGIndexBuffer MapSceneRenderVisBufferVLK::createM2IndexBuffer(int sizeInBytes) { +HGIndexBuffer MapSceneRenderBindlessVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createADTVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createADTVertexBuffer(int sizeInBytes) { return vboAdtBuffer->getSubBuffer(sizeInBytes); } -HGIndexBuffer MapSceneRenderVisBufferVLK::createADTIndexBuffer(int sizeInBytes) { +HGIndexBuffer MapSceneRenderBindlessVLK::createADTIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createWMOVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createWMOVertexBuffer(int sizeInBytes) { return vboWMOBuffer->getSubBuffer(sizeInBytes); } -HGIndexBuffer MapSceneRenderVisBufferVLK::createWMOIndexBuffer(int sizeInBytes) { +HGIndexBuffer MapSceneRenderBindlessVLK::createWMOIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createWaterVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createWaterVertexBuffer(int sizeInBytes) { return vboWaterBuffer->getSubBuffer(sizeInBytes); } -HGIndexBuffer MapSceneRenderVisBufferVLK::createWaterIndexBuffer(int sizeInBytes) { +HGIndexBuffer MapSceneRenderBindlessVLK::createWaterIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } -HGVertexBuffer MapSceneRenderVisBufferVLK::createSkyVertexBuffer(int sizeInBytes) { +HGVertexBuffer MapSceneRenderBindlessVLK::createSkyVertexBuffer(int sizeInBytes) { return vboSkyBuffer->getSubBuffer(sizeInBytes);; }; -HGIndexBuffer MapSceneRenderVisBufferVLK::createSkyIndexBuffer(int sizeInBytes) { +HGIndexBuffer MapSceneRenderBindlessVLK::createSkyIndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } std::shared_ptr -MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { +MapSceneRenderBindlessVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { ZoneScoped; auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); @@ -600,9 +600,9 @@ MapSceneRenderVisBufferVLK::createAdtMaterial(const PipelineTemplate &pipelineTe } std::shared_ptr -MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr &m2ModelData, - const PipelineTemplate &pipelineTemplate, - const M2MaterialTemplate &m2MaterialTemplate) { +MapSceneRenderBindlessVLK::createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) { ZoneScoped; auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); @@ -656,9 +656,9 @@ MapSceneRenderVisBufferVLK::createM2Material(const std::shared_ptr return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, - const PipelineTemplate &pipelineTemplate, - const M2WaterfallMaterialTemplate &m2MaterialTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) { auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); auto &l_sceneWideChunk = sceneWideChunk; @@ -711,7 +711,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Waterf return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createM2ParticleMaterial( +std::shared_ptr MapSceneRenderBindlessVLK::createM2ParticleMaterial( const PipelineTemplate &pipelineTemplate, const M2ParticleMaterialTemplate &m2ParticleMatTemplate) { @@ -741,9 +741,9 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2Particl return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMaterial(const std::shared_ptr &m2ModelData, - const PipelineTemplate &pipelineTemplate, - const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; @@ -767,16 +767,16 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2RibbonMat return material; }; -std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOWideChunk() { +std::shared_ptr> MapSceneRenderBindlessVLK::createWMOWideChunk() { return std::make_shared>(wmoBuffers.wmoPlacementMats); } -std::shared_ptr> MapSceneRenderVisBufferVLK::createWMOGroupAmbientChunk() { +std::shared_ptr> MapSceneRenderBindlessVLK::createWMOGroupAmbientChunk() { return std::make_shared>(wmoBuffers.wmoGroupAmbient); } -std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(const std::shared_ptr> &modelWide, - const PipelineTemplate &pipelineTemplate, - const WMOMaterialTemplate &wmoMaterialTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) { auto l_vertexData = std::make_shared>(wmoBuffers.wmoMeshWideVSes); ; auto l_fragmentData = std::make_shared>(wmoBuffers.wmoMeshWidePSes); ; auto l_bindless = std::make_shared>(wmoBuffers.wmoMeshWideBindless); @@ -823,9 +823,9 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWMOMaterial(cons return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial(const std::shared_ptr> &modelWide, - const PipelineTemplate &pipelineTemplate, - const WaterMaterialTemplate &waterMaterialTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) { auto l_fragmentData = std::make_shared>(waterBuffer.waterDataBuffer); ; auto l_waterBindless = std::make_shared>(waterBuffer.waterBindlessBuffer); ; @@ -870,7 +870,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createWaterMaterial( -std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto skyColors = std::make_shared>(uboBuffer); @@ -888,7 +888,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createSkyMeshMater return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMaterial(const PipelineTemplate &pipelineTemplate) { +std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial(const PipelineTemplate &pipelineTemplate) { auto &l_sceneWideChunk = sceneWideChunk; auto materialPS = std::make_shared>(uboBuffer); @@ -906,7 +906,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createPortalMateria return material; } -std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { +std::shared_ptr MapSceneRenderBindlessVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { auto result = std::make_shared(); BufferChunkHelperVLK::create(m2Buffers.placementMatrix, result->m_placementMatrix); @@ -930,7 +930,7 @@ std::shared_ptr MapSceneRenderVisBufferVLK::createM2ModelMat(int b return result; } -inline void MapSceneRenderVisBufferVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { +inline void MapSceneRenderBindlessVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { if (mesh == nullptr) return; const auto &meshVlk = (GMeshVLK*) mesh.get(); @@ -965,20 +965,20 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ public: - COpaqueMeshCollectorBindlessVLK(MapSceneRenderVisBufferVLK &rendererVlk) : m_renderer(rendererVlk) { + COpaqueMeshCollectorBindlessVLK(MapSceneRenderBindlessVLK &rendererVlk) : m_renderer(rendererVlk) { commonMeshes.reserve(1000); m2DrawVec.reserve(5000); wmoDrawVec.reserve(5000); adtDrawVec.reserve(1000); } - COpaqueMeshCollectorBindlessVLK(MapSceneRenderVisBufferVLK &rendererVlk, MeshCount &lastMeshCount) : m_renderer(rendererVlk) { + COpaqueMeshCollectorBindlessVLK(MapSceneRenderBindlessVLK &rendererVlk, MeshCount &lastMeshCount) : m_renderer(rendererVlk) { commonMeshes.reserve(lastMeshCount.commonMesh); m2DrawVec.reserve(lastMeshCount.m2Mesh); wmoDrawVec.reserve(lastMeshCount.wmoMesh); adtDrawVec.reserve(lastMeshCount.adtMesh); } private: - MapSceneRenderVisBufferVLK &m_renderer; + MapSceneRenderBindlessVLK &m_renderer; struct DrawCommand { uint32_t matId; uint32_t indexCount; @@ -1085,7 +1085,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ uint32_t currentMatId = 0xFFFFFFFF; for (auto const &drawCmd : wmoDrawVec) { - if (currentMatId != drawCmd.matId) { +// if (currentMatId != drawCmd.matId) { auto material = m_renderer.m_wmoMatCacheId[drawCmd.matId].lock(); if (!material) continue; @@ -1093,7 +1093,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ cmdBuf.bindPipeline(material->getPipeline()); currentMatId = drawCmd.matId; - } +// } cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } @@ -1123,7 +1123,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ //Render commonMeshes for (auto const &mesh : commonMeshes ) { - MapSceneRenderVisBufferVLK::drawMesh(cmdBuf, mesh, viewPortType); + MapSceneRenderBindlessVLK::drawMesh(cmdBuf, mesh, viewPortType); } } void renderWater(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { @@ -1154,12 +1154,12 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ }; -std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::shared_ptr> &frameInputParams, - const std::shared_ptr &framePlan) { +std::unique_ptr MapSceneRenderBindlessVLK::update(const std::shared_ptr> &frameInputParams, + const std::shared_ptr &framePlan) { TracyMessageStr(("Update stage frame = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); ZoneScoped; - auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); @@ -1335,8 +1335,8 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s { //Sky opaque if (renderSky && skyMesh) - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh, - CmdBufRecorder::ViewportType::vp_skyBox); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh, + CmdBufRecorder::ViewportType::vp_skyBox); l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); } @@ -1354,12 +1354,12 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_skyBox); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); } if (renderSky && skyMesh0x4) - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, skyMesh0x4, - CmdBufRecorder::ViewportType::vp_skyBox); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh0x4, + CmdBufRecorder::ViewportType::vp_skyBox); } { //Render liquids @@ -1380,8 +1380,8 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderVisBufferVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_usual); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); } } } @@ -1398,20 +1398,20 @@ std::unique_ptr MapSceneRenderVisBufferVLK::update(const std::s }); } -std::shared_ptr MapSceneRenderVisBufferVLK::getLastCreatedPlan() { +std::shared_ptr MapSceneRenderBindlessVLK::getLastCreatedPlan() { return m_lastCreatedPlan; } -HGMesh MapSceneRenderVisBufferVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { +HGMesh MapSceneRenderBindlessVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } -HGSortableMesh MapSceneRenderVisBufferVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { +HGSortableMesh MapSceneRenderBindlessVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } -HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { +HGSortableMesh MapSceneRenderBindlessVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyWaterVAO; @@ -1426,7 +1426,7 @@ HGSortableMesh MapSceneRenderVisBufferVLK::createWaterMesh(gMeshTemplate &meshTe } HGMesh -MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { +MapSceneRenderBindlessVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); @@ -1440,8 +1440,8 @@ MapSceneRenderVisBufferVLK::createAdtMesh(gMeshTemplate &meshTemplate, const st return mesh; } HGM2Mesh -MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, - int layer, int priorityPlane) { +MapSceneRenderBindlessVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + int layer, int priorityPlane) { ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyM2VAO; @@ -1453,8 +1453,8 @@ MapSceneRenderVisBufferVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std: return mesh; } -HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, - const std::shared_ptr> &ambientBuffer) { +HGMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + const std::shared_ptr> &ambientBuffer) { auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyWMOVAO; @@ -1479,14 +1479,14 @@ HGMesh MapSceneRenderVisBufferVLK::createWMOMesh(gMeshTemplate &meshTemplate, co mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); return mesh; } -HGM2Mesh MapSceneRenderVisBufferVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, - const std::shared_ptr &material, - int layer, int priorityPlane) { +HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, + const std::shared_ptr &material, + int layer, int priorityPlane) { auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } -std::shared_ptr MapSceneRenderVisBufferVLK::createRenderView(bool createOutput) { +std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } From e732f14e5f78feff740caa8891a5263f69e15310 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 17 Feb 2024 21:17:17 +0200 Subject: [PATCH 174/212] - tempCommit --- visibilityBuffer.txt | 18 + wowViewerLib/CMakeLists.txt | 2 +- wowViewerLib/shaders/CMakeLists.txt | 21 +- .../bindless/{ => adt/forward}/adtShader.frag | 10 +- .../bindless/{ => adt/forward}/adtShader.vert | 10 +- .../bindless/adt/visbuffer/adtShader.frag | 132 ++ .../bindless/adt/visbuffer/adtShader.vert | 68 + .../bindless/{ => m2/forward}/m2Shader.frag | 0 .../bindless/{ => m2/forward}/m2Shader.vert | 12 +- .../{ => m2/forward}/m2Shader_nonopaq.frag | 0 .../{ => m2/forward}/m2shader_text.glsl | 10 +- .../forward/m2ParticleShader.frag} | 14 +- .../forward}/m2ParticleShader.vert | 6 +- .../glsl/bindless/m2ParticleShader.frag | 5 - .../bindless/m2ParticleShader_nonopaq.frag | 7 - .../bindless/{ => water}/waterShader.frag | 8 +- .../bindless/{ => water}/waterShader.vert | 8 +- .../{ => waterfall}/waterfallShader.frag | 12 +- .../{ => waterfall}/waterfallShader.vert | 14 +- .../bindless/{ => wmo/forward}/wmoShader.frag | 12 +- .../bindless/{ => wmo/forward}/wmoShader.vert | 12 +- .../src/engine/shader/ShaderDefinitions.h | 1427 ++++++++++++----- ...rVLK.cpp => MapSceneRenderBindlessVLK.cpp} | 42 +- .../vulkan/MapSceneRenderBindlessVLK.h | 3 + 24 files changed, 1363 insertions(+), 490 deletions(-) rename wowViewerLib/shaders/glsl/bindless/{ => adt/forward}/adtShader.frag (95%) rename wowViewerLib/shaders/glsl/bindless/{ => adt/forward}/adtShader.vert (87%) create mode 100644 wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert rename wowViewerLib/shaders/glsl/bindless/{ => m2/forward}/m2Shader.frag (100%) rename wowViewerLib/shaders/glsl/bindless/{ => m2/forward}/m2Shader.vert (88%) rename wowViewerLib/shaders/glsl/bindless/{ => m2/forward}/m2Shader_nonopaq.frag (100%) rename wowViewerLib/shaders/glsl/bindless/{ => m2/forward}/m2shader_text.glsl (96%) rename wowViewerLib/shaders/glsl/bindless/{m2ParticleShader_text.glsl => m2Particle/forward/m2ParticleShader.frag} (92%) rename wowViewerLib/shaders/glsl/bindless/{ => m2Particle/forward}/m2ParticleShader.vert (86%) delete mode 100644 wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag delete mode 100644 wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag rename wowViewerLib/shaders/glsl/bindless/{ => water}/waterShader.frag (95%) rename wowViewerLib/shaders/glsl/bindless/{ => water}/waterShader.vert (85%) rename wowViewerLib/shaders/glsl/bindless/{ => waterfall}/waterfallShader.frag (94%) rename wowViewerLib/shaders/glsl/bindless/{ => waterfall}/waterfallShader.vert (89%) rename wowViewerLib/shaders/glsl/bindless/{ => wmo/forward}/wmoShader.frag (92%) rename wowViewerLib/shaders/glsl/bindless/{ => wmo/forward}/wmoShader.vert (86%) rename wowViewerLib/src/renderer/mapScene/vulkan/{MapSceneRenderVisBufferVLK.cpp => MapSceneRenderBindlessVLK.cpp} (98%) diff --git a/visibilityBuffer.txt b/visibilityBuffer.txt index 3f274b96a..7e04e233d 100644 --- a/visibilityBuffer.txt +++ b/visibilityBuffer.txt @@ -4,3 +4,21 @@ What needs to be inside the buffer: type: m2, WMO, ADT, Liquid, Particle, Ribbon -> can be stored in stencil +2) Be able to choose between forward bindless and visbuffer bindless + +M2 forward: vert and frag +M2 vis: vis vert and frag and frag_alphaCut, CS, m2 Forward vert and frag for transparent + +WMO forward: vert and frag +WMO vis: vis vert and frag and frag_alphaCut, CS, WMO Forward vert and frag for transparent + +ADT forward: vert and frag +ADT vis: vis vert and frag, CS + +For visbuffer all calls should come from indirect + +Vis buffer format: +1) gl_DrawId -> indirect buffer (for VertexOffset, IndexOffset, InstanceIndex = meshIndex) +2) gl_PrimitiveId (usage: vertexIndex = IndexBuffer[(IndexOffset) / 2 + PrimitiveId]) +3) Normal for LightBuffer creation + diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 94eeff729..6342c2969 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -525,7 +525,7 @@ if (LINK_VULKAN) src/gapi/vulkan/GRenderPassVLK.h src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h - src/renderer/mapScene/vulkan/MapSceneRenderVisBufferVLK.cpp + src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 45545cf09..711713c4e 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -100,15 +100,26 @@ macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 des set(srcTemplatePath ${srcDir}/${templateFile}) if(NOT IS_DIRECTORY ${srcTemplatePath}) message(STATUS "Configuring file ${templateFile}") + file(RELATIVE_PATH srcFileRelative ${srcDir} ${srcTemplatePath}) + get_filename_component(FILE_NAME_WO_EXT ${srcTemplatePath} NAME_WE) get_filename_component(FILE_NAME ${srcTemplatePath} NAME) + get_filename_component(SHADER_SUB_DIR ${srcFileRelative} DIRECTORY ) +# file(RELATIVE_PATH SHADER_SUB_DIR shaderDir ${srcTemplatePath}) + +# message(srcFileRelative = ${srcFileRelative}) +# message(srcTemplatePath = ${srcTemplatePath}) +# message(templateFile = ${templateFile}) +# message(SHADER_SUB_DIR = ${SHADER_SUB_DIR}) if (NOT SPIRV_OPT_APP) - set(SPIRV_NonOpt "${destDir}/${shaderDir}/${FILE_NAME}.spv") + set(SPIRV_NonOpt "${destDir}/${shaderDir}/${SHADER_SUB_DIR}${FILE_NAME}.spv") else() - set(SPIRV_NonOpt "${spirvNonOptDir}/${shaderDir}/${FILE_NAME}.spv") - set(SPIRVOpt "${destDir}/${shaderDir}/${FILE_NAME}.spv") + set(SPIRV_NonOpt "${spirvNonOptDir}/${shaderDir}/${SHADER_SUB_DIR}${FILE_NAME}.spv") + set(SPIRVOpt "${destDir}/${shaderDir}/${SHADER_SUB_DIR}${FILE_NAME}.spv") endif() +# message(SPIRV_NonOpt = ${SPIRV_NonOpt}) +# message(SPIRVOpt = ${SPIRVOpt}) add_custom_command( OUTPUT ${SPIRV_NonOpt} @@ -127,8 +138,8 @@ macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 des list(APPEND SPIRV_BINARY_FILES_OPT ${SPIRVOpt}) #Generate GLSL for ogl33 and ogl20 from spirv - set(GLSL20_FILE ${destDirGL20}/${shaderDir}/${FILE_NAME}) - set(GLSL33_FILE ${destDirGL33}/${shaderDir}/${FILE_NAME}) + set(GLSL20_FILE ${destDirGL20}/${shaderDir}/${SHADER_SUB_DIR}/${FILE_NAME}) + set(GLSL33_FILE ${destDirGL33}/${shaderDir}/${SHADER_SUB_DIR}/${FILE_NAME}) get_filename_component(GLSL20_FILE_FULLPATH "${GLSL20_FILE}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") diff --git a/wowViewerLib/shaders/glsl/bindless/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag similarity index 95% rename from wowViewerLib/shaders/glsl/bindless/adtShader.frag rename to wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag index d80914ed7..b119d2c50 100644 --- a/wowViewerLib/shaders/glsl/bindless/adtShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag @@ -6,11 +6,11 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" -#include "../common/commonADTMaterial.glsl" -#include "../common/commonAdtIndirectDescriptorSet.glsl" +#include "../../../common/commonADTMaterial.glsl" +#include "../../../common/commonAdtIndirectDescriptorSet.glsl" layout(location = 0) in vec2 vChunkCoords; layout(location = 1) in vec3 vPosition; @@ -24,7 +24,7 @@ layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonUboSceneData.glsl" layout(location = 0) out vec4 outColor; layout(location = 1) out vec4 outNormal; diff --git a/wowViewerLib/shaders/glsl/bindless/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert similarity index 87% rename from wowViewerLib/shaders/glsl/bindless/adtShader.vert rename to wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert index d7e736c54..0a560bee4 100644 --- a/wowViewerLib/shaders/glsl/bindless/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert @@ -7,9 +7,9 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonADTMaterial.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonADTMaterial.glsl" /* vertex shader code */ layout(location = 0) in vec3 aPos; @@ -17,8 +17,8 @@ layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; -#include "../common/commonUboSceneData.glsl" -#include "../common/commonAdtIndirectDescriptorSet.glsl" +#include "../../../common/commonUboSceneData.glsl" +#include "../../../common/commonAdtIndirectDescriptorSet.glsl" mat3 blizzTranspose(mat4 value) { diff --git a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag new file mode 100644 index 000000000..b119d2c50 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag @@ -0,0 +1,132 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +precision highp float; +precision highp int; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" + +#include "../../../common/commonADTMaterial.glsl" +#include "../../../common/commonAdtIndirectDescriptorSet.glsl" + +layout(location = 0) in vec2 vChunkCoords; +layout(location = 1) in vec3 vPosition; +layout(location = 2) in vec4 vColor; +layout(location = 3) in vec3 vNormal; +layout(location = 4) in vec3 vVertexLighting; +layout(location = 5) in vec2 vAlphaCoords; +layout(location = 6) in flat int meshIndex; + +layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; +layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; +layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; + +#include "../../../common/commonUboSceneData.glsl" + +layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outNormal; +layout(location = 2) out vec4 outViewPos; +layout(location = 3) out uint outMatProps; + +const InteriorLightParam intLight = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + +void main() { + AdtInstanceData adtInstanceData = adtInstanceDatas[nonuniformEXT(meshIndex)]; + AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x)]; + AdtMeshWidePS adtMeshWidePS = adtMeshWidePSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.y)]; + + + vec2 vTexCoord = vChunkCoords; + const float threshold = 1.5; + + ivec4 animation_rotationPerLayer = adtMeshWidePS.animation_rotationPerLayer; + ivec4 animation_speedPerLayer = adtMeshWidePS.animation_speedPerLayer; + vec4 scaleFactorPerLayer = adtMeshWidePS.scaleFactorPerLayer; + float sceneTime = scene.uViewUpSceneTime.w; + + vec2 tcLayer0 = transformADTUV(vTexCoord, 0, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer1 = transformADTUV(vTexCoord, 1, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer2 = transformADTUV(vTexCoord, 2, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + + int layerHeight0 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.x; + int layerHeight1 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.y; + int layerHeight2 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.z; + int layerHeight3 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.w; + + int txLayer0 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.x; + int txLayer1 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.y; + int txLayer2 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.z; + int txLayer3 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.w; + + vec4 heightScale = adtMeshWideVSPS.uHeightScale; + vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; + + vec4 final; + if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { + calcADTHeightFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + s_LayerHeightTextures[nonuniformEXT(layerHeight0)], s_LayerHeightTextures[nonuniformEXT(layerHeight1)], + s_LayerHeightTextures[nonuniformEXT(layerHeight2)], s_LayerHeightTextures[nonuniformEXT(layerHeight3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + heightOffset, heightScale, + final + ); + } else { + calcADTOrigFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + final + ); + } + + vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; + + +// vec4 finalColor = vec4( +// calcLight( +// matDiffuse, +// vNormal, +// true, +// 0.0, +// scene, +// intLight, +// vVertexLighting.rgb, /* accumLight */ +// vec3(0.0), /*precomputedLight*/ +// vec3(0.0), /* specular */ +// vec3(0.0) /* emissive */ +// ), +// 1.0 +// ); + + vec4 finalColor = vec4(matDiffuse, 1.0); + + //Spec part + float specBlend = final.a; + vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); + vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); + vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; + finalColor.rgb += specTerm; + +// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, +// vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); + + finalColor.a = 1.0; + + outColor = finalColor; + outNormal = vec4(normalize(vNormal), 0); + outViewPos = vec4(vPosition, 0); + outMatProps = 0; +} diff --git a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert new file mode 100644 index 000000000..0a560bee4 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert @@ -0,0 +1,68 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_ARB_shader_draw_parameters: require + + +precision highp float; +precision highp int; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonADTMaterial.glsl" + +/* vertex shader code */ +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec4 aColor; +layout(location = 2) in vec4 aVertexLighting; +layout(location = 3) in vec3 aNormal; + +#include "../../../common/commonUboSceneData.glsl" +#include "../../../common/commonAdtIndirectDescriptorSet.glsl" + + +mat3 blizzTranspose(mat4 value) { + return mat3( + value[0].xyz, + value[1].xyz, + value[2].xyz + ); +} + +layout(location = 0) out vec2 vChunkCoords; +layout(location = 1) out vec3 vPosition; +layout(location = 2) out vec4 vColor; +layout(location = 3) out vec3 vNormal; +layout(location = 4) out vec3 vVertexLighting; +layout(location = 5) out vec2 vAlphaCoords; +layout(location = 6) out flat int vMeshIndex; + +void main() { + AdtInstanceData adtInstanceData = adtInstanceDatas[gl_InstanceIndex]; + AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x]; + +/* + Y + X 0 1 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 16 +*/ + + //With current implementation ADT's VBO is combined buffer, which contains all vertexes from all MCNK of ADT + //Thus, we first need to get vertexNumber within MCNK + + int indexInMCNK = (gl_VertexIndex - gl_BaseVertexARB) % (9 * 9 + 8 * 8); + calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords); + + vec4 worldPoint = vec4(aPos, 1); + + mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); + + vPosition = (scene.uLookAtMat * worldPoint).xyz; + vNormal = normal; + vColor = aColor; + vVertexLighting = aVertexLighting.rgb; + vMeshIndex = gl_InstanceIndex; + + gl_Position = scene.uPMatrix * scene.uLookAtMat * worldPoint; +} diff --git a/wowViewerLib/shaders/glsl/bindless/m2Shader.frag b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/m2Shader.frag rename to wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag diff --git a/wowViewerLib/shaders/glsl/bindless/m2Shader.vert b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.vert similarity index 88% rename from wowViewerLib/shaders/glsl/bindless/m2Shader.vert rename to wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.vert index cc0b09743..5fa7edd2c 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2Shader.vert +++ b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.vert @@ -7,11 +7,11 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonFunctions.glsl" -#include "../common/commonM2Material.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonFunctions.glsl" +#include "../../../common/commonM2Material.glsl" +#include "../../../common/commonUboSceneData.glsl" /* vertex shader code */ layout(location=0) in vec3 aPosition; @@ -22,7 +22,7 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; //Whole model -#include "../common/commonM2IndirectDescriptorSet.glsl" +#include "../../../common/commonM2IndirectDescriptorSet.glsl" //Shader output layout(location=0) out vec2 vTexCoord; diff --git a/wowViewerLib/shaders/glsl/bindless/m2Shader_nonopaq.frag b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_nonopaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/m2Shader_nonopaq.frag rename to wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_nonopaq.frag diff --git a/wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl similarity index 96% rename from wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl rename to wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl index 2b37ed558..2c8dd0eee 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl @@ -1,9 +1,9 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonM2Material.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonM2Material.glsl" layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; @@ -19,10 +19,10 @@ layout(location = 3) out uint outMatProps; #endif -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonUboSceneData.glsl" //Whole model -#include "../common/commonM2IndirectDescriptorSet.glsl" +#include "../../../common/commonM2IndirectDescriptorSet.glsl" layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; diff --git a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag similarity index 92% rename from wowViewerLib/shaders/glsl/bindless/m2ParticleShader_text.glsl rename to wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag index daef08bc6..4e756f0ba 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag @@ -1,3 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + precision highp float; precision highp int; @@ -9,11 +13,9 @@ layout(location = 3) in vec2 vTexcoord1; layout(location = 4) in vec2 vTexcoord2; layout(location = 5) in float alphaCutoff; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" - - +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonUboSceneData.glsl" //Individual meshes layout(std140, set=1, binding=0) uniform meshWideBlockPS { @@ -37,7 +39,7 @@ void main() { float colorMult = uAlphaTest_alphaMult_colorMult.z; if(tex.a < uAlphaTest) - discard; + discard; vec4 finalColor = vec4((tex * vColor ).rgb, tex.a*vColor.a ); int uNonOptPixelShader = uPixelShaderBlendModev.x; diff --git a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.vert b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.vert similarity index 86% rename from wowViewerLib/shaders/glsl/bindless/m2ParticleShader.vert rename to wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.vert index 9b7b1155a..6075a8b6b 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.vert @@ -20,10 +20,10 @@ layout(location = 3) out vec2 vTexcoord1; layout(location = 4) out vec2 vTexcoord2; layout(location = 5) out float vAlphaCutoff; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonUboSceneData.glsl" void main() { diff --git a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag deleted file mode 100644 index a76d9d621..000000000 --- a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader.frag +++ /dev/null @@ -1,5 +0,0 @@ -#version 450 -#extension GL_GOOGLE_include_directive: require -#extension GL_EXT_nonuniform_qualifier : require - -#include "m2ParticleShader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag b/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag deleted file mode 100644 index 6eb3b82a6..000000000 --- a/wowViewerLib/shaders/glsl/bindless/m2ParticleShader_nonopaq.frag +++ /dev/null @@ -1,7 +0,0 @@ -#version 450 -#extension GL_GOOGLE_include_directive: require -#extension GL_EXT_nonuniform_qualifier : require - -#define NON_OPAQ_SHADER - -#include "m2ParticleShader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/waterShader.frag b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag similarity index 95% rename from wowViewerLib/shaders/glsl/bindless/waterShader.frag rename to wowViewerLib/shaders/glsl/bindless/water/waterShader.frag index 06b507555..362eb7c29 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag @@ -3,8 +3,8 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier: require -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" precision highp float; precision highp int; @@ -14,8 +14,8 @@ layout(location=1) in vec2 vTextCoords; layout(location=2) in vec3 vNormal; layout(location=3) in flat int meshInd; -#include "../common/commonUboSceneData.glsl" -#include "../common/commonWaterIndirect.glsl" +#include "../../common/commonUboSceneData.glsl" +#include "../../common/commonWaterIndirect.glsl" layout(location = 0) out vec4 outColor; diff --git a/wowViewerLib/shaders/glsl/bindless/waterShader.vert b/wowViewerLib/shaders/glsl/bindless/water/waterShader.vert similarity index 85% rename from wowViewerLib/shaders/glsl/bindless/waterShader.vert rename to wowViewerLib/shaders/glsl/bindless/water/waterShader.vert index cd28fabe6..46ef1f489 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/water/waterShader.vert @@ -6,14 +6,14 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonUboSceneData.glsl" layout(location=0) in vec4 aPositionTransp; layout(location=1) in vec2 aTexCoord; -#include "../common/commonWaterIndirect.glsl" +#include "../../common/commonWaterIndirect.glsl" //out vec2 vTexCoord; layout(location=0) out vec3 vPosition; diff --git a/wowViewerLib/shaders/glsl/bindless/waterfallShader.frag b/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag similarity index 94% rename from wowViewerLib/shaders/glsl/bindless/waterfallShader.frag rename to wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag index ac7f6d040..fb202edea 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag @@ -6,10 +6,10 @@ precision highp float; precision highp int; -#include "../common/commonFunctions.glsl" -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../common/commonFunctions.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonUboSceneData.glsl" layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; @@ -29,8 +29,8 @@ layout(location = 3) out uint outMatProps; //Whole model -#include "../common/commonM2IndirectDescriptorSet.glsl" -#include "../common/commonM2WaterfallDescriptorSet.glsl" +#include "../../common/commonM2IndirectDescriptorSet.glsl" +#include "../../common/commonM2WaterfallDescriptorSet.glsl" const InteriorLightParam intLightWaterfall = { vec4(0,0,0,0), diff --git a/wowViewerLib/shaders/glsl/bindless/waterfallShader.vert b/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert similarity index 89% rename from wowViewerLib/shaders/glsl/bindless/waterfallShader.vert rename to wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert index 950371a99..5a39beb4b 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert @@ -6,11 +6,11 @@ precision highp float; precision highp int; -#include "../common/commonFunctions.glsl" -#include "../common/commonM2Material.glsl" -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../common/commonFunctions.glsl" +#include "../../common/commonM2Material.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonUboSceneData.glsl" precision highp float; @@ -23,8 +23,8 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; -#include "../common/commonM2IndirectDescriptorSet.glsl" -#include "../common/commonM2WaterfallDescriptorSet.glsl" +#include "../../common/commonM2IndirectDescriptorSet.glsl" +#include "../../common/commonM2WaterfallDescriptorSet.glsl" //Shader output diff --git a/wowViewerLib/shaders/glsl/bindless/wmoShader.frag b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag similarity index 92% rename from wowViewerLib/shaders/glsl/bindless/wmoShader.frag rename to wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag index 39c3e8f4d..06e68bcf0 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag @@ -7,11 +7,11 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonFunctions.glsl" -#include "../common/commonWMOMaterial.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonFunctions.glsl" +#include "../../../common/commonWMOMaterial.glsl" +#include "../../../common/commonUboSceneData.glsl" @@ -27,7 +27,7 @@ layout(location=8) in vec3 vNormal; layout(location=9) in flat int vMeshIndex; -#include "../common/commonWMOIndirectDescriptorSet.glsl" +#include "../../../common/commonWMOIndirectDescriptorSet.glsl" layout(set=2, binding=0) uniform sampler2D s_Textures[]; diff --git a/wowViewerLib/shaders/glsl/bindless/wmoShader.vert b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.vert similarity index 86% rename from wowViewerLib/shaders/glsl/bindless/wmoShader.vert rename to wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.vert index d36869bf3..cbf1f07cf 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmoShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.vert @@ -5,10 +5,10 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonFunctions.glsl" -#include "../common/commonWMOMaterial.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonFunctions.glsl" +#include "../../../common/commonWMOMaterial.glsl" /* vertex shader code */ layout (location = 0) in vec3 aPosition; @@ -21,8 +21,8 @@ layout (location = 6) in vec4 aColor; layout (location = 7) in vec4 aColor2; layout (location = 8) in vec4 aColorSecond; -#include "../common/commonUboSceneData.glsl" -#include "../common/commonWMOIndirectDescriptorSet.glsl" +#include "../../../common/commonUboSceneData.glsl" +#include "../../../common/commonWMOIndirectDescriptorSet.glsl" layout(location=0) out vec2 vTexCoord; layout(location=1) out vec2 vTexCoord2; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d0c71b344..5c2126d3e 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -72,6 +72,30 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; +struct waterwaterShader { + enum class Attribute { + aPositionTransp = 0, aTexCoord = 1, waterwaterShaderAttributeEnd + }; +}; + +struct forwardm2ParticleShader { + enum class Attribute { + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, forwardm2ParticleShaderAttributeEnd + }; +}; + +struct forwardm2Shader { + enum class Attribute { + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, forwardm2ShaderAttributeEnd + }; +}; + +struct visbuferadtShader { + enum class Attribute { + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, visbuferadtShaderAttributeEnd + }; +}; + struct waterfallShader { enum class Attribute { aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd @@ -108,6 +132,12 @@ struct m2ParticleShader { }; }; +struct forwardwmoShader { + enum class Attribute { + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, forwardwmoShaderAttributeEnd + }; +}; + struct drawFrustumShader { enum class Attribute { aPosition = 0, drawFrustumShaderAttributeEnd @@ -150,6 +180,12 @@ struct renderFrameBufferShader { }; }; +struct waterfallwaterfallShader { + enum class Attribute { + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallwaterfallShaderAttributeEnd + }; +}; + struct wmoShader { enum class Attribute { aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd @@ -162,6 +198,12 @@ struct imguiShader { }; }; +struct forwardadtShader { + enum class Attribute { + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, forwardadtShaderAttributeEnd + }; +}; + struct drawLinesShader { enum class Attribute { aPosition = 0, drawLinesShaderAttributeEnd @@ -177,6 +219,40 @@ struct ribbonShader { std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { +{ "waterwaterShader", + { + { "aPositionTransp", 0}, + { "aTexCoord", 1}, + } +}, +{ "forwardm2ParticleShader", + { + { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + { "aTexcoord1", 3}, + { "aTexcoord2", 4}, + { "aAlphaCutoff", 5}, + } +}, +{ "forwardm2Shader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, +{ "visbuferadtShader", + { + { "aPos", 0}, + { "aColor", 1}, + { "aVertexLighting", 2}, + { "aNormal", 3}, + } +}, { "waterfallShader", { { "aPosition", 0}, @@ -222,6 +298,19 @@ const std::unordered_map> attributesPe { "aAlphaCutoff", 5}, } }, +{ "forwardwmoShader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "aTexCoord", 2}, + { "aTexCoord2", 3}, + { "aTexCoord3", 4}, + { "aTexCoord4", 5}, + { "aColor", 6}, + { "aColor2", 7}, + { "aColorSecond", 8}, + } +}, { "drawFrustumShader", { { "aPosition", 0}, @@ -262,6 +351,16 @@ const std::unordered_map> attributesPe { "a_position", 0}, } }, +{ "waterfallwaterfallShader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, { "wmoShader", { { "aPosition", 0}, @@ -283,6 +382,14 @@ const std::unordered_map> attributesPe { "Color", 2}, } }, +{ "forwardadtShader", + { + { "aPos", 0}, + { "aColor", 1}, + { "aVertexLighting", 2}, + { "aNormal", 3}, + } +}, { "drawLinesShader", { { "aPosition", 0}, @@ -298,7 +405,7 @@ const std::unordered_map> attributesPe }; const std::unordered_map shaderMetaInfo = { -{ "bindless/waterfallShader.vert.spv", +{ "bindless/wmo/forwardwmoShader.vert.spv", { ShaderStage::Vertex, { @@ -317,27 +424,21 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, {1,6,0}, - {1,3,0}, + {1,4,0}, {1,1,0}, {1,2,0}, - {1,4,0}, + {1,3,0}, {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -346,7 +447,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterfallShader.frag.spv", +{ "bindless/wmo/forwardwmoShader.frag.spv", { ShaderStage::Fragment, { @@ -365,24 +466,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, + {1,6,0}, {1,4,0}, + {1,3,0}, {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, + {1,1,0}, + {1,2,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -390,11 +485,12 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "bindless/ribbonShader.vert.spv", +{ "bindless/waterwaterShader.vert.spv", { ShaderStage::Vertex, { @@ -413,14 +509,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -430,9 +530,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2Shader.vert.spv", +{ "bindless/waterwaterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -449,23 +549,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, + {1,0,0}, + {1,1,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -475,7 +570,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterShader.vert.spv", +{ "bindless/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -494,18 +589,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -515,9 +606,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2Shader.frag.spv", +{ "bindless/m2Particle/forwardm2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -534,24 +625,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -561,7 +642,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2ParticleShader_nonopaq.frag.spv", +{ "bindless/m2Particle/forwardm2ParticleShader.frag.spv", { ShaderStage::Fragment, { @@ -601,18 +682,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "bindless/m2/forwardm2Shader_nonopaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, - {1,1,16}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -622,14 +701,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -639,24 +728,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "bindless/waterfallwaterfallShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -665,16 +747,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {3,3, "uBumpTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -683,17 +776,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "bindless/m2/forwardm2Shader.vert.spv", { ShaderStage::Vertex, { {0,0,544}, - {1,0,64}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -703,6 +795,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -720,16 +821,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "bindless/m2/forwardm2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, - {1,0,96}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -737,17 +836,28 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,1,0}, + {1,6,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -757,14 +867,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "bindless/adt/visbuferadtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -775,6 +886,9 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { }, @@ -792,7 +906,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterShader.frag.spv", +{ "bindless/adt/visbuferadtShader.frag.spv", { ShaderStage::Fragment, { @@ -811,18 +925,59 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, + {1,3,0}, {1,1,0}, + {1,2,0}, }, { - {2,0, "s_Textures"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, {0,0,1}, + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "bindless/adt/forwardadtShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,3,0}, + {1,1,0}, + {1,2,0}, + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -832,16 +987,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { + {1,0,64}, {0,0,544}, + {1,1,16}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -868,18 +1025,63 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2Shader_nonopaq.frag.spv", +{ "forwardRendering/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {2,0,112}, + {1,5,4096}, + {1,2,16384}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { {0,0,1}, + {0,5,6}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {3,3, "uBumpTexture"}, + }, + { + { {0,0,0}, {0,0,0}, {0,0,0}, + {3,3,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/waterShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + {1,0,64}, + }, + { + { + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -887,42 +1089,68 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "forwardRendering/skyConus.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,544}, + {1,0,96}, + }, + { + { + {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -950,7 +1178,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { @@ -986,15 +1214,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1022,17 +1250,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2ParticleShader.frag.spv", +{ "forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1044,15 +1271,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1062,14 +1286,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,128}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1082,12 +1307,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1098,15 +1322,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/wmoShader.frag.spv", +{ "forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1117,19 +1340,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, + {1,0, "Texture"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1137,6 +1353,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } @@ -1335,48 +1552,6 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, { "forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, @@ -1570,16 +1745,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adtShader.vert.spv", +{ "forwardRendering/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,2,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1589,17 +1765,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1609,17 +1791,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,2,32}, - {0,0,544}, + {0,1,32}, }, { { - {0,0,1}, - {2,2,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1631,21 +1812,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, + {1,0, "texture0"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, - {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1655,15 +1828,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "bindless/adt/forwardadtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,32}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1674,17 +1847,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {1,0, "texture0"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { - {0,0,0}, - {0,0,1}, - {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1851,7 +2029,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/wmoShader.vert.spv", +{ "bindless/waterfallwaterfallShader.vert.spv", { ShaderStage::Vertex, { @@ -1870,21 +2048,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, {1,6,0}, - {1,4,0}, + {1,3,0}, {1,1,0}, {1,2,0}, - {1,3,0}, + {1,4,0}, {1,5,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2226,42 +2410,6 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2ParticleShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, { "forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, @@ -2419,11 +2567,56 @@ const std::unordered_map shaderMetaInfo = { }; const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { + {"waterwaterShader", { { - 9, { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, + { + 0, { + } + }, + }}, + {"forwardm2ParticleShader", { + { + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, + {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, + {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, + {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, + {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, + {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, + {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, + {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, + {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, + {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, + {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, + {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, + {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, + {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, + {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, + {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, + {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, + {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, + {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, + {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, } }, + }}, + {"forwardm2Shader", { { 8, { } @@ -2434,7 +2627,8 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"m2ParticleShader_nonopaq", { + {"waterwaterShader", { + { + 1, { + {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + } + }, + { + 2, { + } + }, + { + 0, { + } + }, + }}, + {"forwardm2ParticleShader", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, @@ -2905,22 +3325,25 @@ const std::unordered_map MapSceneRenderBindlessVLK::chooseRenderPass(cons } } +std::string MapSceneRenderBindlessVLK::chooseShadDir(const std::string &shaderName) { + if (useVisBuffer) { + return "visbuffer/"+shaderName; + } else { + return "forward/"+shaderName; + } +} + void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -241,7 +249,7 @@ void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { pipelineTemplate.backFaceCulling = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; - g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtVisShaderConfig) + g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("adtShader"), chooseShadDir("adtShader")}, adtBindlessShaderConfig) .createPipeline(m_emptyADTVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -271,7 +279,7 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global water descriptor for bindless textures - g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) + g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { @@ -297,7 +305,7 @@ void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global wmo descriptor for bindless textures - g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("wmoShader"), chooseShadDir("wmoShader")}, wmoBindlessShaderConfig) .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -326,7 +334,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global m2 descriptor for bindless textures - g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2VisShaderConfig) + g_m2Material = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("m2Shader"), chooseShadDir("m2Shader")}, m2BindlessShaderConfig) .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -349,7 +357,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { m2TextureHolder = std::make_shared(m2TexturesBindlessCount); } void MapSceneRenderBindlessVLK::createM2WaterfallGlobalMaterialData() { - MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallVisShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) .overridePipelineLayout({{1, m2BufferOneDS}}) .createDescriptorSet(2, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -375,7 +383,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMateri pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isOpaq ? "m2Shader" : "m2Shader_nonopaq"}, m2VisShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isOpaq ? "m2Shader" : "m2Shader_nonopaq"}, m2BindlessShaderConfig) .setMaterialId(generateUniqueM2MatId()) .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) @@ -396,7 +404,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMater } auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoVisShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) .setMaterialId(generateUniqueWMOMatId()) .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) @@ -668,7 +676,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Waterfa m2WaterfallBuffer.waterfallBindless); auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, - m2WaterfallVisShaderConfig) + m2WaterfallBindlessShaderConfig) .overridePipelineLayout({{1, m2BufferOneDS}}) .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) @@ -721,7 +729,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Particle bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", isOpaq ? "m2ParticleShader" : "m2ParticleShader_nonopaq"}, visShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", isOpaq ? "m2ParticleShader" : "m2ParticleShader_nonopaq"}, bindlessShaderConfig) .createPipeline(m_emptyM2ParticleVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { @@ -748,7 +756,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMate auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; - auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, visShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, bindlessShaderConfig) .createPipeline(m_emptyM2RibbonVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { @@ -830,7 +838,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(c auto l_waterBindless = std::make_shared>(waterBuffer.waterBindlessBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterVisShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index ac0cccce9..83610dab7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -140,6 +140,7 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::unique_ptr glowPass; + bool useVisBuffer = false; HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; @@ -248,6 +249,8 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { MeshCount lastMeshCount; + std::string chooseShadDir(const std::string &shaderName); + void createM2GlobalMaterialData(); void createWMOGlobalMaterialData(); void createADTGlobalMaterialData(); From c745431dc629da61b3487e4eaa917301609977b3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 13 Mar 2024 22:27:08 +0200 Subject: [PATCH 175/212] - restored forward bindless --- src/ui/FrontendUI.cpp | 2 +- .../fileListWindow/FileListWindow.cpp | 39 +- wowViewerLib/CMakeLists.txt | 3 +- wowViewerLib/shaders/CMakeLists.txt | 25 +- .../glsl/bindless/adt/adtShader_text.glsl | 137 ++ .../glsl/bindless/adt/deferred/adtShader.frag | 8 + .../glsl/bindless/adt/forward/adtShader.frag | 128 +- .../m2Shader_opaq_deferred.frag} | 4 +- .../glsl/bindless/m2/forward/m2Shader.frag | 2 +- .../bindless/m2/forward/m2shader_text.glsl | 201 -- .../glsl/bindless/m2/m2shader_text.glsl | 188 ++ .../m2ParticleShader_opaq_deferred.frag | 7 + .../m2Particle/forward/m2ParticleShader.frag | 104 +- .../m2Particle/m2ParticleShader_text.glsl | 118 + .../{ => m2Ribbon/forward}/ribbonShader.frag | 18 +- .../{ => m2Ribbon/forward}/ribbonShader.vert | 6 +- .../bindless/m2Ribbon/ribbonShader_text.glsl | 0 .../waterFallShader_opaq_defferred.frag | 7 + .../waterfall/forward/waterfallShader.frag | 6 + .../{ => forward}/waterfallShader.vert | 14 +- ...lShader.frag => waterFallShader_text.glsl} | 35 +- .../wmo/deferred/wmoShader_opaq_deferred.frag | 7 + .../glsl/bindless/wmo/forward/wmoShader.frag | 104 +- .../glsl/bindless/wmo/wmoshader_text.glsl | 110 + .../glsl/common/commonLightFunctions.glsl | 4 +- .../common/commonM2IndirectDescriptorSet.glsl | 1 - .../glsl/forwardRendering/m2Shader.frag | 2 +- .../shaders/src/spirv/dumpShaderFields.h | 1 + wowViewerLib/src/engine/geometry/m2Geom.cpp | 2 +- .../src/engine/geometry/wmoGroupGeom.cpp | 2 +- .../src/engine/geometry/wmoMainGeom.cpp | 2 +- .../src/engine/persistance/adtFile.cpp | 2 +- .../src/engine/persistance/animFile.cpp | 2 +- .../persistance/helper/ChunkFileReader.h | 12 +- .../src/engine/persistance/skelFile.cpp | 2 +- .../src/engine/persistance/wdlFile.cpp | 2 +- .../src/engine/persistance/wdtFile.cpp | 2 +- .../src/engine/shader/ShaderDefinitions.h | 2139 ++++++++--------- .../src/gapi/UniformBufferStructures.h | 2 +- .../CommandBufferRecorder.cpp | 1 + .../vulkan/shaders/GShaderPermutationVLK.cpp | 4 +- wowViewerLib/src/gapi/vulkan/vkAllocator.cpp | 1 + wowViewerLib/src/include/database/dbStructs.h | 1 + .../renderer/mapScene/MapSceneRenderer.cpp | 5 +- .../src/renderer/mapScene/MapSceneRenderer.h | 5 +- .../mapScene/MapSceneRendererFactory.cpp | 2 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 94 +- .../vulkan/MapSceneRenderBindlessVLK.h | 34 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 1 + .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../mapScene/vulkan/MapSceneRenderVisVLK.cpp | 1500 ++++++++++++ .../mapScene/vulkan/MapSceneRenderVisVLK.h | 98 + .../mapScene/vulkan/view/IRenderViewVLK.h | 8 + .../vulkan/view/RenderViewDeferredVLK.cpp | 10 +- .../vulkan/view/RenderViewForwardVLK.cpp | 19 +- .../vulkan/view/RenderViewForwardVLK.h | 5 +- 56 files changed, 3319 insertions(+), 1921 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl create mode 100644 wowViewerLib/shaders/glsl/bindless/adt/deferred/adtShader.frag rename wowViewerLib/shaders/glsl/bindless/m2/{forward/m2Shader_nonopaq.frag => deferred/m2Shader_opaq_deferred.frag} (67%) delete mode 100644 wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl create mode 100644 wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl create mode 100644 wowViewerLib/shaders/glsl/bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl rename wowViewerLib/shaders/glsl/bindless/{ => m2Ribbon/forward}/ribbonShader.frag (77%) rename wowViewerLib/shaders/glsl/bindless/{ => m2Ribbon/forward}/ribbonShader.vert (80%) create mode 100644 wowViewerLib/shaders/glsl/bindless/m2Ribbon/ribbonShader_text.glsl create mode 100644 wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.frag rename wowViewerLib/shaders/glsl/bindless/waterfall/{ => forward}/waterfallShader.vert (89%) rename wowViewerLib/shaders/glsl/bindless/waterfall/{waterfallShader.frag => waterFallShader_text.glsl} (91%) create mode 100644 wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.h create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/view/IRenderViewVLK.h diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index a4a6332fc..c86724da3 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -117,7 +117,7 @@ void FrontendUI::composeUI() { } - static bool show_demo_window = true; + static bool show_demo_window = false; if (show_demo_window) ImGui::ShowDemoWindow(&show_demo_window); diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 5a905d5c1..36dd01064 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -258,8 +258,9 @@ class my_container { storage store_; }; +const bool processFileOnDetect = true; -std::string detectFileType(const HFileContent &fileContent) { +std::string detectFileType(int fileDataId, const HFileContent &fileContent) { std::string fileType = "unk"; if (fileContent == nullptr) return fileType; @@ -269,27 +270,16 @@ std::string detectFileType(const HFileContent &fileContent) { uint32_t magic = *(uint32_t *)fileContent->data(); magic = ntohl(magic); -// if (magic[0] == 0 || magic[0] == 4) -// { -// if (bin.BaseStream.Length >= 8) -// { -// var wwfMagic = bin.ReadUInt32(); -// switch (wwfMagic) -// { -// case 0x932C64B4: // WWFParticulateGroup -// type = "wwf"; -// break; -// } -// } -// -// bin.BaseStream.Position = 4; -// } switch (magic) { case 'MD21': case 'MD20': fileType = "m2"; + if (processFileOnDetect) { + M2Geom test = M2Geom(fileDataId); + test.process(fileContent, std::to_string(fileDataId)); + } break; case 'SKIN': fileType = "skin"; @@ -323,12 +313,27 @@ std::string detectFileType(const HFileContent &fileContent) { break; case 'DHOM': // WMO root fileType = "wmo"; + + if (processFileOnDetect) { + WmoMainGeom test = WmoMainGeom(fileDataId); + test.process(fileContent, std::to_string(fileDataId)); + } break; case 'PGOM': // WMO GROUP fileType = "gwmo"; + + if (processFileOnDetect) { + WmoGroupGeom test = WmoGroupGeom(fileDataId); + test.process(fileContent, std::to_string(fileDataId)); + } break; case 'DHPM': // WDT root fileType = "wdt"; + + if (processFileOnDetect) { + WdtFile test = WdtFile(fileDataId); + test.process(fileContent, std::to_string(fileDataId)); + } break; case 'IOAM': // WDT OCC/LGT fileType = "wdt_sec"; @@ -431,7 +436,7 @@ class FileListLambdaInst : public FileListLamda { return fileRecord.fileType.empty(); }, [&statement, &storage](int fileDataId, const HFileContent &fileData) -> void { - auto fileType = detectFileType(fileData); + auto fileType = detectFileType(fileDataId, fileData); statement->setFileType(storage, fileDataId, fileType); } ); diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 6342c2969..fb115c880 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -633,7 +633,8 @@ if (LINK_VULKAN) # install(FILES ${Vulkan_LIBRARY_DIR}/libMoltenVK.dylib DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() #Add volk loader - set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c) + set(VULKAN_IMPLEMENTATION ${VULKAN_IMPLEMENTATION} src/gapi/vulkan/volk.c + src/renderer/mapScene/vulkan/view/IRenderViewVLK.h) endif() diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 711713c4e..8276acbf8 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -75,20 +75,22 @@ endif() -macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 destDirGL33 ) +macro(configure_filesVLK rootDir srcCommonDirs shaderDirs destDir destDirGL20 destDirGL33 ) message(STATUS "Configuring directory ${destDir}") set(spirvNonOptDir ${CMAKE_BINARY_DIR}/spriv_raw) file(MAKE_DIRECTORY ${spirvNonOptDir}) - file(GLOB_RECURSE commonFilesRelative RELATIVE ${srcCommonDir} ${srcCommonDir}/*.glsl) + foreach(srcCommonDir ${srcCommonDirs}) + file(GLOB_RECURSE commonFilesRelative RELATIVE ${srcCommonDir} ${srcCommonDir}/*.glsl) - foreach(commonFileRelative ${commonFilesRelative}) - set(commonFileFullPath ${srcCommonDir}/${commonFileRelative}) - if(NOT IS_DIRECTORY ${commonFileFullPath}) - list(APPEND commonFiles ${commonFileFullPath}) - endif() - endforeach(commonFileRelative) + foreach(commonFileRelative ${commonFilesRelative}) + set(commonFileFullPath ${srcCommonDir}/${commonFileRelative}) + if(NOT IS_DIRECTORY ${commonFileFullPath}) + list(APPEND commonFiles ${commonFileFullPath}) + endif() + endforeach(commonFileRelative) + endforeach(srcCommonDir) foreach(shaderDir ${shaderDirs}) set(srcDir "${rootDir}/${shaderDir}") @@ -105,6 +107,9 @@ macro(configure_filesVLK rootDir srcCommonDir shaderDirs destDir destDirGL20 des get_filename_component(FILE_NAME_WO_EXT ${srcTemplatePath} NAME_WE) get_filename_component(FILE_NAME ${srcTemplatePath} NAME) get_filename_component(SHADER_SUB_DIR ${srcFileRelative} DIRECTORY ) + if (SHADER_SUB_DIR) + set(SHADER_SUB_DIR "${SHADER_SUB_DIR}/") + endif() # file(RELATIVE_PATH SHADER_SUB_DIR shaderDir ${srcTemplatePath}) # message(srcFileRelative = ${srcFileRelative}) @@ -193,8 +198,8 @@ endmacro(configure_filesVLK) configure_filesVLK( ${PROJECT_SOURCE_DIR}/shaders/glsl/ - ${PROJECT_SOURCE_DIR}/shaders/glsl/common - "forwardRendering;bindless" + "${PROJECT_SOURCE_DIR}/shaders/glsl/common;${PROJECT_SOURCE_DIR}/shaders/glsl/bindless" + "." ${GLSL_TARGET_FOLDER}/spirv ${GLSL_TARGET_FOLDER}/glsl/glsl20/ ${GLSL_TARGET_FOLDER}/glsl/glsl3.3/) diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl new file mode 100644 index 000000000..f365ec8f3 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -0,0 +1,137 @@ +precision highp float; +precision highp int; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" + +#include "../../../common/commonADTMaterial.glsl" +#include "../../../common/commonAdtIndirectDescriptorSet.glsl" + +layout(location = 0) in vec2 vChunkCoords; +layout(location = 1) in vec3 vPosition; +layout(location = 2) in vec4 vColor; +layout(location = 3) in vec3 vNormal; +layout(location = 4) in vec3 vVertexLighting; +layout(location = 5) in vec2 vAlphaCoords; +layout(location = 6) in flat int meshIndex; + +layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; +layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; +layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; + +#include "../../../common/commonUboSceneData.glsl" + +#ifndef DEFERRED +layout(location = 0) out vec4 outColor; +#else +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; +#endif + +const InteriorLightParam intLight = { + vec4(0,0,0,0), + vec4(0,0,0,1) +}; + +void main() { + AdtInstanceData adtInstanceData = adtInstanceDatas[nonuniformEXT(meshIndex)]; + AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x)]; + AdtMeshWidePS adtMeshWidePS = adtMeshWidePSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.y)]; + + + vec2 vTexCoord = vChunkCoords; + const float threshold = 1.5; + + ivec4 animation_rotationPerLayer = adtMeshWidePS.animation_rotationPerLayer; + ivec4 animation_speedPerLayer = adtMeshWidePS.animation_speedPerLayer; + vec4 scaleFactorPerLayer = adtMeshWidePS.scaleFactorPerLayer; + float sceneTime = scene.uViewUpSceneTime.w; + + vec2 tcLayer0 = transformADTUV(vTexCoord, 0, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer1 = transformADTUV(vTexCoord, 1, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer2 = transformADTUV(vTexCoord, 2, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); + + int layerHeight0 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.x; + int layerHeight1 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.y; + int layerHeight2 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.z; + int layerHeight3 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.w; + + int txLayer0 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.x; + int txLayer1 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.y; + int txLayer2 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.z; + int txLayer3 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.w; + + vec4 heightScale = adtMeshWideVSPS.uHeightScale; + vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; + + vec4 final; + if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { + calcADTHeightFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + s_LayerHeightTextures[nonuniformEXT(layerHeight0)], s_LayerHeightTextures[nonuniformEXT(layerHeight1)], + s_LayerHeightTextures[nonuniformEXT(layerHeight2)], s_LayerHeightTextures[nonuniformEXT(layerHeight3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + heightOffset, heightScale, + final + ); + } else { + calcADTOrigFragMaterial( + tcLayer0, tcLayer1, tcLayer2, tcLayer3, + s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], + s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], + vAlphaCoords, + s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + final + ); + } + + vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; + + vec4 finalColor = vec4(matDiffuse, 1.0); + +#ifndef DEFERRED + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + true, + 0.0, + scene, + intLight, + vVertexLighting.rgb, /* accumLight */ + vec3(0.0), /*precomputedLight*/ + vec3(0.0), /* specular */ + vec3(0.0) /* emissive */ + ), + 1.0 + ); +#endif + + //Spec part + float specBlend = final.a; + vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); + vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); + vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; +#ifndef DEFERRED + finalColor.rgb += specTerm; +#endif + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); + + + finalColor.a = 1.0; + +#ifndef DEFERRED + outColor = finalColor; +#else + outAlbedo = vec4(matDiffuse.xyz, 0); + outNormal = vec4(normalize(vNormal), 0); + outSpecular = vec4(specTerm.rgb, 0); +#endif +} diff --git a/wowViewerLib/shaders/glsl/bindless/adt/deferred/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adt/deferred/adtShader.frag new file mode 100644 index 000000000..a6725f88d --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/adt/deferred/adtShader.frag @@ -0,0 +1,8 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED + +#include "./../adtShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag index b119d2c50..f2ce5a162 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.frag @@ -3,130 +3,4 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier : require -precision highp float; -precision highp int; - -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" - -#include "../../../common/commonADTMaterial.glsl" -#include "../../../common/commonAdtIndirectDescriptorSet.glsl" - -layout(location = 0) in vec2 vChunkCoords; -layout(location = 1) in vec3 vPosition; -layout(location = 2) in vec4 vColor; -layout(location = 3) in vec3 vNormal; -layout(location = 4) in vec3 vVertexLighting; -layout(location = 5) in vec2 vAlphaCoords; -layout(location = 6) in flat int meshIndex; - -layout (set = 2, binding = 0) uniform sampler2D s_LayerTextures[]; -layout (set = 3, binding = 0) uniform sampler2D s_AlphaTextures[]; -layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; - -#include "../../../common/commonUboSceneData.glsl" - -layout(location = 0) out vec4 outColor; -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outViewPos; -layout(location = 3) out uint outMatProps; - -const InteriorLightParam intLight = { - vec4(0,0,0,0), - vec4(0,0,0,1) -}; - -void main() { - AdtInstanceData adtInstanceData = adtInstanceDatas[nonuniformEXT(meshIndex)]; - AdtMeshWideVSPS adtMeshWideVSPS = adtMeshWideVSPSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.x)]; - AdtMeshWidePS adtMeshWidePS = adtMeshWidePSes[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.y)]; - - - vec2 vTexCoord = vChunkCoords; - const float threshold = 1.5; - - ivec4 animation_rotationPerLayer = adtMeshWidePS.animation_rotationPerLayer; - ivec4 animation_speedPerLayer = adtMeshWidePS.animation_speedPerLayer; - vec4 scaleFactorPerLayer = adtMeshWidePS.scaleFactorPerLayer; - float sceneTime = scene.uViewUpSceneTime.w; - - vec2 tcLayer0 = transformADTUV(vTexCoord, 0, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); - vec2 tcLayer1 = transformADTUV(vTexCoord, 1, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); - vec2 tcLayer2 = transformADTUV(vTexCoord, 2, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); - vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); - - int layerHeight0 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.x; - int layerHeight1 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.y; - int layerHeight2 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.z; - int layerHeight3 = adtInstanceData.LayerHeight0Ind_LayerHeight1Ind_LayerHeight2Ind_LayerHeight3Ind.w; - - int txLayer0 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.x; - int txLayer1 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.y; - int txLayer2 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.z; - int txLayer3 = adtInstanceData.Layer0Ind_Layer1Ind_Layer2Ind_Layer3Ind.w; - - vec4 heightScale = adtMeshWideVSPS.uHeightScale; - vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; - - vec4 final; - if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { - calcADTHeightFragMaterial( - tcLayer0, tcLayer1, tcLayer2, tcLayer3, - s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], - s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], - s_LayerHeightTextures[nonuniformEXT(layerHeight0)], s_LayerHeightTextures[nonuniformEXT(layerHeight1)], - s_LayerHeightTextures[nonuniformEXT(layerHeight2)], s_LayerHeightTextures[nonuniformEXT(layerHeight3)], - vAlphaCoords, - s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], - heightOffset, heightScale, - final - ); - } else { - calcADTOrigFragMaterial( - tcLayer0, tcLayer1, tcLayer2, tcLayer3, - s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], - s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], - vAlphaCoords, - s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], - final - ); - } - - vec3 matDiffuse = final.rgb * 2.0 * vColor.rgb; - - -// vec4 finalColor = vec4( -// calcLight( -// matDiffuse, -// vNormal, -// true, -// 0.0, -// scene, -// intLight, -// vVertexLighting.rgb, /* accumLight */ -// vec3(0.0), /*precomputedLight*/ -// vec3(0.0), /* specular */ -// vec3(0.0) /* emissive */ -// ), -// 1.0 -// ); - - vec4 finalColor = vec4(matDiffuse, 1.0); - - //Spec part - float specBlend = final.a; - vec3 halfVec = -(normalize((scene.extLight.uExteriorDirectColorDir.xyz + normalize(vPosition)))); - vec3 lSpecular = ((scene.extLight.uExteriorDirectColor.xyz * pow(max(0.0, dot(halfVec, normalize(vNormal))), 20.0))); - vec3 specTerm = (vec3(specBlend) * lSpecular) * scene.extLight.adtSpecMult_fogCount.x; - finalColor.rgb += specTerm; - -// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, -// vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, 0); - - finalColor.a = 1.0; - - outColor = finalColor; - outNormal = vec4(normalize(vNormal), 0); - outViewPos = vec4(vPosition, 0); - outMatProps = 0; -} +#include "../adtShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_nonopaq.frag b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq_deferred.frag similarity index 67% rename from wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_nonopaq.frag rename to wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq_deferred.frag index d62526f5b..bd6cb5313 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_nonopaq.frag +++ b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq_deferred.frag @@ -2,6 +2,6 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier : require -#define NON_OPAQ_SHADER +#define DEFERRED -#include "m2shader_text.glsl" \ No newline at end of file +#include "../m2shader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag index 88a4e81fd..99c0b8990 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader.frag @@ -3,4 +3,4 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier : require -#include "m2shader_text.glsl" \ No newline at end of file +#include "../m2shader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl deleted file mode 100644 index 2c8dd0eee..000000000 --- a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2shader_text.glsl +++ /dev/null @@ -1,201 +0,0 @@ -precision highp float; -precision highp int; - -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonM2Material.glsl" - -layout(location=0) in vec2 vTexCoord; -layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec3 vNormal; -layout(location=3) in vec4 vPosition_EdgeFade; -layout(location=4) in flat int vMeshIndex; - -layout(location = 0) out vec4 outColor; -#ifndef NON_OPAQ_SHADER -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outViewPos; -layout(location = 3) out uint outMatProps; -#endif - - -#include "../../../common/commonUboSceneData.glsl" - -//Whole model -#include "../../../common/commonM2IndirectDescriptorSet.glsl" - -layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; - -void main() { - /* Animation support */ - vec2 texCoord = vTexCoord.xy; - vec2 texCoord2 = vTexCoord2.xy; - vec2 texCoord3 = vTexCoord2.xy; - - vec4 finalColor = vec4(0); - - meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[vMeshIndex]; - meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; - - int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; - M2InstanceRecordBindless m2Instance = instances[nonuniformEXT(instanceIndex)]; - - modelWideBlockPSStruct modelWide = modelWides[m2Instance.textureMatricesInd_modelFragmentDatasInd.y]; - - - int placementMatrixInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; - int textureWeightsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.w; - int m2ColorsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.z; - int textureMatricesInd = m2Instance.textureMatricesInd_modelFragmentDatasInd.x; - - vec3 uTexSampleAlpha = vec3( - meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], - meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], - meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] - ); - - vec4 vMeshColorAlpha = vec4( - meshWide.colorIndex_applyWeight.x < 0 ? - vec4(1.0,1.0,1.0,1.0) : - colors[m2ColorsInd + meshWide.colorIndex_applyWeight.x] - ); - if (meshWide.colorIndex_applyWeight.y > 0) - vMeshColorAlpha.a *= - meshWide.textureWeightIndexes.x < 0 ? - 1.0 : - textureWeight[textureWeightsInd + meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; - - vec3 l_Normal = vNormal; - - //Accumulate and apply lighting - - vec3 meshResColor = vMeshColorAlpha.rgb; - - vec3 accumLight = vec3(0.0); - - if ((meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y == 1)) { - mat4 placementMat = uPlacementMats[placementMatrixInd]; - - vec3 vPos3 = vPosition_EdgeFade.xyz; - vec3 vNormal3 = normalize(l_Normal.xyz); - vec3 lightColor = vec3(0.0); - int count = int(modelWide.pc_lights[0].attenuation.w); - - for (int index = 0; index < 4; index++) - { - if (index >= modelWide.lightCountAndBcHack.x) break; - - LocalLight lightRecord = modelWide.pc_lights[index]; - vec3 vectorToLight = ((scene.uLookAtMat * (placementMat * lightRecord.position)).xyz - vPos3); - float distanceToLightSqr = dot(vectorToLight, vectorToLight); - float distanceToLightInv = inversesqrt(distanceToLightSqr); - float distanceToLight = (distanceToLightSqr * distanceToLightInv); - float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0); - vec4 attenuationRec = lightRecord.attenuation; - - float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); - - vec3 attenuatedColor = attenuation * lightRecord.color.xyz; - lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); - } - - meshResColor.rgb = clamp(lightColor , 0.0, 1.0); - accumLight = mix(lightColor.rgb, meshResColor.rgb, modelWide.lightCountAndBcHack.y); - //finalColor.rgb = finalColor.rgb * lightColor; - } - - //---------------------- - // Calc Diffuse and Specular - //--------------------- - int uVertexShader = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; - - mat4 textMat[2]; - int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; - int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; - - textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex1]; - textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex2]; - float edgeFade = 1.0; - - calcM2VertexMat(uVertexShader, - vPosition_EdgeFade.xyz, l_Normal, - vTexCoord, vTexCoord2, - textMat, edgeFade, - texCoord, texCoord2, texCoord3); - - vMeshColorAlpha *= edgeFade; - - float finalOpacity = 0.0; - vec3 matDiffuse; - vec3 specular; - - int uPixelShader = meshWide.PixelShader_UnFogged_blendMode.x; - int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; - - bool doDiscard = false; - - - calcM2FragMaterial(uPixelShader, - s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.x)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.y)], - s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.z)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.w)], - texCoord, texCoord2, texCoord3, - vMeshColorAlpha.rgb, vMeshColorAlpha.a, - uTexSampleAlpha.rgb, - blendMode, - matDiffuse, specular, finalOpacity, doDiscard - ); - - if (doDiscard) - discard; - - // ------------------------------ - // Apply lighting - // ------------------------------ - - // specular *= vMeshColorAlpha.rgb; - -// finalColor = vec4( -// calcLight( -// matDiffuse, -// l_Normal, -// meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, -// modelWide.interiorExteriorBlend.x, -// scene, -// modelWide.intLight, -// accumLight, -// vec3(0.0), -// specular, -// vec3(0.0) -// ) , -// finalOpacity -// ); - - finalColor = vec4(matDiffuse, finalOpacity); - - // ------------------------------ - // Apply Fog - // ------------------------------ - - int uUnFogged = meshWide.PixelShader_UnFogged_blendMode.y; - if (uUnFogged == 0) { - vec3 sunDir = - mix( - scene.uInteriorSunDir, - scene.extLight.uExteriorDirectColorDir, - modelWide.interiorExteriorBlend.x - ).xyz; - -// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, -// finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, -// meshWide.PixelShader_UnFogged_blendMode.z -// ); - } - - //Forward rendering without lights - outColor = finalColor; - #ifndef NON_OPAQ_SHADER - outNormal = vec4(normalize(vNormal), 0); - outViewPos = vec4(vPosition_EdgeFade.xyz, 0); - outMatProps = 0; - #endif -} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl new file mode 100644 index 000000000..e41f9af0b --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -0,0 +1,188 @@ +precision highp float; +precision highp int; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonM2Material.glsl" + +layout(location=0) in vec2 vTexCoord; +layout(location=1) in vec2 vTexCoord2; +layout(location=2) in vec3 vNormal; +layout(location=3) in vec4 vPosition_EdgeFade; +layout(location=4) in flat int vMeshIndex; + +#ifndef DEFERRED +layout(location = 0) out vec4 outColor; +#else +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; +#endif + +#include "../../../common/commonUboSceneData.glsl" + +//Whole model +#include "../../../common/commonM2IndirectDescriptorSet.glsl" + +layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; + +void main() { + /* Animation support */ + vec2 texCoord = vTexCoord.xy; + vec2 texCoord2 = vTexCoord2.xy; + vec2 texCoord3 = vTexCoord2.xy; + + vec4 finalColor = vec4(0); + + meshWideBlockVSPSBindless meshWideBindless = meshWideBindleses[vMeshIndex]; + meshWideBlockVSPS meshWide = meshWides[nonuniformEXT(meshWideBindless.instanceIndex_meshIndex.y)]; + + int instanceIndex = meshWideBindless.instanceIndex_meshIndex.x; + M2InstanceRecordBindless m2Instance = instances[nonuniformEXT(instanceIndex)]; + + modelWideBlockPSStruct modelWide = modelWides[m2Instance.textureMatricesInd_modelFragmentDatasInd.y]; + + bool calcMaterial = true; +#ifdef DEFERRED +// { +// int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; +// calcMaterial = (blendMode == 1); +// } +#endif + + + int placementMatrixInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.x; + int textureWeightsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.w; + int m2ColorsInd = m2Instance.placementMatrixInd_boneMatrixInd_m2ColorsInd_textureWeightsInd.z; + int textureMatricesInd = m2Instance.textureMatricesInd_modelFragmentDatasInd.x; + + vec3 uTexSampleAlpha = vec3( + meshWide.textureWeightIndexes.x < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4], + meshWide.textureWeightIndexes.y < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.y / 4][meshWide.textureWeightIndexes.y % 4], + meshWide.textureWeightIndexes.z < 0 ? 1.0 : textureWeight[textureWeightsInd+meshWide.textureWeightIndexes.z / 4][meshWide.textureWeightIndexes.z % 4] + ); + + vec4 vMeshColorAlpha = vec4( + meshWide.colorIndex_applyWeight.x < 0 ? + vec4(1.0,1.0,1.0,1.0) : + colors[m2ColorsInd + meshWide.colorIndex_applyWeight.x] + ); + if (meshWide.colorIndex_applyWeight.y > 0) + vMeshColorAlpha.a *= + meshWide.textureWeightIndexes.x < 0 ? + 1.0 : + textureWeight[textureWeightsInd + meshWide.textureWeightIndexes.x / 4][meshWide.textureWeightIndexes.x % 4]; + + vec3 l_Normal = vNormal; + + //Accumulate and apply lighting + + vec3 meshResColor = vMeshColorAlpha.rgb; + + vec3 accumLight = vec3(0.0); + + //Query light buffer + + + //---------------------- + // Calc Diffuse and Specular + //--------------------- + int uVertexShader = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.x; + + mat4 textMat[2]; + int textMatIndex1 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.z; + int textMatIndex2 = meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.w; + + textMat[0] = textMatIndex1 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex1]; + textMat[1] = textMatIndex2 < 0 ? mat4(1.0) : textureMatrix[textureMatricesInd + textMatIndex2]; + float edgeFade = 1.0; + + calcM2VertexMat(uVertexShader, + vPosition_EdgeFade.xyz, l_Normal, + vTexCoord, vTexCoord2, + textMat, edgeFade, + texCoord, texCoord2, texCoord3); + + vMeshColorAlpha *= edgeFade; + + float finalOpacity = 0.0; + vec3 matDiffuse; + vec3 specular; + + int uPixelShader = meshWide.PixelShader_UnFogged_blendMode.x; + int blendMode = meshWide.PixelShader_UnFogged_blendMode.z; + + bool doDiscard = false; + + if (calcMaterial) { + calcM2FragMaterial(uPixelShader, + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.x)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.y)], + s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.z)], s_Textures[nonuniformEXT(meshWideBindless.textureIndicies.w)], + texCoord, texCoord2, texCoord3, + vMeshColorAlpha.rgb, vMeshColorAlpha.a, + uTexSampleAlpha.rgb, + blendMode, + matDiffuse, specular, finalOpacity, doDiscard + ); + + if (doDiscard) + discard; + + // ------------------------------ + // Apply lighting + // ------------------------------ + + + specular *= vMeshColorAlpha.rgb; + +#ifndef DEFERRED + finalColor = vec4( + calcLight( + matDiffuse, + l_Normal, + meshWide.vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2.y > 0, + modelWide.interiorExteriorBlend.x, + scene, + modelWide.intLight, + accumLight, + vec3(0.0), + specular, + vec3(0.0) + ) , + finalOpacity + ); +#endif + + finalColor = vec4(matDiffuse, finalOpacity); + } + + // ------------------------------ + // Apply Fog + // ------------------------------ + +#ifndef DEFERRED + int uUnFogged = meshWide.PixelShader_UnFogged_blendMode.y; + if (uUnFogged == 0) { + vec3 sunDir = + mix( + scene.uInteriorSunDir_lightBufferIndex, + scene.extLight.uExteriorDirectColorDir, + modelWide.interiorExteriorBlend.x + ).xyz; + + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, + finalColor, scene.uViewUpSceneTime.xyz, vPosition_EdgeFade.xyz, sunDir.xyz, + meshWide.PixelShader_UnFogged_blendMode.z + ); + } +#endif + + //Forward rendering without lights +#ifndef DEFERRED + outColor = finalColor; +#else + outAlbedo = vec4(matDiffuse.xyz, 0.0); + outNormal = vec4(normalize(vNormal), 0.0); + outSpecular = vec4(specular.rgb, 0.0); +#endif +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag b/wowViewerLib/shaders/glsl/bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag new file mode 100644 index 000000000..dfa221570 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED + +#include "../m2ParticleShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag index 4e756f0ba..4c3c4fdb9 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/forward/m2ParticleShader.frag @@ -2,106 +2,4 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier : require - -precision highp float; -precision highp int; - -layout(location = 0) in vec3 vPosition; -layout(location = 1) in vec4 vColor; -layout(location = 2) in vec2 vTexcoord0; -layout(location = 3) in vec2 vTexcoord1; -layout(location = 4) in vec2 vTexcoord2; -layout(location = 5) in float alphaCutoff; - -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonUboSceneData.glsl" - -//Individual meshes -layout(std140, set=1, binding=0) uniform meshWideBlockPS { - vec4 uAlphaTest_alphaMult_colorMult; - ivec4 uPixelShaderBlendModev; -}; - -layout(set=2,binding=0) uniform sampler2D uTexture; -layout(set=2,binding=1) uniform sampler2D uTexture2; -layout(set=2,binding=2) uniform sampler2D uTexture3; - -layout(location = 0) out vec4 outputColor; - -void main() { - vec4 tex = texture(uTexture, vTexcoord0).rgba; - vec4 tex2 = texture(uTexture2, vTexcoord1).rgba; - vec4 tex3 = texture(uTexture3, vTexcoord2).rgba; - - float uAlphaTest = uAlphaTest_alphaMult_colorMult.x; - float alphaMult = uAlphaTest_alphaMult_colorMult.y; - float colorMult = uAlphaTest_alphaMult_colorMult.z; - - if(tex.a < uAlphaTest) - discard; - - vec4 finalColor = vec4((tex * vColor ).rgb, tex.a*vColor.a ); - int uNonOptPixelShader = uPixelShaderBlendModev.x; - if (uNonOptPixelShader == 0) { //particle_mod - vec3 matDiffuse = vColor.xyz * tex.rgb; - - finalColor = vec4(matDiffuse.rgb, tex.a*vColor.a); - } else if (uNonOptPixelShader == 1) {//particle_2colortex_3alphatex - vec4 textureMod = tex*tex2; - float texAlpha = (textureMod.w * tex3.w); - float opacity = texAlpha*vColor.a; - - - vec3 matDiffuse = vColor.xyz * textureMod.rgb; - finalColor = vec4(matDiffuse.rgb, opacity); - } else if (uNonOptPixelShader == 2) { //particle_3colortex_3alphatex - vec4 textureMod = tex*tex2*tex3; - float texAlpha = (textureMod.w); - float opacity = texAlpha*vColor.a; - - - vec3 matDiffuse = vColor.xyz * textureMod.rgb; - finalColor = vec4(matDiffuse.rgb, opacity); - } else if (uNonOptPixelShader == 3) { //Particle_3ColorTex_3AlphaTex_UV - //TODO: incorrect implementation, because the original shader is too complicated - vec4 textureMod = tex*tex2*tex3; - float texAlpha = (textureMod.w); - float opacity = texAlpha*vColor.a; - - vec3 matDiffuse = vColor.xyz * textureMod.rgb; - finalColor = vec4(matDiffuse.rgb, opacity); - } else if (uNonOptPixelShader == 4) { //Refraction - discard; - float t0_973 = tex.x; - float t1_978 = tex2.y; - float t2_983 = tex3.z; - float textureMod_986 = (((t0_973 * t1_978) * t2_983) * 4.0); - float depthScale_991 = (1.0 - clamp((vPosition.z * 0.00999999978), 0, 1)); - float textureMod_992 = (textureMod_986 * depthScale_991); - float height_995 = (textureMod_992 * vColor.x); - float alpha_997 = (textureMod_992 * vColor.w); - finalColor = vec4(height_995, 0.0, 0.0, alpha_997); - } - - finalColor = vec4(finalColor.rgb * colorMult, finalColor.a * alphaMult); - - if(finalColor.a < uAlphaTest) - discard; - - if(finalColor.a < alphaCutoff) - discard; - - // vec3 sunDir = - // mix( - // scene.uInteriorSunDir, - // scene.extLight.uExteriorDirectColorDir, - // interiorExteriorBlend.x - // ) - // .xyz; - vec3 sunDir =scene.extLight.uExteriorDirectColorDir.xyz; - - finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); - - outputColor.rgba = finalColor ; -} +#include "../m2ParticleShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl new file mode 100644 index 000000000..18bf64a85 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl @@ -0,0 +1,118 @@ +precision highp float; +precision highp int; + +layout (location = 0) in vec3 vPosition; +layout (location = 1) in vec4 vColor; +layout (location = 2) in vec2 vTexcoord0; +layout (location = 3) in vec2 vTexcoord1; +layout (location = 4) in vec2 vTexcoord2; +layout (location = 5) in float alphaCutoff; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonUboSceneData.glsl" + +//Individual meshes +layout (std140, set = 1, binding = 0) uniform meshWideBlockPS { + vec4 uAlphaTest_alphaMult_colorMult; + ivec4 uPixelShaderBlendModev; +}; + +layout (set = 2, binding = 0) uniform sampler2D uTexture; +layout (set = 2, binding = 1) uniform sampler2D uTexture2; +layout (set = 2, binding = 2) uniform sampler2D uTexture3; + +#ifndef DEFERRED +layout(location = 0) out vec4 outColor; +#else +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; +#endif + + +void main() { + vec4 tex = texture(uTexture, vTexcoord0).rgba; + vec4 tex2 = texture(uTexture2, vTexcoord1).rgba; + vec4 tex3 = texture(uTexture3, vTexcoord2).rgba; + + float uAlphaTest = uAlphaTest_alphaMult_colorMult.x; + float alphaMult = uAlphaTest_alphaMult_colorMult.y; + float colorMult = uAlphaTest_alphaMult_colorMult.z; + + if (tex.a < uAlphaTest) + discard; + + vec3 matDiffuse = (tex * vColor).rgb; + float opacity = tex.a * vColor.a; + + int uNonOptPixelShader = uPixelShaderBlendModev.x; + if (uNonOptPixelShader == 0) { //particle_mod + matDiffuse.rgb = vColor.xyz * tex.rgb; + opacity = tex.a * vColor.a; + + } else if (uNonOptPixelShader == 1) {//particle_2colortex_3alphatex + vec4 textureMod = tex * tex2; + float texAlpha = (textureMod.w * tex3.w); + opacity = texAlpha * vColor.a; + + matDiffuse = vColor.xyz * textureMod.rgb; + } else if (uNonOptPixelShader == 2) { //particle_3colortex_3alphatex + vec4 textureMod = tex * tex2 * tex3; + float texAlpha = (textureMod.w); + + matDiffuse = vColor.xyz * textureMod.rgb; + opacity = texAlpha * vColor.a; + + } else if (uNonOptPixelShader == 3) { //Particle_3ColorTex_3AlphaTex_UV + //TODO: incorrect implementation, because the original shader is too complicated + vec4 textureMod = tex * tex2 * tex3; + float texAlpha = (textureMod.w); + + matDiffuse = vColor.xyz * textureMod.rgb; + opacity = texAlpha * vColor.a; + } else if (uNonOptPixelShader == 4) { //Refraction + discard; + float t0_973 = tex.x; + float t1_978 = tex2.y; + float t2_983 = tex3.z; + float textureMod_986 = (((t0_973 * t1_978) * t2_983) * 4.0); + float depthScale_991 = (1.0 - clamp((vPosition.z * 0.00999999978), 0, 1)); + float textureMod_992 = (textureMod_986 * depthScale_991); + float height_995 = (textureMod_992 * vColor.x); + float alpha_997 = (textureMod_992 * vColor.w); + + matDiffuse = vec3(height_995, 0.0, 0.0); + opacity = alpha_997; + } + + matDiffuse = matDiffuse.rgb * colorMult; + opacity = opacity * alphaMult; + + if (opacity < uAlphaTest) + discard; + + if (opacity < alphaCutoff) + discard; + + // vec3 sunDir = + // mix( + // scene.uInteriorSunDir, + // scene.extLight.uExteriorDirectColorDir, + // interiorExteriorBlend.x + // ) + // .xyz; + vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; + +#ifndef DEFERRED + vec4 finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, vec4(matDiffuse, opacity), scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShaderBlendModev.y); +#endif + +#ifndef DEFERRED + outColor = finalColor; +#else + outAlbedo = vec4(matDiffuse.xyz, 0.0); + outNormal = vec4(0,0,1.0, 0.0); + outSpecular = vec4(0.0); +#endif +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/ribbonShader.frag b/wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.frag similarity index 77% rename from wowViewerLib/shaders/glsl/bindless/ribbonShader.frag rename to wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.frag index 136f28176..c634e697e 100644 --- a/wowViewerLib/shaders/glsl/bindless/ribbonShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.frag @@ -5,17 +5,15 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonUboSceneData.glsl" precision highp float; layout(location = 0) in vec3 vPosition; layout(location = 1) in vec4 vColor; layout(location = 2) in vec2 vTexcoord0; - - layout(std140, set=1, binding=0) buffer readonly textureMatrices { mat4 textureMatrix[64]; }; @@ -26,11 +24,6 @@ layout(std140, set=1, binding=1) uniform meshWideBlockPS { layout(set=2, binding=0) uniform sampler2D uTexture; layout(location = 0) out vec4 outColor; -#ifndef NON_OPAQ_SHADER -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outViewPos; -layout(location = 3) out uint outMatProps; -#endif void main() { int textureTransformIndex = uPixelShader_BlendMode_TextureTransformIndex.z; @@ -52,9 +45,4 @@ void main() { finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, uPixelShader_BlendMode_TextureTransformIndex.y); outColor = finalColor; -#ifndef NON_OPAQ_SHADER - outNormal = vec4(0,0,0,0); - outViewPos = vec4(vPosition, 0); - outMatProps = 0; -#endif } diff --git a/wowViewerLib/shaders/glsl/bindless/ribbonShader.vert b/wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.vert similarity index 80% rename from wowViewerLib/shaders/glsl/bindless/ribbonShader.vert rename to wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.vert index e07baea34..96de17a86 100644 --- a/wowViewerLib/shaders/glsl/bindless/ribbonShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/m2Ribbon/forward/ribbonShader.vert @@ -5,9 +5,9 @@ precision highp float; precision highp int; -#include "../common/commonLightFunctions.glsl" -#include "../common/commonFogFunctions.glsl" -#include "../common/commonUboSceneData.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonUboSceneData.glsl" precision highp float; layout(location = 0) in vec3 aPosition; diff --git a/wowViewerLib/shaders/glsl/bindless/m2Ribbon/ribbonShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Ribbon/ribbonShader_text.glsl new file mode 100644 index 000000000..e69de29bb diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag b/wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag new file mode 100644 index 000000000..af5607695 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED + +#include "../waterFallShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.frag b/wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.frag new file mode 100644 index 000000000..6707973a8 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.frag @@ -0,0 +1,6 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#include "../waterFallShader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert b/wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.vert similarity index 89% rename from wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert rename to wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.vert index 5a39beb4b..ed683533f 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/forward/waterfallShader.vert @@ -6,11 +6,11 @@ precision highp float; precision highp int; -#include "../../common/commonFunctions.glsl" -#include "../../common/commonM2Material.glsl" -#include "../../common/commonLightFunctions.glsl" -#include "../../common/commonFogFunctions.glsl" -#include "../../common/commonUboSceneData.glsl" +#include "../../../common/commonFunctions.glsl" +#include "../../../common/commonM2Material.glsl" +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonUboSceneData.glsl" precision highp float; @@ -23,8 +23,8 @@ layout(location=4) in vec2 aTexCoord; layout(location=5) in vec2 aTexCoord2; -#include "../../common/commonM2IndirectDescriptorSet.glsl" -#include "../../common/commonM2WaterfallDescriptorSet.glsl" +#include "../../../common/commonM2IndirectDescriptorSet.glsl" +#include "../../../common/commonM2WaterfallDescriptorSet.glsl" //Shader output diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl similarity index 91% rename from wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag rename to wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl index fb202edea..dd4bc2653 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfall/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl @@ -1,8 +1,3 @@ -#version 450 - -#extension GL_GOOGLE_include_directive: require -#extension GL_EXT_nonuniform_qualifier : require - precision highp float; precision highp int; @@ -18,23 +13,21 @@ layout(location=3) in vec3 vNormal; layout(location=4) in vec3 vPosition; layout(location=5) flat in int meshInd; +#ifndef DEFERRED layout(location = 0) out vec4 outColor; -#ifndef NON_OPAQ_SHADER -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outViewPos; -layout(location = 3) out uint outMatProps; +#else +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; #endif - - - //Whole model #include "../../common/commonM2IndirectDescriptorSet.glsl" #include "../../common/commonM2WaterfallDescriptorSet.glsl" const InteriorLightParam intLightWaterfall = { - vec4(0,0,0,0), - vec4(0,0,0,1) +vec4(0,0,0,0), +vec4(0,0,0,1) }; // For references: @@ -113,17 +106,19 @@ void main() { vec4 finalColor = vec4( mix(colorAfterLight.rgb, whiteWater_val_baseColor_mix.rgb, waterfallCommon.values3.w), w_alpha_combined -// whiteWater_val.a+0.2 + // whiteWater_val.a+0.2 ); +#ifndef DEFERRED vec3 sunDir = scene.extLight.uExteriorDirectColorDir.xyz; finalColor = makeFog2(fogData,/*int(scene.extLight.adtSpecMult_fogCount.y),*/ finalColor, scene.uViewUpSceneTime.xyz, vPosition.xyz, sunDir.xyz, 0); +#endif - +#ifndef DEFERRED outColor = finalColor; -#ifndef NON_OPAQ_SHADER - outNormal = vec4(normalize(vNormal), 0); - outViewPos = vec4(vPosition, 0); - outMatProps = 0; +#else + outAlbedo = vec4(whiteWater_val_baseColor_mix.rgb, 0.0); + outNormal = vec4(perturbedNormal.rgb, 0.0); + outSpecular = vec4(0.0); #endif } diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag b/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag new file mode 100644 index 000000000..307b925e6 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED + +#include "../wmoshader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag index 06e68bcf0..efd48ac03 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader.frag @@ -2,106 +2,4 @@ #extension GL_GOOGLE_include_directive: require #extension GL_EXT_nonuniform_qualifier: require -#define FRAGMENT_SHADER 1 - -precision highp float; -precision highp int; - -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonFunctions.glsl" -#include "../../../common/commonWMOMaterial.glsl" -#include "../../../common/commonUboSceneData.glsl" - - - -layout(location=0) in vec2 vTexCoord; -layout(location=1) in vec2 vTexCoord2; -layout(location=2) in vec2 vTexCoord3; -layout(location=3) in vec2 vTexCoord4; -layout(location=4) in vec4 vColor; -layout(location=5) in vec4 vColor2; -layout(location=6) in vec4 vColorSecond; -layout(location=7) in vec4 vPosition; -layout(location=8) in vec3 vNormal; -layout(location=9) in flat int vMeshIndex; - - -#include "../../../common/commonWMOIndirectDescriptorSet.glsl" - - -layout(set=2, binding=0) uniform sampler2D s_Textures[]; - -layout(location = 0) out vec4 outColor; -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outViewPos; -layout(location = 3) out uint outMatProps; - -void main() { - WMOPerMeshData perMeshData = perMeshDatas[nonuniformEXT(vMeshIndex)]; - WmoMeshWideBindless meshWideBindless = wmoMeshWideBindlesses[nonuniformEXT(perMeshData.meshWideBindlessIndex_wmoAmbientIndex.x)]; - WmoMeshWide wmoMeshWide = wmoMeshWides[nonuniformEXT(meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.y)]; - - int uPixelShader = wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.z; - - vec3 matDiffuse = vec3(0.0); - vec3 spec = vec3(0.0); - vec3 emissive = vec3(0.0); - float finalOpacity = 0.0; - bool doDiscard; - - int text1 = meshWideBindless.text1_text2_text3_text4.x; - int text2 = meshWideBindless.text1_text2_text3_text4.y; - int text3 = meshWideBindless.text1_text2_text3_text4.z; - int text4 = meshWideBindless.text1_text2_text3_text4.w; - int text5 = meshWideBindless.text5_text6_text7_text8.x; - int text6 = meshWideBindless.text5_text6_text7_text8.y; - int text7 = meshWideBindless.text5_text6_text7_text8.z; - int text8 = meshWideBindless.text5_text6_text7_text8.w; - int text9 = meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.w; - - caclWMOFragMat(uPixelShader, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.y == 1, - s_Textures[nonuniformEXT(text1)], s_Textures[nonuniformEXT(text2)], s_Textures[nonuniformEXT(text3)], s_Textures[nonuniformEXT(text4)], - s_Textures[text5], s_Textures[text6], s_Textures[text7], s_Textures[text8], - s_Textures[text9], - vPosition.xyz, vNormal, vTexCoord, vTexCoord2, vTexCoord3, vTexCoord4, - vColor2, - vColorSecond, - matDiffuse, spec, emissive, finalOpacity, - doDiscard - ); - - if (doDiscard) - discard; - - InteriorLightParam intLight; - intLight.uInteriorAmbientColorAndApplyInteriorLight = s_wmoAmbient[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.y]; - intLight.uInteriorDirectColorAndApplyExteriorLight = vec4(0, 0, 0, 1.0f); - - vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); -// finalColor = vec4( -// calcLight( -// matDiffuse, -// vNormal, -// wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, -// vColor.w, -// scene, -// intLight, -// vec3(0.0) /*accumLight*/, -// vColor.rgb, -// spec, /* specular */ -// emissive -// ), -// finalOpacity -// ); - finalColor.rgb = matDiffuse; - -// finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, -// vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); -// finalColor.a = 1.0; - - outColor = finalColor; - outNormal = vec4(normalize(vNormal), 0.0); - outViewPos = vec4(vPosition.xyz, 0.0); - outMatProps = 0; -} +#include "../wmoshader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl new file mode 100644 index 000000000..1c442df0f --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -0,0 +1,110 @@ +#define FRAGMENT_SHADER 1 + +precision highp float; +precision highp int; + +#include "../../../common/commonLightFunctions.glsl" +#include "../../../common/commonFogFunctions.glsl" +#include "../../../common/commonFunctions.glsl" +#include "../../../common/commonWMOMaterial.glsl" +#include "../../../common/commonUboSceneData.glsl" + +layout (location = 0) in vec2 vTexCoord; +layout (location = 1) in vec2 vTexCoord2; +layout (location = 2) in vec2 vTexCoord3; +layout (location = 3) in vec2 vTexCoord4; +layout (location = 4) in vec4 vColor; +layout (location = 5) in vec4 vColor2; +layout (location = 6) in vec4 vColorSecond; +layout (location = 7) in vec4 vPosition; +layout (location = 8) in vec3 vNormal; +layout (location = 9) in flat int vMeshIndex; + +#include "../../../common/commonWMOIndirectDescriptorSet.glsl" + +layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; + +#ifndef DEFERRED +layout(location = 0) out vec4 outColor; +#else +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; +#endif + +void main() { + WMOPerMeshData perMeshData = perMeshDatas[nonuniformEXT(vMeshIndex)]; + WmoMeshWideBindless meshWideBindless = wmoMeshWideBindlesses[nonuniformEXT(perMeshData.meshWideBindlessIndex_wmoAmbientIndex.x)]; + WmoMeshWide wmoMeshWide = wmoMeshWides[nonuniformEXT(meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.y)]; + + int uPixelShader = wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.z; + + vec3 matDiffuse = vec3(0.0); + vec3 spec = vec3(0.0); + vec3 emissive = vec3(0.0); + float finalOpacity = 0.0; + bool doDiscard; + + int text1 = meshWideBindless.text1_text2_text3_text4.x; + int text2 = meshWideBindless.text1_text2_text3_text4.y; + int text3 = meshWideBindless.text1_text2_text3_text4.z; + int text4 = meshWideBindless.text1_text2_text3_text4.w; + int text5 = meshWideBindless.text5_text6_text7_text8.x; + int text6 = meshWideBindless.text5_text6_text7_text8.y; + int text7 = meshWideBindless.text5_text6_text7_text8.z; + int text8 = meshWideBindless.text5_text6_text7_text8.w; + int text9 = meshWideBindless.placementMat_meshWideIndex_blockVSIndex_texture9.w; + + caclWMOFragMat(uPixelShader, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.y == 1, + s_Textures[nonuniformEXT(text1)], s_Textures[nonuniformEXT(text2)], s_Textures[nonuniformEXT(text3)], s_Textures[nonuniformEXT(text4)], + s_Textures[text5], s_Textures[text6], s_Textures[text7], s_Textures[text8], + s_Textures[text9], + vPosition.xyz, vNormal, vTexCoord, vTexCoord2, vTexCoord3, vTexCoord4, + vColor2, + vColorSecond, + matDiffuse, spec, emissive, finalOpacity, + doDiscard + ); + + if (doDiscard) + discard; + + InteriorLightParam intLight; + intLight.uInteriorAmbientColorAndApplyInteriorLight = s_wmoAmbient[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.y]; + intLight.uInteriorDirectColorAndApplyExteriorLight = vec4(0, 0, 0, 1.0f); + + vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); +#ifndef DEFERRED + finalColor = vec4( + calcLight( + matDiffuse, + vNormal, + wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.x == 1, + vColor.w, + scene, + intLight, + vec3(0.0) /*accumLight*/, + vColor.rgb, + spec, /* specular */ + emissive + ), + finalOpacity + ); +#endif + finalColor.rgb = matDiffuse; + +#ifndef DEFERRED + finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, + vPosition.xyz, scene.extLight.uExteriorDirectColorDir.xyz, wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w); +#endif + +finalColor.a = 1.0; + +#ifndef DEFERRED + outColor = finalColor; +#else + outAlbedo = vec4(matDiffuse.xyz, 0.0); + outNormal = vec4(normalize(vNormal), 0.0); + outSpecular = vec4(spec.rgb, 0.0); +#endif +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 20d346160..121b89910 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -20,7 +20,7 @@ struct SceneWideParams { mat4 uLookAtMat; mat4 uPMatrix; vec4 uViewUpSceneTime; - vec4 uInteriorSunDir; + vec4 uInteriorSunDir_lightBufferIndex; vec4 closeRiverColor; vec4 farRiverColor; @@ -91,7 +91,7 @@ vec3 calcLight( currColor = mix(groundColor, skyColor, (0.5f + vec3(0.5f * nDotL))); } if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { - float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir.xyz)), 0.0, 1.0); + float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir_lightBufferIndex.xyz)), 0.0, 1.0); vec3 lDiffuseInterior = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz * nDotL; vec3 interiorAmbient = intLight.uInteriorAmbientColorAndApplyInteriorLight.xyz + precomputedLight; diff --git a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl index 5c66d0487..43ceb27f3 100644 --- a/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonM2IndirectDescriptorSet.glsl @@ -11,7 +11,6 @@ layout(std430, set=1, binding=1) buffer readonly modelWideBlockVS { struct modelWideBlockPSStruct { InteriorLightParam intLight; - LocalLight pc_lights[4]; ivec4 lightCountAndBcHack; vec4 interiorExteriorBlend; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index f064c4b6c..09fa3b6eb 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -164,7 +164,7 @@ void main() { if (uUnFogged == 0) { vec3 sunDir = mix( - scene.uInteriorSunDir, + scene.uInteriorSunDir_lightBufferIndex, scene.extLight.uExteriorDirectColorDir, interiorExteriorBlend.x ) diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index 146f5f766..0586955a0 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -151,6 +151,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vector\n" "#include \n" "#include \n" + "#include \n" "\n" "template \n" "inline constexpr const uint32_t operator+ (T const val) { return static_cast(val); };" diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 6a2b41833..02d5908f1 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -233,7 +233,7 @@ void M2Geom::process(HFileContent m2File, const std::string &fileName) { m2SizeLoaded.fetch_add(m2File->size()); if (ident == '12DM') { - CChunkFileReader reader(*this->m2File.get()); + CChunkFileReader reader(*this->m2File.get(), fileName); reader.processFile(*this, &M2Geom::m2FileTable); } else { M2Data *m2Header = (M2Data *) this->m2File->data(); diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 59ce1c1f5..fd3aed07b 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -222,7 +222,7 @@ chunkDef WmoGroupGeom::wmoGroupTable = { void WmoGroupGeom::process(HFileContent wmoGroupFile, const std::string &fileName) { m_wmoGroupFile = wmoGroupFile; - CChunkFileReader reader(*m_wmoGroupFile.get()); + CChunkFileReader reader(*m_wmoGroupFile.get(), fileName); reader.processFile(*this, &WmoGroupGeom::wmoGroupTable); fsStatus = FileStatus::FSLoaded; diff --git a/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp b/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp index ab9d55202..f7883a0ca 100644 --- a/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp @@ -206,7 +206,7 @@ chunkDef WmoMainGeom::wmoMainTable = { void WmoMainGeom::process(HFileContent wmoMainFile, const std::string &fileName) { m_wmoMainFile = wmoMainFile; - CChunkFileReader reader(*m_wmoMainFile.get()); + CChunkFileReader reader(*m_wmoMainFile.get(), fileName); reader.processFile(*this, &WmoMainGeom::wmoMainTable); fsStatus = FileStatus::FSLoaded; diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index d155d6dcc..48485462b 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -663,7 +663,7 @@ void AdtFile::createTriangleStrip() { void AdtFile::process(HFileContent adtFile, const std::string &fileName) { m_adtFile = adtFile; - CChunkFileReader reader(*m_adtFile.get()); + CChunkFileReader reader(*m_adtFile.get(), fileName); reader.processFile(*this, &AdtFile::adtFileTable); createTriangleStrip(); diff --git a/wowViewerLib/src/engine/persistance/animFile.cpp b/wowViewerLib/src/engine/persistance/animFile.cpp index a90809f8c..503d4834e 100644 --- a/wowViewerLib/src/engine/persistance/animFile.cpp +++ b/wowViewerLib/src/engine/persistance/animFile.cpp @@ -44,7 +44,7 @@ void AnimFile::process(HFileContent animFile, const std::string &fileName) { if (chunk == 'BSFA' || chunk == 'ASFA' || chunk == '2MFA') { - CChunkFileReader reader(fileVec); + CChunkFileReader reader(fileVec, fileName); reader.processFile(*this, &AnimFile::animFileTable); } else { m_animFileDataBlob = (uint8_t *) &fileVec[0]; diff --git a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h index a6e26f6ca..bb376beb5 100644 --- a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h +++ b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h @@ -32,6 +32,7 @@ class CChunkFileReader { protected: void *fileData; int regionSizeToProcess; + std::string fileName; public: unsigned int chunkIdent; @@ -46,9 +47,10 @@ class CChunkFileReader { public: CChunkFileReader() { } - CChunkFileReader(std::vector &file){ + CChunkFileReader(std::vector &file, const std::string &fileName){ regionSizeToProcess = (int) file.size(); fileData = &file[0]; + this->fileName = fileName; } template @@ -129,16 +131,16 @@ class CChunkFileReader { char *indentPtr = (char *) &subChunk.chunkIdent; char indent[5] = { indentPtr[3], indentPtr[2], indentPtr[1], indentPtr[0], 0x0}; if (bytesReadAfter - bytesReadBefore > subChunk.chunkLen) { - debuglog("Read out of bounds of chunk "<< indent <<" in "<< __PRETTY_FUNCTION__); + debuglog("Read out of bounds of chunk "<< indent <<" in "<< __PRETTY_FUNCTION__<< " in file "<< this->fileName); } if (bytesReadAfter - bytesReadBefore < subChunk.chunkLen) { - debuglog("Not all data was read from chunk "<< indent <<" in "<< __PRETTY_FUNCTION__); + debuglog("Not all data was read from chunk "<< indent <<" in "<< __PRETTY_FUNCTION__<< " in file "<< this->fileName); } } else { char *indentPtr = (char *) &subChunk.chunkIdent; char indent[5] = { indentPtr[3], indentPtr[2], indentPtr[1], indentPtr[0], 0x0}; - debuglog("Handler for "<< indent << " was not found in "<< __PRETTY_FUNCTION__); + debuglog("Handler for "<< indent << " was not found in "<< __PRETTY_FUNCTION__ << " in file "<< this->fileName); } //TODO: HACK! @@ -155,7 +157,7 @@ class CChunkFileReader { if (sectionHandlerProc->subChunks.size() == 0) { char *indentPtr = (char *) &chunk.chunkIdent; char indent[5] = { indentPtr[3], indentPtr[2], indentPtr[1], indentPtr[0], 0x0}; - debuglog("Not all data was read from "<< indent << " chunk, parsed from "<< __PRETTY_FUNCTION__); + debuglog("Not all data was read from "<< indent << " chunk, parsed from "<< __PRETTY_FUNCTION__<< " in file "<< this->fileName); } else { int chunkLoadOffset = chunk.dataOffset+chunk.bytesRead; int chunkEndOffset = chunk.dataOffset + chunk.chunkLen; diff --git a/wowViewerLib/src/engine/persistance/skelFile.cpp b/wowViewerLib/src/engine/persistance/skelFile.cpp index 3e81a23b3..2606ae315 100644 --- a/wowViewerLib/src/engine/persistance/skelFile.cpp +++ b/wowViewerLib/src/engine/persistance/skelFile.cpp @@ -73,7 +73,7 @@ chunkDef SkelFile::skelFileTable = { void SkelFile::process(HFileContent skelFile, const std::string &fileName) { m_skelFile = skelFile; - CChunkFileReader reader(*m_skelFile.get()); + CChunkFileReader reader(*m_skelFile.get(), fileName); reader.processFile(*this, &SkelFile::skelFileTable); if (this->m_ska1 != nullptr) { diff --git a/wowViewerLib/src/engine/persistance/wdlFile.cpp b/wowViewerLib/src/engine/persistance/wdlFile.cpp index dab9a6ac6..fbca5e306 100644 --- a/wowViewerLib/src/engine/persistance/wdlFile.cpp +++ b/wowViewerLib/src/engine/persistance/wdlFile.cpp @@ -69,7 +69,7 @@ chunkDef WdlFile::wdlFileTable = { void WdlFile::process(HFileContent wdlFile, const std::string &fileName) { m_wdlFile = wdlFile; - CChunkFileReader reader(*m_wdlFile.get()); + CChunkFileReader reader(*m_wdlFile.get(), fileName); reader.processFile(*this, &WdlFile::wdlFileTable); fsStatus = FileStatus::FSLoaded; diff --git a/wowViewerLib/src/engine/persistance/wdtFile.cpp b/wowViewerLib/src/engine/persistance/wdtFile.cpp index 58cdbf8ad..e0b2f6368 100644 --- a/wowViewerLib/src/engine/persistance/wdtFile.cpp +++ b/wowViewerLib/src/engine/persistance/wdtFile.cpp @@ -57,7 +57,7 @@ chunkDef WdtFile::wdtFileTable = { void WdtFile::process(HFileContent wdtFile, const std::string &fileName) { m_wdtFile = wdtFile; - CChunkFileReader reader(*m_wdtFile.get()); + CChunkFileReader reader(*m_wdtFile.get(), fileName); reader.processFile(*this, &WdtFile::wdtFileTable); fsStatus = FileStatus::FSLoaded; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 5c2126d3e..f200f3773 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -7,6 +7,7 @@ #include #include #include +#include template inline constexpr const uint32_t operator+ (T const val) { return static_cast(val); }; @@ -72,45 +73,39 @@ struct attributeDefine { extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterwaterShader { - enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterwaterShaderAttributeEnd - }; -}; - -struct forwardm2ParticleShader { +struct drawQuad { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, forwardm2ParticleShaderAttributeEnd + position = 0, drawQuadAttributeEnd }; }; -struct forwardm2Shader { +struct adtShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, forwardm2ShaderAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct visbuferadtShader { +struct skyConus { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, visbuferadtShaderAttributeEnd + aPosition = 0, skyConusAttributeEnd }; }; -struct waterfallShader { +struct m2Shader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd }; }; -struct adtLodShader { +struct imguiShader { enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd + Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd }; }; -struct adtShader { +struct wmoShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd }; }; @@ -120,57 +115,39 @@ struct drawBBShader { }; }; -struct waterShader { - enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd - }; -}; - -struct m2ParticleShader { - enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd - }; -}; - -struct forwardwmoShader { - enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, forwardwmoShaderAttributeEnd - }; -}; - -struct drawFrustumShader { +struct drawLinesShader { enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd + aPosition = 0, drawLinesShaderAttributeEnd }; }; -struct drawPoints { +struct ribbonShader { enum class Attribute { - aPosition = 0, drawPointsAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd }; }; -struct drawQuad { +struct m2ParticleShader { enum class Attribute { - position = 0, drawQuadAttributeEnd + aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd }; }; -struct skyConus { +struct waterShader { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd }; }; -struct m2Shader { +struct waterfallShader { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd }; }; -struct drawPortalShader { +struct adtLodShader { enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd + aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd }; }; @@ -180,80 +157,46 @@ struct renderFrameBufferShader { }; }; -struct waterfallwaterfallShader { - enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallwaterfallShaderAttributeEnd - }; -}; - -struct wmoShader { - enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd - }; -}; - -struct imguiShader { - enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd - }; -}; - -struct forwardadtShader { +struct drawPortalShader { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, forwardadtShaderAttributeEnd + aPosition = 0, drawPortalShaderAttributeEnd }; }; -struct drawLinesShader { +struct drawFrustumShader { enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd + aPosition = 0, drawFrustumShaderAttributeEnd }; }; -struct ribbonShader { +struct drawPoints { enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { -{ "waterwaterShader", +{ "drawQuad", { - { "aPositionTransp", 0}, - { "aTexCoord", 1}, + { "position", 0}, } }, -{ "forwardm2ParticleShader", +{ "adtShader", { - { "aPosition", 0}, + { "aPos", 0}, { "aColor", 1}, - { "aTexcoord0", 2}, - { "aTexcoord1", 3}, - { "aTexcoord2", 4}, - { "aAlphaCutoff", 5}, + { "aVertexLighting", 2}, + { "aNormal", 3}, } }, -{ "forwardm2Shader", +{ "skyConus", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "visbuferadtShader", - { - { "aPos", 0}, - { "aColor", 1}, - { "aVertexLighting", 2}, - { "aNormal", 3}, } }, -{ "waterfallShader", +{ "m2Shader", { { "aPosition", 0}, { "aNormal", 1}, @@ -263,42 +206,14 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "adtLodShader", - { - { "aHeight", 0}, - { "aIndex", 1}, - } -}, -{ "adtShader", - { - { "aPos", 0}, - { "aColor", 1}, - { "aVertexLighting", 2}, - { "aNormal", 3}, - } -}, -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "waterShader", - { - { "aPositionTransp", 0}, - { "aTexCoord", 1}, - } -}, -{ "m2ParticleShader", +{ "imguiShader", { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - { "aTexcoord1", 3}, - { "aTexcoord2", 4}, - { "aAlphaCutoff", 5}, + { "Position", 0}, + { "UV", 1}, + { "Color", 2}, } }, -{ "forwardwmoShader", +{ "wmoShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -309,49 +224,43 @@ const std::unordered_map> attributesPe { "aColor", 6}, { "aColor2", 7}, { "aColorSecond", 8}, + { "wmoAmbient", 9}, } }, -{ "drawFrustumShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", +{ "drawBBShader", { { "aPosition", 0}, } }, -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "skyConus", +{ "drawLinesShader", { { "aPosition", 0}, } }, -{ "m2Shader", +{ "ribbonShader", { { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, + { "aColor", 1}, + { "aTexcoord0", 2}, } }, -{ "drawPortalShader", +{ "m2ParticleShader", { { "aPosition", 0}, + { "aColor", 1}, + { "aTexcoord0", 2}, + { "aTexcoord1", 3}, + { "aTexcoord2", 4}, + { "aAlphaCutoff", 5}, } }, -{ "renderFrameBufferShader", +{ "waterShader", { - { "a_position", 0}, + { "aPositionTransp", 0}, + { "aTexCoord", 1}, } }, -{ "waterfallwaterfallShader", +{ "waterfallShader", { { "aPosition", 0}, { "aNormal", 1}, @@ -361,60 +270,47 @@ const std::unordered_map> attributesPe { "aTexCoord2", 5}, } }, -{ "wmoShader", +{ "adtLodShader", { - { "aPosition", 0}, - { "aNormal", 1}, - { "aTexCoord", 2}, - { "aTexCoord2", 3}, - { "aTexCoord3", 4}, - { "aTexCoord4", 5}, - { "aColor", 6}, - { "aColor2", 7}, - { "aColorSecond", 8}, - { "wmoAmbient", 9}, + { "aHeight", 0}, + { "aIndex", 1}, } }, -{ "imguiShader", +{ "renderFrameBufferShader", { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, + { "a_position", 0}, } }, -{ "forwardadtShader", +{ "drawPortalShader", { - { "aPos", 0}, - { "aColor", 1}, - { "aVertexLighting", 2}, - { "aNormal", 3}, + { "aPosition", 0}, } }, -{ "drawLinesShader", +{ "drawFrustumShader", { { "aPosition", 0}, } }, -{ "ribbonShader", +{ "drawPoints", { { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, } }, }; const std::unordered_map shaderMetaInfo = { -{ "bindless/wmo/forwardwmoShader.vert.spv", +{ "./forwardRendering/wmoShader.vert.spv", { ShaderStage::Vertex, { + {1,0,64}, {0,0,544}, + {1,1,16}, }, { { {0,0,1}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -424,12 +320,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -447,16 +337,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/wmo/forwardwmoShader.frag.spv", +{ "./forwardRendering/wmoShader.frag.spv", { ShaderStage::Fragment, { + {1,2,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -466,21 +357,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {2,3, "uTexture4"}, + {2,4, "uTexture5"}, + {2,5, "uTexture6"}, + {2,6, "uTexture7"}, + {2,7, "uTexture8"}, + {2,8, "uTexture9"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -490,17 +383,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterwaterShader.vert.spv", +{ "./forwardRendering/waterfallShader.vert.spv", { ShaderStage::Vertex, { + {2,0,112}, + {1,5,4096}, + {1,2,16384}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -509,19 +409,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -530,16 +427,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterwaterShader.frag.spv", +{ "./forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -549,18 +447,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, - {1,1,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -570,17 +464,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/ribbonShader.vert.spv", +{ "./forwardRendering/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, {0,0,544}, + {1,0,64}, + {1,5,4096}, + {1,2,16384}, }, { { {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -591,13 +492,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -606,15 +511,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2Particle/forwardm2ParticleShader.vert.spv", +{ "./forwardRendering/renderFrameBufferShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,168}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -627,10 +532,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {0,0,0}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -642,17 +549,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2Particle/forwardm2ParticleShader.frag.spv", +{ "./forwardRendering/imguiShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, - {0,0,544}, + {0,0,80}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -664,15 +570,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -682,15 +585,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2/forwardm2Shader_nonopaq.frag.spv", +{ "./forwardRendering/skyConus.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -701,24 +603,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -728,15 +620,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterfallwaterfallShader.frag.spv", +{ "./forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -747,27 +638,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {1,0, "Texture"}, }, { { {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -776,11 +656,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2/forwardm2Shader.vert.spv", +{ "./forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,16}, }, { { @@ -795,15 +675,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -821,9 +692,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/m2/forwardm2Shader.frag.spv", +{ "./forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -840,24 +711,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,1,0}, - {1,6,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -867,11 +728,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adt/visbuferadtShader.vert.spv", +{ "./forwardRendering/drawLinesShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, }, { { @@ -886,9 +747,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { }, @@ -906,16 +764,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adt/visbuferadtShader.frag.spv", +{ "./forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -925,22 +784,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -948,15 +801,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adt/forwardadtShader.vert.spv", +{ "./forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -967,16 +819,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -987,18 +837,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.vert.spv", +{ "./forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, - {0,0,544}, - {1,1,16}, + {0,1,12}, }, { { - {0,0,1}, - {0,1,2}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1025,24 +873,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.vert.spv", +{ "./forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, + {0,0,128}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1053,14 +894,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,3, "uBumpTexture"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1069,17 +909,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.vert.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,1,16}, {0,0,544}, - {1,0,64}, }, { { {0,0,1}, - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1089,14 +929,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,4096}, }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1106,12 +948,12 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.vert.spv", +{ "./bindless/m2Particle/forward/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,0,32}, {0,0,544}, - {1,0,96}, }, { { @@ -1128,12 +970,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1143,14 +988,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/skyConus.frag.spv", +{ "./forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { + {0,1,16}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1163,11 +1009,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1178,16 +1026,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.vert.spv", +{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,0,32}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1199,12 +1048,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1214,15 +1066,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.frag.spv", +{ "./bindless/m2/deferred/m2Shader_opaq_deferred.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1233,14 +1085,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1250,15 +1112,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.vert.spv", +{ "./forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,15 +1149,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.vert.spv", +{ "./forwardRendering/drawBBShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,1,112}, + {0,0,544}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1322,14 +1186,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.frag.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1342,12 +1207,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1358,15 +1222,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.frag.spv", +{ "./forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,1,12}, }, { { - {2,2,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1379,12 +1243,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1396,24 +1258,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterfallShader.frag.spv", +{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1424,17 +1279,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1443,15 +1294,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawLinesShader.frag.spv", +{ "./forwardRendering/imguiShaderDepth.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1464,11 +1314,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1479,17 +1330,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.vert.spv", +{ "./forwardRendering/drawPortalShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,544}, + {1,0,16}, }, { { - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1516,15 +1366,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPortalShader.frag.spv", +{ "./forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,16}, + {1,0,64}, + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1552,17 +1403,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.frag.spv", +{ "./forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {2,0,112}, + {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {2,2,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,13 +1431,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1588,11 +1450,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader.vert.spv", +{ "./bindless/adt/visbuffer/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,0,80}, + {0,0,544}, }, { { @@ -1607,6 +1469,9 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { }, @@ -1624,11 +1489,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.vert.spv", +{ "./bindless/adt/visbuffer/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, + {0,0,544}, }, { { @@ -1643,16 +1508,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1660,18 +1531,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.frag.spv", +{ "./bindless/adt/forward/adtShader.frag.spv", { ShaderStage::Fragment, { {0,0,544}, - {1,1,48}, - {1,0,64}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1681,25 +1550,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1707,11 +1573,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtLodShader.frag.spv", +{ "./bindless/wmo/deferred/wmoShader_opaq_deferred.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,0,544}, }, { { @@ -1726,16 +1592,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {2,0, "s_Textures"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1745,17 +1616,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/wmoShader.frag.spv", +{ "./bindless/waterfall/forward/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,2,32}, {0,0,544}, }, { { {0,0,1}, - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1765,24 +1635,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1791,14 +1664,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxgauss4.frag.spv", +{ "./forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,32}, + {1,1,48}, + {0,0,544}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1806,19 +1681,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { }, { - {1,0, "texture0"}, + {2,0, "uTexture"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1828,11 +1702,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/adt/forwardadtShader.frag.spv", +{ "./forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,0,84}, }, { { @@ -1847,22 +1721,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1870,11 +1740,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawQuad.vert.spv", +{ "./bindless/m2/forward/m2Shader.vert.spv", { ShaderStage::Vertex, { - {0,0,16}, + {0,0,544}, }, { { @@ -1889,6 +1759,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -1906,15 +1785,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ffxglow.frag.spv", +{ "./forwardRendering/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,16}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1927,13 +1806,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, }, { { {0,0,0}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1944,17 +1821,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/waterShader.frag.spv", +{ "./bindless/adt/deferred/adtShader.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1964,17 +1840,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {2,0, "uTexture"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1982,24 +1863,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.frag.spv", +{ "./forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, - {0,0,544}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2010,17 +1883,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,3,4}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2029,9 +1898,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/waterfallwaterfallShader.vert.spv", +{ "./bindless/water/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -2048,24 +1917,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, + {1,0,0}, + {1,1,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -2073,19 +1933,23 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "forwardRendering/imguiShaderDepth.frag.spv", +{ "./forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { + {1,1,16}, + {1,0,4096}, + {0,0,544}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2097,13 +1961,13 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, + {2,0, "uTexture"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2113,11 +1977,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawFrustumShader.vert.spv", +{ "./bindless/water/waterShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,544}, }, { { @@ -2132,14 +1996,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2149,16 +2017,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/adtShader.vert.spv", +{ "./bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, {0,0,544}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -2166,18 +2032,31 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2186,14 +2065,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/imguiShader_opaque.frag.spv", +{ "./bindless/waterfall/forward/waterfallShader.frag.spv", { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2204,16 +2084,27 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { - {1,0, "Texture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2222,16 +2113,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawPoints.vert.spv", +{ "./bindless/wmo/forward/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2242,6 +2132,12 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -2259,15 +2155,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawBBShader.frag.spv", +{ "./forwardRendering/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2295,16 +2191,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.frag.spv", +{ "./bindless/m2/forward/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, {0,0,544}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -2312,20 +2206,28 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2335,9 +2237,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2ParticleShader.vert.spv", +{ "./bindless/wmo/forward/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, }, @@ -2354,14 +2256,21 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2371,18 +2280,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "bindless/ribbonShader.frag.spv", +{ "./forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,1,16}, + {1,2,16384}, + {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {1,1,1}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2391,16 +2306,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2410,15 +2323,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/renderFrameBufferShader.vert.spv", +{ "./forwardRendering/m2ParticleShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,0,32}, + {0,0,544}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2430,12 +2345,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2445,15 +2363,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/drawDepthShader.frag.spv", +{ "./bindless/adt/forward/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, }, { { - {2,2,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2464,13 +2382,15 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2482,24 +2402,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/m2Shader.vert.spv", +{ "./forwardRendering/adtLodShader.vert.spv", { ShaderStage::Vertex, { - {1,2,16384}, - {1,0,64}, - {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, + {0,0,144}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2525,18 +2438,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "forwardRendering/ribbonShader.frag.spv", +{ "./forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, - {0,0,544}, + {0,1,32}, }, { { - {0,0,1}, - {0,1,2}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2548,11 +2459,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, + {1,0, "texture0"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -2560,138 +2470,178 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterwaterShader", { +{ "./forwardRendering/drawDepthShader.frag.spv", + { + ShaderStage::Fragment, { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } + {0,2,12}, }, { - 2, { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { - 0, { - } }, - }}, - {"forwardm2ParticleShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, - } + {0,3, "diffuse"}, }, - }}, - {"forwardm2Shader", { { - 8, { + { + {3,3,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } - }, + } + } +}, +{ "./forwardRendering/adtShader.frag.spv", + { + ShaderStage::Fragment, { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } + {0,0,544}, + {1,1,48}, + {1,0,64}, }, { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, + { + {0,0,1}, + {0,1,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } }, { - 2, { - } + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + { + {0,0,0}, + {0,0,0}, + {0,8,9}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } + } + } +}, +{ "./forwardRendering/drawBBShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,1,112}, }, { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, + { + {1,1,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { - 7, { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } + } + } +}, +{ "./forwardRendering/drawFrustumShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,2,12}, }, { - 9, { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +}; + +const std::unordered_map>> fieldDefMapPerShaderNameVert = { + {"drawQuad", { { 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, } }, }}, - {"visbuferadtShader", { + {"adtShader", { { 2, { } @@ -2709,7 +2659,7 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { + {"imguiShader_opaque", { + }}, + {"imguiShaderDepth", { + }}, + {"ffxglow", { { 1, { - {"_1_1_VertexShader_UseLitColor", false, 0, 1, 4, 0}, + {"_0_1_blurAmount", true, 0, 1, 4, 0}, } }, + }}, + {"renderFrameBufferShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 2, { + {"_0_2_gauss_offsets[0]", true, 0, 1, 1, 5}, + {"_0_2_gauss_weights[0]", true, 80, 1, 1, 5}, + {"_0_2_uResolution", true, 160, 1, 2, 0}, } }, }}, - {"imguiShader", { + {"drawPortalShader", { { 0, { - {"_0_0_ProjMtx", true, 0, 4, 4, 0}, - {"_0_0_uiScale", true, 64, 1, 4, 0}, + {"_1_0_uColor", true, 0, 1, 4, 0}, } }, }}, - {"forwardadtShader", { - { - 2, { - } - }, + {"drawPoints", { { 1, { + {"_0_1_uColor", true, 0, 1, 3, 0}, } }, + }}, + {"ffxgauss4", { { - 3, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 1, { + {"_0_1_texOffsetX", true, 0, 1, 4, 0}, + {"_0_1_texOffsetY", true, 16, 1, 4, 0}, } }, }}, - {"drawLinesShader", { + {"drawFrustumShader", { { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, + 2, { + {"_0_2_uColor", true, 0, 1, 3, 0}, } }, }}, - {"ribbonShader", { + {"adtShader", { { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 304, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 320, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 352, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 368, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 384, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 416, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 448, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 464, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 512, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 528, 1, 4, 0}, + 2, { } }, - }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterwaterShader", { { 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, + {"_1_1_scaleFactorPerLayer", true, 0, 1, 4, 0}, + {"_1_1_animation_rotationPerLayer", false, 16, 1, 4, 0}, + {"_1_1_animation_speedPerLayer", false, 32, 1, 4, 0}, } }, { - 2, { + 3, { } }, { 0, { + {"_1_0_uPos", true, 0, 1, 4, 0}, + {"_1_0_uUseHeightMixFormula", false, 16, 1, 4, 0}, + {"_1_0_uHeightScale", true, 32, 1, 4, 0}, + {"_1_0_uHeightOffset", true, 48, 1, 4, 0}, } }, }}, - {"forwardm2ParticleShader", { + {"m2ParticleShader_opaq_deferred", { { 0, { {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, + {"_0_0_scene_uInteriorSunDir_lightBufferIndex", true, 144, 1, 4, 0}, {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, {"_0_0_scene_closeOceanColor", true, 192, 1, 4, 0}, @@ -3325,20 +3204,22 @@ const std::unordered_mapcreateShaderLayout(); diff --git a/wowViewerLib/src/gapi/vulkan/vkAllocator.cpp b/wowViewerLib/src/gapi/vulkan/vkAllocator.cpp index 613467ca1..276246d83 100644 --- a/wowViewerLib/src/gapi/vulkan/vkAllocator.cpp +++ b/wowViewerLib/src/gapi/vulkan/vkAllocator.cpp @@ -1,4 +1,5 @@ #define VMA_IMPLEMENTATION #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#define VMA_STATS_STRING_ENABLED 0 #include "vk_mem_alloc.h" diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index ad179c30f..6f683087d 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifndef AWEBWOWVIEWERCPP_DBSTRUCTS_H #define AWEBWOWVIEWERCPP_DBSTRUCTS_H diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 95ac4d41b..4c705216e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -84,6 +84,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr &renderingMatricess, const HFrameDependantData &fdd, bool isVulkan, + int lightBufferIndex, animTime_t sceneTime ) { ZoneScoped; @@ -105,7 +106,9 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrperspectiveMat; } - blockPSVS.uInteriorSunDir = renderingMatrices->interiorDirectLightDir; + blockPSVS.uInteriorSunDir_lightBufferIndex = mathfu::vec4_packed( + mathfu::vec4(renderingMatrices->interiorDirectLightDir.xyz(), lightBufferIndex) + ); blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); blockPSVS.closeOceanColor = fdd->closeOceanColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index e78971f98..f5104d0e4 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -38,9 +38,9 @@ static const std::vector staticWaterBindings = {{ static const std::vector staticM2Bindings = {{ {+m2Shader::Attribute::aPosition, 3, GBindingType::GFLOAT, false, sizeof(M2Vertex), offsetof(M2Vertex, pos) }, - {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(M2Vertex), offsetof(M2Vertex, bone_weights)}, // bonesWeight - {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, sizeof(M2Vertex), offsetof(M2Vertex, bone_indices)}, // bones {+m2Shader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(M2Vertex), offsetof(M2Vertex, normal)}, // normal + {+m2Shader::Attribute::bones, 4, GBindingType::GUNSIGNED_BYTE, false, sizeof(M2Vertex), offsetof(M2Vertex, bone_indices)}, // bones + {+m2Shader::Attribute::boneWeights, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(M2Vertex), offsetof(M2Vertex, bone_weights)}, // bonesWeight {+m2Shader::Attribute::aTexCoord, 2, GBindingType::GFLOAT, false, sizeof(M2Vertex), offsetof(M2Vertex, tex_coords)}, // texcoord {+m2Shader::Attribute::aTexCoord2, 2, GBindingType::GFLOAT, false, sizeof(M2Vertex), offsetof(M2Vertex, tex_coords[1])} // texcoord }}; @@ -111,6 +111,7 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public const std::vector &renderingMatrices, const HFrameDependantData &fdd, bool isVulkan, + int lightBufferIndex, animTime_t sceneTime); virtual std::shared_ptr createRenderView(bool createOutput) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index d73786717..6c6e73caa 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -9,7 +9,7 @@ std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - if (!device->supportsBindless()) { + if (device->supportsBindless()) { return std::make_shared(std::dynamic_pointer_cast(device), config); } else { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index b345fed2d..6189a3c6d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -16,7 +16,6 @@ #include "../../frame/FrameProfile.h" #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" -#include "view/RenderViewDeferredVLK.h" #include static const ShaderConfig forwardShaderConfig = { @@ -34,7 +33,7 @@ const int adtTexturesBindlessCount = 4096; const int waterTexturesBindlessCount = 1024; static const ShaderConfig m2BindlessShaderConfig = { - "bindless", + "bindless/m2/forward", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -55,7 +54,7 @@ static const ShaderConfig bindlessShaderConfig = { }}; static const ShaderConfig m2WaterfallBindlessShaderConfig = { - "bindless", + "bindless/waterfall", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -66,7 +65,7 @@ static const ShaderConfig m2WaterfallBindlessShaderConfig = { }}; static const ShaderConfig wmoBindlessShaderConfig = { - "bindless", + "bindless/wmo/forward", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -77,7 +76,7 @@ static const ShaderConfig wmoBindlessShaderConfig = { }}; static const ShaderConfig adtBindlessShaderConfig = { - "bindless", + "bindless/adt/forward", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -94,7 +93,7 @@ static const ShaderConfig adtBindlessShaderConfig = { }}; static const ShaderConfig waterBindlessShaderConfig = { - "bindless", + "bindless/water", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -194,10 +193,10 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; - defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + + m_renderPass = defaultView->getRenderPass(); - m_opaqueRenderPass = defaultView->getOpaqueRenderPass(); - m_nonOpaquerenderPass = defaultView->getNonOpaqueRenderPass(); glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); @@ -221,18 +220,14 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, std::shared_ptr MapSceneRenderBindlessVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { if (pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_Opaque && pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_AlphaKey) { - return m_nonOpaquerenderPass; + return getRenderPass(false); } else { - return m_opaqueRenderPass; + return getRenderPass(true); } } -std::string MapSceneRenderBindlessVLK::chooseShadDir(const std::string &shaderName) { - if (useVisBuffer) { - return "visbuffer/"+shaderName; - } else { - return "forward/"+shaderName; - } +std::shared_ptr MapSceneRenderBindlessVLK::getRenderPass(bool isOpaque) { + return m_renderPass; } void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { @@ -249,7 +244,7 @@ void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { pipelineTemplate.backFaceCulling = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; - g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("adtShader"), chooseShadDir("adtShader")}, adtBindlessShaderConfig) + g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) .createPipeline(m_emptyADTVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -280,7 +275,7 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { //Create global water descriptor for bindless textures g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) + .createPipeline(m_emptyWaterVAO, getRenderPass(false), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { ds->beginUpdate() @@ -305,7 +300,7 @@ void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global wmo descriptor for bindless textures - g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("wmoShader"), chooseShadDir("wmoShader")}, wmoBindlessShaderConfig) + g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -334,7 +329,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global m2 descriptor for bindless textures - g_m2Material = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("m2Shader"), chooseShadDir("m2Shader")}, m2BindlessShaderConfig) + g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -383,7 +378,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMateri pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isOpaq ? "m2Shader" : "m2Shader_nonopaq"}, m2BindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) .setMaterialId(generateUniqueM2MatId()) .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) @@ -613,7 +608,7 @@ MapSceneRenderBindlessVLK::createM2Material(const std::shared_ptr const M2MaterialTemplate &m2MaterialTemplate) { ZoneScoped; - auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); auto vertexFragmentDataBindless = std::make_shared>(m2Buffers.meshWideBlocksBindless); auto vertexFragmentData = std::make_shared>(m2Buffers.meshWideBlocks); @@ -667,7 +662,7 @@ MapSceneRenderBindlessVLK::createM2Material(const std::shared_ptr std::shared_ptr MapSceneRenderBindlessVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, const PipelineTemplate &pipelineTemplate, const M2WaterfallMaterialTemplate &m2MaterialTemplate) { - auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); auto &l_sceneWideChunk = sceneWideChunk; auto commonData = std::make_shared>( @@ -729,7 +724,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Particle bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", isOpaq ? "m2ParticleShader" : "m2ParticleShader_nonopaq"}, bindlessShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Particle/forward/m2ParticleShader", "m2Particle/forward/m2ParticleShader"}, bindlessShaderConfig) .createPipeline(m_emptyM2ParticleVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { @@ -756,7 +751,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMate auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; - auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, bindlessShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Ribbon/forward/ribbonShader", "m2Ribbon/forward/ribbonShader"}, bindlessShaderConfig) .createPipeline(m_emptyM2RibbonVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { @@ -839,7 +834,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(c auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) + .createPipeline(m_emptyWaterVAO, getRenderPass(false), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) .bindDescriptorSet(2, waterTexturesDS) @@ -883,7 +878,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMateri auto skyColors = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) - .createPipeline(m_emptySkyVAO, m_nonOpaquerenderPass, pipelineTemplate) + .createPipeline(m_emptySkyVAO, getRenderPass(false), pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() @@ -915,7 +910,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial } std::shared_ptr MapSceneRenderBindlessVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { - auto result = std::make_shared(); + auto result = std::make_shared(); BufferChunkHelperVLK::create(m2Buffers.placementMatrix, result->m_placementMatrix); BufferChunkHelperVLK::create(m2Buffers.boneMatrix, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); @@ -1028,7 +1023,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); -// const auto &meshVlk = (GMeshVLK*) mesh->getObjectId(); + auto const matId = meshVlk->material()->getMaterialId(); auto &drawCommand = drawVec.emplace_back(); @@ -1093,7 +1088,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ uint32_t currentMatId = 0xFFFFFFFF; for (auto const &drawCmd : wmoDrawVec) { -// if (currentMatId != drawCmd.matId) { + if (currentMatId != drawCmd.matId) { auto material = m_renderer.m_wmoMatCacheId[drawCmd.matId].lock(); if (!material) continue; @@ -1101,7 +1096,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ cmdBuf.bindPipeline(material->getPipeline()); currentMatId = drawCmd.matId; -// } + } cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } @@ -1203,6 +1198,7 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh renderingMatricess, framePlan->frameDependentData, true, + -1, mapScene->getCurrentSceneTime()); @@ -1224,7 +1220,7 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh mapScene->doPostLoad(l_this, framePlan); for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { - auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); if (!updatingTarget) updatingTarget = l_this->defaultView; updatingTarget->update( @@ -1322,24 +1318,17 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh auto currentView = renderTarget.target == nullptr ? l_this->defaultView : - std::dynamic_pointer_cast(renderTarget.target); + std::dynamic_pointer_cast(renderTarget.target); { - //Opaque part - { - auto passHelper = currentView->beginOpaquePass(frameBufCmd, false, - frameInputParams->frameParameters->clearColor); - - { - ZoneScopedN("submit opaque"); - VkZone(frameBufCmd, "render opaque") - l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); - } + auto passHelper = currentView->beginPass(frameBufCmd, l_this->getRenderPass(true), false, + frameInputParams->frameParameters->clearColor); + { + //Opaque part + l_this->drawOpaque(frameBufCmd, l_opaqueMeshes); } - currentView->doOpaqueNonOpaqueBarrier(frameBufCmd); +// currentView->doOpaqueNonOpaqueBarrier(frameBufCmd); - auto passHelper = currentView->beginNonOpaquePass(frameBufCmd, false, - frameInputParams->frameParameters->clearColor); { //Sky opaque if (renderSky && skyMesh) @@ -1406,6 +1395,15 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh }); } +void MapSceneRenderBindlessVLK::drawOpaque(CmdBufRecorder &frameBufCmd, + const std::unique_ptr &l_opaqueMeshes) { + { + ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") + l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + } +} + std::shared_ptr MapSceneRenderBindlessVLK::getLastCreatedPlan() { return m_lastCreatedPlan; } @@ -1496,5 +1494,5 @@ HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTem } std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { - return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); + return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 83610dab7..a14b3bbdd 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -15,7 +15,8 @@ #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" #include "../../../engine/objects/scenes/EntityActorsFactory.h" -#include "view/RenderViewDeferredVLK.h" + +class COpaqueMeshCollectorBindlessVLK; class MapSceneRenderBindlessVLK : public MapSceneRenderer { friend class COpaqueMeshCollectorBindlessVLK; @@ -114,9 +115,9 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::shared_ptr createRenderView(bool createOutput) override; std::shared_ptr> meshFactory = std::make_shared>(); -private: - std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); - std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); +protected: + virtual std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); + virtual std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); struct PipelineTemplateHasher { std::size_t operator()(const PipelineTemplate& k) const { @@ -132,7 +133,7 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { }; robin_hood::unordered_flat_map, PipelineTemplateHasher> m_m2StaticMaterials; robin_hood::unordered_flat_map, PipelineTemplateHasher> m_wmoStaticMaterials; -private: +protected: HGDeviceVLK m_device; int m_width = 640; @@ -140,8 +141,6 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::unique_ptr glowPass; - bool useVisBuffer = false; - HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboM2RibbonBuffer; @@ -229,8 +228,7 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::shared_ptr waterTexturesDS = nullptr; std::shared_ptr waterTextureHolder = nullptr; - std::shared_ptr m_opaqueRenderPass; - std::shared_ptr m_nonOpaquerenderPass; + std::shared_ptr m_renderPass; std::shared_ptr m_lastCreatedPlan = nullptr; @@ -244,13 +242,11 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWaterVAO = nullptr; - using RendererViewClass = RenderViewDeferredVLK; - std::shared_ptr defaultView; + using RendererViewClass = RenderViewForwardVLK; + std::shared_ptr defaultView; MeshCount lastMeshCount; - std::string chooseShadDir(const std::string &shaderName); - void createM2GlobalMaterialData(); void createWMOGlobalMaterialData(); void createADTGlobalMaterialData(); @@ -294,15 +290,11 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBufferBindings getDefaultWaterVao() const {return m_emptyWaterVAO;}; std::shared_ptr chooseRenderPass(const PipelineTemplate &pipelineTemplate); + virtual std::shared_ptr getRenderPass(bool isOpaque); + void + drawOpaque(CmdBufRecorder &frameBufCmd, + const std::unique_ptr &l_opaqueMeshes); }; -class IM2ModelDataVisVLK : public IM2ModelData { -public: - ~IM2ModelDataVisVLK() override = default; - std::shared_ptr placementMatrixDS; -}; - - - #endif //AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index f072a305a..07689c50e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -643,6 +643,7 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha renderingMatricess, framePlan->frameDependentData, true, + -1, mapScene->getCurrentSceneTime()); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index c9d630c7a..ba1f59c5c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -111,7 +111,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; - std::shared_ptr> meshFactory = std::shared_ptr>(); + std::shared_ptr> meshFactory = std::make_shared>(); HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp new file mode 100644 index 000000000..b345fed2d --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp @@ -0,0 +1,1500 @@ +// +// Created by Deamon on 12/1/2022. +// + +#include "MapSceneRenderBindlessVLK.h" +#include "../../vulkan/IRenderFunctionVLK.h" +#include "../../../engine/objects/scenes/map.h" +#include "../../../gapi/vulkan/materials/MaterialBuilderVLK.h" +#include "../../../gapi/vulkan/meshes/GMeshVLK.h" +#include "../../../gapi/vulkan/buffers/CBufferChunkVLK.h" +#include "../../../gapi/vulkan/meshes/GM2MeshVLK.h" +#include "materials/IMaterialInstance.h" +#include "../../../gapi/vulkan/meshes/GSortableMeshVLK.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVLK.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" +#include "../../frame/FrameProfile.h" +#include "view/RenderViewForwardVLK.h" +#include "../../../gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder_inline.h" +#include "view/RenderViewDeferredVLK.h" +#include + +static const ShaderConfig forwardShaderConfig = { + "forwardRendering", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }} + } +}; + +const int m2TexturesBindlessCount = 4096; +const int m2WaterfallTexturesBindlessCount = 128; +const int adtTexturesBindlessCount = 4096; +const int waterTexturesBindlessCount = 1024; + +static const ShaderConfig m2BindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {1, { + {6, {VkDescriptorType::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} + }} + }}; +static const ShaderConfig bindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + }}; + +static const ShaderConfig m2WaterfallBindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {3, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2WaterfallTexturesBindlessCount}} + }} + }}; + +static const ShaderConfig wmoBindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} + }} + }}; + +static const ShaderConfig adtBindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }}, + {3, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }}, + {4, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} + }} + }}; + +static const ShaderConfig waterBindlessShaderConfig = { + "bindless", + { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + }}, + {2, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, waterTexturesBindlessCount}} + }} + }}; + +MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, Config *config) : + m_device(hDevice), MapSceneRenderer(config) { + std::cout << "Create Bindless scene renderer " << std::endl; + + iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); + + vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, sizeof(M2Vertex)); + vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); + vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, sizeof(AdtVertex)); + vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, sizeof(WMOVertex)); + vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, sizeof(LiquidVertexFormat)); + vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); + + + { + const float epsilon = 0.f; + std::array vertexBuffer = { + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(-1.0f + epsilon, 1.0f - epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, -1.0f + epsilon)), + mathfu::vec2_packed(mathfu::vec2(1.0f - epsilon, 1.f - epsilon)) + }; + std::vector indexBuffer = { + 0, 1, 2, + 2, 1, 3 + }; + m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + m_drawQuadVao = m_device->createVertexBufferBindings(); + m_drawQuadVao->addVertexBufferBinding(m_vboQuad, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); + m_drawQuadVao->setIndexBuffer(m_iboQuad); + m_drawQuadVao->save(); + } + + //Create m2 shaders + { + m2Buffers.placementMatrix = m_device->createSSBOBuffer("M2 Placement", 1024*1024, sizeof(M2::PlacementMatrix)); + m2Buffers.boneMatrix = m_device->createSSBOBuffer("M2 BoneMatrices",1024*1024, sizeof(mathfu::mat4)); + m2Buffers.m2Colors = m_device->createSSBOBuffer("M2 BoneMatrices", 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureWeights = m_device->createSSBOBuffer("M2 TextureWeight", 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureMatrices = m_device->createSSBOBuffer("M2 TextureMatrices", 1024*1024, sizeof(mathfu::mat4)); + m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer("M2 FragmentData", 1024*1024, sizeof(M2::modelWideBlockPS)); + m2Buffers.m2InstanceData = m_device->createSSBOBuffer("M2 InstanceData", 1024*1024, sizeof(M2::M2InstanceRecordBindless)); + m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS)); + m2Buffers.meshWideBlocksBindless = m_device->createSSBOBuffer("M2 MeshWide Bindless", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); + } + //Create adt Shader buffs + { + adtBuffers.adtMeshWideVSPSes = m_device->createSSBOBuffer("ADT MeshVSPS", 1024*1024, sizeof(ADT::meshWideBlockVSPS)); + adtBuffers.adtMeshWidePSes = m_device->createSSBOBuffer("ADT MeshPS", 1024*1024, sizeof(ADT::meshWideBlockPS)); + adtBuffers.adtInstanceDatas = m_device->createSSBOBuffer("ADT InstanceData", 1024*1024, sizeof(ADT::AdtInstanceData)); + } + //Create wmo Shader buffs + { + wmoBuffers.wmoPlacementMats = m_device->createSSBOBuffer("WMO PlaceMat", 1024*1024, sizeof(mathfu::mat4)); + wmoBuffers.wmoMeshWideVSes = m_device->createSSBOBuffer("WMO MeshWideVS", 1024*1024, sizeof(WMO::meshWideBlockVS)); + wmoBuffers.wmoMeshWidePSes = m_device->createSSBOBuffer("WMO MeshWidePS", 1024*1024, sizeof(WMO::meshWideBlockPS)); + wmoBuffers.wmoMeshWideBindless = m_device->createSSBOBuffer("WMO MeshWideBindless", 1024*1024, sizeof(WMO::meshWideBlockBindless)); + wmoBuffers.wmoPerMeshData = m_device->createSSBOBuffer("WMO PerMeshData", 1024*1024, sizeof(WMO::perMeshData)); + wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer("Scene_VBO_WMOAmbient",16*200, sizeof(mathfu::vec4_packed)); + } + //Create water buffs + { + waterBuffer.waterDataBuffer = m_device->createSSBOBuffer("Water data", 1024, sizeof(Water::meshWideBlockPS)); + waterBuffer.waterBindlessBuffer = m_device->createSSBOBuffer("Water Bindless", 1024, sizeof(Water::WaterBindless)); + } + + m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer("M2 Waterfall Common",200, sizeof(M2::WaterfallData::WaterfallCommon)); + m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer("M2 Waterfall Bindless",200, sizeof(M2::WaterfallData::WaterfallBindless)); + + uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); + uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); + + m_emptyADTVAO = createADTVAO(vboAdtBuffer, iboBuffer); + m_emptyM2VAO = createM2VAO(vboM2Buffer, iboBuffer); + m_emptyM2ParticleVAO = createM2ParticleVAO(nullptr, nullptr); + m_emptyM2RibbonVAO = createM2RibbonVAO(nullptr, nullptr); + m_emptySkyVAO = createSkyVAO(nullptr, nullptr); + m_emptyWMOVAO = createWmoVAO(vboWMOBuffer, iboBuffer, nullptr); + m_emptyWaterVAO = createWaterVAO(vboWaterBuffer, iboBuffer); + m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); + + //Framebuffers for rendering + auto const dataFormat = { ITextureFormat::itRGBA}; + + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + + m_opaqueRenderPass = defaultView->getOpaqueRenderPass(); + m_nonOpaquerenderPass = defaultView->getNonOpaqueRenderPass(); + + glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); + + { + //Create SceneWide descriptor + sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + .createDescriptorSet(0, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo_dynamic(0, sceneWideChunk); + sceneWideDS = ds; + }); + } + + createM2GlobalMaterialData(); + createWMOGlobalMaterialData(); + createADTGlobalMaterialData(); + createM2WaterfallGlobalMaterialData(); + createWaterGlobalMaterialData(); +} + +std::shared_ptr MapSceneRenderBindlessVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { + if (pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_Opaque && pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_AlphaKey) { + return m_nonOpaquerenderPass; + } else { + return m_opaqueRenderPass; + } +} + +std::string MapSceneRenderBindlessVLK::chooseShadDir(const std::string &shaderName) { + if (useVisBuffer) { + return "visbuffer/"+shaderName; + } else { + return "forward/"+shaderName; + } +} + +void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { + adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); + adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); + adtAlphaTextureHolder = std::make_shared(adtTexturesBindlessCount); + + //Create global ADT descriptor for bindless textures + { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("adtShader"), chooseShadDir("adtShader")}, adtBindlessShaderConfig) + .createPipeline(m_emptyADTVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, adtBuffers.adtMeshWideVSPSes) + .ssbo(2, adtBuffers.adtMeshWidePSes) + .ssbo(3, adtBuffers.adtInstanceDatas); + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + adtLayerTextureDS = ds; + }) + .createDescriptorSet(3, [&](std::shared_ptr &ds) { + adtAlphaTextureDS = ds; + }) + .createDescriptorSet(4, [&](std::shared_ptr &ds) { + adtHeightLayerTextureDS = ds; + }).toMaterial(); + } +} + +void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + //Create global water descriptor for bindless textures + g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) + .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [this](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, waterBuffer.waterDataBuffer) + .ssbo(1, wmoBuffers.wmoPlacementMats) + .ssbo(2, waterBuffer.waterBindlessBuffer); + + waterDataDS = ds; + }) + .createDescriptorSet(2, [this](std::shared_ptr &ds) { + waterTexturesDS = ds; + }).toMaterial();; + + waterTextureHolder = std::make_shared(waterTexturesBindlessCount); +} +void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + //Create global wmo descriptor for bindless textures + g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("wmoShader"), chooseShadDir("wmoShader")}, wmoBindlessShaderConfig) + .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, wmoBuffers.wmoPlacementMats) + .ssbo(2, wmoBuffers.wmoMeshWideVSes) + .ssbo(3, wmoBuffers.wmoMeshWidePSes) + .ssbo(4, wmoBuffers.wmoMeshWideBindless) + .ssbo(5, wmoBuffers.wmoGroupAmbient) + .ssbo(6, wmoBuffers.wmoPerMeshData); + + wmoBufferOneDS = ds; + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + wmoTexturesDS = ds; + }).toMaterial(); + wmoTextureHolder = std::make_shared(m2TexturesBindlessCount); +} + +void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { + PipelineTemplate pipelineTemplate; + pipelineTemplate.element = DrawElementMode::TRIANGLES; + pipelineTemplate.depthWrite = true; + pipelineTemplate.depthCulling = true; + pipelineTemplate.backFaceCulling = true; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + + //Create global m2 descriptor for bindless textures + g_m2Material = MaterialBuilderVLK::fromShader(m_device, {chooseShadDir("m2Shader"), chooseShadDir("m2Shader")}, m2BindlessShaderConfig) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(1, m2Buffers.placementMatrix) + .ssbo(2, m2Buffers.modelFragmentDatas) + .ssbo(3, m2Buffers.boneMatrix) + .ssbo(4, m2Buffers.m2Colors) + .ssbo(5, m2Buffers.textureWeights) + .ssbo(6, m2Buffers.textureMatrices) + .ssbo(7, m2Buffers.m2InstanceData) + .ssbo(8, m2Buffers.meshWideBlocks) + .ssbo(9, m2Buffers.meshWideBlocksBindless); + + m2BufferOneDS = ds; + }) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + m2TextureDS = ds; + }).toMaterial(); + m2TextureHolder = std::make_shared(m2TexturesBindlessCount); +} +void MapSceneRenderBindlessVLK::createM2WaterfallGlobalMaterialData() { + MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) + .overridePipelineLayout({{1, m2BufferOneDS}}) + .createDescriptorSet(2, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, m2WaterfallBuffer.waterfallCommon) + .ssbo(1, m2WaterfallBuffer.waterfallBindless); + + m2WaterfallBufferDS = ds; + }) + .createDescriptorSet(3, [&](std::shared_ptr &ds) { + m2WaterfallTextureDS = ds; + }); + + m2WaterfallTextureHolder = std::make_shared(m2WaterfallTexturesBindlessCount); +} + +std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) { + auto i = m_m2StaticMaterials.find(pipelineTemplate); + if (i != m_m2StaticMaterials.end()) { + return i->second; + } + + bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || + pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; + + auto staticMaterial = + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isOpaq ? "m2Shader" : "m2Shader_nonopaq"}, m2BindlessShaderConfig) + .setMaterialId(generateUniqueM2MatId()) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, m2BufferOneDS) + .bindDescriptorSet(2, m2TextureDS) + .toMaterial(); + + m_m2StaticMaterials[pipelineTemplate] = staticMaterial; + m_m2MatCacheId[staticMaterial->getMaterialId()] = staticMaterial; + + return staticMaterial; +} + +std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate) { + auto i = m_wmoStaticMaterials.find(pipelineTemplate); + if (i != m_wmoStaticMaterials.end()) { + return i->second; + } + + auto staticMaterial = + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) + .setMaterialId(generateUniqueWMOMatId()) + .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, wmoBufferOneDS) + .bindDescriptorSet(2, wmoTexturesDS) + .toMaterial(); + + m_wmoStaticMaterials[pipelineTemplate] = staticMaterial; + m_wmoMatCacheId[staticMaterial->getMaterialId()] = staticMaterial; + + return staticMaterial; +} + +// ------------------ +// Buffer creation +// ------------------ + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createADTVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto adtVAO = m_device->createVertexBufferBindings(); + adtVAO->addVertexBufferBinding(vertexBuffer, adtVertexBufferBinding); + adtVAO->setIndexBuffer(indexBuffer); + + return adtVAO; +}; + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createWmoVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer, const std::shared_ptr> &ambientBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto wmoVAO = m_device->createVertexBufferBindings(); + + wmoVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWMOBindings.begin(), staticWMOBindings.end())); + wmoVAO->setIndexBuffer(indexBuffer); + + return wmoVAO; +} +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2VAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2VAO = m_device->createVertexBufferBindings(); + m2VAO->addVertexBufferBinding(vertexBuffer, staticM2Bindings); + m2VAO->setIndexBuffer(indexBuffer); + + return m2VAO; +} +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2ParticleVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2ParticleVAO = m_device->createVertexBufferBindings(); + m2ParticleVAO->addVertexBufferBinding(vertexBuffer, staticM2ParticleBindings); + m2ParticleVAO->setIndexBuffer(indexBuffer); + + return m2ParticleVAO; +} + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createM2RibbonVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto m2RibbonVAO = m_device->createVertexBufferBindings(); + m2RibbonVAO->addVertexBufferBinding(vertexBuffer, staticM2RibbonBindings); + m2RibbonVAO->setIndexBuffer(indexBuffer); + + return m2RibbonVAO; +}; + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createWaterVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto waterVAO = m_device->createVertexBufferBindings(); + waterVAO->addVertexBufferBinding(vertexBuffer, std::vector(staticWaterBindings.begin(), staticWaterBindings.end())); + waterVAO->setIndexBuffer(indexBuffer); + + return waterVAO; +}; + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createSkyVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto skyVAO = m_device->createVertexBufferBindings(); + skyVAO->addVertexBufferBinding(vertexBuffer, std::vector(skyConusBinding.begin(), skyConusBinding.end())); + skyVAO->setIndexBuffer(indexBuffer); + + return skyVAO; +} + +HGVertexBufferBindings MapSceneRenderBindlessVLK::createPortalVAO(HGVertexBuffer vertexBuffer, HGIndexBuffer indexBuffer) { + //VAO doesn't exist in Vulkan, but it's used to hold proper reading rules as well as buffers + auto portalVAO = m_device->createVertexBufferBindings(); + portalVAO->addVertexBufferBinding(vertexBuffer, std::vector(drawPortalBindings.begin(), drawPortalBindings.end())); + portalVAO->setIndexBuffer(indexBuffer); + + return portalVAO; +}; + +HGVertexBuffer MapSceneRenderBindlessVLK::createPortalVertexBuffer(int sizeInBytes) { + return vboPortalBuffer->getSubBuffer(sizeInBytes); +}; +HGIndexBuffer MapSceneRenderBindlessVLK::createPortalIndexBuffer(int sizeInBytes){ + return iboBuffer->getSubBuffer(sizeInBytes); +}; + +HGVertexBuffer MapSceneRenderBindlessVLK::createM2VertexBuffer(int sizeInBytes) { + return vboM2Buffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderBindlessVLK::createM2ParticleVertexBuffer(int sizeInBytes) { + return vboM2ParticleBuffer->getSubBuffer(sizeInBytes); +} +HGVertexBuffer MapSceneRenderBindlessVLK::createM2RibbonVertexBuffer(int sizeInBytes) { + return vboM2RibbonBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderBindlessVLK::createM2IndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderBindlessVLK::createADTVertexBuffer(int sizeInBytes) { + return vboAdtBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderBindlessVLK::createADTIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderBindlessVLK::createWMOVertexBuffer(int sizeInBytes) { + return vboWMOBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderBindlessVLK::createWMOIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + +HGVertexBuffer MapSceneRenderBindlessVLK::createWaterVertexBuffer(int sizeInBytes) { + return vboWaterBuffer->getSubBuffer(sizeInBytes); +} + +HGIndexBuffer MapSceneRenderBindlessVLK::createWaterIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} +HGVertexBuffer MapSceneRenderBindlessVLK::createSkyVertexBuffer(int sizeInBytes) { + return vboSkyBuffer->getSubBuffer(sizeInBytes);; +}; + +HGIndexBuffer MapSceneRenderBindlessVLK::createSkyIndexBuffer(int sizeInBytes) { + return iboBuffer->getSubBuffer(sizeInBytes); +} + + + +std::shared_ptr +MapSceneRenderBindlessVLK::createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) { + ZoneScoped; + auto &l_sceneWideChunk = sceneWideChunk; + auto vertexFragmentData = std::make_shared>(adtBuffers.adtMeshWideVSPSes); + auto fragmentData = std::make_shared>(adtBuffers.adtMeshWidePSes); + auto instanceData = std::make_shared>(adtBuffers.adtInstanceDatas); + + auto material = MaterialBuilderVLK::fromMaterial(m_device, g_adtMaterial) + .toMaterial([&fragmentData, &vertexFragmentData, &instanceData](IADTMaterialVis *instance) -> void { + instance->m_materialVSPS = vertexFragmentData; + instance->m_materialPS = fragmentData; + instance->m_instanceData = instanceData; + }); + + { + auto &adtInstanceData = instanceData->getObject(); + adtInstanceData.meshIndexVSPS = vertexFragmentData->getSubBuffer()->getIndex(); + adtInstanceData.meshIndexPS = fragmentData->getSubBuffer()->getIndex(); + { + auto dsUpdate = adtLayerTextureDS->beginUpdate(); + + for (int i = 0; i < 4; i++) { + auto bindlessText = adtLayerTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.LayerIndexes[i] = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto dsUpdate = adtAlphaTextureDS->beginUpdate(); + + for (int i = 4; i <= 4; i++) { + auto bindlessText = adtAlphaTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.AlphaTextureInd = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto dsUpdate = adtHeightLayerTextureDS->beginUpdate(); + + for (int i = 5; i < 9; i++) { + auto bindlessText = adtHeightLayerTextureHolder->allocate(adtMaterialTemplate.textures[i]); + adtInstanceData.LayerHeight[i-5] = bindlessText->getIndex(); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, adtMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + instanceData->save(); + } + + material->instanceIndex = instanceData->getSubBuffer()->getIndex(); + + return material; +} + +std::shared_ptr +MapSceneRenderBindlessVLK::createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) { + ZoneScoped; + + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + + auto vertexFragmentDataBindless = std::make_shared>(m2Buffers.meshWideBlocksBindless); + auto vertexFragmentData = std::make_shared>(m2Buffers.meshWideBlocks); + + auto staticMaterial = getM2StaticMaterial(pipelineTemplate); + + auto material = MaterialBuilderVLK::fromMaterial(m_device, staticMaterial) + .toMaterial([&vertexFragmentDataBindless, &vertexFragmentData](IM2MaterialVis *instance) -> void { + instance->m_vertexFragmentDataBindless = vertexFragmentDataBindless; + instance->m_vertexFragmentData = vertexFragmentData; + }); + { + auto dsUpdate = m2TextureDS->beginUpdate(); + + for (int i = 0; i < 4; i++) { + auto bindlessText = m2TextureHolder->allocate(m2MaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, m2MaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto &modelFragmentDataVis = vertexFragmentDataBindless->getObject(); + + modelFragmentDataVis.instanceIndex = + BufferChunkHelperVLK::castToChunk(m2ModelDataVisVLK->m_instanceBindless)->getSubBuffer()->getIndex(); + modelFragmentDataVis.meshIndex = + vertexFragmentData->getSubBuffer()->getIndex(); + for (int i = 0; i < 4; i++) { + modelFragmentDataVis.textureIndicies[i] = material->m_bindlessText[i]->getIndex(); + } + + vertexFragmentDataBindless->save(); + } + + material->instanceIndex = vertexFragmentDataBindless->getSubBuffer()->getIndex(); + + material->blendMode = pipelineTemplate.blendMode; + material->depthWrite = pipelineTemplate.depthWrite; + material->depthCulling = pipelineTemplate.depthCulling; + material->backFaceCulling = pipelineTemplate.backFaceCulling; + + material->batchIndex = m2MaterialTemplate.batchIndex; + material->vertexShader = m2MaterialTemplate.vertexShader; + material->pixelShader = m2MaterialTemplate.pixelShader; + + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) { + auto m2ModelDataVisVLK = std::dynamic_pointer_cast(m2ModelData); + + auto &l_sceneWideChunk = sceneWideChunk; + auto commonData = std::make_shared>( + m2WaterfallBuffer.waterfallCommon); + auto bindlessData = std::make_shared>( + m2WaterfallBuffer.waterfallBindless); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, + m2WaterfallBindlessShaderConfig) + .overridePipelineLayout({{1, m2BufferOneDS}}) + .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, m2BufferOneDS) + .bindDescriptorSet(2, m2WaterfallBufferDS) + .bindDescriptorSet(3, m2WaterfallTextureDS) + .toMaterial( + [&commonData, &bindlessData](IM2WaterFallMaterialBindless *instance) -> void { + instance->m_waterfallCommon = commonData; + instance->m_waterfallBindless = bindlessData; + }); + + { + auto dsUpdate = m2WaterfallTextureDS->beginUpdate(); + + for (int i = 0; i < 5; i++) { + auto bindlessText = m2WaterfallTextureHolder->allocate(m2MaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, m2MaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto &bindless = bindlessData->getObject(); + bindless.instanceIndex = BufferChunkHelperVLK::castToChunk(m2ModelDataVisVLK->m_instanceBindless)->getSubBuffer()->getIndex(); + bindless.waterfallInd = commonData->getIndex(); + + bindless.maskInd = material->m_bindlessText[0]->getIndex(); + bindless.whiteWaterInd = material->m_bindlessText[1]->getIndex(); + bindless.noiseInd = material->m_bindlessText[2]->getIndex(); + bindless.bumpTextureInd = material->m_bindlessText[3]->getIndex(); + bindless.normalTexInd = material->m_bindlessText[4]->getIndex(); + + + bindlessData->save(); + } + + material->instanceIndex = bindlessData->getIndex(); + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createM2ParticleMaterial( + const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2ParticleMatTemplate) { + + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + + bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || + pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", isOpaq ? "m2ParticleShader" : "m2ParticleShader_nonopaq"}, bindlessShaderConfig) + .createPipeline(m_emptyM2ParticleVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, *l_fragmentData).delayUpdate(); + }) + .createDescriptorSet(2, [&m2ParticleMatTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(0, m2ParticleMatTemplate.textures[0]) + .texture(1, m2ParticleMatTemplate.textures[1]) + .texture(2, m2ParticleMatTemplate.textures[2]); + }) + .toMaterial([l_fragmentData](IM2ParticleMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto l_fragmentData = std::make_shared>(uboBuffer); ; + auto &l_m2ModelData = m2ModelData; + + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, bindlessShaderConfig) + .createPipeline(m_emptyM2RibbonVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, BufferChunkHelperVLK::cast(l_m2ModelData->m_textureMatrices)) + .ubo(1, *l_fragmentData).delayUpdate(); + }) + .createDescriptorSet(2, [&m2RibbonMaterialTemplate](std::shared_ptr &ds) { + ds->beginUpdate() + .texture(0, m2RibbonMaterialTemplate.textures[0]); + }) + .toMaterial([l_fragmentData](IM2RibbonMaterial *instance) -> void { + instance->m_fragmentData = l_fragmentData; + }); + + return material; +}; + +std::shared_ptr> MapSceneRenderBindlessVLK::createWMOWideChunk() { + return std::make_shared>(wmoBuffers.wmoPlacementMats); +} +std::shared_ptr> MapSceneRenderBindlessVLK::createWMOGroupAmbientChunk() { + return std::make_shared>(wmoBuffers.wmoGroupAmbient); +} + +std::shared_ptr MapSceneRenderBindlessVLK::createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) { + auto l_vertexData = std::make_shared>(wmoBuffers.wmoMeshWideVSes); ; + auto l_fragmentData = std::make_shared>(wmoBuffers.wmoMeshWidePSes); ; + auto l_bindless = std::make_shared>(wmoBuffers.wmoMeshWideBindless); + + auto staticMaterial = getWMOStaticMaterial(pipelineTemplate); + + auto material = MaterialBuilderVLK::fromMaterial(m_device, staticMaterial) + .toMaterial([&l_vertexData, &l_fragmentData, &l_bindless](IWMOMaterialVis *instance) -> void { + instance->m_materialPS = l_fragmentData; + instance->m_materialVS = l_vertexData; + instance->m_meshBindless = l_bindless; + }); + { + auto dsUpdate = wmoTexturesDS->beginUpdate(); + + for (int i = 0; i < 9; i++) { + auto bindlessText = wmoTextureHolder->allocate(wmoMaterialTemplate.textures[i]); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, wmoMaterialTemplate.textures[i], bindlessText->getIndex()); + } + } + + { + auto &bindless = l_bindless->getObject(); + bindless.blockVSIndex = l_vertexData->getIndex(); + bindless.meshWideIndex = l_fragmentData->getIndex(); + bindless.placementMat = BufferChunkHelperVLK::cast(modelWide)->getIndex(); + + bindless.texture1 = material->m_bindlessText[0]->getIndex(); + bindless.texture2 = material->m_bindlessText[1]->getIndex(); + bindless.texture3 = material->m_bindlessText[2]->getIndex(); + bindless.texture4 = material->m_bindlessText[3]->getIndex(); + bindless.texture5 = material->m_bindlessText[4]->getIndex(); + bindless.texture6 = material->m_bindlessText[5]->getIndex(); + bindless.texture7 = material->m_bindlessText[6]->getIndex(); + bindless.texture8 = material->m_bindlessText[7]->getIndex(); + bindless.texture9 = material->m_bindlessText[8]->getIndex(); + + l_bindless->save(); + } + + material->meshWideBindlessIndex = l_bindless->getIndex(); + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) { + auto l_fragmentData = std::make_shared>(waterBuffer.waterDataBuffer); ; + auto l_waterBindless = std::make_shared>(waterBuffer.waterBindlessBuffer); ; + + auto &l_sceneWideChunk = sceneWideChunk; + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) + .createPipeline(m_emptyWaterVAO, m_nonOpaquerenderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .bindDescriptorSet(1, waterDataDS) + .bindDescriptorSet(2, waterTexturesDS) + .toMaterial([&l_fragmentData, l_waterBindless](IWaterMaterialBindless *instance) -> void { + instance->m_materialPS = l_fragmentData; + instance->m_bindless = l_waterBindless; + }); + + material->color = waterMaterialTemplate.color; + material->liquidFlags = waterMaterialTemplate.liquidFlags; + material->materialId = waterMaterialTemplate.liquidMaterialId; + + { + auto dsUpdate = waterTexturesDS->beginUpdate(); + +// for (int i = 0; i < 9; i++) { + auto bindlessText = waterTextureHolder->allocate(waterMaterialTemplate.texture); + material->m_bindlessText.push_back(bindlessText); + dsUpdate.texture(0, waterMaterialTemplate.texture, bindlessText->getIndex()); +// } + } + + { + auto &bindless = l_waterBindless->getObject(); + bindless.placementMatInd = BufferChunkHelperVLK::cast(modelWide)->getIndex(); + bindless.textureInd = material->m_bindlessText[0]->getIndex(); + bindless.waterDataInd = l_fragmentData->getIndex(); + + l_waterBindless->save(); + } + + material->instanceIndex = l_waterBindless->getIndex(); + + return material; +} + + + +std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto skyColors = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) + .createPipeline(m_emptySkyVAO, m_nonOpaquerenderPass, pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, *skyColors).delayUpdate(); + }) + .toMaterial([&skyColors](ISkyMeshMaterial *instance) -> void { + instance->m_skyColors = skyColors; + }); + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial(const PipelineTemplate &pipelineTemplate) { + auto &l_sceneWideChunk = sceneWideChunk; + auto materialPS = std::make_shared>(uboBuffer); + + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) + .createPipeline(m_emptyPortalVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .bindDescriptorSet(0, sceneWideDS) + .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { + ds->beginUpdate() + .ubo(0, *materialPS).delayUpdate(); + }) + .toMaterial([&materialPS](IPortalMaterial *instance) -> void { + instance->m_materialPS = materialPS; + }); + + return material; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) { + auto result = std::make_shared(); + + BufferChunkHelperVLK::create(m2Buffers.placementMatrix, result->m_placementMatrix); + BufferChunkHelperVLK::create(m2Buffers.boneMatrix, result->m_bonesData, sizeof(mathfu::mat4) * bonesCount); + BufferChunkHelperVLK::create(m2Buffers.m2Colors, result->m_colors, sizeof(mathfu::vec4_packed) * m2ColorsCount); + BufferChunkHelperVLK::create(m2Buffers.textureWeights, result->m_textureWeights, sizeof(float) * textureWeightsCount); + BufferChunkHelperVLK::create(m2Buffers.textureMatrices, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); + BufferChunkHelperVLK::create(m2Buffers.modelFragmentDatas, result->m_modelFragmentData); + + BufferChunkHelperVLK::create(m2Buffers.m2InstanceData, result->m_instanceBindless); + + auto &instanceData = result->m_instanceBindless->getObject(); + instanceData.placementMatrixInd = BufferChunkHelperVLK::castToChunk(result->m_placementMatrix)->getSubBuffer()->getIndex(); + instanceData.boneMatrixInd = BufferChunkHelperVLK::castToChunk(result->m_bonesData)->getSubBuffer()->getIndex(); + instanceData.m2ColorsInd = BufferChunkHelperVLK::castToChunk(result->m_colors)->getSubBuffer()->getIndex(); + instanceData.textureWeightsInd = BufferChunkHelperVLK::castToChunk(result->m_textureWeights)->getSubBuffer()->getIndex(); + instanceData.textureMatricesInd = BufferChunkHelperVLK::castToChunk(result->m_textureMatrices)->getSubBuffer()->getIndex(); + instanceData.modelFragmentDatasInd = BufferChunkHelperVLK::castToChunk(result->m_modelFragmentData)->getSubBuffer()->getIndex(); + result->m_instanceBindless->save(); + + return result; +} + +inline void MapSceneRenderBindlessVLK::drawMesh(CmdBufRecorder &cmdBuf, const HGMesh &mesh, CmdBufRecorder::ViewportType viewportType ) { + if (mesh == nullptr) return; + + const auto &meshVlk = (GMeshVLK*) mesh.get(); + + //1. Bind Vertex bindings + cmdBuf.bindVertexBindings(mesh->bindings()); + + //2. Bind Material + cmdBuf.bindMaterial(meshVlk->material()); + + //3. Set view port + cmdBuf.setViewPort(viewportType); + + //4. Set scissors + if (meshVlk->scissorEnabled()) { + cmdBuf.setScissors(meshVlk->scissorOffset(), meshVlk->scissorSize()); + } else { + cmdBuf.setDefaultScissors(); + } + + //5. Draw the mesh + if (meshVlk->instanceIndex != -1) { + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, meshVlk->instanceIndex, meshVlk->vertexStart); + } else { + cmdBuf.drawIndexed(meshVlk->end(), 1, meshVlk->start() / 2, 0); + } +} + +static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { + return {vec[0], vec[1], vec[2]}; +} + +class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ +public: + COpaqueMeshCollectorBindlessVLK(MapSceneRenderBindlessVLK &rendererVlk) : m_renderer(rendererVlk) { + commonMeshes.reserve(1000); + m2DrawVec.reserve(5000); + wmoDrawVec.reserve(5000); + adtDrawVec.reserve(1000); + } + COpaqueMeshCollectorBindlessVLK(MapSceneRenderBindlessVLK &rendererVlk, MeshCount &lastMeshCount) : m_renderer(rendererVlk) { + commonMeshes.reserve(lastMeshCount.commonMesh); + m2DrawVec.reserve(lastMeshCount.m2Mesh); + wmoDrawVec.reserve(lastMeshCount.wmoMesh); + adtDrawVec.reserve(lastMeshCount.adtMesh); + } +private: + MapSceneRenderBindlessVLK &m_renderer; + struct DrawCommand { + uint32_t matId; + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + uint32_t firstInstance; + uint32_t vertexOffset; + }; + + typedef robin_hood::unordered_flat_map, std::vector> MeshMap; + + framebased::vector m2DrawVec; + framebased::vector wmoDrawVec; + MeshMap waterMeshMap; + framebased::vector adtDrawVec; + framebased::vector commonMeshes; + + inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { + const auto &meshVlk = (GMeshVLK*) mesh.get(); + auto const &pipeline = meshVlk->material()->getPipeline(); + + auto &vec = meshMap[pipeline]; + if (vec.empty()) + vec.reserve(3000); + + auto &drawCommand = meshMap[pipeline].emplace_back(); + drawCommand.indexCount = meshVlk->end(); + drawCommand.instanceCount = 1; + drawCommand.firstIndex = meshVlk->start() / 2; + + if (meshVlk->instanceIndex != -1) { + drawCommand.firstInstance = meshVlk->instanceIndex; + drawCommand.vertexOffset = meshVlk->vertexStart; + } else { + drawCommand.firstInstance = 0; + drawCommand.vertexOffset = 0; + } + } + inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { + auto meshId = mesh->getObjectId(); + auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); +// const auto &meshVlk = (GMeshVLK*) mesh->getObjectId(); + auto const matId = meshVlk->material()->getMaterialId(); + + auto &drawCommand = drawVec.emplace_back(); + drawCommand.matId = matId; + drawCommand.indexCount = meshVlk->end(); + drawCommand.instanceCount = 1; + drawCommand.firstIndex = meshVlk->start() / 2; + + if (meshVlk->instanceIndex != -1) { + drawCommand.firstInstance = meshVlk->instanceIndex; + drawCommand.vertexOffset = meshVlk->vertexStart; + } else { + drawCommand.firstInstance = 0; + drawCommand.vertexOffset = 0; + } + } +public: + void addM2Mesh(const HGM2Mesh &mesh) override { + addDrawCommand(m2DrawVec, mesh); + }; + void addWMOMesh(const HGMesh &mesh) override { + addDrawCommand(wmoDrawVec, mesh); + } ; + void addWaterMesh(const HGMesh &mesh) override { + fillMapWithMesh(waterMeshMap, mesh); + } ; + void addADTMesh(const HGMesh &mesh) override { + addDrawCommand(adtDrawVec, mesh); + } ; + + void addMesh(const HGMesh &mesh) override { + commonMeshes.push_back(mesh); + }; + + void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + std::sort(m2DrawVec.begin(), m2DrawVec.end(), [](DrawCommand const &a, DrawCommand const &b) { + return a.matId < b.matId; + }); + std::sort(wmoDrawVec.begin(), wmoDrawVec.end(), [](DrawCommand const &a, DrawCommand const &b) { + return a.matId < b.matId; + }); + + cmdBuf.setDefaultScissors(); + cmdBuf.setViewPort(viewPortType); + + if (!adtDrawVec.empty()) + { + //1. Render ADT + cmdBuf.bindVertexBindings(m_renderer.getDefaultADTVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalADTMaterial()); + + for (auto const & drawCmd : adtDrawVec) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + + if (!wmoDrawVec.empty()) + { + //2. Render WMO + cmdBuf.bindVertexBindings(m_renderer.getDefaultWMOVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalWMOMaterial()); + + uint32_t currentMatId = 0xFFFFFFFF; + for (auto const &drawCmd : wmoDrawVec) { +// if (currentMatId != drawCmd.matId) { + auto material = m_renderer.m_wmoMatCacheId[drawCmd.matId].lock(); + if (!material) + continue; + + cmdBuf.bindPipeline(material->getPipeline()); + + currentMatId = drawCmd.matId; +// } + + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + + if (!m2DrawVec.empty()) + { + //3. Render m2 + cmdBuf.bindVertexBindings(m_renderer.getDefaultM2Vao()); + cmdBuf.bindMaterial(m_renderer.getGlobalM2Material()); + + uint32_t currentMatId = 0xFFFFFFFF; + for (auto const &drawCmd : m2DrawVec) { + if (currentMatId != drawCmd.matId) { + auto material = m_renderer.m_m2MatCacheId[drawCmd.matId].lock(); + if (!material) + continue; + + cmdBuf.bindPipeline(material->getPipeline()); + + currentMatId = drawCmd.matId; + } + + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + + //Render commonMeshes + for (auto const &mesh : commonMeshes ) { + MapSceneRenderBindlessVLK::drawMesh(cmdBuf, mesh, viewPortType); + } + } + void renderWater(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { + cmdBuf.setDefaultScissors(); + cmdBuf.setViewPort(viewPortType); + + if (!waterMeshMap.empty()) + { + //4. Render water + cmdBuf.bindVertexBindings(m_renderer.getDefaultWaterVao()); + cmdBuf.bindMaterial(m_renderer.getGlobalWaterMaterial()); + + for (auto const &record : waterMeshMap) { + cmdBuf.bindPipeline(record.first); + + for (auto const & drawCmd : record.second) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); + } + } + } + } + void fillMeshCount(MeshCount &meshCount) { + meshCount.adtMesh = adtDrawVec.size(); + meshCount.m2Mesh = m2DrawVec.size(); + meshCount.wmoMesh = wmoDrawVec.size(); + meshCount.commonMesh = commonMeshes.size(); + } + +}; + +std::unique_ptr MapSceneRenderBindlessVLK::update(const std::shared_ptr> &frameInputParams, + const std::shared_ptr &framePlan) { + TracyMessageStr(("Update stage frame = " + std::to_string(m_device->getCurrentProcessingFrameNumber()))); + + ZoneScoped; + auto l_this = std::dynamic_pointer_cast(this->shared_from_this()); + auto mapScene = std::dynamic_pointer_cast(frameInputParams->frameParameters->scene); + + + //Create meshes + std::unique_ptr u_collector = std::make_unique(*this, lastMeshCount); + std::unique_ptr u_skyCollector = std::make_unique(*this); + auto transparentMeshes = std::make_shared>(); + + + + auto skyTransparentMeshes = std::make_shared>(); + framePlan->m2Array.lock(); + framePlan->wmoArray.lock(); + framePlan->wmoGroupArray.lock(); + + +// TracyMessageL("collect meshes created"); +// std::future collectMeshAsync = std::async(std::launch::async, +// [&]() { + +// } +// ); + + mapScene->update(framePlan); + mapScene->updateBuffers(l_this, framePlan); + + std::vector renderingMatricess; + for (auto &rt : frameInputParams->frameParameters->renderTargets) { + renderingMatricess.push_back(rt.cameraMatricesForRendering); + } + + updateSceneWideChunk(sceneWideChunk, + renderingMatricess, + framePlan->frameDependentData, + true, + mapScene->getCurrentSceneTime()); + + + collectMeshes(framePlan, *u_collector, *u_skyCollector, transparentMeshes, skyTransparentMeshes); + u_collector->fillMeshCount(lastMeshCount); + +// { +// ZoneScopedN("collect meshes wait"); +// collectMeshAsync.wait(); +// } + + bool renderSky = framePlan->renderSky; + auto skyMesh = framePlan->skyMesh; + auto skyMesh0x4 = framePlan->skyMesh0x4; + return createRenderFuncVLK([l_this, mapScene, framePlan, transparentMeshes, frameInputParams](CmdBufRecorder &uploadCmd) -> void { + { + ZoneScopedN("Post Load"); + //Do postLoad here. So creation of stuff is done from main thread + + mapScene->doPostLoad(l_this, framePlan); + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + if (!updatingTarget) updatingTarget = l_this->defaultView; + + updatingTarget->update( + renderTarget.viewPortDimensions.maxs[0], + renderTarget.viewPortDimensions.maxs[1], + framePlan->frameDependentData->currentGlow + ); + } + } + { + ZoneScopedN("Collect Portal Meshes"); + //And add portal meshes + for (auto const &view: framePlan->viewsHolder.getInteriorViews()) { + view->collectPortalMeshes(*transparentMeshes); + } + { + auto const &exteriorView = framePlan->viewsHolder.getExterior(); + if (exteriorView != nullptr) { + exteriorView->collectPortalMeshes(*transparentMeshes); + } + } + } + { + ZoneScopedN("Set Last Created Plan"); + //Needs to be executed only after lock + l_this->m_lastCreatedPlan = framePlan; + } + // --------------------- + // Upload stuff + // --------------------- + { +// ZoneScopedN("submit buffers"); +// VkZone(uploadCmd, "submit buffers") + uploadCmd.submitBufferUploads(l_this->uboBuffer); + uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); + uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2RibbonBuffer); + uploadCmd.submitBufferUploads(l_this->vboAdtBuffer); + uploadCmd.submitBufferUploads(l_this->vboWMOBuffer); + uploadCmd.submitBufferUploads(l_this->vboWaterBuffer); + uploadCmd.submitBufferUploads(l_this->vboSkyBuffer); + + uploadCmd.submitBufferUploads(l_this->m2Buffers.placementMatrix); + uploadCmd.submitBufferUploads(l_this->m2Buffers.boneMatrix); + uploadCmd.submitBufferUploads(l_this->m2Buffers.m2Colors); + uploadCmd.submitBufferUploads(l_this->m2Buffers.textureWeights); + uploadCmd.submitBufferUploads(l_this->m2Buffers.textureMatrices); + uploadCmd.submitBufferUploads(l_this->m2Buffers.modelFragmentDatas); + uploadCmd.submitBufferUploads(l_this->m2Buffers.m2InstanceData); + uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocks); + uploadCmd.submitBufferUploads(l_this->m2Buffers.meshWideBlocksBindless); + + uploadCmd.submitBufferUploads(l_this->m2WaterfallBuffer.waterfallCommon); + uploadCmd.submitBufferUploads(l_this->m2WaterfallBuffer.waterfallBindless); + + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWidePSes); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtMeshWideVSPSes); + uploadCmd.submitBufferUploads(l_this->adtBuffers.adtInstanceDatas); + + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoPlacementMats); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWideVSes); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWidePSes); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoMeshWideBindless); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoGroupAmbient); + uploadCmd.submitBufferUploads(l_this->wmoBuffers.wmoPerMeshData); + + uploadCmd.submitBufferUploads(l_this->waterBuffer.waterDataBuffer); + uploadCmd.submitBufferUploads(l_this->waterBuffer.waterBindlessBuffer); + + uploadCmd.submitBufferUploads(l_this->iboBuffer); + uploadCmd.submitBufferUploads(l_this->m_vboQuad); + uploadCmd.submitBufferUploads(l_this->m_iboQuad); + } + }, [transparentMeshes, l_opaqueMeshes = std::move(u_collector), + l_skyOpaqueMeshes = std::move(u_skyCollector), + skyTransparentMeshes, + renderSky, + skyMesh, + skyMesh0x4, + mapScene, framePlan, + l_this, frameInputParams](CmdBufRecorder &frameBufCmd, CmdBufRecorder &swapChainCmd) -> void { + + TracyMessageStr(("Draw stage frame = " + std::to_string(l_this->m_device->getCurrentProcessingFrameNumber()))); + + // ---------------------- + // Draw meshes + // ---------------------- + { + uint8_t wideChunkVersion = 0; + for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { + l_this->sceneWideChunk->setCurrentVersion(wideChunkVersion++); + + auto currentView = renderTarget.target == nullptr ? + l_this->defaultView : + std::dynamic_pointer_cast(renderTarget.target); + { + //Opaque part + { + auto passHelper = currentView->beginOpaquePass(frameBufCmd, false, + frameInputParams->frameParameters->clearColor); + + + { + ZoneScopedN("submit opaque"); + VkZone(frameBufCmd, "render opaque") + l_opaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + } + } + currentView->doOpaqueNonOpaqueBarrier(frameBufCmd); + + auto passHelper = currentView->beginNonOpaquePass(frameBufCmd, false, + frameInputParams->frameParameters->clearColor); + { + //Sky opaque + if (renderSky && skyMesh) + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh, + CmdBufRecorder::ViewportType::vp_skyBox); + + l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); + } + { + //Sky transparent + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); + +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); +// +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + if (renderSky && skyMesh0x4) + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh0x4, + CmdBufRecorder::ViewportType::vp_skyBox); + } + { + //Render liquids + l_opaqueMeshes->renderWater(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + } + { + VkZone(frameBufCmd, "render transparent") + ZoneScopedN("submit transparent"); + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); +// +// std::string debugMess = +// "Drawing mesh " +// " meshType = " + std::to_string((int)mesh->getMeshType()) + +// " priorityPlane = " + std::to_string(mesh->priorityPlane()) + +// " sortDistance = " + std::to_string(mesh->getSortDistance()) + +// " blendMode = " + std::to_string((int)mesh->getGxBlendMode()); +// +// auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); + + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } + } + } + { + currentView->doPostGlow(frameBufCmd); + if (currentView == l_this->defaultView) { + currentView->doPostFinal(swapChainCmd); + } else { + currentView->doOutputPass(frameBufCmd); + } + } + } + } + }); +} + +std::shared_ptr MapSceneRenderBindlessVLK::getLastCreatedPlan() { + return m_lastCreatedPlan; +} + +HGMesh MapSceneRenderBindlessVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { + return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); +} + +HGSortableMesh MapSceneRenderBindlessVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); + return mesh; +} + +HGSortableMesh MapSceneRenderBindlessVLK::createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyWaterVAO; + + auto _material = std::dynamic_pointer_cast(material); + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); + + mesh->instanceIndex = _material->instanceIndex; + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + + return mesh; +} + +HGMesh +MapSceneRenderBindlessVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) { + ZoneScoped; + + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyADTVAO; + + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + + return mesh; +} +HGM2Mesh +MapSceneRenderBindlessVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + int layer, int priorityPlane) { + ZoneScoped; + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyM2VAO; + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + + return mesh; +} + +HGMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, + const std::shared_ptr> &ambientBuffer) { + auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); + meshTemplate.bindings = m_emptyWMOVAO; + + auto originalMat = std::dynamic_pointer_cast(material); + auto c_perMeshData = std::make_shared>(wmoBuffers.wmoPerMeshData); + + auto newMat = MaterialBuilderVLK::fromMaterial(m_device, std::dynamic_pointer_cast(material)) + .toMaterial([&c_perMeshData](IWMOMaterialVis *instance) -> void { + instance->m_perMeshData = c_perMeshData; + }); + + { + auto &perMeshData = c_perMeshData->getObject(); + perMeshData.meshWideBindlessIndex = originalMat->meshWideBindlessIndex; + perMeshData.wmoAmbientIndex = BufferChunkHelperVLK::castToChunk(ambientBuffer)->getIndex(); + c_perMeshData->save(); + } + + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); + mesh->instanceIndex = c_perMeshData->getIndex(); + mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); + mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); + return mesh; +} +HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, + const std::shared_ptr &material, + int layer, int priorityPlane) { + auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); + mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; + return mesh; +} + +std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { + return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.h new file mode 100644 index 000000000..4e6e9f561 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.h @@ -0,0 +1,98 @@ +// +// Created by Deamon on 12/1/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSVLK_H + + +#include "../MapSceneRenderer.h" +#include "../../../gapi/vulkan/GDeviceVulkan.h" +#include "../../../gapi/vulkan/buffers/GBufferChunkDynamicVersionedVLK.h" +#include "../materials/IMaterialStructs.h" +#include "passes/FFXGlowPassVLK.h" +#include "../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" +#include "view/RenderViewForwardVLK.h" +#include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" +#include "../../../engine/objects/scenes/EntityActorsFactory.h" +#include "view/RenderViewDeferredVLK.h" +#include "MapSceneRenderBindlessVLK.h" + +class MapSceneRenderVisBufferVLK : public MapSceneRenderBindlessVLK { + friend class COpaqueMeshCollectorBindlessVLK; +public: + explicit MapSceneRenderVisBufferVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderVisBufferVLK() override = default; + + std::unique_ptr update(const std::shared_ptr> &frameInputParams, const std::shared_ptr &framePlan) override; + +//------------------------------------- +// Material creation +//------------------------------------- + + std::shared_ptr createAdtMaterial(const PipelineTemplate &pipelineTemplate, const ADTMaterialTemplate &adtMaterialTemplate) override; + std::shared_ptr createM2ModelMat(int bonesCount, int m2ColorsCount, int textureWeightsCount, int textureMatricesCount) override; + std::shared_ptr createM2Material(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2MaterialTemplate &m2MaterialTemplate) override; + std::shared_ptr createM2WaterfallMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2WaterfallMaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr createM2ParticleMaterial(const PipelineTemplate &pipelineTemplate, + const M2ParticleMaterialTemplate &m2MaterialTemplate) override; + + std::shared_ptr createM2RibbonMaterial(const std::shared_ptr &m2ModelData, + const PipelineTemplate &pipelineTemplate, + const M2RibbonMaterialTemplate &m2RibbonMaterialTemplate) override; + + std::shared_ptr> createWMOWideChunk() override; + std::shared_ptr> createWMOGroupAmbientChunk() override; + + std::shared_ptr createWMOMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WMOMaterialTemplate &wmoMaterialTemplate) override; + std::shared_ptr createWaterMaterial(const std::shared_ptr> &modelWide, + const PipelineTemplate &pipelineTemplate, + const WaterMaterialTemplate &waterMaterialTemplate) override; + + std::shared_ptr createSkyMeshMaterial(const PipelineTemplate &pipelineTemplate) override; + + std::shared_ptr createPortalMaterial(const PipelineTemplate &pipelineTemplate) override; + + std::shared_ptr createRenderView(bool createOutput) override; +protected: + virtual std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate) ; + virtual std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); + + struct PipelineTemplateHasher { + std::size_t operator()(const PipelineTemplate& k) const { + using std::hash; + return (hash{}(k.backFaceCulling) << 2) ^ + (hash{}(k.triCCW) << 4) ^ + (hash{}(k.depthCulling) << 8) ^ + (hash{}(k.depthWrite) << 10) ^ + (hash{}(k.blendMode) << 14) ^ + (hash{}(k.element) << 16) ^ + (hash{}(k.colorMask) << 18); + }; + }; + robin_hood::unordered_flat_map, PipelineTemplateHasher> m_m2StaticMaterials; + robin_hood::unordered_flat_map, PipelineTemplateHasher> m_wmoStaticMaterials; + +public: + const std::shared_ptr &getGlobalADTMaterial() const {return g_adtMaterial;}; + const std::shared_ptr &getGlobalM2Material() const {return g_m2Material;}; + const std::shared_ptr &getGlobalWMOMaterial() const {return g_wmoMaterial;}; + const std::shared_ptr &getGlobalWaterMaterial() const {return g_waterMaterial;}; + + HGVertexBufferBindings getDefaultADTVao() const {return m_emptyADTVAO;}; + HGVertexBufferBindings getDefaultM2Vao() const {return m_emptyM2VAO;}; + HGVertexBufferBindings getDefaultWMOVao() const {return m_emptyWMOVAO;}; + HGVertexBufferBindings getDefaultWaterVao() const {return m_emptyWaterVAO;}; + + std::shared_ptr chooseRenderPass(const PipelineTemplate &pipelineTemplate); + +}; + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERVISVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/IRenderViewVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/IRenderViewVLK.h new file mode 100644 index 000000000..301ea8ab1 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/IRenderViewVLK.h @@ -0,0 +1,8 @@ +// +// Created by Deamon on 2/17/2024. +// + +#ifndef AWEBWOWVIEWERCPP_IRENDERVIEWVLK_H +#define AWEBWOWVIEWERCPP_IRENDERVIEWVLK_H + +#endif //AWEBWOWVIEWERCPP_IRENDERVIEWVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 7c919f689..752de89b5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -30,10 +30,9 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, void RenderViewDeferredVLK::createFrameBuffers() { { auto const dataFormat = { - ITextureFormat::itRGBA, //Diffuse - ITextureFormat::itRGBA, //Normal - ITextureFormat::itRGBAFloat32, //ViewPos - ITextureFormat::itInt //MatProps + ITextureFormat::itRGBA, //Albedo + ITextureFormat::itRGBA, //Specular + ITextureFormat::itRGBA //Normal }; auto depthFormat = ITextureFormat::itDepth32; @@ -69,10 +68,7 @@ void RenderViewDeferredVLK::createFrameBuffers() { attachmentsToCopy, m_nonOpaqueRenderPass ); - } - - } if (m_createOutputFBO) { auto const dataFormat = {ITextureFormat::itRGBA}; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp index e83899b6b..b872ca0b7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -23,21 +23,30 @@ RenderViewForwardVLK::RenderViewForwardVLK(const HGDeviceVLK &device, glowPass->updateDimensions(m_width, m_height, inputColorTextures, - !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); } } void RenderViewForwardVLK::createFrameBuffers() { { auto const dataFormat = {ITextureFormat::itRGBA}; + auto depthFormat = ITextureFormat::itDepth32; + bool invertZ = true; + + m_mainRenderPass = m_device->getRenderPass(dataFormat, + depthFormat, + sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + invertZ, false, + true, true); + for (auto &colorFrameBuffer: m_colorFrameBuffers) { colorFrameBuffer = std::make_shared( *m_device, dataFormat, - ITextureFormat::itDepth32, + depthFormat, m_device->getMaxSamplesCnt(), - true, + invertZ, m_width, m_height ); } @@ -46,7 +55,7 @@ void RenderViewForwardVLK::createFrameBuffers() { auto const dataFormat = {ITextureFormat::itRGBA}; bool invertZ = false; - m_renderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, + m_outputRenderPass = m_device->getRenderPass(dataFormat, ITextureFormat::itNone, VK_SAMPLE_COUNT_1_BIT, invertZ, false, true, true); @@ -82,7 +91,7 @@ void RenderViewForwardVLK::update(int width, int height, float glow) { glowPass->updateDimensions(m_width, m_height, inputColorTextures, - !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_renderPass); + !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); } this->executeOnChange(); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h index 5c0e66054..7e04f74f7 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.h @@ -26,6 +26,8 @@ class RenderViewForwardVLK : public IRenderView { void iterateOverOutputTextures(std::function, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, const std::string &name, ITextureFormat textureFormat)> callback) override; void readRGBAPixels(int frameNumber, int x, int y, int width, int height, void *outputdata); + + std::shared_ptr getRenderPass() {return m_mainRenderPass;} private: uint32_t m_width = 640; uint32_t m_height = 480; @@ -33,10 +35,11 @@ class RenderViewForwardVLK : public IRenderView { HGDeviceVLK m_device; bool m_createOutputFBO; + std::shared_ptr m_mainRenderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; std::unique_ptr glowPass; - std::shared_ptr m_renderPass; + std::shared_ptr m_outputRenderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; void createFrameBuffers(); From c31dd94fd85223e1bc79310303e0b64827db2956 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 14 Mar 2024 09:51:33 +0200 Subject: [PATCH 176/212] - restore forward bindless --- wowViewerLib/CMakeLists.txt | 2 + .../glsl/bindless/m2/m2shader_text.glsl | 2 - .../glsl/bindless/wmo/wmoshader_text.glsl | 3 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 40 +- .../src/engine/shader/ShaderDefinitions.h | 474 +++--------------- .../src/gapi/UniformBufferStructures.h | 1 - .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../mapScene/MapSceneRendererFactory.cpp | 2 +- .../MapSceneRenderBindlessDeferredVLK.cpp | 2 + .../MapSceneRenderBindlessDeferredVLK.h | 20 + .../vulkan/MapSceneRenderBindlessVLK.cpp | 3 +- 11 files changed, 127 insertions(+), 424 deletions(-) create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.cpp create mode 100644 wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index fb115c880..14ea4a076 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -527,6 +527,8 @@ if (LINK_VULKAN) src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h + src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.cpp + src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.h src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp src/gapi/vulkan/buffers/GBufferVLK.cpp diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl index e41f9af0b..3791092b8 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -152,8 +152,6 @@ void main() { finalOpacity ); #endif - - finalColor = vec4(matDiffuse, finalOpacity); } // ------------------------------ diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index 1c442df0f..5add4ebfc 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -67,7 +67,7 @@ void main() { ); if (doDiscard) - discard; + discard; InteriorLightParam intLight; intLight.uInteriorAmbientColorAndApplyInteriorLight = s_wmoAmbient[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.y]; @@ -91,7 +91,6 @@ void main() { finalOpacity ); #endif - finalColor.rgb = matDiffuse; #ifndef DEFERRED finalColor = makeFog2(fogData/*, int(scene.extLight.adtSpecMult_fogCount.y)*/, finalColor, scene.uViewUpSceneTime.xyz, diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index 18d862a73..b2da35357 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -95,26 +95,26 @@ void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Obje void M2MeshBufferUpdater::fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS) { bool BCLoginScreenHack = m2Object.m_api->getConfig()->BCLightHack; - int lightCount = (int) std::min(m2Object.lights.size(), (size_t) 4); - for (int j = 0; j < lightCount; j++) { - std::string uniformName; - mathfu::vec4 attenVec; - - attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, m2Object.lights[j].diffuse_intensity, m2Object.lights[j].attenuation_end, m2Object.lights.size()); - - - modelBlockPS.pc_lights[j].attenuation = attenVec;//;lights[i].diffuse_color); - - if (BCLoginScreenHack) { - modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color ; - } else { - modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color * m2Object.lights[j].diffuse_intensity; - } - -// mathfu::vec4 viewPos = modelView * m2Object.lights[j].position; - modelBlockPS.pc_lights[j].position = m2Object.lights[j].position; - } - modelBlockPS.LightCount = lightCount; +// int lightCount = (int) std::min(m2Object.lights.size(), (size_t) 4); +// for (int j = 0; j < lightCount; j++) { +// std::string uniformName; +// mathfu::vec4 attenVec; +// +// attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, m2Object.lights[j].diffuse_intensity, m2Object.lights[j].attenuation_end, m2Object.lights.size()); +// +// +// modelBlockPS.pc_lights[j].attenuation = attenVec;//;lights[i].diffuse_color); +// +// if (BCLoginScreenHack) { +// modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color ; +// } else { +// modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color * m2Object.lights[j].diffuse_intensity; +// } +// +//// mathfu::vec4 viewPos = modelView * m2Object.lights[j].position; +// modelBlockPS.pc_lights[j].position = m2Object.lights[j].position; +// } +// modelBlockPS.LightCount = lightCount; modelBlockPS.bcHack = BCLoginScreenHack ? 1 : 0; } diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f200f3773..87a90c3d2 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -392,9 +392,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -475,7 +472,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -533,11 +529,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -841,11 +836,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,1,12}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1031,11 +1025,10 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1070,11 +1063,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1088,12 +1080,9 @@ const std::unordered_map shaderMetaInfo = { {1,9,0}, {1,8,0}, {1,7,0}, - {1,2,0}, {1,5,0}, {1,4,0}, {1,6,0}, - {1,1,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1409,17 +1398,11 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1471,7 +1454,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -1577,11 +1559,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1595,9 +1576,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,4,0}, {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1641,11 +1619,6 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1723,12 +1696,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1763,11 +1734,6 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -1919,7 +1885,6 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, - {1,1,0}, }, { {2,0, "s_Textures"}, @@ -1998,16 +1963,14 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2021,11 +1984,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2038,15 +2000,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -2086,15 +2039,6 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { {3,0, "s_Textures"}, @@ -2136,8 +2080,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,5,0}, }, { }, @@ -2217,8 +2159,6 @@ const std::unordered_map shaderMetaInfo = { {1,5,0}, {1,4,0}, {1,6,0}, - {1,1,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, @@ -2260,8 +2200,6 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, @@ -2287,17 +2225,12 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, }, { { {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2384,7 +2317,6 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { }, @@ -2599,11 +2531,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2642,10 +2573,6 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index 6c6e73caa..d73786717 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -9,7 +9,7 @@ std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: - if (device->supportsBindless()) { + if (!device->supportsBindless()) { return std::make_shared(std::dynamic_pointer_cast(device), config); } else { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.cpp new file mode 100644 index 000000000..03c7041b2 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.cpp @@ -0,0 +1,2 @@ +#include "MapSceneRenderBindlessDeferredVLK.h" + diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.h new file mode 100644 index 000000000..65de330f5 --- /dev/null +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessDeferredVLK.h @@ -0,0 +1,20 @@ +// +// Created by Deamon on 12/1/2022. +// + +#ifndef AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSDEFERREDVLK_H +#define AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSDEFERREDVLK_H + +#include "MapSceneRenderBindlessVLK.h" + +class COpaqueMeshCollectorBindlessVLK; + +class MapSceneRenderBindlessDeferredVLK : public MapSceneRenderBindlessVLK { + friend class COpaqueMeshCollectorBindlessVLK; +public: + explicit MapSceneRenderBindlessDeferredVLK(const HGDeviceVLK &hDevice, Config *config); + ~MapSceneRenderBindlessDeferredVLK() override = default; + +}; + +#endif //AWEBWOWVIEWERCPP_MAPSCENERENDERBINDLESSDEFERREDVLK_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 6189a3c6d..ea552b174 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -53,8 +53,9 @@ static const ShaderConfig bindlessShaderConfig = { }}, }}; + static const ShaderConfig m2WaterfallBindlessShaderConfig = { - "bindless/waterfall", + "bindless/waterfall/forward", { {0, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} From 32936f17a5f5e39f185dbc4f470017bcf3e2d35e Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 27 Mar 2024 19:31:17 +0200 Subject: [PATCH 177/212] multi threadin experiments --- .../glsl/bindless/adt/adtShader_text.glsl | 11 +- .../bindless/m2/forward/m2Shader_opaque.frag | 8 + .../glsl/bindless/m2/m2shader_text.glsl | 17 +- .../m2Particle/m2ParticleShader_text.glsl | 10 +- .../wmo/forward/wmoShader_opaque.frag | 7 + .../glsl/bindless/wmo/wmoshader_text.glsl | 7 +- .../FrameBasedStackAllocator.h | 3 + .../src/engine/managers/CRibbonEmitter.cpp | 2 +- .../src/engine/managers/CRibbonEmitter.h | 2 +- .../managers/particles/particleEmitter.cpp | 2 +- .../managers/particles/particleEmitter.h | 2 +- .../src/engine/objects/m2/m2Object.cpp | 4 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../src/engine/objects/scenes/map.cpp | 5 +- .../src/engine/shader/ShaderDefinitions.h | 474 +++++++++++++++--- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 4 + .../vulkan/commandBuffer/CommandBuffer.cpp | 12 +- .../gapi/vulkan/commandBuffer/CommandBuffer.h | 3 +- .../CommandBufferRecorder.cpp | 30 +- .../CommandBufferRecorder.h | 5 +- .../commandPoolThread/CommandPoolThread.cpp | 87 ++++ .../commandPoolThread/CommandPoolThread.h | 50 ++ .../renderer/mapScene/MapSceneRenderer.cpp | 50 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 47 +- 25 files changed, 705 insertions(+), 143 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.cpp create mode 100644 wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.h diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl index f365ec8f3..c669e8f87 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -1,11 +1,14 @@ precision highp float; precision highp int; -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" -#include "../../../common/commonADTMaterial.glsl" -#include "../../../common/commonAdtIndirectDescriptorSet.glsl" +#include "../../common/commonADTMaterial.glsl" +#include "../../common/commonAdtIndirectDescriptorSet.glsl" + +//ADT is always opaque +layout(early_fragment_tests) in; layout(location = 0) in vec2 vChunkCoords; layout(location = 1) in vec3 vPosition; diff --git a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag new file mode 100644 index 000000000..f05e08424 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag @@ -0,0 +1,8 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define TRUE_OPAQUE + +#include "../m2shader_text.glsl" \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl index 3791092b8..d7cfb8f2c 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -1,10 +1,13 @@ precision highp float; precision highp int; -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonM2Material.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonM2Material.glsl" +#ifdef TRUE_OPAQUE +layout(early_fragment_tests) in; +#endif layout(location=0) in vec2 vTexCoord; layout(location=1) in vec2 vTexCoord2; layout(location=2) in vec3 vNormal; @@ -19,10 +22,12 @@ layout(location = 1) out vec4 outSpecular; layout(location = 2) out vec4 outNormal; #endif -#include "../../../common/commonUboSceneData.glsl" + + +#include "../../common/commonUboSceneData.glsl" //Whole model -#include "../../../common/commonM2IndirectDescriptorSet.glsl" +#include "../../common/commonM2IndirectDescriptorSet.glsl" layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; @@ -125,8 +130,10 @@ void main() { matDiffuse, specular, finalOpacity, doDiscard ); +#ifndef TRUE_OPAQUE if (doDiscard) discard; +#endif // ------------------------------ // Apply lighting diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl index 18bf64a85..eac148306 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl @@ -1,6 +1,10 @@ precision highp float; precision highp int; +#ifdef TRUE_OPAQUE +layout(early_fragment_tests) in; +#endif + layout (location = 0) in vec3 vPosition; layout (location = 1) in vec4 vColor; layout (location = 2) in vec2 vTexcoord0; @@ -8,9 +12,9 @@ layout (location = 3) in vec2 vTexcoord1; layout (location = 4) in vec2 vTexcoord2; layout (location = 5) in float alphaCutoff; -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonUboSceneData.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonUboSceneData.glsl" //Individual meshes layout (std140, set = 1, binding = 0) uniform meshWideBlockPS { diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag new file mode 100644 index 000000000..0f4a651ed --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier: require + +#define TRUE_OPAQUE + +#include "../wmoshader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index 5add4ebfc..ceb76cfde 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -9,6 +9,10 @@ precision highp int; #include "../../../common/commonWMOMaterial.glsl" #include "../../../common/commonUboSceneData.glsl" +#ifdef TRUE_OPAQUE +layout(early_fragment_tests) in; +#endif + layout (location = 0) in vec2 vTexCoord; layout (location = 1) in vec2 vTexCoord2; layout (location = 2) in vec2 vTexCoord3; @@ -65,9 +69,10 @@ void main() { matDiffuse, spec, emissive, finalOpacity, doDiscard ); - +#ifndef TRUE_OPAQUE if (doDiscard) discard; +#endif InteriorLightParam intLight; intLight.uInteriorAmbientColorAndApplyInteriorLight = s_wmoAmbient[perMeshData.meshWideBindlessIndex_wmoAmbientIndex.y]; diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index bd4a4cde5..ca01d7b5b 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -13,6 +13,9 @@ #include "tbb/tbb.h" #include "tbb/scalable_allocator.h" +template +using transp_vec = tbb::concurrent_vector; + namespace framebased { #if ((defined (_GLIBCXX_VECTOR) \ diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 7eb5ce931..54ae79d39 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -839,7 +839,7 @@ void CRibbonEmitter::Initialize(float edgesPerSec, float edgeLifeSpanInSec, CImV this->m_ribbonEmitterflags.m_initialized = 1; } -void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { +void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { auto &currFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; if (currFrame.isDead) return; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.h b/wowViewerLib/src/engine/managers/CRibbonEmitter.h index 3986e8c01..8e3dc7b5f 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.h +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.h @@ -122,7 +122,7 @@ class CRibbonEmitter { //CTexture **SetTexture(unsigned int a2, CTexture *a3); //int ReplaceTexture(unsigned int a2, CTexture *a3); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 18c68146c..f0a4cef6e 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -1114,7 +1114,7 @@ ParticleEmitter::BuildQuadT3( } -void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { +void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index c579cb634..326612b4d 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -68,7 +68,7 @@ class ParticleEmitter { CParticleGenerator * getGenerator(){ return generator; } - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); void updateBuffers(); void fitBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 198c08960..cd3394036 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1651,7 +1651,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index return m2Mesh; } -void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { +void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; @@ -1928,7 +1928,7 @@ int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { return -1; } -void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder) { +void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { // return; // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 47aa7680b..76699adfb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -245,7 +245,7 @@ class M2Object : public ObjectWithId { mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); bool setUseLocalLighting(bool value) { if (m_useLocalDiffuseColor == -1) { @@ -289,7 +289,7 @@ class M2Object : public ObjectWithId { m_ambientColorOverride = ambientColor; } - void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); + void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); void createVertexBindings(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 13a90878f..3e36528c4 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1576,7 +1576,8 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe if (granSize > 0) { auto l_device = m_api->hDevice; - auto processingFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto oldProcessingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); + auto processingFrame = oldProcessingFrame % IDevice::MAX_FRAMES_IN_FLIGHT; oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); arena.execute([&] { tbb::affinity_partitioner ap; @@ -1592,6 +1593,8 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe } }, ap); }); + //Restore processing frame + l_device->setCurrentProcessingFrameNumber(oldProcessingFrame); } // for (auto &m2Object: renderPlan->m2Array.getDrawn()) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 87a90c3d2..f200f3773 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -392,6 +392,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, }, { { @@ -472,6 +475,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,544}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -529,10 +533,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -836,10 +841,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1025,10 +1031,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1063,10 +1070,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1080,9 +1088,12 @@ const std::unordered_map shaderMetaInfo = { {1,9,0}, {1,8,0}, {1,7,0}, + {1,2,0}, {1,5,0}, {1,4,0}, {1,6,0}, + {1,1,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -1398,11 +1409,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, + {1,0,64}, + {1,1,256}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1454,6 +1471,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -1559,10 +1577,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1576,6 +1595,9 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,4,0}, {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -1619,6 +1641,11 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -1696,10 +1723,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1734,6 +1763,11 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { }, @@ -1885,6 +1919,7 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, @@ -1963,14 +1998,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1984,10 +2021,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2000,6 +2038,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -2039,6 +2086,15 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, @@ -2080,6 +2136,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { }, @@ -2159,6 +2217,8 @@ const std::unordered_map shaderMetaInfo = { {1,5,0}, {1,4,0}, {1,6,0}, + {1,1,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, @@ -2200,6 +2260,8 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, @@ -2225,12 +2287,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,544}, + {1,1,256}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2317,6 +2384,7 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { }, @@ -2531,10 +2599,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2573,6 +2642,10 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 3250060c3..979faf367 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -58,6 +58,10 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this getSubmitRecords(); void resize(int newLength); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp index 78e53a26b..755aa5583 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.cpp @@ -8,10 +8,8 @@ GCommandBuffer::GCommandBuffer(IDeviceVulkan &deviceVlk, VkQueue vkQueue, VkCommandPool commandPool, - bool isPrimary, - uint32_t queueFamilyIndex) : m_device(deviceVlk), + bool isPrimary) : m_device(deviceVlk), m_isPrimary(isPrimary), - m_queueFamilyIndex(queueFamilyIndex), m_commandPool(commandPool), m_vkQueue(vkQueue) { @@ -41,8 +39,10 @@ void GCommandBuffer::createCommandBufVLK() { auto l_cmdBuf = m_cmdBuffer; #ifdef LINK_TRACY - auto l_tracyContext = tracyContext; - TracyVkCollect(l_tracyContext, l_cmdBuf); + if (m_isPrimary) { + auto l_tracyContext = tracyContext; + TracyVkCollect(l_tracyContext, l_cmdBuf); + } #endif vkResetCommandBuffer(m_cmdBuffer, 0); @@ -59,7 +59,7 @@ void GCommandBuffer::createCommandBufVLK() { } } - if (!m_cmdBufWasCreated) { + if (!m_cmdBufWasCreated && m_isPrimary) { #ifdef LINK_TRACY tracyContext = TracyVkContext(m_device.getVkPhysicalDevice(), m_device.getVkDevice(), m_vkQueue, m_cmdBuffer); #endif diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h index 49bfdcf9d..9d2599180 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/CommandBuffer.h @@ -20,7 +20,7 @@ class GCommandBuffer { friend class IDeviceVulkan; public: - GCommandBuffer(IDeviceVulkan &deviceVlk, VkQueue vkQueue, VkCommandPool commandPool, bool isPrimary, uint32_t queueFamilyIndex); + GCommandBuffer(IDeviceVulkan &deviceVlk, VkQueue vkQueue, VkCommandPool commandPool, bool isPrimary); CmdBufRecorder beginRecord(const std::shared_ptr &renderPass); VkCommandBuffer getNativeCmdBuffer() const { @@ -34,7 +34,6 @@ class GCommandBuffer { VkCommandBuffer m_cmdBuffer; VkQueue m_vkQueue; bool m_isPrimary = true; - const uint32_t m_queueFamilyIndex; VkCommandPool m_commandPool; bool m_cmdBufWasCreated = false; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 5f5fbb097..1687ab923 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -29,7 +29,8 @@ CmdBufRecorder::CmdBufRecorder(GCommandBuffer &cmdBuffer, const std::shared_ptr< VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | + ((renderPass != nullptr) ? (VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) : 0); beginInfo.pNext = NULL; beginInfo.pInheritanceInfo = (renderPass != nullptr) ? &bufferInheritanceInfo : nullptr; @@ -48,11 +49,18 @@ CmdBufRecorder::~CmdBufRecorder() { } } +void CmdBufRecorder::setSecondaryCmdRenderArea(const std::array &areaOffset, + const std::array &areaSize) { + std::array fixedAreasSize = { + std::max(1, areaSize[0]), + std::max(1, areaSize[1]) + }; -uint32_t CmdBufRecorder::getQueueFamily() { - return m_gCmdBuffer.m_queueFamilyIndex; -} + createViewPortTypes(areaOffset, fixedAreasSize, m_currentRenderPass->getInvertZ()); + createDefaultScissors(areaOffset, fixedAreasSize); + setDefaultScissors(); +} RenderPassHelper CmdBufRecorder::beginRenderPass( bool isAboutToExecSecondaryCMD, @@ -89,7 +97,9 @@ RenderPassHelper CmdBufRecorder::beginRenderPass( isAboutToExecSecondaryCMD, renderPassVlk, frameBuffer, areaOffset, fixedAreasSize, colorClearColor ); - setDefaultScissors(); + if (!isAboutToExecSecondaryCMD) { + setDefaultScissors(); + } return renderPass; } @@ -158,6 +168,12 @@ void CmdBufRecorder::drawIndexed(uint32_t indexCount, uint32_t instanceCount, ui firstInstance); } +void CmdBufRecorder::executeSecondaryCmdBuffer(const std::shared_ptr &cmdBuffer) { + std::array buffers = {cmdBuffer->getNativeCmdBuffer()}; + + vkCmdExecuteCommands(m_gCmdBuffer.m_cmdBuffer, 1, buffers.data()); +} + void CmdBufRecorder::recordPipelineImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const std::vector &imageBarrierData) { vkCmdPipelineBarrier( @@ -193,6 +209,10 @@ void CmdBufRecorder::copyBufferToImage(VkBuffer buffer, VkImage image, const std } void CmdBufRecorder::submitBufferUploads(const std::shared_ptr &bufferVLK) { +// TracyMessageStr(("Submiting buffer " + bufferVLK->getName())); + ZoneScopedN("submitBufferUploads"); + + auto submitRecords = bufferVLK->getSubmitRecords(); if (submitRecords.get().empty()) diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index a5be62217..6ecdba6cf 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -40,7 +40,8 @@ class CmdBufRecorder { CmdBufRecorder operator=(const CmdBufRecorder&) = delete; ~CmdBufRecorder(); - uint32_t getQueueFamily(); + void setSecondaryCmdRenderArea(const std::array &areaOffset, + const std::array &areaSize); RenderPassHelper beginRenderPass( bool isAboutToExecSecondaryCMD, @@ -63,6 +64,8 @@ class CmdBufRecorder { void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance, uint32_t vertexOffset = 0); + void executeSecondaryCmdBuffer(const std::shared_ptr &cmdBuffer); + void setScissors(const std::array &areaOffset, const std::array &areaSize); void setDefaultScissors(); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.cpp new file mode 100644 index 000000000..911d85f32 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.cpp @@ -0,0 +1,87 @@ +// +// Created by Deamon on 3/18/2024. +// + +#include "CommandPoolThread.h" + +CommandPoolThread::CommandPoolThread(const HGDeviceVLK &device, const std::string &name) : m_device(device) { + m_thread = std::thread([&, l_name= name] { + setThreadName(l_name.c_str()); + + VkCommandPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.pNext = NULL; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + poolInfo.queueFamilyIndex = m_device->getQueueFamilyIndices().graphicsFamily.value(); + + if (vkCreateCommandPool(m_device->getVkDevice(), &poolInfo, nullptr, &m_commandPool) != VK_SUCCESS) { + throw std::runtime_error("failed to create graphics command pool!"); + } + + for (auto &cmdBuff : m_commandBuffers) { + cmdBuff = std::make_shared( + *m_device, + VK_NULL_HANDLE, + m_commandPool, + false + ); + } + uint32_t lastFrame = m_device->getFrameNumber() + 10; + while (!this->m_isTerminating) { + auto input = poolInput.waitForNewInput(); + + uint32_t currentFrame = input.currentProcessingFrame; + if (lastFrame == currentFrame) { + std::cerr << "Same pool was called twice in a frame" << std::endl; + throw "Same pool was called twice in a frame"; + } + + lastFrame = currentFrame; + + if (input.task) { + (*input.task)(); + } + } + }); +} + +CommandPoolThread::~CommandPoolThread() { + m_isTerminating = true; + + poolInput.pushInput({}); + + m_thread.join(); +} + +std::shared_future> +CommandPoolThread::asyncRecordSecondaryBuffer(std::function callback, + const std::shared_ptr &renderPass, + const std::array &areaOffset, + const std::array &areaSize, + uint32_t currentProcessingFrame + ) { + + HCommandTask task = std::make_shared([&, + l_renderPass = renderPass, + l_currentProcessingFrame = currentProcessingFrame, + l_callback = std::move(callback), + l_areaOffset = areaOffset, + l_areaSize = areaSize]() { + auto commandBuffer = m_commandBuffers[l_currentProcessingFrame % (IDevice::MAX_FRAMES_IN_FLIGHT + 1)]; + + auto cmdRecorder = commandBuffer->beginRecord(l_renderPass); + cmdRecorder.setSecondaryCmdRenderArea(l_areaOffset, l_areaSize); + + l_callback(cmdRecorder); + + return commandBuffer; + }); + + CommandBuffRequest request; + request.task = task; + request.currentProcessingFrame = currentProcessingFrame; + + poolInput.pushInput(request); + + return task->get_future(); +} diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.h new file mode 100644 index 000000000..edd954e61 --- /dev/null +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandPoolThread/CommandPoolThread.h @@ -0,0 +1,50 @@ +// +// Created by Deamon on 3/18/2024. +// + +#ifndef AWEBWOWVIEWERCPP_COMMANDPOOLTHREAD_H +#define AWEBWOWVIEWERCPP_COMMANDPOOLTHREAD_H + + +#include "../../IDeviceVulkan.h" +#include "../../../../renderer/frame/prodConsumerChain/ProdConsumerIOConnector.h" +#include "../CommandBuffer.h" +#include +#include + +class CommandPoolThread { +public: + CommandPoolThread(const HGDeviceVLK &device, const std::string &name); + ~CommandPoolThread(); + + std::shared_future> asyncRecordSecondaryBuffer( + std::function callback, + const std::shared_ptr &renderPass, + const std::array &areaOffset, + const std::array &areaSize, + uint32_t currentProcessingFrame + ); +private: + typedef std::packaged_task< + std::shared_ptr() + > CommandTask; + typedef std::shared_ptr HCommandTask; + + struct CommandBuffRequest { + HCommandTask task; + uint32_t currentProcessingFrame; + }; + + std::thread m_thread; + HGDeviceVLK m_device; + + VkCommandPool m_commandPool; + + bool m_isTerminating = false; + ProdConsumerIOConnector poolInput = {m_isTerminating}; + + std::array, (IDevice::MAX_FRAMES_IN_FLIGHT + 1)> m_commandBuffers; +}; + + +#endif //AWEBWOWVIEWERCPP_COMMANDPOOLTHREAD_H diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 4c705216e..b0d57b76d 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -44,38 +44,76 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende bool renderWMO = m_config->renderWMO; for (auto &view : cullStage->viewsHolder.getInteriorViews()) { + ZoneScopedN("Collect interiors"); view->collectMeshes(renderADT, true, renderWMO, opaqueMeshCollector, transparentMeshes); } { auto exteriorView = cullStage->viewsHolder.getExterior(); if (exteriorView != nullptr) { + ZoneScopedN("Collect Exterior"); exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshCollector, transparentMeshes); } } if (m_config->renderM2) { - for (auto &m2Object : cullStage->m2Array.getDrawn()) { - if (m2Object == nullptr) continue; - m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); - m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); + ZoneScopedN("collect m2s"); + + auto threadsAvailable = m_config->hardwareThreadCount(); + auto &m2ToDraw = cullStage->m2Array.getDrawn(); + int granSize = m2ToDraw.size() / (2 * threadsAvailable); + + transp_vec transpVec; + + if (granSize > 0) { + oneapi::tbb::task_arena arena(std::min(threadsAvailable, 16), 1); + arena.execute([&] { + tbb::affinity_partitioner ap; + + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &m2Object = m2ToDraw[i]; + if (m2Object != nullptr) { + m2Object->collectMeshes(opaqueMeshCollector, transpVec, + m_viewRenderOrder); + m2Object->drawParticles(opaqueMeshCollector, transpVec, + m_viewRenderOrder); + } + } + }, ap); + }); + } else { + for (auto &m2Object : cullStage->m2Array.getDrawn()) { + if (m2Object == nullptr) continue; + m2Object->collectMeshes(opaqueMeshCollector, transpVec, m_viewRenderOrder); + m2Object->drawParticles(opaqueMeshCollector, transpVec, m_viewRenderOrder); + } } + transparentMeshes.insert(transparentMeshes.end(), transpVec.begin(), transpVec.end()); + auto skyBoxView = cullStage->viewsHolder.getSkybox(); if (skyBoxView) { + transp_vec skyTranspVec; + + ZoneScopedN("collect skyBox"); for (auto &m2Object : skyBoxView->m2List.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(skyOpaqueMeshCollector, skyTransparentMeshes, m_viewRenderOrder); - m2Object->drawParticles(skyOpaqueMeshCollector, skyTransparentMeshes, m_viewRenderOrder); + m2Object->collectMeshes(skyOpaqueMeshCollector, skyTranspVec, m_viewRenderOrder); + m2Object->drawParticles(skyOpaqueMeshCollector, skyTranspVec, m_viewRenderOrder); } + skyTransparentMeshes.insert(skyTransparentMeshes.end(), skyTranspVec.begin(), skyTranspVec.end()); } } //No need to sort array which has only one element if (transparentMeshes.size() > 1) { + ZoneScopedN("sort transparent"); std::sort(transparentMeshes.begin(), transparentMeshes.end(), SortMeshes); } if (skyTransparentMeshes.size() > 1) { + ZoneScopedN("sky transparent"); std::sort(skyTransparentMeshes.begin(), skyTransparentMeshes.end(), SortMeshes); } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index ea552b174..7f371a30d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -994,21 +994,16 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ typedef robin_hood::unordered_flat_map, std::vector> MeshMap; - framebased::vector m2DrawVec; + tbb::concurrent_vector m2DrawVec; framebased::vector wmoDrawVec; MeshMap waterMeshMap; framebased::vector adtDrawVec; framebased::vector commonMeshes; - inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { - const auto &meshVlk = (GMeshVLK*) mesh.get(); - auto const &pipeline = meshVlk->material()->getPipeline(); - - auto &vec = meshMap[pipeline]; - if (vec.empty()) - vec.reserve(3000); + inline static void fillDrawCommand(DrawCommand &drawCommand, GMeshVLK *meshVlk) { + auto const matId = meshVlk->material()->getMaterialId(); - auto &drawCommand = meshMap[pipeline].emplace_back(); + drawCommand.matId = matId; drawCommand.indexCount = meshVlk->end(); drawCommand.instanceCount = 1; drawCommand.firstIndex = meshVlk->start() / 2; @@ -1021,25 +1016,33 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ drawCommand.vertexOffset = 0; } } + + inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { + const auto &meshVlk = (GMeshVLK*) mesh.get(); + auto const &pipeline = meshVlk->material()->getPipeline(); + + auto &vec = meshMap[pipeline]; + if (vec.empty()) + vec.reserve(3000); + + auto &drawCommand = meshMap[pipeline].emplace_back(); + fillDrawCommand(drawCommand, meshVlk); + } + inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); - auto const matId = meshVlk->material()->getMaterialId(); - auto &drawCommand = drawVec.emplace_back(); - drawCommand.matId = matId; - drawCommand.indexCount = meshVlk->end(); - drawCommand.instanceCount = 1; - drawCommand.firstIndex = meshVlk->start() / 2; + fillDrawCommand(drawCommand, meshVlk); + } + inline void addDrawCommand(tbb::concurrent_vector &drawVec, const HGMesh &mesh) { + auto meshId = mesh->getObjectId(); + auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); - if (meshVlk->instanceIndex != -1) { - drawCommand.firstInstance = meshVlk->instanceIndex; - drawCommand.vertexOffset = meshVlk->vertexStart; - } else { - drawCommand.firstInstance = 0; - drawCommand.vertexOffset = 0; - } + DrawCommand drawCommand; + fillDrawCommand(drawCommand, meshVlk); + drawVec.push_back(drawCommand); } public: void addM2Mesh(const HGM2Mesh &mesh) override { From 80d79d899e0b348111db7176d1b4ff3e476f1791 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 28 Mar 2024 20:58:04 +0200 Subject: [PATCH 178/212] - changes to better cache situation - small changes to persistent system --- src/persistance/CascRequestProcessor.cpp | 3 +- src/persistance/HttpRequestProcessor.cpp | 4 +-- src/persistance/RequestProcessor.h | 6 ---- src/ui/FrontendUI.cpp | 2 -- .../childWindow/sceneWindow/SceneWindow.cpp | 1 + wowViewerLib/src/engine/cache/cache.h | 2 +- .../FrameBasedStackAllocator.h | 2 +- .../src/engine/objects/scenes/map.cpp | 26 +++++++++++---- .../src/engine/persistance/PersistentFile.h | 2 +- .../src/gapi/interface/meshes/IMesh.h | 4 +++ .../src/gapi/vulkan/GDeviceVulkan.cpp | 8 ++--- .../vulkan/buffers/GStagingRingBuffer.cpp | 33 ++++++++++--------- .../gapi/vulkan/buffers/GStagingRingBuffer.h | 6 ++-- .../renderer/mapScene/MapSceneRenderer.cpp | 25 ++++++++++---- .../vulkan/MapSceneRenderBindlessVLK.cpp | 16 ++++++++- .../vulkan/MapSceneRenderForwardVLK.cpp | 8 +++++ 16 files changed, 96 insertions(+), 52 deletions(-) diff --git a/src/persistance/CascRequestProcessor.cpp b/src/persistance/CascRequestProcessor.cpp index 8ac1f9f02..cb2d398e2 100644 --- a/src/persistance/CascRequestProcessor.cpp +++ b/src/persistance/CascRequestProcessor.cpp @@ -194,7 +194,8 @@ void CascRequestProcessor::processFileRequest(const std::string &fileName, Cache std::cout << "Could read file " << fileName << std::endl << std::flush; } toBeProcessed--; - this->m_fileRequester->rejectFile(holderType, fileName.c_str()); + perstFile->setRejected(); +// this->m_fileRequester->rejectFile(holderType, fileName.c_str()); } } diff --git a/src/persistance/HttpRequestProcessor.cpp b/src/persistance/HttpRequestProcessor.cpp index 1370aa2af..a7683b224 100644 --- a/src/persistance/HttpRequestProcessor.cpp +++ b/src/persistance/HttpRequestProcessor.cpp @@ -127,8 +127,8 @@ void HttpRequestProcessor::processFileRequest(const std::string &fileName, Cache toBeProcessed--; } ); - httpFile->setFailCallback([fileName, this, holderType, httpFile](HFileContent fileContent) -> void { - this->m_fileRequester->rejectFile(holderType, fileName.c_str()); + httpFile->setFailCallback([fileName, this, perstFile, httpFile](HFileContent fileContent) -> void { + perstFile->setRejected(); toBeProcessed--; }); httpFile->startDownloading(); diff --git a/src/persistance/RequestProcessor.h b/src/persistance/RequestProcessor.h index 4cdc205f0..9bd7c14b7 100644 --- a/src/persistance/RequestProcessor.h +++ b/src/persistance/RequestProcessor.h @@ -37,14 +37,8 @@ class RequestProcessor : public IFileRequest { }; protected: - IFileRequester *m_fileRequester = nullptr; - virtual void processFileRequest(const std::string &fileName, CacheHolderType holderType, const std::weak_ptr &s_file) = 0; public: - void setFileRequester(IFileRequester *fileRequester) { - m_fileRequester = fileRequester; - } - void initThreadQueue(bool &isTerminating) { m_threaded = true; m_requestQueue = std::make_unique(isTerminating); diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index c86724da3..4f93117f0 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1771,7 +1771,6 @@ bool FrontendUI::tryOpenCasc(std::string &cascPath, BuildDefinition &buildDef) { try { newProcessor = std::make_shared(cascPath, buildDef); newStorage = std::make_shared(newProcessor.get()); - newProcessor->setFileRequester(newStorage.get()); } catch (...){ return false; }; @@ -1860,7 +1859,6 @@ void FrontendUI::createDefaultprocessor() { //// processor->setThreaded(false); //// m_api->cacheStorage = std::make_shared(m_api->requestProcessor.get()); - m_api->requestProcessor->setFileRequester(m_api->cacheStorage.get()); overrideCascOpened(true); } diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index 2b9e2d0f8..ad99c7a30 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -122,6 +122,7 @@ inline HMapSceneParams createMapSceneParams(const HApiContainer &apiContainer, } SceneWindow::SceneWindow(const HApiContainer &api, bool renderToSwapChain) : m_api(api), m_renderToSwapChain(renderToSwapChain){ + } /* diff --git a/wowViewerLib/src/engine/cache/cache.h b/wowViewerLib/src/engine/cache/cache.h index b567ec41c..799aef82b 100644 --- a/wowViewerLib/src/engine/cache/cache.h +++ b/wowViewerLib/src/engine/cache/cache.h @@ -125,7 +125,7 @@ class Cache { if (!weakPtr.expired()) { if (std::shared_ptr sharedPtr = weakPtr.lock()) { - sharedPtr->rejected(); + sharedPtr->setRejected(); } } } diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index ca01d7b5b..ca1f47795 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -14,7 +14,7 @@ #include "tbb/scalable_allocator.h" template -using transp_vec = tbb::concurrent_vector; +using transp_vec = std::vector>; namespace framebased { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 3e36528c4..27a5f863b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -476,6 +476,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { + ZoneScopedN("Skybox"); auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); auto skyBoxView = mapRenderPlan->viewsHolder.getSkybox(); if (m_wdlObject != nullptr) { @@ -496,16 +497,27 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams } { + auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); if (exteriorView != nullptr) { - exteriorView->addM2FromGroups(frustumData, cameraPos); - for (auto &adtRes: exteriorView->drawnADTs) { - adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_adtOpaqueMeshes, - exteriorView->liquidMeshes, - exteriorView->renderOrder); + { + ZoneScopedN("collect m2 from groups"); + exteriorView->addM2FromGroups(frustumData, cameraPos); + } + + { + ZoneScopedN("adt mesh collect"); + for (auto &adtRes: exteriorView->drawnADTs) { + adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_adtOpaqueMeshes, + exteriorView->liquidMeshes, + exteriorView->renderOrder); + } + } + { + ZoneScopedN("m2AndWMOArr merge"); + mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); + mapRenderPlan->wmoGroupArray.addToLoadAndDraw(exteriorView->wmoGroupArray); } - mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); - mapRenderPlan->wmoGroupArray.addToLoadAndDraw(exteriorView->wmoGroupArray); } } diff --git a/wowViewerLib/src/engine/persistance/PersistentFile.h b/wowViewerLib/src/engine/persistance/PersistentFile.h index a8ffa8bd7..5e3c6c0aa 100644 --- a/wowViewerLib/src/engine/persistance/PersistentFile.h +++ b/wowViewerLib/src/engine/persistance/PersistentFile.h @@ -15,7 +15,7 @@ class PersistentFile { FileStatus getStatus() { return fsStatus; }; - void rejected() { + void setRejected() { fsStatus = FileStatus::FSRejected; }; protected: diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 98c2ad8e7..3ad3df8aa 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -102,11 +102,15 @@ class IMesh : public ObjectWithId { class COpaqueMeshCollector { public: + virtual ~COpaqueMeshCollector() {}; virtual void addM2Mesh(const HGM2Mesh &mesh) = 0; virtual void addWMOMesh(const HGMesh &mesh) = 0; virtual void addWaterMesh(const HGMesh &mesh) = 0; virtual void addADTMesh(const HGMesh &mesh) = 0; virtual void addMesh(const HGMesh &mesh) = 0; + + virtual void merge(COpaqueMeshCollector & collector) = 0; + virtual COpaqueMeshCollector * clone() = 0; }; #endif //AWEBWOWVIEWERCPP_IMESH_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index cfaec71e9..703a85efc 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; @@ -916,14 +916,14 @@ void GDeviceVLK::createCommandPoolForUpload(){ void GDeviceVLK::createCommandBuffers() { for (auto & commandBuffer : fbCommandBuffers) { - commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true, indices.graphicsFamily.value()); + commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true); } for (auto & commandBuffer : swapChainCommandBuffers) { - commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true, indices.graphicsFamily.value()); + commandBuffer = std::make_shared(*this, graphicsQueue, commandPool, true); } for (auto & commandBuffer : uploadCommandBuffers) { - commandBuffer = std::make_shared(*this, uploadQueue, uploadCommandPool, true, indices.transferFamily.value()); + commandBuffer = std::make_shared(*this, uploadQueue, uploadCommandPool, true); } } diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp index b408d991e..6864032a0 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.cpp @@ -12,8 +12,9 @@ void * GStagingRingBuffer::allocateNext(int o_size, VkBuffer &o_staging, int &o_ int bufferIndex = 0; auto ¤tOffset = offsets[frame]; - //Add alignment - auto size = o_size + 16; + //Add alignment to round up to cache line + auto size = o_size + + (std::hardware_destructive_interference_size); if (size > STAGE_BUFFER_SIZE) throw std::runtime_error(("size > STAGE_BUFFER_SIZE; size = " + std::to_string(size))); @@ -28,13 +29,12 @@ void * GStagingRingBuffer::allocateNext(int o_size, VkBuffer &o_staging, int &o_ currentIndex = ( offset ) / STAGE_BUFFER_SIZE; currentIndexAfter = (offset + size) / STAGE_BUFFER_SIZE; - if (currentIndexAfter >= vec.size() || vec[currentIndexAfter] == nullptr) { + if (currentIndexAfter >= vec.size()) { std::unique_lock l(m_mutex);// while (currentIndexAfter >= vec.size()) { auto &bufferAndCPU = vec.emplace_back(); - bufferAndCPU = std::make_shared(); - bufferAndCPU->staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); + bufferAndCPU.staging = std::make_shared(m_device, STAGE_BUFFER_SIZE); } } @@ -46,25 +46,26 @@ void * GStagingRingBuffer::allocateNext(int o_size, VkBuffer &o_staging, int &o_ throw "OOOOSP"; } auto &bufferAndCPU = vec[bufferIndex]; - auto buffPtr = reinterpret_cast(bufferAndCPU->cpuBuffer.data()); + auto buffPtr = reinterpret_cast(bufferAndCPU.cpuBuffer.data()); - uint32_t buffPtrAlign = buffPtr % 16; - uint32_t offsetAlign = startOffset % 16; + constexpr uint8_t cache_align = std::hardware_destructive_interference_size; + uint32_t buffPtrAlign = buffPtr % cache_align; + uint32_t offsetAlign = startOffset % cache_align; uint32_t alignAdd = 0; if (buffPtrAlign > offsetAlign) { - alignAdd = (16-buffPtrAlign) + (buffPtrAlign - offsetAlign); + alignAdd = (cache_align-buffPtrAlign) + (buffPtrAlign - offsetAlign); } else { - alignAdd = (16-buffPtrAlign) + ((16 - offsetAlign) + buffPtrAlign); + alignAdd = (cache_align-buffPtrAlign) + ((cache_align - offsetAlign) + buffPtrAlign); } - alignAdd %= 16; + alignAdd %= cache_align; startOffset += alignAdd; - auto allocatedPtr = ((uint8_t *)bufferAndCPU->cpuBuffer.data()) + startOffset; - if ((startOffset + o_size) > bufferAndCPU->cpuBuffer.size()) { + auto allocatedPtr = ((uint8_t *)bufferAndCPU.cpuBuffer.data()) + startOffset; + if ((startOffset + o_size) > bufferAndCPU.cpuBuffer.size()) { std::cerr << startOffset << " " << o_size << std::endl; throw "OOOOSP"; } - o_staging = bufferAndCPU->staging->getBuffer(); + o_staging = bufferAndCPU.staging->getBuffer(); o_offset = startOffset; return allocatedPtr; @@ -80,11 +81,11 @@ void GStagingRingBuffer::flushBuffers() { for (int i = 0; i < maxIndex; i++) { auto &stagingRec = vec[i]; - memcpy(stagingRec->staging->getPointer(), stagingRec->cpuBuffer.data(), STAGE_BUFFER_SIZE); + memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), STAGE_BUFFER_SIZE); } if (currentOffset > 0) { auto &stagingRec = vec[maxIndex]; - memcpy(stagingRec->staging->getPointer(), stagingRec->cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); + memcpy(stagingRec.staging->getPointer(), stagingRec.cpuBuffer.data(), currentOffset % STAGE_BUFFER_SIZE); } uint32_t prevMaxIndex = ( currentOffset ) / STAGE_BUFFER_SIZE; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h index b34c7d344..c7aac76fe 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GStagingRingBuffer.h @@ -12,7 +12,7 @@ class BufferStagingVLK; #include "gpu/BufferStagingVLK.h" class GStagingRingBuffer { - static constexpr uint32_t STAGE_BUFFER_SIZE = 20*1024*1024; + static constexpr uint32_t STAGE_BUFFER_SIZE = 60*1024*1024; public: GStagingRingBuffer(const HGDeviceVLK &device) : m_device(device) {}; @@ -26,11 +26,11 @@ class GStagingRingBuffer { std::array, IDevice::MAX_FRAMES_IN_FLIGHT> offsets = {0}; struct BufferAndCPU { - std::shared_ptr staging; std::array cpuBuffer; + std::shared_ptr staging; }; - std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> m_stagingBuffers; + std::array>, IDevice::MAX_FRAMES_IN_FLIGHT> m_stagingBuffers; }; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index b0d57b76d..cc9ac3850 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -63,35 +63,46 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende auto &m2ToDraw = cullStage->m2Array.getDrawn(); int granSize = m2ToDraw.size() / (2 * threadsAvailable); - transp_vec transpVec; + if (granSize > 0) { + std::mutex mergeMtx; oneapi::tbb::task_arena arena(std::min(threadsAvailable, 16), 1); arena.execute([&] { - tbb::affinity_partitioner ap; + tbb::static_partitioner ap; tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), [&](tbb::blocked_range r) { + transp_vec transpVec; + auto lCollector = opaqueMeshCollector.clone(); for (size_t i = r.begin(); i != r.end(); ++i) { auto &m2Object = m2ToDraw[i]; if (m2Object != nullptr) { - m2Object->collectMeshes(opaqueMeshCollector, transpVec, + m2Object->collectMeshes(*lCollector, transpVec, m_viewRenderOrder); - m2Object->drawParticles(opaqueMeshCollector, transpVec, + m2Object->drawParticles(*lCollector, transpVec, m_viewRenderOrder); } } + + { + std::lock_guard lock(mergeMtx); + opaqueMeshCollector.merge(*lCollector); + transparentMeshes.insert(transparentMeshes.end(), transpVec.begin(), transpVec.end()); + } + delete lCollector; + }, ap); }); } else { for (auto &m2Object : cullStage->m2Array.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(opaqueMeshCollector, transpVec, m_viewRenderOrder); - m2Object->drawParticles(opaqueMeshCollector, transpVec, m_viewRenderOrder); + m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); + m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); } } - transparentMeshes.insert(transparentMeshes.end(), transpVec.begin(), transpVec.end()); + auto skyBoxView = cullStage->viewsHolder.getSkybox(); if (skyBoxView) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 7f371a30d..5af8e4354 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -994,7 +994,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ typedef robin_hood::unordered_flat_map, std::vector> MeshMap; - tbb::concurrent_vector m2DrawVec; + framebased::vector m2DrawVec; framebased::vector wmoDrawVec; MeshMap waterMeshMap; framebased::vector adtDrawVec; @@ -1062,6 +1062,20 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ commonMeshes.push_back(mesh); }; + virtual COpaqueMeshCollector * clone() { + return new COpaqueMeshCollectorBindlessVLK(m_renderer); + } + + void merge(COpaqueMeshCollector & collector) override { + auto l_collector = (COpaqueMeshCollectorBindlessVLK &) collector; + + m2DrawVec.insert(m2DrawVec.end(), l_collector.m2DrawVec.begin(), l_collector.m2DrawVec.end()); + wmoDrawVec.insert(wmoDrawVec.end(), l_collector.wmoDrawVec.begin(), l_collector.wmoDrawVec.end()); + adtDrawVec.insert(adtDrawVec.end(), l_collector.adtDrawVec.begin(), l_collector.adtDrawVec.end()); + commonMeshes.insert(commonMeshes.end(), l_collector.commonMeshes.begin(), l_collector.commonMeshes.end()); + waterMeshMap.insert(l_collector.waterMeshMap.begin(), l_collector.waterMeshMap.end()); + } + void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { std::sort(m2DrawVec.begin(), m2DrawVec.end(), [](DrawCommand const &a, DrawCommand const &b) { return a.matId < b.matId; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 07689c50e..3cbdd12af 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -598,7 +598,15 @@ class COpaqueMeshCollectorForwardVLK : public COpaqueMeshCollector{ MapSceneRenderForwardVLK::drawMesh(cmdBuf, mesh, viewPortType); } } + COpaqueMeshCollector* clone() override { + return new COpaqueMeshCollectorForwardVLK(); + } + void merge(COpaqueMeshCollector& collector) override { + auto l_collector = (COpaqueMeshCollectorForwardVLK &) collector; + commonMeshes.insert(commonMeshes.end(), l_collector.commonMeshes.begin(), l_collector.commonMeshes.end()); + waterMeshes.insert(waterMeshes.end(), l_collector.waterMeshes.begin(), l_collector.waterMeshes.end()); + } }; std::unique_ptr MapSceneRenderForwardVLK::update(const std::shared_ptr> &frameInputParams, From 5de27fe75c12fd5a1244bff1d45dd369e575a001 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 31 Mar 2024 20:52:30 +0300 Subject: [PATCH 179/212] - deferred buffer that is not shit --- src/ui/FrontendUI.cpp | 6 +- .../fileListWindow/FileListWindow.cpp | 6 + .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- .../glsl/bindless/adt/adtShader_text.glsl | 8 +- .../glsl/bindless/deferred_excerpt.glsl | 14 + ...hader_opaq_deferred.frag => m2Shader.frag} | 0 .../bindless/m2/deferred/m2Shader_opaq.frag | 7 + ...2Shader_opaque.frag => m2Shader_opaq.frag} | 0 .../glsl/bindless/m2/m2shader_text.glsl | 8 +- .../m2Particle/m2ParticleShader_text.glsl | 8 +- ...fferred.frag => waterFallShader_opaq.frag} | 0 .../waterfall/waterFallShader_text.glsl | 8 +- ...ader_opaq_deferred.frag => wmoShader.frag} | 0 .../bindless/wmo/deferred/wmoShader_opaq.frag | 8 + ...Shader_opaque.frag => wmoShader_opaq.frag} | 0 .../glsl/bindless/wmo/wmoshader_text.glsl | 8 +- .../engine/algorithms/mathHelper_culling.h | 2 +- .../src/engine/managers/CRibbonEmitter.cpp | 2 +- .../managers/particles/particleEmitter.cpp | 16 +- .../managers/particles/particleEmitter.h | 2 +- .../src/engine/objects/ViewsObjects.cpp | 6 +- .../src/engine/objects/ViewsObjects.h | 4 +- .../src/engine/objects/adt/adtObject.cpp | 18 +- .../engine/objects/liquid/LiquidInstance.cpp | 2 +- .../src/engine/objects/m2/m2Object.cpp | 6 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 22 +- .../src/engine/objects/scenes/map.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 10 +- .../src/engine/objects/wmo/wmoObject.cpp | 30 +- .../src/engine/persistance/adtFile.cpp | 24 +- .../src/engine/shader/ShaderDefinitions.h | 1483 ++++++++--------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 7 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 9 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 10 +- .../src/gapi/vulkan/GFrameBufferVLK.h | 5 +- .../CommandBufferRecorder.cpp | 6 +- .../CommandBufferRecorder.h | 8 + .../vulkan/materials/ISimpleMaterialVLK.cpp | 3 +- .../vulkan/materials/ISimpleMaterialVLK.h | 5 + .../vulkan/materials/MaterialBuilderVLK.cpp | 38 +- .../vulkan/materials/MaterialBuilderVLK.h | 7 + .../src/gapi/vulkan/pipeline/GPipelineVLK.cpp | 15 +- .../src/gapi/vulkan/pipeline/GPipelineVLK.h | 4 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 4 +- .../src/gapi/vulkan/shaders/ShaderConfig.h | 3 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 2 +- .../mapScene/materials/IMaterialStructs.h | 5 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 169 +- .../vulkan/MapSceneRenderBindlessVLK.h | 14 +- .../vulkan/MapSceneRenderForwardVLK.cpp | 4 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../mapScene/vulkan/MapSceneRenderVisVLK.cpp | 2 +- .../vulkan/materials/IMaterialInstance.h | 3 +- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 6 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 79 +- .../vulkan/view/RenderViewDeferredVLK.h | 20 +- .../vulkan/view/RenderViewForwardVLK.cpp | 2 + 57 files changed, 1115 insertions(+), 1031 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl rename wowViewerLib/shaders/glsl/bindless/m2/deferred/{m2Shader_opaq_deferred.frag => m2Shader.frag} (100%) create mode 100644 wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag rename wowViewerLib/shaders/glsl/bindless/m2/forward/{m2Shader_opaque.frag => m2Shader_opaq.frag} (100%) rename wowViewerLib/shaders/glsl/bindless/waterfall/deferred/{waterFallShader_opaq_defferred.frag => waterFallShader_opaq.frag} (100%) rename wowViewerLib/shaders/glsl/bindless/wmo/deferred/{wmoShader_opaq_deferred.frag => wmoShader.frag} (100%) create mode 100644 wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq.frag rename wowViewerLib/shaders/glsl/bindless/wmo/forward/{wmoShader_opaque.frag => wmoShader_opaq.frag} (100%) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 4f93117f0..5f3db8fee 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -53,7 +53,7 @@ void FrontendUI::composeUI() { ZoneScoped; { - auto processingFrame = m_api->hDevice->getFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto processingFrame = m_api->hDevice->getFrameNumber(); m_api->hDevice->setCurrentProcessingFrameNumber(processingFrame); } @@ -845,7 +845,7 @@ void FrontendUI::showMainMenu() { } ImGui::Separator(); if (ImGui::MenuItem("Open settings")) {showSettings = true;} - if (ImGui::MenuItem("Open QuickLinks")) {showQuickLinks = true;} + if (ImGui::MenuItem("Open QuickLinks", "", nullptr,cascOpened)) {showQuickLinks = true;} if (ImGui::MenuItem("Open MapConstruction")) {showMapConstruction = true;} if (ImGui::MenuItem("Open minimap generator", "", false, cascOpened)) { showMinimapGeneratorSettings = true; @@ -1702,7 +1702,7 @@ HFrameScenario FrontendUI::createFrameScenario(int canvWidth, int canvHeight, do m_minimapGenerationWindow->process(); } auto l_device = m_api->hDevice; - auto processingFrame = l_device->getFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto processingFrame = l_device->getFrameNumber(); std::function updateFrameNumberLambda = [l_device, frame = processingFrame]() -> uint32_t { l_device->setCurrentProcessingFrameNumber(frame); return frame; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 36dd01064..01e2a660e 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -6,6 +6,12 @@ #include "../../../database/csvtest/csv.h" #include "../../../../wowViewerLib/src/include/string_utils.h" +#ifndef _WIN32 +#include +#else +#include +#endif + namespace FileListDB { inline static auto makeStorage(const std::string &dataBaseFile) { using namespace sqlite_orm; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index c7e336cad..6fdc5563c 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -59,7 +59,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering","forwardRendering"}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() @@ -93,7 +93,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterialDepth(c } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering", "forwardRendering"}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl index c669e8f87..433d7e289 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -27,9 +27,7 @@ layout (set = 4, binding = 0) uniform sampler2D s_LayerHeightTextures[]; #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +#include "../deferred_excerpt.glsl" #endif const InteriorLightParam intLight = { @@ -133,8 +131,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - outAlbedo = vec4(matDiffuse.xyz, 0); - outNormal = vec4(normalize(vNormal), 0); - outSpecular = vec4(specTerm.rgb, 0); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), specTerm.rgb); #endif } diff --git a/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl new file mode 100644 index 000000000..f056328e6 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl @@ -0,0 +1,14 @@ +#ifndef DEFERRED_EXCERPT +#define DEFERRED_EXCERPT + +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outSpecular; +layout(location = 2) out vec4 outNormal; + +void writeGBuffer(vec3 albedo, vec3 normal, vec3 specular) { + outAlbedo = vec4(albedo, 0.0); + outNormal = vec4(normal, 0.0); + outSpecular = vec4(specular, 0.0); +} + +#endif //DEFERRED_EXCERPT \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq_deferred.frag b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq_deferred.frag rename to wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader.frag diff --git a/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag new file mode 100644 index 000000000..bd6cb5313 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED + +#include "../m2shader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag b/wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaque.frag rename to wowViewerLib/shaders/glsl/bindless/m2/forward/m2Shader_opaq.frag diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl index d7cfb8f2c..37938bd84 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -17,9 +17,7 @@ layout(location=4) in flat int vMeshIndex; #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +#include "../deferred_excerpt.glsl" #endif @@ -186,8 +184,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - outAlbedo = vec4(matDiffuse.xyz, 0.0); - outNormal = vec4(normalize(vNormal), 0.0); - outSpecular = vec4(specular.rgb, 0.0); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), specular.rgb); #endif } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl index eac148306..9b08d9062 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl @@ -29,9 +29,7 @@ layout (set = 2, binding = 2) uniform sampler2D uTexture3; #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +#include "../deferred_excerpt.glsl" #endif @@ -115,8 +113,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - outAlbedo = vec4(matDiffuse.xyz, 0.0); - outNormal = vec4(0,0,1.0, 0.0); - outSpecular = vec4(0.0); + writeGBuffer(matDiffuse.xyz, vec3(0.0, 0.0, 1.0), vec3(0.0)); #endif } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag b/wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag rename to wowViewerLib/shaders/glsl/bindless/waterfall/deferred/waterFallShader_opaq.frag diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl index dd4bc2653..980b6b303 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl @@ -16,9 +16,7 @@ layout(location=5) flat in int meshInd; #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +#include "../deferred_excerpt.glsl" #endif //Whole model @@ -117,8 +115,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - outAlbedo = vec4(whiteWater_val_baseColor_mix.rgb, 0.0); - outNormal = vec4(perturbedNormal.rgb, 0.0); - outSpecular = vec4(0.0); + writeGBuffer(whiteWater_val_baseColor_mix.rgb, perturbedNormal.rgb, vec3(0.0)); #endif } diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag b/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq_deferred.frag rename to wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader.frag diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq.frag b/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq.frag new file mode 100644 index 000000000..b858478bf --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/wmo/deferred/wmoShader_opaq.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_GOOGLE_include_directive: require +#extension GL_EXT_nonuniform_qualifier : require + +#define DEFERRED +#define TRUE_OPAQUE + +#include "../wmoshader_text.glsl" diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag b/wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaq.frag similarity index 100% rename from wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaque.frag rename to wowViewerLib/shaders/glsl/bindless/wmo/forward/wmoShader_opaq.frag diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index ceb76cfde..59e2cf4e1 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -31,9 +31,7 @@ layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +#include "../deferred_excerpt.glsl" #endif void main() { @@ -107,8 +105,6 @@ finalColor.a = 1.0; #ifndef DEFERRED outColor = finalColor; #else - outAlbedo = vec4(matDiffuse.xyz, 0.0); - outNormal = vec4(normalize(vNormal), 0.0); - outSpecular = vec4(spec.rgb, 0.0); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), spec.rgb); #endif } \ No newline at end of file diff --git a/wowViewerLib/src/engine/algorithms/mathHelper_culling.h b/wowViewerLib/src/engine/algorithms/mathHelper_culling.h index f975d938e..0ef6f54b4 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper_culling.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper_culling.h @@ -13,7 +13,7 @@ class ObjectCulling { static void cull(const MathHelper::FrustumCullingData &cullingData, const int start, const int end, - const std::vector &objects, + const framebased::vector &objects, std::vector &culling_res) { for (int i = start; i < end; i++) { culling_res[i] &= MathHelper::checkFrustum(cullingData.frustums, retrieveAABB(objects[i])) ? 0 : 0xFFFFFFFF; diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 54ae79d39..828419e9d 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -846,7 +846,7 @@ void CRibbonEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, tr for (int i = 0; i < currFrame.m_meshes.size(); i++) { auto mesh = currFrame.m_meshes[i]; if (mesh->getIsTransparent()) { - transparentMeshes.push_back(mesh); + transparentMeshes.emplace_back() = mesh; } else { opaqueMeshCollector.addMesh(mesh); } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index f0a4cef6e..3a7b6853c 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -339,7 +339,7 @@ void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { //Create Buffers - for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT + 1; i++) { //Create mesh createMesh(sceneRenderer, frame[i], 10 * sizeof(ParticleBuffStructQuad)); } @@ -470,7 +470,7 @@ void ParticleEmitter::Update(animTime_t delta, mathfu::mat4 &transformMat, mathf this->InternalUpdate(delta); } - const HGParticleMesh &mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT].m_mesh; + const HGParticleMesh &mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % (IDevice::MAX_FRAMES_IN_FLIGHT + 1)].m_mesh; mesh->setSortDistance(m_currentBonePos); } @@ -652,7 +652,7 @@ void ParticleEmitter::prepearBuffers(mathfu::mat4 &viewMatrix) { this->calculateQuadToViewEtc(nullptr, viewMatrix); // FrameOfRerefence mat is null since it's not used - int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % (IDevice::MAX_FRAMES_IN_FLIGHT + 1); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; szVertexBuf = (ParticleBuffStructQuad *) vboBufferDynamic->getPointer(); @@ -680,7 +680,7 @@ void ParticleEmitter::fitBuffersToSize(const HMapSceneBufferCreate &sceneRendere if ((m_data->old.flags & 0x60000) == 0x60000) { maxFutureSize *= 2; } - int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + int frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % (IDevice::MAX_FRAMES_IN_FLIGHT + 1); auto vboBufferDynamic = frame[frameNum].m_bufferVBO; if (maxFutureSize > vboBufferDynamic->getSize()) { @@ -1117,13 +1117,13 @@ ParticleEmitter::BuildQuadT3( void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % (IDevice::MAX_FRAMES_IN_FLIGHT + 1)]; if (!currentFrame.active) return; - HGParticleMesh mesh = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT].m_mesh; + HGParticleMesh mesh = currentFrame.m_mesh; if (mesh->getIsTransparent()) { - transparentMeshes.push_back(mesh); + transparentMeshes.emplace_back() = mesh; } else { opaqueMeshCollector.addMesh(mesh); } @@ -1132,7 +1132,7 @@ void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, t void ParticleEmitter::updateBuffers() { if (getGenerator() == nullptr) return; - auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; + auto ¤tFrame = frame[m_api->hDevice->getCurrentProcessingFrameNumber() % (IDevice::MAX_FRAMES_IN_FLIGHT + 1)]; currentFrame.active = szVertexCnt > 0; if (!currentFrame.active) diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 326612b4d..7cd079c2a 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -200,7 +200,7 @@ class ParticleEmitter { bool active = false; } ; std::shared_ptr m_material = nullptr; - std::array frame; + std::array frame; void createMeshes(const HMapSceneBufferCreate &sceneRenderer); diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 9bcd9763e..65c28b2bc 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -45,7 +45,7 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD } } - auto candidatesArr = this->m2List.getCandidates(); + auto &candidatesArr = this->m2List.getCandidates(); auto candCullRes = std::vector(candidatesArr.size(), 0xFFFFFFFF); oneapi::tbb::task_arena arena(oneapi::tbb::task_arena::automatic, 3); @@ -75,7 +75,7 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD } } -void GeneralView::setM2Lights(std::shared_ptr &m2Object) { +void GeneralView::setM2Lights(const std::shared_ptr &m2Object) { m2Object->setUseLocalLighting(false); } @@ -168,7 +168,7 @@ void GeneralView::collectPortalMeshes(framebased::vector &transp } } -void InteriorView::setM2Lights(std::shared_ptr &m2Object) { +void InteriorView::setM2Lights(const std::shared_ptr &m2Object) { if (ownerGroupWMO == nullptr || !ownerGroupWMO->getIsLoaded()) return; if (ownerGroupWMO->getDontUseLocalLightingForM2()) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index b4f17da10..ba473998b 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -58,7 +58,7 @@ class GeneralView { virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); void collectPortalMeshes(framebased::vector &transparentMeshes); - virtual void setM2Lights(std::shared_ptr &m2Object); + virtual void setM2Lights(const std::shared_ptr &m2Object); void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, const std::vector> &portalsVerts, bool isAntiportal = false); @@ -69,7 +69,7 @@ class InteriorView : public GeneralView { public: std::vector portalIndexes; std::shared_ptr ownerGroupWMO = {}; //Wmos which portals belong to - void setM2Lights(std::shared_ptr &m2Object) override; + void setM2Lights(const std::shared_ptr &m2Object) override; }; class ExteriorView : public GeneralView { diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 8f9456fcb..1782ac340 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -500,7 +500,7 @@ constexpr int alphaTexSize = 64; constexpr int texWidth = alphaTexSize * 16; constexpr int texHeight = alphaTexSize * 16; -std::vector bigTexture = std::vector(texWidth * texHeight * 4, 0); +auto bigTexture = std::vector>(texWidth * texHeight * 4, 0); void AdtObject::loadAlphaTextures() { ZoneScoped; @@ -509,7 +509,7 @@ void AdtObject::loadAlphaTextures() { int createdThisRun = 0; alphaTexture = m_api->hDevice->createTexture(false, false); - memset(bigTexture.data(), 0, bigTexture.size()); + memset(bigTexture.data(), 0, bigTexture.size()); if (chunkCount > 0) { // for (int i = 0; i < chunkCount; i++){ @@ -589,7 +589,7 @@ void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaq transparentMeshes.reserve(transparentMeshes.size() + m_liquidInstancesPerChunk.size()); for (int i = 0; i < meshCount; i++) { if (adtRes.drawChunk[i] && (adtMeshes[i] != nullptr)) { - opaqueMeshes.push_back(adtMeshes[i]); + opaqueMeshes.emplace_back() = adtMeshes[i]; } if (adtRes.drawWaterChunk[i]) { for (auto const &liquidInstance : m_liquidInstancesPerChunk[i]) { @@ -760,14 +760,10 @@ void AdtObject::update(animTime_t deltaTime ) { void AdtObject::uploadGeneratorBuffers(const HFrameDependantData &frameDependantData) { if (!m_loaded) return; - if (m_waterPlacementChunk != nullptr) { - m_waterPlacementChunk->getObject().uPlacementMat = mathfu::mat4::Identity(); - m_waterPlacementChunk->save(); - } - - for(auto &liquidInstance : m_liquidInstances) { - liquidInstance->updateLiquidMaterials(frameDependantData, m_mapApi->getCurrentSceneTime()); - } +//Not used in current code +// for(auto &liquidInstance : m_liquidInstances) { +// liquidInstance->updateLiquidMaterials(frameDependantData, m_mapApi->getCurrentSceneTime()); +// } } HGSamplableTexture AdtObject::getAdtTexture(int textureId) { diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index 3d677c3e6..bfb02cc7f 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -297,7 +297,7 @@ void LiquidInstance::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector) { void LiquidInstance::collectMeshes(framebased::vector &transparentMeshes) { //TODO: Get time and right mesh instance for animation if (m_api->getConfig()->renderLiquid) { - transparentMeshes.push_back(m_liquidMeshes[0]); + transparentMeshes.emplace_back() = m_liquidMeshes[0]; } } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index cd3394036..3878a89dd 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1144,7 +1144,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa } } -bool M2Object::isMainDataLoaded() { +bool M2Object::isMainDataLoaded() const { if (m_m2Geom == nullptr) return false; if (m_m2Geom->getStatus() != FileStatus::FSLoaded) return false; @@ -1677,7 +1677,7 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_v } if (mesh->getIsTransparent()) { - transparentMeshes.push_back(mesh); + transparentMeshes.emplace_back() = mesh; } else { if (!isWaterFallMesh) { opaqueMeshCollector.addM2Mesh(mesh); @@ -1713,7 +1713,7 @@ void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_v } if (m_api->getConfig()->drawM2BB) { - transparentMeshes.push_back(boundingBoxMesh); + transparentMeshes.emplace_back(boundingBoxMesh); } // std::cout << "Collected meshes at update frame =" << m_api->hDevice->getUpdateFrameNumber() << std::endl; } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 76699adfb..75ea59c7f 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -261,8 +261,8 @@ class M2Object : public ObjectWithId { const bool checkFrustumCulling(const mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData); - bool isMainDataLoaded(); - bool getHasBoundingBox() {return m_hasAABB;} + bool isMainDataLoaded() const; + bool getHasBoundingBox() const {return m_hasAABB;} void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); @@ -354,17 +354,17 @@ using m2Container = framebased::vector>; toLoadGeom.reserve(10000); drawn.reserve(10000); } - void addCandidate(const std::shared_ptr &cand) { - if (m_locked) { - throw "oops"; - } + inline void addCandidate(const std::shared_ptr &cand) { +// if (m_locked) { +// throw "oops"; +// } if (cand == nullptr) return; if (cand->getHasBoundingBox()) { - candidates.push_back(cand); + candidates.emplace_back() = cand; candCanHaveDuplicates = true; } else { - toLoadMain.push_back(cand); + toLoadMain.emplace_back() = cand; toLoadMainCanHaveDuplicates = true; } } @@ -375,13 +375,13 @@ using m2Container = framebased::vector>; } if (toDraw->getGetIsLoaded()) { - drawn.push_back(toDraw); + drawn.emplace_back() = toDraw; drawnCanHaveDuplicates = true; } else if (!toDraw->isMainDataLoaded()) { - toLoadMain.push_back(toDraw); + toLoadMain.emplace_back() = toDraw; toLoadMainCanHaveDuplicates = true; } else { - toLoadGeom.push_back(toDraw); + toLoadGeom.emplace_back() = toDraw; toLoadGeomCanHaveDuplicates = true; } } diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 27a5f863b..9c1447e74 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1589,7 +1589,7 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe if (granSize > 0) { auto l_device = m_api->hDevice; auto oldProcessingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); - auto processingFrame = oldProcessingFrame % IDevice::MAX_FRAMES_IN_FLIGHT; + auto processingFrame = oldProcessingFrame; oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); arena.execute([&] { tbb::affinity_partitioner ap; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index e607aa272..3841f7f27 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -166,8 +166,12 @@ void WmoGroupObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { meshTemplate.end = renderBatch.num_indices; //Make mesh - HGMesh hmesh = sceneRenderer->createWMOMesh(meshTemplate, materialInstance, m_ambientChunk); - this->m_meshArray.push_back(hmesh); + auto hmesh = sceneRenderer->createWMOMesh(meshTemplate, materialInstance, m_ambientChunk); + if (!hmesh->getIsTransparent()) { + this->m_meshArray.push_back(hmesh); + } else { + this->m_sortableMeshArray.push_back(hmesh); + } } } @@ -752,7 +756,7 @@ void WmoGroupObject::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, fr opaqueMeshCollector.addWMOMesh(i); } for (auto &i : this->m_sortableMeshArray) { - if (i->getIsTransparent()) { + if (!i->getIsTransparent()) { opaqueMeshCollector.addWMOMesh(i); } else { transparentMeshes.push_back(i); diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index ba2f22642..479fdbeda 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -20,9 +20,9 @@ std::vector createAntiPortal(const HWmoGroupGeom& groupGeom, const ; ++mopy_index, ++movi_index ) { - points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+0]]), 1.0f)).xyz()); - points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+1]]), 1.0f)).xyz()); - points.push_back((placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+2]]), 1.0f)).xyz()); + points.emplace_back() = (placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+0]]), 1.0f)).xyz(); + points.emplace_back() = (placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+1]]), 1.0f)).xyz(); + points.emplace_back() = (placementMat * mathfu::vec4(mathfu::vec3(groupGeom->verticles[groupGeom->indicies[3*movi_index+2]]), 1.0f)).xyz(); } return points; } @@ -245,7 +245,7 @@ void WmoObject::createWorldPortals() { portalVerticles[base_index + k].y, portalVerticles[base_index + k].z); - portalVecs.push_back(verticle); + portalVecs.emplace_back() = verticle; } //Calculate center of the portal @@ -276,7 +276,7 @@ void WmoObject::createWorldPortals() { portalVecs.clear(); for (int k = 0; k < hulled.size(); k++) { - portalVecs.push_back((viewMatInv * mathfu::vec4(hulled[k], 1.0)).xyz()); + portalVecs.emplace_back() = (viewMatInv * mathfu::vec4(hulled[k], 1.0)).xyz(); } geometryPerPortal[j].sortedVericles = portalVecs; @@ -709,8 +709,8 @@ bool WmoObject::startTraversingWMOGroup( } else { if ((mainGeom->groups[i].flags.ANTIPORTAL) > 0) { //ANTIPORTAL if (this->groupObjects[i]->getIsLoaded()) { - exteriorView->worldAntiPortalVertices.push_back( - createAntiPortal(this->groupObjects[i]->getWmoGroupGeom(), m_placementMatrix)); + exteriorView->worldAntiPortalVertices.emplace_back() = + createAntiPortal(this->groupObjects[i]->getWmoGroupGeom(), m_placementMatrix); } } } @@ -930,7 +930,7 @@ void WmoObject::traverseGroupWmo( n *= -1.0f; } - thisPortalPlanes.push_back(n); + thisPortalPlanes.emplace_back() = n; } //The portalPlanes do not have far and near plane. So we need to add them //Near plane is this portal's plane, far plane is a global one @@ -939,8 +939,8 @@ void WmoObject::traverseGroupWmo( nearPlane *= -1.0f; auto &farPlane = traverseTempData.farPlane; - thisPortalPlanes.push_back(nearPlane); - thisPortalPlanes.push_back(farPlane); + thisPortalPlanes.emplace_back() = nearPlane; + thisPortalPlanes.emplace_back() = farPlane; } else { // If camera is too close - just use usual frustums thisPortalPlanes = localFrustumPlanes; @@ -982,11 +982,11 @@ void WmoObject::traverseGroupWmo( interiorView->ownerGroupWMO = nextGroupObject; interiorView->wmoGroupArray.addToDraw(nextGroupObject); interiorView->wmoGroupArray.addToCheckM2(nextGroupObject); - interiorView->portalIndexes.push_back(relation->portal_index); + interiorView->portalIndexes.emplace_back() = relation->portal_index; } - interiorView->worldPortalVertices.push_back(worldSpacePortalVertices); - interiorView->frustumData.frustums.push_back(worldSpaceFrustum); + interiorView->worldPortalVertices.emplace_back() = worldSpacePortalVertices; + interiorView->frustumData.frustums.emplace_back() = worldSpaceFrustum; if (globalLevel+1 >= interiorView->level) { interiorView->level = globalLevel + 1; } else { @@ -1012,8 +1012,8 @@ void WmoObject::traverseGroupWmo( if (!traverseTempData.exteriorWasCreatedBeforeTraversing) { auto exteriorView = traverseTempData.viewsHolder.getOrCreateExterior({}); exteriorView->level = globalLevel + 1; - exteriorView->worldPortalVertices.push_back(worldSpacePortalVertices); - exteriorView->frustumData.frustums.push_back(worldSpaceFrustum); + exteriorView->worldPortalVertices.emplace_back() = worldSpacePortalVertices; + exteriorView->frustumData.frustums.emplace_back() = worldSpaceFrustum; } } } diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index 48485462b..eb5fcaa60 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -582,18 +582,18 @@ void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MP // } } - if (mcalRuntime.uncompressedIndex) { - auto pCurrentLayer = currentLayer; - auto pCurrentLayerInt = (uint32_t *)currentLayer; - for ( int i = 0; i < 64; i++ ) { - uint8_t layer0 = *pCurrentLayer++; - uint8_t layer1 = *pCurrentLayer++; - uint8_t layer2 = *pCurrentLayer++; - uint8_t layer3 = *pCurrentLayer++; - - *pCurrentLayerInt++ = 255 - layer0 - layer1 - layer2 - layer3; - } - } +// if (mcalRuntime.uncompressedIndex) { +// auto pCurrentLayer = currentLayer; +// auto pCurrentLayerInt = (uint32_t *)currentLayer; +// for ( int i = 0; i < 64; i++ ) { +// uint8_t layer0 = *pCurrentLayer++; +// uint8_t layer1 = *pCurrentLayer++; +// uint8_t layer2 = *pCurrentLayer++; +// uint8_t layer3 = *pCurrentLayer++; +// +// *pCurrentLayerInt++ = 255 - layer0 - layer1 - layer2 - layer3; +// } +// } } static bool isHoleLowRes(int hole, int i, int j) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index f200f3773..e42d4496b 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -392,9 +392,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,544}, {1,0,64}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, }, { { @@ -427,17 +424,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/skyConus.vert.spv", +{ "./forwardRendering/adtShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { {0,0,544}, - {1,0,96}, + {1,1,48}, + {1,0,64}, }, { { {0,0,1}, - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -449,12 +447,21 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -464,24 +471,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/m2Shader.frag.spv", +{ "./bindless/m2/deferred/m2Shader.frag.spv", { ShaderStage::Fragment, { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,256}, - {0,0,544}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -490,19 +489,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, }, { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, - {0,3,4}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -511,11 +513,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/renderFrameBufferShader.frag.spv", +{ "./forwardRendering/drawDepthShader.frag.spv", { ShaderStage::Fragment, { - {0,2,168}, + {0,2,12}, }, { { @@ -532,12 +534,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, + {0,3, "diffuse"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -549,15 +550,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader.vert.spv", +{ "./forwardRendering/ffxgauss4.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,80}, + {0,1,32}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -570,11 +571,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "texture0"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -585,14 +587,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/skyConus.frag.spv", +{ "./forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,144}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -620,15 +623,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader.frag.spv", +{ "./forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,2,16384}, + {1,0,64}, + {0,0,544}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -640,12 +646,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -656,11 +661,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawQuad.vert.spv", +{ "./bindless/wmo/forward/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,16}, + {0,0,544}, }, { { @@ -675,14 +680,19 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -692,7 +702,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPortalShader.vert.spv", +{ "./forwardRendering/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -728,15 +738,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawLinesShader.vert.spv", +{ "./bindless/wmo/deferred/wmoShader_opaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -747,14 +756,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -764,17 +777,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterShader.vert.spv", +{ "./bindless/adt/forward/adtShader.vert.spv", { ShaderStage::Vertex, { {0,0,544}, - {1,0,64}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -784,6 +796,8 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, }, { }, @@ -801,7 +815,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader_opaque.frag.spv", +{ "./bindless/wmo/deferred/wmoShader.frag.spv", { ShaderStage::Fragment, { @@ -819,15 +833,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, }, { - {1,0, "Texture"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -837,15 +854,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawLinesShader.frag.spv", +{ "./forwardRendering/drawQuad.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,0,16}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -873,11 +890,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.vert.spv", +{ "./bindless/wmo/forward/wmoShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, + {0,0,544}, }, { { @@ -892,6 +909,10 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, }, { }, @@ -909,17 +930,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", +{ "./bindless/waterfall/forward/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, {0,0,544}, }, { { {0,0,1}, - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,17 +949,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,4096}, + {2,1,0}, + {2,0,0}, }, { - {2,0, "uTexture"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -948,17 +969,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/forward/m2ParticleShader.frag.spv", +{ "./bindless/waterfall/deferred/waterFallShader_opaq.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, - {0,0,544}, }, { { - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -968,18 +987,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -988,15 +1007,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ffxglow.frag.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,16}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1009,13 +1028,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, }, { { {0,0,0}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1026,17 +1043,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, + {1,1,16}, {0,0,544}, }, { { {0,0,1}, - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1046,17 +1063,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,4096}, }, { {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1066,7 +1082,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/deferred/m2Shader_opaq_deferred.frag.spv", +{ "./bindless/adt/deferred/adtShader.frag.spv", { ShaderStage::Fragment, { @@ -1085,26 +1101,22 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {2,0, "s_Textures"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, {0,0,1}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1112,16 +1124,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPoints.vert.spv", +{ "./forwardRendering/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,128}, - {0,1,64}, + {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1149,16 +1160,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.vert.spv", +{ "./bindless/wmo/forward/wmoShader_opaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, {0,0,544}, }, { { - {0,1,2}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1169,14 +1179,19 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1186,7 +1201,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", +{ "./bindless/m2/forward/m2Shader.vert.spv", { ShaderStage::Vertex, { @@ -1205,6 +1220,10 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,7,0}, + {1,3,0}, + {1,1,0}, }, { }, @@ -1222,14 +1241,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPoints.frag.spv", +{ "./forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {1,1,48}, + {0,0,544}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1237,18 +1258,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { }, { + {2,0, "uTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1258,7 +1279,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", +{ "./bindless/waterfall/forward/waterfallShader.vert.spv", { ShaderStage::Vertex, { @@ -1277,15 +1298,22 @@ const std::unordered_map shaderMetaInfo = { } }, { - }, + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, + {1,3,0}, + {1,1,0}, + }, { + {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1294,14 +1322,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShaderDepth.frag.spv", +{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", { ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1312,15 +1341,22 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, }, { - {1,0, "Texture"}, + {2,0, "s_Textures"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1330,26 +1366,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPortalShader.frag.spv", +{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", { ShaderStage::Fragment, - { - {1,0,16}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, { }, { @@ -1363,37 +1382,23 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, } - } - } -}, -{ "./forwardRendering/adtShader.vert.spv", - { - ShaderStage::Vertex, - { - {1,0,64}, - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1409,17 +1414,11 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,544}, - {1,0,64}, - {1,1,256}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { {0,0,1}, - {0,5,6}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1450,45 +1449,6 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/visbuffer/adtShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,544}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, { "./bindless/adt/visbuffer/adtShader.frag.spv", { ShaderStage::Fragment, @@ -1531,9 +1491,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/forward/adtShader.frag.spv", +{ "./bindless/adt/visbuffer/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -1552,20 +1512,16 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1573,16 +1529,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/wmo/deferred/wmoShader_opaq_deferred.frag.spv", +{ "./forwardRendering/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {1,0,64}, {0,0,544}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1592,21 +1549,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1616,16 +1566,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/forward/waterfallShader.vert.spv", +{ "./forwardRendering/drawPortalShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {1,0,16}, }, { { - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1635,27 +1585,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1664,17 +1602,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterShader.frag.spv", +{ "./forwardRendering/imguiShaderDepth.frag.spv", { ShaderStage::Fragment, { - {1,1,48}, - {0,0,544}, }, { { - {0,0,1}, - {1,1,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1686,11 +1622,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, + {1,0, "Texture"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1698,6 +1633,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } @@ -1723,12 +1659,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, }, { { - {4,5,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1740,7 +1674,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader.vert.spv", +{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", { ShaderStage::Vertex, { @@ -1759,15 +1693,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { }, @@ -1785,16 +1710,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ribbonShader.vert.spv", +{ "./forwardRendering/skyConus.vert.spv", { ShaderStage::Vertex, { {0,0,544}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1821,15 +1747,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/deferred/adtShader.frag.spv", +{ "./forwardRendering/drawPoints.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,12}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1840,22 +1766,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1863,14 +1783,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/renderFrameBufferShader.vert.spv", +{ "./bindless/water/waterShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {0,0,544}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1881,14 +1802,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,2,0}, + {1,0,0}, }, { + {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1898,9 +1822,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.frag.spv", +{ "./bindless/water/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,544}, }, @@ -1918,17 +1842,15 @@ const std::unordered_map shaderMetaInfo = { }, { {1,2,0}, - {1,0,0}, {1,1,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1977,15 +1899,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.vert.spv", +{ "./forwardRendering/renderFrameBufferShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1996,18 +1917,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2017,7 +1934,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/deferred/waterFallShader_opaq_defferred.frag.spv", +{ "./bindless/adt/forward/adtShader.frag.spv", { ShaderStage::Fragment, { @@ -2036,28 +1953,22 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, + {1,3,0}, {1,1,0}, {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2065,7 +1976,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/forward/waterfallShader.frag.spv", +{ "./bindless/m2/forward/m2Shader.frag.spv", { ShaderStage::Fragment, { @@ -2084,24 +1995,19 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, + {1,9,0}, + {1,8,0}, + {1,7,0}, {1,2,0}, - {1,3,0}, - {1,4,0}, {1,5,0}, + {1,4,0}, {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, }, { { - {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -2109,20 +2015,21 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "./bindless/wmo/forward/wmoShader.vert.spv", +{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {1,0,32}, }, { { - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2132,20 +2039,17 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2155,15 +2059,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/m2ParticleShader.vert.spv", +{ "./forwardRendering/ffxglow.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,1,16}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2176,11 +2080,13 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { {0,0,0}, - {0,0,0}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2191,15 +2097,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader.frag.spv", +{ "./forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2210,24 +2116,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2237,15 +2133,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/wmo/forward/wmoShader.frag.spv", +{ "./forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,1,112}, {0,0,544}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2256,21 +2153,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2280,24 +2170,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/m2Shader.vert.spv", +{ "./forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { - {1,2,16384}, - {1,0,64}, - {0,0,544}, - {1,1,256}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, + {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, - {0,5,6}, - {0,0,1}, + {0,1,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2323,17 +2207,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/m2ParticleShader.frag.spv", +{ "./forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, - {0,0,544}, }, { { - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2345,15 +2227,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2363,11 +2242,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/forward/adtShader.vert.spv", +{ "./forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,128}, }, { { @@ -2382,9 +2261,6 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { }, @@ -2402,15 +2278,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtLodShader.vert.spv", +{ "./forwardRendering/drawLinesShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,144}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2438,15 +2313,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ffxgauss4.frag.spv", +{ "./forwardRendering/imguiShader_opaque.frag.spv", { ShaderStage::Fragment, { - {0,1,32}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2459,7 +2333,7 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "texture0"}, + {1,0, "Texture"}, }, { { @@ -2475,16 +2349,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawDepthShader.frag.spv", +{ "./forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,2,12}, + {0,0,544}, + {1,0,64}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2496,11 +2371,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,3, "diffuse"}, }, { { - {3,3,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2512,18 +2386,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtShader.frag.spv", +{ "./forwardRendering/drawLinesShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, - {1,1,48}, - {1,0,64}, + {0,0,128}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2535,21 +2407,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, }, { { {0,0,0}, {0,0,0}, - {0,8,9}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2559,15 +2422,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.frag.spv", +{ "./forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,112}, + {0,0,544}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2595,16 +2458,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.frag.spv", +{ "./forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, + {1,0,32}, + {0,0,544}, }, { { - {2,2,1}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2616,12 +2480,15 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2631,34 +2498,260 @@ const std::unordered_map shaderMetaInfo = { } } }, -}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawQuad", { +{ "./bindless/m2Particle/forward/m2ParticleShader.frag.spv", + { + ShaderStage::Fragment, { - 0, { - {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, - } + {1,0,32}, + {0,0,544}, }, - }}, - {"adtShader", { { - 2, { + { + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { - 1, { - } }, { - 3, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,2,3}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, } + } + } +}, +{ "./forwardRendering/imguiShader.frag.spv", + { + ShaderStage::Fragment, + { }, { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {1,0, "Texture"}, + }, + { + { + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/skyConus.frag.spv", + { + ShaderStage::Fragment, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/imguiShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,80}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/renderFrameBufferShader.frag.spv", + { + ShaderStage::Fragment, + { + {0,2,168}, + }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {0,3, "u_sampler"}, + }, + { + { + {3,3,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/m2Shader.frag.spv", + { + ShaderStage::Fragment, + { + {2,0,64}, + {1,4,256}, + {1,3,4096}, + {1,1,256}, + {0,0,544}, + {1,0,64}, + {1,5,4096}, + }, + { + { + {0,0,1}, + {0,5,6}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {3,0, "uTexture"}, + {3,1, "uTexture2"}, + {3,2, "uTexture3"}, + {3,3, "uTexture4"}, + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,3,4}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +}; + +const std::unordered_map>> fieldDefMapPerShaderNameVert = { + {"drawQuad", { + { + 0, { + {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, + } + }, + }}, + {"adtShader", { + { + 1, { + } + }, + { + 3, { + } + }, + { + 0, { + {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, + {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, + {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, {"_0_0_scene_uInteriorSunDir_lightBufferIndex", true, 144, 1, 4, 0}, {"_0_0_scene_closeRiverColor", true, 160, 1, 4, 0}, {"_0_0_scene_farRiverColor", true, 176, 1, 4, 0}, @@ -2695,25 +2788,6 @@ const std::unordered_map weakPtr(hgPipeline); loadedPipeLines[pipelineCacheRecord] = weakPtr; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 67f272fb7..4c61e2f42 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -130,7 +130,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getRenderPass(const std::vector &textureAttachments, ITextureFormat depthAttachment, @@ -347,7 +348,8 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(k.shaderConfig.shaderFolder); + size_t mapHash = hash{}(k.shaderConfig.vertexShaderFolder) ^ + hash{}(k.shaderConfig.fragmentShaderFolder); for (const auto &rec : k.shaderConfig.typeOverrides) for (const auto &rec2 : rec.second) mapHash ^= diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index f29cdb9e3..de866d896 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -114,6 +114,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, GFrameBufferVLK::GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, + const HGTexture &depthBuffer, int multiSampleCnt, bool invertZ, int width, int height) : mdevice(dynamic_cast(device)), @@ -165,7 +166,12 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, }); //Depth attachment - if (depthAttachment != ITextureFormat::itNone) { + if (depthBuffer != nullptr) { + m_depthTexture = depthBuffer; + + attachments.push_back(std::dynamic_pointer_cast(m_depthTexture)->texture.view); + + } else if (depthAttachment != ITextureFormat::itNone) { assert(depthAttachment == ITextureFormat::itDepth32); // Find a suitable depth format @@ -179,7 +185,7 @@ GFrameBufferVLK::GFrameBufferVLK(IDevice &device, fbDepthFormat, sampleCountToVkSampleCountFlagBits(multiSampleCnt), 1, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT )); m_depthTexture = h_depthTexture; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h index ad865725d..011af7608 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.h @@ -12,7 +12,8 @@ class GFrameBufferVLK : public IFrameBuffer { public: - GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, int multiSampleCnt, bool invertZ, int width, int height); + GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, ITextureFormat depthAttachment, const HGTexture &depthBuffer, int multiSampleCnt, bool invertZ, int width, int height); + GFrameBufferVLK(IDevice &device, const std::vector &textureAttachments, const HGTexture &depthBuffer, int multiSampleCnt, bool invertZ, int width, int height); GFrameBufferVLK(IDevice &device, const HGTexture &colorImage, const HGTexture &depthBuffer, @@ -55,7 +56,7 @@ class GFrameBufferVLK : public IFrameBuffer { std::vector m_textureAttachments; ITextureFormat m_depthAttachment = ITextureFormat::itNone; - int m_multiSampleCnt; + int m_multiSampleCnt = 0; int m_width = 0; int m_height = 0; diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp index 1687ab923..177eb1af4 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.cpp @@ -366,7 +366,11 @@ void CmdBufRecorder::bindMaterial(const std::shared_ptr &mat if (m_material == material) return; //1. Bind pipeline - this->bindPipeline(material->getPipeline()); + if (m_gbufferMode) { + this->bindPipeline(material->getGBufferPipeline()); + } else { + this->bindPipeline(material->getPipeline()); + } //2. Bind Descriptor sets auto const &descSets = material->getDescriptorSets(); diff --git a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h index 6ecdba6cf..e87b33520 100644 --- a/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h +++ b/wowViewerLib/src/gapi/vulkan/commandBuffer/commandBufferRecorder/CommandBufferRecorder.h @@ -43,6 +43,13 @@ class CmdBufRecorder { void setSecondaryCmdRenderArea(const std::array &areaOffset, const std::array &areaSize); + void setGBufferMode(bool value) { + if (m_gbufferMode != value) { + m_currentPipeline = nullptr; + m_gbufferMode = value; + } + } + RenderPassHelper beginRenderPass( bool isAboutToExecSecondaryCMD, const std::shared_ptr &renderPassVlk, @@ -106,6 +113,7 @@ class CmdBufRecorder { std::array viewportsForThisStage; VkRect2D defaultScissor; + bool m_gbufferMode = false; void createViewPortTypes(const std::array &areaOffset, const std::array &areaSize, diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp index a7c22ffd7..728d6e017 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.cpp @@ -11,10 +11,11 @@ ISimpleMaterialVLK::ISimpleMaterialVLK(const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, + const HPipelineVLK &gBufferPipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, uint32_t materialId) : m_shader(shader), m_pipelineTemplate(pipelineTemplate), - m_pipeline(pipeline), m_materialId(materialId) { + m_pipeline(pipeline), m_gBufferPipeline(gBufferPipeline), m_materialId(materialId) { for (int i = descriptorSets.size()-1; i < descriptorSets.size(); i--) { if (descriptorSets[i] != nullptr) { this->descriptors.resize(i+1); diff --git a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h index 7d4e3b26c..4c4a06f77 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/ISimpleMaterialVLK.h @@ -18,6 +18,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this explicit ISimpleMaterialVLK(const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, + const HPipelineVLK &gBufferPipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, uint32_t materialId); ~ISimpleMaterialVLK() override = default; @@ -32,6 +33,9 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this const HPipelineVLK &getPipeline() const { return m_pipeline; } + const HPipelineVLK &getGBufferPipeline() const { + return m_gBufferPipeline; + } const PipelineTemplate &getPipelineTemplate() const { return m_pipelineTemplate; } @@ -45,6 +49,7 @@ class ISimpleMaterialVLK : public IMaterial, public std::enable_shared_from_this uint32_t m_materialId; std::shared_ptr m_shader; HPipelineVLK m_pipeline; + HPipelineVLK m_gBufferPipeline; PipelineTemplate m_pipelineTemplate; }; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index eb0debc9d..b67f37f05 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -23,11 +23,13 @@ MaterialBuilderVLK::MaterialBuilderVLK( const std::shared_ptr &device, const std::shared_ptr &shader, const HPipelineVLK &pipeline, + const HPipelineVLK &gBufferPipeline, const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, uint32_t materialId) : - m_device(device), m_shader(shader), m_pipeline(pipeline), m_pipelineTemplate(pipelineTemplate), + m_device(device), m_shader(shader), m_pipeline(pipeline), m_gBufferPipeline(gBufferPipeline), + m_pipelineTemplate(pipelineTemplate), m_descriptorSets(descriptorSets), m_pipelineLayout(pipelineLayout), m_materialId(materialId) { } @@ -74,12 +76,43 @@ MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindi pipelineTemplate.triCCW, pipelineTemplate.blendMode, pipelineTemplate.depthCulling, - pipelineTemplate.depthWrite + pipelineTemplate.depthWrite, + pipelineTemplate.colorMask ); return *this; } +MaterialBuilderVLK& MaterialBuilderVLK::createGBufferPipeline(const HGVertexBufferBindings &bindings, + const std::vector &shaderFiles, const ShaderConfig &shaderConfig, + const std::shared_ptr &renderPass) { + if (m_pipelineTemplate.blendMode >= EGxBlendEnum::GxBlend_Alpha) { + return *this; + } + + auto gbufferShader = std::dynamic_pointer_cast(std::dynamic_pointer_cast(m_device)->getShader( + shaderFiles[0], + shaderFiles[1], shaderConfig)); + + + m_gBufferPipeline = std::dynamic_pointer_cast(m_device)->createPipeline( + bindings, + gbufferShader, + m_pipelineLayout, + renderPass, + m_pipelineTemplate.element, + m_pipelineTemplate.backFaceCulling, + m_pipelineTemplate.triCCW, + m_pipelineTemplate.blendMode, + m_pipelineTemplate.depthCulling, + m_pipelineTemplate.depthWrite, + m_pipelineTemplate.colorMask + ); + + return *this; +} + + MaterialBuilderVLK &MaterialBuilderVLK::setMaterialId(uint32_t matId) { m_materialId = matId; @@ -91,6 +124,7 @@ std::shared_ptr MaterialBuilderVLK::toMaterial() { m_shader, m_pipelineTemplate, m_pipeline, + m_gBufferPipeline, m_descriptorSets, m_materialId ); diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index ab9ad0bb6..bcf524f0f 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -26,6 +26,7 @@ class MaterialBuilderVLK { const std::shared_ptr &materialVlk) { return {device, materialVlk->getShader(), materialVlk->getPipeline(), + materialVlk->getGBufferPipeline(), materialVlk->getPipeline()->getLayout(), materialVlk->getPipelineTemplate(), toArray(materialVlk->getDescriptorSets()), @@ -38,6 +39,9 @@ class MaterialBuilderVLK { MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, const std::shared_ptr &renderPass, const PipelineTemplate &pipelineTemplate); + MaterialBuilderVLK& createGBufferPipeline(const HGVertexBufferBindings &bindings, + const std::vector &shaderFiles, const ShaderConfig &shaderConfig, + const std::shared_ptr &renderPass); MaterialBuilderVLK& setMaterialId(uint32_t matId); std::shared_ptr toMaterial(); @@ -47,6 +51,7 @@ class MaterialBuilderVLK { m_shader, m_pipelineTemplate, m_pipeline, + m_gBufferPipeline, m_descriptorSets, m_materialId); } @@ -66,6 +71,7 @@ class MaterialBuilderVLK { MaterialBuilderVLK(const std::shared_ptr &device, const std::shared_ptr &shader, const HPipelineVLK &pipeline, + const HPipelineVLK &gBufferPipeline, const std::shared_ptr &pipelineLayout, const PipelineTemplate &pipelineTemplate, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, @@ -79,6 +85,7 @@ class MaterialBuilderVLK { uint32_t m_materialId; std::shared_ptr m_shader; HPipelineVLK m_pipeline; + HPipelineVLK m_gBufferPipeline = nullptr; std::shared_ptr m_pipelineLayout; PipelineTemplate m_pipelineTemplate; std::array, MAX_SHADER_DESC_SETS> m_descriptorSets; diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp index 97625dc0d..840f757c1 100644 --- a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.cpp @@ -43,7 +43,8 @@ GPipelineVLK::GPipelineVLK(IDevice &device, bool triCCW, EGxBlendEnum blendMode, bool depthCulling, - bool depthWrite) : m_device(dynamic_cast(device)) { + bool depthWrite, + uint8_t colorMask) : m_device(dynamic_cast(device)) { GVertexBufferBindingsVLK* bufferBindingsVlk = dynamic_cast(m_bindings.get()); auto &arrVLKFormat = bufferBindingsVlk->getVLKFormat(); @@ -70,6 +71,7 @@ GPipelineVLK::GPipelineVLK(IDevice &device, blendMode, depthCulling, depthWrite, + colorMask, vertexBindingDescriptions, vertexAttributeDescriptions); } @@ -94,6 +96,7 @@ void GPipelineVLK::createPipeline( EGxBlendEnum m_blendMode, bool depthCulling, bool depthWrite, + uint8_t colorMask, const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions) { @@ -191,7 +194,10 @@ void GPipelineVLK::createPipeline( { auto &colorBlendAttachment = colorBlendAttachments.emplace_back(); colorBlendAttachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + (((colorMask & 1) > 0) ? VK_COLOR_COMPONENT_R_BIT : 0) | + (((colorMask & 2) > 0) ? VK_COLOR_COMPONENT_G_BIT : 0) | + (((colorMask & 4) > 0) ? VK_COLOR_COMPONENT_B_BIT : 0) | + (((colorMask & 8) > 0) ? VK_COLOR_COMPONENT_A_BIT : 0); colorBlendAttachment.blendEnable = blendModesVLK[(char) m_blendMode].blendModeEnable ? VK_TRUE : VK_FALSE; colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; @@ -207,7 +213,10 @@ void GPipelineVLK::createPipeline( colorBlendAttachment.blendEnable = VK_FALSE; colorBlendAttachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + (((colorMask & 1) > 0) ? VK_COLOR_COMPONENT_R_BIT : 0) | + (((colorMask & 2) > 0) ? VK_COLOR_COMPONENT_G_BIT : 0) | + (((colorMask & 4) > 0) ? VK_COLOR_COMPONENT_B_BIT : 0) | + (((colorMask & 8) > 0) ? VK_COLOR_COMPONENT_A_BIT : 0); colorBlendAttachment.blendEnable = VK_FALSE; colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; diff --git a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h index aca67efec..71db81ac6 100644 --- a/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h +++ b/wowViewerLib/src/gapi/vulkan/pipeline/GPipelineVLK.h @@ -25,7 +25,8 @@ class GPipelineVLK { bool triCCW, EGxBlendEnum blendMode, bool depthCulling, - bool depthWrite); + bool depthWrite, + uint8_t colorMask); ~GPipelineVLK(); void createPipeline( @@ -37,6 +38,7 @@ class GPipelineVLK { EGxBlendEnum m_blendMode, bool m_depthCulling, bool m_depthWrite, + uint8_t colorMask, const std::vector &vertexBindingDescriptions, const std::vector &vertexAttributeDescriptions); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index b171119d2..08bcc810e 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -69,8 +69,8 @@ void GShaderPermutationVLK::createSetDescriptorLayouts() { } void GShaderPermutationVLK::compileShader(const std::string &vertExtraDef, const std::string &fragExtraDef) { - vertShaderName = m_shaderConf.shaderFolder +"/" + m_shaderNameVert; - vertShaderFrag = m_shaderConf.shaderFolder +"/" + m_shaderNameFrag; + vertShaderName = m_shaderConf.vertexShaderFolder +"/" + m_shaderNameVert; + vertShaderFrag = m_shaderConf.fragmentShaderFolder +"/" + m_shaderNameFrag; auto vertShaderCode = readFile("spirv/" + vertShaderName + ".vert.spv"); auto fragShaderCode = readFile("spirv/" + vertShaderFrag + ".frag.spv"); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h index 6e7b2531c..f3a8ca0fd 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/ShaderConfig.h @@ -27,7 +27,8 @@ struct DescTypeConfig { typedef std::unordered_map> DescTypeOverride; struct ShaderConfig { - std::string shaderFolder; + std::string vertexShaderFolder; + std::string fragmentShaderFolder; DescTypeOverride typeOverrides; }; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 506a03620..6e01d684a 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -128,7 +128,7 @@ class IMapSceneBufferCreate { virtual HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) = 0; virtual HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; virtual HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) = 0; - virtual HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) = 0; + virtual HGSortableMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) = 0; virtual HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) = 0; }; typedef std::shared_ptr HMapSceneBufferCreate; diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 6d40514d4..6915155c5 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -55,12 +55,15 @@ struct WaterMaterialTemplate { class IM2ModelData { public: virtual ~IM2ModelData() = default; + std::shared_ptr> m_placementMatrix = nullptr; std::shared_ptr> m_bonesData = nullptr; std::shared_ptr> m_colors = nullptr; std::shared_ptr> m_textureWeights = nullptr; - std::shared_ptr> m_textureMatrices = nullptr; + std::shared_ptr> m_modelFragmentData = nullptr; + std::shared_ptr> m_textureMatrices = nullptr; + //Constants std::shared_ptr> m_instanceBindless = nullptr; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 5af8e4354..91700b77b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -19,6 +19,7 @@ #include static const ShaderConfig forwardShaderConfig = { + "forwardRendering", "forwardRendering", { {0, { @@ -33,6 +34,7 @@ const int adtTexturesBindlessCount = 4096; const int waterTexturesBindlessCount = 1024; static const ShaderConfig m2BindlessShaderConfig = { + "bindless/m2/forward", "bindless/m2/forward", { {0, { @@ -45,7 +47,13 @@ static const ShaderConfig m2BindlessShaderConfig = { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} }} }}; +static const ShaderConfig m2BindlessGBufferShaderConfig = { + "bindless/m2/forward", + "bindless/m2/deferred", + m2BindlessShaderConfig.typeOverrides +}; static const ShaderConfig bindlessShaderConfig = { + "bindless", "bindless", { {0, { @@ -55,6 +63,7 @@ static const ShaderConfig bindlessShaderConfig = { static const ShaderConfig m2WaterfallBindlessShaderConfig = { + "bindless/waterfall/forward", "bindless/waterfall/forward", { {0, { @@ -66,6 +75,7 @@ static const ShaderConfig m2WaterfallBindlessShaderConfig = { }}; static const ShaderConfig wmoBindlessShaderConfig = { + "bindless/wmo/forward", "bindless/wmo/forward", { {0, { @@ -76,7 +86,14 @@ static const ShaderConfig wmoBindlessShaderConfig = { }} }}; +static const ShaderConfig wmoBindlessGBufferShaderConfig = { + "bindless/wmo/forward", + "bindless/wmo/deferred", + wmoBindlessShaderConfig.typeOverrides +}; + static const ShaderConfig adtBindlessShaderConfig = { + "bindless/adt/forward", "bindless/adt/forward", { {0, { @@ -93,7 +110,14 @@ static const ShaderConfig adtBindlessShaderConfig = { }} }}; +static const ShaderConfig adtBindlessGBufferShaderConfig = { + "bindless/adt/forward", + "bindless/adt/deferred", + adtBindlessShaderConfig.typeOverrides +}; + static const ShaderConfig waterBindlessShaderConfig = { + "bindless/water", "bindless/water", { {0, { @@ -112,8 +136,8 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, sizeof(M2Vertex)); vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024); - vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024, 64); + vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024, 64); vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, sizeof(AdtVertex)); vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, sizeof(WMOVertex)); vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, sizeof(LiquidVertexFormat)); @@ -194,9 +218,10 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; - defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); - m_renderPass = defaultView->getRenderPass(); + m_forwardRenderPass = defaultView->getForwardPass(); + m_gBufferPass = defaultView->getGBufferPass(); glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); @@ -219,18 +244,6 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, createWaterGlobalMaterialData(); } -std::shared_ptr MapSceneRenderBindlessVLK::chooseRenderPass(const PipelineTemplate &pipelineTemplate) { - if (pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_Opaque && pipelineTemplate.blendMode != EGxBlendEnum::GxBlend_AlphaKey) { - return getRenderPass(false); - } else { - return getRenderPass(true); - } -} - -std::shared_ptr MapSceneRenderBindlessVLK::getRenderPass(bool isOpaque) { - return m_renderPass; -} - void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { adtLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); adtHeightLayerTextureHolder = std::make_shared(adtTexturesBindlessCount); @@ -246,7 +259,9 @@ void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) - .createPipeline(m_emptyADTVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyADTVAO, m_forwardRenderPass, pipelineTemplate) + .createGBufferPipeline(m_emptyADTVAO, {"adtShader", "adtShader"}, adtBindlessGBufferShaderConfig, m_gBufferPass) + .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -276,7 +291,7 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { //Create global water descriptor for bindless textures g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .createPipeline(m_emptyWaterVAO, getRenderPass(false), pipelineTemplate) + .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { ds->beginUpdate() @@ -302,7 +317,7 @@ void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { //Create global wmo descriptor for bindless textures g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) - .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -331,7 +346,8 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { //Create global m2 descriptor for bindless textures g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) - .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) + .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() @@ -378,10 +394,13 @@ std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMateri bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; + bool isTrueOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque; + auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessShaderConfig) .setMaterialId(generateUniqueM2MatId()) - .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) + .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) .bindDescriptorSet(2, m2TextureDS) @@ -399,10 +418,13 @@ std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMater return i->second; } + bool isTrueOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque; + auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessShaderConfig) .setMaterialId(generateUniqueWMOMatId()) - .createPipeline(m_emptyWMOVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) + .createGBufferPipeline(m_emptyWMOVAO, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, wmoBufferOneDS) .bindDescriptorSet(2, wmoTexturesDS) @@ -674,7 +696,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Waterfa auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) .overridePipelineLayout({{1, m2BufferOneDS}}) - .createPipeline(m_emptyM2VAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) .bindDescriptorSet(2, m2WaterfallBufferDS) @@ -726,7 +748,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Particle pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Particle/forward/m2ParticleShader", "m2Particle/forward/m2ParticleShader"}, bindlessShaderConfig) - .createPipeline(m_emptyM2ParticleVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyM2ParticleVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { ds->beginUpdate() @@ -753,7 +775,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMate auto &l_m2ModelData = m2ModelData; auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Ribbon/forward/ribbonShader", "m2Ribbon/forward/ribbonShader"}, bindlessShaderConfig) - .createPipeline(m_emptyM2RibbonVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyM2RibbonVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { ds->beginUpdate() @@ -835,7 +857,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(c auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .createPipeline(m_emptyWaterVAO, getRenderPass(false), pipelineTemplate) + .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) .bindDescriptorSet(2, waterTexturesDS) @@ -879,7 +901,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMateri auto skyColors = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) - .createPipeline(m_emptySkyVAO, getRenderPass(false), pipelineTemplate) + .createPipeline(m_emptySkyVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() @@ -897,7 +919,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial auto materialPS = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) - .createPipeline(m_emptyPortalVAO, chooseRenderPass(pipelineTemplate), pipelineTemplate) + .createPipeline(m_emptyPortalVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { ds->beginUpdate() @@ -1102,7 +1124,6 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ { //2. Render WMO cmdBuf.bindVertexBindings(m_renderer.getDefaultWMOVao()); - cmdBuf.bindMaterial(m_renderer.getGlobalWMOMaterial()); uint32_t currentMatId = 0xFFFFFFFF; for (auto const &drawCmd : wmoDrawVec) { @@ -1111,7 +1132,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ if (!material) continue; - cmdBuf.bindPipeline(material->getPipeline()); + cmdBuf.bindMaterial(material); currentMatId = drawCmd.matId; } @@ -1124,7 +1145,6 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ { //3. Render m2 cmdBuf.bindVertexBindings(m_renderer.getDefaultM2Vao()); - cmdBuf.bindMaterial(m_renderer.getGlobalM2Material()); uint32_t currentMatId = 0xFFFFFFFF; for (auto const &drawCmd : m2DrawVec) { @@ -1133,7 +1153,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ if (!material) continue; - cmdBuf.bindPipeline(material->getPipeline()); + cmdBuf.bindMaterial(material); currentMatId = drawCmd.matId; } @@ -1238,7 +1258,7 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh mapScene->doPostLoad(l_this, framePlan); for (auto &renderTarget : frameInputParams->frameParameters->renderTargets) { - auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); + auto updatingTarget = std::dynamic_pointer_cast(renderTarget.target); if (!updatingTarget) updatingTarget = l_this->defaultView; updatingTarget->update( @@ -1336,29 +1356,39 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh auto currentView = renderTarget.target == nullptr ? l_this->defaultView : - std::dynamic_pointer_cast(renderTarget.target); + std::dynamic_pointer_cast(renderTarget.target); { - auto passHelper = currentView->beginPass(frameBufCmd, l_this->getRenderPass(true), false, - frameInputParams->frameParameters->clearColor); { - //Opaque part - l_this->drawOpaque(frameBufCmd, l_opaqueMeshes); + auto passHelper = currentView->beginGBufferPass(frameBufCmd, false, + frameInputParams->frameParameters->clearColor); + frameBufCmd.setGBufferMode(true); + { + //Opaque part + l_this->drawOpaque(frameBufCmd, l_opaqueMeshes); + } + frameBufCmd.setGBufferMode(false); } -// currentView->doOpaqueNonOpaqueBarrier(frameBufCmd); + currentView->doGBufferBarrier(frameBufCmd); { - //Sky opaque - if (renderSky && skyMesh) - MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh, - CmdBufRecorder::ViewportType::vp_skyBox); + auto passHelper = currentView->beginForwardPass(frameBufCmd, false, false, + frameInputParams->frameParameters->clearColor); - l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); - } - { - //Sky transparent - for (int i = 0; i < skyTransparentMeshes->size(); i++) { - auto const &mesh = skyTransparentMeshes->at(i); + l_this->drawOpaque(frameBufCmd, l_opaqueMeshes); + + { + //Sky opaque + if (renderSky && skyMesh) + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh, + CmdBufRecorder::ViewportType::vp_skyBox); + + l_skyOpaqueMeshes->render(frameBufCmd, CmdBufRecorder::ViewportType::vp_skyBox); + } + { + //Sky transparent + for (int i = 0; i < skyTransparentMeshes->size(); i++) { + auto const &mesh = skyTransparentMeshes->at(i); // std::string debugMess = // "Drawing mesh " @@ -1369,22 +1399,22 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_skyBox); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_skyBox); + } + if (renderSky && skyMesh0x4) + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh0x4, + CmdBufRecorder::ViewportType::vp_skyBox); } - if (renderSky && skyMesh0x4) - MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, skyMesh0x4, - CmdBufRecorder::ViewportType::vp_skyBox); - } - { - //Render liquids - l_opaqueMeshes->renderWater(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); - } - { - VkZone(frameBufCmd, "render transparent") - ZoneScopedN("submit transparent"); - for (int i = 0; i < transparentMeshes->size(); i++) { - auto const &mesh = transparentMeshes->at(i); + { + //Render liquids + l_opaqueMeshes->renderWater(frameBufCmd, CmdBufRecorder::ViewportType::vp_usual); + } + { + VkZone(frameBufCmd, "render transparent") + ZoneScopedN("submit transparent"); + for (int i = 0; i < transparentMeshes->size(); i++) { + auto const &mesh = transparentMeshes->at(i); // // std::string debugMess = // "Drawing mesh " @@ -1395,8 +1425,9 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh // // auto debugLabel = frameBufCmd.beginDebugLabel(debugMess, {1.0, 0, 0, 1.0}); - MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, - CmdBufRecorder::ViewportType::vp_usual); + MapSceneRenderBindlessVLK::drawMesh(frameBufCmd, mesh, + CmdBufRecorder::ViewportType::vp_usual); + } } } } @@ -1477,7 +1508,7 @@ MapSceneRenderBindlessVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std:: return mesh; } -HGMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, +HGSortableMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyWMOVAO; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index a14b3bbdd..300aa4c9b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -15,6 +15,7 @@ #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" #include "../../../engine/objects/scenes/EntityActorsFactory.h" +#include "view/RenderViewDeferredVLK.h" class COpaqueMeshCollectorBindlessVLK; @@ -105,7 +106,7 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGMesh createAdtMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material) override; HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; - HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; + HGSortableMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; //-------------------------------------- @@ -228,7 +229,9 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::shared_ptr waterTexturesDS = nullptr; std::shared_ptr waterTextureHolder = nullptr; - std::shared_ptr m_renderPass; + std::shared_ptr m_forwardRenderPass; + std::shared_ptr m_gBufferPass; + std::shared_ptr m_shadowPass; std::shared_ptr m_lastCreatedPlan = nullptr; @@ -242,8 +245,8 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBufferBindings m_emptyWaterVAO = nullptr; - using RendererViewClass = RenderViewForwardVLK; - std::shared_ptr defaultView; + using RendererViewClass = RenderViewDeferredVLK; + std::shared_ptr defaultView; MeshCount lastMeshCount; @@ -289,9 +292,6 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBufferBindings getDefaultWMOVao() const {return m_emptyWMOVAO;}; HGVertexBufferBindings getDefaultWaterVao() const {return m_emptyWaterVAO;}; - std::shared_ptr chooseRenderPass(const PipelineTemplate &pipelineTemplate); - virtual std::shared_ptr getRenderPass(bool isOpaque); - void drawOpaque(CmdBufRecorder &frameBufCmd, const std::unique_ptr &l_opaqueMeshes); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 3cbdd12af..35ca03059 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -18,6 +18,7 @@ #include static const ShaderConfig forwardShaderConfig = { + "forwardRendering", "forwardRendering", { {0, { @@ -26,6 +27,7 @@ static const ShaderConfig forwardShaderConfig = { } }; static const ShaderConfig m2ForwardShaderConfig = { + "forwardRendering", "forwardRendering", { {0, { @@ -857,7 +859,7 @@ HGSortableMesh MapSceneRenderForwardVLK::createWaterMesh(gMeshTemplate &meshTemp auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } -HGMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { +HGSortableMesh MapSceneRenderForwardVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index ba1f59c5c..73b921f13 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -101,7 +101,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGM2Mesh createM2Mesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGM2Mesh createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) override; HGSortableMesh createWaterMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) override; - HGMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; + HGSortableMesh createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) override; //-------------------------------------- // RenderView //-------------------------------------- diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp index b345fed2d..dd7e12f08 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp @@ -1461,7 +1461,7 @@ MapSceneRenderBindlessVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std:: return mesh; } -HGMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, +HGSortableMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, const std::shared_ptr> &ambientBuffer) { auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyWMOVAO; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h index 5ed5e6224..d9919a1bf 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h @@ -17,9 +17,10 @@ class IMaterialInstance : public ISimpleMaterialVLK, public IMaterialClass { const std::shared_ptr &shader, const PipelineTemplate &pipelineTemplate, const HPipelineVLK &pipeline, + const HPipelineVLK &gBufferPipeline, const std::array, MAX_SHADER_DESC_SETS> &descriptorSets, uint32_t materialId) : - ISimpleMaterialVLK(shader, pipelineTemplate, pipeline, descriptorSets, materialId) { + ISimpleMaterialVLK(shader, pipelineTemplate, pipeline, gBufferPipeline, descriptorSets, materialId) { initializer(this); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index ca57f2caf..34a64e5c1 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -185,6 +185,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { *m_device, dataFormat, ITextureFormat::itNone, + nullptr, 1, false, targetWidth, targetHeight @@ -195,6 +196,7 @@ void FFXGlowPassVLK::createFrameBuffers(int m_width, int m_height) { *m_device, dataFormat, ITextureFormat::itNone, + nullptr, 1, false, targetWidth, targetHeight @@ -217,7 +219,7 @@ FFXGlowPassVLK::createFFXGaussMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {"forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {"forwardRendering", "forwardRendering"}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() @@ -242,7 +244,7 @@ FFXGlowPassVLK::createFFXGlowMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {"forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {"forwardRendering", "forwardRendering"}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 752de89b5..dc17c6665 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -17,8 +17,8 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, createFrameBuffers(); { std::vector> inputColorTextures; - for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + for (int i = 0; i < m_forwardFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_forwardFrameBuffers[i]->getAttachment(0)); } glowPass->updateDimensions(m_width, m_height, @@ -29,44 +29,63 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, void RenderViewDeferredVLK::createFrameBuffers() { { - auto const dataFormat = { + auto const gBufferFormat = { ITextureFormat::itRGBA, //Albedo ITextureFormat::itRGBA, //Specular ITextureFormat::itRGBA //Normal }; + auto const forwardBufferFormat = { + ITextureFormat::itRGBA //Color + }; + auto depthFormat = ITextureFormat::itDepth32; bool invertZ = true; - m_opaqueRenderPass = m_device->getRenderPass(dataFormat, + int gBufferPassSamples = 1; + int forwardPassSamples = 1; //m_device->getMaxSamplesCnt(); + + m_gBufferRenderPass = m_device->getRenderPass(gBufferFormat, depthFormat, - sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + sampleCountToVkSampleCountFlagBits(gBufferPassSamples), invertZ, false, true, true); - m_nonOpaqueRenderPass = m_device->getRenderPass({ITextureFormat::itRGBA}, + m_forwardRenderPass = m_device->getRenderPass(forwardBufferFormat, + depthFormat, + sampleCountToVkSampleCountFlagBits(forwardPassSamples), + invertZ, false, + true, true); + + m_forwardRenderPassNoDepthClear = m_device->getRenderPass(forwardBufferFormat, depthFormat, - sampleCountToVkSampleCountFlagBits(m_device->getMaxSamplesCnt()), + sampleCountToVkSampleCountFlagBits(forwardPassSamples), invertZ, false, - false, false); + true, false); - for (auto &colorFrameBuffer: m_colorFrameBuffers) { - colorFrameBuffer = std::make_shared( + for (auto &gBufferFrameBuffer: m_gBufferFrameBuffers) { + gBufferFrameBuffer = std::make_shared( *m_device, - dataFormat, + gBufferFormat, depthFormat, - m_device->getMaxSamplesCnt(), + nullptr, + gBufferPassSamples, invertZ, m_width, m_height ); } - std::vector attachmentsToCopy = {0}; - for (int i = 0; i < m_colorNonOpaqFrameBuffers.size(); i++) { - m_colorNonOpaqFrameBuffers[i] = std::make_shared( - m_colorFrameBuffers[i].get(), - attachmentsToCopy, - m_nonOpaqueRenderPass +// std::vector attachmentsToCopy = {}; + for (int i = 0; i < m_forwardFrameBuffers.size(); i++) { + m_forwardFrameBuffers[i] = std::make_shared( + *m_device, + forwardBufferFormat, + depthFormat, + m_gBufferFrameBuffers[i]->getDepthTexture(), + forwardPassSamples, //m_device->getMaxSamplesCnt(), + invertZ, + m_width, + m_height ); } } @@ -83,6 +102,7 @@ void RenderViewDeferredVLK::createFrameBuffers() { *m_device, dataFormat, ITextureFormat::itNone, + nullptr, 1, invertZ, m_width, m_height @@ -104,8 +124,8 @@ void RenderViewDeferredVLK::update(int width, int height, float glow) { { std::vector> inputColorTextures; - for (int i = 0; i < m_colorFrameBuffers.size(); i++) { - inputColorTextures.emplace_back(m_colorFrameBuffers[i]->getAttachment(0)); + for (int i = 0; i < m_forwardFrameBuffers.size(); i++) { + inputColorTextures.emplace_back(m_forwardFrameBuffers[i]->getAttachment(0)); } glowPass->updateDimensions(m_width, m_height, @@ -122,18 +142,18 @@ static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { return {vec[0], vec[1], vec[2]}; } -RenderPassHelper RenderViewDeferredVLK::beginOpaquePass(CmdBufRecorder &frameBufCmd, +RenderPassHelper RenderViewDeferredVLK::beginGBufferPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor) { return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, - m_opaqueRenderPass, - m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + m_gBufferRenderPass, + m_gBufferFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], {0,0}, {m_width, m_height}, vec4ToArr3(clearColor)); } -void RenderViewDeferredVLK::doOpaqueNonOpaqueBarrier(CmdBufRecorder &frameBufCmd) { - auto const &fb = m_colorFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; +void RenderViewDeferredVLK::doGBufferBarrier(CmdBufRecorder &frameBufCmd) { + auto const &fb = m_gBufferFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; VkImageSubresourceRange subresourceRange = {}; // Image only contains color data @@ -163,10 +183,11 @@ void RenderViewDeferredVLK::doOpaqueNonOpaqueBarrier(CmdBufRecorder &frameBufCmd ); } -RenderPassHelper RenderViewDeferredVLK::beginNonOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor) { +RenderPassHelper RenderViewDeferredVLK::beginForwardPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, + bool clearDepth, mathfu::vec4 &clearColor) { return frameBufCmd.beginRenderPass(willExecuteSecondaryBuffs, - m_nonOpaqueRenderPass, - m_colorNonOpaqFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], + clearDepth ? m_forwardRenderPass : m_forwardRenderPassNoDepthClear, + m_forwardFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT], {0,0}, {m_width, m_height}, vec4ToArr3(clearColor)); @@ -203,7 +224,7 @@ void RenderViewDeferredVLK::iterateOverOutputTextures( { std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) - depthTextures[i] = m_device->createSampledTexture(m_colorFrameBuffers[i]->getDepthTexture(), false, false); + depthTextures[i] = m_device->createSampledTexture(m_forwardFrameBuffers[i]->getDepthTexture(), false, false); callback(depthTextures, "Depth buffer", ITextureFormat::itDepth32); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h index 66520703f..f9bd87231 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h @@ -16,13 +16,13 @@ class RenderViewDeferredVLK : public IRenderView { void update(int width, int height, float glow); - std::shared_ptr getOpaqueRenderPass() {return m_opaqueRenderPass;} - std::shared_ptr getNonOpaqueRenderPass() {return m_nonOpaqueRenderPass;} + std::shared_ptr getGBufferPass() {return m_gBufferRenderPass;} + std::shared_ptr getForwardPass() {return m_forwardRenderPass;} - RenderPassHelper beginOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); - RenderPassHelper beginNonOpaquePass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + RenderPassHelper beginGBufferPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, mathfu::vec4 &clearColor); + RenderPassHelper beginForwardPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, bool clearDepth, mathfu::vec4 &clearColor); - void doOpaqueNonOpaqueBarrier(CmdBufRecorder &frameBufCmd); + void doGBufferBarrier(CmdBufRecorder &frameBufCmd); void doOutputPass(CmdBufRecorder &frameBufCmd); @@ -38,10 +38,12 @@ class RenderViewDeferredVLK : public IRenderView { HGDeviceVLK m_device; bool m_createOutputFBO; - std::shared_ptr m_opaqueRenderPass; - std::shared_ptr m_nonOpaqueRenderPass; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorFrameBuffers; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_colorNonOpaqFrameBuffers; + std::shared_ptr m_gBufferRenderPass; + std::shared_ptr m_forwardRenderPass; + std::shared_ptr m_forwardRenderPassNoDepthClear; + std::shared_ptr m_shadowPass; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_gBufferFrameBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_forwardFrameBuffers; std::unique_ptr glowPass; std::shared_ptr m_outputRenderPass; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp index b872ca0b7..b515fbda4 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewForwardVLK.cpp @@ -45,6 +45,7 @@ void RenderViewForwardVLK::createFrameBuffers() { *m_device, dataFormat, depthFormat, + nullptr, m_device->getMaxSamplesCnt(), invertZ, m_width, m_height @@ -64,6 +65,7 @@ void RenderViewForwardVLK::createFrameBuffers() { *m_device, dataFormat, ITextureFormat::itNone, + nullptr, 1, invertZ, m_width, m_height From 8d84ee537a3cf1fb8b7cc350bedf17d21e4e04d4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 2 Apr 2024 00:43:16 +0300 Subject: [PATCH 180/212] - Lights from _lgt.wdt file - light buffer part 1 --- wowViewerLib/CMakeLists.txt | 8 ++ .../glsl/bindless/deferred_excerpt.glsl | 15 ++- .../glsl/bindless/lights/pointLight.frag | 1 + .../glsl/bindless/lights/pointLight.vert | 26 +++++ .../glsl/bindless/wmo/wmoshader_text.glsl | 12 +- .../glsl/common/commonLightFunctions.glsl | 16 ++- .../glsl/common/commonUboSceneData.glsl | 2 + .../src/engine/WowFilesCacheStorage.cpp | 7 +- .../src/engine/WowFilesCacheStorage.h | 3 + .../src/engine/managers/animationManager.cpp | 9 +- .../src/engine/managers/animationManager.h | 4 +- .../src/engine/objects/lights/CPointLight.cpp | 26 +++++ .../src/engine/objects/lights/CPointLight.h | 24 ++++ .../src/engine/objects/lights/CSpotLight.cpp | 5 + .../src/engine/objects/lights/CSpotLight.h | 14 +++ .../src/engine/objects/m2/m2Object.cpp | 26 ++++- wowViewerLib/src/engine/objects/m2/m2Object.h | 3 +- .../src/engine/objects/scenes/map.cpp | 30 ++++- wowViewerLib/src/engine/objects/scenes/map.h | 2 + .../engine/objects/wdt/wdtLightsObject.cpp | 71 ++++++++++++ .../src/engine/objects/wdt/wdtLightsObject.h | 33 ++++++ .../persistance/helper/ChunkFileReader.h | 16 ++- .../src/engine/persistance/wdtLightFile.cpp | 65 +++++++++++ .../src/engine/persistance/wdtLightFile.h | 82 ++++++++++++++ .../src/engine/shader/ShaderDefinitions.h | 67 +++++------ wowViewerLib/src/engine/wowCommonClasses.h | 2 + .../src/gapi/UniformBufferStructures.h | 14 ++- .../src/gapi/interface/textures/ITexture.h | 1 + .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 4 + wowViewerLib/src/include/iostuff.h | 1 + .../src/renderer/mapScene/MapScenePlan.h | 3 + .../renderer/mapScene/MapSceneRenderer.cpp | 7 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 31 ++--- .../vulkan/MapSceneRenderBindlessVLK.h | 2 + .../vulkan/view/RenderViewDeferredVLK.cpp | 106 ++++++++++++++++-- .../vulkan/view/RenderViewDeferredVLK.h | 32 +++++- 37 files changed, 674 insertions(+), 98 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert create mode 100644 wowViewerLib/src/engine/objects/lights/CPointLight.cpp create mode 100644 wowViewerLib/src/engine/objects/lights/CPointLight.h create mode 100644 wowViewerLib/src/engine/objects/lights/CSpotLight.cpp create mode 100644 wowViewerLib/src/engine/objects/lights/CSpotLight.h create mode 100644 wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp create mode 100644 wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h create mode 100644 wowViewerLib/src/engine/persistance/wdtLightFile.cpp create mode 100644 wowViewerLib/src/engine/persistance/wdtLightFile.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 14ea4a076..0353cc0e9 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -368,6 +368,14 @@ set(SOURCE_FILES src/engine/objects/SceneObjectWithID.h src/engine/custom_allocators/FrameBasedStackAllocator.cpp src/engine/custom_allocators/FrameBasedStackAllocator.h + src/engine/objects/wdt/wdtLightsObject.cpp + src/engine/objects/wdt/wdtLightsObject.h + src/engine/persistance/wdtLightFile.cpp + src/engine/persistance/wdtLightFile.h + src/engine/objects/lights/CPointLight.cpp + src/engine/objects/lights/CPointLight.h + src/engine/objects/lights/CSpotLight.cpp + src/engine/objects/lights/CSpotLight.h ) if (LINK_OGL2) diff --git a/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl index f056328e6..5f08475ba 100644 --- a/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl +++ b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl @@ -1,14 +1,17 @@ #ifndef DEFERRED_EXCERPT #define DEFERRED_EXCERPT -layout(location = 0) out vec4 outAlbedo; -layout(location = 1) out vec4 outSpecular; -layout(location = 2) out vec4 outNormal; +//layout(location = 0) out vec4 outAlbedo; +//layout(location = 1) out vec4 outSpecular; +layout(location = 0) out vec4 outNormal; +layout(location = 1) out float outDepth; void writeGBuffer(vec3 albedo, vec3 normal, vec3 specular) { - outAlbedo = vec4(albedo, 0.0); - outNormal = vec4(normal, 0.0); - outSpecular = vec4(specular, 0.0); +// outAlbedo = vec4(albedo, 0.0); +// outNormal = vec4(normal, 0.0); +// outSpecular = vec4(specular, 0.0); + outNormal = vec4(normal * 0.5 + 0.5, 0.0); + outDepth = gl_FragCoord.z; } #endif //DEFERRED_EXCERPT \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag new file mode 100644 index 000000000..5dfeaf516 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert new file mode 100644 index 000000000..19097c92f --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert @@ -0,0 +1,26 @@ +#include "../../common/commonUboSceneData.glsl" + +layout (location = 0) in vec2 position; + +layout(std430, set=1, binding=0) buffer readonly pointLightBuffer { + LocalLight lights[]; +}; + +void main() { + + LocalLight lightRec = lights[gl_InstanceIndex]; + + vec4 lightPosView = scene.uLookAtMat * vec4(lightRec.position.xyz, 1.0); + + float attentuationEnd = lightRec.attenuation.z; + + //Hack to get square bounding the circle of point light + //The quads (-1.0, 1.0) or other is multiplied by radius end of point light + vec2 quadPosView = (position.xy * attentuationEnd); + + lightPosView.xy += quadPosView; + + //Now it's safe to multiply it by perspective matrix + gl_Position = scene.uPMatrix * (lightPosView.xyz, 1.0); +} + diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index 59e2cf4e1..446ca3cfd 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -3,11 +3,11 @@ precision highp float; precision highp int; -#include "../../../common/commonLightFunctions.glsl" -#include "../../../common/commonFogFunctions.glsl" -#include "../../../common/commonFunctions.glsl" -#include "../../../common/commonWMOMaterial.glsl" -#include "../../../common/commonUboSceneData.glsl" +#include "../../common/commonLightFunctions.glsl" +#include "../../common/commonFogFunctions.glsl" +#include "../../common/commonFunctions.glsl" +#include "../../common/commonWMOMaterial.glsl" +#include "../../common/commonUboSceneData.glsl" #ifdef TRUE_OPAQUE layout(early_fragment_tests) in; @@ -24,7 +24,7 @@ layout (location = 7) in vec4 vPosition; layout (location = 8) in vec3 vNormal; layout (location = 9) in flat int vMeshIndex; -#include "../../../common/commonWMOIndirectDescriptorSet.glsl" +#include "../../common/commonWMOIndirectDescriptorSet.glsl" layout (set = 2, binding = 0) uniform sampler2D s_Textures[]; diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 121b89910..e158d9fde 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -1,12 +1,26 @@ #ifndef COMMON_LIGHT_FUNCTIONS #define COMMON_LIGHT_FUNCTIONS + struct LocalLight { - vec4 color; + vec4 innerColor; + vec4 outerColor; vec4 position; vec4 attenuation; + vec4 blendParams; }; +struct Spotlight +{ + vec4 colorAndFalloff; + vec4 outercolor; + vec4 positionAndcosInnerAngle; + vec4 attenuationAndcosOuterAngle; + vec4 directionAndcosAngleDiff; + vec4 interior; +}; + + struct SceneExteriorLight { vec4 uExteriorAmbientColor; vec4 uExteriorHorizontAmbientColor; diff --git a/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl b/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl index f47434e03..0dfafc7f4 100644 --- a/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl +++ b/wowViewerLib/shaders/glsl/common/commonUboSceneData.glsl @@ -8,5 +8,7 @@ layout(std140, set=0, binding=0) uniform sceneWideBlockVSPS { SceneWideParams scene; PSFog fogData; }; +layout(set=0, binding=1) uniform sampler2D lightBuffer; +layout(set=0, binding=2) uniform sampler2D aoBuffer; #endif \ No newline at end of file diff --git a/wowViewerLib/src/engine/WowFilesCacheStorage.cpp b/wowViewerLib/src/engine/WowFilesCacheStorage.cpp index 053f3f630..a3a78d298 100644 --- a/wowViewerLib/src/engine/WowFilesCacheStorage.cpp +++ b/wowViewerLib/src/engine/WowFilesCacheStorage.cpp @@ -48,6 +48,7 @@ WoWFilesCacheStorage::WoWFilesCacheStorage(IFileRequest *requestProcessor) : wmoMainCache(requestProcessor, CacheHolderType::CACHE_MAIN_WMO), wmoGeomCache(requestProcessor, CacheHolderType::CACHE_GROUP_WMO), wdtCache(requestProcessor, CacheHolderType::CACHE_WDT), + wdtLightCache(requestProcessor, CacheHolderType::CACHE_WDT_LIGHT), wdlCache(requestProcessor, CacheHolderType::CACHE_WDL), m2GeomCache(requestProcessor, CacheHolderType::CACHE_M2), skinGeomCache(requestProcessor, CacheHolderType::CACHE_SKIN), @@ -104,8 +105,12 @@ Cache *WoWFilesCacheStorage::getWmoGroupGeomCache() { return &wmoGeomCache; }; -Cache *WoWFilesCacheStorage::getWdtFileCache() { +Cache* WoWFilesCacheStorage::getWdtFileCache() { return &wdtCache; +} + +Cache *WoWFilesCacheStorage::getWdtLightFileCache() { + return &wdtLightCache; }; Cache *WoWFilesCacheStorage::getWdlFileCache() { diff --git a/wowViewerLib/src/engine/WowFilesCacheStorage.h b/wowViewerLib/src/engine/WowFilesCacheStorage.h index 58dc9d61b..b00728ae0 100644 --- a/wowViewerLib/src/engine/WowFilesCacheStorage.h +++ b/wowViewerLib/src/engine/WowFilesCacheStorage.h @@ -14,6 +14,7 @@ typedef std::shared_ptr HWoWFilesCacheStorage; #include "../gapi/interface/IDevice.h" #include "persistance/adtFile.h" #include "persistance/wdtFile.h" +#include "persistance/wdtLightFile.h" #include "persistance/wdlFile.h" #include "persistance/skelFile.h" #include "cache/cache.h" @@ -30,6 +31,7 @@ class WoWFilesCacheStorage : public IFileRequester { private: Cache adtObjectCache; Cache wdtCache; + Cache wdtLightCache; Cache wdlCache; Cache wmoGeomCache; Cache wmoMainCache; @@ -54,6 +56,7 @@ class WoWFilesCacheStorage : public IFileRequester { Cache* getWmoMainCache(); Cache* getWmoGroupGeomCache(); Cache* getWdtFileCache(); + Cache* getWdtLightFileCache(); Cache* getWdlFileCache(); Cache* getDb2Cache(); }; diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index a322e4f08..3dd361228 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -731,6 +731,7 @@ void AnimationManager::update( mathfu::vec3 &cameraPosInLocal, mathfu::vec3 &localUpVector, mathfu::vec3 &localRightVector, + const mathfu::mat4 &modelMatrix, const mathfu::mat4 &modelViewMatrix, std::vector &bonesMatrices, std::vector &textAnimMatrices, @@ -935,7 +936,7 @@ void AnimationManager::update( this->calcTransparencies(transparencies); // this->calcCameras(cameraDetails, this->currentAnimationIndex, this->currentAnimationTime); - this->calcLights(lights, bonesMatrices); + this->calcLights(lights, bonesMatrices, modelMatrix); this->calcParticleEmitters(particleEmitters, bonesMatrices); this->calcRibbonEmitters(ribbonEmitters); @@ -1000,7 +1001,7 @@ void AnimationManager::calcTransparencies(std::vector &transparencies) { } -void AnimationManager::calcLights(std::vector &lights, std::vector &bonesMatrices) { +void AnimationManager::calcLights(std::vector &lights, const std::vector &bonesMatrices, const mathfu::mat4 &modelMatrix) { auto &lightRecords = boneMasterData->getM2Geom()->getM2Data()->lights; auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; @@ -1111,10 +1112,10 @@ void AnimationManager::calcLights(std::vector &lights, std::vecto defaultChar ); - mathfu::mat4 &boneMat = bonesMatrices[lightRecord->bone]; + const mathfu::mat4 &boneMat = bonesMatrices[lightRecord->bone]; C3Vector &pos_vec = lightRecord->position; - mathfu::vec4 lightWorldPos = boneMat * mathfu::vec4(mathfu::vec3(pos_vec), 1.0); + mathfu::vec4 lightWorldPos = modelMatrix * boneMat * mathfu::vec4(mathfu::vec3(pos_vec), 1.0); lightWorldPos.w = 1.0; // if (i == 0) { diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index 4185168d5..b98b21f2b 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -58,6 +58,7 @@ class AnimationManager { mathfu::vec3 &cameraPosInLocal, mathfu::vec3 &localUpVector, mathfu::vec3 &localRightVector, + const mathfu::mat4 &modelMatrix, const mathfu::mat4 &modelViewMatrix, std::vector &bonesMatrices, std::vector &textAnimMatrices, @@ -93,7 +94,8 @@ class AnimationManager { } void calcLights(std::vector &lights, - std::vector &bonesMatrices); + const std::vector &bonesMatrices, + const mathfu::mat4 &modelMatrix); void calcParticleEmitters( const std::vector> &particleEmitters, std::vector &bonesMatrices); diff --git a/wowViewerLib/src/engine/objects/lights/CPointLight.cpp b/wowViewerLib/src/engine/objects/lights/CPointLight.cpp new file mode 100644 index 000000000..fb740dcc9 --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CPointLight.cpp @@ -0,0 +1,26 @@ +// +// Created by Deamon on 4/1/2024. +// + +#include "CPointLight.h" + +CPointLight::CPointLight() { + +} + +CPointLight::CPointLight(WdtLightFile::MapPointLight3 &lightRecord) { + + mathfu::vec4 attenVec = mathfu::vec4(lightRecord.attenuationStart, lightRecord.intensity, lightRecord.attenuationEnd, 0); + + m_localLight.attenuation = attenVec; + + m_localLight.innerColor = mathfu::vec4( + ((float)lightRecord.color.r)/255.0f, + ((float)lightRecord.color.g)/255.0f, + ((float)lightRecord.color.b)/255.0f, + 0); + + m_localLight.outerColor = m_localLight.innerColor; + m_localLight.position = mathfu::vec4(mathfu::vec3(lightRecord.position), 0.0); + m_localLight.blendParams = mathfu::vec4(0.0); +} diff --git a/wowViewerLib/src/engine/objects/lights/CPointLight.h b/wowViewerLib/src/engine/objects/lights/CPointLight.h new file mode 100644 index 000000000..8e3c342e4 --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CPointLight.h @@ -0,0 +1,24 @@ +// +// Created by Deamon on 4/1/2024. +// + +#ifndef AWEBWOWVIEWERCPP_CPOINTLIGHT_H +#define AWEBWOWVIEWERCPP_CPOINTLIGHT_H + +#include "../../persistance/wdtLightFile.h" +#include "../../../gapi/UniformBufferStructures.h" + +class CPointLight { +public: + CPointLight(); + CPointLight(WdtLightFile::MapPointLight3 &lightRecord); + + LocalLight& getLightRec() { + return m_localLight; + } +private: + LocalLight m_localLight; +}; + + +#endif //AWEBWOWVIEWERCPP_CPOINTLIGHT_H diff --git a/wowViewerLib/src/engine/objects/lights/CSpotLight.cpp b/wowViewerLib/src/engine/objects/lights/CSpotLight.cpp new file mode 100644 index 000000000..019a6fc48 --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CSpotLight.cpp @@ -0,0 +1,5 @@ +// +// Created by Deamon on 4/1/2024. +// + +#include "CSpotLight.h" diff --git a/wowViewerLib/src/engine/objects/lights/CSpotLight.h b/wowViewerLib/src/engine/objects/lights/CSpotLight.h new file mode 100644 index 000000000..c08beb4b2 --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CSpotLight.h @@ -0,0 +1,14 @@ +// +// Created by Deamon on 4/1/2024. +// + +#ifndef AWEBWOWVIEWERCPP_CSPOTLIGHT_H +#define AWEBWOWVIEWERCPP_CSPOTLIGHT_H + + +class CSpotLight { + +}; + + +#endif //AWEBWOWVIEWERCPP_CSPOTLIGHT_H diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 3878a89dd..edb5f428a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -969,6 +969,7 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v cameraInlocalPos, this->m_localUpVector, this->m_localRightVector, + m_placementMatrix, modelViewMat, this->bonesMatrices, this->textAnimMatrices, @@ -1041,6 +1042,29 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v } } +void M2Object::collectLights(std::vector &pointLights) { + //Fill lights + { + auto const m2Data = m_m2Geom->getM2Data(); + pointLights.reserve(pointLights.size() + lights.size()); + for (int i = 0; i < lights.size(); i++) { + //1 == point light + if (m2Data->lights[i]->type != 1) continue; + + auto const &m2Light = lights[i]; + if (!m2Light.visibility) continue; + + auto &pointLight = pointLights.emplace_back(); + pointLight.attenuation = mathfu::vec4(m2Light.attenuation_start, m2Light.diffuse_intensity, + m2Light.attenuation_end, 0); + pointLight.innerColor = m2Light.diffuse_color ; + pointLight.outerColor = m2Light.diffuse_color ; + pointLight.position = m2Light.position; + pointLight.blendParams = mathfu::vec4(0,0,0,0); + } + } +} + void M2Object::fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer) { int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); @@ -1651,7 +1675,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index return m2Mesh; } -void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { +void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes) { M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 75ea59c7f..b2d519995 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -245,7 +245,7 @@ class M2Object : public ObjectWithId { mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); - void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); + void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes); bool setUseLocalLighting(bool value) { if (m_useLocalDiffuseColor == -1) { @@ -267,6 +267,7 @@ class M2Object : public ObjectWithId { void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); + void collectLights(std::vector &pointLights); void fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 9c1447e74..83065f9ad 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -281,11 +281,15 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) { std::string wdtFileName = "world/maps/"+mapName+"/"+mapName+".wdt"; std::string wdlFileName = "world/maps/"+mapName+"/"+mapName+".wdl"; + std::string wdtLightFileName = "world/maps/"+mapName+"/"+mapName+"_lgt.wdt"; m_wdtfile = api->cacheStorage->getWdtFileCache()->get(wdtFileName); + m_wdtLightObject = std::make_shared(api, wdtLightFileName); + m_wdlObject = std::make_shared(api, wdlFileName); m_wdlObject->setMapApi(this); + loadZoneLights(); m_sceneWideBlockVSPSChunk = nullptr; @@ -1096,6 +1100,12 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, } } + if (m_wdtLightObject == nullptr && m_wdtfile != nullptr && m_wdtfile->getStatus() == FileStatus::FSLoaded) { + if (m_wdtfile->mphd->flags.wdt_has_maid) { + m_wdtLightObject = std::make_shared(m_api, m_wdtfile->mphd->lgtFileDataID); + } + } + auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); //Should not be null, since we called checkExterior if (m_wdlObject != nullptr) { @@ -1272,6 +1282,14 @@ void Map::checkADTCulling(int i, int j, if (result) { mapRenderPlan->viewsHolder.getExterior()->drawnADTs.push_back(adtFrustRes); mapRenderPlan->adtArray.push_back(adtFrustRes); + + //Add lights from WDTLightObject + if (m_wdtLightObject) { + auto pointLightsOfAdt = m_wdtLightObject->getPointLights(i, j); + auto pointLights = mapRenderPlan->pointLights; + pointLights.reserve(pointLights.size() + pointLightsOfAdt.size()); + for (auto pointLight : pointLightsOfAdt) pointLights.push_back(pointLight.getLightRec()); + } } } else if (!m_lockedMap && true) { //(m_wdtfile->mapTileTable->mainInfo[j][i].Flag_HasADT > 0) { if (m_wdtfile->mphd->flags.wdt_has_maid) { @@ -1444,6 +1462,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { int granSize = m2ToDraw.size() / (2 * threadsAvailable); if (granSize == 0) granSize = m2ToDraw.size(); + std::mutex fillLights; if (granSize > 0) { oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); arena.execute([&] { @@ -1452,7 +1471,16 @@ void Map::update(const HMapRenderPlan &renderPlan) { [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { auto &m2Object = m2ToDraw[i]; - m2Object->update(deltaTime, cameraVec3, lookAtMat); + m2Object->update(deltaTime, cameraVec3, lookAtMat);\ + + std::vector localLights; + m2Object->collectLights(localLights); + if (!localLights.empty()) { + std::unique_lock lock(fillLights); + renderPlan->pointLights.insert( + renderPlan->pointLights.end(), + localLights.begin(),localLights.end()); + } } }, ap); }); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index ff48b2102..a1dfeb10d 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -19,6 +19,7 @@ #include "../../../renderer/frame/FrameInputParams.h" #include "../../../renderer/mapScene/MapScenePlan.h" #include "../../../renderer/mapScene/MapSceneParams.h" +#include "../wdt/wdtLightsObject.h" enum class SceneMode { smMap, @@ -57,6 +58,7 @@ class Map : public IScene, public IMapApi { std::vector> m_exteriorSkyBoxes; std::shared_ptr m_wdlObject = nullptr; + std::shared_ptr m_wdtLightObject = nullptr; int m_viewRenderOrder = 0; diff --git a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp new file mode 100644 index 000000000..3fbd91a9a --- /dev/null +++ b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp @@ -0,0 +1,71 @@ +// +// Created by Deamon on 3/31/2024. +// + +#include "wdtLightsObject.h" + +WdtLightsObject::WdtLightsObject(HApiContainer api, std::string &wdtLgtFileName) { + m_api = api; + m_wdtLightFile = m_api->cacheStorage->getWdtLightFileCache()->get(wdtLgtFileName); +} + +WdtLightsObject::WdtLightsObject(HApiContainer api, int wdtLgtFileDataId) { + m_api = api; + m_wdtLightFile = m_api->cacheStorage->getWdtLightFileCache()->getFileId(wdtLgtFileDataId); +} + +static const std::vector emptyPointLights = {}; +static const std::vector emptySpotLights = {}; + +const std::vector &WdtLightsObject::getPointLights(uint8_t tileX, uint8_t tileY) { + if (m_wdtLightFile->getStatus() != FileStatus::FSLoaded) + return emptyPointLights; + + if (!m_lightsCreated) { + createLightArray(); + m_lightsCreated = true; + } + + return m_pointLights[tileX][tileY]; +} + +const std::vector &WdtLightsObject::getSpotLights(uint8_t tileX, uint8_t tileY) { + if (m_wdtLightFile->getStatus() != FileStatus::FSLoaded) + return emptySpotLights; + + if (!m_lightsCreated) { + createLightArray(); + m_lightsCreated = true; + } + + return m_spotLights[tileX][tileY]; +} + +void WdtLightsObject::createLightArray() { + if (m_wdtLightFile->getStatus() != FileStatus::FSLoaded) + return; + + //Create Point Lights + { +// std::unordered_map processedLightIds; + for (int i = 0; i < m_wdtLightFile->mapPointLights3Len; i++) { + auto &pointLight3 = m_wdtLightFile->mapPointLights3[i]; + +// { +// auto it = processedLightIds.find(pointLight3.lightIndex); +// bool found = it != processedLightIds.end(); +// if (found) { +// auto duplicateRec = it->second; +// std::cout << "Found duploicate" << std::endl; +// } +// } + + + m_pointLights[pointLight3.tileX][pointLight3.tileY].emplace_back() = + CPointLight(pointLight3); + +// processedLightIds[pointLight3.lightIndex] = &pointLight3; + } + } +} + diff --git a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h new file mode 100644 index 000000000..1f62ca504 --- /dev/null +++ b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h @@ -0,0 +1,33 @@ +// +// Created by Deamon on 3/31/2024. +// + +#ifndef AWEBWOWVIEWERCPP_WDTLIGHTSOBJECT_H +#define AWEBWOWVIEWERCPP_WDTLIGHTSOBJECT_H + + +#include "../../ApiContainer.h" +#include "../lights/CPointLight.h" +#include "../lights/CSpotLight.h" + +class WdtLightsObject { +public: + explicit WdtLightsObject(HApiContainer api, std::string &wdtLgtFileName); + explicit WdtLightsObject(HApiContainer api, int wdtLgtFileDataId); + + const std::vector &getPointLights(uint8_t tileX, uint8_t tileY); + const std::vector &getSpotLights(uint8_t tileX, uint8_t tileY); +private: + void createLightArray(); +private: + HApiContainer m_api; + HWdtLightFile m_wdtLightFile; + + bool m_lightsCreated = false; + + std::array, 64>, 64> m_pointLights = {}; + std::array, 64>, 64> m_spotLights = {}; +}; + + +#endif //AWEBWOWVIEWERCPP_WDTLIGHTSOBJECT_H diff --git a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h index bb376beb5..2c4b4512c 100644 --- a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h +++ b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h @@ -185,16 +185,20 @@ class CChunkFileReader { } template inline void readValues(T* &value, int count) { static_assert(!std::is_pointer::value, "T is a pointer"); - value = (T*)&(((unsigned char *)fileData)[currentOffset]); - currentOffset += count*sizeof(T); - bytesRead += count*sizeof(T); + if (count > 0) { + value = (T *) &(((unsigned char *) fileData)[currentOffset]); + currentOffset += count * sizeof(T); + bytesRead += count * sizeof(T); + } } template inline void readValues(PointerChecker &value, int count) { static_assert(!std::is_pointer::value, "T is a pointer"); - value = (T*)&(((unsigned char *)fileData)[currentOffset]); - currentOffset += count*sizeof(T); - bytesRead += count*sizeof(T); + if (count > 0) { + value = (T *) &(((unsigned char *) fileData)[currentOffset]); + currentOffset += count * sizeof(T); + bytesRead += count * sizeof(T); + } } }; diff --git a/wowViewerLib/src/engine/persistance/wdtLightFile.cpp b/wowViewerLib/src/engine/persistance/wdtLightFile.cpp new file mode 100644 index 000000000..b9954e255 --- /dev/null +++ b/wowViewerLib/src/engine/persistance/wdtLightFile.cpp @@ -0,0 +1,65 @@ +// +// Created by Deamon on 3/31/2024. +// + +#include "wdtLightFile.h" +chunkDef WdtLightFile::wdtLightFileTable = { + [](WdtLightFile &file, ChunkData &chunkData) {}, + { + { + 'MPL3', + { + [](WdtLightFile &file, ChunkData &chunkData) { + debuglog("Entered MPL3"); + file.mapPointLights3Len = (chunkData.chunkLen / sizeof(MapPointLight3)); + chunkData.readValues(file.mapPointLights3, file.mapPointLights3Len); + } + } + }, + { + 'MSLT', + { + [](WdtLightFile &file, ChunkData &chunkData) { + debuglog("Entered MSLT"); + file.mapSpotLightLen = (chunkData.chunkLen / sizeof(MapSpotLight)); + chunkData.readValues(file.mapSpotLights3, file.mapSpotLightLen); + } + } + }, + { + 'MLTA', + { + [](WdtLightFile &file, ChunkData &chunkData) { + debuglog("Entered MLTA"); + file.mapTextureLightAttenuationLen = (chunkData.chunkLen / sizeof(MapLightTextureAttenuation)); + chunkData.readValues(file.mapTextureLightAttenuation, file.mapTextureLightAttenuationLen); + } + } + }, + { + 'MTEX', + { + [](WdtLightFile &file, ChunkData &chunkData) { + debuglog("Entered MTEX"); + file.textureFileDataIds = + std::vector( + (unsigned long) (chunkData.chunkLen / 4)); + + for (int i = 0; i < file.textureFileDataIds.size(); i++) { + chunkData.readValue(file.textureFileDataIds[i]); + } + } + } + }, + } +}; + + +void WdtLightFile::process(HFileContent wdtLightFile, const std::string &fileName) { + m_wdtLightFile = wdtLightFile; + + CChunkFileReader reader(*m_wdtLightFile.get(), fileName); + reader.processFile(*this, &WdtLightFile::wdtLightFileTable); + + fsStatus = FileStatus::FSLoaded; +} diff --git a/wowViewerLib/src/engine/persistance/wdtLightFile.h b/wowViewerLib/src/engine/persistance/wdtLightFile.h new file mode 100644 index 000000000..e5623d447 --- /dev/null +++ b/wowViewerLib/src/engine/persistance/wdtLightFile.h @@ -0,0 +1,82 @@ +// +// Created by Deamon on 3/31/2024. +// + +#ifndef AWEBWOWVIEWERCPP_WDTLIGHTFILE_H +#define AWEBWOWVIEWERCPP_WDTLIGHTFILE_H + +#include "../../include/sharedFile.h" +#include "PersistentFile.h" +#include "helper/ChunkFileReader.h" + +class WdtLightFile : public PersistentFile { +public: + WdtLightFile(std::string fileName){}; + WdtLightFile(int fileDataId){}; + ~WdtLightFile() { +// std::cout << "destructor for WdtLightFile was called" << std::endl; + } + + void process(HFileContent wdtFile, const std::string &fileName) override; +public: + PACK( + struct MapPointLight3 + { +/*0x00*/ uint32_t lightIndex; +/*0x04*/ CImVector color; +/*0x08*/ C3Vector position; +/*0x14*/ float attenuationStart; +/*0x18*/ float attenuationEnd; +/*0x1C*/ float intensity; +/*0x20*/ C3Vector rotation; //Should be rotation, but rotation doesn't make sense for point light. Probably unused? +/*0x2C*/ uint16_t tileX; +/*0x2E*/ uint16_t tileY; +/*0x30*/ int16_t mlta_index; //Index into MLTA +/*0x32*/ int16_t textureIndex; //Index into MTEX +/*0x34*/ uint16_t flags; +/*0x36*/ uint16_t unk1; //Some packed value + }); + + PACK( + struct MapSpotLight + { + uint32_t id; + CArgb color; + C3Vector position; + float rangeAttenuationStart;// When to start the attenuation of the light, must be <= rangeAttenuationEnd or glitches + float rangeAttenuationEnd; + float intensity; + C3Vector rotation; // radians + float falloffExponent; + float innerRadius; + float outerRadius; // radians + uint16_t tile_x; + uint16_t tile_y; + int16_t unk[2]; // -1 mostly, may be an MLTA ID though. + }) ; + + PACK( + struct MapLightTextureAttenuation{ + float flickerIntensity; + float flickerSpeed; + int flickerMode; // 0 = off, 1 = sine curve, 2 = noise curve, 3 = noise step curve + }); + + PointerChecker mapPointLights3 = (mapPointLights3Len); + int mapPointLights3Len = 0; + + PointerChecker mapSpotLights3 = (mapSpotLightLen); + int mapSpotLightLen = 0; + + PointerChecker mapTextureLightAttenuation = (mapTextureLightAttenuationLen); + int mapTextureLightAttenuationLen = 0; + + std::vector textureFileDataIds; + +private: + HFileContent m_wdtLightFile; + static chunkDef wdtLightFileTable; +}; + + +#endif //AWEBWOWVIEWERCPP_WDTLIGHTFILE_H diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index e42d4496b..6738ee241 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -493,7 +493,6 @@ const std::unordered_map shaderMetaInfo = { {1,8,0}, {1,7,0}, {1,5,0}, - {1,4,0}, {1,6,0}, }, { @@ -756,18 +755,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1086,11 +1081,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1101,22 +1095,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, }, { { {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1388,7 +1376,6 @@ const std::unordered_map shaderMetaInfo = { {1,8,0}, {1,7,0}, {1,5,0}, - {1,4,0}, {1,6,0}, }, { @@ -3256,6 +3243,11 @@ const std::unordered_map HAdtFile; typedef std::shared_ptr HWdtFile; +typedef std::shared_ptr HWdtLightFile; typedef std::shared_ptr HWdlFile; typedef std::shared_ptr HM2Geom; typedef std::shared_ptr HSkinGeom; diff --git a/wowViewerLib/src/gapi/UniformBufferStructures.h b/wowViewerLib/src/gapi/UniformBufferStructures.h index 388c6eb09..70abab258 100644 --- a/wowViewerLib/src/gapi/UniformBufferStructures.h +++ b/wowViewerLib/src/gapi/UniformBufferStructures.h @@ -66,9 +66,21 @@ struct InteriorLightParam { struct LocalLight { - mathfu::vec4_packed color; + mathfu::vec4_packed innerColor; + mathfu::vec4_packed outerColor; mathfu::vec4_packed position; mathfu::vec4_packed attenuation; + mathfu::vec4_packed blendParams; +}; + +struct Spotlight +{ + mathfu::vec4_packed colorAndFalloff; + mathfu::vec4_packed outercolor; + mathfu::vec4_packed positionAndcosInnerAngle; + mathfu::vec4_packed attenuationAndcosOuterAngle; + mathfu::vec4_packed directionAndcosAngleDiff; + mathfu::vec4_packed interior; }; namespace M2 { diff --git a/wowViewerLib/src/gapi/interface/textures/ITexture.h b/wowViewerLib/src/gapi/interface/textures/ITexture.h index ff0ddafd0..9e9789ff3 100644 --- a/wowViewerLib/src/gapi/interface/textures/ITexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ITexture.h @@ -12,6 +12,7 @@ enum class ITextureFormat { itNone, itRGBA, itInt, + itFloat32, itRGBAFloat32, itDepth32 }; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 0d63d721a..c2b678ee1 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp index de866d896..58eee2340 100644 --- a/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GFrameBufferVLK.cpp @@ -25,6 +25,10 @@ void GFrameBufferVLK::iterateOverAttachments(const std::vector & textureFormat = VK_FORMAT_R32_UINT; break; + case ITextureFormat::itFloat32: + textureFormat = VK_FORMAT_R32_SFLOAT; + break; + case ITextureFormat::itRGBAFloat32: textureFormat = VK_FORMAT_R32G32B32A32_SFLOAT; break; diff --git a/wowViewerLib/src/include/iostuff.h b/wowViewerLib/src/include/iostuff.h index 8d7466b19..295f8b442 100644 --- a/wowViewerLib/src/include/iostuff.h +++ b/wowViewerLib/src/include/iostuff.h @@ -26,6 +26,7 @@ enum class CacheHolderType { CACHE_GROUP_WMO, CACHE_ADT, CACHE_WDT, + CACHE_WDT_LIGHT, CACHE_WDL, CACHE_BLP, CACHE_DB2, diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index 004c28676..39c97e5fc 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -44,6 +44,9 @@ struct MapRenderPlan { WMOListContainer wmoArray; WMOGroupListContainer wmoGroupArray; + std::vector pointLights; + std::vector spotLights; + }; typedef std::shared_ptr HMapRenderPlan; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index cc9ac3850..b085e3dab 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -78,8 +78,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende for (size_t i = r.begin(); i != r.end(); ++i) { auto &m2Object = m2ToDraw[i]; if (m2Object != nullptr) { - m2Object->collectMeshes(*lCollector, transpVec, - m_viewRenderOrder); + m2Object->collectMeshes(*lCollector, transpVec); m2Object->drawParticles(*lCollector, transpVec, m_viewRenderOrder); } @@ -97,7 +96,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende } else { for (auto &m2Object : cullStage->m2Array.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); + m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes); m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); } } @@ -111,7 +110,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende ZoneScopedN("collect skyBox"); for (auto &m2Object : skyBoxView->m2List.getDrawn()) { if (m2Object == nullptr) continue; - m2Object->collectMeshes(skyOpaqueMeshCollector, skyTranspVec, m_viewRenderOrder); + m2Object->collectMeshes(skyOpaqueMeshCollector, skyTranspVec); m2Object->drawParticles(skyOpaqueMeshCollector, skyTranspVec, m_viewRenderOrder); } skyTransparentMeshes.insert(skyTransparentMeshes.end(), skyTranspVec.begin(), skyTranspVec.end()); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 91700b77b..38f726545 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -203,6 +203,9 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer("M2 Waterfall Common",200, sizeof(M2::WaterfallData::WaterfallCommon)); m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer("M2 Waterfall Bindless",200, sizeof(M2::WaterfallData::WaterfallBindless)); + pointLightBuffer = m_device->createSSBOBuffer("Point Light Buffer",200, sizeof(LocalLight)); + spotLightBuffer = m_device->createSSBOBuffer("Spot Light Buffer",200, sizeof(Spotlight)); + uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); @@ -218,7 +221,7 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, //Framebuffers for rendering auto const dataFormat = { ITextureFormat::itRGBA}; - defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); + defaultView = std::make_shared(m_device, uboBuffer, pointLightBuffer, m_drawQuadVao, false); m_forwardRenderPass = defaultView->getForwardPass(); m_gBufferPass = defaultView->getGBufferPass(); @@ -232,7 +235,10 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) .createDescriptorSet(0, [&](std::shared_ptr &ds) { ds->beginUpdate() - .ubo_dynamic(0, sceneWideChunk); + .ubo_dynamic(0, sceneWideChunk) + .texture(1, hDevice->getBlackTexturePixel()) + .texture(2, hDevice->getWhiteTexturePixel()); + sceneWideDS = ds; }); } @@ -1216,14 +1222,6 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh framePlan->wmoArray.lock(); framePlan->wmoGroupArray.lock(); - -// TracyMessageL("collect meshes created"); -// std::future collectMeshAsync = std::async(std::launch::async, -// [&]() { - -// } -// ); - mapScene->update(framePlan); mapScene->updateBuffers(l_this, framePlan); @@ -1264,7 +1262,9 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh updatingTarget->update( renderTarget.viewPortDimensions.maxs[0], renderTarget.viewPortDimensions.maxs[1], - framePlan->frameDependentData->currentGlow + framePlan->frameDependentData->currentGlow, + framePlan->pointLights, + framePlan->spotLights ); } } @@ -1295,6 +1295,9 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh uploadCmd.submitBufferUploads(l_this->uboBuffer); uploadCmd.submitBufferUploads(l_this->uboStaticBuffer); + uploadCmd.submitBufferUploads(l_this->pointLightBuffer); + uploadCmd.submitBufferUploads(l_this->spotLightBuffer); + uploadCmd.submitBufferUploads(l_this->vboM2Buffer); uploadCmd.submitBufferUploads(l_this->vboPortalBuffer); uploadCmd.submitBufferUploads(l_this->vboM2ParticleBuffer); @@ -1357,6 +1360,8 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh auto currentView = renderTarget.target == nullptr ? l_this->defaultView : std::dynamic_pointer_cast(renderTarget.target); + + currentView->setLightBuffers(l_this->sceneWideDS); { { @@ -1370,7 +1375,7 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh frameBufCmd.setGBufferMode(false); } currentView->doGBufferBarrier(frameBufCmd); - + currentView->doLightPass(frameBufCmd); { auto passHelper = currentView->beginForwardPass(frameBufCmd, false, false, frameInputParams->frameParameters->clearColor); @@ -1543,5 +1548,5 @@ HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTem } std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { - return std::make_shared(m_device, uboBuffer, m_drawQuadVao, createOutput); + return std::make_shared(m_device, uboBuffer, pointLightBuffer, m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 300aa4c9b..82862f237 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -155,6 +155,8 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGBufferVLK iboBuffer; HGBufferVLK uboStaticBuffer; + HGBufferVLK pointLightBuffer; + HGBufferVLK spotLightBuffer; struct { HGBufferVLK placementMatrix; HGBufferVLK boneMatrix; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index dc17c6665..9b746fb82 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -3,15 +3,17 @@ // #include "RenderViewDeferredVLK.h" +#include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" /* * RenderViewDeferredVLK */ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, - const HGBufferVLK &uboBuffer, - const HGVertexBufferBindings &quadVAO, - bool createOutputFBO) : m_device(device), m_createOutputFBO(createOutputFBO) { + const HGBufferVLK &uboBuffer, + const HGBufferVLK &lightDataBuffer, + const HGVertexBufferBindings &quadVAO, + bool createOutputFBO) : m_device(device), m_quadVAO(quadVAO), m_lightDataBuffer(lightDataBuffer), m_createOutputFBO(createOutputFBO) { glowPass = std::make_unique(m_device, uboBuffer, quadVAO); createFrameBuffers(); @@ -25,20 +27,29 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, inputColorTextures, !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); } + + for (auto &pointLightBuff : m_pointLightBuffers) { + pointLightBuff = lightDataBuffer->getSubBuffer(100*sizeof(LocalLight)); + } + } void RenderViewDeferredVLK::createFrameBuffers() { { auto const gBufferFormat = { - ITextureFormat::itRGBA, //Albedo - ITextureFormat::itRGBA, //Specular - ITextureFormat::itRGBA //Normal + ITextureFormat::itRGBA, //Normals + ITextureFormat::itFloat32, //Depth Readable }; auto const forwardBufferFormat = { ITextureFormat::itRGBA //Color }; + auto const lightBufferFormat = { + ITextureFormat::itRGBA //Color + }; + + auto depthFormat = ITextureFormat::itDepth32; bool invertZ = true; @@ -63,6 +74,12 @@ void RenderViewDeferredVLK::createFrameBuffers() { invertZ, false, true, false); + m_lightBufferPass = m_device->getRenderPass(lightBufferFormat, + depthFormat, + sampleCountToVkSampleCountFlagBits(gBufferPassSamples), + invertZ, false, + true, false); + for (auto &gBufferFrameBuffer: m_gBufferFrameBuffers) { gBufferFrameBuffer = std::make_shared( *m_device, @@ -88,6 +105,18 @@ void RenderViewDeferredVLK::createFrameBuffers() { m_height ); } + for (int i = 0; i < m_lightFrameBuffers.size(); i++) { + m_lightFrameBuffers[i] = std::make_shared( + *m_device, + forwardBufferFormat, + depthFormat, + m_gBufferFrameBuffers[i]->getDepthTexture(), + gBufferPassSamples, //m_device->getMaxSamplesCnt(), + invertZ, + m_width, + m_height + ); + } } if (m_createOutputFBO) { auto const dataFormat = {ITextureFormat::itRGBA}; @@ -109,10 +138,36 @@ void RenderViewDeferredVLK::createFrameBuffers() { ); } } +} +static const PipelineTemplate s_lightBufferPipelineT = { + DrawElementMode::TRIANGLES, + false, + true, + EGxBlendEnum::GxBlend_Add, + true, + false, + 0xFF +}; + +void RenderViewDeferredVLK::createLightBufferMats() { + PipelineTemplate pipelineTemplate; + for (int i = 0; i < m_pointLightMats.size(); i++) { + m_pointLightMats[i] = MaterialBuilderVLK::fromShader(m_device, {"pointLight", "pointLight"}, { + .vertexShaderFolder = "bindless/lights/forward", + .fragmentShaderFolder = "bindless/lights/forward", + + }) + .createPipeline(m_quadVAO, m_lightBufferPass, s_lightBufferPipelineT) + + .toMaterial(); + } } -void RenderViewDeferredVLK::update(int width, int height, float glow) { +void RenderViewDeferredVLK::update(int width, int height, float glow, + const std::vector &pointLights, + const std::vector &spotLights + ) { width = std::max(1, width); height = std::max(1, height); @@ -135,9 +190,17 @@ void RenderViewDeferredVLK::update(int width, int height, float glow) { this->executeOnChange(); } + updateLightBuffers(pointLights, spotLights); glowPass->assignFFXGlowUBOConsts(glow); } +void RenderViewDeferredVLK::setLightBuffers(const std::shared_ptr &sceneWideDS) { + auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + + sceneWideDS->beginUpdate() + .texture(1, m_lightFrameBuffers[frameNum]->getAttachment(0)); +} + static inline std::array vec4ToArr3(const mathfu::vec4 &vec) { return {vec[0], vec[1], vec[2]}; } @@ -182,6 +245,19 @@ void RenderViewDeferredVLK::doGBufferBarrier(CmdBufRecorder &frameBufCmd) { } ); } +void RenderViewDeferredVLK::doLightPass(CmdBufRecorder &frameBufCmd) { + auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + + auto renderPass = frameBufCmd.beginRenderPass(false, m_lightBufferPass, + m_lightFrameBuffers[frameNum], + {0,0}, + {m_width, m_height}, + {0,0,0}); + + frameBufCmd.bindVertexBindings(m_quadVAO); + frameBufCmd.bindMaterial(m_pointLightMats[frameNum]); + frameBufCmd.drawIndexed(6, m_lightPointCount, 0, 0, 0); +} RenderPassHelper RenderViewDeferredVLK::beginForwardPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, bool clearDepth, mathfu::vec4 &clearColor) { @@ -236,4 +312,18 @@ RenderViewDeferredVLK::readRGBAPixels(int frameNumber, int x, int y, int width, if (m_createOutputFBO) { m_outputFrameBuffers[frameNumber % IDevice::MAX_FRAMES_IN_FLIGHT]->readRGBAPixels(x,y,width,height,outputdata); } -} \ No newline at end of file +} + +void RenderViewDeferredVLK::updateLightBuffers(const std::vector &pointLights, + const std::vector &spotLights) { + + auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + auto &pointLightBuffer = m_pointLightBuffers[frameNum]; + if (pointLightBuffer->getSize() < pointLights.size()*sizeof(LocalLight)) { + pointLightBuffer = m_lightDataBuffer->getSubBuffer((pointLights.size() + 100) * sizeof(LightResult)); + } + + pointLightBuffer->uploadData(pointLights.data(), pointLights.size()*sizeof(LocalLight)); + + m_lightPointCount = pointLights.size(); +} diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h index f9bd87231..59717dc7b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h @@ -11,10 +11,16 @@ class RenderViewDeferredVLK : public IRenderView { public: - RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); + RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, + const HGBufferVLK &lightDataBuffer, + const HGVertexBufferBindings &quadVAO, bool createOutputFBO); ~RenderViewDeferredVLK() override = default; - void update(int width, int height, float glow); + void update(int width, int height, float glow, + const std::vector &pointLights, + const std::vector &spotLights); + + void setLightBuffers(const std::shared_ptr &sceneWideDS); std::shared_ptr getGBufferPass() {return m_gBufferRenderPass;} std::shared_ptr getForwardPass() {return m_forwardRenderPass;} @@ -23,7 +29,7 @@ class RenderViewDeferredVLK : public IRenderView { RenderPassHelper beginForwardPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, bool clearDepth, mathfu::vec4 &clearColor); void doGBufferBarrier(CmdBufRecorder &frameBufCmd); - + void doLightPass(CmdBufRecorder &frameBufCmd); void doOutputPass(CmdBufRecorder &frameBufCmd); void doPostGlow(CmdBufRecorder &frameBufCmd); @@ -35,22 +41,42 @@ class RenderViewDeferredVLK : public IRenderView { uint32_t m_width = 640; uint32_t m_height = 480; + uint32_t m_lightPointCount; + uint32_t m_spotPointCount; + HGDeviceVLK m_device; + bool m_createOutputFBO; + HGVertexBufferBindings m_quadVAO; + + HGBufferVLK m_lightDataBuffer; + std::shared_ptr m_gBufferRenderPass; std::shared_ptr m_forwardRenderPass; std::shared_ptr m_forwardRenderPassNoDepthClear; + std::shared_ptr m_lightBufferPass; std::shared_ptr m_shadowPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_gBufferFrameBuffers; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_forwardFrameBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_lightFrameBuffers; + + + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightMats; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_spotLightMats; + + std::unique_ptr glowPass; std::shared_ptr m_outputRenderPass; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_outputFrameBuffers; void createFrameBuffers(); + void createLightBufferMats(); std::vector> onUpdates; + + void updateLightBuffers(const std::vector &pointLights, const std::vector &spotLights); }; #endif //AWEBWOWVIEWERCPP_RENDERVIEWDEFERREDVLK_H From 2264b7ada91d62bb5a21f13d7b81891d8aa3a75d Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 2 Apr 2024 18:33:37 +0300 Subject: [PATCH 181/212] - light buffer for point lights work! --- src/ui/FrontendUI.cpp | 5 + .../glsl/bindless/adt/adtShader_text.glsl | 11 +- .../glsl/bindless/deferred_excerpt.glsl | 14 +- .../glsl/bindless/lights/pointLight.frag | 68 +- .../glsl/bindless/lights/pointLight.vert | 17 +- .../glsl/bindless/m2/m2shader_text.glsl | 19 +- .../m2Particle/m2ParticleShader_text.glsl | 2 +- .../waterfall/waterFallShader_text.glsl | 2 +- .../glsl/bindless/wmo/wmoshader_text.glsl | 9 +- .../glsl/common/commonLightFunctions.glsl | 7 +- .../glsl/forwardRendering/m2Shader.frag | 4 +- .../src/engine/managers/animationManager.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 2132 ++++++++++------- .../src/gapi/UniformBufferStructures.h | 3 +- .../src/gapi/vulkan/GFrameBufferVLK.cpp | 2 +- .../src/gapi/vulkan/TextureManagerVLK.cpp | 8 +- .../vulkan/textures/GTextureSamplerVLK.cpp | 10 +- .../gapi/vulkan/textures/GTextureSamplerVLK.h | 2 +- wowViewerLib/src/include/config.h | 2 + .../renderer/mapScene/MapSceneRenderer.cpp | 19 +- .../src/renderer/mapScene/MapSceneRenderer.h | 9 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 32 +- .../vulkan/MapSceneRenderBindlessVLK.h | 2 - .../vulkan/MapSceneRenderForwardVLK.cpp | 11 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 156 +- .../vulkan/view/RenderViewDeferredVLK.h | 7 +- 27 files changed, 1635 insertions(+), 924 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 5f3db8fee..22712c048 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1413,6 +1413,11 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->disableFog = disableFog; } + bool enableLightBuffer = m_api->getConfig()->enableLightBuffer; + if (ImGui::Checkbox("Enable lightBuffer", &enableLightBuffer)) { + m_api->getConfig()->enableLightBuffer = enableLightBuffer; + } + bool renderADT = m_api->getConfig()->renderAdt; if (ImGui::Checkbox("Render ADT", &renderADT)) { m_api->getConfig()->renderAdt = renderADT; diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl index 433d7e289..a89f0bede 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -5,6 +5,7 @@ precision highp int; #include "../../common/commonFogFunctions.glsl" #include "../../common/commonADTMaterial.glsl" +#include "../../../common/commonUboSceneData.glsl" #include "../../common/commonAdtIndirectDescriptorSet.glsl" //ADT is always opaque @@ -96,6 +97,12 @@ void main() { vec4 finalColor = vec4(matDiffuse, 1.0); #ifndef DEFERRED + + vec3 accumLight = vVertexLighting.rgb; + if (scene.uSceneSize_DisableLightBuffer.z == 0.0 ) { + accumLight = texture(lightBuffer, (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy)).xyz; + } + finalColor = vec4( calcLight( matDiffuse, @@ -104,7 +111,7 @@ void main() { 0.0, scene, intLight, - vVertexLighting.rgb, /* accumLight */ + accumLight, /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ vec3(0.0) /* emissive */ @@ -131,6 +138,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - writeGBuffer(matDiffuse.xyz, normalize(vNormal), specTerm.rgb); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), specTerm.rgb, vPosition.xyz); #endif } diff --git a/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl index 5f08475ba..c77caf231 100644 --- a/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl +++ b/wowViewerLib/shaders/glsl/bindless/deferred_excerpt.glsl @@ -5,13 +5,25 @@ //layout(location = 1) out vec4 outSpecular; layout(location = 0) out vec4 outNormal; layout(location = 1) out float outDepth; +//layout(location = 2) out vec4 outVPos; -void writeGBuffer(vec3 albedo, vec3 normal, vec3 specular) { +vec4 pack_depth(const in float depth) +{ + const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0); + const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0); + vec4 res = fract(depth * bit_shift); + res -= res.xxyz * bit_mask; + return res; +} + +void writeGBuffer(vec3 albedo, vec3 normal, vec3 specular, vec3 vPos) { // outAlbedo = vec4(albedo, 0.0); // outNormal = vec4(normal, 0.0); // outSpecular = vec4(specular, 0.0); outNormal = vec4(normal * 0.5 + 0.5, 0.0); outDepth = gl_FragCoord.z; +// outVPos = vec4(vPos, 0.0); +// outDepth = pack_depth(scene.uPMatrix[3].z/(gl_FragCoord.z * -2.0 + 1.0 - scene.uPMatrix[2].z)); } #endif //DEFERRED_EXCERPT \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag index 5dfeaf516..b40068963 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag @@ -1 +1,67 @@ -#include \ No newline at end of file +#version 450 + +#extension GL_GOOGLE_include_directive: require +//#extension GL_EXT_debug_printf : enable + +precision highp float; +precision highp int; + +#include "../../common/commonUboSceneData.glsl" +#include "../../common/commonLightFunctions.glsl" + +layout(location = 0) in flat int lightIndex; + +layout(std430, set=1, binding=0) buffer readonly pointLightBuffer { + LocalLight lights[]; +}; +layout(set=1, binding=1) uniform sampler2D depthTex; +layout(set=1, binding=2) uniform sampler2D normalTex; +layout(std140, set=1, binding=3) uniform pointLightBuffer { + vec4 screenSize; +}; + +layout(location = 0) out vec4 outColor; + + +float unpack_depth(const in vec4 rgba_depth) +{ + const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); + float depth = dot(rgba_depth, bit_shift); + return depth; +} + +void main() { + LocalLight lightRec = lights[lightIndex]; + + vec2 uv = gl_FragCoord.xy / screenSize.xy; + + vec3 normal = texture(normalTex, uv).rgb * 2.0 - vec3(1.0); + float depth = texture(depthTex, uv).r; + + float z = (depth - 0.06f) / (1.0f - 0.06f) ; + + vec4 viewPos = inverse(scene.uPMatrix) * vec4(uv.xy * 2.0 - 1.0, z, 1.0); + viewPos.xyz = viewPos.xyz / viewPos.w; + + vec4 worldPos = inverse(scene.uLookAtMat) * vec4(viewPos.xyz, 1.0); + worldPos.xyz = worldPos.xyz / worldPos.w; + + + // debugPrintfEXT("My worldPos is %f %f %f", worldPos.x, worldPos.y, worldPos.z); + + //Calc color + vec3 lightViewPos = (scene.uLookAtMat * vec4(lightRec.position.xyz, 1.0)).xyz; + vec3 vectorToLight = (lightViewPos.xyz - viewPos.xyz); + float distanceToLightSqr = dot(vectorToLight, vectorToLight); + float distanceToLightInv = inversesqrt(distanceToLightSqr); + float distanceToLight = (distanceToLightSqr * distanceToLightInv); + float diffuseTerm1 = max((dot(vectorToLight, normal) * distanceToLightInv), 0.0); + vec4 attenuationRec = lightRec.attenuation; + + float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); + + vec3 attenuatedColor = attenuation * lightRec.innerColor.xyz; + vec3 lightColor = vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ); + + outColor = vec4(vec3(lightColor), 1.0); +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert index 19097c92f..5e2ed8d64 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert @@ -1,3 +1,11 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +#extension GL_ARB_shader_draw_parameters: require + +precision highp float; +precision highp int; + #include "../../common/commonUboSceneData.glsl" layout (location = 0) in vec2 position; @@ -6,6 +14,8 @@ layout(std430, set=1, binding=0) buffer readonly pointLightBuffer { LocalLight lights[]; }; +layout(location = 0) out flat int lightIndex; + void main() { LocalLight lightRec = lights[gl_InstanceIndex]; @@ -19,8 +29,13 @@ void main() { vec2 quadPosView = (position.xy * attentuationEnd); lightPosView.xy += quadPosView; + //Bring the projection on sphere to the front + lightPosView.z = min(-0.001, lightPosView.z + attentuationEnd); + + //Now it's safe to multiply it by perspective matrix - gl_Position = scene.uPMatrix * (lightPosView.xyz, 1.0); + gl_Position = scene.uPMatrix * vec4(lightPosView.xyz, 1.0); + lightIndex = gl_InstanceIndex; } diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl index 37938bd84..1680a7013 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -14,16 +14,15 @@ layout(location=2) in vec3 vNormal; layout(location=3) in vec4 vPosition_EdgeFade; layout(location=4) in flat int vMeshIndex; +#include "../../common/commonUboSceneData.glsl" + #ifndef DEFERRED layout(location = 0) out vec4 outColor; #else #include "../deferred_excerpt.glsl" #endif - - #include "../../common/commonUboSceneData.glsl" - //Whole model #include "../../common/commonM2IndirectDescriptorSet.glsl" @@ -82,11 +81,6 @@ void main() { vec3 meshResColor = vMeshColorAlpha.rgb; - vec3 accumLight = vec3(0.0); - - //Query light buffer - - //---------------------- // Calc Diffuse and Specular //--------------------- @@ -141,6 +135,11 @@ void main() { specular *= vMeshColorAlpha.rgb; #ifndef DEFERRED + vec3 accumLight = vec3(0.0); + if (scene.uSceneSize_DisableLightBuffer.z == 0.0 && blendMode <= 1) { + accumLight = texture(lightBuffer, (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy)).xyz; + } + finalColor = vec4( calcLight( matDiffuse, @@ -168,7 +167,7 @@ void main() { if (uUnFogged == 0) { vec3 sunDir = mix( - scene.uInteriorSunDir_lightBufferIndex, + scene.uInteriorSunDir, scene.extLight.uExteriorDirectColorDir, modelWide.interiorExteriorBlend.x ).xyz; @@ -184,6 +183,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - writeGBuffer(matDiffuse.xyz, normalize(vNormal), specular.rgb); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), specular.rgb, vPosition_EdgeFade.xyz); #endif } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl index 9b08d9062..870e0a554 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2Particle/m2ParticleShader_text.glsl @@ -113,6 +113,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - writeGBuffer(matDiffuse.xyz, vec3(0.0, 0.0, 1.0), vec3(0.0)); + writeGBuffer(matDiffuse.xyz, vec3(0.0, 0.0, 1.0), vec3(0.0), vPosition.xyz); #endif } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl index 980b6b303..44c32f290 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl @@ -115,6 +115,6 @@ void main() { #ifndef DEFERRED outColor = finalColor; #else - writeGBuffer(whiteWater_val_baseColor_mix.rgb, perturbedNormal.rgb, vec3(0.0)); + writeGBuffer(whiteWater_val_baseColor_mix.rgb, perturbedNormal.rgb, vec3(0.0), vPosition.xyz); #endif } diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index 446ca3cfd..9c7c6be1e 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -78,6 +78,11 @@ void main() { vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); #ifndef DEFERRED + vec3 accumLight = vec3(0.0); + if (scene.uSceneSize_DisableLightBuffer.z == 0.0 && wmoMeshWide.UseLitColor_EnableAlpha_PixelShader_BlendMode.w <= 1) { + accumLight = texture(lightBuffer, (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy)).xyz; + } + finalColor = vec4( calcLight( matDiffuse, @@ -86,7 +91,7 @@ void main() { vColor.w, scene, intLight, - vec3(0.0) /*accumLight*/, + accumLight /*accumLight*/, vColor.rgb, spec, /* specular */ emissive @@ -105,6 +110,6 @@ finalColor.a = 1.0; #ifndef DEFERRED outColor = finalColor; #else - writeGBuffer(matDiffuse.xyz, normalize(vNormal), spec.rgb); + writeGBuffer(matDiffuse.xyz, normalize(vNormal), spec.rgb, vPosition.xyz); #endif } \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index e158d9fde..71312fea9 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -34,7 +34,8 @@ struct SceneWideParams { mat4 uLookAtMat; mat4 uPMatrix; vec4 uViewUpSceneTime; - vec4 uInteriorSunDir_lightBufferIndex; + vec4 uInteriorSunDir; + vec4 uSceneSize_DisableLightBuffer; vec4 closeRiverColor; vec4 farRiverColor; @@ -59,7 +60,7 @@ vec3 Slerp(vec3 p0, vec3 p1, float t) return p1; } float theta = acos(dotp); - vec3 P = ((p0*sin((1-t)*theta) + p1*sin(t*theta)) / sin(theta)); + vec3 P = ((p0*sin((1.0-t)*theta) + p1*sin(t*theta)) / sin(theta)); return P; } @@ -105,7 +106,7 @@ vec3 calcLight( currColor = mix(groundColor, skyColor, (0.5f + vec3(0.5f * nDotL))); } if (intLight.uInteriorAmbientColorAndApplyInteriorLight.w > 0) { - float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir_lightBufferIndex.xyz)), 0.0, 1.0); + float nDotL = clamp(dot(normalizedN, -(sceneParams.uInteriorSunDir.xyz)), 0.0, 1.0); vec3 lDiffuseInterior = intLight.uInteriorDirectColorAndApplyExteriorLight.xyz * nDotL; vec3 interiorAmbient = intLight.uInteriorAmbientColorAndApplyInteriorLight.xyz + precomputedLight; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 09fa3b6eb..075ff2922 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -83,7 +83,7 @@ void main() { float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); - vec3 attenuatedColor = attenuation * lightRecord.color.xyz; + vec3 attenuatedColor = attenuation * lightRecord.innerColor.xyz; lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 )); } @@ -164,7 +164,7 @@ void main() { if (uUnFogged == 0) { vec3 sunDir = mix( - scene.uInteriorSunDir_lightBufferIndex, + scene.uInteriorSunDir, scene.extLight.uExteriorDirectColorDir, interiorExteriorBlend.x ) diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index 3dd361228..7347b8182 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -1101,7 +1101,7 @@ void AnimationManager::calcLights(std::vector &lights, const std: defaultFloat ); - static unsigned char defaultChar = 0; + static unsigned char defaultChar = 1; unsigned char visibility = animateTrackWithBlend( animationInfo, diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 83065f9ad..f91436a4b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1286,9 +1286,9 @@ void Map::checkADTCulling(int i, int j, //Add lights from WDTLightObject if (m_wdtLightObject) { auto pointLightsOfAdt = m_wdtLightObject->getPointLights(i, j); - auto pointLights = mapRenderPlan->pointLights; + auto &pointLights = mapRenderPlan->pointLights; pointLights.reserve(pointLights.size() + pointLightsOfAdt.size()); - for (auto pointLight : pointLightsOfAdt) pointLights.push_back(pointLight.getLightRec()); + for (auto &pointLight : pointLightsOfAdt) pointLights.push_back(pointLight.getLightRec()); } } } else if (!m_lockedMap && true) { //(m_wdtfile->mapTileTable->mainInfo[j][i].Flag_HasADT > 0) { diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 6738ee241..d8abbd223 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -79,12 +79,30 @@ struct drawQuad { }; }; +struct renderFrameBufferShader { + enum class Attribute { + a_position = 0, renderFrameBufferShaderAttributeEnd + }; +}; + +struct drawPortalShader { + enum class Attribute { + aPosition = 0, drawPortalShaderAttributeEnd + }; +}; + struct adtShader { enum class Attribute { aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; +struct pointLight { + enum class Attribute { + position = 0, pointLightAttributeEnd + }; +}; + struct skyConus { enum class Attribute { aPosition = 0, skyConusAttributeEnd @@ -151,18 +169,6 @@ struct adtLodShader { }; }; -struct renderFrameBufferShader { - enum class Attribute { - a_position = 0, renderFrameBufferShaderAttributeEnd - }; -}; - -struct drawPortalShader { - enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd - }; -}; - struct drawFrustumShader { enum class Attribute { aPosition = 0, drawFrustumShaderAttributeEnd @@ -183,6 +189,16 @@ const std::unordered_map> attributesPe { "position", 0}, } }, +{ "renderFrameBufferShader", + { + { "a_position", 0}, + } +}, +{ "drawPortalShader", + { + { "aPosition", 0}, + } +}, { "adtShader", { { "aPos", 0}, @@ -191,6 +207,11 @@ const std::unordered_map> attributesPe { "aNormal", 3}, } }, +{ "pointLight", + { + { "position", 0}, + } +}, { "skyConus", { { "aPosition", 0}, @@ -276,16 +297,6 @@ const std::unordered_map> attributesPe { "aIndex", 1}, } }, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, { "drawFrustumShader", { { "aPosition", 0}, @@ -304,7 +315,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Vertex, { {1,0,64}, - {0,0,544}, + {0,0,560}, {1,1,16}, }, { @@ -322,10 +333,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -342,7 +355,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,2,32}, - {0,0,544}, + {0,0,560}, }, { { @@ -368,10 +381,12 @@ const std::unordered_map shaderMetaInfo = { {2,6, "uTexture7"}, {2,7, "uTexture8"}, {2,8, "uTexture9"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,8,9}, {0,0,0}, @@ -390,8 +405,11 @@ const std::unordered_map shaderMetaInfo = { {2,0,112}, {1,5,4096}, {1,2,16384}, - {0,0,544}, + {0,0,560}, {1,0,64}, + {1,1,384}, + {1,3,4096}, + {1,4,256}, }, { { @@ -409,10 +427,12 @@ const std::unordered_map shaderMetaInfo = { }, { {3,3, "uBumpTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {3,3,1}, @@ -424,120 +444,34 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtShader.frag.spv", +{ "./forwardRendering/waterShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, - {1,1,48}, + {0,0,560}, {1,0,64}, }, { { {0,0,1}, - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, - }, - { - { - {0,0,0}, - {0,0,0}, - {0,8,9}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/deferred/m2Shader.frag.spv", - { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,5,0}, - {1,6,0}, - }, - { - {2,0, "s_Textures"}, - }, - { - { - {0,0,0}, - {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawDepthShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,2,12}, - }, - { - { - {2,2,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, {0,0,0}, } }, { }, { - {0,3, "diffuse"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {3,3,1}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -549,14 +483,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ffxgauss4.frag.spv", +{ "./forwardRendering/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,1,32}, + {1,1,48}, + {0,0,560}, }, { { + {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -564,16 +500,18 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } }, { }, { - {1,0, "texture0"}, + {2,0, "uTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -581,7 +519,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,0}, } } } @@ -628,13 +565,18 @@ const std::unordered_map shaderMetaInfo = { { {1,2,16384}, {1,0,64}, - {0,0,544}, + {0,0,560}, + {1,1,384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -645,10 +587,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -664,7 +608,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, + {0,0,560}, }, { { @@ -683,13 +627,17 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -705,7 +653,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -722,10 +670,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -741,10 +691,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -755,14 +706,23 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -776,7 +736,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -793,12 +753,15 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -814,10 +777,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -831,13 +795,18 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,4,0}, {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -889,7 +858,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -908,12 +877,16 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -929,7 +902,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, + {0,0,560}, }, { { @@ -946,13 +919,24 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -968,10 +952,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -984,13 +969,24 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -1006,7 +1002,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -1023,10 +1019,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1043,7 +1041,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,1,16}, - {0,0,544}, + {0,0,560}, }, { { @@ -1062,10 +1060,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1081,10 +1081,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1095,16 +1096,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1116,7 +1125,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -1133,10 +1142,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1152,7 +1163,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,544}, + {0,0,560}, }, { { @@ -1171,13 +1182,17 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1189,11 +1204,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader.vert.spv", +{ "./bindless/m2/deferred/m2Shader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,0,560}, }, { { @@ -1209,17 +1224,25 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, + {1,8,0}, {1,7,0}, - {1,3,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, {1,1,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1229,17 +1252,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterShader.frag.spv", +{ "./forwardRendering/adtShader.frag.spv", { ShaderStage::Fragment, { + {0,0,560}, {1,1,48}, - {0,0,544}, + {1,0,64}, }, { { {0,0,1}, - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1251,13 +1275,23 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, + {2,0, "uLayer0"}, + {2,1, "uLayer1"}, + {2,2, "uLayer2"}, + {2,3, "uLayer3"}, + {2,5, "uLayerHeight0"}, + {2,6, "uLayerHeight1"}, + {2,7, "uLayerHeight2"}, + {2,8, "uLayerHeight3"}, + {2,4, "uAlphaTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,1}, + {0,8,9}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1267,15 +1301,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/forward/waterfallShader.vert.spv", +{ "./forwardRendering/drawDepthShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {0,2,12}, }, { { - {0,0,1}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1286,22 +1320,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, }, { - {3,0, "s_Textures"}, + {0,3, "diffuse"}, }, { { + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1310,15 +1338,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", +{ "./forwardRendering/ffxgauss4.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,32}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1329,20 +1357,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, }, { - {2,0, "s_Textures"}, + {1,0, "texture0"}, }, { { - {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1350,18 +1370,20 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", +{ "./bindless/m2/forward/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1373,19 +1395,24 @@ const std::unordered_map shaderMetaInfo = { }, { {1,9,0}, - {1,8,0}, {1,7,0}, + {1,3,0}, + {1,1,0}, + {1,2,0}, + {1,4,0}, {1,5,0}, {1,6,0}, + {1,8,0}, }, { - {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1395,18 +1422,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterfallShader.frag.spv", +{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {2,0,112}, - {0,0,544}, + {0,0,560}, }, { { {0,0,1}, {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1417,17 +1443,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1436,11 +1460,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/visbuffer/adtShader.frag.spv", +{ "./forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,0,84}, }, { { @@ -1455,22 +1479,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { + {4,5,2}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1478,11 +1498,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/visbuffer/adtShader.vert.spv", +{ "./bindless/waterfall/forward/waterfallShader.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -1497,17 +1517,29 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {1,7,0}, + {2,0,0}, + {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { + {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1516,17 +1548,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtShader.vert.spv", +{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, - {0,0,544}, + {0,0,560}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1536,14 +1567,26 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1553,17 +1596,24 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPortalShader.frag.spv", +{ "./forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {1,0,16}, + {2,0,112}, + {0,0,560}, + {1,0,64}, + {1,1,384}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { - {0,0,0}, {0,0,1}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1574,13 +1624,19 @@ const std::unordered_map shaderMetaInfo = { { }, { + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1589,14 +1645,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShaderDepth.frag.spv", +{ "./bindless/adt/visbuffer/adtShader.frag.spv", { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1607,17 +1664,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { - {1,0, "Texture"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1625,11 +1689,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtLodShader.frag.spv", +{ "./bindless/adt/visbuffer/adtShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,84}, + {0,0,560}, }, { { @@ -1644,12 +1708,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1661,16 +1730,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", +{ "./bindless/lights/pointLight.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, + {1,3,16}, + {0,0,560}, }, { { {0,0,1}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1680,13 +1750,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,0}, }, { + {1,2, "normalTex"}, + {1,1, "depthTex"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, - {0,0,0}, + {1,2,2}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1697,16 +1772,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/skyConus.vert.spv", +{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,96}, + {0,0,560}, }, { { - {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1714,17 +1787,30 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, }, { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1770,16 +1856,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.frag.spv", +{ "./forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1789,17 +1876,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, }, { - {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1809,11 +1895,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.vert.spv", +{ "./bindless/lights/pointLight.vert.spv", { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -1828,14 +1914,15 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,1,0}, + {1,0,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1847,18 +1934,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ribbonShader.frag.spv", +{ "./bindless/m2/forward/m2Shader.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, - {0,0,544}, + {0,0,560}, }, { { {0,0,1}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1868,13 +1953,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, }, { - {2,0, "uTexture"}, + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1886,15 +1982,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/renderFrameBufferShader.vert.spv", +{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,0,32}, + {0,0,560}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1906,12 +2004,17 @@ const std::unordered_map shaderMetaInfo = { { }, { + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1921,15 +2024,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/forward/adtShader.frag.spv", +{ "./forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,1,16}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1940,22 +2043,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { + {0,0,0}, + {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1963,11 +2062,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader.frag.spv", +{ "./bindless/water/waterShader.frag.spv", { ShaderStage::Fragment, { - {0,0,544}, + {0,0,560}, }, { { @@ -1982,21 +2081,61 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, + {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + }, + { + { + {1,2,2}, + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./bindless/water/waterShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,560}, }, { { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + {1,2,0}, + {1,1,0}, + {1,0,0}, + }, + { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + {2,0, "s_Textures"}, + }, + { + { + {1,2,2}, + {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -2007,16 +2146,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", +{ "./forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,0,32}, + {1,1,16}, + {1,0,4096}, + {0,0,560}, }, { { - {0,0,0}, {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2029,14 +2170,14 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,2,3}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2046,15 +2187,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ffxglow.frag.spv", +{ "./forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,16}, }, { { - {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2067,13 +2207,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, }, { { {0,0,0}, - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2084,15 +2222,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.frag.spv", +{ "./bindless/adt/forward/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,0,560}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2103,15 +2241,62 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, + }, + { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { + { + {1,2,2}, + {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/adtShader.vert.spv", + { + ShaderStage::Vertex, + { + {1,0,64}, + {0,0,560}, }, { { + {0,0,1}, + {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + } + }, + { + }, + { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + }, + { + { + {1,2,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2120,17 +2305,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.vert.spv", +{ "./forwardRendering/drawPortalShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,1,112}, - {0,0,544}, + {1,0,16}, }, { { - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2157,16 +2341,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPoints.vert.spv", +{ "./forwardRendering/imguiShaderDepth.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, }, { { - {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2179,11 +2361,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2194,14 +2377,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.frag.spv", +{ "./forwardRendering/drawBBShader.frag.spv", { ShaderStage::Fragment, { + {0,1,112}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2229,15 +2413,55 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.vert.spv", +{ "./forwardRendering/drawBBShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,1,112}, + {0,0,560}, + }, + { + { + {0,1,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + }, + { + { + {1,2,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/drawPoints.vert.spv", { ShaderStage::Vertex, { {0,0,128}, + {0,1,64}, }, { { - {0,0,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2265,9 +2489,26 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawLinesShader.frag.spv", +{ "./forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, + { + {0,2,12}, + }, + { + { + {2,2,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, { }, { @@ -2281,6 +2522,26 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, } + } + } +}, +{ "./forwardRendering/drawFrustumShader.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,128}, + }, + { + { + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } }, { }, @@ -2300,14 +2561,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader_opaque.frag.spv", +{ "./forwardRendering/drawLinesShader.frag.spv", { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2320,12 +2582,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2336,17 +2597,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterShader.vert.spv", +{ "./forwardRendering/imguiShader_opaque.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,544}, - {1,0,64}, }, { { - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2358,11 +2617,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2413,7 +2673,7 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Vertex, { - {0,0,544}, + {0,0,560}, }, { { @@ -2430,10 +2690,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2450,7 +2712,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, - {0,0,544}, + {0,0,560}, }, { { @@ -2470,10 +2732,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -2490,7 +2754,7 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, - {0,0,544}, + {0,0,560}, }, { { @@ -2510,10 +2774,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -2654,10 +2920,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2676,10 +2943,11 @@ const std::unordered_map shaderMetaInfo = { {2,0,64}, {1,4,256}, {1,3,4096}, - {1,1,256}, - {0,0,544}, + {1,1,384}, + {0,0,560}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -2700,10 +2968,12 @@ const std::unordered_map shaderMetaInfo = { {3,1, "uTexture2"}, {3,2, "uTexture3"}, {3,3, "uTexture4"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,3,4}, @@ -2725,7 +2995,48 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"imguiShader_opaque", { - }}, {"imguiShaderDepth", { }}, {"ffxglow", { @@ -3172,6 +3519,11 @@ const std::unordered_map s_sampler = nullptr; inline void GFrameBufferVLK::initSampler(GDeviceVLK &device) { if (s_sampler == nullptr) - s_sampler = std::make_shared(device, false, false); + s_sampler = std::make_shared(device, false, false, true); } inline void GFrameBufferVLK::initSamplableTextures() { m_attachmentTexturesSampled.resize(m_attachmentTextures.size()); diff --git a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp index ccb867e64..e43626d65 100644 --- a/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/TextureManagerVLK.cpp @@ -13,10 +13,10 @@ TextureManagerVLK::TextureManagerVLK(IDeviceVulkan &device) : mdevice(device) { void TextureManagerVLK::initialize() { createUpdateCallback(); - m_textureSamplers[0] = std::make_shared(mdevice, false, false); - m_textureSamplers[1] = std::make_shared(mdevice, false, true); - m_textureSamplers[2] = std::make_shared(mdevice, true, false); - m_textureSamplers[3] = std::make_shared(mdevice, true, true); + m_textureSamplers[0] = std::make_shared(mdevice, false, false, false); + m_textureSamplers[1] = std::make_shared(mdevice, false, true, false); + m_textureSamplers[2] = std::make_shared(mdevice, true, false, false); + m_textureSamplers[3] = std::make_shared(mdevice, true, true, false); } HGSamplableTexture TextureManagerVLK::createBlpTexture(HBlpTexture &texture, bool wrapX, bool wrapY) { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp index adae1ac42..5eaee517b 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.cpp @@ -6,16 +6,16 @@ #include "GTextureSamplerVLK.h" #include "../../interface/IDevice.h" -GTextureSamplerVLK::GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex) : m_device(deviceVlk) { +GTextureSamplerVLK::GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex, bool nearest) : m_device(deviceVlk) { // Create a texture sampler // In Vulkan textures are accessed by samplers // This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings // Note: Similar to the samplers available with OpenGL 3.3 VkSamplerCreateInfo sampler = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - sampler.magFilter = VK_FILTER_LINEAR; - sampler.minFilter = VK_FILTER_LINEAR; - sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler.magFilter = nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + sampler.minFilter = nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + sampler.mipmapMode = nearest ? VK_SAMPLER_MIPMAP_MODE_NEAREST : VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = xWrapTex ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = yWrapTex ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; @@ -26,7 +26,7 @@ GTextureSamplerVLK::GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, sampler.maxLod = 64.0f;//vulkanMipMapCount; // Enable anisotropic filtering // This feature is optional, so we must check if it's supported on the device - if (deviceVlk.getIsAnisFiltrationSupported()) { + if (deviceVlk.getIsAnisFiltrationSupported() && !nearest) { // Use max. level of anisotropy for this example sampler.maxAnisotropy = std::min(deviceVlk.getAnisLevel(), 16.0); sampler.anisotropyEnable = VK_TRUE; diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h index 08bfc3575..f1c76a331 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureSamplerVLK.h @@ -12,7 +12,7 @@ class GTextureSamplerVLK : public ITextureSampler { public: - GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex); + GTextureSamplerVLK(IDeviceVulkan &deviceVlk, bool xWrapTex, bool yWrapTex, bool nearest); ~GTextureSamplerVLK() override; VkSampler getSampler() { diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 0658a70e5..fccbea120 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -67,6 +67,8 @@ class Config { bool BCLightHack = false; + bool enableLightBuffer = false; + bool drawDepthBuffer = false; int cameraM2 = -1; // this will be sceneNumber of object diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index b085e3dab..a58156e8e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -129,10 +129,9 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende } void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, - const std::vector &renderingMatricess, + const std::vector &renderingMatricesAndSizes, const HFrameDependantData &fdd, bool isVulkan, - int lightBufferIndex, animTime_t sceneTime ) { ZoneScoped; @@ -144,8 +143,9 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrgetObject(i); blockPSVS.uLookAtMat = renderingMatrices->lookAtMat; @@ -154,9 +154,16 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrperspectiveMat; } - blockPSVS.uInteriorSunDir_lightBufferIndex = mathfu::vec4_packed( - mathfu::vec4(renderingMatrices->interiorDirectLightDir.xyz(), lightBufferIndex) + blockPSVS.uInteriorSunDir = mathfu::vec4_packed( + mathfu::vec4(renderingMatrices->interiorDirectLightDir.xyz(), 0) ); + blockPSVS.uSceneSize_DisableLightBuffer = mathfu::vec4_packed(mathfu::vec4( + (float)matAndSceneSize.width, + (float)matAndSceneSize.height, + !m_config->enableLightBuffer ? 1.0 : 0.0, + 0.0 + )); + blockPSVS.uViewUpSceneTime = mathfu::vec4(renderingMatrices->viewUp.xyz(), sceneTime); blockPSVS.closeOceanColor = fdd->closeOceanColor; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index f5104d0e4..1d0ac715f 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -94,6 +94,12 @@ struct MeshCount { int adtMesh = 0; }; +struct RenderingMatAndSceneSize { + HCameraMatrices renderingMat; + int width; + int height; +}; + class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public IRendererParameters { public: MapSceneRenderer(Config *config) : m_config(config) {}; @@ -108,10 +114,9 @@ class MapSceneRenderer : public IRenderer, public IMapSceneBufferCreate, public const std::shared_ptr> &hSkyTransparentMeshes); void updateSceneWideChunk(const std::shared_ptr> &sceneWideChunk, - const std::vector &renderingMatrices, + const std::vector &renderingMatricesAndSizes, const HFrameDependantData &fdd, bool isVulkan, - int lightBufferIndex, animTime_t sceneTime); virtual std::shared_ptr createRenderView(bool createOutput) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 38f726545..84d1d5c5b 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -218,17 +218,6 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m_emptyWaterVAO = createWaterVAO(vboWaterBuffer, iboBuffer); m_emptyPortalVAO = createPortalVAO(nullptr, nullptr); - //Framebuffers for rendering - auto const dataFormat = { ITextureFormat::itRGBA}; - - defaultView = std::make_shared(m_device, uboBuffer, pointLightBuffer, m_drawQuadVao, false); - - m_forwardRenderPass = defaultView->getForwardPass(); - m_gBufferPass = defaultView->getGBufferPass(); - - - glowPass = std::make_unique(hDevice, uboBuffer, m_drawQuadVao); - { //Create SceneWide descriptor sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); @@ -243,6 +232,13 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, }); } + defaultView = std::make_shared(m_device, uboBuffer, + pointLightBuffer, sceneWideDS, + m_drawQuadVao, false); + + m_forwardRenderPass = defaultView->getForwardPass(); + m_gBufferPass = defaultView->getGBufferPass(); + createM2GlobalMaterialData(); createWMOGlobalMaterialData(); createADTGlobalMaterialData(); @@ -907,6 +903,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMateri auto skyColors = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptySkyVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -1225,16 +1222,18 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh mapScene->update(framePlan); mapScene->updateBuffers(l_this, framePlan); - std::vector renderingMatricess; + std::vector renderingMatricessAndSizes; for (auto &rt : frameInputParams->frameParameters->renderTargets) { - renderingMatricess.push_back(rt.cameraMatricesForRendering); + auto &matAndSceneSize = renderingMatricessAndSizes.emplace_back(); + matAndSceneSize.renderingMat = rt.cameraMatricesForRendering; + matAndSceneSize.width = rt.viewPortDimensions.maxs[0]; + matAndSceneSize.height = rt.viewPortDimensions.maxs[1]; } updateSceneWideChunk(sceneWideChunk, - renderingMatricess, + renderingMatricessAndSizes, framePlan->frameDependentData, true, - -1, mapScene->getCurrentSceneTime()); @@ -1548,5 +1547,6 @@ HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTem } std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { - return std::make_shared(m_device, uboBuffer, pointLightBuffer, m_drawQuadVao, createOutput); + return std::make_shared(m_device, uboBuffer, pointLightBuffer, sceneWideDS, + m_drawQuadVao, createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 82862f237..065e8c3b0 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -140,8 +140,6 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { int m_width = 640; int m_height = 480; - std::unique_ptr glowPass; - HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; HGBufferVLK vboM2RibbonBuffer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 35ca03059..793289322 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -644,16 +644,19 @@ std::unique_ptr MapSceneRenderForwardVLK::update(const std::sha // } // ); - std::vector renderingMatricess; + std::vector renderingMatricessAndSizes; for (auto &rt : frameInputParams->frameParameters->renderTargets) { - renderingMatricess.push_back(rt.cameraMatricesForRendering); + auto &matAndSceneSize = renderingMatricessAndSizes.emplace_back(); + matAndSceneSize.renderingMat = rt.cameraMatricesForRendering; + matAndSceneSize.width = rt.viewPortDimensions.maxs[0]; + matAndSceneSize.height = rt.viewPortDimensions.maxs[1]; } + updateSceneWideChunk(sceneWideChunk, - renderingMatricess, + renderingMatricessAndSizes, framePlan->frameDependentData, true, - -1, mapScene->getCurrentSceneTime()); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 9b746fb82..8467757e2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -4,6 +4,7 @@ #include "RenderViewDeferredVLK.h" #include "../../../../gapi/vulkan/materials/MaterialBuilderVLK.h" +#include "../../../../gapi/vulkan/buffers/CBufferChunkVLK.h" /* * RenderViewDeferredVLK @@ -12,10 +13,18 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGBufferVLK &lightDataBuffer, + const std::shared_ptr &sceneWideDS, const HGVertexBufferBindings &quadVAO, - bool createOutputFBO) : m_device(device), m_quadVAO(quadVAO), m_lightDataBuffer(lightDataBuffer), m_createOutputFBO(createOutputFBO) { + bool createOutputFBO) : m_device(device), + m_quadVAO(quadVAO), m_lightDataBuffer(lightDataBuffer), + m_sceneWideDS(sceneWideDS), + m_createOutputFBO(createOutputFBO) { glowPass = std::make_unique(m_device, uboBuffer, quadVAO); + for (auto &pointLightBuff : m_pointLightBuffers) { + pointLightBuff = lightDataBuffer->getSubBuffer(100*sizeof(LocalLight)); + } + createFrameBuffers(); { std::vector> inputColorTextures; @@ -28,17 +37,14 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, !this->m_createOutputFBO ? m_device->getSwapChainRenderPass() : this->m_outputRenderPass); } - for (auto &pointLightBuff : m_pointLightBuffers) { - pointLightBuff = lightDataBuffer->getSubBuffer(100*sizeof(LocalLight)); - } - + m_lightScreenSize = std::make_shared>(uboBuffer); } void RenderViewDeferredVLK::createFrameBuffers() { { auto const gBufferFormat = { ITextureFormat::itRGBA, //Normals - ITextureFormat::itFloat32, //Depth Readable + ITextureFormat::itFloat32, //Depth packed Readable }; auto const forwardBufferFormat = { @@ -46,7 +52,7 @@ void RenderViewDeferredVLK::createFrameBuffers() { }; auto const lightBufferFormat = { - ITextureFormat::itRGBA //Color + ITextureFormat::itRGBAFloat32 //Color }; @@ -108,7 +114,7 @@ void RenderViewDeferredVLK::createFrameBuffers() { for (int i = 0; i < m_lightFrameBuffers.size(); i++) { m_lightFrameBuffers[i] = std::make_shared( *m_device, - forwardBufferFormat, + lightBufferFormat, depthFormat, m_gBufferFrameBuffers[i]->getDepthTexture(), gBufferPassSamples, //m_device->getMaxSamplesCnt(), @@ -151,17 +157,31 @@ static const PipelineTemplate s_lightBufferPipelineT = { }; void RenderViewDeferredVLK::createLightBufferMats() { - PipelineTemplate pipelineTemplate; for (int i = 0; i < m_pointLightMats.size(); i++) { m_pointLightMats[i] = MaterialBuilderVLK::fromShader(m_device, {"pointLight", "pointLight"}, { - .vertexShaderFolder = "bindless/lights/forward", - .fragmentShaderFolder = "bindless/lights/forward", - + .vertexShaderFolder = "bindless/lights", + .fragmentShaderFolder = "bindless/lights", + .typeOverrides = { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, + }} + } }) + .overridePipelineLayout({{0, m_sceneWideDS}}) .createPipeline(m_quadVAO, m_lightBufferPass, s_lightBufferPipelineT) - + .bindDescriptorSet(0, m_sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, m_pointLightBuffers[i]) + .texture(1, m_gBufferFrameBuffers[i]->getAttachment(1)) + .texture(2, m_gBufferFrameBuffers[i]->getAttachment(0)) + .ubo(3, BufferChunkHelperVLK::cast(m_lightScreenSize)) + .delayUpdate(); + }) .toMaterial(); } + + m_lightMatsCreated = true; } void RenderViewDeferredVLK::update(int width, int height, float glow, @@ -175,7 +195,16 @@ void RenderViewDeferredVLK::update(int width, int height, float glow, m_width = std::max(1, width); m_height = std::max(1, height); + { + auto &screensize = m_lightScreenSize->getObject(); + screensize = {m_width, m_height, 0, 0}; + m_lightScreenSize->save(); + } + this->createFrameBuffers(); + this->createLightBufferMats(); + + { std::vector> inputColorTextures; @@ -190,6 +219,10 @@ void RenderViewDeferredVLK::update(int width, int height, float glow, this->executeOnChange(); } + if (!m_lightMatsCreated) { + this->createLightBufferMats(); + } + updateLightBuffers(pointLights, spotLights); glowPass->assignFFXGlowUBOConsts(glow); } @@ -218,34 +251,65 @@ RenderPassHelper RenderViewDeferredVLK::beginGBufferPass(CmdBufRecorder &frameBu void RenderViewDeferredVLK::doGBufferBarrier(CmdBufRecorder &frameBufCmd) { auto const &fb = m_gBufferFrameBuffers[m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT]; - VkImageSubresourceRange subresourceRange = {}; - // Image only contains color data - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // Start at first mip level - subresourceRange.baseMipLevel = 0; - // We will transition on all mip levels - subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - // The 2D texture only has one layer - subresourceRange.layerCount = 1; - - VkImageMemoryBarrier imgBarrier{}; - imgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imgBarrier.subresourceRange = subresourceRange; - imgBarrier.image = std::dynamic_pointer_cast(fb->getAttachment(0)->getTexture())->texture.image; - imgBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - - frameBufCmd.recordPipelineImageBarrier( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - { - imgBarrier - } - ); + { + VkImageSubresourceRange subresourceRange = {}; + // Image only contains color data + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // Start at first mip level + subresourceRange.baseMipLevel = 0; + // We will transition on all mip levels + subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + // The 2D texture only has one layer + subresourceRange.layerCount = 1; + + VkImageMemoryBarrier imgBarrier{}; + imgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imgBarrier.subresourceRange = subresourceRange; + imgBarrier.image = std::dynamic_pointer_cast(fb->getAttachment(0)->getTexture())->texture.image; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + + frameBufCmd.recordPipelineImageBarrier( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + { + imgBarrier + } + ); + } + { + VkImageSubresourceRange subresourceRange = {}; + // Image only contains color data + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // Start at first mip level + subresourceRange.baseMipLevel = 0; + // We will transition on all mip levels + subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + // The 2D texture only has one layer + subresourceRange.layerCount = 1; + + VkImageMemoryBarrier imgBarrier{}; + imgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imgBarrier.subresourceRange = subresourceRange; + imgBarrier.image = std::dynamic_pointer_cast(fb->getAttachment(1)->getTexture())->texture.image; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + + frameBufCmd.recordPipelineImageBarrier( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + { + imgBarrier + } + ); + } } void RenderViewDeferredVLK::doLightPass(CmdBufRecorder &frameBufCmd) { + auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto renderPass = frameBufCmd.beginRenderPass(false, m_lightBufferPass, @@ -254,9 +318,11 @@ void RenderViewDeferredVLK::doLightPass(CmdBufRecorder &frameBufCmd) { {m_width, m_height}, {0,0,0}); - frameBufCmd.bindVertexBindings(m_quadVAO); - frameBufCmd.bindMaterial(m_pointLightMats[frameNum]); - frameBufCmd.drawIndexed(6, m_lightPointCount, 0, 0, 0); + if (m_lightPointCount > 0) { + frameBufCmd.bindVertexBindings(m_quadVAO); + frameBufCmd.bindMaterial(m_pointLightMats[frameNum]); + frameBufCmd.drawIndexed(6, m_lightPointCount, 0, 0, 0); + } } RenderPassHelper RenderViewDeferredVLK::beginForwardPass(CmdBufRecorder &frameBufCmd, bool willExecuteSecondaryBuffs, @@ -316,14 +382,20 @@ RenderViewDeferredVLK::readRGBAPixels(int frameNumber, int x, int y, int width, void RenderViewDeferredVLK::updateLightBuffers(const std::vector &pointLights, const std::vector &spotLights) { + bool recreateLightMat = false; auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; auto &pointLightBuffer = m_pointLightBuffers[frameNum]; if (pointLightBuffer->getSize() < pointLights.size()*sizeof(LocalLight)) { pointLightBuffer = m_lightDataBuffer->getSubBuffer((pointLights.size() + 100) * sizeof(LightResult)); + recreateLightMat = true; } pointLightBuffer->uploadData(pointLights.data(), pointLights.size()*sizeof(LocalLight)); m_lightPointCount = pointLights.size(); + + if (recreateLightMat) { + createLightBufferMats(); + } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h index 59717dc7b..b81f65545 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h @@ -13,6 +13,7 @@ class RenderViewDeferredVLK : public IRenderView { public: RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGBufferVLK &lightDataBuffer, + const std::shared_ptr &sceneWideDS, const HGVertexBufferBindings &quadVAO, bool createOutputFBO); ~RenderViewDeferredVLK() override = default; @@ -44,13 +45,17 @@ class RenderViewDeferredVLK : public IRenderView { uint32_t m_lightPointCount; uint32_t m_spotPointCount; + std::shared_ptr m_sceneWideDS; + HGDeviceVLK m_device; bool m_createOutputFBO; + bool m_lightMatsCreated = false; HGVertexBufferBindings m_quadVAO; HGBufferVLK m_lightDataBuffer; + std::shared_ptr> m_lightScreenSize; std::shared_ptr m_gBufferRenderPass; std::shared_ptr m_forwardRenderPass; @@ -62,7 +67,7 @@ class RenderViewDeferredVLK : public IRenderView { std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_lightFrameBuffers; - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightBuffers; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightMats; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_spotLightMats; From 34cf3914e7b0b836ac8a6016ecb62a6cad447983 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 3 Apr 2024 04:29:17 +0300 Subject: [PATCH 182/212] - WMO new lights --- wowViewerLib/CMakeLists.txt | 2 + .../src/engine/geometry/wmoGroupGeom.cpp | 57 ++- .../src/engine/geometry/wmoGroupGeom.h | 23 +- .../src/engine/geometry/wmoMainGeom.cpp | 374 +++++++++--------- .../src/engine/geometry/wmoMainGeom.h | 3 + .../src/engine/objects/ViewsObjects.cpp | 17 + .../src/engine/objects/ViewsObjects.h | 1 + .../src/engine/objects/adt/adtObject.cpp | 2 +- wowViewerLib/src/engine/objects/iWmoApi.h | 4 + .../src/engine/objects/lights/CPointLight.cpp | 34 ++ .../src/engine/objects/lights/CPointLight.h | 5 +- .../engine/objects/lights/CWmoNewLight.cpp | 49 +++ .../src/engine/objects/lights/CWmoNewLight.h | 36 ++ .../src/engine/objects/scenes/map.cpp | 14 + .../src/engine/objects/wmo/wmoGroupObject.cpp | 52 +++ .../src/engine/objects/wmo/wmoGroupObject.h | 10 +- .../src/engine/objects/wmo/wmoObject.cpp | 17 + .../src/engine/objects/wmo/wmoObject.h | 12 +- .../engine/persistance/header/wmoFileHeader.h | 122 +++++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 24 +- 21 files changed, 649 insertions(+), 211 deletions(-) create mode 100644 wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp create mode 100644 wowViewerLib/src/engine/objects/lights/CWmoNewLight.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 0353cc0e9..bc57c4452 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -376,6 +376,8 @@ set(SOURCE_FILES src/engine/objects/lights/CPointLight.h src/engine/objects/lights/CSpotLight.cpp src/engine/objects/lights/CSpotLight.h + src/engine/objects/lights/CWmoNewLight.cpp + src/engine/objects/lights/CWmoNewLight.h ) if (LINK_OGL2) diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index fd3aed07b..790bcb0aa 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -208,11 +208,64 @@ chunkDef WmoGroupGeom::wmoGroupTable = { 'MOLP', { [](WmoGroupGeom& object, ChunkData& chunkData){ debuglog("Entered MOLP"); - object.molpCnt = chunkData.chunkLen / sizeof(MOLP); - chunkData.readValues(object.molp, object.molpCnt); + object.map_object_point_lightLen = chunkData.chunkLen / sizeof(map_object_point_light); + chunkData.readValues(object.map_object_point_lights, object.map_object_point_lightLen); }, } }, + { + 'MOP2', { + [](WmoGroupGeom& object, ChunkData& chunkData){ + debuglog("Entered MOP2"); + object.map_object_pointlight_animLen = chunkData.chunkLen / sizeof(map_object_point_light); + chunkData.readValues(object.map_object_pointlight_anims, object.map_object_pointlight_animLen); + }, + } + }, + { + 'MLSK', { + [](WmoGroupGeom& object, ChunkData& chunkData){ + debuglog("Entered MLSK"); + object.mapobject_pointlight_animsetsLen = chunkData.chunkLen / sizeof(LightRecPerSet); + chunkData.readValues(object.mapobject_pointlight_animsets, object.mapobject_pointlight_animsetsLen); + }, + } + }, + { + 'MLSO', { + [](WmoGroupGeom& object, ChunkData& chunkData){ + debuglog("Entered MLSO"); + object.mapobject_spotlight_animsetsLen = chunkData.chunkLen / sizeof(LightRecPerSet); + chunkData.readValues(object.mapobject_spotlight_animsets, object.mapobject_spotlight_animsetsLen); + }, + } + }, + { + 'MLSP', { + [](WmoGroupGeom& object, ChunkData& chunkData){ + debuglog("Entered MLSP"); + object.map_object_lightset_pointlightsLen = chunkData.chunkLen / sizeof(LightRecPerSet); + chunkData.readValues(object.map_object_lightset_pointlights, object.map_object_lightset_pointlightsLen); + }, + } + }, + { + 'MNLR', { + [](WmoGroupGeom& object, ChunkData& chunkData){ + debuglog("Entered MNLR"); + object.mapobject_new_light_refsLen = chunkData.chunkLen / sizeof(uint16_t); + chunkData.readValues(object.mapobject_new_light_refs, object.mapobject_new_light_refsLen); + }, + } + }, + +// { +// 'MLSO', { +// [](WmoGroupGeom& object, ChunkData& chunkData){ +// +// } +// } +// } } } } diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h index 6d61d438f..d205c054a 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.h @@ -118,8 +118,7 @@ class WmoGroupGeom : public PersistentFile { int use_replacement_for_header_color = 0; CArgb replacement_for_header_color = {}; - PointerChecker molp = (molpCnt); - int molpCnt = 0; + MLIQ *m_mliq = nullptr; @@ -129,6 +128,26 @@ class WmoGroupGeom : public PersistentFile { PointerChecker m_liquidTiles = (m_liquidTiles_len); int m_liquidTiles_len = -1; + + + PointerChecker mapobject_pointlight_animsets = (mapobject_pointlight_animsetsLen); + int mapobject_pointlight_animsetsLen = -1; + + PointerChecker mapobject_spotlight_animsets = (mapobject_spotlight_animsetsLen); + int mapobject_spotlight_animsetsLen = -1; + + PointerChecker map_object_lightset_pointlights = (map_object_lightset_pointlightsLen); + int map_object_lightset_pointlightsLen = -1; + + PointerChecker map_object_point_lights = (map_object_point_lightLen); + int map_object_point_lightLen = 0; + + PointerChecker map_object_pointlight_anims = (map_object_pointlight_animLen); + int map_object_pointlight_animLen = 0; + + PointerChecker mapobject_new_light_refs = (mapobject_new_light_refsLen); + int mapobject_new_light_refsLen = 0; + HGVertexBuffer combinedVBO; HGIndexBuffer indexVBO; HGVertexBufferBindings vertexBufferBindings; diff --git a/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp b/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp index f7883a0ca..370e23eef 100644 --- a/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoMainGeom.cpp @@ -7,198 +7,206 @@ chunkDef WmoMainGeom::wmoMainTable = { [](WmoMainGeom& object, ChunkData& chunkData){}, + { { - { - 'MVER', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MVER"); - int version; - chunkData.readValue(version); - } - } - }, - { - 'MOHD', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOHD"); - - chunkData.readValue(object.header); - } - } - }, - { - 'GFID', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered GFID"); + 'MVER', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MVER"); + int version; + chunkData.readValue(version); + } + } + }, + { + 'MOHD', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOHD"); - int fileDataIdCount = chunkData.chunkLen / sizeof(uint32_t); - int lodCount = fileDataIdCount / object.header->nGroups; - object.gfids = std::vector>(lodCount); - for (int i = 0; i < lodCount; i++) { - object.gfids[i] = std::vector(object.header->nGroups); - for (int j = 0; j < object.header->nGroups; j++) { - uint32_t fileDataId; - chunkData.readValue(fileDataId); - object.gfids[i][j] = fileDataId; - } - } - } - } - }, + chunkData.readValue(object.header); + } + } + }, + { + 'GFID', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered GFID"); - { - 'MOGI', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOGI"); - object.groupsLen = chunkData.chunkLen / sizeof(SMOGroupInfo); - chunkData.readValues(object.groups, object.groupsLen); - } - } - }, - { - 'MODI', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MODI"); - object.doodadFileDataIdsLen = chunkData.chunkLen / sizeof(int); - chunkData.readValues(object.doodadFileDataIds, object.doodadFileDataIdsLen); - } - } - }, - { - 'MLIQ', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MLIQ"); - } - } - }, - { - 'MOPV', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOPV"); - object.portal_verticesLen = chunkData.chunkLen / sizeof(C3Vector); - chunkData.readValues(object.portal_vertices, object.portal_verticesLen); - } - } - }, - { - 'MOPT', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOPT"); - object.portalsLen = chunkData.chunkLen / sizeof(SMOPortal); - chunkData.readValues(object.portals, object.portalsLen); - } - } - }, - { - 'MOPR', { - [](WmoMainGeom &object, ChunkData &chunkData) { - object.portalReferencesLen = chunkData.chunkLen / sizeof(SMOPortalRef); - chunkData.readValues(object.portalReferences, object.portalReferencesLen); - debuglog("Entered MOPR"); - } - } - }, - { - 'MOMT', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOMT"); - object.materialsLen = chunkData.chunkLen / sizeof(SMOMaterial); - chunkData.readValues(object.materials, object.materialsLen); - } - } - }, - { - 'MOTX', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOTX"); - object.textureNamesFieldLen = chunkData.chunkLen; - chunkData.readValues(object.textureNamesField, object.textureNamesFieldLen); - } - } - }, - { - 'MODN', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MODN"); - object.doodadNamesFieldLen = chunkData.chunkLen; - chunkData.readValues(object.doodadNamesField, object.doodadNamesFieldLen); - } - } - }, - { - 'MODS', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MODS"); - object.doodadSetsLen = chunkData.chunkLen / sizeof(SMODoodadSet); - chunkData.readValues(object.doodadSets, object.doodadSetsLen); - } - } - }, - { - 'MODD', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MODD"); - object.doodadDefsLen = chunkData.chunkLen / sizeof(SMODoodadDef); - chunkData.readValues(object.doodadDefs, object.doodadDefsLen); - } - } - }, - { - 'MFOG', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MFOG"); - object.fogsLen = chunkData.chunkLen / sizeof(SMOFog); - chunkData.readValues(object.fogs, object.fogsLen); - } - } - }, - { - 'MOLT', { - [](WmoMainGeom& object, ChunkData& chunkData) { - debuglog("Entered MOLT"); - object.lightsLen = chunkData.chunkLen / sizeof(SMOLight); - chunkData.readValues(object.lights, object.lightsLen); - } - } - }, - { - 'MOSB', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOSB"); - object.skyBoxM2FileNameLen = chunkData.chunkLen; - chunkData.readValues(object.skyBoxM2FileName, object.skyBoxM2FileNameLen); + int fileDataIdCount = chunkData.chunkLen / sizeof(uint32_t); + int lodCount = fileDataIdCount / object.header->nGroups; + object.gfids = std::vector>(lodCount); + for (int i = 0; i < lodCount; i++) { + object.gfids[i] = std::vector(object.header->nGroups); + for (int j = 0; j < object.header->nGroups; j++) { + uint32_t fileDataId; + chunkData.readValue(fileDataId); + object.gfids[i][j] = fileDataId; } } + } + } + }, - }, - { - 'MOSI', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MOSI"); - chunkData.readValue(object.skyboxM2FileId); - } - } - }, - { - 'MAVG', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MAVG"); - object.mavgsLen = chunkData.chunkLen / sizeof(MAVG); - chunkData.readValues(object.mavgs, object.mavgsLen); - } - } - }, - { - 'MCVP', { - [](WmoMainGeom &object, ChunkData &chunkData) { - debuglog("Entered MCVP"); - object.convexVolumePlanesLen = chunkData.chunkLen / sizeof(mathfu::vec4_packed); - chunkData.readValues(object.convexVolumePlanes, object.convexVolumePlanesLen); - } - } + { + 'MOGI', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOGI"); + object.groupsLen = chunkData.chunkLen / sizeof(SMOGroupInfo); + chunkData.readValues(object.groups, object.groupsLen); + } + } + }, + { + 'MODI', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MODI"); + object.doodadFileDataIdsLen = chunkData.chunkLen / sizeof(int); + chunkData.readValues(object.doodadFileDataIds, object.doodadFileDataIdsLen); + } + } + }, + { + 'MLIQ', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MLIQ"); + } + } + }, + { + 'MOPV', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOPV"); + object.portal_verticesLen = chunkData.chunkLen / sizeof(C3Vector); + chunkData.readValues(object.portal_vertices, object.portal_verticesLen); + } + } + }, + { + 'MOPT', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOPT"); + object.portalsLen = chunkData.chunkLen / sizeof(SMOPortal); + chunkData.readValues(object.portals, object.portalsLen); + } + } + }, + { + 'MOPR', { + [](WmoMainGeom &object, ChunkData &chunkData) { + object.portalReferencesLen = chunkData.chunkLen / sizeof(SMOPortalRef); + chunkData.readValues(object.portalReferences, object.portalReferencesLen); + debuglog("Entered MOPR"); } + } + }, + { + 'MOMT', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOMT"); + object.materialsLen = chunkData.chunkLen / sizeof(SMOMaterial); + chunkData.readValues(object.materials, object.materialsLen); + } + } + }, + { + 'MOTX', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOTX"); + object.textureNamesFieldLen = chunkData.chunkLen; + chunkData.readValues(object.textureNamesField, object.textureNamesFieldLen); + } + } + }, + { + 'MODN', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MODN"); + object.doodadNamesFieldLen = chunkData.chunkLen; + chunkData.readValues(object.doodadNamesField, object.doodadNamesFieldLen); + } + } + }, + { + 'MODS', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MODS"); + object.doodadSetsLen = chunkData.chunkLen / sizeof(SMODoodadSet); + chunkData.readValues(object.doodadSets, object.doodadSetsLen); + } + } + }, + { + 'MODD', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MODD"); + object.doodadDefsLen = chunkData.chunkLen / sizeof(SMODoodadDef); + chunkData.readValues(object.doodadDefs, object.doodadDefsLen); + } + } + }, + { + 'MFOG', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MFOG"); + object.fogsLen = chunkData.chunkLen / sizeof(SMOFog); + chunkData.readValues(object.fogs, object.fogsLen); + } + } + }, + { + 'MOLT', { + [](WmoMainGeom& object, ChunkData& chunkData) { + debuglog("Entered MOLT"); + object.lightsLen = chunkData.chunkLen / sizeof(SMOLight); + chunkData.readValues(object.lights, object.lightsLen); + } + } + }, + { + 'MOSB', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOSB"); + object.skyBoxM2FileNameLen = chunkData.chunkLen; + chunkData.readValues(object.skyBoxM2FileName, object.skyBoxM2FileNameLen); + } + } + }, + { + 'MOSI', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MOSI"); + chunkData.readValue(object.skyboxM2FileId); + } + } + }, + { + 'MAVG', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MAVG"); + object.mavgsLen = chunkData.chunkLen / sizeof(MAVG); + chunkData.readValues(object.mavgs, object.mavgsLen); + } + } + }, + { + 'MCVP', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MCVP"); + object.convexVolumePlanesLen = chunkData.chunkLen / sizeof(mathfu::vec4_packed); + chunkData.readValues(object.convexVolumePlanes, object.convexVolumePlanesLen); + } + } + }, + { + 'MNLD', { + [](WmoMainGeom &object, ChunkData &chunkData) { + debuglog("Entered MNLD"); + object.newLightsLen = chunkData.chunkLen / sizeof(mapobject_new_light_def); + chunkData.readValues(object.newLights, object.newLightsLen); + } + } } + } }; diff --git a/wowViewerLib/src/engine/geometry/wmoMainGeom.h b/wowViewerLib/src/engine/geometry/wmoMainGeom.h index 7182cc872..1e1ac0154 100644 --- a/wowViewerLib/src/engine/geometry/wmoMainGeom.h +++ b/wowViewerLib/src/engine/geometry/wmoMainGeom.h @@ -73,6 +73,9 @@ class WmoMainGeom : public PersistentFile { PointerChecker convexVolumePlanes = (convexVolumePlanesLen); int convexVolumePlanesLen = 0; + PointerChecker newLights = (newLightsLen); + int newLightsLen = 0; + int skyboxM2FileId = 0; }; diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 65c28b2bc..07dd303b6 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -36,6 +36,23 @@ void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool rende } } } +void GeneralView::collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights) { + for (auto &wmoGroup: wmoGroupArray.getToDraw()) { + auto &wmoPointLights = wmoGroup->getPointLights(); + + pointLights.reserve(pointLights.size() + wmoPointLights.size()); + + for (auto &pointLight : wmoPointLights) + pointLights.push_back(pointLight.getLightRec()); + + auto &wmoNewLights = wmoGroup->getWmoNewLights(); + newWmoLights.reserve(newWmoLights.size() + wmoNewLights.size()); + for (auto &newLight : wmoNewLights) { + newWmoLights.push_back(newLight); + } + } +}; + void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumData, mathfu::vec4 &cameraPos) { for (auto &wmoGroup : wmoGroupArray.getToCheckM2()) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index ba473998b..7481ca29e 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -57,6 +57,7 @@ class GeneralView { framebased::vector liquidMeshes = {}; virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); + virtual void collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights); void collectPortalMeshes(framebased::vector &transparentMeshes); virtual void setM2Lights(const std::shared_ptr &m2Object); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 1782ac340..19ed2595d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -253,7 +253,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { if (m_adtFile->mcnkStructs[i].mclv != nullptr) { auto &mclv = m_adtFile->mcnkStructs[i].mclv; adtVertex.mclv = { - mclv->values[j].b / 255.0f, + mclv->values[j].b / 255.0f, mclv->values[j].g / 255.0f, mclv->values[j].r / 255.0f, mclv->values[j].a / 255.0f diff --git a/wowViewerLib/src/engine/objects/iWmoApi.h b/wowViewerLib/src/engine/objects/iWmoApi.h index fad85126f..3c4ace1af 100644 --- a/wowViewerLib/src/engine/objects/iWmoApi.h +++ b/wowViewerLib/src/engine/objects/iWmoApi.h @@ -8,6 +8,7 @@ #include #include "../engineClassList.h" #include "m2/m2Object.h" +#include "lights/CWmoNewLight.h" struct PortalInfo_t { std::vector sortedVericles; @@ -318,6 +319,9 @@ class IWmoApi { virtual PointerChecker &getLightArray() = 0; virtual std::vector &getPortalInfos() = 0; + virtual int getActiveDoodadSet() = 0; + virtual std::shared_ptr getNewLight(int index) = 0; + virtual HGSamplableTexture getTexture(int textureId, bool isSpec) = 0; virtual void updateBB() = 0; diff --git a/wowViewerLib/src/engine/objects/lights/CPointLight.cpp b/wowViewerLib/src/engine/objects/lights/CPointLight.cpp index fb740dcc9..260bb56e1 100644 --- a/wowViewerLib/src/engine/objects/lights/CPointLight.cpp +++ b/wowViewerLib/src/engine/objects/lights/CPointLight.cpp @@ -24,3 +24,37 @@ CPointLight::CPointLight(WdtLightFile::MapPointLight3 &lightRecord) { m_localLight.position = mathfu::vec4(mathfu::vec3(lightRecord.position), 0.0); m_localLight.blendParams = mathfu::vec4(0.0); } +CPointLight::CPointLight(const mathfu::mat4 &modelMat, const map_object_point_light &lightRecord) { + const auto &pointLightRec = lightRecord; + mathfu::vec4 attenVec = mathfu::vec4(pointLightRec.attenuationStart, pointLightRec.intensity, pointLightRec.attenuationEnd, 0); + + m_localLight.attenuation = attenVec; + + m_localLight.innerColor = mathfu::vec4( + ((float)pointLightRec.color.r)/255.0f, + ((float)pointLightRec.color.g)/255.0f, + ((float)pointLightRec.color.b)/255.0f, + 0); + + m_localLight.outerColor = m_localLight.innerColor; + m_localLight.position = mathfu::vec4((modelMat * mathfu::vec4(mathfu::vec3(pointLightRec.pos), 1.0)).xyz(), 1.0); + m_localLight.blendParams = mathfu::vec4(0.0); +} + +CPointLight::CPointLight(const mathfu::mat4 &modelMat, const map_object_pointlight_anim &lightRecord) { + const auto &pointLightRec = lightRecord.pointLight; + + mathfu::vec4 attenVec = mathfu::vec4(pointLightRec.attenuationStart, pointLightRec.intensity, pointLightRec.attenuationEnd, 0); + + m_localLight.attenuation = attenVec; + + m_localLight.innerColor = mathfu::vec4( + ((float)pointLightRec.color.r)/255.0f, + ((float)pointLightRec.color.g)/255.0f, + ((float)pointLightRec.color.b)/255.0f, + 0); + + m_localLight.outerColor = m_localLight.innerColor; + m_localLight.position = mathfu::vec4((modelMat * mathfu::vec4(mathfu::vec3(pointLightRec.pos), 1.0)).xyz(), 1.0); + m_localLight.blendParams = mathfu::vec4(0.0); +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/lights/CPointLight.h b/wowViewerLib/src/engine/objects/lights/CPointLight.h index 8e3c342e4..78e3c1f81 100644 --- a/wowViewerLib/src/engine/objects/lights/CPointLight.h +++ b/wowViewerLib/src/engine/objects/lights/CPointLight.h @@ -6,14 +6,17 @@ #define AWEBWOWVIEWERCPP_CPOINTLIGHT_H #include "../../persistance/wdtLightFile.h" +#include "../../persistance/header/wmoFileHeader.h" #include "../../../gapi/UniformBufferStructures.h" class CPointLight { public: CPointLight(); CPointLight(WdtLightFile::MapPointLight3 &lightRecord); + CPointLight(const mathfu::mat4 &modelMat, const map_object_point_light &lightRecord); + CPointLight(const mathfu::mat4 &modelMat, const map_object_pointlight_anim &lightRecord); - LocalLight& getLightRec() { + const LocalLight& getLightRec() const { return m_localLight; } private: diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp new file mode 100644 index 000000000..e48bc15b2 --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp @@ -0,0 +1,49 @@ +// +// Created by Deamon on 4/3/2024. +// + +#include "CWmoNewLight.h" + +CWmoNewLight::CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_light_def &newLightDef) { + isPointLight = newLightDef.type == 0; + isSpotLight = newLightDef.type == 1; + + m_innerColor = newLightDef.innerColor; + m_pos = (modelMatrix * mathfu::vec4(mathfu::vec3(newLightDef.position), 1.0)).xyz(); + m_rotation = newLightDef.rotation; + m_attenuationStart = newLightDef.attenStart; + m_attenuationEnd = newLightDef.attenEnd; + m_intensity = newLightDef.intensity; + m_outerColor = newLightDef.outerColor; + m_spotLightAttenuationStart = newLightDef.spotLightAttenuationStart; + m_spotLightAttenuationEnd = newLightDef.spotLightAttenuationEnd; + m_spotlightRadius = newLightDef.spotlightRadius; + m_innerAngle = newLightDef.innerAngle; + m_outerAngle = newLightDef.outerAngle; +} + +void CWmoNewLight::collectLight(std::vector &pointLights, std::vector &spotLights) { + if (isPointLight) { + auto &pointLight = pointLights.emplace_back(); + //TODO: implement flickering animation + pointLight.innerColor = mathfu::vec4( + ((float)m_innerColor.r)/255.0f, + ((float)m_innerColor.g)/255.0f, + ((float)m_innerColor.b)/255.0f, + 0); + pointLight.outerColor = mathfu::vec4( + ((float)m_outerColor.r)/255.0f, + ((float)m_outerColor.g)/255.0f, + ((float)m_outerColor.b)/255.0f, + 0);; + pointLight.blendParams.x = m_attenuationStart; + pointLight.blendParams.y = m_attenuationEnd; + + mathfu::vec4 attenVec = mathfu::vec4(m_attenuationStart, m_intensity, m_attenuationEnd, 0); + pointLight.attenuation = attenVec; + pointLight.position = mathfu::vec4(mathfu::vec3(m_pos), 1.0); + + } else if (isSpotLight) { + + } +} diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h new file mode 100644 index 000000000..0c137e59e --- /dev/null +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h @@ -0,0 +1,36 @@ +// +// Created by Deamon on 4/3/2024. +// + +#ifndef AWEBWOWVIEWERCPP_CWMONEWLIGHT_H +#define AWEBWOWVIEWERCPP_CWMONEWLIGHT_H + +#include +#include "../../persistance/header/wmoFileHeader.h" +#include "../../../gapi/UniformBufferStructures.h" + + +class CWmoNewLight { +public: + CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_light_def &newLightDef ); + + void collectLight(std::vector &pointLights, std::vector &spotLights); + +private: + bool isPointLight; + bool isSpotLight; + CImVector m_innerColor; + C3Vector m_pos; + C3Vector m_rotation; + float m_attenuationStart; + float m_attenuationEnd; + float m_intensity; + CImVector m_outerColor; + float m_spotLightAttenuationStart; + float m_spotLightAttenuationEnd; + float m_spotlightRadius; + float m_innerAngle; + float m_outerAngle; +}; + +#endif //AWEBWOWVIEWERCPP_CWMONEWLIGHT_H diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f91436a4b..84fa22c30 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -500,6 +500,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams } } + std::vector> newWmoLights = {}; { auto exteriorView = mapRenderPlan->viewsHolder.getExterior(); @@ -522,17 +523,30 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); mapRenderPlan->wmoGroupArray.addToLoadAndDraw(exteriorView->wmoGroupArray); } + + exteriorView->collectLights(mapRenderPlan->pointLights, mapRenderPlan->spotLights, newWmoLights); } } //Fill and collect M2 objects for views from WmoGroups { + ZoneScopedN("collect from interiors"); auto &interiorViews = mapRenderPlan->viewsHolder.getInteriorViews(); for (auto &interiorView: interiorViews) { interiorView->addM2FromGroups(frustumData, cameraPos); mapRenderPlan->m2Array.addDrawnAndToLoad(interiorView->m2List); mapRenderPlan->wmoGroupArray.addToLoadAndDraw(interiorView->wmoGroupArray); + + interiorView->collectLights(mapRenderPlan->pointLights, mapRenderPlan->spotLights, newWmoLights); + } + } + { + ZoneScopedN("process new lights"); + std::sort(newWmoLights.begin(), newWmoLights.end()); + newWmoLights.erase(std::unique(newWmoLights.begin(), newWmoLights.end()), newWmoLights.end()); + for (auto &newWmoLight: newWmoLights) { + newWmoLight->collectLight(mapRenderPlan->pointLights, mapRenderPlan->spotLights); } } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 3841f7f27..9bc6f5acd 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -113,6 +113,7 @@ void WmoGroupObject::postLoad(const HMapSceneBufferCreate &sceneRenderer) { m_localGroupBorder = m_geom->mogp->boundingBox; this->createWorldGroupBB(m_geom->mogp->boundingBox, *m_modelMatrix); this->loadDoodads(); + this->loadLights(); this->createMeshes(sceneRenderer); this->createWaterMeshes(sceneRenderer); } @@ -266,6 +267,49 @@ void WmoGroupObject::loadDoodads() { this->m_recalcBoundries = true; } +void WmoGroupObject::loadLights() { + auto &modelMatrix = *m_modelMatrix; + //Create Point Lights + { + auto doodadSet = m_wmoApi->getActiveDoodadSet(); + if (doodadSet < 0) { + doodadSet = 0; + }; + + if (doodadSet < m_geom->map_object_lightset_pointlightsLen) { + auto lightPointSet = m_geom->map_object_lightset_pointlights[doodadSet]; + for (int i = 0; i < lightPointSet.count; i++) { + const auto lightIndex = lightPointSet.offset + i; + if (lightIndex > m_geom->map_object_point_lightLen) break; + + auto &lightRecord = m_geom->map_object_point_lights[lightIndex]; + + m_pointLights.emplace_back() = CPointLight(modelMatrix, lightRecord); + } + } + + if (doodadSet < m_geom->mapobject_pointlight_animsetsLen) { + auto lightPointSet = m_geom->mapobject_pointlight_animsets[doodadSet]; + for (int i = 0; i < lightPointSet.count; i++) { + const auto lightIndex = lightPointSet.offset + i; + if (lightIndex > m_geom->map_object_pointlight_animLen) break; + + auto &lightRecord = m_geom->map_object_pointlight_anims[lightIndex]; + + m_pointLights.emplace_back() = CPointLight(modelMatrix, lightRecord); + } + } + } + + //Get newlights array + m_wmoNewLights.reserve(m_geom->mapobject_new_light_refsLen); + for (int i = 0; i < m_geom->mapobject_new_light_refsLen; i++) { + auto wmoNewLight = m_wmoApi->getNewLight(m_geom->mapobject_new_light_refs[i]); + if (wmoNewLight) { + m_wmoNewLights.push_back(wmoNewLight); + } + } +} void WmoGroupObject::createWorldGroupBB(CAaBox &bbox, mathfu::mat4 &placementMatrix) { // groupInfo = this.groupInfo; @@ -768,6 +812,14 @@ void WmoGroupObject::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, fr } } +const std::vector &WmoGroupObject::getPointLights() { + return m_pointLights; +} + +const std::vector> &WmoGroupObject::getWmoNewLights() { + return m_wmoNewLights; +} + mathfu::vec4 WmoGroupObject::getAmbientColor() { if (!m_geom->mogp->flags.EXTERIOR && !m_geom->mogp->flags.EXTERIOR_LIT) { mathfu::vec4 ambColor; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index bc2b267d8..da3d209b3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -14,6 +14,9 @@ class WMOGroupListContainer; #include "../liquid/LiquidInstance.h" #include "../../../gapi/interface/meshes/IMesh.h" #include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" +#include "../lights/CPointLight.h" +#include "../lights/CSpotLight.h" +#include "../lights/CWmoNewLight.h" class WmoGroupObject { @@ -47,7 +50,8 @@ class WmoGroupObject { void setModelFileId(int fileId); void collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes, int renderOrder); - + const std::vector &getPointLights(); + const std::vector> &getWmoNewLights(); bool getDontUseLocalLightingForM2() { return !m_useLocalLightingForM2; }; bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); @@ -91,6 +95,9 @@ class WmoGroupObject { SMOGroupInfo *m_main_groupInfo; std::vector > m_doodads = {}; + std::vector m_pointLights = {}; + std::vector m_spotLights = {}; + std::vector> m_wmoNewLights = {}; bool m_useLocalLightingForM2 = false; @@ -114,6 +121,7 @@ class WmoGroupObject { void setLiquidType(); void loadDoodads(); + void loadLights(); bool checkIfInsidePortals( mathfu::vec3 point, diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 479fdbeda..cf10301e1 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -299,6 +299,7 @@ bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { if (mainGeom != nullptr && mainGeom->getStatus() == FileStatus::FSLoaded){ this->createMaterialCache(); + this->createNewLights(); this->createGroupObjects(); this->createWorldPortals(); this->createBB(mainGeom->header->bounding_box); @@ -1402,3 +1403,19 @@ mathfu::vec3 WmoObject::getAmbientColor() { return ambColor; } + +void WmoObject::createNewLights() { + m_newLights.resize(mainGeom->newLightsLen); + for (int i = 0; i < mainGeom->newLightsLen; i++) { + auto &newLightRec = mainGeom->newLights[i]; + if (m_doodadSet != newLightRec.doodadSet) { + m_newLights[i] = nullptr; + continue; + } + m_newLights[i] = std::make_shared(m_placementMatrix, mainGeom->newLights[i]); + } +} + +std::shared_ptr WmoObject::getNewLight(int index) { + return m_newLights[index]; +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index a75b5a34f..3764b6551 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -23,6 +23,7 @@ class WmoGroupObject; #include "../ViewsObjects.h" #include "../../../include/database/dbStructs.h" #include "../SceneObjectWithID.h" +#include "../lights/CWmoNewLight.h" class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { @@ -72,6 +73,8 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { std::vector> groupObjectsLod2 = std::vector>(0); std::vector blpTextures; + std::vector> m_newLights; + std::vector drawGroupWMO; std::vector lodGroupLevelWMO; robin_hood::unordered_flat_map> m_doodadsUnorderedMap; @@ -117,8 +120,11 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { } int getWmoGroupId (int groupNum); - virtual std::function getAttenFunction() override; - virtual SMOHeader *getWmoHeader() override; + std::function getAttenFunction() override; + SMOHeader *getWmoHeader() override; + int getActiveDoodadSet() override { + return m_doodadSet; + } mathfu::vec3 getAmbientColor() override; PointerChecker &getMaterials() override; @@ -186,6 +192,8 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { void drawDebugLights(); void createWorldPortals(); + void createNewLights(); + std::shared_ptr getNewLight(int index) override; }; class WMOListContainer { diff --git a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h index 2a615fb24..311ba2dbd 100644 --- a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h @@ -326,15 +326,6 @@ struct t_BSP_NODE float fDist; }; -struct MOLP { - float unk; - CArgb unk2; - C3Vector vec1; - C3Vector vec2; - float unk3; - unsigned int unk4; - CArgb unk5; -}; #pragma pack(push, 1) struct MLIQ { uint32_t xverts; @@ -375,4 +366,117 @@ struct SMOLTile ; }; +//Light related structs + +struct Light_texture_animation +{ + float flickerIntensity; + float flickerSpeed; + int flickerMode; +}; + +struct LightUnkRecord +{ + int unk0; + int unk1; + int unk2; + int unk3; + int lightTextureFileDataId; + int unk5; + int unk6; + int unk7; + int unk8; + int unk9; +}; + + +struct LightRecPerSet { + uint32_t offset; + uint32_t count; +}; + +//MOLP +PACK( +struct map_object_point_light { + uint32_t lightId; + CImVector color; + C3Vector pos; + float attenuationStart; + float attenuationEnd; + float intensity; + C3Vector rotation; +}); + +//MOP2 +PACK( +struct map_object_pointlight_anim +{ + map_object_point_light pointLight; + Light_texture_animation lightTextureAnimation; + LightUnkRecord lightUnkRecord; +}); + +//MOLS +PACK( +struct map_object_spot_light { + uint32_t lightIndex; + uint32_t color; + C3Vector pos; + uint32_t attenuationStart; + float attenuationEnd; + uint32_t intesity; + C3Vector rotation; + uint32_t spotlightRadius; //A + float innerAngle; + float outerAngle; +}); + +//MOS2 +PACK( +struct map_object_spotlight_anim +{ + map_object_spot_light spotLight; + Light_texture_animation lightTextureAnimation; + LightUnkRecord lightUnkRecord; +}); + +//MLND - lives in main WMO +struct mapobject_new_light_def { + int type; + int lightIndex; + int flags; + int doodadSet; + CImVector innerColor; + C3Vector position; + C3Vector rotation; + float attenStart; + float attenEnd; + float intensity; + CImVector outerColor; + float spotLightAttenuationStart; + float spotLightAttenuationEnd; + int field_44; + Light_texture_animation lightTextureAnimation; + LightUnkRecord lightUnkRecord; + float spotlightRadius; + float innerAngle; + float outerAngle; + uint16_t packedVal1; + uint16_t field_8A; + int field_8C; + int field_90; + int field_94; + int field_98; + int field_9C; + int field_A0; + int field_A4; + int field_A8; + int field_AC; + int field_B0; + int field_B4; +}; + +static_assert(sizeof(mapobject_new_light_def) == 0xb8); + + #endif //WOWVIEWERLIB_WMOFILEHEADER_H diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index c2b678ee1..0d63d721a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 84d1d5c5b..0ce007a3e 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -23,7 +23,9 @@ static const ShaderConfig forwardShaderConfig = { "forwardRendering", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, + {1, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT}}, + {2, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT}} }} } }; @@ -38,7 +40,7 @@ static const ShaderConfig m2BindlessShaderConfig = { "bindless/m2/forward", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, {1, { {6, {VkDescriptorType::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} @@ -57,7 +59,7 @@ static const ShaderConfig bindlessShaderConfig = { "bindless", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, }}; @@ -67,7 +69,7 @@ static const ShaderConfig m2WaterfallBindlessShaderConfig = { "bindless/waterfall/forward", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, {3, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2WaterfallTexturesBindlessCount}} @@ -79,7 +81,7 @@ static const ShaderConfig wmoBindlessShaderConfig = { "bindless/wmo/forward", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, {2, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, m2TexturesBindlessCount}} @@ -97,7 +99,7 @@ static const ShaderConfig adtBindlessShaderConfig = { "bindless/adt/forward", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, {2, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, adtTexturesBindlessCount}} @@ -121,7 +123,7 @@ static const ShaderConfig waterBindlessShaderConfig = { "bindless/water", { {0, { - {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}} + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }}, {2, { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, true, waterTexturesBindlessCount}} @@ -221,12 +223,16 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, { //Create SceneWide descriptor sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); - MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) .createDescriptorSet(0, [&](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, sceneWideChunk) .texture(1, hDevice->getBlackTexturePixel()) - .texture(2, hDevice->getWhiteTexturePixel()); +//Untill AO is ready. +#ifndef NDEBUG + .texture(2, hDevice->getWhiteTexturePixel()) +#endif + ; sceneWideDS = ds; }); From 583f927fbf43fd7c0b7f8c64373a893616593801 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 4 Apr 2024 06:08:06 +0300 Subject: [PATCH 183/212] - start of spot lights --- .../childWindow/sceneWindow/SceneWindow.cpp | 15 ++++ .../glsl/bindless/lights/pointLight.frag | 22 ++++- .../glsl/bindless/lights/pointLight.vert | 27 ++++-- .../glsl/bindless/lights/spotLight.frag | 0 .../glsl/bindless/lights/spotLight.vert | 5 ++ .../bindless/m2/deferred/m2Shader_opaq.frag | 1 + .../src/engine/objects/adt/adtObject.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 3 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 8 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 8 +- .../src/gapi/vulkan/buffers/GBufferVLK.cpp | 2 +- .../src/gapi/vulkan/buffers/GBufferVLK.h | 2 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 83 ++++++++++--------- .../vulkan/view/RenderViewDeferredVLK.cpp | 2 +- 14 files changed, 122 insertions(+), 58 deletions(-) create mode 100644 wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag create mode 100644 wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index ad99c7a30..ffd2bfaf2 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -169,6 +169,8 @@ std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneTyp */ void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, wdtFileId); @@ -177,6 +179,8 @@ void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y m_camera->setMovementSpeed(movementSpeed); } void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2Fdid); m_currentScene = m2Scene; @@ -198,6 +202,8 @@ void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacem } void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::vector &replacementTextureIds) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); auto m2Scene = std::make_shared(m_api, m2FileName); @@ -218,6 +224,8 @@ void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::ve } void SceneWindow::openWMOSceneByfdid(int WMOFdid) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, WMOFdid); @@ -225,6 +233,8 @@ void SceneWindow::openWMOSceneByfdid(int WMOFdid) { m_camera->setCameraPos(0, 0, 0); } void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, wmoFileName); @@ -233,6 +243,8 @@ void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { } void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z) { + unload(); + m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); m_currentScene = std::make_shared(m_api, mapId, mapName); @@ -246,6 +258,9 @@ void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, void SceneWindow::unload() { m_sceneRenderer = nullptr; m_currentScene = std::make_shared(); + m_camera = nullptr; + m_cameraList.resize(0); + m_renderView = nullptr; } std::shared_ptr SceneWindow::getLastPlan() { diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag index b40068963..edd3dc85c 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag @@ -64,4 +64,24 @@ void main() { vec3 lightColor = vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ); outColor = vec4(vec3(lightColor), 1.0); -} \ No newline at end of file +} + +//void test() { +//t391 = cb_local_light_data.cb_localLightData.c_lights[index_388]; +//float3 vectorToLight_394 = (t391.position.xyz - t376); +//float distanceToLightSqr_395 = dot(vectorToLight_394, vectorToLight_394); +//float distanceToLightInv_396 = rsqrt(distanceToLightSqr_395); +//float distanceToLight_397 = (distanceToLightSqr_395 * distanceToLightInv_396); +//float dot_398 = dot(vectorToLight_394, normalize_366); +//float diffuseTerm_400 = fmax((dot_398 * distanceToLightInv_396), 0.0f); +//float4 t401 = t391.attenuation; +//float saturate_406 = saturate(((distanceToLight_397 - t401.x) * t401.z)); +//float attenuation_407 = (1.0f - saturate_406); +//float4 t408 = t391.blendParams; +//float colorLerp_411 = smoothstep(t408.y, t408.x, distanceToLight_397); +//float3 lerp_417 = mix(t391.outerColor.xyz, t391.innerColor.xyz, float3(colorLerp_411)); +//float3 color_421 = (color_389 + (((lerp_417 * attenuation_407) * (lerp_417 * attenuation_407)) * diffuseTerm_400)); +//); +// +// +//1.0f - (x - attStart) * (1.) \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert index 5e2ed8d64..854fd767d 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.vert @@ -22,20 +22,35 @@ void main() { vec4 lightPosView = scene.uLookAtMat * vec4(lightRec.position.xyz, 1.0); - float attentuationEnd = lightRec.attenuation.z; + float attenStart = lightRec.attenuation.x; + float attenEnd = lightRec.attenuation.z; + + float pointLightRadius = attenEnd; + + //Hack. If the point light is behind the camera + //With current first person camera positive Z is behind the camera. Should fix? + { + float distToLight = abs(lightPosView.z); + if (lightPosView.z > 0.0 && distToLight < attenEnd) { + pointLightRadius *= ((attenEnd - distToLight) / attenEnd); + } + } + //Hack to get square bounding the circle of point light //The quads (-1.0, 1.0) or other is multiplied by radius end of point light - vec2 quadPosView = (position.xy * attentuationEnd); + vec2 quadPosView = (position.xy * pointLightRadius); lightPosView.xy += quadPosView; //Bring the projection on sphere to the front - lightPosView.z = min(-0.001, lightPosView.z + attentuationEnd); - - //Now it's safe to multiply it by perspective matrix - gl_Position = scene.uPMatrix * vec4(lightPosView.xyz, 1.0); + vec4 pointLightClip = scene.uPMatrix * vec4(lightPosView.xyz, 1.0); + pointLightClip.z = pointLightClip.w - (sign(pointLightClip.w) * 0.0001); + //clamp it against screen bounderies +// pointLightClip.xy = clamp(pointLightClip.xy, -vec2(abs(pointLightClip.w)), vec2(abs(pointLightClip.w))); + + gl_Position = pointLightClip; lightIndex = gl_InstanceIndex; } diff --git a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag new file mode 100644 index 000000000..e69de29bb diff --git a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert new file mode 100644 index 000000000..98c531608 --- /dev/null +++ b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert @@ -0,0 +1,5 @@ +#version 120 + +void main() { + gl_Position = vec4(vec3(0.0), 1.0); +} diff --git a/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag index bd6cb5313..e6bfd3c59 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag +++ b/wowViewerLib/shaders/glsl/bindless/m2/deferred/m2Shader_opaq.frag @@ -3,5 +3,6 @@ #extension GL_EXT_nonuniform_qualifier : require #define DEFERRED +#define TRUE_OPAQUE #include "../m2shader_text.glsl" diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 19ed2595d..1782ac340 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -253,7 +253,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { if (m_adtFile->mcnkStructs[i].mclv != nullptr) { auto &mclv = m_adtFile->mcnkStructs[i].mclv; adtVertex.mclv = { - mclv->values[j].b / 255.0f, + mclv->values[j].b / 255.0f, mclv->values[j].g / 255.0f, mclv->values[j].r / 255.0f, mclv->values[j].a / 255.0f diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 84fa22c30..56776415e 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1621,7 +1621,8 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe if (granSize == 0) granSize = m2ToDraw.size(); //Can't be paralleled? - for (auto &m2Object: renderPlan->m2Array.getDrawn()) { + auto &drawnM2s = renderPlan->m2Array.getDrawn(); + for (auto &m2Object: drawnM2s) { if (m2Object != nullptr) { m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 0d63d721a..208036def 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1260,23 +1260,23 @@ std::shared_ptr GDeviceVLK::getShader(std::string vertexName return sharedPtr; } -HGBufferVLK GDeviceVLK::createUniformBuffer(const char * objName, size_t initialSize) { +HGBufferVLK GDeviceVLK::createUniformBuffer(const std::string &objName, size_t initialSize) { auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, initialSize, uniformBufferOffsetAlign); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createSSBOBuffer(const char * objName, size_t initialSize, int recordSize) { +HGBufferVLK GDeviceVLK::createSSBOBuffer(const std::string &objName, size_t initialSize, int recordSize) { auto h_uniformBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, initialSize, recordSize); return h_uniformBuffer; } -HGBufferVLK GDeviceVLK::createVertexBuffer(const char * objName, size_t initialSize, int recordSize) { +HGBufferVLK GDeviceVLK::createVertexBuffer(const std::string &objName, size_t initialSize, int recordSize) { auto h_vertexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, initialSize, recordSize); return h_vertexBuffer; } -HGBufferVLK GDeviceVLK::createIndexBuffer(const char * objName, size_t initialSize) { +HGBufferVLK GDeviceVLK::createIndexBuffer(const std::string &objName, size_t initialSize) { auto h_indexBuffer = std::make_shared(this->shared_from_this(), objName, m_ringBuffer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, initialSize, 2); return h_indexBuffer; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 4c61e2f42..40ec1972c 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -102,10 +102,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); - HGBufferVLK createUniformBuffer(const char * objName, size_t size); - HGBufferVLK createSSBOBuffer(const char * objName, size_t size, int recordSize); - HGBufferVLK createVertexBuffer(const char * objName, size_t size, int recordSize = -1); - HGBufferVLK createIndexBuffer(const char * objName, size_t size); + HGBufferVLK createUniformBuffer(const std::string &objName, size_t size); + HGBufferVLK createSSBOBuffer(const std::string &objName, size_t size, int recordSize); + HGBufferVLK createVertexBuffer(const std::string &objName, size_t size, int recordSize = -1); + HGBufferVLK createIndexBuffer(const std::string &objName, size_t size); HGVertexBufferBindings createVertexBufferBindings() override; HGSamplableTexture createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) override; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp index 5854285ec..32df152f8 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.cpp @@ -5,7 +5,7 @@ #include "GBufferVLK.h" #include "../vk_mem_alloc.h" -GBufferVLK::GBufferVLK(const HGDeviceVLK &device, const char *objName, +GBufferVLK::GBufferVLK(const HGDeviceVLK &device, const std::string &objName, const std::shared_ptr &ringBuff, VkBufferUsageFlags usageFlags, int maxSize, int alignment) : m_device(device) { m_usageFlags = usageFlags; diff --git a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h index 979faf367..ba65f05b1 100644 --- a/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h +++ b/wowViewerLib/src/gapi/vulkan/buffers/GBufferVLK.h @@ -37,7 +37,7 @@ class GBufferVLK : public IBufferVLK, public std::enable_shared_from_this &ringBuff, + GBufferVLK(const HGDeviceVLK &device, const std::string &objName, const std::shared_ptr &ringBuff, VkBufferUsageFlags usageFlags, int maxSize, int alignment = -1); ~GBufferVLK() override; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 0ce007a3e..97ea28a7d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -136,14 +136,21 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); - vboM2Buffer = m_device->createVertexBuffer("Scene_VBO_M2",1024*1024, sizeof(M2Vertex)); - vboPortalBuffer = m_device->createVertexBuffer("Scene_VBO_Portal",1024*1024); - vboM2ParticleBuffer = m_device->createVertexBuffer("Scene_VBO_M2Particle",1024*1024, 64); - vboM2RibbonBuffer = m_device->createVertexBuffer("Scene_VBO_M2Ribbon",1024*1024, 64); - vboAdtBuffer = m_device->createVertexBuffer("Scene_VBO_ADT",3*1024*1024, sizeof(AdtVertex)); - vboWMOBuffer = m_device->createVertexBuffer("Scene_VBO_WMO",1024*1024, sizeof(WMOVertex)); - vboWaterBuffer = m_device->createVertexBuffer("Scene_VBO_Water",1024*1024, sizeof(LiquidVertexFormat)); - vboSkyBuffer = m_device->createVertexBuffer("Scene_VBO_Sky",1024*1024); + const int rendererId = std::hash()((uint64_t)this) & 0xFFFF; + const std::string rendererIdStr = " " + std::to_string(rendererId); + + auto un = [rendererIdStr](const std::string &name) -> std::string { + return name + rendererIdStr; + }; + + vboM2Buffer = m_device->createVertexBuffer(un("Scene_VBO_M2"),1024*1024, sizeof(M2Vertex)); + vboPortalBuffer = m_device->createVertexBuffer(un("Scene_VBO_Portal"),1024*1024); + vboM2ParticleBuffer = m_device->createVertexBuffer(un("Scene_VBO_M2Particle"),1024*1024, 64); + vboM2RibbonBuffer = m_device->createVertexBuffer(un("Scene_VBO_M2Ribbon"),1024*1024, 64); + vboAdtBuffer = m_device->createVertexBuffer(un("Scene_VBO_ADT"),3*1024*1024, sizeof(AdtVertex)); + vboWMOBuffer = m_device->createVertexBuffer(un("Scene_VBO_WMO"),1024*1024, sizeof(WMOVertex)); + vboWaterBuffer = m_device->createVertexBuffer(un("Scene_VBO_Water"),1024*1024, sizeof(LiquidVertexFormat)); + vboSkyBuffer = m_device->createVertexBuffer(un("Scene_VBO_Sky"),1024*1024); { @@ -158,8 +165,8 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, 0, 1, 2, 2, 1, 3 }; - m_vboQuad = m_device->createVertexBuffer("Scene_VBO_Quad", vertexBuffer.size() * sizeof(mathfu::vec2_packed)); - m_iboQuad = m_device->createIndexBuffer("Scene_IBO_Quad", indexBuffer.size() * sizeof(uint16_t)); + m_vboQuad = m_device->createVertexBuffer(un("Scene_VBO_Quad"), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboQuad = m_device->createIndexBuffer(un("Scene_IBO_Quad"), indexBuffer.size() * sizeof(uint16_t)); m_vboQuad->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); m_iboQuad->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); @@ -171,45 +178,45 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, //Create m2 shaders { - m2Buffers.placementMatrix = m_device->createSSBOBuffer("M2 Placement", 1024*1024, sizeof(M2::PlacementMatrix)); - m2Buffers.boneMatrix = m_device->createSSBOBuffer("M2 BoneMatrices",1024*1024, sizeof(mathfu::mat4)); - m2Buffers.m2Colors = m_device->createSSBOBuffer("M2 BoneMatrices", 1024*1024, sizeof(mathfu::vec4_packed)); - m2Buffers.textureWeights = m_device->createSSBOBuffer("M2 TextureWeight", 1024*1024, sizeof(mathfu::vec4_packed)); - m2Buffers.textureMatrices = m_device->createSSBOBuffer("M2 TextureMatrices", 1024*1024, sizeof(mathfu::mat4)); - m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer("M2 FragmentData", 1024*1024, sizeof(M2::modelWideBlockPS)); - m2Buffers.m2InstanceData = m_device->createSSBOBuffer("M2 InstanceData", 1024*1024, sizeof(M2::M2InstanceRecordBindless)); - m2Buffers.meshWideBlocks = m_device->createSSBOBuffer("M2 MeshWide", 1024*1024, sizeof(M2::meshWideBlockVSPS)); - m2Buffers.meshWideBlocksBindless = m_device->createSSBOBuffer("M2 MeshWide Bindless", 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); + m2Buffers.placementMatrix = m_device->createSSBOBuffer(un("M2 Placement"), 1024*1024, sizeof(M2::PlacementMatrix)); + m2Buffers.boneMatrix = m_device->createSSBOBuffer(un("M2 BoneMatrices"),1024*1024, sizeof(mathfu::mat4)); + m2Buffers.m2Colors = m_device->createSSBOBuffer(un("M2 BoneMatrices"), 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureWeights = m_device->createSSBOBuffer(un("M2 TextureWeight"), 1024*1024, sizeof(mathfu::vec4_packed)); + m2Buffers.textureMatrices = m_device->createSSBOBuffer(un("M2 TextureMatrices"), 1024*1024, sizeof(mathfu::mat4)); + m2Buffers.modelFragmentDatas = m_device->createSSBOBuffer(un("M2 FragmentData"), 1024*1024, sizeof(M2::modelWideBlockPS)); + m2Buffers.m2InstanceData = m_device->createSSBOBuffer(un("M2 InstanceData"), 1024*1024, sizeof(M2::M2InstanceRecordBindless)); + m2Buffers.meshWideBlocks = m_device->createSSBOBuffer(un("M2 MeshWide"), 1024*1024, sizeof(M2::meshWideBlockVSPS)); + m2Buffers.meshWideBlocksBindless = m_device->createSSBOBuffer(un("M2 MeshWide Bindless"), 1024*1024, sizeof(M2::meshWideBlockVSPS_Bindless)); } //Create adt Shader buffs { - adtBuffers.adtMeshWideVSPSes = m_device->createSSBOBuffer("ADT MeshVSPS", 1024*1024, sizeof(ADT::meshWideBlockVSPS)); - adtBuffers.adtMeshWidePSes = m_device->createSSBOBuffer("ADT MeshPS", 1024*1024, sizeof(ADT::meshWideBlockPS)); - adtBuffers.adtInstanceDatas = m_device->createSSBOBuffer("ADT InstanceData", 1024*1024, sizeof(ADT::AdtInstanceData)); + adtBuffers.adtMeshWideVSPSes = m_device->createSSBOBuffer(un("ADT MeshVSPS"), 1024*1024, sizeof(ADT::meshWideBlockVSPS)); + adtBuffers.adtMeshWidePSes = m_device->createSSBOBuffer(un("ADT MeshPS"), 1024*1024, sizeof(ADT::meshWideBlockPS)); + adtBuffers.adtInstanceDatas = m_device->createSSBOBuffer(un("ADT InstanceData"), 1024*1024, sizeof(ADT::AdtInstanceData)); } //Create wmo Shader buffs { - wmoBuffers.wmoPlacementMats = m_device->createSSBOBuffer("WMO PlaceMat", 1024*1024, sizeof(mathfu::mat4)); - wmoBuffers.wmoMeshWideVSes = m_device->createSSBOBuffer("WMO MeshWideVS", 1024*1024, sizeof(WMO::meshWideBlockVS)); - wmoBuffers.wmoMeshWidePSes = m_device->createSSBOBuffer("WMO MeshWidePS", 1024*1024, sizeof(WMO::meshWideBlockPS)); - wmoBuffers.wmoMeshWideBindless = m_device->createSSBOBuffer("WMO MeshWideBindless", 1024*1024, sizeof(WMO::meshWideBlockBindless)); - wmoBuffers.wmoPerMeshData = m_device->createSSBOBuffer("WMO PerMeshData", 1024*1024, sizeof(WMO::perMeshData)); - wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer("Scene_VBO_WMOAmbient",16*200, sizeof(mathfu::vec4_packed)); + wmoBuffers.wmoPlacementMats = m_device->createSSBOBuffer(un("WMO PlaceMat"), 1024*1024, sizeof(mathfu::mat4)); + wmoBuffers.wmoMeshWideVSes = m_device->createSSBOBuffer(un("WMO MeshWideVS"), 1024*1024, sizeof(WMO::meshWideBlockVS)); + wmoBuffers.wmoMeshWidePSes = m_device->createSSBOBuffer(un("WMO MeshWidePS"), 1024*1024, sizeof(WMO::meshWideBlockPS)); + wmoBuffers.wmoMeshWideBindless = m_device->createSSBOBuffer(un("WMO MeshWideBindless"), 1024*1024, sizeof(WMO::meshWideBlockBindless)); + wmoBuffers.wmoPerMeshData = m_device->createSSBOBuffer(un("WMO PerMeshData"), 1024*1024, sizeof(WMO::perMeshData)); + wmoBuffers.wmoGroupAmbient = m_device->createSSBOBuffer(un("Scene_VBO_WMOAmbient"),16*200, sizeof(mathfu::vec4_packed)); } //Create water buffs { - waterBuffer.waterDataBuffer = m_device->createSSBOBuffer("Water data", 1024, sizeof(Water::meshWideBlockPS)); - waterBuffer.waterBindlessBuffer = m_device->createSSBOBuffer("Water Bindless", 1024, sizeof(Water::WaterBindless)); + waterBuffer.waterDataBuffer = m_device->createSSBOBuffer(un("Water data"), 1024, sizeof(Water::meshWideBlockPS)); + waterBuffer.waterBindlessBuffer = m_device->createSSBOBuffer(un("Water Bindless"), 1024, sizeof(Water::WaterBindless)); } - m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer("M2 Waterfall Common",200, sizeof(M2::WaterfallData::WaterfallCommon)); - m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer("M2 Waterfall Bindless",200, sizeof(M2::WaterfallData::WaterfallBindless)); + m2WaterfallBuffer.waterfallCommon = m_device->createSSBOBuffer(un("M2 Waterfall Common"),200, sizeof(M2::WaterfallData::WaterfallCommon)); + m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer(un("M2 Waterfall Bindless"),200, sizeof(M2::WaterfallData::WaterfallBindless)); - pointLightBuffer = m_device->createSSBOBuffer("Point Light Buffer",200, sizeof(LocalLight)); - spotLightBuffer = m_device->createSSBOBuffer("Spot Light Buffer",200, sizeof(Spotlight)); + pointLightBuffer = m_device->createSSBOBuffer(un("Point Light Buffer"),200, sizeof(LocalLight)); + spotLightBuffer = m_device->createSSBOBuffer(un("Spot Light Buffer"),200, sizeof(Spotlight)); - uboBuffer = m_device->createUniformBuffer("UBO Buffer", 1024*1024); - uboStaticBuffer = m_device->createUniformBuffer("UBO Static", 1024*1024); + uboBuffer = m_device->createUniformBuffer(un("UBO Buffer"), 1024*1024); + uboStaticBuffer = m_device->createUniformBuffer(un("UBO Static"), 1024*1024); m_emptyADTVAO = createADTVAO(vboAdtBuffer, iboBuffer); m_emptyM2VAO = createM2VAO(vboM2Buffer, iboBuffer); @@ -229,9 +236,9 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, .ubo_dynamic(0, sceneWideChunk) .texture(1, hDevice->getBlackTexturePixel()) //Untill AO is ready. -#ifndef NDEBUG +//#ifndef NDEBUG .texture(2, hDevice->getWhiteTexturePixel()) -#endif +//#endif ; sceneWideDS = ds; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 8467757e2..652c63caa 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -151,7 +151,7 @@ static const PipelineTemplate s_lightBufferPipelineT = { false, true, EGxBlendEnum::GxBlend_Add, - true, + false, false, 0xFF }; From c181a5512c33cf4ba1c7b3a64af4882e183adfda Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 4 Apr 2024 12:26:27 +0300 Subject: [PATCH 184/212] - fix memory leak in quick links --- src/ui/childWindow/sceneWindow/SceneWindow.cpp | 2 +- src/ui/childWindow/sceneWindow/SceneWindow.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index ffd2bfaf2..8576edcee 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -266,7 +266,7 @@ void SceneWindow::unload() { std::shared_ptr SceneWindow::getLastPlan() { return (m_sceneRenderer) ? m_sceneRenderer->getLastCreatedPlan() : nullptr; } -const std::shared_ptr SceneWindow::getCamera() { +const std::shared_ptr &SceneWindow::getCamera() { if (m_currentCameraIndex >= 0 && m_currentCameraIndex <= m_cameraList.size()) { return m_cameraList[m_currentCameraIndex]; } diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 202acdd4d..0ea51defd 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -34,7 +34,7 @@ class SceneWindow { void unload(); std::shared_ptr getLastPlan(); - const std::shared_ptr getCamera(); + const std::shared_ptr &getCamera(); bool hasRenderer(); std::shared_ptr createRenderView(); From 946b57e8028d810c5fe4d09bd9f6997a74a908a3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 8 Apr 2024 10:36:32 +0300 Subject: [PATCH 185/212] - SpotLight first version implemented --- src/minimapGenerator/minimapGenerator.cpp | 4 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- .../glsl/bindless/adt/adtShader_text.glsl | 14 +- .../glsl/bindless/lights/pointLight.frag | 28 +- .../glsl/bindless/lights/spotLight.frag | 86 + .../glsl/bindless/lights/spotLight.vert | 45 +- .../glsl/bindless/m2/m2shader_text.glsl | 3 +- .../glsl/bindless/water/waterShader.frag | 3 +- .../waterfall/waterFallShader_text.glsl | 3 +- .../glsl/bindless/wmo/wmoshader_text.glsl | 3 +- .../glsl/common/commonLightFunctions.glsl | 12 +- .../glsl/forwardRendering/adtShader.frag | 3 +- .../glsl/forwardRendering/m2Shader.frag | 3 +- .../glsl/forwardRendering/waterShader.frag | 4 +- .../forwardRendering/waterfallShader.frag | 3 +- .../glsl/forwardRendering/wmoShader.frag | 3 +- .../src/engine/objects/SceneObjectWithID.h | 9 +- .../src/engine/objects/ViewsObjects.cpp | 13 +- .../src/engine/objects/ViewsObjects.h | 6 +- .../engine/objects/lights/CWmoNewLight.cpp | 101 +- .../src/engine/objects/lights/CWmoNewLight.h | 30 +- .../src/engine/objects/m2/m2Object.cpp | 2 + wowViewerLib/src/engine/objects/m2/m2Object.h | 44 +- .../objects/scenes/EntityActorsFactory.h | 10 +- .../src/engine/objects/scenes/m2Scene.cpp | 4 +- .../src/engine/objects/scenes/map.cpp | 41 +- .../src/engine/objects/wdl/wdlObject.cpp | 2 +- .../engine/objects/wdt/wdtLightsObject.cpp | 35 +- .../src/engine/objects/wdt/wdtLightsObject.h | 6 +- .../src/engine/objects/wmo/wmoGroupObject.cpp | 2 +- .../src/engine/objects/wmo/wmoGroupObject.h | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../persistance/header/commonFileStructs.h | 9 + .../engine/persistance/header/wmoFileHeader.h | 4 +- .../src/engine/persistance/wdtLightFile.cpp | 2 +- .../src/engine/persistance/wdtLightFile.h | 19 +- .../src/engine/shader/ShaderDefinitions.h | 1508 +++++++---------- .../src/gapi/UniformBufferStructures.h | 6 +- .../src/gapi/interface/meshes/IMesh.h | 4 +- wowViewerLib/src/include/config.h | 2 +- .../src/renderer/mapScene/MapScenePlan.h | 2 +- .../renderer/mapScene/MapSceneRenderer.cpp | 9 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 64 +- .../vulkan/MapSceneRenderBindlessVLK.h | 7 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../vulkan/materials/IMaterialInstance.h | 1 + .../vulkan/view/RenderViewDeferredVLK.cpp | 82 +- .../vulkan/view/RenderViewDeferredVLK.h | 14 +- 48 files changed, 1210 insertions(+), 1055 deletions(-) diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index b8c45ddb6..cf9501a80 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -570,8 +570,8 @@ void MinimapGenerator::calcBB(const HMapRenderPlan &mapRenderPlan, mathfu::vec3 minCoord = mathfu::vec3(20000, 20000, 20000); maxCoord = mathfu::vec3(-20000, -20000, -20000); - for (auto &m2Object: mapRenderPlan->m2Array.getDrawn()) { - auto objBB = m2Object->getAABB(); + for (auto &m2ObjectId: mapRenderPlan->m2Array.getDrawn()) { + auto objBB = m2Factory.getObjectById(m2ObjectId)->getAABB(); if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 0172a7e83..9915659d7 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -35,7 +35,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { private: HGDeviceVLK m_device; - std::shared_ptr> meshFactory = std::make_shared>(); + std::shared_ptr> meshFactory = std::make_shared>(); std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator //and seed it with entropy. diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl index a89f0bede..b202aa6f3 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -5,7 +5,7 @@ precision highp int; #include "../../common/commonFogFunctions.glsl" #include "../../common/commonADTMaterial.glsl" -#include "../../../common/commonUboSceneData.glsl" +#include "../../common/commonUboSceneData.glsl" #include "../../common/commonAdtIndirectDescriptorSet.glsl" //ADT is always opaque @@ -99,8 +99,13 @@ void main() { #ifndef DEFERRED vec3 accumLight = vVertexLighting.rgb; - if (scene.uSceneSize_DisableLightBuffer.z == 0.0 ) { - accumLight = texture(lightBuffer, (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy)).xyz; + float ao = 0.0; + { + vec2 screenUV = (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy); + if (scene.uSceneSize_DisableLightBuffer.z == 0.0) { + accumLight = texture(lightBuffer, screenUV).xyz; + } + ao = texture(aoBuffer, screenUV).x; } finalColor = vec4( @@ -114,7 +119,8 @@ void main() { accumLight, /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ - vec3(0.0) /* emissive */ + vec3(0.0), /* emissive */ + ao /* ambient occlusion */ ), 1.0 ); diff --git a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag index edd3dc85c..2c52c66c1 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag +++ b/wowViewerLib/shaders/glsl/bindless/lights/pointLight.frag @@ -60,28 +60,12 @@ void main() { float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0)); - vec3 attenuatedColor = attenuation * lightRec.innerColor.xyz; + vec4 blendParams = lightRec.blendParams; + float colorLerp = smoothstep(blendParams.y, blendParams.x, distanceToLight); + vec3 lerp = mix(lightRec.outerColor.xyz, lightRec.innerColor.xyz, vec3(colorLerp)); + + vec3 attenuatedColor = attenuation * lerp; vec3 lightColor = vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ); outColor = vec4(vec3(lightColor), 1.0); -} - -//void test() { -//t391 = cb_local_light_data.cb_localLightData.c_lights[index_388]; -//float3 vectorToLight_394 = (t391.position.xyz - t376); -//float distanceToLightSqr_395 = dot(vectorToLight_394, vectorToLight_394); -//float distanceToLightInv_396 = rsqrt(distanceToLightSqr_395); -//float distanceToLight_397 = (distanceToLightSqr_395 * distanceToLightInv_396); -//float dot_398 = dot(vectorToLight_394, normalize_366); -//float diffuseTerm_400 = fmax((dot_398 * distanceToLightInv_396), 0.0f); -//float4 t401 = t391.attenuation; -//float saturate_406 = saturate(((distanceToLight_397 - t401.x) * t401.z)); -//float attenuation_407 = (1.0f - saturate_406); -//float4 t408 = t391.blendParams; -//float colorLerp_411 = smoothstep(t408.y, t408.x, distanceToLight_397); -//float3 lerp_417 = mix(t391.outerColor.xyz, t391.innerColor.xyz, float3(colorLerp_411)); -//float3 color_421 = (color_389 + (((lerp_417 * attenuation_407) * (lerp_417 * attenuation_407)) * diffuseTerm_400)); -//); -// -// -//1.0f - (x - attStart) * (1.) \ No newline at end of file +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag index e69de29bb..f88d526f1 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag +++ b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag @@ -0,0 +1,86 @@ +#version 450 + +#extension GL_GOOGLE_include_directive: require +//#extension GL_EXT_debug_printf : enable + +precision highp float; +precision highp int; + +#include "../../common/commonUboSceneData.glsl" +#include "../../common/commonLightFunctions.glsl" + +layout(location = 0) in flat int lightIndex; + +layout(std430, set=1, binding=0) buffer readonly spotLightBuffer { + SpotLight lights[]; +}; + +layout(set=1, binding=1) uniform sampler2D depthTex; +layout(set=1, binding=2) uniform sampler2D normalTex; +layout(std140, set=1, binding=3) uniform pointLightBuffer { + vec4 screenSize; +}; + +layout(location = 0) out vec4 outColor; + +void main() { + SpotLight lightRec = lights[lightIndex]; + + vec2 uv = gl_FragCoord.xy / screenSize.xy; + + vec3 viewNormal = texture(normalTex, uv).rgb * 2.0 - vec3(1.0); + float sceneDepth = texture(depthTex, uv).r; + + float z = (sceneDepth - 0.06f) / (1.0f - 0.06f) ; + + vec4 viewPos = inverse(scene.uPMatrix) * vec4(uv.xy * 2.0 - 1.0, z, 1.0); + viewPos.xyz = viewPos.xyz / viewPos.w; + +// vec3 viewRay = vec3((in_viewPos.xy / vec2(in_viewPos.z)), 1.0); +// vec3 viewPos = (viewRay * sceneDepth); + + vec3 lightDir = -(transpose(inverse(scene.uLookAtMat)) * vec4(lightRec.directionAndcosAngleDiff.xyz, 0.0)).xyz; + vec3 lightAtten = lightRec.attenuationAndcosOuterAngle.xyz; + + vec3 color = lightRec.colorAndFalloff.xyz; + float cosOuterAngle = lightRec.attenuationAndcosOuterAngle.w; + + vec3 lightPos = (scene.uLookAtMat * vec4(lightRec.positionAndcosInnerAngle.xyz, 1.0)).xyz; + float cosInnerAngle = lightRec.positionAndcosInnerAngle.w; + float falloff = lightRec.colorAndFalloff.w; + + float cosAngleDiffInv = lightRec.directionAndcosAngleDiff.w; + + vec3 vectorToLight = (lightPos.xyz - viewPos.xyz); + + float distanceToLightSqr = dot(vectorToLight, vectorToLight); + float distanceToLightInv = inversesqrt(distanceToLightSqr); + float diffuseTerm = max((dot(vectorToLight, viewNormal.xyz) * distanceToLightInv), 0.0); + + float ld = max(dot(lightDir, -(vectorToLight)), 0.0); + float attenuation = (1.0 - clamp(((ld - lightAtten.x) * lightAtten.z), 0.0, 1.0)); + ld = max(dot(lightDir, (-(vectorToLight) * distanceToLightInv)), 0.0); + + float spotLightEffect; + if ((ld < cosOuterAngle)) + { + spotLightEffect = 0.0; + } + else if ((ld <= cosInnerAngle)) + { + spotLightEffect = pow(abs(((ld - cosOuterAngle) * cosAngleDiffInv)), falloff); + } else { + spotLightEffect = 1.0; + } + + vec3 finalColor = ((((color * attenuation) * (color * attenuation)) * diffuseTerm) * spotLightEffect); +// if ((lightRec.interior.x != 0.0)) +// { +// vec3 finalColor = (t597 * t668.www); +// color_688 = color_644; +// } + + outColor = vec4(finalColor, 1.0); +// outColor = vec4(1.0, 1.0, 1.0, 1.0); +// outColor = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert index 98c531608..b464d2e6c 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert +++ b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.vert @@ -1,5 +1,44 @@ -#version 120 +#version 450 -void main() { - gl_Position = vec4(vec3(0.0), 1.0); +#extension GL_GOOGLE_include_directive: require +#extension GL_ARB_shader_draw_parameters: require + +precision highp float; +precision highp int; + +#include "../../common/commonUboSceneData.glsl" + +layout (location = 0) in vec2 position; + +layout(std430, set=1, binding=0) buffer readonly spotLightBuffer { + SpotLight lights[]; +}; + +layout(location = 0) out flat int lightIndex; + +vec3 quat_transform( vec4 q, vec3 v ) +{ + return v + 2.*cross( q.xyz, cross( q.xyz, v ) + q.w*v ); } + +void main() { + SpotLight lightRec = lights[gl_InstanceIndex]; + + vec3 lightAtten = lightRec.attenuationAndcosOuterAngle.xyz; + vec4 vertPos = vec4(position * lightAtten.y, 0.0, 1.0); + + if (gl_VertexIndex > 0) { + vertPos.z += lightRec.spotLightLen.x; + } + + //Do rotation of cone +// vertPos.xyz = quat_transform(lightRec.rotQuaternion, vertPos.xyz); + vertPos.xyz = (lightRec.rotMat * vec4(vertPos.xyz, 0.0)).xyz; + vertPos.xyz = vertPos.xyz + lightRec.positionAndcosInnerAngle.xyz; + + //And world to view transform + vec4 viewPos = scene.uLookAtMat * vertPos; + + gl_Position = scene.uPMatrix * viewPos; + lightIndex = gl_InstanceIndex; +} \ No newline at end of file diff --git a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl index 1680a7013..df2af5ecb 100644 --- a/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/m2/m2shader_text.glsl @@ -151,7 +151,8 @@ void main() { accumLight, vec3(0.0), specular, - vec3(0.0) + vec3(0.0), + 1.0 /* ao */ ) , finalOpacity ); diff --git a/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag index 362eb7c29..660525fc2 100644 --- a/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag @@ -128,7 +128,8 @@ void main() { vec3(0.0) /*accumLight*/, vec3(0.0), vec3(0.0), /* specular */ - vec3(0.0) + vec3(0.0), + 1.0 /* ao */ ), 1.0 ); diff --git a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl index 44c32f290..a57516d49 100644 --- a/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/waterfall/waterFallShader_text.glsl @@ -95,7 +95,8 @@ void main() { vec3(0.0), /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ - vec3(0.0) /* emissive */ + vec3(0.0), /* emissive */ + 1.0 /* ao */ ); float w_clamped = clamp((1.0f - mask_val_0.w) * waterfallCommon.values1.w, 0.0f, 1.0f); diff --git a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl index 9c7c6be1e..06b24f34b 100644 --- a/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/wmo/wmoshader_text.glsl @@ -94,7 +94,8 @@ void main() { accumLight /*accumLight*/, vColor.rgb, spec, /* specular */ - emissive + emissive, + 1.0 /* ao */ ), finalOpacity ); diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index 71312fea9..c603ab3bf 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -10,10 +10,12 @@ struct LocalLight vec4 blendParams; }; -struct Spotlight +struct SpotLight { +// vec4 rotQuaternion; + mat4 rotMat; + vec4 spotLightLen; vec4 colorAndFalloff; - vec4 outercolor; vec4 positionAndcosInnerAngle; vec4 attenuationAndcosOuterAngle; vec4 directionAndcosAngleDiff; @@ -73,7 +75,9 @@ vec3 calcLight( const in SceneWideParams sceneParams, const in InteriorLightParam intLight, const in vec3 accumLight, const in vec3 precomputedLight, const in vec3 specular, - const in vec3 emissive) { + const in vec3 emissive, + const in float ao +) { vec3 result = matDiffuse; if (applyLight) { @@ -129,7 +133,7 @@ vec3 calcLight( result = sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) + emTerm; } - return result + specular; + return (result + specular) * ao; } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 8694ac3e1..079307538 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -93,7 +93,8 @@ void main() { vVertexLighting.rgb, /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ - vec3(0.0) /* emissive */ + vec3(0.0), /* emissive */ + 1.0 /* ao */ ), 1.0 ); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag index 075ff2922..3bca8a5c0 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/m2Shader.frag @@ -151,7 +151,8 @@ void main() { accumLight, vec3(0.0), specular, - vec3(0.0) + vec3(0.0), + 1.0 /* ao */ ) , finalOpacity ); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index e0d946076..23ca678e8 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -119,7 +119,9 @@ void main() { vec3(0.0) /*accumLight*/, vec3(0.0), vec3(0.0), /* specular */ - vec3(0.0) + vec3(0.0), + 1.0 /* ao */ + ), 1.0 ); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag index deafcb8d4..9e975cd39 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterfallShader.frag @@ -101,7 +101,8 @@ void main() { vec3(0.0), /* accumLight */ vec3(0.0), /*precomputedLight*/ vec3(0.0), /* specular */ - vec3(0.0) /* emissive */ + vec3(0.0), /* emissive */ + 1.0 /* ao */ ); float w_clamped = clamp((1.0f - mask_val_0.w) * values1.w, 0.0f, 1.0f); diff --git a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag index c7e9f1107..2a09f9de2 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/wmoShader.frag @@ -80,7 +80,8 @@ void main() { vec3(0.0) /*accumLight*/, vColor.rgb, spec, /* specular */ - emissive + emissive, + 1.0 /* ao */ ), finalOpacity ); diff --git a/wowViewerLib/src/engine/objects/SceneObjectWithID.h b/wowViewerLib/src/engine/objects/SceneObjectWithID.h index 08e8b6c5f..912750321 100644 --- a/wowViewerLib/src/engine/objects/SceneObjectWithID.h +++ b/wowViewerLib/src/engine/objects/SceneObjectWithID.h @@ -5,19 +5,20 @@ #ifndef AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H #define AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H +template class ObjectWithId { - template friend class EntityFactory; + template friend class EntityFactory; public: ObjectWithId() { } virtual ~ObjectWithId() = default; - int getObjectId() { return m_id;} + ObjIdType getObjectId() { return m_id;} private: - void setId(int id) {m_id = id;}; + void setId(ObjIdType id) {m_id = id;}; - int m_id = -1; + ObjIdType m_id = ObjIdType(-1); }; #endif //AWEBWOWVIEWERCPP_SCENEOBJECTWITHID_H diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 07dd303b6..b34606906 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -36,7 +36,7 @@ void GeneralView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool rende } } } -void GeneralView::collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights) { +void GeneralView::collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights) { for (auto &wmoGroup: wmoGroupArray.getToDraw()) { auto &wmoPointLights = wmoGroup->getPointLights(); @@ -72,7 +72,7 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD [&](tbb::blocked_range r) { //for (int i = 0; i < candidatesArr.size(); i++) { #if (__AVX__ && __SSE2__) - ObjectCullingSEE>::cull(this->frustumData, r.begin(), + ObjectCullingSEE::cull(this->frustumData, r.begin(), r.end(), candidatesArr, candCullRes); #else @@ -85,14 +85,15 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD for (int i = 0; i < candCullRes.size(); i++) { if (!candCullRes[i]) { - auto &m2ObjectCandidate = candidatesArr[i]; + const auto m2ObjectCandidate = m2Factory.getObjectById(candidatesArr[i]); setM2Lights(m2ObjectCandidate); - this->m2List.addToDraw(m2ObjectCandidate); + if (m2ObjectCandidate != nullptr) + this->m2List.addToDraw(m2ObjectCandidate); } } } -void GeneralView::setM2Lights(const std::shared_ptr &m2Object) { +void GeneralView::setM2Lights(M2Object *m2Object) { m2Object->setUseLocalLighting(false); } @@ -185,7 +186,7 @@ void GeneralView::collectPortalMeshes(framebased::vector &transp } } -void InteriorView::setM2Lights(const std::shared_ptr &m2Object) { +void InteriorView::setM2Lights(M2Object *m2Object) { if (ownerGroupWMO == nullptr || !ownerGroupWMO->getIsLoaded()) return; if (ownerGroupWMO->getDontUseLocalLightingForM2()) { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 7481ca29e..1ad39c3a8 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -57,9 +57,9 @@ class GeneralView { framebased::vector liquidMeshes = {}; virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); - virtual void collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights); + virtual void collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights); void collectPortalMeshes(framebased::vector &transparentMeshes); - virtual void setM2Lights(const std::shared_ptr &m2Object); + virtual void setM2Lights(M2Object *m2Object); void produceTransformedPortalMeshes(const HMapSceneBufferCreate &sceneRenderer, const HApiContainer &apiContainer, const std::vector> &portalsVerts, bool isAntiportal = false); @@ -70,7 +70,7 @@ class InteriorView : public GeneralView { public: std::vector portalIndexes; std::shared_ptr ownerGroupWMO = {}; //Wmos which portals belong to - void setM2Lights(const std::shared_ptr &m2Object) override; + void setM2Lights(M2Object *m2Object) override; }; class ExteriorView : public GeneralView { diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp index e48bc15b2..d44fd87e2 100644 --- a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp @@ -3,10 +3,14 @@ // #include "CWmoNewLight.h" +#include "../../algorithms/mathHelper.h" CWmoNewLight::CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_light_def &newLightDef) { isPointLight = newLightDef.type == 0; isSpotLight = newLightDef.type == 1; + isWmoNewLight = true; + + flags_raw = 0; m_innerColor = newLightDef.innerColor; m_pos = (modelMatrix * mathfu::vec4(mathfu::vec3(newLightDef.position), 1.0)).xyz(); @@ -15,27 +19,50 @@ CWmoNewLight::CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_ m_attenuationEnd = newLightDef.attenEnd; m_intensity = newLightDef.intensity; m_outerColor = newLightDef.outerColor; - m_spotLightAttenuationStart = newLightDef.spotLightAttenuationStart; - m_spotLightAttenuationEnd = newLightDef.spotLightAttenuationEnd; + m_falloffStart = newLightDef.falloffStart; + m_falloff = newLightDef.falloff; m_spotlightRadius = newLightDef.spotlightRadius; m_innerAngle = newLightDef.innerAngle; m_outerAngle = newLightDef.outerAngle; + + rot_mat = + MathHelper::RotationZ((m_rotation.z)) * + MathHelper::RotationY((m_rotation.y)) * + MathHelper::RotationX((m_rotation.x)); + calcedLightDir = ((modelMatrix * rot_mat).Inverse().Transpose()*mathfu::vec4(0,0,-1,0)); +} + +CWmoNewLight::CWmoNewLight(const WdtLightFile::MapSpotLight &mapSpotLight ) { + isPointLight = false; + isSpotLight = true; + isWmoNewLight = false; + + flags_raw = 0; + + m_spotlightRadius = mapSpotLight.spotlightRadius; + m_innerAngle = mapSpotLight.innerAngle; + m_outerAngle = mapSpotLight.outerAngle; + m_innerColor = mapSpotLight.color; + m_outerColor = mapSpotLight.color; + m_pos = mapSpotLight.position; + m_attenuationStart = mapSpotLight.attenuationStart; + m_attenuationEnd = mapSpotLight.attenuationEnd; + m_intensity = mapSpotLight.intensity; + m_rotation = mapSpotLight.rotation; + + rot_mat = + MathHelper::RotationZ((m_rotation.z)) * + MathHelper::RotationY((m_rotation.y)) * + MathHelper::RotationX((m_rotation.x)); + calcedLightDir = (rot_mat).Inverse().Transpose()*mathfu::vec4(0,0,-1,0); } -void CWmoNewLight::collectLight(std::vector &pointLights, std::vector &spotLights) { +void CWmoNewLight::collectLight(std::vector &pointLights, std::vector &spotLights) { if (isPointLight) { auto &pointLight = pointLights.emplace_back(); //TODO: implement flickering animation - pointLight.innerColor = mathfu::vec4( - ((float)m_innerColor.r)/255.0f, - ((float)m_innerColor.g)/255.0f, - ((float)m_innerColor.b)/255.0f, - 0); - pointLight.outerColor = mathfu::vec4( - ((float)m_outerColor.r)/255.0f, - ((float)m_outerColor.g)/255.0f, - ((float)m_outerColor.b)/255.0f, - 0);; + pointLight.innerColor = ImVectorToVec4(m_innerColor) * m_intensity; + pointLight.outerColor = ImVectorToVec4(m_outerColor) * m_intensity; pointLight.blendParams.x = m_attenuationStart; pointLight.blendParams.y = m_attenuationEnd; @@ -44,6 +71,54 @@ void CWmoNewLight::collectLight(std::vector &pointLights, std::vecto pointLight.position = mathfu::vec4(mathfu::vec3(m_pos), 1.0); } else if (isSpotLight) { + auto &spotLight = spotLights.emplace_back(); +// auto rotQuat = mathfu::quat::FromEulerAngles(m_rotation.x, m_rotation.y, m_rotation.z); + + if (true) { + auto rotQuatD = mathfu::quat::FromMatrix( + rot_mat + ); + +// assert(rotQuatD.vector() == rotQuat.vector() && rotQuatD.scalar() == rotQuat.scalar()); +// rotQuat = rotQuatD; + } + + spotLight.rotMat = rot_mat; +// spotLight.rotQuaternion = mathfu::vec4( +// rotQuat[1], rotQuat[2],rotQuat[3], rotQuat[0] +// ); + spotLight.spotLightLen = mathfu::vec4( + tanf(m_outerAngle * 0.5f) * m_attenuationEnd + 0.8,0,0,0 + ); + float l_falloffStart = 0.0f; + if (flags.FLAG_OUTERCOLOR_IS_MAIN) { + spotLight.colorAndFalloff = mathfu::vec4( + ImVectorToVec4(m_outerColor).xyz() * m_intensity, m_falloff + ); + l_falloffStart = m_falloffStart; + } else { + spotLight.colorAndFalloff = mathfu::vec4( + ImVectorToVec4(m_innerColor).xyz() * m_intensity, m_attenuationEnd + ); + l_falloffStart = m_attenuationStart; + } + spotLight.positionAndcosInnerAngle = mathfu::vec4( + mathfu::vec3(m_pos), cosf(m_innerAngle * 0.5f) + ); + spotLight.attenuationAndcosOuterAngle = mathfu::vec4( + m_attenuationStart, m_attenuationEnd, 1.0f / (m_attenuationEnd - m_attenuationStart), + cosf(m_outerAngle * 0.5f) + ); + spotLight.directionAndcosAngleDiff = mathfu::vec4( + calcedLightDir.xyz(), + 1.0f/fmaxf(cosf(m_innerAngle * 0.5f) - cosf(m_outerAngle * 0.5f), 0.0099999f) + ); + spotLight.interior = mathfu::vec4( + isWmoNewLight ? 0.0f : 1.0f, + l_falloffStart, + 0.0f, + 0.0f + ); } } diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h index 0c137e59e..855e1fcd1 100644 --- a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h @@ -7,30 +7,52 @@ #include #include "../../persistance/header/wmoFileHeader.h" +#include "../../persistance/wdtLightFile.h" #include "../../../gapi/UniformBufferStructures.h" class CWmoNewLight { public: + CWmoNewLight(){}; CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_light_def &newLightDef ); + CWmoNewLight(const WdtLightFile::MapSpotLight &mapSpotLight ); - void collectLight(std::vector &pointLights, std::vector &spotLights); + void collectLight(std::vector &pointLights, std::vector &spotLights); private: bool isPointLight; bool isSpotLight; + bool isWmoNewLight; + union { + uint32_t flags_raw; + struct + { + uint32_t FLAG_OUTERCOLOR_IS_MAIN : 1; + uint32_t FLAG_2 : 1; + uint32_t FLAG_4 : 1; + uint32_t FLAG_8 : 1; + uint32_t FLAG_10 : 1; + uint32_t FLAG_20 : 1; + uint32_t FLAG_40 : 1; + } flags; + }; + CImVector m_innerColor; C3Vector m_pos; C3Vector m_rotation; float m_attenuationStart; float m_attenuationEnd; - float m_intensity; + float m_intensity = 1.0f; CImVector m_outerColor; - float m_spotLightAttenuationStart; - float m_spotLightAttenuationEnd; + float m_falloffStart; + float m_falloff; float m_spotlightRadius; float m_innerAngle; float m_outerAngle; + + mathfu::mat4 rot_mat; + mathfu::vec4 calcedLightDir; + }; #endif //AWEBWOWVIEWERCPP_CWMONEWLIGHT_H diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index edb5f428a..69e39310e 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -2129,3 +2129,5 @@ void M2Object::resetReplaceParticleColor() { int M2Object::getCurrentAnimationIndex() { return m_animationManager->getCurrentAnimationIndex(); } + +EntityFactory m2Factory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index b2d519995..2b8bef574 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -27,8 +27,8 @@ class M2ObjectListContainer; #include "m2Helpers/CBoneMasterData.h" #include "../../../gapi/UniformBufferStructures.h" - -class M2Object : public ObjectWithId { +enum class M2ObjId : int; +class M2Object : public ObjectWithId { public: friend class IExporter; @@ -314,14 +314,24 @@ class M2Object : public ObjectWithId { #include "../../algorithms/mathHelper.h" #include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" +#include "../scenes/EntityActorsFactory.h" + +extern EntityFactory m2Factory; template<> inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { return object->getAABB(); } +template<> +inline const CAaBox &retrieveAABB<>(const M2ObjId &objectId) { + return m2Factory.getObjectById(objectId)->getAABB(); +} + + + class M2ObjectListContainer { -using m2Container = framebased::vector>; +using m2Container = framebased::vector; //using m2Container = std::vector>; private: m2Container candidates; @@ -362,10 +372,10 @@ using m2Container = framebased::vector>; if (cand == nullptr) return; if (cand->getHasBoundingBox()) { - candidates.emplace_back() = cand; + candidates.push_back(cand->getObjectId()); candCanHaveDuplicates = true; } else { - toLoadMain.emplace_back() = cand; + toLoadMain.push_back(cand->getObjectId()); toLoadMainCanHaveDuplicates = true; } } @@ -376,16 +386,34 @@ using m2Container = framebased::vector>; } if (toDraw->getGetIsLoaded()) { - drawn.emplace_back() = toDraw; + drawn.push_back(toDraw->getObjectId()); drawnCanHaveDuplicates = true; } else if (!toDraw->isMainDataLoaded()) { - toLoadMain.emplace_back() = toDraw; + toLoadMain.push_back(toDraw->getObjectId()); toLoadMainCanHaveDuplicates = true; } else { - toLoadGeom.emplace_back() = toDraw; + toLoadGeom.push_back(toDraw->getObjectId()); toLoadGeomCanHaveDuplicates = true; } } + + void addToDraw(M2Object * toDraw) { + if (m_locked) { + throw "oops"; + } + + if (toDraw->getGetIsLoaded()) { + drawn.push_back(toDraw->getObjectId()); + drawnCanHaveDuplicates = true; + } else if (!toDraw->isMainDataLoaded()) { + toLoadMain.push_back(toDraw->getObjectId()); + toLoadMainCanHaveDuplicates = true; + } else { + toLoadGeom.push_back(toDraw->getObjectId()); + toLoadGeomCanHaveDuplicates = true; + } + } + void addDrawnAndToLoad(M2ObjectListContainer &anotherList) { if (m_locked) { throw "oops"; diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index d1cece954..38ea92a8a 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -9,8 +9,8 @@ #include #include "../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" -template -class EntityFactory : public std::enable_shared_from_this>{ +template +class EntityFactory : public std::enable_shared_from_this>{ static constexpr int initSize = 1000; public: explicit EntityFactory() { @@ -34,7 +34,7 @@ static constexpr int initSize = 1000; } entity = new T(std::forward(__args)...); - entity->setId(offsetData.offset); + entity->setId((ObjIdType)offsetData.offset); objectCache[offsetData.offset] = entity; } @@ -45,8 +45,8 @@ static constexpr int initSize = 1000; shared->deallocate(offsetData); }); } - T * getObjectById(int id) { - return objectCache[id]; + T * getObjectById(ObjIdType id) { + return objectCache[(int)id]; } void deallocate(const OffsetAllocator::Allocation &alloc) { diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 89ab5d32b..c8c35e81d 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -99,7 +99,7 @@ M2Scene::M2Scene(const HApiContainer &api, const std::string &m2Model) { m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; - auto m2Object = std::make_shared(m_api); + auto m2Object = m2Factory.createObject(m_api); std::vector replaceTextures = {}; std::vector meshIds = {}; m2Object->setLoadParams(0, meshIds, replaceTextures); @@ -118,7 +118,7 @@ M2Scene::M2Scene(const HApiContainer &api, int fileDataId) { m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; - auto m2Object = std::make_shared(m_api); + auto m2Object = m2Factory.createObject(m_api); std::vector replaceTextures = {}; std::vector meshIds = {}; m2Object->setLoadParams(0, meshIds, replaceTextures); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 56776415e..28f727864 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -650,7 +650,7 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp stateForConditions.currentSkyboxIds.push_back(_light.lightSkyboxId); std::shared_ptr skyBox = nullptr; if (perFdidMap[_light.skyBoxFdid] == nullptr) { - skyBox = std::make_shared(m_api, true); + skyBox = m2Factory.createObject(m_api, true); skyBox->setLoadParams(0, {}, {}); skyBox->setModelFileId(_light.skyBoxFdid); @@ -1165,7 +1165,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, // cullStage->m2Array.insert(m2ObjectCandidate); // } #if (__AVX__ && __SSE2__) - ObjectCullingSEE>::cull(frustumData, + ObjectCullingSEE::cull(frustumData, r.begin(), r.end(), candidates, results); #else @@ -1180,7 +1180,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, for (int i = 0; i < candidates.size(); i++) { if (!results[i]) { - auto &m2ObjectCandidate = candidates[i]; + auto m2ObjectCandidate = m2Factory.getObjectById(candidates[i]); exteriorView->m2List.addToDraw(m2ObjectCandidate); } } @@ -1303,6 +1303,9 @@ void Map::checkADTCulling(int i, int j, auto &pointLights = mapRenderPlan->pointLights; pointLights.reserve(pointLights.size() + pointLightsOfAdt.size()); for (auto &pointLight : pointLightsOfAdt) pointLights.push_back(pointLight.getLightRec()); + + //Get spotLights + m_wdtLightObject->collectSpotLights(i, j, mapRenderPlan->spotLights); } } } else if (!m_lockedMap && true) { //(m_wdtfile->mapTileTable->mainInfo[j][i].Flag_HasADT > 0) { @@ -1371,7 +1374,8 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende { ZoneScopedN("Load m2 main"); if (m_api->getConfig()->renderM2) { - for (auto &m2Object: renderPlan->m2Array.getToLoadMain()) { + for (auto &m2ObjectId: renderPlan->m2Array.getToLoadMain()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); } @@ -1380,7 +1384,8 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende { ZoneScopedN("Load m2 geom"); if (m_api->getConfig()->renderM2) { - for (auto &m2Object: renderPlan->m2Array.getToLoadGeom()) { + for (auto &m2ObjectId: renderPlan->m2Array.getToLoadGeom()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); m2ProcessedThisFrame++; @@ -1391,11 +1396,13 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende if (m_api->getConfig()->renderSkyDom) { if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { - for (auto &m2Object: skyboxView->m2List.getToLoadMain()) { + for (auto &m2ObjectId: skyboxView->m2List.getToLoadMain()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); } - for (auto &m2Object: skyboxView->m2List.getToLoadGeom()) { + for (auto &m2ObjectId: skyboxView->m2List.getToLoadGeom()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); } @@ -1484,7 +1491,8 @@ void Map::update(const HMapRenderPlan &renderPlan) { tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; + auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); + if (m2Object == nullptr) continue; m2Object->update(deltaTime, cameraVec3, lookAtMat);\ std::vector localLights; @@ -1501,7 +1509,8 @@ void Map::update(const HMapRenderPlan &renderPlan) { } if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { - for (auto &m2Object : skyBoxView->m2List.getDrawn()) { + for (auto &m2ObjectId : skyBoxView->m2List.getDrawn()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); m2Object->update(deltaTime, cameraVec3, lookAtMat); } } @@ -1545,7 +1554,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; + auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); if (m2Object == nullptr) continue; m2Object->calcDistance(cameraVec3); } @@ -1622,7 +1631,8 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe //Can't be paralleled? auto &drawnM2s = renderPlan->m2Array.getDrawn(); - for (auto &m2Object: drawnM2s) { + for (auto &m2ObjectId: drawnM2s) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object != nullptr) { m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); } @@ -1640,7 +1650,7 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe [&](tbb::blocked_range r) { l_device->setCurrentProcessingFrameNumber(processingFrame); for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; + auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); if (m2Object != nullptr) { m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, renderPlan->frameDependentData); @@ -1662,7 +1672,8 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe { ZoneScopedN("m2SkyboxBuffersUpdate"); if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { - for (auto &m2Object: skyBoxView->m2List.getDrawn()) { + for (auto &m2ObjectId: skyBoxView->m2List.getDrawn()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, renderPlan->frameDependentData); } @@ -1694,7 +1705,7 @@ std::shared_ptr Map::getM2Object(std::string fileName, SMDoodadDef &do if (!it.expired()) { return it.lock(); } else { - auto m2Object = std::make_shared(m_api); + auto m2Object = m2Factory.createObject(m_api); m2Object->setLoadParams(0, {}, {}); m2Object->setModelFileName(fileName); m2Object->createPlacementMatrix(doodadDef); @@ -1712,7 +1723,7 @@ std::shared_ptr Map::getM2Object(int fileDataId, SMDoodadDef &doodadDe if (!it.expired()) { return it.lock(); } else { - auto m2Object = std::make_shared(m_api); + auto m2Object = m2Factory.createObject(m_api); m2Object->setLoadParams(0, {}, {}); m2Object->setModelFileId(fileDataId); m2Object->createPlacementMatrix(doodadDef); diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp index 8281af5b6..ef6d1a9ae 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp @@ -61,7 +61,7 @@ void WdlObject::loadM2s() { auto &msso_rec = m_wdlFile->m_msso[l]; - auto m2Object = std::make_shared(m_api, false, false); + auto m2Object = m2Factory.createObject(m_api, false, false); m2Object->setLoadParams(0, {}, {}); m2Object->setModelFileId(msso_rec.fileDataID); // std::cout << "fileDataID = " << msso_rec.fileDataID << std::endl; diff --git a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp index 3fbd91a9a..09c90aa1c 100644 --- a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp +++ b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.cpp @@ -15,7 +15,7 @@ WdtLightsObject::WdtLightsObject(HApiContainer api, int wdtLgtFileDataId) { } static const std::vector emptyPointLights = {}; -static const std::vector emptySpotLights = {}; +static const std::vector emptySpotLights = {}; const std::vector &WdtLightsObject::getPointLights(uint8_t tileX, uint8_t tileY) { if (m_wdtLightFile->getStatus() != FileStatus::FSLoaded) @@ -29,16 +29,20 @@ const std::vector &WdtLightsObject::getPointLights(uint8_t tileX, u return m_pointLights[tileX][tileY]; } -const std::vector &WdtLightsObject::getSpotLights(uint8_t tileX, uint8_t tileY) { +void WdtLightsObject::collectSpotLights(uint8_t tileX, uint8_t tileY, std::vector &spotLights) { if (m_wdtLightFile->getStatus() != FileStatus::FSLoaded) - return emptySpotLights; + return; if (!m_lightsCreated) { createLightArray(); m_lightsCreated = true; } - return m_spotLights[tileX][tileY]; + std::vector dummyPointLight; + auto &lights = m_spotLights[tileX][tileY]; + for (auto &spotLight : lights) { + spotLight.collectLight(dummyPointLight, spotLights); + } } void WdtLightsObject::createLightArray() { @@ -64,6 +68,29 @@ void WdtLightsObject::createLightArray() { m_pointLights[pointLight3.tileX][pointLight3.tileY].emplace_back() = CPointLight(pointLight3); +// processedLightIds[pointLight3.lightIndex] = &pointLight3; + } + } + + //Create Spot Lights + { +// std::unordered_map processedLightIds; + for (int i = 0; i < m_wdtLightFile->mapSpotLightLen; i++) { + auto &spotLight = m_wdtLightFile->mapSpotLights[i]; + +// { +// auto it = processedLightIds.find(pointLight3.lightIndex); +// bool found = it != processedLightIds.end(); +// if (found) { +// auto duplicateRec = it->second; +// std::cout << "Found duploicate" << std::endl; +// } +// } + + + m_spotLights[spotLight.tileX][spotLight.tileY].emplace_back() = + CWmoNewLight(spotLight); + // processedLightIds[pointLight3.lightIndex] = &pointLight3; } } diff --git a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h index 1f62ca504..9c81768d5 100644 --- a/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h +++ b/wowViewerLib/src/engine/objects/wdt/wdtLightsObject.h @@ -8,7 +8,7 @@ #include "../../ApiContainer.h" #include "../lights/CPointLight.h" -#include "../lights/CSpotLight.h" +#include "../lights/CWmoNewLight.h" class WdtLightsObject { public: @@ -16,7 +16,7 @@ class WdtLightsObject { explicit WdtLightsObject(HApiContainer api, int wdtLgtFileDataId); const std::vector &getPointLights(uint8_t tileX, uint8_t tileY); - const std::vector &getSpotLights(uint8_t tileX, uint8_t tileY); + void collectSpotLights(uint8_t tileX, uint8_t tileY, std::vector &spotLights); private: void createLightArray(); private: @@ -26,7 +26,7 @@ class WdtLightsObject { bool m_lightsCreated = false; std::array, 64>, 64> m_pointLights = {}; - std::array, 64>, 64> m_spotLights = {}; + std::array, 64>, 64> m_spotLights = {}; }; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp index 9bc6f5acd..7a8a2b4e3 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.cpp @@ -866,7 +866,7 @@ void AdjustLighting(const mathfu::vec3 color_in, mathfu::vec3 &color_out_0, uint } } -void WmoGroupObject::assignInteriorParams(const std::shared_ptr &m2Object) { +void WmoGroupObject::assignInteriorParams(M2Object *m2Object) { mathfu::vec4 ambientColor = getAmbientColor(); if (!m2Object->setUseLocalLighting(true)) return; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h index da3d209b3..9d9407932 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoGroupObject.h @@ -62,7 +62,7 @@ class WmoGroupObject { const MathHelper::FrustumCullingData &frustumData); mathfu::vec4 getAmbientColor(); - void assignInteriorParams(const std::shared_ptr &m2Object); + void assignInteriorParams(M2Object *m2Object); bool checkIfInsideGroup(mathfu::vec4 &cameraVec4, mathfu::vec4 &cameraLocal, diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index cf10301e1..321c47b48 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -87,7 +87,7 @@ std::shared_ptr WmoObject::getDoodad(int index) { fileIdMode = true; } - auto m2Object = std::make_shared(m_api); + auto m2Object = m2Factory.createObject(m_api); m2Object->setLoadParams(0, {},{}); if (fileIdMode) { @@ -306,7 +306,7 @@ bool WmoObject::doPostLoad(const HMapSceneBufferCreate &sceneRenderer) { m_modelWideChunk = sceneRenderer->createWMOWideChunk(); if ((mainGeom->skyBoxM2FileName != nullptr && mainGeom->skyBoxM2FileNameLen > 0) || mainGeom->skyboxM2FileId != 0) { - skyBox = std::make_shared(m_api, true); + skyBox = m2Factory.createObject(m_api, true); skyBox->setLoadParams(0, {},{}); if ( mainGeom->skyboxM2FileId != 0) { diff --git a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h index 266758012..aede27c6e 100644 --- a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h +++ b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h @@ -318,6 +318,15 @@ struct CImVector }; using CArgb = CImVector; +inline mathfu::vec4 ImVectorToVec4(const CImVector &color) { + return mathfu::vec4( + ((float)color.r)/255.0f, + ((float)color.g)/255.0f, + ((float)color.b)/255.0f, + ((float)color.a)/255.0f + ); +} + struct C4Plane { union { diff --git a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h index 311ba2dbd..dcae881b0 100644 --- a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h @@ -453,8 +453,8 @@ struct mapobject_new_light_def { float attenEnd; float intensity; CImVector outerColor; - float spotLightAttenuationStart; - float spotLightAttenuationEnd; + float falloffStart; + float falloff; int field_44; Light_texture_animation lightTextureAnimation; LightUnkRecord lightUnkRecord; diff --git a/wowViewerLib/src/engine/persistance/wdtLightFile.cpp b/wowViewerLib/src/engine/persistance/wdtLightFile.cpp index b9954e255..fcbdc7b44 100644 --- a/wowViewerLib/src/engine/persistance/wdtLightFile.cpp +++ b/wowViewerLib/src/engine/persistance/wdtLightFile.cpp @@ -22,7 +22,7 @@ chunkDef WdtLightFile::wdtLightFileTable = { [](WdtLightFile &file, ChunkData &chunkData) { debuglog("Entered MSLT"); file.mapSpotLightLen = (chunkData.chunkLen / sizeof(MapSpotLight)); - chunkData.readValues(file.mapSpotLights3, file.mapSpotLightLen); + chunkData.readValues(file.mapSpotLights, file.mapSpotLightLen); } } }, diff --git a/wowViewerLib/src/engine/persistance/wdtLightFile.h b/wowViewerLib/src/engine/persistance/wdtLightFile.h index e5623d447..4ce896538 100644 --- a/wowViewerLib/src/engine/persistance/wdtLightFile.h +++ b/wowViewerLib/src/engine/persistance/wdtLightFile.h @@ -43,16 +43,17 @@ class WdtLightFile : public PersistentFile { uint32_t id; CArgb color; C3Vector position; - float rangeAttenuationStart;// When to start the attenuation of the light, must be <= rangeAttenuationEnd or glitches - float rangeAttenuationEnd; + float attenuationStart; // When to start the attenuation of the light, must be <= attenuationEnd or glitches + float attenuationEnd; float intensity; C3Vector rotation; // radians - float falloffExponent; - float innerRadius; - float outerRadius; // radians - uint16_t tile_x; - uint16_t tile_y; - int16_t unk[2]; // -1 mostly, may be an MLTA ID though. + float spotlightRadius; + float innerAngle; + float outerAngle; // radians + uint16_t tileX; + uint16_t tileY; + uint16_t mlta_index; //Index into MTLA + uint16_t textureIndex; //Index into MTEX }) ; PACK( @@ -65,7 +66,7 @@ class WdtLightFile : public PersistentFile { PointerChecker mapPointLights3 = (mapPointLights3Len); int mapPointLights3Len = 0; - PointerChecker mapSpotLights3 = (mapSpotLightLen); + PointerChecker mapSpotLights = (mapSpotLightLen); int mapSpotLightLen = 0; PointerChecker mapTextureLightAttenuation = (mapTextureLightAttenuationLen); diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index d8abbd223..9cfbab863 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -91,27 +91,27 @@ struct drawPortalShader { }; }; -struct adtShader { +struct drawPoints { enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd + aPosition = 0, drawPointsAttributeEnd }; }; -struct pointLight { +struct adtShader { enum class Attribute { - position = 0, pointLightAttributeEnd + aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd }; }; -struct skyConus { +struct pointLight { enum class Attribute { - aPosition = 0, skyConusAttributeEnd + position = 0, pointLightAttributeEnd }; }; -struct m2Shader { +struct spotLight { enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + position = 0, spotLightAttributeEnd }; }; @@ -133,6 +133,18 @@ struct drawBBShader { }; }; +struct skyConus { + enum class Attribute { + aPosition = 0, skyConusAttributeEnd + }; +}; + +struct m2Shader { + enum class Attribute { + aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd + }; +}; + struct drawLinesShader { enum class Attribute { aPosition = 0, drawLinesShaderAttributeEnd @@ -175,12 +187,6 @@ struct drawFrustumShader { }; }; -struct drawPoints { - enum class Attribute { - aPosition = 0, drawPointsAttributeEnd - }; -}; - std::string loadShader(std::string shaderName); #ifdef SHADERDATACPP const std::unordered_map> attributesPerShaderName = { @@ -199,6 +205,11 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, +{ "drawPoints", + { + { "aPosition", 0}, + } +}, { "adtShader", { { "aPos", 0}, @@ -212,19 +223,9 @@ const std::unordered_map> attributesPe { "position", 0}, } }, -{ "skyConus", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", +{ "spotLight", { - { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, + { "position", 0}, } }, { "imguiShader", @@ -253,6 +254,21 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, +{ "skyConus", + { + { "aPosition", 0}, + } +}, +{ "m2Shader", + { + { "aPosition", 0}, + { "aNormal", 1}, + { "bones", 2}, + { "boneWeights", 3}, + { "aTexCoord", 4}, + { "aTexCoord2", 5}, + } +}, { "drawLinesShader", { { "aPosition", 0}, @@ -302,11 +318,6 @@ const std::unordered_map> attributesPe { "aPosition", 0}, } }, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, }; const std::unordered_map shaderMetaInfo = { @@ -333,12 +344,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -381,12 +390,10 @@ const std::unordered_map shaderMetaInfo = { {2,6, "uTexture7"}, {2,7, "uTexture8"}, {2,8, "uTexture9"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,8,9}, {0,0,0}, @@ -407,9 +414,6 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,560}, {1,0,64}, - {1,1,384}, - {1,3,4096}, - {1,4,256}, }, { { @@ -427,12 +431,10 @@ const std::unordered_map shaderMetaInfo = { }, { {3,3, "uBumpTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {3,3,1}, @@ -466,12 +468,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -506,12 +506,10 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -523,26 +521,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtLodShader.vert.spv", +{ "./forwardRendering/skyConus.frag.spv", { - ShaderStage::Vertex, - { - {0,0,144}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, + ShaderStage::Fragment, { }, { @@ -556,43 +537,14 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, } - } - } -}, -{ "./forwardRendering/m2Shader.vert.spv", - { - ShaderStage::Vertex, - { - {1,2,16384}, - {1,0,64}, - {0,0,560}, - {1,1,384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, - }, - { - { - {0,0,1}, - {0,5,6}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } }, { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -627,17 +579,14 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -670,12 +619,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -691,11 +638,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,560}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -706,23 +652,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -732,11 +669,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/forward/adtShader.vert.spv", +{ "./forwardRendering/drawQuad.vert.spv", { ShaderStage::Vertex, { - {0,0,560}, + {0,0,16}, }, { { @@ -751,17 +688,12 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -773,15 +705,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/wmo/deferred/wmoShader.frag.spv", +{ "./bindless/waterfall/deferred/waterFallShader_opaq.frag.spv", { ShaderStage::Fragment, { - {0,0,560}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -792,25 +723,19 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, + {2,1,0}, + {2,0,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {3,0, "s_Textures"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -818,11 +743,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawQuad.vert.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", { ShaderStage::Vertex, { - {0,0,16}, + {0,0,560}, }, { { @@ -854,16 +779,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/wmo/forward/wmoShader.vert.spv", +{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,1,16}, {0,0,560}, }, { { {0,0,1}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -873,22 +799,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, + {1,0,4096}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "uTexture"}, }, { { - {1,2,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -898,7 +818,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/forward/waterfallShader.frag.spv", +{ "./bindless/m2/forward/m2Shader.frag.spv", { ShaderStage::Fragment, { @@ -917,47 +837,42 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, + {1,9,0}, + {1,8,0}, + {1,7,0}, {1,2,0}, - {1,3,0}, - {1,4,0}, {1,5,0}, + {1,4,0}, {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, + {2,0, "s_Textures"}, {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } } } }, -{ "./bindless/waterfall/deferred/waterFallShader_opaq.frag.spv", +{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", { ShaderStage::Fragment, { - {0,0,560}, + {1,0,32}, }, { { - {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -967,29 +882,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, }, { - {3,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { - {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,1}, + {0,2,3}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -998,7 +902,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", +{ "./bindless/lights/pointLight.vert.spv", { ShaderStage::Vertex, { @@ -1017,14 +921,13 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1036,16 +939,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", +{ "./forwardRendering/ffxglow.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {0,0,560}, + {0,1,16}, }, { { - {0,0,1}, {1,1,1}, {0,0,0}, {0,0,0}, @@ -1053,21 +954,20 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { - {1,0,4096}, }, { - {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {1,0, "screenTex"}, + {1,1, "blurTex"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, + {0,1,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1081,11 +981,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,560}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1096,24 +995,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1142,12 +1033,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1182,17 +1071,14 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, - {1,1,0}, - {1,2,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {1,1,1}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1208,11 +1094,10 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { - {0,0,560}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1226,21 +1111,15 @@ const std::unordered_map shaderMetaInfo = { {1,9,0}, {1,8,0}, {1,7,0}, - {1,2,0}, {1,5,0}, - {1,4,0}, {1,6,0}, - {1,1,0}, - {1,3,0}, }, { {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1284,12 +1163,10 @@ const std::unordered_map shaderMetaInfo = { {2,7, "uLayerHeight2"}, {2,8, "uLayerHeight3"}, {2,4, "uAlphaTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,8,9}, {0,0,0}, @@ -1398,19 +1275,12 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1422,7 +1292,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", +{ "./bindless/wmo/forward/wmoShader.vert.spv", { ShaderStage::Vertex, { @@ -1441,14 +1311,16 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,1,0}, + {1,2,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1460,11 +1332,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtLodShader.frag.spv", +{ "./bindless/waterfall/forward/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,0,84}, + {0,0,560}, }, { { @@ -1479,17 +1351,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {2,1,0}, + {2,0,0}, }, { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, + {3,0, "s_Textures"}, }, { { - {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1498,16 +1371,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/waterfall/forward/waterfallShader.vert.spv", +{ "./bindless/lights/spotLight.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { + {1,3,16}, {0,0,560}, }, { { {0,0,1}, - {0,0,0}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1517,29 +1391,18 @@ const std::unordered_map shaderMetaInfo = { } }, { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, + {1,0,0}, }, { - {3,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {1,2, "normalTex"}, + {1,1, "depthTex"}, }, { { + {0,0,0}, {1,2,2}, {0,0,0}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1548,9 +1411,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", +{ "./bindless/waterfall/forward/waterfallShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,560}, }, @@ -1567,28 +1430,23 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, + {2,1,0}, {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, + {2,0,0}, {1,6,0}, - {1,1,0}, {1,3,0}, + {1,1,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {3,0, "s_Textures"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1596,47 +1454,43 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/waterfallShader.frag.spv", +{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", { ShaderStage::Fragment, { - {2,0,112}, {0,0,560}, - {1,0,64}, - {1,1,384}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, }, { { - {0,0,1}, - {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, + {0,0,0}, } }, { + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, }, { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, + {2,0, "s_Textures"}, {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {1,1,1}, {0,0,0}, + {0,0,1}, {0,0,0}, - {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1645,7 +1499,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/visbuffer/adtShader.frag.spv", +{ "./bindless/water/waterShader.frag.spv", { ShaderStage::Fragment, { @@ -1664,24 +1518,19 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, {1,2,0}, + {1,0,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "s_Textures"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1689,7 +1538,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/visbuffer/adtShader.vert.spv", +{ "./bindless/water/waterShader.vert.spv", { ShaderStage::Vertex, { @@ -1708,17 +1557,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, {1,2,0}, + {1,1,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1730,17 +1576,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/lights/pointLight.frag.spv", +{ "./forwardRendering/ribbonShader.frag.spv", { ShaderStage::Fragment, { - {1,3,16}, + {1,1,16}, + {1,0,4096}, {0,0,560}, }, { { {0,0,1}, - {3,3,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1750,20 +1597,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,0}, }, { - {1,2, "normalTex"}, - {1,1, "depthTex"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "uTexture"}, }, { { - {1,2,2}, - {1,2,2}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1772,15 +1615,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", +{ "./forwardRendering/renderFrameBufferShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,560}, }, { { - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1791,26 +1633,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1820,15 +1650,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPoints.frag.spv", +{ "./bindless/adt/forward/adtShader.frag.spv", { ShaderStage::Fragment, { - {0,1,12}, + {0,0,560}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1839,16 +1669,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1856,17 +1694,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/skyConus.vert.spv", +{ "./bindless/wmo/deferred/wmoShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,560}, - {1,0,96}, }, { { - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1876,16 +1712,18 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "s_Textures"}, }, { { - {1,2,2}, {0,0,0}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1895,7 +1733,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/lights/pointLight.vert.spv", +{ "./bindless/adt/forward/adtShader.vert.spv", { ShaderStage::Vertex, { @@ -1914,15 +1752,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,0,0}, + {1,3,0}, + {1,1,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1934,11 +1771,11 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2/forward/m2Shader.frag.spv", +{ "./forwardRendering/adtLodShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,0,560}, + {0,0,144}, }, { { @@ -1953,26 +1790,14 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1982,17 +1807,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", +{ "./forwardRendering/m2Shader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, + {1,2,16384}, + {1,0,64}, {0,0,560}, }, { { {0,0,1}, - {0,0,1}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2004,17 +1830,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,2,3}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2024,17 +1845,18 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ffxglow.frag.spv", +{ "./forwardRendering/waterfallShader.frag.spv", { ShaderStage::Fragment, { - {0,1,16}, + {2,0,112}, + {0,0,560}, }, { { - {1,1,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2045,15 +1867,17 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "screenTex"}, - {1,1, "blurTex"}, + {3,4, "uNormalTex"}, + {3,2, "uNoise"}, + {3,1, "uWhiteWater"}, + {3,0, "uMask"}, }, { { {0,0,0}, - {0,1,2}, {0,0,0}, {0,0,0}, + {0,4,5}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2062,7 +1886,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.frag.spv", +{ "./bindless/adt/visbuffer/adtShader.frag.spv", { ShaderStage::Fragment, { @@ -2081,22 +1905,22 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, - {1,0,0}, + {1,3,0}, {1,1,0}, + {1,2,0}, }, { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, }, { { - {1,2,2}, - {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2104,7 +1928,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/water/waterShader.vert.spv", +{ "./bindless/adt/visbuffer/adtShader.vert.spv", { ShaderStage::Vertex, { @@ -2123,20 +1947,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,2,0}, + {1,3,0}, {1,1,0}, - {1,0,0}, }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - {2,0, "s_Textures"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2146,18 +1966,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/ribbonShader.frag.spv", +{ "./bindless/lights/pointLight.frag.spv", { ShaderStage::Fragment, { - {1,1,16}, - {1,0,4096}, + {1,3,16}, {0,0,560}, }, { { {0,0,1}, - {0,1,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2167,17 +1986,17 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,0,0}, }, { - {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, + {1,2, "normalTex"}, + {1,1, "depthTex"}, }, { { + {0,0,0}, {1,2,2}, {0,0,0}, - {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2187,9 +2006,9 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/renderFrameBufferShader.vert.spv", +{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { }, { @@ -2222,16 +2041,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./bindless/adt/forward/adtShader.frag.spv", +{ "./forwardRendering/skyConus.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { {0,0,560}, + {1,0,96}, }, { { {0,0,1}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2241,24 +2061,16 @@ const std::unordered_map shaderMetaInfo = { } }, { - {1,3,0}, - {1,1,0}, - {1,2,0}, }, { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2266,17 +2078,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/adtShader.vert.spv", +{ "./forwardRendering/drawPoints.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {1,0,64}, - {0,0,560}, + {0,1,12}, }, { { - {0,0,1}, - {0,0,1}, + {1,1,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2288,12 +2099,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2305,15 +2114,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPortalShader.frag.spv", +{ "./bindless/lights/spotLight.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,16}, + {0,0,560}, }, { { - {0,0,0}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -2321,9 +2129,11 @@ const std::unordered_map shaderMetaInfo = { {0,0,0}, {0,0,0}, {0,0,0}, + {0,0,0}, } }, { + {1,0,0}, }, { }, @@ -2341,14 +2151,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShaderDepth.frag.spv", +{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2361,12 +2172,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2377,15 +2187,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.frag.spv", +{ "./forwardRendering/adtLodShader.frag.spv", { ShaderStage::Fragment, { - {0,1,112}, + {0,0,84}, }, { { - {1,1,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2413,17 +2223,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawBBShader.vert.spv", +{ "./forwardRendering/adtShader.vert.spv", { ShaderStage::Vertex, { - {0,1,112}, + {1,0,64}, {0,0,560}, }, { { - {0,1,2}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2435,12 +2245,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2452,17 +2260,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPoints.vert.spv", +{ "./forwardRendering/drawPortalShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, - {0,1,64}, + {1,0,16}, }, { { - {0,1,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2489,15 +2296,14 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.frag.spv", +{ "./forwardRendering/imguiShaderDepth.frag.spv", { ShaderStage::Fragment, { - {0,2,12}, }, { { - {2,2,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2510,11 +2316,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2525,15 +2332,15 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawFrustumShader.vert.spv", +{ "./forwardRendering/drawBBShader.frag.spv", { - ShaderStage::Vertex, + ShaderStage::Fragment, { - {0,0,128}, + {0,1,112}, }, { { - {0,0,1}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2561,15 +2368,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawLinesShader.frag.spv", +{ "./forwardRendering/drawBBShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {0,1,12}, + {0,1,112}, + {0,0,560}, }, { { - {1,1,1}, + {0,1,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2597,7 +2405,44 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader_opaque.frag.spv", +{ "./forwardRendering/drawPoints.vert.spv", + { + ShaderStage::Vertex, + { + {0,0,128}, + {0,1,64}, + }, + { + { + {0,1,2}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/drawFrustumShader.frag.spv", { ShaderStage::Fragment, { @@ -2617,12 +2462,11 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2633,7 +2477,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawLinesShader.vert.spv", +{ "./forwardRendering/drawFrustumShader.vert.spv", { ShaderStage::Vertex, { @@ -2669,11 +2513,82 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/drawPortalShader.vert.spv", +{ "./forwardRendering/drawLinesShader.frag.spv", + { + ShaderStage::Fragment, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/imguiShader_opaque.frag.spv", + { + ShaderStage::Fragment, + { + }, + { + { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + }, + { + }, + { + {1,0, "Texture"}, + }, + { + { + {0,0,0}, + {0,0,1}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + } + } + } +}, +{ "./forwardRendering/drawLinesShader.vert.spv", { ShaderStage::Vertex, { - {0,0,560}, + {0,0,128}, }, { { @@ -2690,12 +2605,10 @@ const std::unordered_map shaderMetaInfo = { { }, { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2707,17 +2620,16 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/m2ParticleShader.frag.spv", +{ "./forwardRendering/drawPortalShader.vert.spv", { - ShaderStage::Fragment, + ShaderStage::Vertex, { - {1,0,32}, {0,0,560}, }, { { {0,0,1}, - {0,0,1}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2729,17 +2641,12 @@ const std::unordered_map shaderMetaInfo = { { }, { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, {0,0,0}, - {0,2,3}, + {0,0,0}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2774,12 +2681,10 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -2791,15 +2696,17 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/imguiShader.frag.spv", +{ "./forwardRendering/m2ParticleShader.frag.spv", { ShaderStage::Fragment, { + {1,0,32}, + {0,0,560}, }, { { - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2811,13 +2718,15 @@ const std::unordered_map shaderMetaInfo = { { }, { - {1,0, "Texture"}, + {2,0, "uTexture"}, + {2,1, "uTexture2"}, + {2,2, "uTexture3"}, }, { { {0,0,0}, - {0,0,1}, {0,0,0}, + {0,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2827,7 +2736,7 @@ const std::unordered_map shaderMetaInfo = { } } }, -{ "./forwardRendering/skyConus.frag.spv", +{ "./forwardRendering/imguiShader.frag.spv", { ShaderStage::Fragment, { @@ -2847,11 +2756,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {1,0, "Texture"}, }, { { {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2920,11 +2830,10 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, - {0,4, "u_depth"}, }, { { - {3,4,2}, + {3,3,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2947,7 +2856,6 @@ const std::unordered_map shaderMetaInfo = { {0,0,560}, {1,0,64}, {1,5,4096}, - {1,2,16384}, }, { { @@ -2968,12 +2876,10 @@ const std::unordered_map shaderMetaInfo = { {3,1, "uTexture2"}, {3,2, "uTexture3"}, {3,3, "uTexture4"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, }, { { - {1,2,2}, + {0,0,0}, {0,0,0}, {0,0,0}, {0,3,4}, @@ -3032,11 +2938,20 @@ const std::unordered_map>> fieldDefMapPerShaderNameFrag = { {"imguiShaderDepth", { @@ -3519,11 +3365,6 @@ const std::unordered_map scissorSize = {0,0}; }; - -class IMesh : public ObjectWithId { +enum class GMeshId : int; +class IMesh : public ObjectWithId { friend class IDevice; public: diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index fccbea120..16bc9f5ad 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -67,7 +67,7 @@ class Config { bool BCLightHack = false; - bool enableLightBuffer = false; + bool enableLightBuffer = true; bool drawDepthBuffer = false; int cameraM2 = -1; // this will be sceneNumber of object diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index 39c97e5fc..efda5b54c 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -45,7 +45,7 @@ struct MapRenderPlan { WMOGroupListContainer wmoGroupArray; std::vector pointLights; - std::vector spotLights; + std::vector spotLights; }; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index a58156e8e..f76b3d41e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -76,7 +76,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende transp_vec transpVec; auto lCollector = opaqueMeshCollector.clone(); for (size_t i = r.begin(); i != r.end(); ++i) { - auto &m2Object = m2ToDraw[i]; + auto *m2Object = m2Factory.getObjectById(m2ToDraw[i]); if (m2Object != nullptr) { m2Object->collectMeshes(*lCollector, transpVec); m2Object->drawParticles(*lCollector, transpVec, @@ -94,7 +94,8 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende }, ap); }); } else { - for (auto &m2Object : cullStage->m2Array.getDrawn()) { + for (auto m2ObjectId : cullStage->m2Array.getDrawn()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); if (m2Object == nullptr) continue; m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes); m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); @@ -108,7 +109,9 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende transp_vec skyTranspVec; ZoneScopedN("collect skyBox"); - for (auto &m2Object : skyBoxView->m2List.getDrawn()) { + for (auto &m2ObjectId : skyBoxView->m2List.getDrawn()) { + auto m2Object = m2Factory.getObjectById(m2ObjectId); + if (m2Object == nullptr) continue; m2Object->collectMeshes(skyOpaqueMeshCollector, skyTranspVec); m2Object->drawParticles(skyOpaqueMeshCollector, skyTranspVec, m_viewRenderOrder); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 97ea28a7d..5a8c6b737 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -176,6 +176,44 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m_drawQuadVao->save(); } + //Create vertex data for SpotLight in z-up + { + std::vector vertexBuffer; + std::vector indexBuffer; + + vertexBuffer.push_back(mathfu::vec2_packed(mathfu::vec2(0,0))); + + for (uint32_t i = 0; i < spotLightSegments; i++) { + float angle = i * 2.0f * M_PI / (float)spotLightSegments; + vertexBuffer.push_back(mathfu::vec2_packed( + mathfu::vec2(cos(angle),sin(angle)) + )); + } + vertexBuffer.push_back(mathfu::vec2_packed(mathfu::vec2(0,0))); + + for (uint32_t i = 0; i < spotLightSegments; i++) { + indexBuffer.push_back(0); + indexBuffer.push_back(((i+1) % spotLightSegments) + 1); + indexBuffer.push_back(((i) % spotLightSegments) + 1); + } + + for (uint32_t i = 2; i < spotLightSegments; i++) { + indexBuffer.push_back(1); + indexBuffer.push_back(((i+1) % spotLightSegments) + 1); + indexBuffer.push_back(((i) % spotLightSegments) + 1); + } + + m_vboSpot = m_device->createVertexBuffer(un("Scene_VBO_Spot"), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboSpot = m_device->createIndexBuffer(un("Scene_IBO_Spot"), indexBuffer.size() * sizeof(uint16_t)); + m_vboSpot->uploadData(vertexBuffer.data(), vertexBuffer.size() * sizeof(mathfu::vec2_packed)); + m_iboSpot->uploadData(indexBuffer.data(), indexBuffer.size() * sizeof(uint16_t)); + + m_drawSpotVao = m_device->createVertexBufferBindings(); + m_drawSpotVao->addVertexBufferBinding(m_vboSpot, std::vector(fullScreenQuad.begin(), fullScreenQuad.end())); + m_drawSpotVao->setIndexBuffer(m_iboSpot); + m_drawSpotVao->save(); + } + //Create m2 shaders { m2Buffers.placementMatrix = m_device->createSSBOBuffer(un("M2 Placement"), 1024*1024, sizeof(M2::PlacementMatrix)); @@ -213,7 +251,7 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m2WaterfallBuffer.waterfallBindless = m_device->createSSBOBuffer(un("M2 Waterfall Bindless"),200, sizeof(M2::WaterfallData::WaterfallBindless)); pointLightBuffer = m_device->createSSBOBuffer(un("Point Light Buffer"),200, sizeof(LocalLight)); - spotLightBuffer = m_device->createSSBOBuffer(un("Spot Light Buffer"),200, sizeof(Spotlight)); + spotLightBuffer = m_device->createSSBOBuffer(un("Spot Light Buffer"),200, sizeof(SpotLight)); uboBuffer = m_device->createUniformBuffer(un("UBO Buffer"), 1024*1024); uboStaticBuffer = m_device->createUniformBuffer(un("UBO Static"), 1024*1024); @@ -247,7 +285,9 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, defaultView = std::make_shared(m_device, uboBuffer, pointLightBuffer, sceneWideDS, - m_drawQuadVao, false); + m_drawQuadVao, + m_drawSpotVao, + false); m_forwardRenderPass = defaultView->getForwardPass(); m_gBufferPass = defaultView->getGBufferPass(); @@ -274,6 +314,7 @@ void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyADTVAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyADTVAO, {"adtShader", "adtShader"}, adtBindlessGBufferShaderConfig, m_gBufferPass) @@ -306,6 +347,7 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { //Create global water descriptor for bindless textures g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { @@ -332,6 +374,7 @@ void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { //Create global wmo descriptor for bindless textures g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -361,6 +404,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { //Create global m2 descriptor for bindless textures g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -385,7 +429,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { } void MapSceneRenderBindlessVLK::createM2WaterfallGlobalMaterialData() { MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) - .overridePipelineLayout({{1, m2BufferOneDS}}) + .overridePipelineLayout({{0, sceneWideDS}, {1, m2BufferOneDS}}) .createDescriptorSet(2, [&](std::shared_ptr &ds) { ds->beginUpdate() .ssbo(0, m2WaterfallBuffer.waterfallCommon) @@ -414,6 +458,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMateri auto staticMaterial = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessShaderConfig) .setMaterialId(generateUniqueM2MatId()) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -438,6 +483,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMater auto staticMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessShaderConfig) .setMaterialId(generateUniqueWMOMatId()) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyWMOVAO, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -710,7 +756,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Waterfa auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) - .overridePipelineLayout({{1, m2BufferOneDS}}) + .overridePipelineLayout({{0, sceneWideDS}, {1, m2BufferOneDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) @@ -763,6 +809,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Particle pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Particle/forward/m2ParticleShader", "m2Particle/forward/m2ParticleShader"}, bindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyM2ParticleVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { @@ -790,6 +837,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMate auto &l_m2ModelData = m2ModelData; auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Ribbon/forward/ribbonShader", "m2Ribbon/forward/ribbonShader"}, bindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyM2RibbonVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { @@ -872,6 +920,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(c auto &l_sceneWideChunk = sceneWideChunk; auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) @@ -935,6 +984,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial auto materialPS = std::make_shared>(uboBuffer); auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) + .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyPortalVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -1349,6 +1399,8 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); + uploadCmd.submitBufferUploads(l_this->m_vboSpot); + uploadCmd.submitBufferUploads(l_this->m_iboSpot); } }, [transparentMeshes, l_opaqueMeshes = std::move(u_collector), l_skyOpaqueMeshes = std::move(u_skyCollector), @@ -1561,5 +1613,7 @@ HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTem std::shared_ptr MapSceneRenderBindlessVLK::createRenderView(bool createOutput) { return std::make_shared(m_device, uboBuffer, pointLightBuffer, sceneWideDS, - m_drawQuadVao, createOutput); + m_drawQuadVao, + m_drawSpotVao, + createOutput); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 065e8c3b0..3d1b42369 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -115,7 +115,7 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { std::shared_ptr createRenderView(bool createOutput) override; - std::shared_ptr> meshFactory = std::make_shared>(); + std::shared_ptr> meshFactory = std::make_shared>(); protected: virtual std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); virtual std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); @@ -199,6 +199,11 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBufferBindings m_drawQuadVao = nullptr; + HGBufferVLK m_vboSpot; + HGBufferVLK m_iboSpot; + + HGVertexBufferBindings m_drawSpotVao = nullptr; + std::shared_ptr> sceneWideChunk; std::shared_ptr sceneWideDS = nullptr; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 73b921f13..a5c9730cd 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -111,7 +111,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; - std::shared_ptr> meshFactory = std::make_shared>(); + std::shared_ptr> meshFactory = std::make_shared>(); HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h index d9919a1bf..b64b9408c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/materials/IMaterialInstance.h @@ -26,5 +26,6 @@ class IMaterialInstance : public ISimpleMaterialVLK, public IMaterialClass { } }; +constexpr uint32_t spotLightSegments = 10; #endif //AWEBWOWVIEWERCPP_IMATERIALINSTANCE_H diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 652c63caa..4550acdc4 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -15,8 +15,11 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &lightDataBuffer, const std::shared_ptr &sceneWideDS, const HGVertexBufferBindings &quadVAO, + const HGVertexBufferBindings &spotVAO, bool createOutputFBO) : m_device(device), - m_quadVAO(quadVAO), m_lightDataBuffer(lightDataBuffer), + m_quadVAO(quadVAO), + m_spotVAO(spotVAO), + m_lightDataBuffer(lightDataBuffer), m_sceneWideDS(sceneWideDS), m_createOutputFBO(createOutputFBO) { glowPass = std::make_unique(m_device, uboBuffer, quadVAO); @@ -24,6 +27,9 @@ RenderViewDeferredVLK::RenderViewDeferredVLK(const HGDeviceVLK &device, for (auto &pointLightBuff : m_pointLightBuffers) { pointLightBuff = lightDataBuffer->getSubBuffer(100*sizeof(LocalLight)); } + for (auto &spotLightBuff : m_spotLightBuffers) { + spotLightBuff = lightDataBuffer->getSubBuffer(100*sizeof(SpotLight)); + } createFrameBuffers(); { @@ -156,6 +162,16 @@ static const PipelineTemplate s_lightBufferPipelineT = { 0xFF }; +static const PipelineTemplate s_lightBufferPipelineSpot = { + DrawElementMode::TRIANGLES, + false, + true, + EGxBlendEnum::GxBlend_Add, + false, + false, + 0xFF +}; + void RenderViewDeferredVLK::createLightBufferMats() { for (int i = 0; i < m_pointLightMats.size(); i++) { m_pointLightMats[i] = MaterialBuilderVLK::fromShader(m_device, {"pointLight", "pointLight"}, { @@ -180,13 +196,36 @@ void RenderViewDeferredVLK::createLightBufferMats() { }) .toMaterial(); } + for (int i = 0; i < m_spotLightMats.size(); i++) { + m_spotLightMats[i] = MaterialBuilderVLK::fromShader(m_device, {"spotLight", "spotLight"}, { + .vertexShaderFolder = "bindless/lights", + .fragmentShaderFolder = "bindless/lights", + .typeOverrides = { + {0, { + {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, + }} + } + }) + .overridePipelineLayout({{0, m_sceneWideDS}}) + .createPipeline(m_quadVAO, m_lightBufferPass, s_lightBufferPipelineSpot) + .bindDescriptorSet(0, m_sceneWideDS) + .createDescriptorSet(1, [&](std::shared_ptr &ds) { + ds->beginUpdate() + .ssbo(0, m_spotLightBuffers[i]) + .texture(1, m_gBufferFrameBuffers[i]->getAttachment(1)) + .texture(2, m_gBufferFrameBuffers[i]->getAttachment(0)) + .ubo(3, BufferChunkHelperVLK::cast(m_lightScreenSize)) + .delayUpdate(); + }) + .toMaterial(); + } m_lightMatsCreated = true; } void RenderViewDeferredVLK::update(int width, int height, float glow, const std::vector &pointLights, - const std::vector &spotLights + const std::vector &spotLights ) { width = std::max(1, width); height = std::max(1, height); @@ -204,8 +243,6 @@ void RenderViewDeferredVLK::update(int width, int height, float glow, this->createFrameBuffers(); this->createLightBufferMats(); - - { std::vector> inputColorTextures; for (int i = 0; i < m_forwardFrameBuffers.size(); i++) { @@ -318,10 +355,15 @@ void RenderViewDeferredVLK::doLightPass(CmdBufRecorder &frameBufCmd) { {m_width, m_height}, {0,0,0}); - if (m_lightPointCount > 0) { + if (m_pointLightCount > 0) { frameBufCmd.bindVertexBindings(m_quadVAO); frameBufCmd.bindMaterial(m_pointLightMats[frameNum]); - frameBufCmd.drawIndexed(6, m_lightPointCount, 0, 0, 0); + frameBufCmd.drawIndexed(6, m_pointLightCount, 0, 0, 0); + } + if (m_spotLightCount > 0) { + frameBufCmd.bindVertexBindings(m_spotVAO); + frameBufCmd.bindMaterial(m_spotLightMats[frameNum]); + frameBufCmd.drawIndexed((spotLightSegments*3) + (spotLightSegments - 2) * 3, m_spotLightCount, 0, 0, 0); } } @@ -381,19 +423,33 @@ RenderViewDeferredVLK::readRGBAPixels(int frameNumber, int x, int y, int width, } void RenderViewDeferredVLK::updateLightBuffers(const std::vector &pointLights, - const std::vector &spotLights) { + const std::vector &spotLights) { bool recreateLightMat = false; auto frameNum = m_device->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; - auto &pointLightBuffer = m_pointLightBuffers[frameNum]; - if (pointLightBuffer->getSize() < pointLights.size()*sizeof(LocalLight)) { - pointLightBuffer = m_lightDataBuffer->getSubBuffer((pointLights.size() + 100) * sizeof(LightResult)); - recreateLightMat = true; + + { + auto &pointLightBuffer = m_pointLightBuffers[frameNum]; + if (pointLightBuffer->getSize() < pointLights.size() * sizeof(LocalLight)) { + pointLightBuffer = m_lightDataBuffer->getSubBuffer((pointLights.size() + 100) * sizeof(LocalLight)); + recreateLightMat = true; + } + + pointLightBuffer->uploadData(pointLights.data(), pointLights.size() * sizeof(LocalLight)); + + m_pointLightCount = pointLights.size(); } + { + auto &spotLightBuffer = m_spotLightBuffers[frameNum]; + if (spotLightBuffer->getSize() < spotLights.size()*sizeof(SpotLight)) { + spotLightBuffer = m_lightDataBuffer->getSubBuffer((spotLights.size() + 100) * sizeof(SpotLight)); + recreateLightMat = true; + } - pointLightBuffer->uploadData(pointLights.data(), pointLights.size()*sizeof(LocalLight)); + spotLightBuffer->uploadData(spotLights.data(), spotLights.size()*sizeof(SpotLight)); - m_lightPointCount = pointLights.size(); + m_spotLightCount = spotLights.size(); + } if (recreateLightMat) { createLightBufferMats(); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h index b81f65545..a82915941 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.h @@ -14,12 +14,14 @@ class RenderViewDeferredVLK : public IRenderView { RenderViewDeferredVLK(const HGDeviceVLK &device, const HGBufferVLK &uboBuffer, const HGBufferVLK &lightDataBuffer, const std::shared_ptr &sceneWideDS, - const HGVertexBufferBindings &quadVAO, bool createOutputFBO); + const HGVertexBufferBindings &quadVAO, + const HGVertexBufferBindings &spotVAO, + bool createOutputFBO); ~RenderViewDeferredVLK() override = default; void update(int width, int height, float glow, const std::vector &pointLights, - const std::vector &spotLights); + const std::vector &spotLights); void setLightBuffers(const std::shared_ptr &sceneWideDS); @@ -42,8 +44,8 @@ class RenderViewDeferredVLK : public IRenderView { uint32_t m_width = 640; uint32_t m_height = 480; - uint32_t m_lightPointCount; - uint32_t m_spotPointCount; + uint32_t m_pointLightCount; + uint32_t m_spotLightCount; std::shared_ptr m_sceneWideDS; @@ -53,6 +55,7 @@ class RenderViewDeferredVLK : public IRenderView { bool m_lightMatsCreated = false; HGVertexBufferBindings m_quadVAO; + HGVertexBufferBindings m_spotVAO; HGBufferVLK m_lightDataBuffer; std::shared_ptr> m_lightScreenSize; @@ -68,6 +71,7 @@ class RenderViewDeferredVLK : public IRenderView { std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightBuffers; + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_spotLightBuffers; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_pointLightMats; std::array, IDevice::MAX_FRAMES_IN_FLIGHT> m_spotLightMats; @@ -81,7 +85,7 @@ class RenderViewDeferredVLK : public IRenderView { void createLightBufferMats(); std::vector> onUpdates; - void updateLightBuffers(const std::vector &pointLights, const std::vector &spotLights); + void updateLightBuffers(const std::vector &pointLights, const std::vector &spotLights); }; #endif //AWEBWOWVIEWERCPP_RENDERVIEWDEFERREDVLK_H From a325281c692ec98fa17174565d49e3aefc2f0bda Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 9 Apr 2024 15:07:13 +0300 Subject: [PATCH 186/212] - proper rotation for spotlights --- .../engine/objects/lights/CWmoNewLight.cpp | 24 +- .../src/engine/objects/lights/CWmoNewLight.h | 4 +- .../src/engine/shader/ShaderDefinitions.h | 709 ++++++++++++++---- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- 4 files changed, 564 insertions(+), 175 deletions(-) diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp index d44fd87e2..1aef662d0 100644 --- a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.cpp @@ -26,10 +26,11 @@ CWmoNewLight::CWmoNewLight(const mathfu::mat4 &modelMatrix, const mapobject_new_ m_outerAngle = newLightDef.outerAngle; rot_mat = - MathHelper::RotationZ((m_rotation.z)) * - MathHelper::RotationY((m_rotation.y)) * - MathHelper::RotationX((m_rotation.x)); - calcedLightDir = ((modelMatrix * rot_mat).Inverse().Transpose()*mathfu::vec4(0,0,-1,0)); + mathfu::mat4::RotationZ(m_rotation.z) * + mathfu::mat4::RotationY(m_rotation.y) * + mathfu::mat4::RotationX(m_rotation.x); + + calcedLightDir = ((rot_mat).Inverse().Transpose()*mathfu::vec3(0,0,-1)); } CWmoNewLight::CWmoNewLight(const WdtLightFile::MapSpotLight &mapSpotLight ) { @@ -51,10 +52,13 @@ CWmoNewLight::CWmoNewLight(const WdtLightFile::MapSpotLight &mapSpotLight ) { m_rotation = mapSpotLight.rotation; rot_mat = - MathHelper::RotationZ((m_rotation.z)) * - MathHelper::RotationY((m_rotation.y)) * - MathHelper::RotationX((m_rotation.x)); - calcedLightDir = (rot_mat).Inverse().Transpose()*mathfu::vec4(0,0,-1,0); + mathfu::mat4::RotationZ(m_rotation.z) * + mathfu::mat4::RotationY(m_rotation.y) * + mathfu::mat4::RotationX(m_rotation.x); + + + + calcedLightDir = ((rot_mat).Inverse().Transpose()*mathfu::vec3(0,0,-1)); } void CWmoNewLight::collectLight(std::vector &pointLights, std::vector &spotLights) { @@ -83,7 +87,7 @@ void CWmoNewLight::collectLight(std::vector &pointLights, std::vecto // rotQuat = rotQuatD; } - spotLight.rotMat = rot_mat; + spotLight.rotMat = mathfu::mat4::FromRotationMatrix(rot_mat); // spotLight.rotQuaternion = mathfu::vec4( // rotQuat[1], rotQuat[2],rotQuat[3], rotQuat[0] // ); @@ -110,7 +114,7 @@ void CWmoNewLight::collectLight(std::vector &pointLights, std::vecto cosf(m_outerAngle * 0.5f) ); spotLight.directionAndcosAngleDiff = mathfu::vec4( - calcedLightDir.xyz(), + calcedLightDir, 1.0f/fmaxf(cosf(m_innerAngle * 0.5f) - cosf(m_outerAngle * 0.5f), 0.0099999f) ); spotLight.interior = mathfu::vec4( diff --git a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h index 855e1fcd1..7165f2c15 100644 --- a/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h +++ b/wowViewerLib/src/engine/objects/lights/CWmoNewLight.h @@ -50,8 +50,8 @@ class CWmoNewLight { float m_innerAngle; float m_outerAngle; - mathfu::mat4 rot_mat; - mathfu::vec4 calcedLightDir; + mathfu::mat3 rot_mat; + mathfu::vec3 calcedLightDir; }; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h index 9cfbab863..5b15409f4 100644 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ b/wowViewerLib/src/engine/shader/ShaderDefinitions.h @@ -344,10 +344,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -390,10 +392,12 @@ const std::unordered_map shaderMetaInfo = { {2,6, "uTexture7"}, {2,7, "uTexture8"}, {2,8, "uTexture9"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,8,9}, {0,0,0}, @@ -414,6 +418,9 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {0,0,560}, {1,0,64}, + {1,1,384}, + {1,3,4096}, + {1,4,256}, }, { { @@ -431,10 +438,12 @@ const std::unordered_map shaderMetaInfo = { }, { {3,3, "uBumpTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {3,3,1}, @@ -468,10 +477,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -506,10 +517,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -579,14 +592,17 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -619,10 +635,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -638,10 +656,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -652,14 +671,23 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,6,0}, + {1,4,0}, + {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -709,10 +737,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -725,13 +754,24 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -764,10 +804,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -803,10 +845,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -844,14 +888,17 @@ const std::unordered_map shaderMetaInfo = { {1,5,0}, {1,4,0}, {1,6,0}, + {1,1,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -868,10 +915,11 @@ const std::unordered_map shaderMetaInfo = { ShaderStage::Fragment, { {1,0,32}, + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -887,10 +935,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -924,10 +974,12 @@ const std::unordered_map shaderMetaInfo = { {1,0,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -981,10 +1033,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -995,16 +1048,24 @@ const std::unordered_map shaderMetaInfo = { } }, { + {1,3,0}, + {1,1,0}, + {1,2,0}, }, { + {2,0, "s_LayerTextures"}, + {4,0, "s_LayerHeightTextures"}, + {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, + {0,0,1}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1033,10 +1094,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1071,14 +1134,17 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,3,0}, {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1094,10 +1160,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1111,15 +1178,21 @@ const std::unordered_map shaderMetaInfo = { {1,9,0}, {1,8,0}, {1,7,0}, + {1,2,0}, {1,5,0}, + {1,4,0}, {1,6,0}, + {1,1,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1163,10 +1236,12 @@ const std::unordered_map shaderMetaInfo = { {2,7, "uLayerHeight2"}, {2,8, "uLayerHeight3"}, {2,4, "uAlphaTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,8,9}, {0,0,0}, @@ -1275,12 +1350,19 @@ const std::unordered_map shaderMetaInfo = { {1,7,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,8,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1315,12 +1397,16 @@ const std::unordered_map shaderMetaInfo = { {1,4,0}, {1,1,0}, {1,2,0}, + {1,3,0}, + {1,5,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1353,13 +1439,24 @@ const std::unordered_map shaderMetaInfo = { { {2,1,0}, {2,0,0}, + {1,1,0}, + {1,2,0}, + {1,3,0}, + {1,4,0}, + {1,5,0}, + {1,6,0}, + {1,7,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -1396,10 +1493,12 @@ const std::unordered_map shaderMetaInfo = { { {1,2, "normalTex"}, {1,1, "depthTex"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {1,2,2}, {0,0,0}, {0,0,0}, @@ -1436,13 +1535,20 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,3,0}, {1,1,0}, + {1,2,0}, + {1,4,0}, + {1,5,0}, + {1,8,0}, + {1,9,0}, }, { {3,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,1}, @@ -1480,14 +1586,17 @@ const std::unordered_map shaderMetaInfo = { {1,5,0}, {1,4,0}, {1,6,0}, + {1,1,0}, + {1,3,0}, }, { {2,0, "s_Textures"}, {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {1,1,1}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1520,13 +1629,16 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,0,0}, + {1,1,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1559,14 +1671,18 @@ const std::unordered_map shaderMetaInfo = { { {1,2,0}, {1,1,0}, + {1,0,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + {2,0, "s_Textures"}, }, { { + {1,2,2}, {0,0,0}, - {0,0,0}, - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1600,10 +1716,12 @@ const std::unordered_map shaderMetaInfo = { }, { {2,0, "uTexture"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1698,10 +1816,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1715,13 +1834,18 @@ const std::unordered_map shaderMetaInfo = { {1,6,0}, {1,4,0}, {1,3,0}, + {1,5,0}, + {1,1,0}, + {1,2,0}, }, { {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,0}, @@ -1754,12 +1878,15 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1814,12 +1941,17 @@ const std::unordered_map shaderMetaInfo = { {1,2,16384}, {1,0,64}, {0,0,560}, + {1,1,384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, + {2,0,64}, }, { { {0,0,1}, - {0,2,3}, - {0,0,0}, + {0,5,6}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1830,10 +1962,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1851,11 +1985,17 @@ const std::unordered_map shaderMetaInfo = { { {2,0,112}, {0,0,560}, + {1,0,64}, + {1,1,384}, + {1,2,16384}, + {1,3,4096}, + {1,4,256}, + {1,5,4096}, }, { { {0,0,1}, - {0,0,0}, + {0,5,6}, {0,0,1}, {0,0,0}, {0,0,0}, @@ -1871,10 +2011,12 @@ const std::unordered_map shaderMetaInfo = { {3,2, "uNoise"}, {3,1, "uWhiteWater"}, {3,0, "uMask"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,4,5}, @@ -1913,10 +2055,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "s_LayerTextures"}, {4,0, "s_LayerHeightTextures"}, {3,0, "s_AlphaTextures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,1}, {0,0,1}, @@ -1949,12 +2093,15 @@ const std::unordered_map shaderMetaInfo = { { {1,3,0}, {1,1,0}, + {1,2,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -1991,10 +2138,12 @@ const std::unordered_map shaderMetaInfo = { { {1,2, "normalTex"}, {1,1, "depthTex"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {1,2,2}, {0,0,0}, {0,0,0}, @@ -2010,10 +2159,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,0,560}, }, { { - {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2024,14 +2174,26 @@ const std::unordered_map shaderMetaInfo = { } }, { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, + {1,9,0}, + {1,8,0}, + {1,7,0}, + {1,2,0}, + {1,5,0}, + {1,4,0}, + {1,6,0}, + {1,1,0}, + {1,3,0}, + }, + { + {2,0, "s_Textures"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, + }, + { + { + {1,2,2}, {0,0,0}, + {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2063,10 +2225,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2136,10 +2300,12 @@ const std::unordered_map shaderMetaInfo = { {1,0,0}, }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2172,10 +2338,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2208,10 +2376,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,4, "uDiffuseTexture"}, + {0,5, "uNormalTexture"}, }, { { - {0,0,0}, + {4,5,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2245,10 +2415,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2390,10 +2562,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2446,10 +2620,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,2,12}, }, { { - {0,0,0}, + {2,2,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2517,10 +2692,11 @@ const std::unordered_map shaderMetaInfo = { { ShaderStage::Fragment, { + {0,1,12}, }, { { - {0,0,0}, + {1,1,1}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2641,10 +2817,12 @@ const std::unordered_map shaderMetaInfo = { { }, { + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2681,10 +2859,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -2721,10 +2901,12 @@ const std::unordered_map shaderMetaInfo = { {2,0, "uTexture"}, {2,1, "uTexture2"}, {2,2, "uTexture3"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,2,3}, {0,0,0}, @@ -2830,10 +3012,11 @@ const std::unordered_map shaderMetaInfo = { }, { {0,3, "u_sampler"}, + {0,4, "u_depth"}, }, { { - {3,3,1}, + {3,4,2}, {0,0,0}, {0,0,0}, {0,0,0}, @@ -2856,6 +3039,7 @@ const std::unordered_map shaderMetaInfo = { {0,0,560}, {1,0,64}, {1,5,4096}, + {1,2,16384}, }, { { @@ -2876,10 +3060,12 @@ const std::unordered_map shaderMetaInfo = { {3,1, "uTexture2"}, {3,2, "uTexture3"}, {3,3, "uTexture4"}, + {0,1, "lightBuffer"}, + {0,2, "aoBuffer"}, }, { { - {0,0,0}, + {1,2,2}, {0,0,0}, {0,0,0}, {0,3,4}, @@ -2952,6 +3138,10 @@ const std::unordered_map get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = false; + enableValidationLayers = true; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; From 981ded693efedbe0a2d6d1d6fe89665bef600b5f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 13 Apr 2024 20:45:08 +0300 Subject: [PATCH 187/212] - fix for cache clear - move meta file to build dir --- CMakeLists.txt | 12 +- src/ui/FrontendUI.cpp | 16 +- src/ui/childWindow/m2Window/M2Window.cpp | 53 +- src/ui/childWindow/m2Window/M2Window.h | 16 +- .../childWindow/sceneWindow/SceneWindow.cpp | 43 +- src/ui/childWindow/sceneWindow/SceneWindow.h | 23 +- src/ui/renderer/uiScene/FrontendUIRenderer.h | 1 - wowViewerLib/CMakeLists.txt | 3 + wowViewerLib/shaders/CMakeLists.txt | 15 +- wowViewerLib/src/engine/cache/cache.h | 1 + wowViewerLib/src/engine/geometry/m2Geom.cpp | 2 +- .../src/engine/geometry/wmoGroupGeom.cpp | 2 +- .../src/engine/managers/CRibbonEmitter.cpp | 2 +- .../managers/particles/particleEmitter.cpp | 2 +- .../src/engine/objects/ViewsObjects.cpp | 1 - .../src/engine/objects/adt/adtObject.cpp | 2 +- .../src/engine/objects/m2/m2Object.cpp | 12 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../src/engine/objects/scenes/map.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 4 +- .../src/engine/shader/ShaderDefinitions.h | 4269 ----------------- .../src/gapi/vulkan/GDeviceVulkan.cpp | 2 +- .../descriptorSets/GDescriptorSetLayout.h | 2 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 2 +- .../vulkan/shaders/GShaderPermutationVLK.h | 2 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 2 +- .../src/renderer/mapScene/MapSceneRenderer.h | 2 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 22 +- 28 files changed, 163 insertions(+), 4354 deletions(-) delete mode 100644 wowViewerLib/src/engine/shader/ShaderDefinitions.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f6f6ce11..11ee1edee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,12 +373,12 @@ if (NOT MSVC) # find_library(SSP_EXISTS ssp) # message("SSP_EXISTS = ${SSP_EXISTS}") - # if (SSP_EXISTS STREQUAL "SSP_EXISTS-NOTFOUND" ) - - message("Linking against SSP") - message("SSP_EXISTS = ${SSP_EXISTS}") - target_compile_options(AWebWoWViewerCpp PUBLIC -fstack-protector) - target_link_libraries(AWebWoWViewerCpp ssp) + if (SSP_EXISTS STREQUAL "SSP_EXISTS-NOTFOUND" ) + message("Linking against SSP") + message("SSP_EXISTS = ${SSP_EXISTS}") + target_compile_options(AWebWoWViewerCpp PUBLIC -fstack-protector) + target_link_libraries(AWebWoWViewerCpp ssp) + endif() endif() endif(NOT MSVC) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 22712c048..af24f0b89 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -18,7 +18,6 @@ #include #include #include "imguiLib/fileBrowser/imfilebrowser.h" -#include "../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" #include "../persistance/CascRequestProcessor.h" #include "../../wowViewerLib/src/engine/objects/scenes/map.h" #include "../../wowViewerLib/src/engine/camera/firstPersonCamera.h" @@ -46,7 +45,7 @@ FrontendUI::FrontendUI(HApiContainer api) { m_uiRenderer = FrontendUIRendererFactory::createForwardRenderer(m_api->hDevice); //this->createDefaultprocessor(); - m_backgroundScene = std::make_shared(api, true); + m_backgroundScene = std::make_shared(api, true, m_uiRenderer); } void FrontendUI::composeUI() { @@ -1608,6 +1607,19 @@ void FrontendUI::showSettingsDialog() { } } } + if (ImGui::CollapsingHeader("Mat options")) { + auto activeScene = m_lastActiveScene.lock(); + if (activeScene) { + auto materials = activeScene->getMaterials(); + for (int i = 0; i < materials.size(); i++) { + auto &mat = materials[i]; + + if (ImGui::ImageButton(std::get<0>(mat).c_str(), std::get<1>(mat)->uniqueId, {256, 256})) { + activeScene->setCurrentCameraIndex(i); + } + } + } + } ImGui::End(); diff --git a/src/ui/childWindow/m2Window/M2Window.cpp b/src/ui/childWindow/m2Window/M2Window.cpp index 773da202e..419ece021 100644 --- a/src/ui/childWindow/m2Window/M2Window.cpp +++ b/src/ui/childWindow/m2Window/M2Window.cpp @@ -6,34 +6,17 @@ #include "imgui.h" #include "imgui_internal.h" -M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix) : SceneWindow(api, false), m_uiRenderer(renderer) { +M2Window::M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix) : SceneWindow(api, false, renderer) { m_windowName = "M2Window##" + nameSuffix; } M2Window::~M2Window() { - if (m_renderView) { - m_renderView->eraseOnUpdate(iteratorUnique); - } + } bool M2Window::draw() { this->m_isActive = false; - if (iteratorUnique == nullptr && m_renderView ) { - auto l_weak = this->weak_from_this(); - iteratorUnique = m_renderView->addOnUpdate([l_weak] { - auto shared = l_weak.lock(); - if (shared) { - shared->m_needToUpdateMaterials = true; - } - }); - } - - if (m_needToUpdateMaterials) { - this->createMaterials(); - m_needToUpdateMaterials = false; - } - if (ImGui::Begin(m_windowName.c_str(), &m_showWindow)) { auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; @@ -59,7 +42,10 @@ bool M2Window::draw() { m_height = sizeY > 0 ? sizeY : 1; } - auto const ¤tMaterial = materials[currentFrame]; + //Clamp to 0 if the selected mat is too big + m_selectedMat = (m_selectedMat >= materials.size()) ? 0 : m_selectedMat; + + auto const ¤tMaterial = (m_selectedMat < materials.size()) ? std::get<1>(materials[m_selectedMat])[currentFrame] : nullptr; if (currentMaterial) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); @@ -94,16 +80,6 @@ bool M2Window::draw() { return m_showWindow; } -void M2Window::createMaterials() { - m_renderView->iterateOverOutputTextures([&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, - const std::string &name, ITextureFormat textureFormat) { - if (textureFormat == ITextureFormat::itRGBA) { - for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { - materials[i] = m_uiRenderer->createUIMaterial(textures[i]); - } - } - }); -} void M2Window::render(double deltaTime, const HFrameScenario &scenario, const std::function &updateFrameNumberLambda) { @@ -115,3 +91,20 @@ void M2Window::render(double deltaTime, const HFrameScenario &scenario, SceneWindow::render(deltaTime, 60, scenario, nullptr, updateFrameNumberLambda); } + +bool M2Window::isActive() const {return m_isActive;} + +void M2Window::setSelectedMat(uint8_t matIndex) { + m_selectedMat = matIndex; +} + +std::vector>> M2Window::getMaterials() { + std::vector>> result; + + auto currentFrame = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; + for (auto &matArray : materials) { + result.push_back(std::make_tuple(std::get<0>(matArray), std::get<1>(matArray)[currentFrame])); + } + + return result; +} diff --git a/src/ui/childWindow/m2Window/M2Window.h b/src/ui/childWindow/m2Window/M2Window.h index 40d08a49b..fa0698b83 100644 --- a/src/ui/childWindow/m2Window/M2Window.h +++ b/src/ui/childWindow/m2Window/M2Window.h @@ -20,25 +20,17 @@ class M2Window : public SceneWindow, public std::enable_shared_from_this &updateFrameNumberLambda); - bool isActive() const {return m_isActive;}; -private: - void createMaterials(); + bool isActive() const;; + void setSelectedMat(uint8_t matIndex) override; + std::vector>> getMaterials() override; private: std::string m_windowName = ""; bool m_showWindow = true; bool m_isActive = false; - - bool m_needToUpdateMaterials = false; + uint8_t m_selectedMat = 0; uint16_t m_width = 640; uint16_t m_height = 480; - - std::shared_ptr m_uiRenderer; - - typedef std::list>::const_iterator OnUpdateIter; - std::unique_ptr iteratorUnique = nullptr; - - std::array, IDevice::MAX_FRAMES_IN_FLIGHT> materials = {nullptr}; }; diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index 8576edcee..85708606f 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -11,7 +11,6 @@ #include "../../../screenshots/screenshotMaker.h" #include "../../../../wowViewerLib/src/engine/camera/m2TiedCamera.h" - void updateCameraPosOnLoad(const std::shared_ptr &m2Object, const std::shared_ptr &camera, std::vector> &cameraList) { if (m2Object->isMainDataLoaded()) { CAaBox aabb = m2Object->getColissionAABB(); @@ -121,10 +120,18 @@ inline HMapSceneParams createMapSceneParams(const HApiContainer &apiContainer, return result; } -SceneWindow::SceneWindow(const HApiContainer &api, bool renderToSwapChain) : m_api(api), m_renderToSwapChain(renderToSwapChain){ +SceneWindow::SceneWindow(const HApiContainer &api, bool renderToSwapChain, const std::shared_ptr &uiRenderer) : + m_api(api), m_renderToSwapChain(renderToSwapChain) +{ } +SceneWindow::~SceneWindow() { + if (m_renderView) { + m_renderView->eraseOnUpdate(iteratorUnique); + } +} + /* std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneType, const std::string& name, int cameraNum) { apiContainer->camera = std::make_shared(); @@ -301,6 +308,22 @@ SceneWindow::render(double deltaTime, m_renderView = m_sceneRenderer->createRenderView(true); } + if (iteratorUnique == nullptr && m_renderView ) { + auto l_weak = this->weak_from_this(); + iteratorUnique = m_renderView->addOnUpdate([l_weak] { + auto shared = l_weak.lock(); + if (shared) { + shared->m_needToUpdateMaterials = true; + } + }); + } + + if (m_needToUpdateMaterials) { + this->createMaterials(); + m_needToUpdateMaterials = false; + } + + currentCamera->tick(deltaTime * 1000.0f); if (m_api->getConfig()->pauseAnimation) { @@ -397,3 +420,19 @@ SceneWindow::makeScreenshot(float fov, }, screenshotFilename, screenShotWidth, screenShotHeight); }); } + +void SceneWindow::createMaterials() { + materials = {}; + m_renderView->iterateOverOutputTextures([&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, + const std::string &name, ITextureFormat textureFormat) { + auto &matArrayTuple = materials.emplace_back(); + std::get<0>(matArrayTuple) = name; + + auto &matArray = std::get<1>(matArrayTuple); + if (textureFormat == ITextureFormat::itRGBA) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + matArray[i] = m_uiRenderer->createUIMaterial(textures[i]); + } + } + }); +} diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 0ea51defd..cc2b2519e 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -12,6 +12,8 @@ #include "../../../../wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h" #include "../../../../wowViewerLib/src/engine/objects/iScene.h" #include "../../../../wowViewerLib/src/renderer/frame/SceneScenario.h" +#include "../../renderer/uiScene/materials/UIMaterial.h" +#include "../../renderer/uiScene/FrontendUIRenderer.h" struct RenderTargetParameters { std::shared_ptr camera; @@ -19,9 +21,10 @@ struct RenderTargetParameters { std::shared_ptr target; }; -class SceneWindow { +class SceneWindow : public std::enable_shared_from_this { public: - SceneWindow(const HApiContainer &api, bool renderToSwapChain); + SceneWindow(const HApiContainer &api, bool renderToSwapChain, const std::shared_ptr &uiRenderer); + ~SceneWindow(); void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); @@ -62,11 +65,22 @@ class SceneWindow { else m_currentCameraIndex = -1; } + + virtual void setSelectedMat(uint8_t matIndex) {}; + virtual std::vector>> getMaterials() { + return {}; + }; private: std::shared_ptr m_sceneRenderer = nullptr; std::shared_ptr m_currentScene = nullptr; bool m_renderToSwapChain = true; +private: + void createMaterials(); + + bool m_needToUpdateMaterials = true; + typedef std::list>::const_iterator OnUpdateIter; + std::unique_ptr iteratorUnique = nullptr; protected: float movementSpeed = 1; HApiContainer m_api; @@ -76,7 +90,12 @@ class SceneWindow { int m_currentCameraIndex = -1; std::vector> m_cameraList; + std::shared_ptr m_uiRenderer; + std::shared_ptr m_renderView = nullptr; + std::vector, IDevice::MAX_FRAMES_IN_FLIGHT>>> materials = {}; + + }; diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 0dd53ebe6..8da8c0f46 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -7,7 +7,6 @@ #include "../../../../wowViewerLib/src/renderer/IRenderParameters.h" #include "ImGUIPlan.h" -#include "../../../../wowViewerLib/src/engine/shader/ShaderDefinitions.h" #include "IFrontendUIBufferCreate.h" #include "../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index bc57c4452..04e90d2d5 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -773,6 +773,9 @@ if (1) add_subdirectory(shaders) add_dependencies(WoWViewerLib SPIRV_EXTRACT_META) +# message("SPIRV_META_DIR (include) = ${SPIRV_META_DIR}") + target_include_directories(WoWViewerLib PUBLIC ${SPIRV_META_DIR}) + if (LINK_OGL2) add_dependencies(WoWViewerLib ShadersGLSL20) endif() diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 8276acbf8..602be1fab 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -19,7 +19,8 @@ endif() message(INFO "GLSL_TARGET_FOLDER = ${GLSL_TARGET_FOLDER}") -set(SPIRV_META_FILE ${PROJECT_SOURCE_DIR}/src/engine/shader/ShaderDefinitions.h) +set(SPIRV_META_DIR ${CMAKE_BINARY_DIR}/shader_meta/ PARENT_SCOPE) +set(SPIRV_META_FILE ${SPIRV_META_DIR}ShaderDefinitions.h) if(NOT ANDROID) #GLSL Compiler @@ -249,8 +250,14 @@ if (NOT EMSCRIPTEN) ) endif() if(LINK_VULKAN) - install(FILES ${SPIRV_BINARY_FILES_NON_OPT} - DESTINATION ${CMAKE_INSTALL_BINDIR}/spirv - ) + if(SPIRV_OPT_APP) + install(FILES ${SPIRV_BINARY_FILES_OPT} + DESTINATION ${CMAKE_INSTALL_BINDIR}/spirv + ) + else() + install(FILES ${SPIRV_BINARY_FILES_NON_OPT} + DESTINATION ${CMAKE_INSTALL_BINDIR}/spirv + ) + endif() endif() endif() \ No newline at end of file diff --git a/wowViewerLib/src/engine/cache/cache.h b/wowViewerLib/src/engine/cache/cache.h index 799aef82b..99174ba02 100644 --- a/wowViewerLib/src/engine/cache/cache.h +++ b/wowViewerLib/src/engine/cache/cache.h @@ -134,6 +134,7 @@ class Cache { std::unique_lock cacheLck(cacheMapMutex, std::defer_lock); cacheLck.lock(); m_cache.clear(); + m_cacheFdid.clear(); cacheLck.unlock(); } private: diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 02d5908f1..20cf69c5d 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -4,7 +4,7 @@ #include "m2Geom.h" #include "skinGeom.h" -#include "../shader/ShaderDefinitions.h" +#include #include std::atomic m2SizeLoaded = 0; diff --git a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp index 790bcb0aa..c3c735d6e 100644 --- a/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp +++ b/wowViewerLib/src/engine/geometry/wmoGroupGeom.cpp @@ -4,7 +4,7 @@ #include "wmoGroupGeom.h" #include "../persistance/header/wmoFileHeader.h" -#include "../shader/ShaderDefinitions.h" +#include #include "../../gapi/interface/IDevice.h" #include "../algorithms/mathHelper.h" #include "../algorithms/animate.h" diff --git a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp index 828419e9d..e700a695b 100644 --- a/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp +++ b/wowViewerLib/src/engine/managers/CRibbonEmitter.cpp @@ -2,7 +2,7 @@ #include #include "CRibbonEmitter.h" #include "../../gapi/interface/IVertexBufferBindings.h" -#include "../shader/ShaderDefinitions.h" +#include #include "../../../3rdparty/mathfu/include/mathfu/glsl_mappings.h" #include "../../gapi/UniformBufferStructures.h" #include "../../gapi/interface/materials/IMaterial.h" diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 3a7b6853c..4be9967a9 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -6,7 +6,7 @@ #include "../../../gapi/interface/meshes/IParticleMesh.h" #include "../../algorithms/mathHelper.h" #include "../../algorithms/animate.h" -#include "../../shader/ShaderDefinitions.h" +#include #include "generators/CParticleGenerator.h" #include "generators/CSphereGenerator.h" #include "generators/CPlaneGenerator.h" diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index b34606906..60f7620c7 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -4,7 +4,6 @@ #include "ViewsObjects.h" #include "../../gapi/UniformBufferStructures.h" -#include "../shader/ShaderDefinitions.h" #include "oneapi/tbb/parallel_for.h" #if (__AVX__ && __SSE2__) diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 1782ac340..ad856a455 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -5,7 +5,7 @@ #include #include #include "adtObject.h" -#include "../../shader/ShaderDefinitions.h" +#include #include "../../algorithms/mathHelper.h" #include "../../persistance/adtFile.h" #include "../../persistance/wdtFile.h" diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 69e39310e..3907c66b8 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -728,14 +728,10 @@ uint8_t miniLogic(const CImVector *a2) { return v10; } -void M2Object::setDiffuseColor(CImVector& value) { +void M2Object::setDiffuseColor(CImVector& value, float intensity) { this->m_localDiffuseColor = value; - this->m_localDiffuseColorV = mathfu::vec4( - value.r / 255.0f, - value.g / 255.0f, - value.b / 255.0f, - value.a / 255.0f); + this->m_localDiffuseColorV = ImVectorToVec4(value) * intensity; if (value.a != 255) { // std::cout << "Found index into MOLT = " << (int)value.a << std::endl; @@ -1057,8 +1053,8 @@ void M2Object::collectLights(std::vector &pointLights) { auto &pointLight = pointLights.emplace_back(); pointLight.attenuation = mathfu::vec4(m2Light.attenuation_start, m2Light.diffuse_intensity, m2Light.attenuation_end, 0); - pointLight.innerColor = m2Light.diffuse_color ; - pointLight.outerColor = m2Light.diffuse_color ; + pointLight.innerColor = m2Light.diffuse_color * m2Light.diffuse_intensity; + pointLight.outerColor = m2Light.diffuse_color * m2Light.diffuse_intensity; pointLight.position = m2Light.position; pointLight.blendParams = mathfu::vec4(0,0,0,0); } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 2b8bef574..f0bf9943d 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -278,7 +278,7 @@ class M2Object : public ObjectWithId { void drawBB(mathfu::vec3 &color); - void setDiffuseColor(CImVector& value); + void setDiffuseColor(CImVector& value, float intensity); HBlpTexture getBlpTextureData(int textureInd); HGSamplableTexture getTexture(int textureInd); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 28f727864..230ad7cfe 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -13,7 +13,7 @@ #include "../../../gapi/interface/IDevice.h" #include "../../algorithms/quick-sort-omp.h" #include "../../../gapi/UniformBufferStructures.h" -#include "../../shader/ShaderDefinitions.h" +#include #include "tbb/tbb.h" #include "../../algorithms/FrameCounter.h" diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 321c47b48..807e716c8 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -101,12 +101,12 @@ std::shared_ptr WmoObject::getDoodad(int index) { if (doodadDef->color.a != 255 && doodadDef->color.a < this->mainGeom->lightsLen) { auto &light = this->mainGeom->lights[doodadDef->color.a]; - m2Object->setDiffuseColor(light.color); + m2Object->setDiffuseColor(light.color, light.intensity); // std::cout << "Found index into MOLT = " << (int)doodadDef->color.a << std::endl; } else { - m2Object->setDiffuseColor(doodadDef->color); + m2Object->setDiffuseColor(doodadDef->color, 1.0f); } this->m_doodadsUnorderedMap[index] = m2Object; diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h deleted file mode 100644 index 5b15409f4..000000000 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ /dev/null @@ -1,4269 +0,0 @@ -#ifndef WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H -#define WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H - -#include -#include -#include -#include -#include -#include -#include - -template -inline constexpr const uint32_t operator+ (T const val) { return static_cast(val); }; -struct fieldDefine { - std::string name; - bool isFloat ; - int offset; - int columns; - int vecSize; - int arraySize; -}; -struct attributeDefine { - std::string name; - int location; -}; - - constexpr const int MAX_SHADER_DESC_SETS = 8; - - enum class ShaderStage { - Unk, Vertex, Fragment, RayGenerate, RayAnyHit, RayClosestHit, RayMiss - }; - - - struct uboBindingData { - unsigned int set; - unsigned int binding; - unsigned long long size; - }; - struct ssboBindingData { - unsigned int set; - unsigned int binding; - unsigned long long size; - }; - struct imageBindingData { - unsigned int set; - unsigned int binding; - std::string imageName; - }; - - struct bindingAmountData { - unsigned int start = 999; - unsigned int end = 0; - unsigned int length = 0; - }; - - struct shaderMetaData { - ShaderStage stage; - - std::vector uboBindings; - std::array uboBindingAmountsPerSet; - - std::vector ssboBindingData; - - std::vector imageBindings; - std::array imageBindingAmountsPerSet; - }; - - //Per file - extern const std::unordered_map shaderMetaInfo; - extern const std::unordered_map> attributesPerShaderName; - - extern const std::unordered_map>> fieldDefMapPerShaderNameVert; - - extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; - -struct drawQuad { - enum class Attribute { - position = 0, drawQuadAttributeEnd - }; -}; - -struct renderFrameBufferShader { - enum class Attribute { - a_position = 0, renderFrameBufferShaderAttributeEnd - }; -}; - -struct drawPortalShader { - enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd - }; -}; - -struct drawPoints { - enum class Attribute { - aPosition = 0, drawPointsAttributeEnd - }; -}; - -struct adtShader { - enum class Attribute { - aPos = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, adtShaderAttributeEnd - }; -}; - -struct pointLight { - enum class Attribute { - position = 0, pointLightAttributeEnd - }; -}; - -struct spotLight { - enum class Attribute { - position = 0, spotLightAttributeEnd - }; -}; - -struct imguiShader { - enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd - }; -}; - -struct wmoShader { - enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoAmbient = 9, wmoShaderAttributeEnd - }; -}; - -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct skyConus { - enum class Attribute { - aPosition = 0, skyConusAttributeEnd - }; -}; - -struct m2Shader { - enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd - }; -}; - -struct drawLinesShader { - enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd - }; -}; - -struct ribbonShader { - enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd - }; -}; - -struct m2ParticleShader { - enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd - }; -}; - -struct waterShader { - enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd - }; -}; - -struct waterfallShader { - enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd - }; -}; - -struct adtLodShader { - enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd - }; -}; - -struct drawFrustumShader { - enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd - }; -}; - -std::string loadShader(std::string shaderName); -#ifdef SHADERDATACPP -const std::unordered_map> attributesPerShaderName = { -{ "drawQuad", - { - { "position", 0}, - } -}, -{ "renderFrameBufferShader", - { - { "a_position", 0}, - } -}, -{ "drawPortalShader", - { - { "aPosition", 0}, - } -}, -{ "drawPoints", - { - { "aPosition", 0}, - } -}, -{ "adtShader", - { - { "aPos", 0}, - { "aColor", 1}, - { "aVertexLighting", 2}, - { "aNormal", 3}, - } -}, -{ "pointLight", - { - { "position", 0}, - } -}, -{ "spotLight", - { - { "position", 0}, - } -}, -{ "imguiShader", - { - { "Position", 0}, - { "UV", 1}, - { "Color", 2}, - } -}, -{ "wmoShader", - { - { "aPosition", 0}, - { "aNormal", 1}, - { "aTexCoord", 2}, - { "aTexCoord2", 3}, - { "aTexCoord3", 4}, - { "aTexCoord4", 5}, - { "aColor", 6}, - { "aColor2", 7}, - { "aColorSecond", 8}, - { "wmoAmbient", 9}, - } -}, -{ "drawBBShader", - { - { "aPosition", 0}, - } -}, -{ "skyConus", - { - { "aPosition", 0}, - } -}, -{ "m2Shader", - { - { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "drawLinesShader", - { - { "aPosition", 0}, - } -}, -{ "ribbonShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - } -}, -{ "m2ParticleShader", - { - { "aPosition", 0}, - { "aColor", 1}, - { "aTexcoord0", 2}, - { "aTexcoord1", 3}, - { "aTexcoord2", 4}, - { "aAlphaCutoff", 5}, - } -}, -{ "waterShader", - { - { "aPositionTransp", 0}, - { "aTexCoord", 1}, - } -}, -{ "waterfallShader", - { - { "aPosition", 0}, - { "aNormal", 1}, - { "bones", 2}, - { "boneWeights", 3}, - { "aTexCoord", 4}, - { "aTexCoord2", 5}, - } -}, -{ "adtLodShader", - { - { "aHeight", 0}, - { "aIndex", 1}, - } -}, -{ "drawFrustumShader", - { - { "aPosition", 0}, - } -}, -}; - -const std::unordered_map shaderMetaInfo = { -{ "./forwardRendering/wmoShader.vert.spv", - { - ShaderStage::Vertex, - { - {1,0,64}, - {0,0,560}, - {1,1,16}, - }, - { - { - {0,0,1}, - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/wmoShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,2,32}, - {0,0,560}, - }, - { - { - {0,0,1}, - {2,2,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {2,3, "uTexture4"}, - {2,4, "uTexture5"}, - {2,5, "uTexture6"}, - {2,6, "uTexture7"}, - {2,7, "uTexture8"}, - {2,8, "uTexture9"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,8,9}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/waterfallShader.vert.spv", - { - ShaderStage::Vertex, - { - {2,0,112}, - {1,5,4096}, - {1,2,16384}, - {0,0,560}, - {1,0,64}, - {1,1,384}, - {1,3,4096}, - {1,4,256}, - }, - { - { - {0,0,1}, - {0,5,6}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {3,3, "uBumpTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {3,3,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/waterShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - {1,0,64}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/waterShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,1,48}, - {0,0,560}, - }, - { - { - {0,0,1}, - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/skyConus.frag.spv", - { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/wmo/forward/wmoShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/m2ParticleShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/wmo/deferred/wmoShader_opaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawQuad.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,16}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/waterfall/deferred/waterFallShader_opaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, - }, - { - {3,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2Ribbon/forward/ribbonShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2Ribbon/forward/ribbonShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,1,16}, - {0,0,560}, - }, - { - { - {0,0,1}, - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,0,4096}, - }, - { - {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/forward/m2Shader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2Particle/deferred/m2ParticleShader_opaq_deferred.frag.spv", - { - ShaderStage::Fragment, - { - {1,0,32}, - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,2,3}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/lights/pointLight.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,0,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/ffxglow.frag.spv", - { - ShaderStage::Fragment, - { - {0,1,16}, - }, - { - { - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "screenTex"}, - {1,1, "blurTex"}, - }, - { - { - {0,0,0}, - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/adt/deferred/adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/ribbonShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/wmo/forward/wmoShader_opaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/deferred/m2Shader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - {1,1,48}, - {1,0,64}, - }, - { - { - {0,0,1}, - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uLayer0"}, - {2,1, "uLayer1"}, - {2,2, "uLayer2"}, - {2,3, "uLayer3"}, - {2,5, "uLayerHeight0"}, - {2,6, "uLayerHeight1"}, - {2,7, "uLayerHeight2"}, - {2,8, "uLayerHeight3"}, - {2,4, "uAlphaTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,8,9}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawDepthShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,2,12}, - }, - { - { - {2,2,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,3, "diffuse"}, - }, - { - { - {3,3,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/ffxgauss4.frag.spv", - { - ShaderStage::Fragment, - { - {0,1,32}, - }, - { - { - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "texture0"}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/forward/m2Shader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,7,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,8,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/wmo/forward/wmoShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,6,0}, - {1,4,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,5,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/waterfall/forward/waterfallShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {2,1,0}, - {2,0,0}, - {1,1,0}, - {1,2,0}, - {1,3,0}, - {1,4,0}, - {1,5,0}, - {1,6,0}, - {1,7,0}, - {1,8,0}, - {1,9,0}, - }, - { - {3,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/lights/spotLight.frag.spv", - { - ShaderStage::Fragment, - { - {1,3,16}, - {0,0,560}, - }, - { - { - {0,0,1}, - {3,3,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,0,0}, - }, - { - {1,2, "normalTex"}, - {1,1, "depthTex"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/waterfall/forward/waterfallShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {2,1,0}, - {1,7,0}, - {2,0,0}, - {1,6,0}, - {1,3,0}, - {1,1,0}, - {1,2,0}, - {1,4,0}, - {1,5,0}, - {1,8,0}, - {1,9,0}, - }, - { - {3,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/forward/m2Shader_opaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/water/waterShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,2,0}, - {1,0,0}, - {1,1,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/water/waterShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,2,0}, - {1,1,0}, - {1,0,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - {2,0, "s_Textures"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/ribbonShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,1,16}, - {1,0,4096}, - {0,0,560}, - }, - { - { - {0,0,1}, - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/renderFrameBufferShader.vert.spv", - { - ShaderStage::Vertex, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/adt/forward/adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/wmo/deferred/wmoShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,6,0}, - {1,4,0}, - {1,3,0}, - {1,5,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/adt/forward/adtShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/adtLodShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,144}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/m2Shader.vert.spv", - { - ShaderStage::Vertex, - { - {1,2,16384}, - {1,0,64}, - {0,0,560}, - {1,1,384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - {2,0,64}, - }, - { - { - {0,0,1}, - {0,5,6}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/waterfallShader.frag.spv", - { - ShaderStage::Fragment, - { - {2,0,112}, - {0,0,560}, - {1,0,64}, - {1,1,384}, - {1,2,16384}, - {1,3,4096}, - {1,4,256}, - {1,5,4096}, - }, - { - { - {0,0,1}, - {0,5,6}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {3,4, "uNormalTex"}, - {3,2, "uNoise"}, - {3,1, "uWhiteWater"}, - {3,0, "uMask"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,4,5}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/adt/visbuffer/adtShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {2,0, "s_LayerTextures"}, - {4,0, "s_LayerHeightTextures"}, - {3,0, "s_AlphaTextures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/adt/visbuffer/adtShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,3,0}, - {1,1,0}, - {1,2,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/lights/pointLight.frag.spv", - { - ShaderStage::Fragment, - { - {1,3,16}, - {0,0,560}, - }, - { - { - {0,0,1}, - {3,3,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,0,0}, - }, - { - {1,2, "normalTex"}, - {1,1, "depthTex"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2/deferred/m2Shader_opaq.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,9,0}, - {1,8,0}, - {1,7,0}, - {1,2,0}, - {1,5,0}, - {1,4,0}, - {1,6,0}, - {1,1,0}, - {1,3,0}, - }, - { - {2,0, "s_Textures"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/skyConus.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - {1,0,96}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawPoints.frag.spv", - { - ShaderStage::Fragment, - { - {0,1,12}, - }, - { - { - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/lights/spotLight.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - {1,0,0}, - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2Particle/forward/m2ParticleShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/adtLodShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,0,84}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,4, "uDiffuseTexture"}, - {0,5, "uNormalTexture"}, - }, - { - { - {4,5,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/adtShader.vert.spv", - { - ShaderStage::Vertex, - { - {1,0,64}, - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawPortalShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,0,16}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/imguiShaderDepth.frag.spv", - { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "Texture"}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawBBShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,1,112}, - }, - { - { - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawBBShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,1,112}, - {0,0,560}, - }, - { - { - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawPoints.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,128}, - {0,1,64}, - }, - { - { - {0,1,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawFrustumShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,2,12}, - }, - { - { - {2,2,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawFrustumShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,128}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawLinesShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,1,12}, - }, - { - { - {1,1,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/imguiShader_opaque.frag.spv", - { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "Texture"}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawLinesShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,128}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/drawPortalShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./bindless/m2Particle/forward/m2ParticleShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,0,32}, - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,2,3}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/m2ParticleShader.frag.spv", - { - ShaderStage::Fragment, - { - {1,0,32}, - {0,0,560}, - }, - { - { - {0,0,1}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {2,0, "uTexture"}, - {2,1, "uTexture2"}, - {2,2, "uTexture3"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,2,3}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/imguiShader.frag.spv", - { - ShaderStage::Fragment, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {1,0, "Texture"}, - }, - { - { - {0,0,0}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/imguiShader.vert.spv", - { - ShaderStage::Vertex, - { - {0,0,80}, - }, - { - { - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - }, - { - { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/renderFrameBufferShader.frag.spv", - { - ShaderStage::Fragment, - { - {0,2,168}, - }, - { - { - {2,2,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {0,3, "u_sampler"}, - {0,4, "u_depth"}, - }, - { - { - {3,4,2}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -{ "./forwardRendering/m2Shader.frag.spv", - { - ShaderStage::Fragment, - { - {2,0,64}, - {1,4,256}, - {1,3,4096}, - {1,1,384}, - {0,0,560}, - {1,0,64}, - {1,5,4096}, - {1,2,16384}, - }, - { - { - {0,0,1}, - {0,5,6}, - {0,0,1}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - }, - { - }, - { - {3,0, "uTexture"}, - {3,1, "uTexture2"}, - {3,2, "uTexture3"}, - {3,3, "uTexture4"}, - {0,1, "lightBuffer"}, - {0,2, "aoBuffer"}, - }, - { - { - {1,2,2}, - {0,0,0}, - {0,0,0}, - {0,3,4}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - } - } - } -}, -}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"drawQuad", { - { - 0, { - {"_0_0_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, - } - }, - }}, - {"renderFrameBufferShader", { - }}, - {"drawPortalShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"drawPoints", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"adtShader", { - { - 2, { - } - }, - { - 1, { - } - }, - { - 3, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"pointLight", { - { - 0, { - } - }, - }}, - {"spotLight", { - { - 0, { - } - }, - }}, - {"imguiShader", { - { - 0, { - {"_0_0_ProjMtx", true, 0, 4, 4, 0}, - {"_0_0_uiScale", true, 64, 1, 4, 0}, - } - }, - }}, - {"wmoShader", { - { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, - } - }, - { - 3, { - } - }, - { - 2, { - {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_VertexShader_UseLitColor", false, 0, 1, 4, 0}, - } - }, - { - 4, { - } - }, - { - 6, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, - }}, - {"skyConus", { - { - 0, { - {"_1_0_skyColor[0]", true, 0, 1, 4, 6}, - } - }, - }}, - {"m2Shader", { - { - 8, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 2, { - {"_1_2_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 1, { - {"_1_1_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_1_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_1_pc_lights[0].innerColor", true, 32, 1, 4, 0}, - {"_1_1_pc_lights[0].outerColor", true, 48, 1, 4, 0}, - {"_1_1_pc_lights[0].position", true, 64, 1, 4, 0}, - {"_1_1_pc_lights[0].attenuation", true, 80, 1, 4, 0}, - {"_1_1_pc_lights[0].blendParams", true, 96, 1, 4, 0}, - {"_1_1_pc_lights[1].innerColor", true, 112, 1, 4, 0}, - {"_1_1_pc_lights[1].outerColor", true, 128, 1, 4, 0}, - {"_1_1_pc_lights[1].position", true, 144, 1, 4, 0}, - {"_1_1_pc_lights[1].attenuation", true, 160, 1, 4, 0}, - {"_1_1_pc_lights[1].blendParams", true, 176, 1, 4, 0}, - {"_1_1_pc_lights[2].innerColor", true, 192, 1, 4, 0}, - {"_1_1_pc_lights[2].outerColor", true, 208, 1, 4, 0}, - {"_1_1_pc_lights[2].position", true, 224, 1, 4, 0}, - {"_1_1_pc_lights[2].attenuation", true, 240, 1, 4, 0}, - {"_1_1_pc_lights[2].blendParams", true, 256, 1, 4, 0}, - {"_1_1_pc_lights[3].innerColor", true, 272, 1, 4, 0}, - {"_1_1_pc_lights[3].outerColor", true, 288, 1, 4, 0}, - {"_1_1_pc_lights[3].position", true, 304, 1, 4, 0}, - {"_1_1_pc_lights[3].attenuation", true, 320, 1, 4, 0}, - {"_1_1_pc_lights[3].blendParams", true, 336, 1, 4, 0}, - {"_1_1_lightCountAndBcHack", false, 352, 1, 4, 0}, - {"_1_1_interiorExteriorBlend", true, 368, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 7, { - } - }, - { - 9, { - } - }, - { - 0, { - {"_2_0_vertexShader_IsAffectedByLight_TextureMatIndex1_TextureMatIndex2", false, 0, 1, 4, 0}, - {"_2_0_PixelShader_UnFogged_blendMode", false, 16, 1, 4, 0}, - {"_2_0_textureWeightIndexes", false, 32, 1, 4, 0}, - {"_2_0_colorIndex_applyWeight", false, 48, 1, 4, 0}, - } - }, - }}, - {"drawLinesShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"ribbonShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"m2ParticleShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"waterShader", { - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, - { - 0, { - {"_1_0_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - }}, - {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 5, { - {"_1_5_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 2, { - {"_1_2_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 3, { - {"_1_3_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 7, { - } - }, - { - 1, { - {"_1_1_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_1_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_1_pc_lights[0].innerColor", true, 32, 1, 4, 0}, - {"_1_1_pc_lights[0].outerColor", true, 48, 1, 4, 0}, - {"_1_1_pc_lights[0].position", true, 64, 1, 4, 0}, - {"_1_1_pc_lights[0].attenuation", true, 80, 1, 4, 0}, - {"_1_1_pc_lights[0].blendParams", true, 96, 1, 4, 0}, - {"_1_1_pc_lights[1].innerColor", true, 112, 1, 4, 0}, - {"_1_1_pc_lights[1].outerColor", true, 128, 1, 4, 0}, - {"_1_1_pc_lights[1].position", true, 144, 1, 4, 0}, - {"_1_1_pc_lights[1].attenuation", true, 160, 1, 4, 0}, - {"_1_1_pc_lights[1].blendParams", true, 176, 1, 4, 0}, - {"_1_1_pc_lights[2].innerColor", true, 192, 1, 4, 0}, - {"_1_1_pc_lights[2].outerColor", true, 208, 1, 4, 0}, - {"_1_1_pc_lights[2].position", true, 224, 1, 4, 0}, - {"_1_1_pc_lights[2].attenuation", true, 240, 1, 4, 0}, - {"_1_1_pc_lights[2].blendParams", true, 256, 1, 4, 0}, - {"_1_1_pc_lights[3].innerColor", true, 272, 1, 4, 0}, - {"_1_1_pc_lights[3].outerColor", true, 288, 1, 4, 0}, - {"_1_1_pc_lights[3].position", true, 304, 1, 4, 0}, - {"_1_1_pc_lights[3].attenuation", true, 320, 1, 4, 0}, - {"_1_1_pc_lights[3].blendParams", true, 336, 1, 4, 0}, - {"_1_1_lightCountAndBcHack", false, 352, 1, 4, 0}, - {"_1_1_interiorExteriorBlend", true, 368, 1, 4, 0}, - } - }, - { - 0, { - {"_1_0_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_0_0_uPos", true, 0, 1, 3, 0}, - {"_0_0_uLookAtMat", true, 16, 4, 4, 0}, - {"_0_0_uPMatrix", true, 80, 4, 4, 0}, - } - }, - }}, - {"drawFrustumShader", { - { - 0, { - {"_0_0_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"imguiShaderDepth", { - }}, - {"ffxglow", { - { - 1, { - {"_0_1_blurAmount", true, 0, 1, 4, 0}, - } - }, - }}, - {"renderFrameBufferShader", { - { - 2, { - {"_0_2_gauss_offsets[0]", true, 0, 1, 1, 5}, - {"_0_2_gauss_weights[0]", true, 80, 1, 1, 5}, - {"_0_2_uResolution", true, 160, 1, 2, 0}, - } - }, - }}, - {"drawPortalShader", { - { - 0, { - {"_1_0_uColor", true, 0, 1, 4, 0}, - } - }, - }}, - {"drawPoints", { - { - 1, { - {"_0_1_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"ffxgauss4", { - { - 1, { - {"_0_1_texOffsetX", true, 0, 1, 4, 0}, - {"_0_1_texOffsetY", true, 16, 1, 4, 0}, - } - }, - }}, - {"drawFrustumShader", { - { - 2, { - {"_0_2_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawDepthShader", { - { - 2, { - {"_0_2_drawDepth", false, 0, 1, 1, 0}, - {"_0_2_uFarPlane", true, 4, 1, 1, 0}, - {"_0_2_uNearPlane", true, 8, 1, 1, 0}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_0_0_uViewUp", true, 0, 1, 4, 0}, - {"_0_0_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_0_0_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_0_0_uAmbientLight", true, 48, 1, 4, 0}, - {"_0_0_FogColor", true, 64, 1, 4, 0}, - {"_0_0_uNewFormula", false, 80, 1, 1, 0}, - } - }, - }}, - {"adtShader", { - { - 2, { - } - }, - { - 1, { - {"_1_1_scaleFactorPerLayer", true, 0, 1, 4, 0}, - {"_1_1_animation_rotationPerLayer", false, 16, 1, 4, 0}, - {"_1_1_animation_speedPerLayer", false, 32, 1, 4, 0}, - } - }, - { - 3, { - } - }, - { - 0, { - {"_1_0_uPos", true, 0, 1, 4, 0}, - {"_1_0_uUseHeightMixFormula", false, 16, 1, 4, 0}, - {"_1_0_uHeightScale", true, 32, 1, 4, 0}, - {"_1_0_uHeightOffset", true, 48, 1, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_0_1_uPlacementMat", true, 0, 4, 4, 0}, - {"_0_1_uBBScale", true, 64, 1, 4, 0}, - {"_0_1_uBBCenter", true, 80, 1, 4, 0}, - {"_0_1_uColor", true, 96, 1, 4, 0}, - } - }, - }}, - {"m2Shader_opaq", { - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 2, { - } - }, - { - 7, { - } - }, - { - 8, { - } - }, - { - 9, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"m2ParticleShader_opaq_deferred", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"imguiShader_opaque", { - }}, - {"pointLight", { - { - 0, { - } - }, - { - 3, { - {"_1_3_screenSize", true, 0, 1, 4, 0}, - } - }, - }}, - {"spotLight", { - { - 0, { - } - }, - { - 3, { - {"_1_3_screenSize", true, 0, 1, 4, 0}, - } - }, - }}, - {"imguiShader", { - }}, - {"wmoShader", { - { - 2, { - {"_1_2_UseLitColor_EnableAlpha_PixelShader_BlendMode", false, 0, 1, 4, 0}, - {"_1_2_FogColor_AlphaTest", true, 16, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, - } - }, - { - 3, { - } - }, - { - 4, { - } - }, - { - 6, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"skyConus", { - }}, - {"m2Shader", { - { - 3, { - {"_1_3_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 1, { - {"_1_1_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_1_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_1_pc_lights[0].innerColor", true, 32, 1, 4, 0}, - {"_1_1_pc_lights[0].outerColor", true, 48, 1, 4, 0}, - {"_1_1_pc_lights[0].position", true, 64, 1, 4, 0}, - {"_1_1_pc_lights[0].attenuation", true, 80, 1, 4, 0}, - {"_1_1_pc_lights[0].blendParams", true, 96, 1, 4, 0}, - {"_1_1_pc_lights[1].innerColor", true, 112, 1, 4, 0}, - {"_1_1_pc_lights[1].outerColor", true, 128, 1, 4, 0}, - {"_1_1_pc_lights[1].position", true, 144, 1, 4, 0}, - {"_1_1_pc_lights[1].attenuation", true, 160, 1, 4, 0}, - {"_1_1_pc_lights[1].blendParams", true, 176, 1, 4, 0}, - {"_1_1_pc_lights[2].innerColor", true, 192, 1, 4, 0}, - {"_1_1_pc_lights[2].outerColor", true, 208, 1, 4, 0}, - {"_1_1_pc_lights[2].position", true, 224, 1, 4, 0}, - {"_1_1_pc_lights[2].attenuation", true, 240, 1, 4, 0}, - {"_1_1_pc_lights[2].blendParams", true, 256, 1, 4, 0}, - {"_1_1_pc_lights[3].innerColor", true, 272, 1, 4, 0}, - {"_1_1_pc_lights[3].outerColor", true, 288, 1, 4, 0}, - {"_1_1_pc_lights[3].position", true, 304, 1, 4, 0}, - {"_1_1_pc_lights[3].attenuation", true, 320, 1, 4, 0}, - {"_1_1_pc_lights[3].blendParams", true, 336, 1, 4, 0}, - {"_1_1_lightCountAndBcHack", false, 352, 1, 4, 0}, - {"_1_1_interiorExteriorBlend", true, 368, 1, 4, 0}, - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 4, { - {"_1_4_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 5, { - {"_1_5_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 2, { - {"_1_2_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 7, { - } - }, - { - 8, { - } - }, - { - 9, { - } - }, - { - 0, { - {"_1_0_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - }}, - {"wmoShader_opaq", { - { - 2, { - {"_1_2_VertexShader_UseLitColors", false, 0, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_s_wmoAmbient", true, 0, 1, 4, 0}, - } - }, - { - 3, { - } - }, - { - 4, { - } - }, - { - 6, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"drawLinesShader", { - { - 1, { - {"_0_1_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"ribbonShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - { - 1, { - {"_1_1_uPixelShader_BlendMode_TextureTransformIndex", false, 0, 1, 4, 0}, - } - }, - }}, - {"m2ParticleShader", { - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"waterShader", { - { - 1, { - {"_1_1_materialId_liquidFlags", false, 0, 1, 4, 0}, - {"_1_1_matColor", true, 16, 1, 4, 0}, - {"_1_1_float0_float1", true, 32, 1, 4, 0}, - } - }, - { - 2, { - } - }, - { - 0, { - {"_0_0_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_0_0_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_0_0_scene_uViewUpSceneTime", true, 128, 1, 4, 0}, - {"_0_0_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_0_0_scene_uSceneSize_DisableLightBuffer", true, 160, 1, 4, 0}, - {"_0_0_scene_closeRiverColor", true, 176, 1, 4, 0}, - {"_0_0_scene_farRiverColor", true, 192, 1, 4, 0}, - {"_0_0_scene_closeOceanColor", true, 208, 1, 4, 0}, - {"_0_0_scene_farOceanColor", true, 224, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorAmbientColor", true, 240, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorHorizontAmbientColor", true, 256, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorGroundAmbientColor", true, 272, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColor", true, 288, 1, 4, 0}, - {"_0_0_scene_extLight_uExteriorDirectColorDir", true, 304, 1, 4, 0}, - {"_0_0_scene_extLight_adtSpecMult_fogCount", true, 320, 1, 4, 0}, - {"_0_0_fogData_densityParams", true, 336, 1, 4, 0}, - {"_0_0_fogData_classicFogParams", true, 352, 1, 4, 0}, - {"_0_0_fogData_heightPlane", true, 368, 1, 4, 0}, - {"_0_0_fogData_color_and_heightRate", true, 384, 1, 4, 0}, - {"_0_0_fogData_heightDensity_and_endColor", true, 400, 1, 4, 0}, - {"_0_0_fogData_sunAngle_and_sunColor", true, 416, 1, 4, 0}, - {"_0_0_fogData_heightColor_and_endFogDistance", true, 432, 1, 4, 0}, - {"_0_0_fogData_sunPercentage", true, 448, 1, 4, 0}, - {"_0_0_fogData_sunDirection_and_fogZScalar", true, 464, 1, 4, 0}, - {"_0_0_fogData_heightFogCoeff", true, 480, 1, 4, 0}, - {"_0_0_fogData_mainFogCoeff", true, 496, 1, 4, 0}, - {"_0_0_fogData_heightDensityFogCoeff", true, 512, 1, 4, 0}, - {"_0_0_fogData_mainFogEndDist_mainFogStartDist_legacyFogScalar_blendAlpha", true, 528, 1, 4, 0}, - {"_0_0_fogData_heightFogEndColor_fogStartOffset", true, 544, 1, 4, 0}, - } - }, - }}, - {"waterFallShader_opaq", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureWeight", true, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_1_4_colors", true, 0, 1, 4, 0}, - } - }, - { - 3, { - {"_1_3_uBoneMatrixes", true, 0, 4, 4, 0}, - } - }, - { - 2, { - } - }, - { - 1, { - {"_1_1_uPlacementMats", true, 0, 4, 4, 0}, - } - }, - { - 0, { - } - }, - }}, - {"waterfallShader", { - { - 9, { - } - }, - { - 8, { - } - }, - { - 7, { - } - }, - { - 6, { - {"_1_6_textureMatrix", true, 0, 4, 4, 0}, - } - }, - { - 5, { - {"_1_5_textureMatrix[0]", true, 0, 4, 4, 64}, - } - }, - { - 4, { - {"_1_4_textureWeight[0]", true, 0, 1, 4, 16}, - } - }, - { - 3, { - {"_1_3_colors[0]", true, 0, 1, 4, 256}, - } - }, - { - 2, { - {"_1_2_uBoneMatrixes[0]", true, 0, 4, 4, 256}, - } - }, - { - 1, { - {"_1_1_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_1_1_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_1_1_pc_lights[0].innerColor", true, 32, 1, 4, 0}, - {"_1_1_pc_lights[0].outerColor", true, 48, 1, 4, 0}, - {"_1_1_pc_lights[0].position", true, 64, 1, 4, 0}, - {"_1_1_pc_lights[0].attenuation", true, 80, 1, 4, 0}, - {"_1_1_pc_lights[0].blendParams", true, 96, 1, 4, 0}, - {"_1_1_pc_lights[1].innerColor", true, 112, 1, 4, 0}, - {"_1_1_pc_lights[1].outerColor", true, 128, 1, 4, 0}, - {"_1_1_pc_lights[1].position", true, 144, 1, 4, 0}, - {"_1_1_pc_lights[1].attenuation", true, 160, 1, 4, 0}, - {"_1_1_pc_lights[1].blendParams", true, 176, 1, 4, 0}, - {"_1_1_pc_lights[2].innerColor", true, 192, 1, 4, 0}, - {"_1_1_pc_lights[2].outerColor", true, 208, 1, 4, 0}, - {"_1_1_pc_lights[2].position", true, 224, 1, 4, 0}, - {"_1_1_pc_lights[2].attenuation", true, 240, 1, 4, 0}, - {"_1_1_pc_lights[2].blendParams", true, 256, 1, 4, 0}, - {"_1_1_pc_lights[3].innerColor", true, 272, 1, 4, 0}, - {"_1_1_pc_lights[3].outerColor", true, 288, 1, 4, 0}, - {"_1_1_pc_lights[3].position", true, 304, 1, 4, 0}, - {"_1_1_pc_lights[3].attenuation", true, 320, 1, 4, 0}, - {"_1_1_pc_lights[3].blendParams", true, 336, 1, 4, 0}, - {"_1_1_lightCountAndBcHack", false, 352, 1, 4, 0}, - {"_1_1_interiorExteriorBlend", true, 368, 1, 4, 0}, - } - }, - { - 0, { - {"_1_0_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - }}, -}; -#endif - - -#endif diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 8f3ded29c..208036def 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -204,7 +204,7 @@ std::set get_supported_extensions() { GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::make_shared(*this)), m_descriptorSetUpdater(std::make_shared()){ - enableValidationLayers = true; + enableValidationLayers = false; if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h index 1babb4df7..51dbcfb08 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.h @@ -13,7 +13,7 @@ class IDeviceVulkan; #include #include "../context/vulkan_context.h" #include "../IDeviceVulkan.h" -#include "../../../engine/shader/ShaderDefinitions.h" +#include #include "../shaders/ShaderConfig.h" class GDescriptorSetLayout { diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 08bcc810e..d6f6eab7e 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -6,7 +6,7 @@ #include "GShaderPermutationVLK.h" #include "../../../engine/stringTrim.h" #include "../../../engine/algorithms/hashString.h" -#include "../../../engine/shader/ShaderDefinitions.h" +#include #include "../../UniformBufferStructures.h" #include "../../interface/IDevice.h" #include diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index 52aa5e6ed..dd7e275e2 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -11,7 +11,7 @@ #include "../GDeviceVulkan.h" #include "../../interface/IShaderPermutation.h" #include "../descriptorSets/GDescriptorSet.h" -#include "../../../engine/shader/ShaderDefinitions.h" +#include struct ShaderSetLayout { diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index c80500c64..d8e9bb991 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -250,7 +250,7 @@ void GTextureVLK::createVulkanImageObject(bool isDepthTexture, const VkFormat te VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; } else { - view.components = {VK_COMPONENT_SWIZZLE_IDENTITY}; + view.components = {VK_COMPONENT_SWIZZLE_R}; } // The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view // It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 1d0ac715f..9a133146e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -13,7 +13,7 @@ #include "MapScenePlan.h" #include "../../gapi/interface/buffers/IBufferVersioned.h" -#include "../../engine/shader/ShaderDefinitions.h" +#include #include "../../engine/algorithms/FrameCounter.h" static const std::vector staticWMOBindings = {{ diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 4550acdc4..d08a70444 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -58,7 +58,7 @@ void RenderViewDeferredVLK::createFrameBuffers() { }; auto const lightBufferFormat = { - ITextureFormat::itRGBAFloat32 //Color + ITextureFormat::itRGBA //Color }; @@ -404,7 +404,25 @@ void RenderViewDeferredVLK::iterateOverOutputTextures( callback(colorTextures, "Color Texture", ITextureFormat::itRGBA); } - //2. Depth buffer + //2. Light Buffer + { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> normalBufferTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + normalBufferTextures[i] = m_gBufferFrameBuffers[i]->getAttachment(0); + + callback(normalBufferTextures, "Normal buffer", ITextureFormat::itRGBA); + } + + //3. Light Buffer + { + std::array, IDevice::MAX_FRAMES_IN_FLIGHT> lightBufferTextures; + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) + lightBufferTextures[i] = m_lightFrameBuffers[i]->getAttachment(0); + + callback(lightBufferTextures, "Light buffer", ITextureFormat::itDepth32); + } + + //4. Depth buffer { std::array, IDevice::MAX_FRAMES_IN_FLIGHT> depthTextures; for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) From 969796a2dc16d8313b140c1859bdf19adfd73321 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 13 Apr 2024 23:39:08 +0300 Subject: [PATCH 188/212] - selection of materials for windows --- src/ui/FrontendUI.cpp | 24 +++++++++++++-- src/ui/childWindow/m2Window/M2Window.h | 4 +-- .../childWindow/sceneWindow/SceneWindow.cpp | 29 ++++++++++--------- src/ui/childWindow/sceneWindow/SceneWindow.h | 2 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 2 +- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index af24f0b89..04232602d 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1614,8 +1614,25 @@ void FrontendUI::showSettingsDialog() { for (int i = 0; i < materials.size(); i++) { auto &mat = materials[i]; - if (ImGui::ImageButton(std::get<0>(mat).c_str(), std::get<1>(mat)->uniqueId, {256, 256})) { - activeScene->setCurrentCameraIndex(i); + const uint32_t thumbnailDim = 256; + + auto &textureMat = std::get<1>(mat); + if (textureMat) { + ImGui::BeginChild((std::string("mat##test_") + std::to_string(i)).c_str(), {thumbnailDim+10, thumbnailDim + 25}); + + auto const &matName = std::get<0>(mat); + + if (ImGui::ImageButton(matName.c_str(), std::get<1>(mat)->uniqueId, {thumbnailDim, thumbnailDim})) { + activeScene->setSelectedMat(i); + } + ImGui::Text(matName.c_str()); + ImGui::EndChild(); + } + if ((i+1) < materials.size()) { + if (ImGui::GetCursorPos().x + + (i + 2) * (thumbnailDim + 10 + ImGui::GetStyle().ItemSpacing.x) < ImGui::GetContentRegionMax().x) { + ImGui::SameLine(); + } } } } @@ -1934,7 +1951,8 @@ std::shared_ptr FrontendUI::getOrCreateWindow() { if (io.KeyShift) { for (int i = 0; i < m_m2Windows.size(); i++) { if (m_m2Windows[i] == nullptr) { - m_m2Windows[i] = std::make_shared(m_api, m_uiRenderer, std::to_string(i)); + auto newWindow = std::make_shared(m_api, m_uiRenderer, std::to_string(i)); + m_m2Windows[i] = newWindow; return m_m2Windows[i]; } } diff --git a/src/ui/childWindow/m2Window/M2Window.h b/src/ui/childWindow/m2Window/M2Window.h index fa0698b83..a07418954 100644 --- a/src/ui/childWindow/m2Window/M2Window.h +++ b/src/ui/childWindow/m2Window/M2Window.h @@ -10,10 +10,10 @@ #include "../../renderer/uiScene/materials/UIMaterial.h" #include "../../renderer/uiScene/FrontendUIRenderer.h" -class M2Window : public SceneWindow, public std::enable_shared_from_this { +class M2Window : public SceneWindow { public: M2Window(HApiContainer api, const std::shared_ptr &renderer, const std::string &nameSuffix = ""); - ~M2Window(); + ~M2Window() override; bool draw(); void render(double deltaTime, diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index 85708606f..889603899 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -121,7 +121,7 @@ inline HMapSceneParams createMapSceneParams(const HApiContainer &apiContainer, } SceneWindow::SceneWindow(const HApiContainer &api, bool renderToSwapChain, const std::shared_ptr &uiRenderer) : - m_api(api), m_renderToSwapChain(renderToSwapChain) + m_api(api), m_renderToSwapChain(renderToSwapChain), m_uiRenderer(uiRenderer) { } @@ -423,16 +423,19 @@ SceneWindow::makeScreenshot(float fov, void SceneWindow::createMaterials() { materials = {}; - m_renderView->iterateOverOutputTextures([&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, - const std::string &name, ITextureFormat textureFormat) { - auto &matArrayTuple = materials.emplace_back(); - std::get<0>(matArrayTuple) = name; - - auto &matArray = std::get<1>(matArrayTuple); - if (textureFormat == ITextureFormat::itRGBA) { - for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { - matArray[i] = m_uiRenderer->createUIMaterial(textures[i]); - } - } - }); + if (m_renderView) { + m_renderView->iterateOverOutputTextures( + [&](const std::array, IDevice::MAX_FRAMES_IN_FLIGHT> &textures, + const std::string &name, ITextureFormat textureFormat) { + auto &matArrayTuple = materials.emplace_back(); + std::get<0>(matArrayTuple) = name; + + auto &matArray = std::get<1>(matArrayTuple); + if (textureFormat == ITextureFormat::itRGBA) { + for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) { + matArray[i] = m_uiRenderer->createUIMaterial(textures[i], true); + } + } + }); + } } diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index cc2b2519e..fd87992d3 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -24,7 +24,7 @@ struct RenderTargetParameters { class SceneWindow : public std::enable_shared_from_this { public: SceneWindow(const HApiContainer &api, bool renderToSwapChain, const std::shared_ptr &uiRenderer); - ~SceneWindow(); + virtual ~SceneWindow(); void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index d08a70444..c8cc91afc 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -419,7 +419,7 @@ void RenderViewDeferredVLK::iterateOverOutputTextures( for (int i = 0; i < IDevice::MAX_FRAMES_IN_FLIGHT; i++) lightBufferTextures[i] = m_lightFrameBuffers[i]->getAttachment(0); - callback(lightBufferTextures, "Light buffer", ITextureFormat::itDepth32); + callback(lightBufferTextures, "Light buffer", ITextureFormat::itRGBA); } //4. Depth buffer From 0b327451fb495b2bb797e58b35fe51088af2119f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 18 Apr 2024 15:59:36 +0300 Subject: [PATCH 189/212] better handling of overrides --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 4 +- wowViewerLib/shaders/CMakeLists.txt | 10 ++++- .../glsl/bindless/lights/spotLight.frag | 20 ++++++++- .../engine/persistance/header/wmoFileHeader.h | 10 ++--- .../src/gapi/vulkan/GDeviceVulkan.cpp | 20 +++++++-- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h | 12 +++++- .../vulkan/materials/MaterialBuilderVLK.cpp | 16 ++++---- .../vulkan/materials/MaterialBuilderVLK.h | 16 ++++++-- .../vulkan/shaders/GShaderPermutationVLK.cpp | 21 +++++++--- .../vulkan/shaders/GShaderPermutationVLK.h | 7 +++- .../vulkan/MapSceneRenderBindlessVLK.cpp | 41 +++++++------------ .../vulkan/MapSceneRenderForwardVLK.cpp | 22 +++++----- .../mapScene/vulkan/passes/FFXGlowPassVLK.cpp | 4 +- .../vulkan/view/RenderViewDeferredVLK.cpp | 6 +-- 14 files changed, 130 insertions(+), 79 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index 6fdc5563c..f956bb723 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -59,7 +59,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering","forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering","forwardRendering"}, {}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() @@ -93,7 +93,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterialDepth(c } auto &l_imguiUbo = m_imguiUbo; - auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering", "forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering", "forwardRendering"}, {}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index 602be1fab..e044fa129 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -19,8 +19,12 @@ endif() message(INFO "GLSL_TARGET_FOLDER = ${GLSL_TARGET_FOLDER}") -set(SPIRV_META_DIR ${CMAKE_BINARY_DIR}/shader_meta/ PARENT_SCOPE) -set(SPIRV_META_FILE ${SPIRV_META_DIR}ShaderDefinitions.h) + +set(SPIRV_META_DIR_local ${CMAKE_BINARY_DIR}/shader_meta) +set(SPIRV_META_DIR ${SPIRV_META_DIR_local} PARENT_SCOPE) +set(SPIRV_META_FILE ${SPIRV_META_DIR_local}/ShaderDefinitions.h) + +file(MAKE_DIRECTORY SPIRV_META_DIR) if(NOT ANDROID) #GLSL Compiler @@ -205,6 +209,8 @@ configure_filesVLK( ${GLSL_TARGET_FOLDER}/glsl/glsl20/ ${GLSL_TARGET_FOLDER}/glsl/glsl3.3/) +#message("Executing ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} -sf ${GLSL_TARGET_FOLDER}/spirv ${SPIRV_BINARY_FILES} > ${SPIRV_META_FILE}") + add_custom_command( OUTPUT ${SPIRV_META_FILE} COMMAND ${APP_RUN_PREFIX} ${PATH_TO_NATIVE_SPIRV_REFLECTION} -sf ${GLSL_TARGET_FOLDER}/spirv ${SPIRV_BINARY_FILES} > ${SPIRV_META_FILE} diff --git a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag index f88d526f1..eaf7498da 100644 --- a/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag +++ b/wowViewerLib/shaders/glsl/bindless/lights/spotLight.frag @@ -39,7 +39,7 @@ void main() { // vec3 viewRay = vec3((in_viewPos.xy / vec2(in_viewPos.z)), 1.0); // vec3 viewPos = (viewRay * sceneDepth); - vec3 lightDir = -(transpose(inverse(scene.uLookAtMat)) * vec4(lightRec.directionAndcosAngleDiff.xyz, 0.0)).xyz; + vec3 lightDir = normalize(-(transpose(inverse(scene.uLookAtMat)) * vec4(lightRec.directionAndcosAngleDiff.xyz, 0.0)).xyz); vec3 lightAtten = lightRec.attenuationAndcosOuterAngle.xyz; vec3 color = lightRec.colorAndFalloff.xyz; @@ -57,6 +57,24 @@ void main() { float distanceToLightInv = inversesqrt(distanceToLightSqr); float diffuseTerm = max((dot(vectorToLight, viewNormal.xyz) * distanceToLightInv), 0.0); + //Ld is distance from spot light center + //ld = lightDir * normalize(-(vectorToLight)) * length(vectorToLight) = + // cos(angle_between_lightDir_and_vectorToLight) * length(vectorToLight) = dist_r + // +// |\ +// | \ +// | \ +// | \ +// | \ +// lightDir -> | \ <- vectorToLight +// | \ +// | \ +// | \ +// | \ +// |__________\ +// ^ +// dist_r + float ld = max(dot(lightDir, -(vectorToLight)), 0.0); float attenuation = (1.0 - clamp(((ld - lightAtten.x) * lightAtten.z), 0.0, 1.0)); ld = max(dot(lightDir, (-(vectorToLight) * distanceToLightInv)), 0.0); diff --git a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h index dcae881b0..8f649c4d1 100644 --- a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h @@ -284,17 +284,16 @@ struct SMOPoly uint8_t material_id; // index into MOMT, 0xff for collision faces }; - struct SMOBatch { union { struct { - /*0x00*/ int16_t unknown_box_min[3]; // -2,-2,-1, 2,2,3 in cameron -> seems to be a bounding box for culling - /*0x06*/ int16_t unknown_box_max[3]; + /*0x00*/ int16_t unknown_box_min[3]; // -2,-2,-1, 2,2,3 in cameron -> seems to be a bounding box for culling + /*0x06*/ int16_t unknown_box_max[3]; } preLegion; struct { - /*0x00*/ uint8_t unknown[0xA]; - /*0x0A*/ uint16_t material_id_large; // used if flag_use_uint16_t_material is set. + /*0x00*/ uint8_t unknown[0xA]; + /*0x0A*/ uint16_t material_id_large; // used if flag_use_uint16_t_material is set. } postLegion; }; @@ -317,6 +316,7 @@ struct SMOBatch //#else }; + struct t_BSP_NODE { uint16_t planeType; // 4: leaf, 0 for YZ-plane, 1 for XZ-plane, 2 for XY-plane diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 208036def..64388dccc 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -817,7 +817,8 @@ void GDeviceVLK::createLogicalDevice() { } vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); - vkGetDeviceQueue(device, indices.transferFamily.value(), 0, &uploadQueue); +// vkGetDeviceQueue(device, indices.transferFamily.value(), 0, &uploadQueue); + vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &uploadQueue); // vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); } @@ -1241,18 +1242,31 @@ void GDeviceVLK::updateBuffers(std::vector &frameDepedantDa void GDeviceVLK::uploadTextureForMeshes(std::vector &meshes) {} -std::shared_ptr GDeviceVLK::getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConfig) { +std::shared_ptr GDeviceVLK::getShader(const std::string &vertexName, const std::string &fragmentName, + const ShaderConfig &shaderConfig, + const std::unordered_map> &dsLayoutOverrides) { + + std::unordered_map override = {}; + for (const auto &rec : dsLayoutOverrides) { + override.emplace(rec.first, rec.second->getSetLayout()); + } ShaderPermutationCacheRecord cacheRecord; cacheRecord.name = vertexName + " " + fragmentName; cacheRecord.shaderConfig = shaderConfig; + cacheRecord.dsLayoutOverrides = override; if (m_shaderPermuteCache.find(cacheRecord) != m_shaderPermuteCache.end()) { HGShaderPermutation ptr = m_shaderPermuteCache.at(cacheRecord); return ptr; } - std::shared_ptr sharedPtr = std::make_shared(vertexName, fragmentName, this->shared_from_this(), shaderConfig); + std::shared_ptr sharedPtr = std::make_shared( + vertexName, fragmentName, + this->shared_from_this(), + shaderConfig, + dsLayoutOverrides + ); sharedPtr->compileShader("", ""); m_shaderPermuteCache[cacheRecord] = sharedPtr; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h index 40ec1972c..c8a3baf36 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.h @@ -100,7 +100,9 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this getShader(std::string vertexName, std::string fragmentName, const ShaderConfig &shaderConf); + std::shared_ptr getShader(const std::string &vertexName, const std::string &fragmentName, + const ShaderConfig &shaderConf, + const std::unordered_map> &dsLayoutOverrides); HGBufferVLK createUniformBuffer(const std::string &objName, size_t size); HGBufferVLK createSSBOBuffer(const std::string &objName, size_t size, int recordSize); @@ -344,13 +346,15 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this dsLayoutOverrides; bool operator==(const ShaderPermutationCacheRecord &other) const { return (name == other.name) && (shaderConfig.vertexShaderFolder == other.shaderConfig.vertexShaderFolder) && (shaderConfig.fragmentShaderFolder == other.shaderConfig.fragmentShaderFolder) && - (shaderConfig.typeOverrides == other.shaderConfig.typeOverrides); + (shaderConfig.typeOverrides == other.shaderConfig.typeOverrides) && + (dsLayoutOverrides == other.dsLayoutOverrides); }; }; struct ShaderPermutationRecordHasher { @@ -368,6 +372,10 @@ class GDeviceVLK : public IDevice, public std::enable_shared_from_this{}(rec2.first) << 12 ^ hash{}(rec.first) << 16; + for (const auto &rec : k.dsLayoutOverrides) + mapHash ^= + hash{}(rec.first) << 4 ^ + hash{}(rec.second) << 8; return hash{}(k.name) ^ mapHash; diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp index b67f37f05..9a2258286 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.cpp @@ -8,11 +8,15 @@ #include "ISimpleMaterialVLK.h" MaterialBuilderVLK::MaterialBuilderVLK(const std::shared_ptr &device, - const std::vector &shaderFiles, const ShaderConfig &shaderConfig) : m_device(device) { + const std::vector &shaderFiles, const ShaderConfig &shaderConfig, + const std::unordered_map> &dsLayoutOverrides) : + m_device(device), m_dsLayoutOverrides(dsLayoutOverrides) { m_shader = std::dynamic_pointer_cast(std::dynamic_pointer_cast(device)->getShader( shaderFiles[0], - shaderFiles[1], shaderConfig)); + shaderFiles[1], shaderConfig, + dsLayoutOverrides) + ); m_materialId = 0; @@ -55,12 +59,6 @@ MaterialBuilderVLK &MaterialBuilderVLK::bindDescriptorSet(int bindPoint, std::sh return *this; } -MaterialBuilderVLK& MaterialBuilderVLK::overridePipelineLayout(const std::unordered_map> &dses) { - m_pipelineLayout = m_shader->createPipelineLayoutOverrided(dses); - - return *this; -} - MaterialBuilderVLK &MaterialBuilderVLK::createPipeline(const HGVertexBufferBindings &bindings, const std::shared_ptr &renderPass, const PipelineTemplate &pipelineTemplate) { @@ -92,7 +90,7 @@ MaterialBuilderVLK& MaterialBuilderVLK::createGBufferPipeline(const HGVertexBuff auto gbufferShader = std::dynamic_pointer_cast(std::dynamic_pointer_cast(m_device)->getShader( shaderFiles[0], - shaderFiles[1], shaderConfig)); + shaderFiles[1], shaderConfig, m_dsLayoutOverrides)); m_gBufferPipeline = std::dynamic_pointer_cast(m_device)->createPipeline( diff --git a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h index bcf524f0f..7ed48915f 100644 --- a/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h +++ b/wowViewerLib/src/gapi/vulkan/materials/MaterialBuilderVLK.h @@ -18,8 +18,15 @@ class MaterialBuilderVLK { MaterialBuilderVLK& operator=(MaterialBuilderVLK const& ) = delete; static MaterialBuilderVLK fromShader(const std::shared_ptr &device, - const std::vector &shaderFiles, const ShaderConfig &shaderConfig) { - return {device, shaderFiles, shaderConfig}; + const std::vector &shaderFiles, const ShaderConfig &shaderConfig, + const std::unordered_map> &dsesOverrides) { + + std::unordered_map> dsLayoutOverrides = {}; + for (const auto &rec : dsesOverrides) { + dsLayoutOverrides.emplace(rec.first, rec.second->getDescSetLayout()); + } + + return {device, shaderFiles, shaderConfig, dsLayoutOverrides}; } static MaterialBuilderVLK fromMaterial(const std::shared_ptr &device, @@ -33,7 +40,6 @@ class MaterialBuilderVLK { materialVlk->getMaterialId() }; } - MaterialBuilderVLK& overridePipelineLayout(const std::unordered_map> &dses); MaterialBuilderVLK& bindDescriptorSet(int bindPoint, std::shared_ptr &ds); MaterialBuilderVLK& createDescriptorSet(int bindPoint, const std::function &ds)> &callback); MaterialBuilderVLK& createPipeline(const HGVertexBufferBindings &bindings, @@ -66,7 +72,8 @@ class MaterialBuilderVLK { return res; } MaterialBuilderVLK(const std::shared_ptr &device, - const std::vector &shaderFiles, const ShaderConfig &shaderConfig); + const std::vector &shaderFiles, const ShaderConfig &shaderConfig, + const std::unordered_map> &dsLayoutOverrides); MaterialBuilderVLK(const std::shared_ptr &device, const std::shared_ptr &shader, @@ -89,6 +96,7 @@ class MaterialBuilderVLK { std::shared_ptr m_pipelineLayout; PipelineTemplate m_pipelineTemplate; std::array, MAX_SHADER_DESC_SETS> m_descriptorSets; + std::unordered_map> m_dsLayoutOverrides; }; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index d6f6eab7e..1c3bca7d6 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -45,11 +45,14 @@ VkShaderModule GShaderPermutationVLK::createShaderModule(const std::vector return shaderModule; } -GShaderPermutationVLK::GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, +GShaderPermutationVLK::GShaderPermutationVLK(const std::string &shaderVertName, const std::string &shaderFragName, const std::shared_ptr &device, - const ShaderConfig &shaderConf) : + const ShaderConfig &shaderConf, + const std::unordered_map> &dsLayoutOverrides + ) : m_device(device), m_combinedName(shaderVertName + " "+ shaderFragName), m_shaderConf(shaderConf), - m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName){ + m_shaderNameVert(shaderVertName), m_shaderNameFrag(shaderFragName), + m_dsLayoutOverrides(dsLayoutOverrides) { } @@ -61,10 +64,15 @@ std::vector GShaderPermutationVLK::createMetaArray() { void GShaderPermutationVLK::createSetDescriptorLayouts() { std::vector metas = createMetaArray(); for (int i = 0; i < combinedShaderLayout.setLayouts.size(); i++) { - auto &setLayout = combinedShaderLayout.setLayouts[i]; - if (setLayout.imageBindings.length == 0 && setLayout.uboBindings.length == 0) continue; + if (m_dsLayoutOverrides.find(i) != m_dsLayoutOverrides.end()) { + descriptorSetLayouts[i] = m_dsLayoutOverrides.at(i); + } else { + auto &setLayout = combinedShaderLayout.setLayouts[i]; + if (setLayout.imageBindings.length == 0 && setLayout.uboBindings.length == 0) continue; - descriptorSetLayouts[i] = std::make_shared(m_device, metas, i, m_shaderConf.typeOverrides); + descriptorSetLayouts[i] = std::make_shared(m_device, metas, i, + m_shaderConf.typeOverrides); + } } } @@ -181,6 +189,7 @@ void GShaderPermutationVLK::createShaderLayout() { } } } + std::shared_ptr GShaderPermutationVLK::createPipelineLayoutOverrided(const std::unordered_map> &dses) { std::vector descLayouts; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h index dd7e275e2..3839b4e8d 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.h @@ -29,7 +29,9 @@ struct CombinedShaderLayout { class GShaderPermutationVLK : public IShaderPermutation { friend class GDeviceVLK; public: - explicit GShaderPermutationVLK(std::string &shaderVertName, std::string &shaderFragName, const std::shared_ptr &device, const ShaderConfig &shaderConf); + explicit GShaderPermutationVLK(const std::string &shaderVertName, const std::string &shaderFragName, const std::shared_ptr &device, const ShaderConfig &shaderConf, + const std::unordered_map> &dsLayoutOverrides + ); ~GShaderPermutationVLK() override {}; VkShaderModule getVertexModule() {return vertShaderModule;} @@ -80,6 +82,8 @@ class GShaderPermutationVLK : public IShaderPermutation { CombinedShaderLayout combinedShaderLayout; ShaderConfig m_shaderConf; + const std::unordered_map> m_dsLayoutOverrides; + std::string vertShaderName = ""; std::string vertShaderFrag = ""; @@ -88,6 +92,7 @@ class GShaderPermutationVLK : public IShaderPermutation { void createShaderLayout(); void createPipelineLayout(); + }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 5a8c6b737..557da8b15 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -268,7 +268,7 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, { //Create SceneWide descriptor sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); - MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig, {}) .createDescriptorSet(0, [&](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, sceneWideChunk) @@ -313,8 +313,7 @@ void MapSceneRenderBindlessVLK::createADTGlobalMaterialData() { pipelineTemplate.backFaceCulling = true; pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; - g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + g_adtMaterial = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, adtBindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyADTVAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyADTVAO, {"adtShader", "adtShader"}, adtBindlessGBufferShaderConfig, m_gBufferPass) @@ -346,8 +345,7 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global water descriptor for bindless textures - g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [this](std::shared_ptr &ds) { @@ -373,8 +371,7 @@ void MapSceneRenderBindlessVLK::createWMOGlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global wmo descriptor for bindless textures - g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + g_wmoMaterial = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, wmoBindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -403,8 +400,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; //Create global m2 descriptor for bindless textures - g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + g_m2Material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2BindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -428,8 +424,7 @@ void MapSceneRenderBindlessVLK::createM2GlobalMaterialData() { m2TextureHolder = std::make_shared(m2TexturesBindlessCount); } void MapSceneRenderBindlessVLK::createM2WaterfallGlobalMaterialData() { - MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}, {1, m2BufferOneDS}}) + MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2WaterfallBindlessShaderConfig, {{0, sceneWideDS}, {1, m2BufferOneDS}}) .createDescriptorSet(2, [&](std::shared_ptr &ds) { ds->beginUpdate() .ssbo(0, m2WaterfallBuffer.waterfallCommon) @@ -456,9 +451,8 @@ std::shared_ptr MapSceneRenderBindlessVLK::getM2StaticMateri bool isTrueOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque; auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessShaderConfig, {{0, sceneWideDS}}) .setMaterialId(generateUniqueM2MatId()) - .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyM2VAO, {"m2Shader", isTrueOpaq ? "m2Shader_opaq" : "m2Shader"}, m2BindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -481,9 +475,8 @@ std::shared_ptr MapSceneRenderBindlessVLK::getWMOStaticMater bool isTrueOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque; auto staticMaterial = - MaterialBuilderVLK::fromShader(m_device, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessShaderConfig, {{0, sceneWideDS}}) .setMaterialId(generateUniqueWMOMatId()) - .overridePipelineLayout({{0, sceneWideDS}}) .createPipeline(m_emptyWMOVAO, m_forwardRenderPass, pipelineTemplate) .createGBufferPipeline(m_emptyWMOVAO, {"wmoShader", isTrueOpaq ? "wmoShader_opaq" : "wmoShader"}, wmoBindlessGBufferShaderConfig, m_gBufferPass) .bindDescriptorSet(0, sceneWideDS) @@ -755,8 +748,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Waterfa m2WaterfallBuffer.waterfallBindless); auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, - m2WaterfallBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}, {1, m2BufferOneDS}}) + m2WaterfallBindlessShaderConfig, {{0, sceneWideDS}, {1, m2BufferOneDS}}) .createPipeline(m_emptyM2VAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, m2BufferOneDS) @@ -808,8 +800,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2Particle bool isOpaq = pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_Opaque || pipelineTemplate.blendMode == EGxBlendEnum::GxBlend_AlphaKey; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Particle/forward/m2ParticleShader", "m2Particle/forward/m2ParticleShader"}, bindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Particle/forward/m2ParticleShader", "m2Particle/forward/m2ParticleShader"}, bindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyM2ParticleVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { @@ -836,8 +827,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createM2RibbonMate auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Ribbon/forward/ribbonShader", "m2Ribbon/forward/ribbonShader"}, bindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Ribbon/forward/ribbonShader", "m2Ribbon/forward/ribbonShader"}, bindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyM2RibbonVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { @@ -919,8 +909,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createWaterMaterial(c auto l_waterBindless = std::make_shared>(waterBuffer.waterBindlessBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyWaterVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, waterDataDS) @@ -964,8 +953,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createSkyMeshMateri auto &l_sceneWideChunk = sceneWideChunk; auto skyColors = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptySkyVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -983,8 +971,7 @@ std::shared_ptr MapSceneRenderBindlessVLK::createPortalMaterial auto &l_sceneWideChunk = sceneWideChunk; auto materialPS = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) - .overridePipelineLayout({{0, sceneWideDS}}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig, {{0, sceneWideDS}}) .createPipeline(m_emptyPortalVAO, m_forwardRenderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index 793289322..d0c8f8528 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -100,7 +100,7 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C defaultView = std::make_shared(m_device, uboBuffer, m_drawQuadVao, false); sceneWideChunk = std::make_shared>(hDevice, 3, uboBuffer); - MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig, {}) .createDescriptorSet(0, [&](std::shared_ptr &ds) { ds->beginUpdate() .ubo_dynamic(0, sceneWideChunk).delayUpdate(); @@ -246,7 +246,7 @@ MapSceneRenderForwardVLK::createAdtMaterial(const PipelineTemplate &pipelineTemp auto vertexFragmentData = std::make_shared>(uboStaticBuffer); auto fragmentData = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"adtShader", "adtShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyADTVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&vertexFragmentData, &fragmentData, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -282,7 +282,7 @@ MapSceneRenderForwardVLK::createM2Material(const std::shared_ptr & auto &l_sceneWideChunk = sceneWideChunk; auto vertexFragmentData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig, {}) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) @@ -317,7 +317,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2Waterfal auto waterfallCommonData = std::make_shared>(uboStaticBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterfallShader", "waterfallShader"}, m2ForwardShaderConfig, {}) .createPipeline(m_emptyM2VAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .bindDescriptorSet(1, std::dynamic_pointer_cast(m2ModelData)->m2CommonDS) @@ -347,7 +347,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ParticleM auto &l_sceneWideChunk = sceneWideChunk; auto l_fragmentData = std::make_shared>(uboBuffer); ; - auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"m2ParticleShader", "m2ParticleShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyM2ParticleVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_fragmentData](std::shared_ptr &ds) { @@ -374,7 +374,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2RibbonMater auto l_fragmentData = std::make_shared>(uboBuffer); ; auto &l_m2ModelData = m2ModelData; - auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"ribbonShader", "ribbonShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyM2RibbonVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&l_sceneWideChunk, &l_fragmentData, &l_m2ModelData](std::shared_ptr &ds) { @@ -407,7 +407,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createWMOMaterial(const auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"wmoShader", "wmoShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyWMOVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_vertexData, l_fragmentData](std::shared_ptr &ds) { @@ -442,7 +442,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createWaterMaterial(co auto l_fragmentData = std::make_shared>(uboStaticBuffer); ; auto &l_sceneWideChunk = sceneWideChunk; - auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyWaterVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [l_sceneWideChunk, &modelWide, l_fragmentData](std::shared_ptr &ds) { @@ -471,7 +471,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createSkyMeshMateria auto &l_sceneWideChunk = sceneWideChunk; auto skyColors = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"skyConus", "skyConus"}, forwardShaderConfig, {}) .createPipeline(m_emptySkyVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&skyColors, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -489,7 +489,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createPortalMaterial( auto &l_sceneWideChunk = sceneWideChunk; auto materialPS = std::make_shared>(uboBuffer); - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawPortalShader", "drawPortalShader"}, forwardShaderConfig, {}) .createPipeline(m_emptyPortalVAO, m_renderPass, pipelineTemplate) .bindDescriptorSet(0, sceneWideDS) .createDescriptorSet(1, [&materialPS, &l_sceneWideChunk](std::shared_ptr &ds) { @@ -513,7 +513,7 @@ std::shared_ptr MapSceneRenderForwardVLK::createM2ModelMat(int bon BufferChunkHelperVLK::create(uboBuffer, result->m_textureMatrices, sizeof(mathfu::mat4) * textureMatricesCount); BufferChunkHelperVLK::create(uboBuffer, result->m_modelFragmentData); - MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig) + MaterialBuilderVLK::fromShader(m_device, {"m2Shader", "m2Shader"}, m2ForwardShaderConfig, {}) .createDescriptorSet(1, [&](std::shared_ptr &ds) { ds->beginUpdate() .ubo(0, BufferChunkHelperVLK::cast(result->m_placementMatrix)) diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp index 34a64e5c1..074ecf7ba 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/passes/FFXGlowPassVLK.cpp @@ -219,7 +219,7 @@ FFXGlowPassVLK::createFFXGaussMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {"forwardRendering", "forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxgauss4"}, {"forwardRendering", "forwardRendering"}, {}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGaussVs, &ffxGaussPS](std::shared_ptr &ds) { ds->beginUpdate() @@ -244,7 +244,7 @@ FFXGlowPassVLK::createFFXGlowMat( const PipelineTemplate &pipelineTemplate, const std::shared_ptr &targetRenderPass) { - auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {"forwardRendering", "forwardRendering"}) + auto material = MaterialBuilderVLK::fromShader(m_device, {"drawQuad", "ffxglow"}, {"forwardRendering", "forwardRendering"}, {}) .createPipeline(m_drawQuadVao, targetRenderPass, pipelineTemplate) .createDescriptorSet(0, [&ffxGlowVs, &ffxGlowPS](std::shared_ptr &ds) { ds->beginUpdate() diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index c8cc91afc..56f9bbdc5 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -182,8 +182,7 @@ void RenderViewDeferredVLK::createLightBufferMats() { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }} } - }) - .overridePipelineLayout({{0, m_sceneWideDS}}) + }, {{0, m_sceneWideDS}}) .createPipeline(m_quadVAO, m_lightBufferPass, s_lightBufferPipelineT) .bindDescriptorSet(0, m_sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { @@ -205,8 +204,7 @@ void RenderViewDeferredVLK::createLightBufferMats() { {0, {VkDescriptorType::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, false, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT}}, }} } - }) - .overridePipelineLayout({{0, m_sceneWideDS}}) + }, {{0, m_sceneWideDS}}) .createPipeline(m_quadVAO, m_lightBufferPass, s_lightBufferPipelineSpot) .bindDescriptorSet(0, m_sceneWideDS) .createDescriptorSet(1, [&](std::shared_ptr &ds) { From b413d26faec06ebcdcb518500f469463d14f2c6f Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 18 Apr 2024 22:57:46 +0300 Subject: [PATCH 190/212] - fixes a lot of graphical bugs --- .../childWindow/sceneWindow/SceneWindow.cpp | 19 ++++++++---- src/ui/childWindow/sceneWindow/SceneWindow.h | 2 ++ wowViewerLib/src/engine/ApiContainer.h | 19 ++++++++++-- .../managers/particles/particleEmitter.cpp | 21 +++----------- .../managers/particles/particleEmitter.h | 6 +--- .../src/engine/objects/m2/m2Object.cpp | 5 +++- .../src/gapi/vulkan/GDeviceVulkan.cpp | 5 +--- .../renderer/mapScene/IMapSceneBufferCreate.h | 3 ++ .../vulkan/MapSceneRenderBindlessVLK.cpp | 29 +++++++++++++++++-- .../vulkan/MapSceneRenderBindlessVLK.h | 4 +++ .../vulkan/MapSceneRenderForwardVLK.cpp | 23 +++++++++++++++ .../vulkan/MapSceneRenderForwardVLK.h | 6 +++- 12 files changed, 104 insertions(+), 38 deletions(-) diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index 889603899..24fa6570c 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -175,11 +175,18 @@ std::shared_ptr setScene(const HApiContainer& apiContainer, int sceneTyp } */ +HApiContainer SceneWindow::createNewApiContainer() { + auto newApi = m_api->clone(); + newApi->cacheStorage = std::make_shared(newApi->requestProcessor.get()); + + return newApi; +} + void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, mapId, wdtFileId); + m_currentScene = std::make_shared(createNewApiContainer(), mapId, wdtFileId); m_camera = std::make_shared(); m_camera->setCameraPos(x,y,z); @@ -189,7 +196,7 @@ void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacem unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - auto m2Scene = std::make_shared(m_api, m2Fdid); + auto m2Scene = std::make_shared(createNewApiContainer(), m2Fdid); m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); @@ -213,7 +220,7 @@ void SceneWindow::openM2SceneByName(const std::string &m2FileName, const std::ve m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - auto m2Scene = std::make_shared(m_api, m2FileName); + auto m2Scene = std::make_shared(createNewApiContainer(), m2FileName); m_currentScene = m2Scene; m2Scene->setReplaceTextureArray(m_sceneRenderer, replacementTextureIds); @@ -234,7 +241,7 @@ void SceneWindow::openWMOSceneByfdid(int WMOFdid) { unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, WMOFdid); + m_currentScene = std::make_shared(createNewApiContainer(), WMOFdid); m_camera = std::make_shared(); m_camera->setCameraPos(0, 0, 0); @@ -243,7 +250,7 @@ void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, wmoFileName); + m_currentScene = std::make_shared(createNewApiContainer(), wmoFileName); m_camera = std::make_shared(); m_camera->setCameraPos(0, 0, 0); @@ -253,7 +260,7 @@ void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); - m_currentScene = std::make_shared(m_api, mapId, mapName); + m_currentScene = std::make_shared(createNewApiContainer(), mapId, mapName); m_camera = std::make_shared(); m_camera->setCameraPos(x,y,z); diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index fd87992d3..1475ab024 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -75,6 +75,8 @@ class SceneWindow : public std::enable_shared_from_this { std::shared_ptr m_currentScene = nullptr; bool m_renderToSwapChain = true; + HApiContainer createNewApiContainer(); + private: void createMaterials(); diff --git a/wowViewerLib/src/engine/ApiContainer.h b/wowViewerLib/src/engine/ApiContainer.h index ffe604ae3..ad59ab1a3 100644 --- a/wowViewerLib/src/engine/ApiContainer.h +++ b/wowViewerLib/src/engine/ApiContainer.h @@ -19,15 +19,30 @@ typedef std::shared_ptr HApiContainer; class ApiContainer { private: - Config config; + std::shared_ptr m_config = nullptr; public: + ApiContainer() : m_config(std::make_shared()){ + }; + + HApiContainer clone() { + auto newApi = std::make_shared(); + newApi->m_config = this->m_config; + newApi->requestProcessor = this->requestProcessor; + newApi->cacheStorage = this->cacheStorage; + newApi->hDevice = this->hDevice; + newApi->databaseHandler = this->databaseHandler; + + return newApi; + } + + HWoWFilesCacheStorage cacheStorage = nullptr; HRequestProcessor requestProcessor = nullptr; HGDevice hDevice = nullptr; std::shared_ptr databaseHandler = nullptr; Config *getConfig() { - return &config; + return m_config.get(); } }; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index 4be9967a9..d4dede234 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -17,9 +17,7 @@ #include "../../../gapi/interface/materials/IMaterial.h" -HGIndexBuffer ParticleEmitter::m_indexVBO = nullptr; -static const size_t MAX_PARTICLES_PER_EMITTER = 2000; enum class ParticleVertexShader : int { None = -1, @@ -262,23 +260,9 @@ void ParticleEmitter::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { HGDevice device = m_api->hDevice; if (m_indexVBO == nullptr) { - //TODO: - m_indexVBO = sceneRenderer->createM2IndexBuffer(MAX_PARTICLES_PER_EMITTER*6*sizeof(uint16_t)); - int vo = 0; - for (int i = 0; i < MAX_PARTICLES_PER_EMITTER; i++) { - szIndexBuff.push_back(vo + 0); - szIndexBuff.push_back(vo + 1); - szIndexBuff.push_back(vo + 2); - szIndexBuff.push_back(vo + 3); - szIndexBuff.push_back(vo + 2); - szIndexBuff.push_back(vo + 1); - vo += 4; - } - m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); + m_indexVBO = sceneRenderer->getOrCreateM2ParticleIndexBuffer(); } - - //Create Material { PipelineTemplate pipelineTemplate; @@ -1121,6 +1105,9 @@ void ParticleEmitter::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, t if (!currentFrame.active) return; + if (this->szVertexCnt == 0) + return; + HGParticleMesh mesh = currentFrame.m_mesh; if (mesh->getIsTransparent()) { transparentMeshes.emplace_back() = mesh; diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.h b/wowViewerLib/src/engine/managers/particles/particleEmitter.h index 7cd079c2a..3756f5fe0 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.h +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.h @@ -134,10 +134,6 @@ class ParticleEmitter { ParticleBuffStructQuad *szVertexBuf = nullptr; int szVertexCnt = 0; - std::vector szIndexBuff; - - - private: struct ParticlePreRenderData @@ -204,7 +200,7 @@ class ParticleEmitter { void createMeshes(const HMapSceneBufferCreate &sceneRenderer); - static HGIndexBuffer m_indexVBO; + HGIndexBuffer m_indexVBO = nullptr; void GetSpin(CParticle2 &p, float &baseSpin, float &deltaSpin) const; void createMesh(const HMapSceneBufferCreate &sceneRenderer, particleFrame &frame, int size); diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 3907c66b8..254278c06 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1672,6 +1672,8 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index } void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes) { + if (!this->m_loaded) return; + M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); int minBatch = m_api->getConfig()->m2MinBatch; @@ -1949,7 +1951,8 @@ int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { } void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { -// return; + if (!this->m_loaded) return; + // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 64388dccc..df11cc0bf 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -1296,10 +1296,7 @@ HGBufferVLK GDeviceVLK::createIndexBuffer(const std::string &objName, size_t ini } HGVertexBufferBindings GDeviceVLK::createVertexBufferBindings() { - std::shared_ptr h_vertexBindings; - h_vertexBindings.reset(new GVertexBufferBindingsVLK()); - - return h_vertexBindings; + return std::make_shared(); } HGSamplableTexture GDeviceVLK::createBlpTexture(HBlpTexture &texture, bool xWrapTex, bool yWrapTex) { diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 6e01d684a..c8beda898 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -41,6 +41,7 @@ PACK( } ); +static const size_t MAX_PARTICLES_PER_EMITTER = 2000; class IMapSceneBufferCreate { public: @@ -66,6 +67,8 @@ class IMapSceneBufferCreate { virtual HGIndexBuffer createM2IndexBuffer(int sizeInBytes) = 0; + virtual HGIndexBuffer getOrCreateM2ParticleIndexBuffer() = 0; + virtual HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) = 0; virtual HGVertexBuffer createM2RibbonVertexBuffer(int sizeInBytes) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 557da8b15..cc107691c 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -134,7 +134,6 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m_device(hDevice), MapSceneRenderer(config) { std::cout << "Create Bindless scene renderer " << std::endl; - iboBuffer = m_device->createIndexBuffer("Scene_IBO", 1024*1024); const int rendererId = std::hash()((uint64_t)this) & 0xFFFF; const std::string rendererIdStr = " " + std::to_string(rendererId); @@ -143,6 +142,9 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, return name + rendererIdStr; }; + iboBuffer = m_device->createIndexBuffer(un("Scene_IBO"), 1024*1024); + + vboM2Buffer = m_device->createVertexBuffer(un("Scene_VBO_M2"),1024*1024, sizeof(M2Vertex)); vboPortalBuffer = m_device->createVertexBuffer(un("Scene_VBO_Portal"),1024*1024); vboM2ParticleBuffer = m_device->createVertexBuffer(un("Scene_VBO_M2Particle"),1024*1024, 64); @@ -175,7 +177,24 @@ MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, m_drawQuadVao->setIndexBuffer(m_iboQuad); m_drawQuadVao->save(); } - + { + m_particleIndexBuffer = m_device->createIndexBuffer(un("Scene_IBO_Particle"), + MAX_PARTICLES_PER_EMITTER * 6 * sizeof(uint16_t)); + + std::vector szIndexBuff; + + int vo = 0; + for (int i = 0; i < MAX_PARTICLES_PER_EMITTER; i++) { + szIndexBuff.push_back(vo + 0); + szIndexBuff.push_back(vo + 1); + szIndexBuff.push_back(vo + 2); + szIndexBuff.push_back(vo + 3); + szIndexBuff.push_back(vo + 2); + szIndexBuff.push_back(vo + 1); + vo += 4; + } + m_particleIndexBuffer->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); + } //Create vertex data for SpotLight in z-up { std::vector vertexBuffer; @@ -587,6 +606,11 @@ HGIndexBuffer MapSceneRenderBindlessVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } +HGIndexBuffer MapSceneRenderBindlessVLK::getOrCreateM2ParticleIndexBuffer() { + return m_particleIndexBuffer; +} + + HGVertexBuffer MapSceneRenderBindlessVLK::createADTVertexBuffer(int sizeInBytes) { return vboAdtBuffer->getSubBuffer(sizeInBytes); } @@ -1386,6 +1410,7 @@ std::unique_ptr MapSceneRenderBindlessVLK::update(const std::sh uploadCmd.submitBufferUploads(l_this->iboBuffer); uploadCmd.submitBufferUploads(l_this->m_vboQuad); uploadCmd.submitBufferUploads(l_this->m_iboQuad); + uploadCmd.submitBufferUploads(l_this->m_particleIndexBuffer); uploadCmd.submitBufferUploads(l_this->m_vboSpot); uploadCmd.submitBufferUploads(l_this->m_iboSpot); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 3d1b42369..77d9f690d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -48,6 +48,8 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; + HGIndexBuffer getOrCreateM2ParticleIndexBuffer() override; + HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; HGVertexBuffer createM2RibbonVertexBuffer(int sizeInBytes) override; @@ -197,6 +199,8 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; + HGBufferVLK m_particleIndexBuffer; + HGVertexBufferBindings m_drawQuadVao = nullptr; HGBufferVLK m_vboSpot; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp index d0c8f8528..64fa04a4d 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.cpp @@ -75,6 +75,25 @@ MapSceneRenderForwardVLK::MapSceneRenderForwardVLK(const HGDeviceVLK &hDevice, C m_drawQuadVao->save(); } + { + m_particleIndexBuffer = m_device->createIndexBuffer("Scene_IBO_Particle", + MAX_PARTICLES_PER_EMITTER * 6 * sizeof(uint16_t)); + + std::vector szIndexBuff; + + int vo = 0; + for (int i = 0; i < MAX_PARTICLES_PER_EMITTER; i++) { + szIndexBuff.push_back(vo + 0); + szIndexBuff.push_back(vo + 1); + szIndexBuff.push_back(vo + 2); + szIndexBuff.push_back(vo + 3); + szIndexBuff.push_back(vo + 2); + szIndexBuff.push_back(vo + 1); + vo += 4; + } + m_particleIndexBuffer->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); + } + uboBuffer = m_device->createUniformBuffer("Scene_UBO", 1024*1024); uboStaticBuffer = m_device->createUniformBuffer("Scene_UBOStatic", 1024*1024); @@ -207,6 +226,10 @@ HGIndexBuffer MapSceneRenderForwardVLK::createM2IndexBuffer(int sizeInBytes) { return iboBuffer->getSubBuffer(sizeInBytes); } +HGIndexBuffer MapSceneRenderForwardVLK::getOrCreateM2ParticleIndexBuffer() { + return m_particleIndexBuffer; +} + HGVertexBuffer MapSceneRenderForwardVLK::createADTVertexBuffer(int sizeInBytes) { return vboAdtBuffer->getSubBuffer(sizeInBytes); } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index a5c9730cd..911412abf 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -42,6 +42,8 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGVertexBuffer createM2VertexBuffer(int sizeInBytes) override; HGIndexBuffer createM2IndexBuffer(int sizeInBytes) override; + HGIndexBuffer getOrCreateM2ParticleIndexBuffer() override; + HGVertexBuffer createM2ParticleVertexBuffer(int sizeInBytes) override; HGVertexBuffer createM2RibbonVertexBuffer(int sizeInBytes) override; @@ -132,7 +134,9 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { HGBufferVLK m_vboQuad; HGBufferVLK m_iboQuad; - + + HGBufferVLK m_particleIndexBuffer; + HGVertexBufferBindings m_drawQuadVao = nullptr; std::shared_ptr> sceneWideChunk; From 428c53009bd0e5c9c3b02e5b00e2f25f2133d935 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 19 Apr 2024 01:47:59 +0300 Subject: [PATCH 191/212] changes from MSVC and amd --- .../src/engine/objects/ViewsObjects.cpp | 2 +- wowViewerLib/src/engine/objects/scenes/map.cpp | 2 +- wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp | 17 +++++++++++++++++ .../vulkan/view/RenderViewDeferredVLK.cpp | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index 60f7620c7..c2be89440 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -75,7 +75,7 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD r.end(), candidatesArr, candCullRes); #else - ObjectCulling>::cull(this->frustumData, + ObjectCulling::cull(this->frustumData, r.begin(), r.end(), candidatesArr, candCullRes); #endif diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 230ad7cfe..179397284 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1169,7 +1169,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, r.begin(), r.end(), candidates, results); #else - ObjectCulling>::cull(frustumData, + ObjectCulling::cull(frustumData, r.begin(), r.end(), candidates, results); #endif diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index df11cc0bf..2714df98a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "GDeviceVulkan.h" #include "meshes/GMeshVLK.h" @@ -206,6 +207,8 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma m_descriptorSetUpdater(std::make_shared()){ enableValidationLayers = false; + _putenv("VK_LOADER_DRIVERS_DISABLE=*dzn*"); + if (volkInitialize()) { std::cerr << "Failed to initialize volk loader" << std::endl; exit(1); @@ -221,8 +224,15 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma if (vkEnumerateInstanceVersion != nullptr) vkEnumerateInstanceVersion(&apiVersion); + std::cout << "reported VK API: major = " << VK_VERSION_MAJOR(apiVersion) << + " minor = " << VK_VERSION_MINOR(apiVersion) << + " patch = " << VK_VERSION_PATCH(apiVersion) + + << std::endl; + if (apiVersion > VK_API_VERSION_1_2) apiVersion = VK_API_VERSION_1_2; + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -249,6 +259,13 @@ GDeviceVLK::GDeviceVLK(vkCallInitCallback * callback) : m_textureManager(std::ma char** extensions; int extensionCnt = 0; callback->getRequiredExtensions(extensions, extensionCnt); + + std::cout << "required extensions: "; + for (int i = 0; i < extensionCnt; i++) { + std::cout << std::string(extensions[i]) << " "; + } + std::cout << std::endl; + std::vector extensionsVec(extensions, extensions+extensionCnt); if (enableValidationLayers) { extensionsVec.push_back("VK_EXT_debug_report"); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp index 56f9bbdc5..af5980e8f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/view/RenderViewDeferredVLK.cpp @@ -234,7 +234,7 @@ void RenderViewDeferredVLK::update(int width, int height, float glow, { auto &screensize = m_lightScreenSize->getObject(); - screensize = {m_width, m_height, 0, 0}; + screensize = {(float)m_width, (float)m_height, 0.0, 0.0}; m_lightScreenSize->save(); } From 74a46d9c6dc1b787a94a3f91f3e5c618bcbfcfd5 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 19 Apr 2024 03:19:33 +0300 Subject: [PATCH 192/212] - compress adt vertex a bit --- .../glsl/bindless/adt/forward/adtShader.vert | 7 +++--- .../bindless/adt/visbuffer/adtShader.vert | 7 +++--- .../glsl/common/commonADTMaterial.glsl | 6 ++--- .../glsl/forwardRendering/adtShader.vert | 8 +++---- .../src/engine/objects/adt/adtObject.cpp | 22 +++++-------------- .../src/engine/objects/wdl/wdlObject.cpp | 2 ++ .../renderer/mapScene/IMapSceneBufferCreate.h | 6 ++--- .../src/renderer/mapScene/MapSceneRenderer.h | 6 ++--- 8 files changed, 28 insertions(+), 36 deletions(-) diff --git a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert index 0a560bee4..889605ab4 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert @@ -12,7 +12,7 @@ precision highp int; #include "../../../common/commonADTMaterial.glsl" /* vertex shader code */ -layout(location = 0) in vec3 aPos; +layout(location = 0) in float aHeight; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; @@ -51,9 +51,10 @@ void main() { //Thus, we first need to get vertexNumber within MCNK int indexInMCNK = (gl_VertexIndex - gl_BaseVertexARB) % (9 * 9 + 8 * 8); - calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords); + vec2 worldPointXY; + calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords, worldPointXY); - vec4 worldPoint = vec4(aPos, 1); + vec4 worldPoint = vec4(worldPointXY.xy, aHeight, 1); mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); diff --git a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert index 0a560bee4..889605ab4 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert @@ -12,7 +12,7 @@ precision highp int; #include "../../../common/commonADTMaterial.glsl" /* vertex shader code */ -layout(location = 0) in vec3 aPos; +layout(location = 0) in float aHeight; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; @@ -51,9 +51,10 @@ void main() { //Thus, we first need to get vertexNumber within MCNK int indexInMCNK = (gl_VertexIndex - gl_BaseVertexARB) % (9 * 9 + 8 * 8); - calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords); + vec2 worldPointXY; + calcAdtAlphaUV(indexInMCNK, adtMeshWideVSPS.uPos.xyz, vAlphaCoords, vChunkCoords, worldPointXY); - vec4 worldPoint = vec4(aPos, 1); + vec4 worldPoint = vec4(worldPointXY.xy, aHeight, 1); mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl index 2d603c7d8..b2a921ca9 100644 --- a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -23,7 +23,7 @@ const float TILESIZE = (1600.0 / 3.0); const float CHUNKSIZE = TILESIZE / 16.0; const float UNITSIZE = CHUNKSIZE / 8.0; -void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords, out vec2 chunkCoords) { +void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords, out vec2 chunkCoords, out vec2 worldPointXY) { float iX = mod(indexInMCNK, 17.0); float iY = floor(indexInMCNK/17.0); @@ -32,7 +32,7 @@ void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords iX = iX - 8.5; } - vec2 worldPoint_xy = vec2( + worldPointXY = vec2( adtMCNKPos.x - iY * UNITSIZE, adtMCNKPos.y - iX * UNITSIZE ); @@ -47,7 +47,7 @@ void calcAdtAlphaUV(in int indexInMCNK, in vec3 adtMCNKPos, out vec2 alphaCoords chunkCoords = vec2(iX, iY); - alphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - worldPoint_xy.yx) / TILESIZE; + alphaCoords = ((vec2(32.0f) - ADTIndex) * TILESIZE - worldPointXY.yx) / TILESIZE; alphaCoords.x = fixADTUVBorder(alphaCoords.x, chunkCoords.x/8.0); alphaCoords.y = fixADTUVBorder(alphaCoords.y, chunkCoords.y/8.0); } diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index c72509f37..f53f43d10 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -10,7 +10,7 @@ precision highp int; #include "../common/commonADTMaterial.glsl" /* vertex shader code */ -layout(location = 0) in vec3 aPos; +layout(location = 0) in float aHeight; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; layout(location = 3) in vec3 aNormal; @@ -51,12 +51,12 @@ void main() { //Thus, we first need to get vertexNumber within MCNK int indexInMCNK = gl_VertexIndex % (9 * 9 + 8 * 8); - - calcAdtAlphaUV(indexInMCNK, uPos.xyz, vAlphaCoords, vChunkCoords); + vec2 worldPointXY; + calcAdtAlphaUV(indexInMCNK, uPos.xyz, vAlphaCoords, vChunkCoords, worldPointXY); mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); - vec4 worldPoint = vec4(aPos, 1); + vec4 worldPoint = vec4(worldPointXY, aHeight, 1); vPosition = (scene.uLookAtMat * worldPoint).xyz; vNormal = normal; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index ad856a455..7102a0845 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -225,9 +225,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { iY = iY + 0.5f; iX = iX - 8.5f; } - adtVertex.pos = { m_adtFile->mapTile[i].position.x - iY * UNITSIZE, - m_adtFile->mapTile[i].position.y - iX * UNITSIZE, - m_adtFile->mapTile[i].position.z + m_adtFile->mcnkStructs[i].mcvt->height[j] }; + adtVertex.height = {m_adtFile->mapTile[i].position.z + m_adtFile->mcnkStructs[i].mcvt->height[j] }; /* 1.3 Normals */ if (m_adtFile->mcnkStructs[i].mcnr != nullptr) { @@ -240,27 +238,17 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { /* 1.4 MCCV */ //Color vertex if (m_adtFile->mcnkStructs[i].mccv != nullptr) { auto &mccv = m_adtFile->mcnkStructs[i].mccv; - adtVertex.mccv = { - mccv->entries[j].red / 255.0f, - mccv->entries[j].green / 255.0f, - mccv->entries[j].blue / 255.0f, - mccv->entries[j].alpha / 255.0f, - }; + *(uint32_t*)(&adtVertex.mccv) = *((uint32_t*)&mccv->entries[j]); } else { - adtVertex.mccv = { 0.5f, 0.5f, 0.5f, 0.5f}; + *(uint32_t*)&adtVertex.mccv = 0x7F7F7F7F; } /* 1.4 MCLV */ //Lightning Vertex if (m_adtFile->mcnkStructs[i].mclv != nullptr) { auto &mclv = m_adtFile->mcnkStructs[i].mclv; - adtVertex.mclv = { - mclv->values[j].b / 255.0f, - mclv->values[j].g / 255.0f, - mclv->values[j].r / 255.0f, - mclv->values[j].a / 255.0f - }; + *(uint32_t*)(&adtVertex.mclv) = *((uint32_t*)&mclv->values[j]); } else { //If MCLV is empty, localDiffuse doesn't exist in shader - adtVertex.mclv = { 0.0f, 0.0f, 0.0f, 0.0f }; + *(uint32_t*)&adtVertex.mclv = 0x00000000; } } } diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp index ef6d1a9ae..34a339871 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp @@ -173,6 +173,8 @@ void WdlObject::checkSkyScenes(const StateForConditions &state, std::cout << "Unk condition " << (int) condition.conditionType << std::endl; } } + conditionPassed = true; + if (conditionPassed) { for (auto &m2Object : skyScene.m2Objects) { m2ObjectsCandidates.addToDraw(m2Object); diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index c8beda898..721fbaaa3 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -27,10 +27,10 @@ PACK( PACK( struct AdtVertex { - mathfu::vec3_packed pos; + float height; mathfu::vec3_packed normal; - mathfu::vec4_packed mccv; - mathfu::vec4_packed mclv; + uint8_t mccv[4]; + uint8_t mclv[4]; } ); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 9a133146e..424a8e1fc 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -72,10 +72,10 @@ static std::vector staticM2RibbonBindings = {{ }}; static std::vector adtVertexBufferBinding = {{ - {+adtShader::Attribute::aPos, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, pos)}, + {+adtShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, height)}, {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, - {+adtShader::Attribute::aColor, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, - {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, + {+adtShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, + {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, }}; static std::vector adtVertexBufferLODBinding = {{ From 589b9a0bf4f628d668fe34145f9cee2b70b640d1 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 22 Apr 2024 23:46:40 +0300 Subject: [PATCH 193/212] fix conditions for skyScenes and ADT vertex format optimization --- src/ui/FrontendUI.cpp | 10 ++++ .../fileListWindow/FileListWindow.cpp | 31 ++++++++++-- .../glsl/bindless/adt/forward/adtShader.vert | 4 +- .../glsl/forwardRendering/adtShader.vert | 4 +- wowViewerLib/src/engine/geometry/m2Geom.cpp | 16 +++++-- .../src/engine/objects/adt/adtObject.cpp | 19 ++++---- .../src/engine/objects/scenes/map.cpp | 12 +++-- .../src/engine/objects/wdl/wdlObject.cpp | 48 ++++++++++++------- .../src/engine/objects/wdl/wdlObject.h | 7 ++- .../engine/persistance/header/adtFileHeader.h | 2 +- .../src/engine/persistance/header/wdlHeader.h | 16 +++++-- .../persistance/helper/ChunkFileReader.h | 1 + .../gapi/interface/IVertexBufferBindings.h | 3 +- .../gapi/vulkan/GVertexBufferBindingsVLK.cpp | 28 +++++++++++ wowViewerLib/src/include/config.h | 4 +- .../renderer/mapScene/IMapSceneBufferCreate.h | 2 +- .../src/renderer/mapScene/MapSceneRenderer.h | 2 +- 17 files changed, 154 insertions(+), 55 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 04232602d..0011efeec 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1432,6 +1432,16 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->renderWMO = renderWMO; } + bool renderSkyDom = m_api->getConfig()->renderSkyDom; + if (ImGui::Checkbox("Render Sky M2", &renderSkyDom)) { + m_api->getConfig()->renderSkyDom = renderSkyDom; + } + + bool renderSkyScene = m_api->getConfig()->renderSkyScene; + if (ImGui::Checkbox("Render SkyScene Models", &renderSkyScene)) { + m_api->getConfig()->renderSkyScene = renderSkyScene; + } + bool renderLiquid = m_api->getConfig()->renderLiquid; if (ImGui::Checkbox("Render Liquid", &renderLiquid)) { m_api->getConfig()->renderLiquid = renderLiquid; diff --git a/src/ui/childWindow/fileListWindow/FileListWindow.cpp b/src/ui/childWindow/fileListWindow/FileListWindow.cpp index 01e2a660e..e48570d3a 100644 --- a/src/ui/childWindow/fileListWindow/FileListWindow.cpp +++ b/src/ui/childWindow/fileListWindow/FileListWindow.cpp @@ -54,7 +54,7 @@ class StatementHolderA { auto whereClause = where( (like(&FileListDB::FileRecord::fileName, searchClause) || like(&FileListDB::FileRecord::fileDataId, searchClause)) || - like(&FileListDB::FileRecord::fileType, fileType) + like(&FileListDB::FileRecord::fileType, searchClause) ); calcTotal = [whereClause, &storage]() { @@ -264,7 +264,7 @@ class my_container { storage store_; }; -const bool processFileOnDetect = true; +const bool processFileOnDetect = false; std::string detectFileType(int fileDataId, const HFileContent &fileContent) { std::string fileType = "unk"; @@ -308,14 +308,26 @@ std::string detectFileType(int fileDataId, const HFileContent &fileContent) { uint32_t subChunkMagic = *(uint32_t *) fptr; fptr += 4; subChunkMagic = ntohl(subChunkMagic); switch (subChunkMagic) { - case 'RDHM': // ADT root + case 'RDHM': // ADT main + fileType = "adt"; + if (processFileOnDetect) { + AdtFile adtFile = AdtFile(fileDataId); + adtFile.setIsMain(true); + adtFile.process(fileContent, std::to_string(fileDataId)); + } + break; + case 'FDDM': // ADT OBJ case 'DDLM': // ADT OBJ case 'DFLM': // ADT OBJ case 'XDMM': // ADT OBJ (old) case 'DHLM': // ADT LOD case 'PMAM': // ADT TEX - fileType = "adt"; + fileType = "adt_sec"; + if (processFileOnDetect) { + AdtFile adtFile = AdtFile(fileDataId); + adtFile.process(fileContent, std::to_string(fileDataId)); + } break; case 'DHOM': // WMO root fileType = "wmo"; @@ -342,7 +354,16 @@ std::string detectFileType(int fileDataId, const HFileContent &fileContent) { } break; case 'IOAM': // WDT OCC/LGT - fileType = "wdt_sec"; + fileType = "wdt_occ"; + break; + case '3LPM': // WDT OCC/LGT + case 'TLSM': // WDT OCC/LGT + case 'ATLM': // WDT OCC/LGT + fileType = "wdt_lgt"; + if (processFileOnDetect) { + WdtLightFile test = WdtLightFile(fileDataId); + test.process(fileContent, std::to_string(fileDataId)); + } break; default: fileType = "chUNK"; diff --git a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert index 889605ab4..0b3337676 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert @@ -15,7 +15,7 @@ precision highp int; layout(location = 0) in float aHeight; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; -layout(location = 3) in vec3 aNormal; +layout(location = 3) in vec4 aNormal; #include "../../../common/commonUboSceneData.glsl" #include "../../../common/commonAdtIndirectDescriptorSet.glsl" @@ -57,7 +57,7 @@ void main() { vec4 worldPoint = vec4(worldPointXY.xy, aHeight, 1); mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); - vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal.xyz, 0.0)).xyz); vPosition = (scene.uLookAtMat * worldPoint).xyz; vNormal = normal; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert index f53f43d10..b17c6dc8a 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.vert @@ -13,7 +13,7 @@ precision highp int; layout(location = 0) in float aHeight; layout(location = 1) in vec4 aColor; layout(location = 2) in vec4 aVertexLighting; -layout(location = 3) in vec3 aNormal; +layout(location = 3) in vec4 aNormal; #include "../common/commonUboSceneData.glsl" @@ -55,7 +55,7 @@ void main() { calcAdtAlphaUV(indexInMCNK, uPos.xyz, vAlphaCoords, vChunkCoords, worldPointXY); mat4 viewMatForNormal = transpose(inverse(scene.uLookAtMat)); - vec3 normal = normalize((viewMatForNormal * vec4(aNormal, 0.0)).xyz); + vec3 normal = normalize((viewMatForNormal * vec4(aNormal.xyz, 0.0)).xyz); vec4 worldPoint = vec4(worldPointXY, aHeight, 1); vPosition = (scene.uLookAtMat * worldPoint).xyz; diff --git a/wowViewerLib/src/engine/geometry/m2Geom.cpp b/wowViewerLib/src/engine/geometry/m2Geom.cpp index 20cf69c5d..fe41cddb2 100644 --- a/wowViewerLib/src/engine/geometry/m2Geom.cpp +++ b/wowViewerLib/src/engine/geometry/m2Geom.cpp @@ -214,18 +214,24 @@ chunkDef M2Geom::m2FileTable = { }; -void M2Geom::process(HFileContent m2File, const std::string &fileName) { - this->m2File = m2File; - auto &m2FileData = *m2File.get(); +void M2Geom::process(HFileContent m2FileC, const std::string &fileName) { + this->m2File = m2FileC; + auto &m2FileData = *m2FileC.get(); if (m2FileData.empty()) { - std::cout << "M2 file is empty" << std::endl; + std::cout << "M2 file "+fileName << " " << std::to_string(m_modelFileId)+" is empty" << std::endl; fsStatus = FileStatus::FSRejected; return; } + if (m2FileData.size() < 5) { + std::cout << "Error: file " << std::to_string(m_modelFileId) << " is smaller than header length" << std::endl; + fsStatus = FileStatus::FSRejected; + } + uint32_t ident = *(uint32_t *)m2FileData.data(); if (ident != '12DM' && ident != '02DM') { - std::cout << "wrong file header for M2 file" << std::endl; + std::cout << "wrong file header for M2 file " << fileName << " " << std::to_string(m_modelFileId) << " ident = " << std::string((char *)&ident, 4) << std::endl; + std::cout << "Content : " << std::hex << (int)m2FileData[0] << " " << (int)m2FileData[1] << " " << (int)m2FileData[2] << " " << (int)m2FileData[3] << std::dec << std::endl; fsStatus = FileStatus::FSRejected; return; } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 7102a0845..ebdf3f38a 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -218,22 +218,23 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { AdtVertex &adtVertex = vboArray.emplace_back(); /* 1.2 Heights */ - float iX = fmod(j, 17.0f); - float iY = floor(j/17.0f); - - if (iX > 8.01f) { - iY = iY + 0.5f; - iX = iX - 8.5f; - } +// float iX = fmod(j, 17.0f); +// float iY = floor(j/17.0f); +// +// if (iX > 8.01f) { +// iY = iY + 0.5f; +// iX = iX - 8.5f; +// } adtVertex.height = {m_adtFile->mapTile[i].position.z + m_adtFile->mcnkStructs[i].mcvt->height[j] }; /* 1.3 Normals */ if (m_adtFile->mcnkStructs[i].mcnr != nullptr) { for (int k = 0; k < 3; k++) { - adtVertex.normal.data_[k] = m_adtFile->mcnkStructs[i].mcnr->entries[j].normal[k] / 127.0f; + adtVertex.normal[k] = m_adtFile->mcnkStructs[i].mcnr->entries[j].normal[k]; } + adtVertex.normal[4] = 0; } else { - adtVertex.normal = { 0, 0, 1.0 }; + *(uint32_t*)&adtVertex.normal = 0x00FF0000; } /* 1.4 MCCV */ //Color vertex if (m_adtFile->mcnkStructs[i].mccv != nullptr) { diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 179397284..f1d132472 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -479,11 +479,11 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams - if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox) && (!m_exteriorSkyBoxes.empty())) { + if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox)) { ZoneScopedN("Skybox"); auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); - auto skyBoxView = mapRenderPlan->viewsHolder.getSkybox(); - if (m_wdlObject != nullptr) { + + if (m_wdlObject != nullptr && config->renderSkyScene) { m_wdlObject->checkSkyScenes( stateForConditions, exteriorView->m2List, @@ -491,8 +491,10 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams frustumData); } - if (config->renderSkyDom) { - for (auto &model : m_exteriorSkyBoxes) { + if (!m_exteriorSkyBoxes.empty() && config->renderSkyDom) { + auto skyBoxView = mapRenderPlan->viewsHolder.getSkybox(); + + for (auto &model: m_exteriorSkyBoxes) { if (model != nullptr) { skyBoxView->m2List.addToDraw(model); } diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp index 34a339871..b28fde55a 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp @@ -73,9 +73,11 @@ void WdlObject::loadM2s() { // std::cout << "rotationInRads.z = " << msso_rec.rotationInRads.z << std::endl; // std::cout << "scale = " << msso_rec.scale << std::endl; - auto rotationMatrix = MathHelper::RotationZ(msso_rec.rotationInRads.z - M_PI_2); - rotationMatrix *= MathHelper::RotationY(msso_rec.rotationInRads.x); - rotationMatrix *= MathHelper::RotationX(msso_rec.rotationInRads.y); + constexpr float degreeToRad = M_PI/180.0f; + + auto rotationMatrix = MathHelper::RotationZ(msso_rec.rotationInDegree.z*degreeToRad); + rotationMatrix *= MathHelper::RotationY(msso_rec.rotationInDegree.x*degreeToRad); + rotationMatrix *= MathHelper::RotationX(msso_rec.rotationInDegree.y*degreeToRad); // auto quat = mathfu::quat::FromMatrix(rotationMatrix); // auto rotationMatrix1 = quat.ToMatrix4(); @@ -88,7 +90,9 @@ void WdlObject::loadM2s() { m2Object->calcWorldPosition(); m2Object->setAlwaysDraw(true); - skyObjectScene.m2Objects.push_back(m2Object); + auto &skyModel = skyObjectScene.skyModels.emplace_back(); + skyModel.m_model = m2Object; + skyModel.animateWithTimeOfDay = msso_rec.flags.animateWithTimeOfDay; } skyScenes.push_back(skyObjectScene); } @@ -138,45 +142,55 @@ void WdlObject::checkSkyScenes(const StateForConditions &state, const MathHelper::FrustumCullingData &frustumData ) { for (auto &skyScene : skyScenes) { - bool conditionPassed = true; + bool conditionPassed = false; for (auto &condition : skyScene.conditions) { switch (condition.conditionType) { case 1 : { - if ((state.currentAreaId != condition.conditionValue) && - (state.currentParentAreaId != condition.conditionValue)) - conditionPassed = false; + if ((state.currentAreaId == condition.conditionValue) || + (state.currentParentAreaId == condition.conditionValue)) + conditionPassed = true; break; } case 2 : { auto it = std::find(state.currentLightParams.begin(), state.currentLightParams.end(), condition.conditionValue); - if (it == state.currentLightParams.end()) { - conditionPassed = false; + if (it != state.currentLightParams.end()) { + conditionPassed = true; } break; } case 3 : { auto it = std::find(state.currentSkyboxIds.begin(), state.currentSkyboxIds.end(), condition.conditionValue); - if (it == state.currentSkyboxIds.end()) { - conditionPassed = false; + if (it != state.currentSkyboxIds.end()) { + conditionPassed = true; } break; } case 5 : { auto it = std::find(state.currentZoneLights.begin(), state.currentZoneLights.end(), condition.conditionValue); - if (it == state.currentZoneLights.end()) { - conditionPassed = false; + if (it != state.currentZoneLights.end()) { + conditionPassed = true; } break; } default: - std::cout << "Unk condition " << (int) condition.conditionType << std::endl; } + std::cout << "Unk condition " << (int) condition.conditionType << std::endl; + } + + if (conditionPassed) + break; } - conditionPassed = true; +// conditionPassed = true; if (conditionPassed) { - for (auto &m2Object : skyScene.m2Objects) { + auto const config = m_api->getConfig(); + for (const auto &skyModel : skyScene.skyModels) { + auto const &m2Object = skyModel.m_model; + + if(skyModel.animateWithTimeOfDay) { + m2Object->setOverrideAnimationPerc(config->currentTime / 2880.0, true); + } m2ObjectsCandidates.addToDraw(m2Object); } } diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.h b/wowViewerLib/src/engine/objects/wdl/wdlObject.h index 5518dc8ad..91fb3437a 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.h +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.h @@ -41,8 +41,13 @@ class WdlObject { int conditionType; int conditionValue; }; + struct SkyModelRec { + std::shared_ptr m_model; + bool animateWithTimeOfDay = false; + }; struct SkyObjectScene{ - std::vector> m2Objects = {}; + + std::vector skyModels = {}; std::vector conditions = {}; }; diff --git a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h index 3ab826eeb..8345f38e1 100644 --- a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h @@ -238,7 +238,7 @@ struct MCCV { struct SMNormal { struct MCNREntry { - int8_t normal[3]; // normalized. X, Z, Y. 127 == 1.0, -127 == -1.0. + uint8_t normal[3]; // normalized. X, Z, Y. 127 == 1.0, -127 == -1.0. } entries[9*9+8*8]; //uint8_t unknown[3*3+2*2]; // this data is not included in the MCNR chunk but additional data which purpose is unknown. 0.5.3.3368 lists this as padding // always 0 112 245 18 0 8 0 0 0 84 245 18 0. Nobody yet found a different pattern. The data is not derived from the normals. diff --git a/wowViewerLib/src/engine/persistance/header/wdlHeader.h b/wowViewerLib/src/engine/persistance/header/wdlHeader.h index f93139341..932f09b17 100644 --- a/wowViewerLib/src/engine/persistance/header/wdlHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wdlHeader.h @@ -10,13 +10,21 @@ struct msso_t { - uint32_t unk_0; - uint32_t unk_1; + uint32_t sceneModelId; + union { + uint32_t flags_raw; + struct { + uint32_t unk_0x1: 1; //0x1 + uint32_t unk_0x2: 1; //0x2 + uint32_t animateWithTimeOfDay: 1; //0x4 + } flags; + }; uint32_t fileDataID; C3Vector translateVec; - C3Vector rotationInRads; + C3Vector rotationInDegree; float scale; - uint32_t unk_2; + uint16_t mssf_index; + uint16_t unk_10; uint32_t unk_11; }; diff --git a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h index 2c4b4512c..30320a047 100644 --- a/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h +++ b/wowViewerLib/src/engine/persistance/helper/ChunkFileReader.h @@ -81,6 +81,7 @@ class CChunkFileReader { template void processFile(T &resultObj, chunkDef *sectionReaders) { + debuglog("Processing file " + fileName); loopOverSubChunks(sectionReaders, 0, regionSizeToProcess, resultObj); } diff --git a/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h b/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h index 245027f3e..36721b44e 100644 --- a/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h +++ b/wowViewerLib/src/gapi/interface/IVertexBufferBindings.h @@ -9,7 +9,8 @@ enum class GBindingType { GFLOAT, - GUNSIGNED_BYTE + GUNSIGNED_BYTE, + GSIGNED_BYTE }; struct GBufferBinding{ diff --git a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp index 470b95740..78ef3e2d6 100644 --- a/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/GVertexBufferBindingsVLK.cpp @@ -57,6 +57,34 @@ VkFormat gBindingToVkFormat(GBindingType gType, uint32_t size, bool normalized ) throw std::runtime_error("unknown gBindingFormat"); } } + case GBindingType::GSIGNED_BYTE : + if (normalized) { + switch (size) { + case 1: + return VK_FORMAT_R8_SNORM; + case 2: + return VK_FORMAT_R8G8_SNORM; + case 3: + return VK_FORMAT_R8G8B8_SNORM; + case 4: + return VK_FORMAT_R8G8B8A8_SNORM; + default: + throw std::runtime_error("unknown gBindingFormat"); + } + } else { + switch (size) { + case 1: + return VK_FORMAT_R8_SINT; + case 2: + return VK_FORMAT_R8G8_SINT; + case 3: + return VK_FORMAT_R8G8B8_SINT; + case 4: + return VK_FORMAT_R8G8B8A8_SINT; + default: + throw std::runtime_error("unknown gBindingFormat"); + } + } } throw std::runtime_error("unknown gBindingFormat"); return VK_FORMAT_UNDEFINED; diff --git a/wowViewerLib/src/include/config.h b/wowViewerLib/src/include/config.h index 16bc9f5ad..574caa48a 100644 --- a/wowViewerLib/src/include/config.h +++ b/wowViewerLib/src/include/config.h @@ -44,6 +44,8 @@ class Config { bool renderAdt = true; bool renderWMO = true; bool renderM2 = true; + bool renderSkyDom = true; + bool renderSkyScene = true; bool renderLiquid = true; bool renderBSP = false; bool renderPortals = false; @@ -56,7 +58,7 @@ class Config { bool disableFog = false; - bool renderSkyDom = true; + bool drawWmoBB = false; bool drawM2BB = false; diff --git a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h index 721fbaaa3..c8a14b3f4 100644 --- a/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h +++ b/wowViewerLib/src/renderer/mapScene/IMapSceneBufferCreate.h @@ -28,7 +28,7 @@ PACK( PACK( struct AdtVertex { float height; - mathfu::vec3_packed normal; + uint8_t normal[4]; uint8_t mccv[4]; uint8_t mclv[4]; } diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h index 424a8e1fc..3ecb78b1d 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.h @@ -73,7 +73,7 @@ static std::vector staticM2RibbonBindings = {{ static std::vector adtVertexBufferBinding = {{ {+adtShader::Attribute::aHeight, 1, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, height)}, - {+adtShader::Attribute::aNormal, 3, GBindingType::GFLOAT, false, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, + {+adtShader::Attribute::aNormal, 4, GBindingType::GSIGNED_BYTE, true, sizeof(AdtVertex), offsetof(AdtVertex, normal)}, {+adtShader::Attribute::aColor, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(AdtVertex), offsetof(AdtVertex, mccv)}, {+adtShader::Attribute::aVertexLighting, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(AdtVertex), offsetof(AdtVertex, mclv)}, }}; From bf18d37fec724e7ddff939b349808fd8e9006c79 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 26 Apr 2024 01:20:04 +0300 Subject: [PATCH 194/212] - memory pool stuff --- 3rdparty/DBImporter | 2 +- CMakeLists.txt | 2 +- src/database/CSqliteDB.cpp | 10 +- src/ui/FrontendUI.cpp | 24 +- .../childWindow/sceneWindow/SceneWindow.cpp | 12 +- src/ui/childWindow/sceneWindow/SceneWindow.h | 4 +- .../vulkan/FrontendUIRenderForwardVLK.h | 1 + .../FrameBasedStackAllocator.cpp | 2 + wowViewerLib/src/engine/objects/m2/m2Object.h | 4 +- .../objects/scenes/EntityActorsFactory.h | 18 +- .../src/engine/objects/scenes/map.cpp | 123 +++++---- .../objects/scenes/memoryPool/MemoryPool.h | 98 ++++++++ .../objects/scenes/memoryPool/MemoryPool.tcc | 235 ++++++++++++++++++ .../src/engine/objects/scenes/wmoScene.h | 4 +- .../src/engine/objects/wdl/wdlObject.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 33 +-- .../src/engine/objects/wmo/wmoObject.h | 33 ++- .../persistance/header/commonFileStructs.h | 9 + .../engine/persistance/header/wmoFileHeader.h | 22 +- .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 2 +- wowViewerLib/src/include/database/dbStructs.h | 2 + .../src/renderer/mapScene/MapScenePlan.h | 2 +- .../vulkan/MapSceneRenderBindlessVLK.h | 3 +- .../vulkan/MapSceneRenderForwardVLK.h | 1 + 24 files changed, 524 insertions(+), 124 deletions(-) create mode 100644 wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.h create mode 100644 wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.tcc diff --git a/3rdparty/DBImporter b/3rdparty/DBImporter index 8c06020a5..b23741404 160000 --- a/3rdparty/DBImporter +++ b/3rdparty/DBImporter @@ -1 +1 @@ -Subproject commit 8c06020a5332796a5399583c5f6f18a917b6c555 +Subproject commit b237414045d180dc68e817d9709b75c13150f548 diff --git a/CMakeLists.txt b/CMakeLists.txt index 11ee1edee..c9c484cf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -428,7 +428,7 @@ INSTALL(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION bin COMPONENT Lib if( MINGW ) message( STATUS " Installing system-libraries: MinGW DLLs." ) get_filename_component( Mingw_Path ${CMAKE_CXX_COMPILER} PATH ) - set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${Mingw_Path}/libgcc_s_seh-1.dll ${Mingw_Path}/libstdc++-6.dll ${Mingw_Path}/libssp-0.dll ${Mingw_Path}/libwinpthread-1.dll) + set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${Mingw_Path}/libgcc_s_seh-1.dll ${Mingw_Path}/libstdc++-6.dll ${Mingw_Path}/libwinpthread-1.dll) endif( MINGW ) include( InstallRequiredSystemLibraries ) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 57b73bd33..3a5c45da8 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -42,16 +42,16 @@ SQLite::Column CSqliteDB::StatementFieldHolder::getField(const HashedString fiel const std::string getMapListSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType from Map m where m.WdtFileDataID > 0"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride from Map m where m.WdtFileDataID > 0"; const std::string getMapListSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride from Map m"; const std::string getMapByIDSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType from Map m where m.ID = ?"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride from Map m where m.ID = ?"; const std::string getMapByIDSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride from Map m"; const std::string getWmoAreaAreaNameSQL = R"===( select wat.AreaName_lang as wmoAreaName, at.AreaName_lang as areaName, at.ID as ID, at.ParentAreaID as ParentAreaID, at.Ambient_multiplier as Ambient_multiplier from WMOAreaTable wat @@ -183,6 +183,7 @@ void CSqliteDB::getMapArray(std::vector &mapRecords) { mapRecord.WdtFileID = -1; } mapRecord.MapType = getMapList.getField("MapType").getInt(); + mapRecord.overrideTime = getMapList.getField("TimeOfDayOverride").getInt(); } } @@ -204,6 +205,7 @@ bool CSqliteDB::getMapById(int mapId, MapRecord &mapRecord) { mapRecord.WdtFileID = -1; } mapRecord.MapType = getMapByIdStatement.getField("MapType").getInt(); + mapRecord.overrideTime = getMapByIdStatement.getField("TimeOfDayOverride").getInt(); return true; } diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 0011efeec..19f74a110 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -258,9 +258,13 @@ void FrontendUI::showCurrentStatsDialog() { { int modelFdid = 0; std::string modelFileName = ""; - if (mapPlan->m_currentWMO != nullptr) { - modelFdid = mapPlan->m_currentWMO->getModelFileId(); - modelFileName = mapPlan->m_currentWMO->getModelFileName(); + if (mapPlan->m_currentWMO != emptyWMO) { + auto l_currentWmo = wmoFactory.getObjectById(mapPlan->m_currentWMO); + + if (l_currentWmo != nullptr) { + modelFdid = l_currentWmo->getModelFileId(); + modelFileName = l_currentWmo->getModelFileName(); + } } if (modelFileName.empty()) { ImGui::Text("Current WMO: %d", modelFdid); @@ -568,9 +572,9 @@ void FrontendUI::showAdtSelectionMinimap() { if (ImGui::Button("Go")) { if (prevMapRec.WdtFileID > 0) { - m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, worldPosX, worldPosY, 200); + m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, worldPosX, worldPosY, 200, prevMapRec.overrideTime); } else { - m_backgroundScene->openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, worldPosX, worldPosY, 200); + m_backgroundScene->openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, worldPosX, worldPosY, 200, prevMapRec.overrideTime); } showSelectMap = false; @@ -771,11 +775,11 @@ void FrontendUI::showMapSelectionDialog() { worldPosY = 0; if (ImGui::Button("Open WMO Map", ImVec2(-1, 0))) { if (prevMapRec.WdtFileID > 0) { - m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0); + m_backgroundScene->openMapByIdAndWDTId(prevMapId, prevMapRec.WdtFileID, 17066.6641f, 17066.67380f, 0, prevMapRec.overrideTime); } else { //Try to open map by fileName m_backgroundScene->openMapByIdAndFilename(prevMapId, prevMapRec.MapDirectory, 17066.6641f, 17066.67380f, - 0); + 0, prevMapRec.overrideTime); } showSelectMap = false; } @@ -834,7 +838,7 @@ void FrontendUI::showMainMenu() { } else if (fileType == "wmo") { getOrCreateWindow()->openWMOSceneByfdid(fileId); } else if (fileType == "wdt") { - getOrCreateWindow()->openMapByIdAndWDTId(0, fileId, 0,0,0); + getOrCreateWindow()->openMapByIdAndWDTId(0, fileId, 0,0,0, -1); } }); } @@ -1000,7 +1004,7 @@ void FrontendUI::showQuickLinksDialog() { getOrCreateWindow()->openM2SceneByfdid(1810676, replacementTextureFDids); } if (ImGui::Button("Tomb of sargares hall", ImVec2(-1, 0))) { - getOrCreateWindow()->openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028); + getOrCreateWindow()->openMapByIdAndWDTId(1676, 1532459, 6289, -801, 3028, -1); } if (ImGui::Button("Legion Dalaran", ImVec2(-1, 0))) { getOrCreateWindow()->openWMOSceneByfdid(1120838); @@ -1049,7 +1053,7 @@ void FrontendUI::showQuickLinksDialog() { // openMapByIdAndFilename(0, "azeroth", -8739, 944, 200); // } if (ImGui::Button("Nyalotha map", ImVec2(-1, 0))) { - getOrCreateWindow()->openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260); + getOrCreateWindow()->openMapByIdAndWDTId(2217, 2842322, -11595, 9280, 260, -1); } if (ImGui::Button("WMO 1247268", ImVec2(-1, 0))) { getOrCreateWindow()->openWMOSceneByfdid(1247268); diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.cpp b/src/ui/childWindow/sceneWindow/SceneWindow.cpp index 24fa6570c..fae8777ab 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.cpp +++ b/src/ui/childWindow/sceneWindow/SceneWindow.cpp @@ -182,7 +182,7 @@ HApiContainer SceneWindow::createNewApiContainer() { return newApi; } -void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z) { +void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z, int timeOverride) { unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); @@ -191,6 +191,10 @@ void SceneWindow::openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y m_camera = std::make_shared(); m_camera->setCameraPos(x,y,z); m_camera->setMovementSpeed(movementSpeed); + + if (timeOverride >= 0) { + m_api->getConfig()->currentTime = timeOverride; + } } void SceneWindow::openM2SceneByfdid(int m2Fdid, const std::vector &replacementTextureIds) { unload(); @@ -256,7 +260,7 @@ void SceneWindow::openWMOSceneByFilename(const std::string &wmoFileName) { m_camera->setCameraPos(0, 0, 0); } -void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z) { +void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z, int timeOverride) { unload(); m_sceneRenderer = MapSceneRendererFactory::createForwardRenderer(m_api->hDevice, m_api->getConfig()); @@ -265,6 +269,10 @@ void SceneWindow::openMapByIdAndFilename(int mapId, const std::string &mapName, m_camera = std::make_shared(); m_camera->setCameraPos(x,y,z); m_camera->setMovementSpeed(movementSpeed); + + if (timeOverride >= 0) { + m_api->getConfig()->currentTime = timeOverride; + } } diff --git a/src/ui/childWindow/sceneWindow/SceneWindow.h b/src/ui/childWindow/sceneWindow/SceneWindow.h index 1475ab024..3ff3b8389 100644 --- a/src/ui/childWindow/sceneWindow/SceneWindow.h +++ b/src/ui/childWindow/sceneWindow/SceneWindow.h @@ -26,8 +26,8 @@ class SceneWindow : public std::enable_shared_from_this { SceneWindow(const HApiContainer &api, bool renderToSwapChain, const std::shared_ptr &uiRenderer); virtual ~SceneWindow(); - void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z); - void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z); + void openMapByIdAndFilename(int mapId, const std::string &mapName, float x, float y, float z, int timeOverride); + void openMapByIdAndWDTId(int mapId, int wdtFileId, float x, float y, float z, int timeOverride); void openWMOSceneByfdid(int WMOFdid); void openWMOSceneByFilename(const std::string &wmoFileName); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 9915659d7..8b7e17abe 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -14,6 +14,7 @@ #include "../../../../../wowViewerLib/src/gapi/UniformBufferStructures.h" #include "../../../../../wowViewerLib/src/gapi/interface/materials/IMaterial.h" #include "../../../../../wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../../../wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp index 1c9411988..c919d8b1d 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp @@ -11,3 +11,5 @@ #include "../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" #include #include + + diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index f0bf9943d..f54df69d1 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -348,7 +348,9 @@ using m2Container = framebased::vector; void inline removeDuplicates(m2Container &array) { if (array.size() < 1000) { - std::sort(array.begin(), array.end()); + std::sort(array.begin(), array.end(), [](auto &a, auto &b) -> bool { + return a < b; + }); } else { tbb::parallel_sort(array.begin(), array.end(), [](auto &a, auto &b) -> bool { return a < b; diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index 38ea92a8a..0720f243c 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -8,10 +8,16 @@ #include #include #include "../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" +#include "memoryPool/MemoryPool.h" + + template class EntityFactory : public std::enable_shared_from_this>{ static constexpr int initSize = 1000; +static constexpr int BlockSize = sizeof(T)*5000; + +MemoryPool pool; public: explicit EntityFactory() { objectCache.resize(initSize); @@ -32,27 +38,33 @@ static constexpr int initSize = 1000; offsetData = allocator.allocate(1); objectCache.resize(objectCache.size() + growSize); } + auto ptr = pool.allocate(); - entity = new T(std::forward(__args)...); + entity = new(ptr) T(std::forward(__args)...); entity->setId((ObjIdType)offsetData.offset); objectCache[offsetData.offset] = entity; } auto weakPtr = this->weak_from_this(); - return std::shared_ptr(entity, [offsetData, weakPtr](T *ls) -> void { + return std::shared_ptr(entity, [offsetData, weakPtr, entity](T *ls) -> void { auto shared = weakPtr.lock(); if (shared != nullptr) shared->deallocate(offsetData); }); } T * getObjectById(ObjIdType id) { + int index = (int)id; + if ((index < 0) || (index >= ((int)objectCache.size()))) + return nullptr; + return objectCache[(int)id]; } void deallocate(const OffsetAllocator::Allocation &alloc) { std::unique_lock lock(m_mutex); - delete objectCache[alloc.offset]; + objectCache[alloc.offset]->~T(); + pool.deallocate(objectCache[alloc.offset]); objectCache[alloc.offset] = nullptr; allocator.free(alloc); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f1d132472..7183ea51c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -367,7 +367,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams m_viewRenderOrder = 0; mapRenderPlan->m_currentInteriorGroups = {}; - mapRenderPlan->m_currentWMO = nullptr; + mapRenderPlan->m_currentWMO = emptyWMO; int bspNodeId = -1; int interiorGroupNum = -1; @@ -382,12 +382,15 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams //Hack that is needed to get the current WMO the camera is in. Basically it does frustum culling over current ADT getPotentialEntities(frustumData, cameraPos, mapRenderPlan, potentialM2, potentialWmo); - for (auto &checkingWmoObj: potentialWmo.getCandidates()) { + for (auto &wmoId: potentialWmo.getCandidates()) { WmoGroupResult groupResult; + auto checkingWmoObj = wmoFactory.getObjectById(wmoId); + if (checkingWmoObj == nullptr) continue; + bool result = checkingWmoObj->getGroupWmoThatCameraIsInside(camera4, groupResult); if (result) { - mapRenderPlan->m_currentWMO = checkingWmoObj; + mapRenderPlan->m_currentWMO = wmoId; mapRenderPlan->m_currentWmoGroup = groupResult.groupIndex; if (checkingWmoObj->isGroupWmoInterior(groupResult.groupIndex)) { mapRenderPlan->m_currentInteriorGroups.push_back(groupResult); @@ -410,13 +413,16 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams AreaRecord wmoAreaRecord; bool wmoAreaFound = false; - if (mapRenderPlan->m_currentWMO != nullptr) { - auto nameId = mapRenderPlan->m_currentWMO->getNameSet(); - auto wmoId = mapRenderPlan->m_currentWMO->getWmoId(); - auto groupId = mapRenderPlan->m_currentWMO->getWmoGroupId(mapRenderPlan->m_currentWmoGroup); - - if (m_api->databaseHandler != nullptr) { - wmoAreaFound = m_api->databaseHandler->getWmoArea(wmoId, nameId, groupId, wmoAreaRecord); + if (mapRenderPlan->m_currentWMO != emptyWMO) { + auto l_currentWmoObject = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); + if (l_currentWmoObject != nullptr) { + auto nameId = l_currentWmoObject->getNameSet(); + auto wmoId = l_currentWmoObject->getWmoId(); + auto groupId = l_currentWmoObject->getWmoGroupId(mapRenderPlan->m_currentWmoGroup); + + if (m_api->databaseHandler != nullptr) { + wmoAreaFound = m_api->databaseHandler->getWmoArea(wmoId, nameId, groupId, wmoAreaRecord); + } } } @@ -447,7 +453,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams ///----------------------------------- - auto lcurrentWMO = mapRenderPlan->m_currentWMO; + auto lcurrentWMO = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); auto currentWmoGroup = mapRenderPlan->m_currentWmoGroup; if ((lcurrentWMO != nullptr) && (!mapRenderPlan->m_currentInteriorGroups.empty()) && (lcurrentWMO->isLoaded())) { @@ -459,7 +465,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams m_viewRenderOrder, true, mapRenderPlan->viewsHolder)) { - mapRenderPlan->wmoArray.addToDrawn(mapRenderPlan->m_currentWMO); + mapRenderPlan->wmoArray.addToDrawn(lcurrentWMO); } auto exterior = mapRenderPlan->viewsHolder.getExterior(); @@ -593,9 +599,12 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp bool fogRecordWasFound = false; mathfu::vec3 endFogColor = mathfu::vec3(0.0, 0.0, 0.0); - std::vector wmoFogs = {}; - if (mapRenderPlan->m_currentWMO != nullptr) { - mapRenderPlan->m_currentWMO->checkFog(frustumData.cameraPos, wmoFogs); + std::vector wmoFogData = {}; + if (mapRenderPlan->m_currentWMO != emptyWMO) { + auto l_currentWmoObject = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); + if (l_currentWmoObject != nullptr) { + l_currentWmoObject->checkFog(frustumData.cameraPos, wmoFogData); + } } std::vector lightResults; @@ -823,28 +832,48 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp //Apply fog from WMO { - bool fogDefaultExist = false; - int fogDefaultIndex = -1; - for (int i = 0; i < wmoFogs.size() && totalSummator < 1.0f; i++) { - auto &fogRec = wmoFogs[i]; - if (fogRec.isDefault) { - fogDefaultExist = true; - fogDefaultIndex = i; - continue; + for (auto &wmoFog : wmoFogData) { + auto &lightResult = combinedResults.emplace_back(); + auto farPlaneClamped = std::min(config->farPlane, wmoFog.end); + + std::array colorConverted; + ImVectorToArrBGR(colorConverted, wmoFog.color); + + lightResult.FogEnd = farPlaneClamped; + lightResult.FogStart = farPlaneClamped * wmoFog.start_scalar; + lightResult.SkyFogColor = colorConverted; + lightResult.FogDensity = 1.0; + lightResult.FogHeightColor = colorConverted; + lightResult.EndFogColor = colorConverted; + lightResult.SunFogColor = colorConverted; + lightResult.HeightEndFogColor = colorConverted; + + if (farPlaneClamped < 30.f) { + lightResult.FogEnd = farPlaneClamped; + farPlaneClamped = 30.f; } - if (totalSummator + fogRec.blendCoef > 1.0f) { - fogRec.blendCoef = 1.0f - totalSummator; - totalSummator = 1.0f; - } else { - totalSummator += fogRec.blendCoef; + + bool mapHasWeightedBlendFlag = false; + if (!mapHasWeightedBlendFlag) { + float difference = farPlaneClamped - lightResult.FogStart; + float farPlaneClamped2 = std::min(config->farPlane, 700.0f) - 200.0f; + if ((difference > farPlaneClamped2) || (farPlaneClamped2 <= 0.0f)) { + lightResult.FogDensity = 1.5; + } else { + lightResult.FogDensity = ((1.0 - (difference / farPlaneClamped2)) * 5.5) + 1.5; + } + lightResult.FogEnd = config->farPlane; + if (lightResult.FogStart < 0.0f) + lightResult.FogStart = 0.0; } - combinedResults.push_back(fogRec); - } - if (fogDefaultExist && totalSummator < 1.0f) { - wmoFogs[fogDefaultIndex].blendCoef = 1.0f - totalSummator; - totalSummator = 1.0f; - combinedResults.push_back(wmoFogs[fogDefaultIndex]); + lightResult.FogHeightDensity = lightResult.FogDensity; + lightResult.FogStartOffset = 0; + lightResult.FogHeightScaler = 1.0; + lightResult.FogZScalar = 0; + lightResult.FogHeight = -10000.0; + lightResult.LegacyFogScalar = 1.0; + lightResult.EndFogColorDistance = 10000.0; } } @@ -1065,7 +1094,7 @@ void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData } } else { if (wmoMap == nullptr) { - wmoMap = std::make_shared(m_api); + wmoMap = wmoFactory.createObject(m_api); wmoMap->setLoadingParam(*m_wdtfile->wmoDef); wmoMap->setModelFileId(m_wdtfile->wmoDef->nameId); } @@ -1131,8 +1160,9 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, getCandidatesEntities(frustumData, cameraPos, mapRenderPlan, exteriorView->m2List, mapRenderPlan->wmoArray); //Frustum cull - for (auto &wmoCandidate : mapRenderPlan->wmoArray.getCandidates()) { - if (!wmoCandidate->isLoaded()) continue; + for (auto &wmoId : mapRenderPlan->wmoArray.getCandidates()) { + auto wmoCandidate = wmoFactory.getObjectById(wmoId); + if (wmoCandidate!= nullptr && !wmoCandidate->isLoaded()) continue; if (wmoCandidate->startTraversingWMOGroup( cameraPos, @@ -1415,9 +1445,11 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende { ZoneScopedN("Load wmoObject"); if (m_api->getConfig()->renderWMO) { - for (auto &wmoObject: renderPlan->wmoArray.getToLoad()) { - if (wmoObject == nullptr) continue; - wmoObject->doPostLoad(sceneRenderer); + for (auto wmoId: renderPlan->wmoArray.getToLoad()) { + auto wmoObject = wmoFactory.getObjectById(wmoId); + if (wmoObject != nullptr) { + wmoObject->doPostLoad(sceneRenderer); + } } } } @@ -1521,7 +1553,8 @@ void Map::update(const HMapRenderPlan &renderPlan) { { ZoneScopedN("wmoUpdate"); - for (const auto &wmoObject: renderPlan->wmoArray.getToDrawn()) { + for (const auto &wmoId: renderPlan->wmoArray.getToDrawn()) { + auto wmoObject = wmoFactory.getObjectById(wmoId); if (wmoObject == nullptr) continue; wmoObject->update(); } @@ -1741,7 +1774,7 @@ std::shared_ptr Map::getWmoObject(std::string fileName, SMMapObjDef & if (!it.expired()) { return it.lock(); } else { - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileName(fileName); @@ -1756,7 +1789,7 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDef &mapObj if (!it.expired()) { return it.lock(); } else { - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileId(fileDataId); @@ -1771,7 +1804,7 @@ std::shared_ptr Map::getWmoObject(std::string fileName, SMMapObjDefOb if (!it.expired()) { return it.lock(); } else { - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileName(fileName); @@ -1786,7 +1819,7 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDefObj1 &ma if (!it.expired()) { return it.lock(); } else { - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileId(fileDataId); diff --git a/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.h b/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.h new file mode 100644 index 000000000..bae976eac --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2013 Cosku Acay, http://www.coskuacay.com + * + * 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. + */ + +#ifndef MEMORY_POOL_H +#define MEMORY_POOL_H + +#include +#include + +template +class MemoryPool +{ + public: + /* Member types */ + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef const T* const_pointer; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::false_type propagate_on_container_copy_assignment; + typedef std::true_type propagate_on_container_move_assignment; + typedef std::true_type propagate_on_container_swap; + + template struct rebind { + typedef MemoryPool other; + }; + + /* Member functions */ + MemoryPool() noexcept; + MemoryPool(const MemoryPool& memoryPool) noexcept; + MemoryPool(MemoryPool&& memoryPool) noexcept; + template MemoryPool(const MemoryPool& memoryPool) noexcept; + + ~MemoryPool() noexcept; + + MemoryPool& operator=(const MemoryPool& memoryPool) = delete; + MemoryPool& operator=(MemoryPool&& memoryPool) noexcept; + + pointer address(reference x) const noexcept; + const_pointer address(const_reference x) const noexcept; + + // Can only allocate one object at a time. n and hint are ignored + pointer allocate(size_type n = 1, const_pointer hint = 0); + void deallocate(pointer p, size_type n = 1); + + size_type max_size() const noexcept; + + template void construct(U* p, Args&&... args); + template void destroy(U* p); + + template pointer newElement(Args&&... args); + void deleteElement(pointer p); + + private: + union Slot_ { + value_type element; + Slot_* next; + }; + + typedef char* data_pointer_; + typedef Slot_ slot_type_; + typedef Slot_* slot_pointer_; + + slot_pointer_ currentBlock_; + slot_pointer_ currentSlot_; + slot_pointer_ lastSlot_; + slot_pointer_ freeSlots_; + + size_type padPointer(data_pointer_ p, size_type align) const noexcept; + void allocateBlock(); + + static_assert(BlockSize >= 2 * sizeof(slot_type_), "BlockSize too small."); +}; + +#include "MemoryPool.tcc" + +#endif // MEMORY_POOL_H diff --git a/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.tcc b/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.tcc new file mode 100644 index 000000000..562d958e2 --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/memoryPool/MemoryPool.tcc @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2013 Cosku Acay, http://www.coskuacay.com + * + * 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. + */ + +#ifndef MEMORY_BLOCK_TCC +#define MEMORY_BLOCK_TCC + + + +template +inline typename MemoryPool::size_type +MemoryPool::padPointer(data_pointer_ p, size_type align) +const noexcept +{ + uintptr_t result = reinterpret_cast(p); + return ((align - result) % align); +} + + + +template +MemoryPool::MemoryPool() +noexcept +{ + currentBlock_ = nullptr; + currentSlot_ = nullptr; + lastSlot_ = nullptr; + freeSlots_ = nullptr; +} + + + +template +MemoryPool::MemoryPool(const MemoryPool& memoryPool) +noexcept : +MemoryPool() +{} + + + +template +MemoryPool::MemoryPool(MemoryPool&& memoryPool) +noexcept +{ + currentBlock_ = memoryPool.currentBlock_; + memoryPool.currentBlock_ = nullptr; + currentSlot_ = memoryPool.currentSlot_; + lastSlot_ = memoryPool.lastSlot_; + freeSlots_ = memoryPool.freeSlots; +} + + +template +template +MemoryPool::MemoryPool(const MemoryPool& memoryPool) +noexcept : +MemoryPool() +{} + + + +template +MemoryPool& +MemoryPool::operator=(MemoryPool&& memoryPool) +noexcept +{ + if (this != &memoryPool) + { + std::swap(currentBlock_, memoryPool.currentBlock_); + currentSlot_ = memoryPool.currentSlot_; + lastSlot_ = memoryPool.lastSlot_; + freeSlots_ = memoryPool.freeSlots; + } + return *this; +} + + + +template +MemoryPool::~MemoryPool() +noexcept +{ + slot_pointer_ curr = currentBlock_; + while (curr != nullptr) { + slot_pointer_ prev = curr->next; + operator delete(reinterpret_cast(curr)); + curr = prev; + } +} + + + +template +inline typename MemoryPool::pointer +MemoryPool::address(reference x) +const noexcept +{ + return &x; +} + + + +template +inline typename MemoryPool::const_pointer +MemoryPool::address(const_reference x) +const noexcept +{ + return &x; +} + + + +template +void +MemoryPool::allocateBlock() +{ + // Allocate space for the new block and store a pointer to the previous one + data_pointer_ newBlock = reinterpret_cast + (operator new(BlockSize)); + reinterpret_cast(newBlock)->next = currentBlock_; + currentBlock_ = reinterpret_cast(newBlock); + // Pad block body to staisfy the alignment requirements for elements + data_pointer_ body = newBlock + sizeof(slot_pointer_); + size_type bodyPadding = padPointer(body, alignof(slot_type_)); + currentSlot_ = reinterpret_cast(body + bodyPadding); + lastSlot_ = reinterpret_cast + (newBlock + BlockSize - sizeof(slot_type_) + 1); +} + + + +template +inline typename MemoryPool::pointer +MemoryPool::allocate(size_type n, const_pointer hint) +{ + if (freeSlots_ != nullptr) { + pointer result = reinterpret_cast(freeSlots_); + freeSlots_ = freeSlots_->next; + return result; + } + else { + if (currentSlot_ >= lastSlot_) + allocateBlock(); + return reinterpret_cast(currentSlot_++); + } +} + + + +template +inline void +MemoryPool::deallocate(pointer p, size_type n) +{ + if (p != nullptr) { + reinterpret_cast(p)->next = freeSlots_; + freeSlots_ = reinterpret_cast(p); + } +} + + + +template +inline typename MemoryPool::size_type +MemoryPool::max_size() +const noexcept +{ + size_type maxBlocks = -1 / BlockSize; + return (BlockSize - sizeof(data_pointer_)) / sizeof(slot_type_) * maxBlocks; +} + + + +template +template +inline void +MemoryPool::construct(U* p, Args&&... args) +{ + new (p) U (std::forward(args)...); +} + + + +template +template +inline void +MemoryPool::destroy(U* p) +{ + p->~U(); +} + + + +template +template +inline typename MemoryPool::pointer +MemoryPool::newElement(Args&&... args) +{ + pointer result = allocate(); + construct(result, std::forward(args)...); + return result; +} + + + +template +inline void +MemoryPool::deleteElement(pointer p) +{ + if (p != nullptr) { + p->~value_type(); + deallocate(p); + } +} + + + +#endif // MEMORY_BLOCK_TCC diff --git a/wowViewerLib/src/engine/objects/scenes/wmoScene.h b/wowViewerLib/src/engine/objects/scenes/wmoScene.h index 05b3f3900..f1f511f2b 100644 --- a/wowViewerLib/src/engine/objects/scenes/wmoScene.h +++ b/wowViewerLib/src/engine/objects/scenes/wmoScene.h @@ -41,7 +41,7 @@ class WmoScene : public Map { mapObjDef.extents.max = C3Vector(mathfu::vec3(9999,9999,9999)); mapObjDef.doodadSet = 0; - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileName(m_wmoModel); @@ -61,7 +61,7 @@ class WmoScene : public Map { mapObjDef.extents.max = C3Vector(mathfu::vec3(9999,9999,9999)); mapObjDef.doodadSet = 0; - auto wmoObject = std::make_shared(m_api); + auto wmoObject = wmoFactory.createObject(m_api); wmoObject->setLoadingParam(mapObjDef); wmoObject->setModelFileId(fileDataId); diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp index b28fde55a..c782b564a 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp @@ -189,7 +189,7 @@ void WdlObject::checkSkyScenes(const StateForConditions &state, auto const &m2Object = skyModel.m_model; if(skyModel.animateWithTimeOfDay) { - m2Object->setOverrideAnimationPerc(config->currentTime / 2880.0, true); + m2Object->setOverrideAnimationPerc(config->currentTime / 2880.0f, true); } m2ObjectsCandidates.addToDraw(m2Object); } diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 807e716c8..7e7b44e96 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1224,7 +1224,7 @@ std::function WmoObject::getAttenFunction() { } ; } -void WmoObject::checkFog(mathfu::vec3 &cameraPos, std::vector &fogResults) { +void WmoObject::checkFog(mathfu::vec3 &cameraPos, std::vector &fogResults) { mathfu::vec3 cameraLocal = (m_placementInvertMatrix * mathfu::vec4(cameraPos, 1.0)).xyz(); for (int i = mainGeom->fogsLen-1; i >= 0; i--) { SMOFog &fogRecord = mainGeom->fogs[i]; @@ -1232,32 +1232,7 @@ void WmoObject::checkFog(mathfu::vec3 &cameraPos, std::vector &fogR float distanceToFog = (fogPosVec - cameraLocal).Length(); if ((distanceToFog < fogRecord.larger_radius) || fogRecord.flag_infinite_radius) { - LightResult wmoFog; - wmoFog.id = -1; - wmoFog.FogScaler = fogRecord.fog.start_scalar; - wmoFog.FogEnd = fogRecord.fog.end; - wmoFog.FogDensity = 0.18f; - - wmoFog.FogHeightScaler = 0; - wmoFog.FogHeightDensity = 0; - wmoFog.SunFogAngle = 0; - wmoFog.EndFogColorDistance = 0; - wmoFog.SunFogStrength = 0; - if (fogRecord.flag_infinite_radius) { - wmoFog.blendCoef = 1.0; - wmoFog.isDefault = true; - } else { - wmoFog.blendCoef = std::min( - (fogRecord.larger_radius - distanceToFog) / (fogRecord.larger_radius - fogRecord.smaller_radius), - 1.0f); - wmoFog.isDefault = false; - } - std::array fogColor = {fogRecord.fog.color.r/255.0f, fogRecord.fog.color.g/255.0f, fogRecord.fog.color.b/255.0f}; - wmoFog.EndFogColor = fogColor; - wmoFog.SunFogColor = fogColor; - wmoFog.FogHeightColor = fogColor; - - fogResults.push_back(wmoFog); + fogResults.push_back(fogRecord.fog); } } } @@ -1418,4 +1393,6 @@ void WmoObject::createNewLights() { std::shared_ptr WmoObject::getNewLight(int index) { return m_newLights[index]; -} \ No newline at end of file +} + +EntityFactory wmoFactory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 3764b6551..2ca539b2b 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -25,7 +25,10 @@ class WmoGroupObject; #include "../SceneObjectWithID.h" #include "../lights/CWmoNewLight.h" -class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { +enum class WMOObjId : int; +constexpr WMOObjId emptyWMO = static_cast(0xFFFFFFF); + +class WmoObject : public IWmoApi, public ObjectWithId{ public: WmoObject(HApiContainer &api/*, int id*/) : /*SceneObjectWithId(id),*/ m_api(api) { @@ -142,7 +145,7 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { void collectMeshes(std::vector &renderedThisFrame); void createGroupObjects(); - void checkFog(mathfu::vec3 &cameraPos, std::vector &fogResults); + void checkFog(mathfu::vec3 &cameraPos, std::vector &wmoFogData); bool doPostLoad(const HMapSceneBufferCreate &sceneRenderer); void update(); @@ -196,8 +199,10 @@ class WmoObject : public IWmoApi/*, public SceneObjectWithId*/ { std::shared_ptr getNewLight(int index) override; }; +extern EntityFactory wmoFactory; + class WMOListContainer { - using wmoContainer = framebased::vector>; + using wmoContainer = framebased::vector; // using wmoContainer = std::vector>; private: wmoContainer wmoCandidates; @@ -212,7 +217,9 @@ class WMOListContainer { void inline removeDuplicates(wmoContainer &array) { if (array.size() < 1000) { - std::sort(array.begin(), array.end()); + std::sort(array.begin(), array.end(), [](auto &a, auto &b) -> bool { + return a < b; + }); } else { tbb::parallel_sort(array.begin(), array.end(), [](auto &a, auto &b) -> bool { return a < b; @@ -235,10 +242,10 @@ class WMOListContainer { } if (toDraw->isLoaded()) { - wmoCandidates.push_back(toDraw); + wmoCandidates.push_back(toDraw->getObjectId()); candCanHaveDuplicates = true; } else { - wmoToLoad.push_back(toDraw); + wmoToLoad.push_back(toDraw->getObjectId()); toLoadCanHaveDuplicates = true; } } @@ -249,7 +256,7 @@ class WMOListContainer { } if (!toLoad->isLoaded()) { - wmoToLoad.push_back(toLoad); + wmoToLoad.push_back(toLoad->getObjectId()); toLoadCanHaveDuplicates = true; } } @@ -260,7 +267,17 @@ class WMOListContainer { } if (toDrawn->isLoaded()) { - wmoToDrawn.push_back(toDrawn); + wmoToDrawn.push_back(toDrawn->getObjectId()); + toDrawmCanHaveDuplicates = true; + } + } + void addToDrawn(WmoObject* toDrawn) { + if (m_locked) { + throw "oops"; + } + + if (toDrawn->isLoaded()) { + wmoToDrawn.push_back(toDrawn->getObjectId()); toDrawmCanHaveDuplicates = true; } } diff --git a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h index aede27c6e..e37c8a53a 100644 --- a/wowViewerLib/src/engine/persistance/header/commonFileStructs.h +++ b/wowViewerLib/src/engine/persistance/header/commonFileStructs.h @@ -10,6 +10,7 @@ #endif #include +#include #include #include @@ -327,6 +328,14 @@ inline mathfu::vec4 ImVectorToVec4(const CImVector &color) { ); } +inline void ImVectorToArrBGR(std::array &arr, const CImVector &color) { + arr = {{ + ((float) color.b) / 255.0f, + ((float) color.g) / 255.0f, + ((float) color.r) / 255.0f + }}; +} + struct C4Plane { union { diff --git a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h index 8f649c4d1..2e0a17366 100644 --- a/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wmoFileHeader.h @@ -206,6 +206,12 @@ struct SMODoodadDef /*020h*/ float scale; // scale factor /*024h*/ CImVector color; // (B,G,R,A) diffuse lighting color, used in place of global diffuse from DBCs }; + +struct SMOFog_Data { + /*018h*/ float end; + /*01Ch*/ float start_scalar; // (0..1) + /*020h*/ CImVector color; +}; struct SMOFog { /*000h*/ uint32_t flag_infinite_radius : 1; // F_IEBLEND: Ignore radius in CWorldView::QueryCameraFog @@ -215,20 +221,10 @@ struct SMOFog /*004h*/ C3Vector pos; /*010h*/ float smaller_radius; // start /*014h*/ float larger_radius; // end - struct - { - /*018h*/ float end; - /*01Ch*/ float start_scalar; // (0..1) - /*020h*/ CImVector color; // The back buffer is also cleared to this colour - } fog; - struct - { - /*024h*/ float end; - /*028h*/ float start_scalar; // (0..1) - /*02Ch*/ CImVector color; - } underwater_fog; + SMOFog_Data fog; + SMOFog_Data underwater_fog; }; - +static_assert(sizeof(SMOFog) == 0x30); struct MOGP { diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index a2819e3d0..c7fc2c06c 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -30,7 +30,7 @@ GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, } GMeshVLK::~GMeshVLK() { - +// std::cout << "mesh destroyed" << std::endl; } bool GMeshVLK::getIsTransparent() { return m_isTransparent; } diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 6f683087d..7ebdc473e 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -15,6 +15,7 @@ struct MapRecord { std::string MapName; int WdtFileID; int MapType; + int overrideTime; }; struct LightResult { @@ -36,6 +37,7 @@ struct LightResult { std::array SkyFogColor; //Fog + float FogStart = 0.0; float FogEnd = 0.0; float FogScaler = 0.0; float FogDensity = 100000; diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index efda5b54c..ad9bc075e 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -29,7 +29,7 @@ struct MapRenderPlan { std::vector m_currentInteriorGroups = {}; bool currentWmoGroupIsExtLit = false; bool currentWmoGroupShowExtSkybox = false; - std::shared_ptr m_currentWMO = nullptr; + WMOObjId m_currentWMO = emptyWMO; int m_currentWmoGroup = -1; FrameViewsHolder viewsHolder; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 77d9f690d..96af67697 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -14,8 +14,9 @@ #include "../../../gapi/vulkan/materials/ISimpleMaterialVLK.h" #include "view/RenderViewForwardVLK.h" #include "../../../gapi/vulkan/descriptorSets/bindless/BindlessTextureHolder.h" -#include "../../../engine/objects/scenes/EntityActorsFactory.h" #include "view/RenderViewDeferredVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" +#include "../../../engine/objects/scenes/EntityActorsFactory.h" class COpaqueMeshCollectorBindlessVLK; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index 911412abf..deccbdb35 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -12,6 +12,7 @@ #include "../materials/IMaterialStructs.h" #include "passes/FFXGlowPassVLK.h" #include "view/RenderViewForwardVLK.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../engine/objects/scenes/EntityActorsFactory.h" class MapSceneRenderForwardVLK : public MapSceneRenderer { From 27b02260ec042600ef0fb55a992eb1df6cc6dd03 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 26 Apr 2024 05:02:55 +0300 Subject: [PATCH 195/212] - fix memory leak, use custom allocator for frames --- .../FrameBasedStackAllocator.cpp | 92 ++++++++++++++++++- .../FrameBasedStackAllocator.h | 54 ++++++++++- .../src/engine/objects/m2/m2Object.cpp | 3 +- wowViewerLib/src/engine/objects/m2/m2Object.h | 2 +- .../objects/scenes/EntityActorsFactory.h | 10 +- .../src/engine/objects/scenes/m2Scene.cpp | 6 ++ .../src/engine/objects/scenes/m2Scene.h | 2 +- .../src/engine/objects/scenes/map.cpp | 1 + .../interface/textures/ISamplableTexture.h | 7 ++ .../src/gapi/vulkan/GDeviceVulkan.cpp | 3 + .../vulkan/descriptorSets/DescriptorRecord.h | 2 + .../src/gapi/vulkan/meshes/GMeshVLK.cpp | 3 +- .../src/gapi/vulkan/textures/GTextureVLK.cpp | 11 ++- .../mapScene/MapSceneRendererFactory.cpp | 2 + .../mapScene/materials/IMaterialStructs.h | 6 ++ .../vulkan/MapSceneRenderBindlessVLK.cpp | 20 ++-- .../vulkan/MapSceneRenderBindlessVLK.h | 2 - 17 files changed, 196 insertions(+), 30 deletions(-) diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp index c919d8b1d..2e61d19c8 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp @@ -8,8 +8,98 @@ #include #include "../../gapi/interface/IDevice.h" -#include "../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" #include #include +static inline uint8_t BitScanMSB2(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} +struct MemoryStoringPool { + MemoryStoringPool(size_t size) { + currentOffset = 0; + data.resize(size); + } + int currentOffset; + std::vector> data; +}; + + + +std::array g_frameStackMutexes; +std::array>, 2*IDevice::MAX_FRAMES_IN_FLIGHT> g_frameStackList; + +inline void * allocateFromMemPool(size_t alignedSize, std::unique_ptr &frameRegion, int ®ionSize) { + void *ptr = nullptr; + + regionSize = frameRegion->data.size(); + + bool isWithinBoundary = (frameRegion->currentOffset + ((alignedSize+16)) < regionSize); + if (isWithinBoundary) { + ptr = &frameRegion->data[frameRegion->currentOffset]; + frameRegion->currentOffset += alignedSize; + } + + return ptr; +} + +void * frameLinearAllocate(size_t size) { + auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % (2 * IDevice::MAX_FRAMES_IN_FLIGHT); + + std::lock_guard lock(g_frameStackMutexes[currentFrame]); + auto ¤t_list = g_frameStackList[currentFrame]; + + size_t alignedSize = (size + 16) & (~15L); + + void *ptr = nullptr; + int regionSize = 2048; + if (current_list.size() > 0) { + auto &memPoolRegion = current_list.front(); + + if (memPoolRegion) { + ptr = allocateFromMemPool(alignedSize, memPoolRegion, regionSize); + } + } + if (ptr == nullptr) { + size_t currentBufferSize = regionSize; + size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); + + auto newPool = std::make_unique(newSize); + ptr = allocateFromMemPool(alignedSize, newPool, regionSize); + + current_list.push_front(std::move(newPool)); + } + if (ptr == nullptr) { + std::cout << "oops!!!" << std::endl; + } + + return ptr; +} + +void allocatorBeginFrame(unsigned int frameNum) { + auto currentFrame = frameNum % (2 * IDevice::MAX_FRAMES_IN_FLIGHT); + std::lock_guard lock(g_frameStackMutexes[currentFrame]); + + if (!g_frameStackList[currentFrame].empty()) { + g_frameStackList[currentFrame].resize(1); + g_frameStackList[currentFrame].front()->currentOffset = 0; + } +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index ca1f47795..ccaa0b7ea 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -13,8 +13,56 @@ #include "tbb/tbb.h" #include "tbb/scalable_allocator.h" +void * frameLinearAllocate(size_t size); +void allocatorBeginFrame(unsigned int frameNum); + +template +struct FrameBasedStackAllocator +{ + typedef T value_type; + + FrameBasedStackAllocator() = default; + + template + constexpr FrameBasedStackAllocator(const FrameBasedStackAllocator &) noexcept {} + + [[nodiscard]] T* allocate(std::size_t n) + { + //if (n > (std::numeric_limits::max() / sizeof(T))) + // throw std::bad_array_new_length(); + + + if (auto p = static_cast(frameLinearAllocate(n * sizeof(T)))) + { +// report(p, n); + return p; + } + + return nullptr; + } + + void deallocate(T* p, std::size_t n) noexcept + { +// report(p, n, 0); +// frameDeAllocate(p); + } +private: +// void report(T* p, std::size_t n, bool alloc = true) const +// { +// std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n +// << " bytes at " << std::hex << std::showbase +// << reinterpret_cast(p) << std::dec << '\n'; +// } +}; + +template +bool operator==(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return true; } + +template +bool operator!=(const FrameBasedStackAllocator &, const FrameBasedStackAllocator &) { return false; } + template -using transp_vec = std::vector>; +using transp_vec = std::vector>; namespace framebased { @@ -23,7 +71,7 @@ namespace framebased { || defined (_VECTOR_))) #define ARENA_HAS_VECTOR_DEF template - using vector = std::vector>; + using vector = std::vector>; #endif #if ((defined (_GLIBCXX_UNORDERED_MAP) \ @@ -32,7 +80,7 @@ namespace framebased { && !defined (ARENA_HAS_UNORDERED_MAP_DEF)) #define ARENA_HAS_UNORDERED_MAP_DEF template , class KeyEqual = std::equal_to> - using unordered_map = std::unordered_map>>; + using unordered_map = std::unordered_map>>; #endif } diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 254278c06..a480096ce 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -1658,10 +1658,11 @@ std::shared_ptr M2Object::createM2Material(const HMapSceneBufferCre HGM2Mesh M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int indexStartCorrection, const HGVertexBufferBindings &finalBufferBindings, - const std::shared_ptr m2Material, + const std::shared_ptr &m2Material, const M2SkinSection *skinSection, const M2Batch *m2Batch) { gMeshTemplate meshTemplate(finalBufferBindings); + meshTemplate.meshType = MeshType::eM2Mesh; meshTemplate.start = (skinSection->indexStart + (skinSection->Level << 16) - indexStartCorrection) * 2; meshTemplate.end = skinSection->indexCount; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index f54df69d1..96c75d07a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -304,7 +304,7 @@ class M2Object : public ObjectWithId { HGM2Mesh createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int indexStartCorrection, const HGVertexBufferBindings &finalBufferBindings, - const std::shared_ptr m2Material, + const std::shared_ptr &m2Material, const M2SkinSection *skinSection, const M2Batch *m2Batch); diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index 0720f243c..f33123fbb 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -13,7 +13,7 @@ template -class EntityFactory : public std::enable_shared_from_this>{ +class EntityFactory { static constexpr int initSize = 1000; static constexpr int BlockSize = sizeof(T)*5000; @@ -45,11 +45,9 @@ MemoryPool pool; objectCache[offsetData.offset] = entity; } - auto weakPtr = this->weak_from_this(); - return std::shared_ptr(entity, [offsetData, weakPtr, entity](T *ls) -> void { - auto shared = weakPtr.lock(); - if (shared != nullptr) - shared->deallocate(offsetData); + auto l_this = this; + return std::shared_ptr(entity, [offsetData, l_this, entity](T *ls) -> void { + l_this->deallocate(offsetData); }); } T * getObjectById(ObjIdType id) { diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index c8c35e81d..9a2cdec8e 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -9,6 +9,11 @@ #include "../../../gapi/UniformBufferStructures.h" #include "../../camera/m2TiedCamera.h" +M2Scene::~M2Scene() { +// std::cout << "M2Scene destroyed" << std::endl; +} + + void M2Scene::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, const HMapRenderPlan &mapRenderPlan, @@ -146,3 +151,4 @@ void M2Scene::exportScene(IExporter* exporter) { std::shared_ptr M2Scene::getSceneM2() { return m_m2Object; } + diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.h b/wowViewerLib/src/engine/objects/scenes/m2Scene.h index 4d907fd83..984fac4d1 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.h +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.h @@ -36,7 +36,7 @@ class M2Scene : public Map { explicit M2Scene(const HApiContainer &api, int fileDataId); - ~M2Scene() override {} + ~M2Scene() override; void setReplaceTextureArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextureArray) ; void setMeshIdArray(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) ; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 7183ea51c..ee862b532 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -1545,6 +1545,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { for (auto &m2ObjectId : skyBoxView->m2List.getDrawn()) { auto m2Object = m2Factory.getObjectById(m2ObjectId); + if (m2Object == nullptr) continue; m2Object->update(deltaTime, cameraVec3, lookAtMat); } } diff --git a/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h b/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h index 245c0d0a1..a84184f34 100644 --- a/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h +++ b/wowViewerLib/src/gapi/interface/textures/ISamplableTexture.h @@ -5,6 +5,7 @@ #ifndef AWEBWOWVIEWERCPP_ISAMPLABLETEXTURE_H #define AWEBWOWVIEWERCPP_ISAMPLABLETEXTURE_H +#include #include #include "ITexture.h" #include "ITextureSampler.h" @@ -16,6 +17,12 @@ class ISamplableTexture { }; + ~ISamplableTexture() { +// std::cout << "~ISamplableTexture" << std::endl; + m_texture = nullptr; + m_sampler = nullptr; + } + auto getTexture() const { return m_texture; } diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 2714df98a..310db7a6a 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -406,6 +406,7 @@ void GDeviceVLK::initialize() { void GDeviceVLK::setObjectName(uint64_t object, VkObjectType objectType, const char *name) { // Check for valid function pointer (may not be present if not running in a debugging application) + if (vkSetDebugUtilsObjectNameEXT != nullptr) { VkDebugUtilsObjectNameInfoEXT nameInfo = {}; @@ -970,6 +971,8 @@ unsigned int GDeviceVLK::getProcessingFrameNumber() { void GDeviceVLK::increaseFrameNumber() { m_frameNumber++; + + allocatorBeginFrame(m_frameNumber); } bool GDeviceVLK::getIsAnisFiltrationSupported() { diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h index 00b46d4c9..d837ba264 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/DescriptorRecord.h @@ -49,6 +49,8 @@ class DescriptorRecord { } } } + buffer = nullptr; + texture = nullptr; } typedef std::list>::const_iterator RecordInter; diff --git a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp index c7fc2c06c..59797633a 100644 --- a/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.cpp @@ -30,7 +30,8 @@ GMeshVLK::GMeshVLK(const gMeshTemplate &meshTemplate, } GMeshVLK::~GMeshVLK() { -// std::cout << "mesh destroyed" << std::endl; +// if (m_meshType == MeshType::eM2Mesh) +// std::cout << "mesh destroyed" << std::endl; } bool GMeshVLK::getIsTransparent() { return m_isTransparent; } diff --git a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp index d8e9bb991..c685ac075 100644 --- a/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/textures/GTextureVLK.cpp @@ -63,15 +63,16 @@ void GTextureVLK::destroyBuffer() { if (!m_uploaded) return; auto *l_device = &m_device; - auto &l_texture = texture; + auto l_textureImage = texture.image; + auto l_textureView = texture.view; - auto &l_imageAllocation = imageAllocation; + auto l_imageAllocation = imageAllocation; m_device.addDeallocationRecord( - [l_device, l_texture, l_imageAllocation]() { - vkDestroyImageView(l_device->getVkDevice(), l_texture.view, nullptr); + [l_device, l_textureImage, l_textureView, l_imageAllocation]() { + vkDestroyImageView(l_device->getVkDevice(), l_textureView, nullptr); if (l_imageAllocation != nullptr) { - vmaDestroyImage(l_device->getVMAAllocator(), l_texture.image, l_imageAllocation); + vmaDestroyImage(l_device->getVMAAllocator(), l_textureImage, l_imageAllocation); } else { //This is swapchain image. Deleting swapchain image leads to exception // vkDestroyImage(l_device->getVkDevice(), l_texture.image, nullptr); diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index d73786717..077328f02 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -6,6 +6,8 @@ #include "vulkan/MapSceneRenderForwardVLK.h" #include "vulkan/MapSceneRenderBindlessVLK.h" + + std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: diff --git a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h index 6915155c5..b72310f94 100644 --- a/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h +++ b/wowViewerLib/src/renderer/mapScene/materials/IMaterialStructs.h @@ -69,6 +69,8 @@ class IM2ModelData { class IM2Material : public IMaterial { public: + ~IM2Material() override = default; + int vertexShader; int pixelShader; int batchIndex; @@ -81,6 +83,8 @@ class IM2Material : public IMaterial { class IM2MaterialVis : public IM2Material { public: + ~IM2MaterialVis() override = default; + std::shared_ptr> m_vertexFragmentDataBindless = nullptr; std::vector> m_bindlessText; int instanceIndex = 0; @@ -114,6 +118,8 @@ class IM2RibbonMaterial : public IMaterial { class ISkyMeshMaterial : public IMaterial { public: + ~ISkyMeshMaterial() override = default; + std::shared_ptr> m_skyColors = nullptr; }; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index cc107691c..d70414877 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -130,6 +130,8 @@ static const ShaderConfig waterBindlessShaderConfig = { }} }}; +EntityFactory bindlessMeshFactoryVlk; + MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { std::cout << "Create Bindless scene renderer " << std::endl; @@ -1130,14 +1132,14 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); - auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); + auto meshVlk = bindlessMeshFactoryVlk.getObjectById(meshId); auto &drawCommand = drawVec.emplace_back(); fillDrawCommand(drawCommand, meshVlk); } inline void addDrawCommand(tbb::concurrent_vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); - auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); + auto meshVlk = bindlessMeshFactoryVlk.getObjectById(meshId); DrawCommand drawCommand; fillDrawCommand(drawCommand, meshVlk); @@ -1539,11 +1541,11 @@ std::shared_ptr MapSceneRenderBindlessVLK::getLastCreatedPlan() { } HGMesh MapSceneRenderBindlessVLK::createMesh(gMeshTemplate &meshTemplate, const HMaterial &material) { - return meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); + return bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), 0,0); } HGSortableMesh MapSceneRenderBindlessVLK::createSortableMesh(gMeshTemplate &meshTemplate, const HMaterial &material, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); return mesh; } @@ -1552,7 +1554,7 @@ HGSortableMesh MapSceneRenderBindlessVLK::createWaterMesh(gMeshTemplate &meshTem meshTemplate.bindings = m_emptyWaterVAO; auto _material = std::dynamic_pointer_cast(material); - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, priorityPlane); mesh->instanceIndex = _material->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); @@ -1568,7 +1570,7 @@ MapSceneRenderBindlessVLK::createAdtMesh(gMeshTemplate &meshTemplate, const std: auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyADTVAO; - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), 0, 0); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1581,7 +1583,7 @@ MapSceneRenderBindlessVLK::createM2Mesh(gMeshTemplate &meshTemplate, const std:: ZoneScoped; auto realVAO = (GVertexBufferBindingsVLK *)meshTemplate.bindings.get(); meshTemplate.bindings = m_emptyM2VAO; - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1609,7 +1611,7 @@ HGSortableMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTempl c_perMeshData->save(); } - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(newMat), 0, 0); mesh->instanceIndex = c_perMeshData->getIndex(); mesh->vertexStart = ((IBufferVLK * )realVAO->getVertexBuffers()[0].get())->getIndex(); mesh->start() += ((IBufferVLK * )realVAO->getIndexBuffer().get())->getOffset(); @@ -1618,7 +1620,7 @@ HGSortableMesh MapSceneRenderBindlessVLK::createWMOMesh(gMeshTemplate &meshTempl HGM2Mesh MapSceneRenderBindlessVLK::createM2WaterfallMesh(gMeshTemplate &meshTemplate, const std::shared_ptr &material, int layer, int priorityPlane) { - auto mesh = meshFactory->createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); + auto mesh = bindlessMeshFactoryVlk.createObject(meshTemplate, std::dynamic_pointer_cast(material), layer, priorityPlane); mesh->instanceIndex = std::dynamic_pointer_cast(material)->instanceIndex; return mesh; } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h index 96af67697..cbd4171a2 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.h @@ -117,8 +117,6 @@ class MapSceneRenderBindlessVLK : public MapSceneRenderer { //-------------------------------------- std::shared_ptr createRenderView(bool createOutput) override; - - std::shared_ptr> meshFactory = std::make_shared>(); protected: virtual std::shared_ptr getM2StaticMaterial(const PipelineTemplate &pipelineTemplate); virtual std::shared_ptr getWMOStaticMaterial(const PipelineTemplate &pipelineTemplate); From e9089894879d35e2306f62942756f067a47448fc Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Mon, 29 Apr 2024 02:28:21 +0300 Subject: [PATCH 196/212] - games with memory --- src/minimapGenerator/minimapGenerator.cpp | 8 +- src/ui/FrontendUI.cpp | 2 +- .../vulkan/FrontendUIRenderForwardVLK.h | 2 +- .../glsl/bindless/adt/forward/adtShader.vert | 2 +- .../bindless/adt/visbuffer/adtShader.vert | 2 +- .../FrameBasedStackAllocator.cpp | 85 ++++++++--- .../FrameBasedStackAllocator.h | 3 +- .../src/engine/managers/animationManager.cpp | 20 +-- .../src/engine/managers/animationManager.h | 20 +-- .../src/engine/objects/SceneObjectWithID.h | 2 +- .../src/engine/objects/ViewsObjects.cpp | 2 +- .../src/engine/objects/ViewsObjects.h | 4 +- .../src/engine/objects/adt/adtObject.cpp | 48 ++++-- .../src/engine/objects/adt/adtObject.h | 8 +- .../engine/objects/liquid/LiquidInstance.cpp | 4 +- .../engine/objects/liquid/LiquidInstance.h | 8 +- .../objects/m2/m2Helpers/CBoneMasterData.h | 2 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 2 +- .../m2/m2Helpers/M2MeshBufferUpdater.h | 2 +- .../src/engine/objects/m2/m2Object.cpp | 64 ++++---- wowViewerLib/src/engine/objects/m2/m2Object.h | 96 +++++++++--- .../objects/scenes/EntityActorsFactory.cpp | 39 +++++ .../objects/scenes/EntityActorsFactory.h | 143 +++++++++++++++--- .../src/engine/objects/scenes/map.cpp | 75 ++++----- wowViewerLib/src/engine/objects/scenes/map.h | 2 +- .../src/engine/objects/wmo/wmoObject.cpp | 2 +- .../src/engine/objects/wmo/wmoObject.h | 2 +- .../src/gapi/vulkan/GDeviceVulkan.cpp | 20 ++- .../src/renderer/mapScene/MapScenePlan.h | 2 +- .../renderer/mapScene/MapSceneRenderer.cpp | 6 +- .../vulkan/MapSceneRenderBindlessVLK.cpp | 6 +- .../vulkan/MapSceneRenderForwardVLK.h | 2 +- .../mapScene/vulkan/MapSceneRenderVisVLK.cpp | 2 +- 33 files changed, 477 insertions(+), 210 deletions(-) diff --git a/src/minimapGenerator/minimapGenerator.cpp b/src/minimapGenerator/minimapGenerator.cpp index cf9501a80..f52ba6dd2 100644 --- a/src/minimapGenerator/minimapGenerator.cpp +++ b/src/minimapGenerator/minimapGenerator.cpp @@ -571,7 +571,7 @@ void MinimapGenerator::calcBB(const HMapRenderPlan &mapRenderPlan, mathfu::vec3 maxCoord = mathfu::vec3(-20000, -20000, -20000); for (auto &m2ObjectId: mapRenderPlan->m2Array.getDrawn()) { - auto objBB = m2Factory.getObjectById(m2ObjectId)->getAABB(); + auto objBB = m2Factory.getObjectById<0>(m2ObjectId)->getAABB(); if (applyAdtChecks && !MathHelper::isAabbIntersect2d(objBB, adtBox2d)) continue; @@ -622,7 +622,7 @@ void MinimapGenerator::calcBB(const HMapRenderPlan &mapRenderPlan, mathfu::vec3 for (auto &adtObjectRes: mapRenderPlan->adtArray) { - auto adtObj = adtObjectRes->adtObject; + auto const &adtObj = adtObjectRes.adtObject; if (applyAdtChecks && (adtObj->getAdtX() != adt_x || adtObj->getAdtY() != adt_y)) { @@ -670,8 +670,8 @@ void MinimapGenerator::process() { if (cullStage == nullptr) continue; for (const auto &adtCullRes : cullStage->adtArray) { - if (adtCullRes->adtObject == nullptr) continue; - if (adtCullRes->adtObject->getLoadedStatus() == FileStatus::FSNotLoaded) { + if (adtCullRes.adtObject == nullptr) continue; + if (adtCullRes.adtObject->getLoadedStatus() == FileStatus::FSNotLoaded) { resetCandidate(); return; } diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 19f74a110..0125c7fcc 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -259,7 +259,7 @@ void FrontendUI::showCurrentStatsDialog() { int modelFdid = 0; std::string modelFileName = ""; if (mapPlan->m_currentWMO != emptyWMO) { - auto l_currentWmo = wmoFactory.getObjectById(mapPlan->m_currentWMO); + auto l_currentWmo = wmoFactory.getObjectById<0>(mapPlan->m_currentWMO); if (l_currentWmo != nullptr) { modelFdid = l_currentWmo->getModelFileId(); diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 8b7e17abe..67c0c671e 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -36,7 +36,7 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { private: HGDeviceVLK m_device; - std::shared_ptr> meshFactory = std::make_shared>(); + std::shared_ptr> meshFactory = std::make_shared>(); std::mt19937_64 eng; //Use the 64-bit Mersenne Twister 19937 generator //and seed it with entropy. diff --git a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert index 0b3337676..a5ac4d24b 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/forward/adtShader.vert @@ -61,7 +61,7 @@ void main() { vPosition = (scene.uLookAtMat * worldPoint).xyz; vNormal = normal; - vColor = aColor; + vColor = aColor.bgra; vVertexLighting = aVertexLighting.rgb; vMeshIndex = gl_InstanceIndex; diff --git a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert index 889605ab4..60df3d5d4 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert +++ b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.vert @@ -61,7 +61,7 @@ void main() { vPosition = (scene.uLookAtMat * worldPoint).xyz; vNormal = normal; - vColor = aColor; + vColor = aColor.bgra; vVertexLighting = aVertexLighting.rgb; vMeshIndex = gl_InstanceIndex; diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp index 2e61d19c8..6a0bc64db 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.cpp @@ -8,6 +8,7 @@ #include #include "../../gapi/interface/IDevice.h" +#include "../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" #include #include @@ -34,40 +35,63 @@ static inline uint8_t BitScanMSB2(uint32_t mask) } struct MemoryStoringPool { - MemoryStoringPool(size_t size) { - currentOffset = 0; + + MemoryStoringPool(size_t size) : m_Allocator(OffsetAllocator::Allocator(size)) { + data.resize(size); } - int currentOffset; - std::vector> data; -}; + bool isInThisRegion(void *p) { + bool biggerThanLowerBound = (((uintptr_t)p) > ((uintptr_t)data.data())); + bool lessThanHigherBound = ((((uintptr_t)p) - ((uintptr_t)data.data())) < data.size()); + return biggerThanLowerBound && lessThanHigherBound; + } + inline void * allocateFromMemPool(size_t size, int ®ionSize) { + void *ptr = nullptr; -std::array g_frameStackMutexes; -std::array>, 2*IDevice::MAX_FRAMES_IN_FLIGHT> g_frameStackList; + regionSize = data.size(); -inline void * allocateFromMemPool(size_t alignedSize, std::unique_ptr &frameRegion, int ®ionSize) { - void *ptr = nullptr; + OffsetAllocator::Allocation alloc = m_Allocator.allocate(size+16+sizeof(OffsetAllocator::Allocation)); + if (alloc.offset == OffsetAllocator::Allocation::NO_SPACE) { + return nullptr; + } - regionSize = frameRegion->data.size(); + ptr = &data[alloc.offset & (~15)]; + *(OffsetAllocator::Allocation *) &(((uint8_t*) ptr)[size]) = alloc; - bool isWithinBoundary = (frameRegion->currentOffset + ((alignedSize+16)) < regionSize); - if (isWithinBoundary) { - ptr = &frameRegion->data[frameRegion->currentOffset]; - frameRegion->currentOffset += alignedSize; + return ptr; } + void deallocate(void *ptr, size_t size) { + if (!this->isInThisRegion(ptr)) { + return; + } + + OffsetAllocator::Allocation alloc = *(OffsetAllocator::Allocation *) &(((uint8_t*) ptr)[size]); + m_Allocator.free(alloc); + } + + private: + OffsetAllocator::Allocator m_Allocator; + std::vector> data; +}; + + + +std::array g_frameStackMutexes; +std::mutex g_g_frameStackMutexes; +std::array>, 2*IDevice::MAX_FRAMES_IN_FLIGHT> g_frameStackList; + - return ptr; -} void * frameLinearAllocate(size_t size) { auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % (2 * IDevice::MAX_FRAMES_IN_FLIGHT); + std::lock_guard g_lock(g_g_frameStackMutexes); std::lock_guard lock(g_frameStackMutexes[currentFrame]); auto ¤t_list = g_frameStackList[currentFrame]; - size_t alignedSize = (size + 16) & (~15L); +// size_t alignedSize = (size + 16) & (~15L); void *ptr = nullptr; int regionSize = 2048; @@ -75,7 +99,7 @@ void * frameLinearAllocate(size_t size) { auto &memPoolRegion = current_list.front(); if (memPoolRegion) { - ptr = allocateFromMemPool(alignedSize, memPoolRegion, regionSize); + ptr = memPoolRegion->allocateFromMemPool(size, regionSize); } } if (ptr == nullptr) { @@ -83,7 +107,7 @@ void * frameLinearAllocate(size_t size) { size_t newSize = std::max(currentBufferSize * 2, 1 << (BitScanMSB2(currentBufferSize + size) + 1)); auto newPool = std::make_unique(newSize); - ptr = allocateFromMemPool(alignedSize, newPool, regionSize); + ptr = newPool->allocateFromMemPool(size, regionSize); current_list.push_front(std::move(newPool)); } @@ -94,12 +118,31 @@ void * frameLinearAllocate(size_t size) { return ptr; } +void frameDeAllocate(void *ptr, std::size_t n) { + auto currentFrame = IDevice::getCurrentProcessingFrameNumber() % (2 * IDevice::MAX_FRAMES_IN_FLIGHT); + + std::lock_guard g_lock(g_g_frameStackMutexes); + + for (auto &frameList : g_frameStackList) { + for (auto it = frameList.begin(); it != frameList.end(); ++it) { + auto ®ion = (*it); + if (region->isInThisRegion(ptr)) { + region->deallocate(ptr, n); + + return; + } + } + } + +// std::cout << "failed to deallocate" << std::endl; +}; + void allocatorBeginFrame(unsigned int frameNum) { auto currentFrame = frameNum % (2 * IDevice::MAX_FRAMES_IN_FLIGHT); std::lock_guard lock(g_frameStackMutexes[currentFrame]); if (!g_frameStackList[currentFrame].empty()) { g_frameStackList[currentFrame].resize(1); - g_frameStackList[currentFrame].front()->currentOffset = 0; } -} \ No newline at end of file +} + diff --git a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h index ccaa0b7ea..0a468f1f5 100644 --- a/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h +++ b/wowViewerLib/src/engine/custom_allocators/FrameBasedStackAllocator.h @@ -14,6 +14,7 @@ #include "tbb/scalable_allocator.h" void * frameLinearAllocate(size_t size); +void frameDeAllocate(void *p, size_t size); void allocatorBeginFrame(unsigned int frameNum); template @@ -44,7 +45,7 @@ struct FrameBasedStackAllocator void deallocate(T* p, std::size_t n) noexcept { // report(p, n, 0); -// frameDeAllocate(p); + frameDeAllocate(p, n * sizeof(T)); } private: // void report(T* p, std::size_t n, bool alloc = true) const diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index 7347b8182..e512c2e62 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -284,7 +284,7 @@ inline void calcTextureAnimationTransform( } -void AnimationManager::calcAnimMatrixes (std::vector &textAnimMatrices) { +void AnimationManager::calcAnimMatrixes (std::vector> &textAnimMatrices) { mathfu::vec4 pivotPoint(0.5, 0.5, 0, 0); mathfu::vec4 negatePivotPoint = -pivotPoint; @@ -382,7 +382,7 @@ void calcBoneBillboardMatrix( void AnimationManager::calcBoneMatrix( - std::vector &boneMatrices, + std::vector> &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix ) { @@ -650,7 +650,7 @@ AnimationManager::calcBoneMatrix( } void AnimationManager::calcChildBones( - std::vector &boneMatrices, + std::vector> &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix) { std::vector *childBones = &this->childBonesLookup[boneIndex]; @@ -669,7 +669,7 @@ std::string dumpMatrix(mathfu::mat4 &mat4) { std::to_string(mat4[12])+" "+std::to_string(mat4[13])+" "+std::to_string(mat4[14])+" "+std::to_string(mat4[15])+"\n"; } void AnimationManager::calcBones ( - std::vector &boneMatrices, + std::vector> &boneMatrices, const mathfu::mat4 &modelViewMatrix) { @@ -733,9 +733,9 @@ void AnimationManager::update( mathfu::vec3 &localRightVector, const mathfu::mat4 &modelMatrix, const mathfu::mat4 &modelViewMatrix, - std::vector &bonesMatrices, - std::vector &textAnimMatrices, - std::vector &subMeshColors, + std::vector> &bonesMatrices, + std::vector> &textAnimMatrices, + std::vector> &subMeshColors, std::vector &transparencies, std::vector &lights, std::vector> &particleEmitters, @@ -946,7 +946,7 @@ void AnimationManager::update( this->animationInfo.currentAnimation.firstUpdate = false; } -void AnimationManager::calcSubMeshColors(std::vector &subMeshColors) { +void AnimationManager::calcSubMeshColors(std::vector> &subMeshColors) { M2Array &colors = boneMasterData->getM2Geom()->getM2Data()->colors; auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; @@ -1001,7 +1001,7 @@ void AnimationManager::calcTransparencies(std::vector &transparencies) { } -void AnimationManager::calcLights(std::vector &lights, const std::vector &bonesMatrices, const mathfu::mat4 &modelMatrix) { +void AnimationManager::calcLights(std::vector &lights, const std::vector> &bonesMatrices, const mathfu::mat4 &modelMatrix) { auto &lightRecords = boneMasterData->getM2Geom()->getM2Data()->lights; auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; @@ -1211,7 +1211,7 @@ void AnimationManager::calcCamera(M2CameraResult &camera, int cameraId, mathfu:: } void AnimationManager::calcParticleEmitters(const std::vector> &particleEmitters, - std::vector &bonesMatrices) { + std::vector> &bonesMatrices) { auto &peRecords = boneMasterData->getM2Geom()->getM2Data()->particle_emitters; if (peRecords.size <= 0) return; diff --git a/wowViewerLib/src/engine/managers/animationManager.h b/wowViewerLib/src/engine/managers/animationManager.h index b98b21f2b..ddb1cb8b1 100644 --- a/wowViewerLib/src/engine/managers/animationManager.h +++ b/wowViewerLib/src/engine/managers/animationManager.h @@ -42,7 +42,7 @@ class AnimationManager { void initGlobalSequenceTimes(); void calculateBoneTree(); - void calcAnimMatrixes (std::vector &textAnimMatrices); + void calcAnimMatrixes (std::vector> &textAnimMatrices); void calcAnimRepetition(AnimationStruct &animationStruct); public: @@ -60,9 +60,9 @@ class AnimationManager { mathfu::vec3 &localRightVector, const mathfu::mat4 &modelMatrix, const mathfu::mat4 &modelViewMatrix, - std::vector &bonesMatrices, - std::vector &textAnimMatrices, - std::vector &subMeshColors, + std::vector> &bonesMatrices, + std::vector> &textAnimMatrices, + std::vector> &subMeshColors, std::vector &transparencies, std::vector &lights, std::vector> &particleEmitters, @@ -70,13 +70,13 @@ class AnimationManager { /*cameraDetails, particleEmitters*/); - void calcBones(std::vector &boneMatrices, const mathfu::mat4 &modelViewMatrix); + void calcBones(std::vector> &boneMatrices, const mathfu::mat4 &modelViewMatrix); - void calcBoneMatrix(std::vector &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix); + void calcBoneMatrix(std::vector> &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix); - void calcChildBones(std::vector &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix); + void calcChildBones(std::vector> &boneMatrices, int boneIndex, const mathfu::mat4 &modelViewMatrix); - void calcSubMeshColors(std::vector &subMeshColors); + void calcSubMeshColors(std::vector> &subMeshColors); void calcTransparencies(std::vector &transparencies); @@ -94,11 +94,11 @@ class AnimationManager { } void calcLights(std::vector &lights, - const std::vector &bonesMatrices, + const std::vector> &bonesMatrices, const mathfu::mat4 &modelMatrix); void calcParticleEmitters( const std::vector> &particleEmitters, - std::vector &bonesMatrices); + std::vector> &bonesMatrices); void calcRibbonEmitters(std::vector> &ribbonEmitters); diff --git a/wowViewerLib/src/engine/objects/SceneObjectWithID.h b/wowViewerLib/src/engine/objects/SceneObjectWithID.h index 912750321..92d7a63f2 100644 --- a/wowViewerLib/src/engine/objects/SceneObjectWithID.h +++ b/wowViewerLib/src/engine/objects/SceneObjectWithID.h @@ -7,7 +7,7 @@ template class ObjectWithId { - template friend class EntityFactory; + template friend class EntityFactory; public: ObjectWithId() { diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index c2be89440..eac41b354 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -84,7 +84,7 @@ void GeneralView::addM2FromGroups(const MathHelper::FrustumCullingData &frustumD for (int i = 0; i < candCullRes.size(); i++) { if (!candCullRes[i]) { - const auto m2ObjectCandidate = m2Factory.getObjectById(candidatesArr[i]); + const auto m2ObjectCandidate = m2Factory.getObjectById<0>(candidatesArr[i]); setM2Lights(m2ObjectCandidate); if (m2ObjectCandidate != nullptr) this->m2List.addToDraw(m2ObjectCandidate); diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 1ad39c3a8..49c6464d2 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -24,7 +24,6 @@ typedef std::shared_ptr HExteriorView; class ADTObjRenderRes { public: std::shared_ptr adtObject; - bool wasLoaded = false; std::array drawChunk = {false}; std::array drawWaterChunk = {false}; std::array checkRefs = {false}; @@ -75,8 +74,7 @@ class InteriorView : public GeneralView { class ExteriorView : public GeneralView { public: - std::vector> drawnADTs = {}; - std::vector m_adtOpaqueMeshes = {}; + std::vector m_adtOpaqueMeshes = {}; public: void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) override; }; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index ebdf3f38a..06d91eab2 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -45,16 +45,21 @@ void AdtObject::loadM2s() { int32_t length = m_adtFileObj->doodadDef_len; //1. Load non-lod objectLods[0].m2Objects = std::vector>(length, nullptr); + objectLods[0].m2ObjectIds = std::vector(length); for (int j = 0, i = offset; i < offset+length; i++, j++) { SMDoodadDef &doodadDef = m_adtFileObj->doodadDef[i]; if (doodadDef.flags.mddf_entry_is_filedata_id) { //2. Get model int fileDataId = doodadDef.nameId; - objectLods[0].m2Objects[i] = m_mapApi->getM2Object(fileDataId, doodadDef); + auto m2Object = m_mapApi->getM2Object(fileDataId, doodadDef); + objectLods[0].m2Objects[i] = m2Object; + objectLods[0].m2ObjectIds[i] = m2Object->getObjectId(); } else { std::string fileName = &m_adtFileObj->doodadNamesField[m_adtFileObj->mmid[doodadDef.nameId]]; //2. Get model - objectLods[0].m2Objects[i] = m_mapApi->getM2Object(fileName, doodadDef); + auto m2Object =m_mapApi->getM2Object(fileName, doodadDef); + objectLods[0].m2Objects[i] = m2Object; + objectLods[0].m2ObjectIds[i] = m2Object->getObjectId(); } } @@ -68,17 +73,22 @@ void AdtObject::loadM2s() { length = 0; }; objectLods[1].m2Objects = std::vector>(length, nullptr); + objectLods[1].m2ObjectIds = std::vector(length); for (int j = 0, i = offset; i < offset+length; i++, j++) { //1. Get filename SMDoodadDef &doodadDef = m_adtFileObjLod->doodadDefObj1[i]; if (doodadDef.flags.mddf_entry_is_filedata_id == 1) { //2. Get model int fileDataId = doodadDef.nameId; - objectLods[1].m2Objects[i] = m_mapApi->getM2Object(fileDataId, doodadDef); + auto m2Object = m_mapApi->getM2Object(fileDataId, doodadDef); + objectLods[1].m2Objects[i] = m2Object; + objectLods[1].m2ObjectIds[i] = m2Object->getObjectId(); } else { std::string fileName = &m_adtFileObj->doodadNamesField[m_adtFileObj->mmid[doodadDef.nameId]]; //2. Get model - objectLods[1].m2Objects[i] = m_mapApi->getM2Object(fileName, doodadDef); + auto m2Object = m_mapApi->getM2Object(fileName, doodadDef); + objectLods[0].m2Objects[i] = m2Object; + objectLods[0].m2ObjectIds[i] = m2Object->getObjectId(); } } } @@ -90,6 +100,7 @@ void AdtObject::loadWmos() { //1. Load non lod objectLods[0].wmoObjects = std::vector>(length, nullptr); + objectLods[0].wmoObjectIds = std::vector(length, emptyWMO); for (int j = 0, i = offset; i < offset + length; i++, j++) { //1. Get filename @@ -97,10 +108,14 @@ void AdtObject::loadWmos() { if (!mapDef.flags.modf_entry_is_filedata_id) { std::string fileName; fileName = &m_adtFileObj->wmoNamesField[m_adtFileObj->mwid[mapDef.nameId]]; - objectLods[0].wmoObjects[j] = m_mapApi->getWmoObject(fileName, mapDef); + auto wmoObject = m_mapApi->getWmoObject(fileName, mapDef); + objectLods[0].wmoObjects[j] = wmoObject; + objectLods[0].wmoObjectIds[j] = wmoObject->getObjectId(); } else { uint32_t fileDataId = mapDef.nameId; - objectLods[0].wmoObjects[j] = m_mapApi->getWmoObject(fileDataId, mapDef); + auto wmoObject = m_mapApi->getWmoObject(fileDataId, mapDef); + objectLods[0].wmoObjects[j] = wmoObject; + objectLods[0].wmoObjectIds[j] = wmoObject->getObjectId(); } // std::cout << "wmo filename = "<< fileName << std::endl; } @@ -116,16 +131,23 @@ void AdtObject::loadWmos() { length = 0; } objectLods[1].wmoObjects = std::vector>(length, nullptr); + objectLods[1].wmoObjectIds = std::vector(length, emptyWMO); for (int j = 0, i = offset; i < offset + length; i++, j++) { //Load Lods std::string fileName; auto &mapDefLod = m_adtFileObjLod->mapObjDefObj1[i]; if (mapDefLod.flags.modf_entry_is_filedata_id == 0) { fileName = &m_adtFileObj->wmoNamesField[m_adtFileObj->mwid[mapDefLod.nameId]]; - objectLods[1].wmoObjects[j] = m_mapApi->getWmoObject(fileName, mapDefLod); + + auto wmoObject = m_mapApi->getWmoObject(fileName, mapDefLod); + objectLods[1].wmoObjects[j] = wmoObject; + objectLods[1].wmoObjectIds[j] = wmoObject->getObjectId(); } else { uint32_t fileDataId = mapDefLod.nameId; - objectLods[1].wmoObjects[j] = m_mapApi->getWmoObject(fileDataId, mapDefLod); + + auto wmoObject = m_mapApi->getWmoObject(fileDataId, mapDefLod); + objectLods[1].wmoObjects[j] = wmoObject; + objectLods[1].wmoObjectIds[j] = wmoObject->getObjectId(); } } } @@ -165,7 +187,7 @@ void AdtObject::loadWater(const HMapSceneBufferCreate &sceneRenderer ) { for (int layerInd = 0; layerInd < liquidChunk.layer_count; layerInd++) { SMLiquidInstance &liquidInstance = liquidInstPtr[layerInd]; - auto l_liquidInstance = std::make_shared( + auto l_liquidInstance = liquidInstanceFactory.createObject( m_api, sceneRenderer, liquidInstance, m_waterPlacementChunk, liquidBasePos, m_adtFile->mH2OBlob, waterTileAabb[i] @@ -571,8 +593,6 @@ void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaq if (!m_loaded) return; - adtRes.wasLoaded = true; - size_t meshCount = adtMeshes.size(); opaqueMeshes.reserve(opaqueMeshes.size() + adtMeshes.size()); transparentMeshes.reserve(transparentMeshes.size() + m_liquidInstancesPerChunk.size()); @@ -1030,8 +1050,8 @@ AdtObject::checkWmoGlobally(int lodLevel, M2ObjectListContainer &m2ObjectsCandid int x_len, int y_len) { if (lodLevel >= 4) { - for (auto const &m2Object : objectLods[0].m2Objects) - m2ObjectsCandidates.addCandidate(m2Object); + for (auto const &m2ObjectId : objectLods[0].m2ObjectIds) + m2ObjectsCandidates.addCandidate(m2ObjectId); } else { for (auto const &m2Object: objectLods[1].m2Objects) { m2ObjectsCandidates.addCandidate(m2Object); @@ -1325,3 +1345,5 @@ void AdtObject::createIBOAndBinding(const HMapSceneBufferCreate &sceneRenderer) m_holesIgnored = m_api->getConfig()->ignoreADTHoles; } + +EntityFactory<50, AdtObjectId, AdtObject> adtObjectFactory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index 54ff7c250..b68ca4d6e 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -25,7 +25,10 @@ class M2Object; typedef std::function FreeStrategy; -class AdtObject { +class AdtObject; +enum class AdtObjectId : int; +extern EntityFactory<50, AdtObjectId, AdtObject> adtObjectFactory; +class AdtObject : public ObjectWithId { public: AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, HWdtFile wdtfile); AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDataIDs &fileDataIDs, HWdtFile wdtfile); @@ -161,6 +164,9 @@ class AdtObject { struct lodLevels { std::vector> m2Objects; std::vector> wmoObjects; + + std::vector m2ObjectIds; + std::vector wmoObjectIds; }; std::array objectLods; diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp index bfb02cc7f..181121426 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.cpp @@ -313,4 +313,6 @@ mathfu::mat4 LiquidInstance::GetTexScrollMtx(int time, mathfu::vec2 scrollVec) { } return mathfu::mat4::FromTranslationVector(mathfu::vec3(scrollX, scrollY, 0.0f)); -} \ No newline at end of file +} + +EntityFactory<1000, LiquidInstId, LiquidInstance> liquidInstanceFactory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index d13491cc9..27fee2d31 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -9,8 +9,14 @@ class IMapApi; #include "../../ApiContainer.h" #include "../../custom_allocators/FrameBasedStackAllocator.h" +#include "../scenes/EntityActorsFactory.h" -class LiquidInstance { +class LiquidInstance; + +enum class LiquidInstId : int; +extern EntityFactory<1000, LiquidInstId, LiquidInstance> liquidInstanceFactory; + +class LiquidInstance : public ObjectWithId { public: LiquidInstance(const HApiContainer &api, const HMapSceneBufferCreate &sceneRenderer, diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/CBoneMasterData.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/CBoneMasterData.h index 91fed577c..86583edda 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/CBoneMasterData.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/CBoneMasterData.h @@ -44,7 +44,7 @@ class CBoneMasterData { } } - HM2Geom getM2Geom() { + const HM2Geom &getM2Geom() { return m_m2Geom; } diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index b2da35357..aa7d2daf2 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -152,7 +152,7 @@ void M2MeshBufferUpdater::getTextureMatrixIndexes(const M2Object &m2Object, int mathfu::vec4 M2MeshBufferUpdater::getCombinedColor( M2SkinProfile *skinData, int batchIndex, - const std::vector &subMeshColors + const std::vector> &subMeshColors ) { int colorIndex = skinData->batches[batchIndex]->colorIndex; mathfu::vec4 submeshColor = mathfu::vec4(1,1,1,1); diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index 8c61070b9..e30933f7b 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -26,7 +26,7 @@ class M2MeshBufferUpdater { static void getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, const M2SkinProfile *m2SkinProfile, std::array &o_textureMatIndexes); - static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector &subMeshColors) ; + static mathfu::vec4 getCombinedColor(M2SkinProfile *skinData, int batchIndex, const std::vector> &subMeshColors) ; static float getTextureWeight(M2SkinProfile *skinData, M2Data *m2data, int batchIndex, int textureIndex, const std::vector &transparencies) ; static void fillTextureMatrices(const M2Object &m2Object, int batchIndex, M2Data *m2Data, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index a480096ce..2d39e7f4c 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -537,7 +537,7 @@ void M2Object::createAABB() { CAaBox worldAABB = MathHelper::transformAABBWithMat4(m_placementMatrix, minVec, maxVec); - this->aabb = worldAABB; + *this->aabb = worldAABB; } @@ -551,7 +551,7 @@ void M2Object::createAABB() { CAaBox worldAABB = MathHelper::transformAABBWithMat4(m_placementMatrix, minVec, maxVec); //this.diameter = vec3.distance(worldAABB[0],worldAABB[1]); - this->aabb = worldAABB; + *this->aabb = worldAABB; } { @@ -565,7 +565,7 @@ void M2Object::createAABB() { //this.diameter = vec3.distance(worldAABB[0],worldAABB[1]); this->colissionAabb = worldAABB; } - m_hasAABB = true; + status->m_hasAABB = true; } @@ -666,7 +666,7 @@ void M2Object::createPlacementMatrix (mathfu::vec3 pos, float f, mathfu::vec3 sc } void M2Object::updatePlacementMatrixFromParentAttachment(M2Object *parent, int attachment, float scale) { - if (!parent->m_loaded) return; + if (!parent->status->m_loaded) return; auto &m2Geom = parent->m_m2Geom; if (m2Geom->m_m2Data->attachment_lookup_table.size == 0) return; if (m2Geom->m_m2Data->attachments.size == 0) return; @@ -704,7 +704,8 @@ float M2Object::getCurrentDistance() { return m_currentDistance; } float M2Object::getHeight(){ - return this->aabb.max.z -this->aabb.min.z; + const auto &aabb = *this->aabb; + return aabb.max.z -aabb.min.z; } uint8_t miniLogic(const CImVector *a2) { @@ -766,11 +767,14 @@ void M2Object::setLoadParams (int skinNum, std::vector meshIds, std::ve this->m_skinNum = skinNum; this->m_meshIds = meshIds; this->m_replaceTextures = replaceTextures; + this->aabb = m2Factory.getObjectById<1>(this->getObjectId()); + this->status = m2Factory.getObjectById<2>(this->getObjectId()); + *this->status = M2LoadedStatus(); } void M2Object::startLoading() { - if (!m_loading) { - m_loading = true; + if (!status->m_loading) { + status->m_loading = true; Cache *m2GeomCache = m_api->cacheStorage->getM2GeomCache(); if (!useFileId) { @@ -782,7 +786,7 @@ void M2Object::startLoading() { } void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) { - if (!m_loaded) return; + if (!status->m_loaded) return; M2Data * m2File = this->m_m2Geom->getM2Data(); M2SkinProfile * skinData = this->m_skinGeom->getSkinData(); @@ -847,7 +851,7 @@ void M2Object::debugDumpAnimationSequences() { } void M2Object::doLoadMainFile(){ - if (!this->m_loaded && !this->m_loading) { + if (!this->status->m_loaded && !this->status->m_loading) { this->startLoading(); } @@ -858,7 +862,7 @@ void M2Object::doLoadMainFile(){ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ //0. If loading procedures were already done - exit - if (this->m_loaded) return; + if (this->status->m_loaded) return; //1. Check if .m2 files is loaded if (m_m2Geom == nullptr) return; @@ -916,9 +920,9 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ this->initRibbonEmitters(sceneRenderer); - this->m_loaded = true; - this->m_geomLoaded = true; - this->m_loading = false; + this->status->m_loaded = true; + this->status->m_geomLoaded = true; + this->status->m_loading = false; for ( auto &item : m_postLoadEvents) { item(); @@ -930,7 +934,7 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ //deltaTime = miliseconds void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat) { - if (!this->m_loaded) return; + if (!this->status->m_loaded) return; m_postLoadEvents.clear(); @@ -984,7 +988,7 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v mathfu::vec4(mathfu::vec3(bounds.extent.min), 1.0f), mathfu::vec4(mathfu::vec3(bounds.extent.max), 1.0f)); - this->aabb = worldAABB; + *this->aabb = worldAABB; } @@ -1074,7 +1078,7 @@ void M2Object::fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sc } void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { - if (!this->m_loaded) return; + if (!this->status->m_loaded) return; // mathfu::mat4 modelViewMat = viewMat * m_placementMatrix; @@ -1172,7 +1176,7 @@ bool M2Object::isMainDataLoaded() const { } const bool M2Object::checkFrustumCulling (const mathfu::vec4 &cameraPos, const MathHelper::FrustumCullingData &frustumData) { - if (!this->m_hasAABB) { + if (!this->status->m_hasAABB) { if (!this->isMainDataLoaded()) return false; if (m_m2Geom != nullptr) { @@ -1189,7 +1193,7 @@ const bool M2Object::checkFrustumCulling (const mathfu::vec4 &cameraPos, const M return true; } - CAaBox &aabb = this->aabb; + CAaBox &aabb = *this->aabb; //1. Check if camera position is inside Bounding Box if ( @@ -1280,10 +1284,10 @@ void M2Object::drawBBInternal(CAaBox &bb, mathfu::vec3 &color, mathfu::mat4 &pla } void M2Object::drawBB(mathfu::vec3 &color) { - if (!this->m_loaded) return; + if (!this->status->m_loaded) return; mathfu::mat4 defMat = mathfu::mat4::Identity(); - drawBBInternal(this->aabb, color, defMat); + drawBBInternal(*this->aabb, color, defMat); } @@ -1673,7 +1677,7 @@ M2Object::createSingleMesh(const HMapSceneBufferCreate &sceneRenderer, int index } void M2Object::collectMeshes(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes) { - if (!this->m_loaded) return; + if (!this->status->m_loaded) return; M2SkinProfile* skinData = this->m_skinGeom->getSkinData(); @@ -1749,16 +1753,16 @@ void M2Object::initAnimationManager() { void M2Object::initBoneAnimMatrices() { ZoneScoped; auto &bones = *m_boneMasterData->getSkelData()->m_m2CompBones; - this->bonesMatrices = std::vector(bones.size, mathfu::mat4::Identity());; + this->bonesMatrices = std::vector>(bones.size, mathfu::mat4::Identity());; } void M2Object::initTextAnimMatrices() { ZoneScoped; - textAnimMatrices = std::vector(m_m2Geom->getM2Data()->texture_transforms.size, mathfu::mat4::Identity());; + textAnimMatrices = std::vector>(m_m2Geom->getM2Data()->texture_transforms.size, mathfu::mat4::Identity());; } void M2Object::initSubmeshColors() { ZoneScoped; - subMeshColors = std::vector(m_m2Geom->getM2Data()->colors.size); + subMeshColors = std::vector>(m_m2Geom->getM2Data()->colors.size); } void M2Object::initTransparencies() { @@ -1858,12 +1862,12 @@ void M2Object::setModelFileId(int fileId) { } void M2Object::setAnimationId(int animationId) { - if (!m_loaded) return; + if (!status->m_loaded) return; m_animationManager->setAnimationId(animationId, false); } void M2Object::resetCurrentAnimation() { - if (!m_loaded) return; + if (!status->m_loaded) return; m_animationManager->resetCurrentAnimation(); } @@ -1952,7 +1956,7 @@ int32_t M2Object::getTextureTransformIndexByLookup(int textureTrasformlookup) { } void M2Object::drawParticles(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder) { - if (!this->m_loaded) return; + if (!this->status->m_loaded) return; // for (int i = 0; i< std::min((int)particleEmitters.size(), 10); i++) { int minParticle = m_api->getConfig()->minParticle; @@ -2095,14 +2099,14 @@ void M2Object::updateDynamicMeshes() { void M2Object::setReplaceTextures(const HMapSceneBufferCreate &sceneRenderer, const std::vector &replaceTextures) { m_replaceTextures = replaceTextures; - if (m_loaded) { + if (status->m_loaded) { createMeshes(sceneRenderer); // recreate meshes } } void M2Object::setMeshIds(const HMapSceneBufferCreate &sceneRenderer, const std::vector &meshIds) { m_meshIds = meshIds; - if (m_loaded) { + if (status->m_loaded) { createMeshes(sceneRenderer); // recreate meshes } } @@ -2130,4 +2134,4 @@ int M2Object::getCurrentAnimationIndex() { return m_animationManager->getCurrentAnimationIndex(); } -EntityFactory m2Factory; \ No newline at end of file +EntityFactory<10000, M2ObjId, M2Object, CAaBox, M2LoadedStatus> m2Factory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index 96c75d07a..e34ce069a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -26,15 +26,28 @@ class M2ObjectListContainer; #include "../../ApiContainer.h" #include "m2Helpers/CBoneMasterData.h" #include "../../../gapi/UniformBufferStructures.h" +#include "../scenes/EntityActorsFactory.h" + enum class M2ObjId : int; + +struct M2LoadedStatus { + bool m_loading = false; + bool m_loaded = false; + bool m_geomLoaded = false; + bool m_hasAABB = false; +}; + +extern EntityFactory<10000, M2ObjId, M2Object, CAaBox, M2LoadedStatus> m2Factory; + class M2Object : public ObjectWithId { public: friend class IExporter; M2Object(HApiContainer &api, bool isSkybox = false, bool overrideSkyModelMat = true) : m_api(api), m_m2Geom(nullptr), m_skinGeom(nullptr), m_animationManager(nullptr), m_boolSkybox(isSkybox), m_overrideSkyModelMat(overrideSkyModelMat) - { + { + } ~M2Object(); @@ -42,22 +55,20 @@ class M2Object : public ObjectWithId { friend class M2MeshBufferUpdater; private: void createAABB(); - bool m_loading = false; - bool m_loaded = false; - bool m_geomLoaded = false; - bool m_hasAABB = false; - bool m_alwaysDraw = false; + M2LoadedStatus *status; + bool m_alwaysDraw = false; - void load(std::string modelName, SMODoodadDef &doodadDef, mathfu::mat4 &wmoPlacementMat){ - createPlacementMatrix(doodadDef, wmoPlacementMat); - calcWorldPosition(); - this->setLoadParams(0, {}, {}); - this->setModelFileName(modelName); - } +// void load(std::string modelName, SMODoodadDef &doodadDef, mathfu::mat4 &wmoPlacementMat){ +// createPlacementMatrix(doodadDef, wmoPlacementMat); +// calcWorldPosition(); +// +// this->setLoadParams(0, {}, {}); +// this->setModelFileName(modelName); +// } struct dynamicVaoMeshFrame { int batchIndex = -1; @@ -77,7 +88,7 @@ class M2Object : public ObjectWithId { float m_currentDistance = 0; - CAaBox aabb; + CAaBox *aabb; CAaBox colissionAabb; HApiContainer m_api = nullptr; @@ -122,10 +133,10 @@ class M2Object : public ObjectWithId { bool particleColorReplacementIsSet = false; std::array, 3> m_particleColorReplacement; - - std::vector bonesMatrices; - std::vector textAnimMatrices; - std::vector subMeshColors; + std::unique_ptr m_animationManager; + std::vector> bonesMatrices; + std::vector> textAnimMatrices; + std::vector> subMeshColors; std::vector transparencies; std::vector lights; std::vector> particleEmitters; @@ -143,7 +154,6 @@ class M2Object : public ObjectWithId { //TODO: think about if it's viable to do forced transp for dyn meshes std::vector> dynamicMeshes; - std::unique_ptr m_animationManager; bool m_interiorAmbientWasSet = false; // For static only bool m_boolSkybox = false; @@ -194,8 +204,8 @@ class M2Object : public ObjectWithId { m_postLoadEvents.push_back(value); } - const CAaBox &getAABB() { return aabb; }; - CAaBox getColissionAABB();; + const CAaBox &getAABB() { return *aabb; }; + CAaBox getColissionAABB(); void setLoadParams(int skinNum, std::vector meshIds, std::vector replaceTextures); @@ -241,7 +251,7 @@ class M2Object : public ObjectWithId { void getMeshIds(std::vector &meshIdList); mathfu::mat4 getTextureTransformByLookup(int textureTrasformlookup); int32_t getTextureTransformIndexByLookup(int textureTrasformlookup); - bool getGetIsLoaded() { return m_loaded; }; + bool getGetIsLoaded() { return status->m_loaded; }; mathfu::mat4 getModelMatrix() { return m_placementMatrix; }; bool prepearMaterial(M2MaterialTemplate &materialTemplate, int batchIndex); @@ -262,7 +272,7 @@ class M2Object : public ObjectWithId { const MathHelper::FrustumCullingData &frustumData); bool isMainDataLoaded() const; - bool getHasBoundingBox() const {return m_hasAABB;} + bool getHasBoundingBox() const {return status->m_hasAABB;} void doLoadMainFile(); void doLoadGeom(const HMapSceneBufferCreate &sceneRenderer); @@ -314,9 +324,8 @@ class M2Object : public ObjectWithId { #include "../../algorithms/mathHelper.h" #include "../../../engine/custom_allocators/FrameBasedStackAllocator.h" -#include "../scenes/EntityActorsFactory.h" -extern EntityFactory m2Factory; + template<> inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { @@ -325,7 +334,7 @@ inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { template<> inline const CAaBox &retrieveAABB<>(const M2ObjId &objectId) { - return m2Factory.getObjectById(objectId)->getAABB(); + return *m2Factory.getObjectById<1>(objectId); } @@ -382,6 +391,20 @@ using m2Container = framebased::vector; } } + inline void addCandidate(const M2ObjId &cand) { +// if (m_locked) { +// throw "oops"; +// } + auto status = m2Factory.getObjectById<2>(cand); + if (status->m_hasAABB) { + candidates.push_back(cand); + candCanHaveDuplicates = true; + } else { + toLoadMain.push_back(cand); + toLoadMainCanHaveDuplicates = true; + } + } + void addToDraw(const std::shared_ptr &toDraw) { if (m_locked) { throw "oops"; @@ -399,6 +422,29 @@ using m2Container = framebased::vector; } } + void addToDraw(const M2ObjId &toDrawId) { + if (m_locked) { + throw "oops"; + } + + auto status = m2Factory.getObjectById<2>(toDrawId); + if (status->m_loaded) { + drawn.push_back(toDrawId); + drawnCanHaveDuplicates = true; + } else { + auto toDraw = m2Factory.getObjectById<0>(toDrawId); + if (!toDraw->isMainDataLoaded()) { + toLoadMain.push_back(toDrawId); + toLoadMainCanHaveDuplicates = true; + } else { + toLoadGeom.push_back(toDrawId); + toLoadGeomCanHaveDuplicates = true; + } + } + } + + + void addToDraw(M2Object * toDraw) { if (m_locked) { throw "oops"; diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp index 937497f44..300bef3ed 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.cpp @@ -3,3 +3,42 @@ // #include "EntityActorsFactory.h" +#include "../../../gapi/interface/IDevice.h" + +#include +#include + +struct EntityDeallocationRecord { + unsigned int frameNumberToDoAt; + std::function callback; +}; + +std::mutex m_listOfEntityDeallocatorsAccessMtx; +std::list listOfEntityDeallocators; + +void addEntityDeallocationRecord(std::function callback) { + std::lock_guard lock(m_listOfEntityDeallocatorsAccessMtx); + EntityDeallocationRecord dr; + dr.frameNumberToDoAt = IDevice::getCurrentProcessingFrameNumber() + IDevice::MAX_FRAMES_IN_FLIGHT+1; + dr.callback = callback; + listOfEntityDeallocators.push_back(dr); +}; + +void executeEntityDeallocators() { + std::unique_lock lock(m_listOfEntityDeallocatorsAccessMtx, std::defer_lock); + + lock.lock(); + auto m_frameNumber = IDevice::getCurrentProcessingFrameNumber(); + while ((!listOfEntityDeallocators.empty()) && (listOfEntityDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { + auto stuff = listOfEntityDeallocators.front(); + + if (stuff.callback != nullptr) { + lock.unlock(); + stuff.callback(); + lock.lock(); + } + + listOfEntityDeallocators.pop_front(); + } + lock.unlock(); +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index f33123fbb..4655d6375 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -6,73 +6,166 @@ #define AWEBWOWVIEWERCPP_ENTITYACTORSFACTORY_H #include +#include #include #include "../../../../3rdparty/OffsetAllocator/offsetAllocator.hpp" -#include "memoryPool/MemoryPool.h" +void addEntityDeallocationRecord(std::function callback); +void executeEntityDeallocators(); -template + +namespace EntityMemoryPool { + + template + class EttMemoryPool; + + template + class EttMemoryPool : public EttMemoryPool + { + static constexpr int BlockSizeInBytes = MemoryBlockSize * sizeof(T); + public: + EttMemoryPool() : EttMemoryPool() + { + } + inline T * getPtrFromOffset(int offset) const { + auto blockIndex = offset / MemoryBlockSize; + auto blockOffset = (offset % MemoryBlockSize); + auto byteOffset = blockOffset * sizeof(T); + + if (blockIndex > objectPools.size()) + return nullptr; + + auto &objectPool = objectPools[blockIndex]; + if (byteOffset >= objectPool.size()) + return nullptr; + + return (T *)&objectPools[blockIndex][byteOffset]; + } + void expand() { + objectPools.emplace_back().resize(BlockSizeInBytes); + EttMemoryPool::expand(); + } + + typedef T value_type; + private: + std::vector> objectPools; + }; + template + class EttMemoryPool + { + public: + void expand(){}; + }; +} + + +template class EntityFactory { -static constexpr int initSize = 1000; -static constexpr int BlockSize = sizeof(T)*5000; -MemoryPool pool; + + + static constexpr int ComponentAmount = sizeof...(Types); + + + + template + struct EttMemoryPoolGetter + { + using return_type = typename EttMemoryPoolGetter::return_type; + static const return_type &get(const EntityMemoryPool::EttMemoryPool &t) + { + return EttMemoryPoolGetter::get(t); + } + }; + template + struct EttMemoryPoolGetter<0, Head, Args...> + { + using return_type = EntityMemoryPool::EttMemoryPool; + static const return_type &get(const EntityMemoryPool::EttMemoryPool &t) + { + return t; + } + }; + + EntityMemoryPool::EttMemoryPool m_combinedMemoryPool; + + template + const typename EttMemoryPoolGetter::return_type & + getMemoryPool() + { + return EttMemoryPoolGetter::get(m_combinedMemoryPool); + } + + public: explicit EntityFactory() { - objectCache.resize(initSize); + m_combinedMemoryPool.expand(); }; + + template + typename EttMemoryPoolGetter::return_type::value_type * + getPtrFromOffset(int offset) + { + return getMemoryPool().getPtrFromOffset(offset); + } + +// inline T * getPtrFromOffset(int offset) { +// auto blockIndex = offset / BlockSize; +// auto blockOffset = (offset % BlockSize); +// return (T *)&objectPools[blockIndex][blockOffset * sizeof(T)]; +// } + template - std::shared_ptr createObject(_Args&&... __args) { + std::shared_ptr createObject(_Args&&... __args) { OffsetAllocator::Allocation offsetData; - T * entity = nullptr; + MainClass * entity = nullptr; { std::unique_lock lock(m_mutex); offsetData = allocator.allocate(1); if (offsetData.offset == OffsetAllocator::Allocation::NO_SPACE) { - constexpr int growSize = 1000; + allocator.growSize(MemoryBlockSize); + m_combinedMemoryPool.expand(); - allocator.growSize(growSize); offsetData = allocator.allocate(1); - objectCache.resize(objectCache.size() + growSize); } - auto ptr = pool.allocate(); + auto const offset = offsetData.offset; + auto ptr = getPtrFromOffset<0>(offset); - entity = new(ptr) T(std::forward(__args)...); + entity = new(ptr) MainClass(std::forward(__args)...); entity->setId((ObjIdType)offsetData.offset); - objectCache[offsetData.offset] = entity; } auto l_this = this; - return std::shared_ptr(entity, [offsetData, l_this, entity](T *ls) -> void { - l_this->deallocate(offsetData); + return std::shared_ptr(entity, [offsetData, l_this](MainClass *ls) -> void { + addEntityDeallocationRecord([offsetData, l_this]() { + l_this->deallocate(offsetData); + }); }); } - T * getObjectById(ObjIdType id) { + template + typename EttMemoryPoolGetter::return_type::value_type * + getObjectById(ObjIdType id) { int index = (int)id; - if ((index < 0) || (index >= ((int)objectCache.size()))) + if ((index < 0)) return nullptr; - return objectCache[(int)id]; + return getPtrFromOffset((int)id); } void deallocate(const OffsetAllocator::Allocation &alloc) { std::unique_lock lock(m_mutex); - objectCache[alloc.offset]->~T(); - pool.deallocate(objectCache[alloc.offset]); - - objectCache[alloc.offset] = nullptr; + getPtrFromOffset<0>(alloc.offset)->~MainClass(); allocator.free(alloc); } private: std::mutex m_mutex; - OffsetAllocator::Allocator allocator = OffsetAllocator::Allocator(initSize); - std::vector objectCache; + OffsetAllocator::Allocator allocator = OffsetAllocator::Allocator(MemoryBlockSize); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index ee862b532..d0fac607a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -384,7 +384,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams for (auto &wmoId: potentialWmo.getCandidates()) { WmoGroupResult groupResult; - auto checkingWmoObj = wmoFactory.getObjectById(wmoId); + auto checkingWmoObj = wmoFactory.getObjectById<0>(wmoId); if (checkingWmoObj == nullptr) continue; bool result = checkingWmoObj->getGroupWmoThatCameraIsInside(camera4, groupResult); @@ -414,7 +414,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams AreaRecord wmoAreaRecord; bool wmoAreaFound = false; if (mapRenderPlan->m_currentWMO != emptyWMO) { - auto l_currentWmoObject = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); + auto l_currentWmoObject = wmoFactory.getObjectById<0>(mapRenderPlan->m_currentWMO); if (l_currentWmoObject != nullptr) { auto nameId = l_currentWmoObject->getNameSet(); auto wmoId = l_currentWmoObject->getWmoId(); @@ -453,7 +453,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams ///----------------------------------- - auto lcurrentWMO = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); + auto lcurrentWMO = wmoFactory.getObjectById<0>(mapRenderPlan->m_currentWMO); auto currentWmoGroup = mapRenderPlan->m_currentWmoGroup; if ((lcurrentWMO != nullptr) && (!mapRenderPlan->m_currentInteriorGroups.empty()) && (lcurrentWMO->isLoaded())) { @@ -520,8 +520,8 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams { ZoneScopedN("adt mesh collect"); - for (auto &adtRes: exteriorView->drawnADTs) { - adtRes->adtObject->collectMeshes(*adtRes, exteriorView->m_adtOpaqueMeshes, + for (auto &adtRes: mapRenderPlan->adtArray) { + adtRes.adtObject->collectMeshes(adtRes, exteriorView->m_adtOpaqueMeshes, exteriorView->liquidMeshes, exteriorView->renderOrder); } @@ -601,7 +601,7 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp std::vector wmoFogData = {}; if (mapRenderPlan->m_currentWMO != emptyWMO) { - auto l_currentWmoObject = wmoFactory.getObjectById(mapRenderPlan->m_currentWMO); + auto l_currentWmoObject = wmoFactory.getObjectById<0>(mapRenderPlan->m_currentWMO); if (l_currentWmoObject != nullptr) { l_currentWmoObject->checkFog(frustumData.cameraPos, wmoFogData); } @@ -1161,7 +1161,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, //Frustum cull for (auto &wmoId : mapRenderPlan->wmoArray.getCandidates()) { - auto wmoCandidate = wmoFactory.getObjectById(wmoId); + auto wmoCandidate = wmoFactory.getObjectById<0>(wmoId); if (wmoCandidate!= nullptr && !wmoCandidate->isLoaded()) continue; if (wmoCandidate->startTraversingWMOGroup( @@ -1179,6 +1179,7 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, //3.2 Iterate over all global WMOs and M2s (they have uniqueIds) { + ZoneScopedN("Cull M2"); auto results = std::vector(); auto &candidates = exteriorView->m2List.getCandidates(); @@ -1212,8 +1213,8 @@ void Map::checkExterior(mathfu::vec4 &cameraPos, for (int i = 0; i < candidates.size(); i++) { if (!results[i]) { - auto m2ObjectCandidate = m2Factory.getObjectById(candidates[i]); - exteriorView->m2List.addToDraw(m2ObjectCandidate); +// auto m2ObjectCandidate = m2Factory.getObjectById<0>(candidates[i]); + exteriorView->m2List.addToDraw(candidates[i]); } } } @@ -1309,13 +1310,14 @@ void Map::checkADTCulling(int i, int j, } auto &adtObject = mapTiles[i][j]; + auto &adtArray = mapRenderPlan->adtArray; if (adtObject != nullptr) { - std::shared_ptr adtFrustRes = std::make_shared(); - adtFrustRes->adtObject = adtObject; + auto &adtFrustRes = adtArray.emplace_back(); + adtFrustRes.adtObject = adtObject; bool result = adtObject->checkFrustumCulling( - *adtFrustRes.get(), + adtFrustRes, cameraPos, frustumData, m2ObjectsCandidates, wmoCandidates); @@ -1325,10 +1327,9 @@ void Map::checkADTCulling(int i, int j, // adtObject->getFreeStrategy()(false, true, this->getCurrentSceneTime()); // } - if (result) { - mapRenderPlan->viewsHolder.getExterior()->drawnADTs.push_back(adtFrustRes); - mapRenderPlan->adtArray.push_back(adtFrustRes); - + if (!result) { + adtArray.pop_back(); + } else { //Add lights from WDTLightObject if (m_wdtLightObject) { auto pointLightsOfAdt = m_wdtLightObject->getPointLights(i, j); @@ -1344,7 +1345,7 @@ void Map::checkADTCulling(int i, int j, if (m_wdtfile->mphd->flags.wdt_has_maid) { auto &mapFileIds = m_wdtfile->mapFileDataIDs[j * 64 + i]; if (mapFileIds.rootADT > 0) { - adtObject = std::make_shared(m_api, i, j, + adtObject = adtObjectFactory.createObject(m_api, i, j, m_wdtfile->mapFileDataIDs[j * 64 + i], m_wdtfile); } else { @@ -1354,7 +1355,7 @@ void Map::checkADTCulling(int i, int j, std::string adtFileTemplate = "world/maps/" + mapName + "/" + mapName + "_" + std::to_string(i) + "_" + std::to_string(j); - adtObject = std::make_shared(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); + adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); } adtObject->setMapApi(this); @@ -1407,7 +1408,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende ZoneScopedN("Load m2 main"); if (m_api->getConfig()->renderM2) { for (auto &m2ObjectId: renderPlan->m2Array.getToLoadMain()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); } @@ -1417,7 +1418,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende ZoneScopedN("Load m2 geom"); if (m_api->getConfig()->renderM2) { for (auto &m2ObjectId: renderPlan->m2Array.getToLoadGeom()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); m2ProcessedThisFrame++; @@ -1429,12 +1430,12 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende if (m_api->getConfig()->renderSkyDom) { if (auto skyboxView = renderPlan->viewsHolder.getSkybox()) { for (auto &m2ObjectId: skyboxView->m2List.getToLoadMain()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadMainFile(); } for (auto &m2ObjectId: skyboxView->m2List.getToLoadGeom()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->doLoadGeom(sceneRenderer); } @@ -1446,7 +1447,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende ZoneScopedN("Load wmoObject"); if (m_api->getConfig()->renderWMO) { for (auto wmoId: renderPlan->wmoArray.getToLoad()) { - auto wmoObject = wmoFactory.getObjectById(wmoId); + auto wmoObject = wmoFactory.getObjectById<0>(wmoId); if (wmoObject != nullptr) { wmoObject->doPostLoad(sceneRenderer); } @@ -1469,7 +1470,7 @@ void Map::doPostLoad(const HMapSceneBufferCreate &sceneRenderer, const HMapRende ZoneScopedN("Load adt"); int adtProcessed = 0; for (auto &adtObject: renderPlan->adtArray) { - adtProcessed += (adtObject->adtObject->doPostLoad(sceneRenderer)) ? 1 : 0; + adtProcessed += (adtObject.adtObject->doPostLoad(sceneRenderer)) ? 1 : 0; if (adtProcessed >= 2) break; } } @@ -1525,7 +1526,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { - auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); + auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); if (m2Object == nullptr) continue; m2Object->update(deltaTime, cameraVec3, lookAtMat);\ @@ -1544,7 +1545,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { for (auto &m2ObjectId : skyBoxView->m2List.getDrawn()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->update(deltaTime, cameraVec3, lookAtMat); } @@ -1555,7 +1556,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { ZoneScopedN("wmoUpdate"); for (const auto &wmoId: renderPlan->wmoArray.getToDrawn()) { - auto wmoObject = wmoFactory.getObjectById(wmoId); + auto wmoObject = wmoFactory.getObjectById<0>(wmoId); if (wmoObject == nullptr) continue; wmoObject->update(); } @@ -1574,9 +1575,9 @@ void Map::update(const HMapRenderPlan &renderPlan) { { std::unordered_set> processedADT; for (const auto &adtObjectRes: renderPlan->adtArray) { - if (processedADT.count(adtObjectRes->adtObject) == 0) { - adtObjectRes->adtObject->update(deltaTime); - processedADT.insert(adtObjectRes->adtObject); + if (processedADT.find(adtObjectRes.adtObject) != processedADT.end()) { + adtObjectRes.adtObject->update(deltaTime); + processedADT.insert(adtObjectRes.adtObject); } } } @@ -1590,7 +1591,7 @@ void Map::update(const HMapRenderPlan &renderPlan) { tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), 500), [&](tbb::blocked_range r) { for (size_t i = r.begin(); i != r.end(); ++i) { - auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); + auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); if (m2Object == nullptr) continue; m2Object->calcDistance(cameraVec3); } @@ -1668,7 +1669,7 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe //Can't be paralleled? auto &drawnM2s = renderPlan->m2Array.getDrawn(); for (auto &m2ObjectId: drawnM2s) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object != nullptr) { m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); } @@ -1686,7 +1687,7 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe [&](tbb::blocked_range r) { l_device->setCurrentProcessingFrameNumber(processingFrame); for (size_t i = r.begin(); i != r.end(); ++i) { - auto m2Object = m2Factory.getObjectById(m2ToDraw[i]); + auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); if (m2Object != nullptr) { m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, renderPlan->frameDependentData); @@ -1709,7 +1710,7 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe ZoneScopedN("m2SkyboxBuffersUpdate"); if (auto skyBoxView = renderPlan->viewsHolder.getSkybox()) { for (auto &m2ObjectId: skyBoxView->m2List.getDrawn()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, renderPlan->frameDependentData); } @@ -1728,9 +1729,9 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe ZoneScopedN("adtBuffersUpdate"); std::unordered_set> processedADT; for (const auto &adtObjectRes: renderPlan->adtArray) { - if (processedADT.count(adtObjectRes->adtObject) == 0) { - adtObjectRes->adtObject->uploadGeneratorBuffers(renderPlan->frameDependentData); - processedADT.insert(adtObjectRes->adtObject); + if (processedADT.find(adtObjectRes.adtObject) != processedADT.end()) { + adtObjectRes.adtObject->uploadGeneratorBuffers(renderPlan->frameDependentData); + processedADT.insert(adtObjectRes.adtObject); } } } diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index a1dfeb10d..c31b9d874 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -167,7 +167,7 @@ class Map : public IScene, public IMapApi { m_lockedMap = true; std::string adtFileTemplate = "world/maps/"+mapName+"/"+mapName+"_"+std::to_string(i)+"_"+std::to_string(j); - auto adtObject = std::make_shared(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); + auto adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); adtObject->setMapApi(this); this->mapTiles[i][j] = adtObject; diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp index 7e7b44e96..b67137313 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.cpp @@ -1395,4 +1395,4 @@ std::shared_ptr WmoObject::getNewLight(int index) { return m_newLights[index]; } -EntityFactory wmoFactory; \ No newline at end of file +EntityFactory<2000, WMOObjId, WmoObject> wmoFactory; \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 2ca539b2b..4d3c1fe13 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -199,7 +199,7 @@ class WmoObject : public IWmoApi, public ObjectWithId{ std::shared_ptr getNewLight(int index) override; }; -extern EntityFactory wmoFactory; +extern EntityFactory<2000, WMOObjId, WmoObject> wmoFactory; class WMOListContainer { using wmoContainer = framebased::vector; diff --git a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp index 310db7a6a..467ff3a25 100644 --- a/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp +++ b/wowViewerLib/src/gapi/vulkan/GDeviceVulkan.cpp @@ -27,6 +27,7 @@ #include "../../renderer/vulkan/IRenderFunctionVLK.h" #include "commandBuffer/commandBufferRecorder/TextureUploadHelper.h" #include "../../renderer/frame/FrameProfile.h" +#include "../../engine/objects/scenes/EntityActorsFactory.h" #include const int WIDTH = 1900; @@ -1400,14 +1401,19 @@ void GDeviceVLK::presentQueue(const std::vector &waitSemaphores, } void GDeviceVLK::executeDeallocators() { - std::lock_guard lock(m_listOfDeallocatorsAccessMtx); - while ((!listOfDeallocators.empty()) && (listOfDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { - auto stuff = listOfDeallocators.front(); - if (stuff.callback != nullptr) { - stuff.callback(); - } + { + std::lock_guard lock(m_listOfDeallocatorsAccessMtx); + while ((!listOfDeallocators.empty()) && (listOfDeallocators.front().frameNumberToDoAt <= m_frameNumber)) { + auto stuff = listOfDeallocators.front(); + if (stuff.callback != nullptr) { + stuff.callback(); + } - listOfDeallocators.pop_front(); + listOfDeallocators.pop_front(); + } + } + { + executeEntityDeallocators(); } } diff --git a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h index ad9bc075e..e796b2720 100644 --- a/wowViewerLib/src/renderer/mapScene/MapScenePlan.h +++ b/wowViewerLib/src/renderer/mapScene/MapScenePlan.h @@ -38,7 +38,7 @@ struct MapRenderPlan { //Objects for update and rendering - std::vector> adtArray = {}; + std::vector adtArray = {}; M2ObjectListContainer m2Array; WMOListContainer wmoArray; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index f76b3d41e..9cee0b8b0 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -76,7 +76,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende transp_vec transpVec; auto lCollector = opaqueMeshCollector.clone(); for (size_t i = r.begin(); i != r.end(); ++i) { - auto *m2Object = m2Factory.getObjectById(m2ToDraw[i]); + auto *m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); if (m2Object != nullptr) { m2Object->collectMeshes(*lCollector, transpVec); m2Object->drawParticles(*lCollector, transpVec, @@ -95,7 +95,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende }); } else { for (auto m2ObjectId : cullStage->m2Array.getDrawn()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->collectMeshes(opaqueMeshCollector, transparentMeshes); m2Object->drawParticles(opaqueMeshCollector, transparentMeshes, m_viewRenderOrder); @@ -110,7 +110,7 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende ZoneScopedN("collect skyBox"); for (auto &m2ObjectId : skyBoxView->m2List.getDrawn()) { - auto m2Object = m2Factory.getObjectById(m2ObjectId); + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); if (m2Object == nullptr) continue; m2Object->collectMeshes(skyOpaqueMeshCollector, skyTranspVec); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index d70414877..45e0b0315 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -130,7 +130,7 @@ static const ShaderConfig waterBindlessShaderConfig = { }} }}; -EntityFactory bindlessMeshFactoryVlk; +EntityFactory<10000, GMeshId, GMeshVLK> bindlessMeshFactoryVlk; MapSceneRenderBindlessVLK::MapSceneRenderBindlessVLK(const HGDeviceVLK &hDevice, Config *config) : m_device(hDevice), MapSceneRenderer(config) { @@ -1132,14 +1132,14 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); - auto meshVlk = bindlessMeshFactoryVlk.getObjectById(meshId); + auto meshVlk = bindlessMeshFactoryVlk.getObjectById<0>(meshId); auto &drawCommand = drawVec.emplace_back(); fillDrawCommand(drawCommand, meshVlk); } inline void addDrawCommand(tbb::concurrent_vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); - auto meshVlk = bindlessMeshFactoryVlk.getObjectById(meshId); + auto meshVlk = bindlessMeshFactoryVlk.getObjectById<0>(meshId); DrawCommand drawCommand; fillDrawCommand(drawCommand, meshVlk); diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h index deccbdb35..3216be54f 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderForwardVLK.h @@ -114,7 +114,7 @@ class MapSceneRenderForwardVLK : public MapSceneRenderer { private: HGDeviceVLK m_device; - std::shared_ptr> meshFactory = std::make_shared>(); + std::shared_ptr> meshFactory = std::make_shared>(); HGBufferVLK vboM2Buffer; HGBufferVLK vboM2ParticleBuffer; diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp index dd7e12f08..6e8286cc9 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderVisVLK.cpp @@ -1027,7 +1027,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ } inline void addDrawCommand(framebased::vector &drawVec, const HGMesh &mesh) { auto meshId = mesh->getObjectId(); - auto meshVlk = m_renderer.meshFactory->getObjectById(meshId); + auto meshVlk = m_renderer.meshFactory->getObjectById<0>(meshId); // const auto &meshVlk = (GMeshVLK*) mesh->getObjectId(); auto const matId = meshVlk->material()->getMaterialId(); From dd740f91b7b2076d34fc6112ee3d6e6972617f56 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 1 May 2024 08:02:24 +0300 Subject: [PATCH 197/212] - fix rendering of old world --- src/database/CSqliteDB.cpp | 10 +- .../glsl/bindless/adt/adtShader_text.glsl | 5 +- .../bindless/adt/visbuffer/adtShader.frag | 3 +- .../glsl/common/commonADTMaterial.glsl | 23 +++-- .../commonAdtIndirectDescriptorSet.glsl | 2 +- .../glsl/forwardRendering/adtShader.frag | 5 +- .../src/engine/objects/adt/adtObject.cpp | 63 +++++++----- .../src/engine/objects/adt/adtObject.h | 5 +- .../src/engine/objects/scenes/map.cpp | 10 +- wowViewerLib/src/engine/objects/scenes/map.h | 9 +- .../src/engine/persistance/adtFile.cpp | 97 ++++++++++++------- wowViewerLib/src/engine/persistance/adtFile.h | 3 +- .../engine/persistance/header/adtFileHeader.h | 24 ++--- wowViewerLib/src/include/database/dbStructs.h | 1 + 14 files changed, 167 insertions(+), 93 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 3a5c45da8..e0070577f 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -42,16 +42,16 @@ SQLite::Column CSqliteDB::StatementFieldHolder::getField(const HashedString fiel const std::string getMapListSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride from Map m where m.WdtFileDataID > 0"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.WdtFileDataID > 0"; const std::string getMapListSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m"; const std::string getMapByIDSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride from Map m where m.ID = ?"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.ID = ?"; const std::string getMapByIDSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m"; const std::string getWmoAreaAreaNameSQL = R"===( select wat.AreaName_lang as wmoAreaName, at.AreaName_lang as areaName, at.ID as ID, at.ParentAreaID as ParentAreaID, at.Ambient_multiplier as Ambient_multiplier from WMOAreaTable wat @@ -184,6 +184,7 @@ void CSqliteDB::getMapArray(std::vector &mapRecords) { } mapRecord.MapType = getMapList.getField("MapType").getInt(); mapRecord.overrideTime = getMapList.getField("TimeOfDayOverride").getInt(); + mapRecord.flags0 = getMapList.getField("Flags_0").getInt(); } } @@ -206,6 +207,7 @@ bool CSqliteDB::getMapById(int mapId, MapRecord &mapRecord) { } mapRecord.MapType = getMapByIdStatement.getField("MapType").getInt(); mapRecord.overrideTime = getMapByIdStatement.getField("TimeOfDayOverride").getInt(); + mapRecord.flags0 = getMapByIdStatement.getField("Flags_0").getInt(); return true; } diff --git a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl index b202aa6f3..c3c8e8252 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl +++ b/wowViewerLib/shaders/glsl/bindless/adt/adtShader_text.glsl @@ -69,7 +69,7 @@ void main() { vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; vec4 final; - if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { + if (adtMeshWideVSPS.uUseHeightMixFormula_useWeightedBlend.r > 0) { calcADTHeightFragMaterial( tcLayer0, tcLayer1, tcLayer2, tcLayer3, s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], @@ -88,6 +88,7 @@ void main() { s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], vAlphaCoords, s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + adtMeshWideVSPS.uUseHeightMixFormula_useWeightedBlend.g > 0, final ); } @@ -98,7 +99,7 @@ void main() { #ifndef DEFERRED - vec3 accumLight = vVertexLighting.rgb; + vec3 accumLight = vec3(0.0);//vVertexLighting.rgb; float ao = 0.0; { vec2 screenUV = (gl_FragCoord.xy / scene.uSceneSize_DisableLightBuffer.xy); diff --git a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag index b119d2c50..ed3492d6d 100644 --- a/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/adt/visbuffer/adtShader.frag @@ -69,7 +69,7 @@ void main() { vec4 heightOffset = adtMeshWideVSPS.uHeightOffset; vec4 final; - if (adtMeshWideVSPS.uUseHeightMixFormula.r > 0) { + if (adtMeshWideVSPS.uUseHeightMixFormula_useWeightedBlend.r > 0) { calcADTHeightFragMaterial( tcLayer0, tcLayer1, tcLayer2, tcLayer3, s_LayerTextures[nonuniformEXT(txLayer0)], s_LayerTextures[nonuniformEXT(txLayer1)], @@ -88,6 +88,7 @@ void main() { s_LayerTextures[nonuniformEXT(txLayer2)], s_LayerTextures[nonuniformEXT(txLayer3)], vAlphaCoords, s_AlphaTextures[nonuniformEXT(adtInstanceData.meshIndexVSPS_meshIndexPS_AlphaTextureInd.z)], + adtMeshWideVSPS.uUseHeightMixFormula_useWeightedBlend.g > 0, final ); } diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl index b2a921ca9..91eb76c47 100644 --- a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -94,17 +94,28 @@ void calcADTOrigFragMaterial( in sampler2D t_Layer0, in sampler2D t_Layer1, in sampler2D t_Layer2, in sampler2D t_Layer3, in vec2 tcAlpha, in sampler2D t_alphaTex, - + in bool useWeightedBlend, out vec4 matDiffuse ) { - vec3 alphaBlend = texture( t_alphaTex, tcAlpha).rgb; + vec3 alphaBlend = texture( t_alphaTex, tcAlpha).gba; vec4 tex1 = texture(t_Layer0, tcLayer0).rgba; vec4 tex2 = texture(t_Layer1, tcLayer1).rgba; vec4 tex3 = texture(t_Layer2, tcLayer2).rgba; - vec4 tex4 = texture(t_Layer2, tcLayer3).rgba; - - matDiffuse = mix(mix(mix(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + vec4 tex4 = texture(t_Layer3, tcLayer3).rgba; + + if (!useWeightedBlend) { + matDiffuse = mix(mix(mix(tex1, tex2, alphaBlend.r), tex3, alphaBlend.g), tex4, alphaBlend.b); + } else { + float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); + vec4 weights = vec4(minusAlphaBlendSum, alphaBlend); + + matDiffuse = + (tex1 * weights.r) + + (tex2 * weights.g) + + (tex3 * weights.b) + + (tex4 * weights.a); + } } void calcADTHeightFragMaterial( @@ -118,7 +129,7 @@ void calcADTHeightFragMaterial( out vec4 matDiffuse ) { - vec3 alphaBlend = texture( t_alphaTex, tcAlpha).rgb; + vec3 alphaBlend = texture( t_alphaTex, tcAlpha).gba; float minusAlphaBlendSum = (1.0 - clamp(dot(alphaBlend, vec3(1.0)), 0.0, 1.0)); vec4 weightsVector = vec4(minusAlphaBlendSum, alphaBlend); diff --git a/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl index 3758ea309..b7ffdf32f 100644 --- a/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl +++ b/wowViewerLib/shaders/glsl/common/commonAdtIndirectDescriptorSet.glsl @@ -3,7 +3,7 @@ struct AdtMeshWideVSPS { vec4 uPos; - ivec4 uUseHeightMixFormula; + ivec4 uUseHeightMixFormula_useWeightedBlend; vec4 uHeightScale; vec4 uHeightOffset; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag index 079307538..2ee5fb056 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/adtShader.frag @@ -30,7 +30,7 @@ layout(set=2, binding=8) uniform sampler2D uLayerHeight3; layout(std140, set=1, binding=0) uniform meshWideBlockVSPS { vec4 uPos; - ivec4 uUseHeightMixFormula; + ivec4 uUseHeightMixFormula_useWeightedBlend; vec4 uHeightScale; vec4 uHeightOffset; }; @@ -60,7 +60,7 @@ void main() { vec2 tcLayer3 = transformADTUV(vTexCoord, 3, sceneTime, animation_rotationPerLayer, animation_speedPerLayer, scaleFactorPerLayer); vec4 final; - if (uUseHeightMixFormula.r > 0) { + if (uUseHeightMixFormula_useWeightedBlend.r > 0) { calcADTHeightFragMaterial( tcLayer0, tcLayer1, tcLayer2, tcLayer3, uLayer0, uLayer1, uLayer2, uLayer3, @@ -76,6 +76,7 @@ void main() { uLayer0, uLayer1, uLayer2, uLayer3, vAlphaCoords, uAlphaTexture, + uUseHeightMixFormula_useWeightedBlend.g > 0, final ); } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 06d91eab2..771e35810 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -406,6 +406,7 @@ void AdtObject::createMeshes(const HMapSceneBufferCreate &sceneRenderer) { ); matVSPS.useHeightMixFormula[0] = useHeightMixFormula; + matVSPS.useHeightMixFormula[1] = m_useWeightedBlend > 0 ? 1 : 0; for (int j = 0; j < 4; j++) { matVSPS.uHeightOffset[j] = 0.0f; matVSPS.uHeightScale[j] = 1.0f; @@ -523,22 +524,25 @@ void AdtObject::loadAlphaTextures() { memset(bigTexture.data(), 0, bigTexture.size()); if (chunkCount > 0) { -// for (int i = 0; i < chunkCount; i++){ - oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); - arena.execute([&] { - oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { - ALIGNED_(16) std::array alphaTextureData; + ALIGNED_(16) std::array alphaTextureData; - for (size_t i = r.begin(); i != r.end(); ++i) { + for (int i = 0; i < chunkCount; i++){ +// oneapi::tbb::task_arena arena(std::min(8, m_api->getConfig()->hardwareThreadCount()), 1); +// arena.execute([&] { +// oneapi::tbb::parallel_for(tbb::blocked_range(0, chunkCount, 16), [&](tbb::blocked_range &r) { +// ALIGNED_(16) std::array alphaTextureData; +// +// for (size_t i = r.begin(); i != r.end(); ++i) { auto const &mapTile = m_adtFile->mapTile[i]; const auto indexX = mapTile.IndexX; const auto indexY = mapTile.IndexY; - memset(alphaTextureData.data(), 0, alphaTextureData.size()); auto chunkMcalRuntime = m_adtFileTex->createAlphaTextureRuntime(i); for (int y = 0; y < 64; y++) { - m_adtFileTex->processAlphaTextureRow(chunkMcalRuntime,m_wdtFile->mphd->flags, i, alphaTextureData.data(), alphaTextureData.size()); + memset(alphaTextureData.data(), 0, alphaTextureData.size()); + + m_adtFileTex->processAlphaTextureRow(chunkMcalRuntime,m_wdtFile->mphd->flags, i, alphaTextureData.data(), 64); __m128i *alpha[4] = { (__m128i *)(alphaTextureData.data() + (0)), @@ -551,18 +555,29 @@ void AdtObject::loadAlphaTextures() { indexX * 64 + 0, indexY * 64 + y, texWidth, texHeight, 0); + const __m128i vec255 = _mm_set1_epi8(255); for (int x = 0; x < 64/16; x++) { //Interleave - __m128i alpha0 = _mm_load_si128(alpha[0]++); //a_1 a_2 a_3 a_4 a_5 a_6 a_7 a_8 a_9 a_10 a_11 a_12 a_13 a_14 a_15 a_16 - __m128i alpha1 = _mm_load_si128(alpha[1]++); //b_1 b_2 b_3 b_4 b_5 b_6 b_7 b_8 b_9 b_10 b_11 b_12 b_13 b_14 b_15 b_16 - __m128i alpha2 = _mm_load_si128(alpha[2]++); //c_1 c_2 c_3 c_4 c_5 c_6 c_7 c_8 c_9 c_10 c_11 c_12 c_13 c_14 c_15 c_16 - __m128i alpha3 = _mm_load_si128(alpha[3]++); //d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10 d_11 d_12 d_13 d_14 d_15 d_16 - - __m128i a_b_low = _mm_unpacklo_epi8(alpha0, alpha1); //a_1 b_1 a_2 b_2 a_3 b_3 a_4 b_4 a_5 b_5 a_6 b_6 a_7 b_7 - __m128i a_b_high = _mm_unpackhi_epi8(alpha0, alpha1); //a_8 b_8 a_9 b_9 a_10 b_10 a_11 b_11 a_12 b_12 a_13 b_13 a_14 b_14 - - __m128i c_d_low = _mm_unpacklo_epi8(alpha2, alpha3); //c_1 d_1 c_2 d_2 c_3 d_3 c_4 d_4 c_5 d_5 c_6 d_6 c_7 d_7 - __m128i c_d_high = _mm_unpackhi_epi8(alpha2, alpha3);//c_8 d_8 c_9 d_9 c_10 d_10 c_11 d_11 c_12 d_12 c_13 d_13 c_14 d_14 + __m128i _alpha[4]; + _alpha[0] = _mm_load_si128(alpha[0]++); //a_1 a_2 a_3 a_4 a_5 a_6 a_7 a_8 a_9 a_10 a_11 a_12 a_13 a_14 a_15 a_16 + _alpha[1] = _mm_load_si128(alpha[1]++); //b_1 b_2 b_3 b_4 b_5 b_6 b_7 b_8 b_9 b_10 b_11 b_12 b_13 b_14 b_15 b_16 + _alpha[2] = _mm_load_si128(alpha[2]++); //c_1 c_2 c_3 c_4 c_5 c_6 c_7 c_8 c_9 c_10 c_11 c_12 c_13 c_14 c_15 c_16 + _alpha[3]= _mm_load_si128(alpha[3]++); //d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10 d_11 d_12 d_13 d_14 d_15 d_16 + + if (chunkMcalRuntime.uncompressedIndex) { + _alpha[chunkMcalRuntime.uncompressedIndex] = + vec255 - + _alpha[0] - + _alpha[1] - + _alpha[2] - + _alpha[3]; + } + + __m128i a_b_low = _mm_unpacklo_epi8(_alpha[0], _alpha[1]); //a_1 b_1 a_2 b_2 a_3 b_3 a_4 b_4 a_5 b_5 a_6 b_6 a_7 b_7 + __m128i a_b_high = _mm_unpackhi_epi8(_alpha[0], _alpha[1]); //a_8 b_8 a_9 b_9 a_10 b_10 a_11 b_11 a_12 b_12 a_13 b_13 a_14 b_14 + + __m128i c_d_low = _mm_unpacklo_epi8(_alpha[2], _alpha[3]); //c_1 d_1 c_2 d_2 c_3 d_3 c_4 d_4 c_5 d_5 c_6 d_6 c_7 d_7 + __m128i c_d_high = _mm_unpackhi_epi8(_alpha[2], _alpha[3]);//c_8 d_8 c_9 d_9 c_10 d_10 c_11 d_11 c_12 d_12 c_13 d_13 c_14 d_14 __m128i a_b_c_d_low_low = _mm_unpacklo_epi16(a_b_low, c_d_low); //a_1 b_1 c_1 d_1 a_2 b_2 c_2 d_2... __m128i a_b_c_d_low_high = _mm_unpackhi_epi16(a_b_low, c_d_low);//a_4 b_4 c_4 d_4 a_5 b_5 c_5 d_5... @@ -570,6 +585,8 @@ void AdtObject::loadAlphaTextures() { __m128i a_b_c_d_high_low = _mm_unpacklo_epi16(a_b_high, c_d_high);//a_8 b_8 c_8 d_8 a_9 b_9 c_9 d_9... __m128i a_b_c_d_high_high = _mm_unpackhi_epi16(a_b_high, c_d_high);//a_11 b_11 c_11 d_11 a_12 b_12 c_12 d_12... + + _mm_store_si128(texturePtr++, a_b_c_d_low_low); _mm_store_si128(texturePtr++, a_b_c_d_low_high); _mm_store_si128(texturePtr++, a_b_c_d_high_low); @@ -577,8 +594,8 @@ void AdtObject::loadAlphaTextures() { } } } - }, tbb::auto_partitioner()); - }); +// }, tbb::auto_partitioner()); +// }); } alphaTexture->getTexture()->loadData(texWidth, texHeight, &bigTexture[0], ITextureFormat::itRGBA); @@ -1198,7 +1215,8 @@ bool AdtObject::checkFrustumCulling(ADTObjRenderRes &adtFrustRes, return atLeastOneIsDrawn; } -AdtObject::AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, HWdtFile wdtFile) : adt_x(adt_x), adt_y(adt_y){ +AdtObject::AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, bool useWeightedBlend, HWdtFile wdtFile) : adt_x(adt_x), adt_y(adt_y), +m_useWeightedBlend(useWeightedBlend) { m_api = api; tileAabb = std::vector(256); waterTileAabb = std::vector(256); @@ -1224,7 +1242,8 @@ AdtObject::AdtObject(HApiContainer api, std::string &adtFileTemplate, std::strin } -AdtObject::AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDataIDs &fileDataIDs, HWdtFile wdtFile): adt_x(adt_x), adt_y(adt_y) { +AdtObject::AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDataIDs &fileDataIDs, bool useWeightedBlend, HWdtFile wdtFile): adt_x(adt_x), adt_y(adt_y), + m_useWeightedBlend(useWeightedBlend) { m_api = api; tileAabb = std::vector(256); waterTileAabb = std::vector(256); diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index b68ca4d6e..c7039497f 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -30,8 +30,8 @@ enum class AdtObjectId : int; extern EntityFactory<50, AdtObjectId, AdtObject> adtObjectFactory; class AdtObject : public ObjectWithId { public: - AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, HWdtFile wdtfile); - AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDataIDs &fileDataIDs, HWdtFile wdtfile); + AdtObject(HApiContainer api, std::string &adtFileTemplate, std::string mapname, int adt_x, int adt_y, bool useWeightedBlend, HWdtFile wdtfile); + AdtObject(HApiContainer api, int adt_x, int adt_y, WdtFile::MapFileDataIDs &fileDataIDs, bool useWeightedBlend, HWdtFile wdtfile); ~AdtObject() { // std::cout << "~AdtObject called" << std::endl; }; @@ -157,6 +157,7 @@ class AdtObject : public ObjectWithId { int adt_x; int adt_y; + bool m_useWeightedBlend; std::string m_adtFileTemplate; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index d0fac607a..24f9646bf 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -279,6 +279,11 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) { m_sceneMode = SceneMode::smMap; createAdtFreeLamdas(); + MapRecord mapRecord; + api->databaseHandler->getMapById(mapId, mapRecord); + useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + + std::string wdtFileName = "world/maps/"+mapName+"/"+mapName+".wdt"; std::string wdlFileName = "world/maps/"+mapName+"/"+mapName+".wdl"; std::string wdtLightFileName = "world/maps/"+mapName+"/"+mapName+"_lgt.wdt"; @@ -1347,6 +1352,7 @@ void Map::checkADTCulling(int i, int j, if (mapFileIds.rootADT > 0) { adtObject = adtObjectFactory.createObject(m_api, i, j, m_wdtfile->mapFileDataIDs[j * 64 + i], + useWeightedBlend, m_wdtfile); } else { return; @@ -1355,7 +1361,9 @@ void Map::checkADTCulling(int i, int j, std::string adtFileTemplate = "world/maps/" + mapName + "/" + mapName + "_" + std::to_string(i) + "_" + std::to_string(j); - adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); + adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, + useWeightedBlend, + m_wdtfile); } adtObject->setMapApi(this); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index c31b9d874..0a2cecd35 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -54,6 +54,7 @@ class Map : public IScene, public IMapApi { HWdtFile m_wdtfile = nullptr; std::shared_ptr wmoMap = nullptr; + bool useWeightedBlend = false; std::vector> m_exteriorSkyBoxes; @@ -135,7 +136,7 @@ class Map : public IScene, public IMapApi { explicit Map() { } public: - explicit Map(HApiContainer api, int mapId, const std::string &mapName);; + explicit Map(HApiContainer api, int mapId, const std::string &mapName); explicit Map(HApiContainer api, int mapId, int wdtFileDataId) { initMapTiles(); @@ -143,6 +144,10 @@ class Map : public IScene, public IMapApi { m_mapId = mapId; m_api = api; mapName = ""; m_sceneMode = SceneMode::smMap; + MapRecord mapRecord; + api->databaseHandler->getMapById(mapId, mapRecord); + useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + createAdtFreeLamdas(); m_wdtfile = api->cacheStorage->getWdtFileCache()->getFileId(wdtFileDataId); @@ -167,7 +172,7 @@ class Map : public IScene, public IMapApi { m_lockedMap = true; std::string adtFileTemplate = "world/maps/"+mapName+"/"+mapName+"_"+std::to_string(i)+"_"+std::to_string(j); - auto adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, m_wdtfile); + auto adtObject = adtObjectFactory.createObject(m_api, adtFileTemplate, mapName, i, j, false, m_wdtfile); adtObject->setMapApi(this); this->mapTiles[i][j] = adtObject; diff --git a/wowViewerLib/src/engine/persistance/adtFile.cpp b/wowViewerLib/src/engine/persistance/adtFile.cpp index eb5fcaa60..4967a0113 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.cpp +++ b/wowViewerLib/src/engine/persistance/adtFile.cpp @@ -493,24 +493,52 @@ MCAL_Offsets_Runtime AdtFile::createAlphaTextureRuntime(int mcnkChunkIndex) { uint8_t* mcal = mcnkObj.mcal; auto &layers = mcnkObj.mcly; - MCAL_Offsets_Runtime result; + uint32_t uniqueTextureIds[4] = {0,0,0,0}; + uint32_t uniqTextCnt = 0; + if ( mcnkObj.mclyCnt) { + uniqueTextureIds[0] = layers[0].textureId; + uniqTextCnt = 1; + } for (int j = 1; j < mcnkObj.mclyCnt; j++ ) { auto &layerDef = layers[j]; - int alphaOffs = layerDef.offsetInMCAL; - result.alphaOffsets[j-1] = &mcal[alphaOffs]; + bool alreadyIncluded = false; + for (int k = 0; k < uniqTextCnt; k++) { + if (uniqueTextureIds[k] == layerDef.textureId) { + alreadyIncluded = true; + break; + } + } + if (!alreadyIncluded) { + uniqueTextureIds[uniqTextCnt++] = layerDef.textureId; + } } - result.uncompressedIndex = 0; + + MCAL_Offsets_Runtime result; for (int j = 0; j < mcnkObj.mclyCnt; j++ ) { - if (layers[j].flags.use_alpha_map == 0) { - result.uncompressedIndex = j; + auto &layerDef = layers[j]; + uint32_t alphaOffs = layerDef.offsetInMCAL; + + for (int k = 0; k < uniqTextCnt; k++) { + if (uniqueTextureIds[k] == layerDef.textureId) { + if (layerDef.flags.use_alpha_map) { + result.alphaPtrs[k] = &mcal[alphaOffs]; + } else { + result.uncompressedIndex = k; + } + result.alphaFlags[k] = layerDef.flags; + + break; + } } } return result; } +const std::array noAlphaArray = {}; + void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MPHDFlags &wdtObjFlags, int i, uint8_t* __restrict currentLayer, uint32_t textureSize) { mcnkStruct_t &mcnkObj = mcnkStructs[i]; uint8_t* mcal = mcnkObj.mcal; @@ -520,38 +548,40 @@ void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MP if (layers == nullptr || mcal == nullptr) return; - for (int j = 1; j < mcnkObj.mclyCnt; j++ ) { + for (int j = 0; j < mcnkObj.mclyCnt; j++ ) { auto &layerDef = layers[j]; - auto &alphaArray = mcalRuntime.alphaOffsets[j-1]; + auto &alphaArray = mcalRuntime.alphaPtrs[j]; + auto alphaFlag = mcalRuntime.alphaFlags[j]; int readForThisLayer = 0; - if (!layerDef.flags.use_alpha_map) { -// for (int k = 0; k < 4096; k++) { -// *currentLayer++ = 0; -// } - } else if (layerDef.flags.alpha_map_compressed) { + if (!alphaFlag.use_alpha_map) { + std::copy(noAlphaArray.data(), noAlphaArray.data() + textureSize, currentLayer); + currentLayer += textureSize; + readForThisLayer += textureSize; + } else if (alphaFlag.alpha_map_compressed) { //Compressed //http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18 - while( readForThisLayer < 64 ) - { + while (readForThisLayer < textureSize) { // fill or copy mode uint8_t codeVal = *alphaArray++; - bool fill = (codeVal & 0x80 ) != 0; + bool fill = (codeVal & 0x80) != 0; + int n = fill ? - codeVal & 0x7F : - codeVal; + codeVal & 0x7F : + codeVal; if (fill) { uint8_t alphaVal = *alphaArray++; - for (int k = 0; k < n && readForThisLayer < 64; k++, readForThisLayer++) { + for (int k = 0; (k < n) && (readForThisLayer < textureSize); k++, readForThisLayer++) { *currentLayer++ = alphaVal; } } else { - for (int k = 0; k < n && readForThisLayer < 64; k++, readForThisLayer++) { - *currentLayer++ = *alphaArray++; + for (int k = 0; (k < n) && (readForThisLayer < textureSize); k++, readForThisLayer++) { + *currentLayer++ = *alphaArray; + alphaArray++; } } } @@ -559,27 +589,20 @@ void AdtFile::processAlphaTextureRow(MCAL_Offsets_Runtime &mcalRuntime, const MP //Uncompressed if (((wdtObjFlags.adt_has_big_alpha) > 0) || ((wdtObjFlags.adt_has_height_texturing) > 0)) { //Uncompressed (4096) - for (int iY = 0; iY < 64; iY++){ - *currentLayer++ = *alphaArray++; - } + for (int iY = 0; iY < textureSize; iY++) { + *currentLayer++ = *alphaArray++; + } } else { //Uncompressed (2048) - for (int iY = 0; iY < 32; iY++){ - //Old world - uint8_t alphaVal = *alphaArray++; - *currentLayer++ = (alphaVal & 0x0f ) * 17; - *currentLayer++ = ((alphaVal & 0xf0 ) >> 4) * 17; - } + for (int iY = 0; iY < textureSize; iY += 2) { + //Old world + uint8_t alphaVal = *alphaArray++; + *currentLayer++ = (alphaVal & 0x0f) * 17; + *currentLayer++ = ((alphaVal & 0xf0) >> 4) * 17; + } } } - //Fix alpha depending on flag -// if (((wdtObjFlags.adt_has_big_alpha) > 0) || ((wdtObjFlags.adt_has_height_texturing) > 0)) { -// int offO = j; -// for (int k = 0; k < 4096; k++) { -// currentLayer[offO+k*4] = (unsigned char) (178 * currentLayer[offO + k * 4] >> 8); -// } -// } } // if (mcalRuntime.uncompressedIndex) { diff --git a/wowViewerLib/src/engine/persistance/adtFile.h b/wowViewerLib/src/engine/persistance/adtFile.h index 78db0df83..91a0d615b 100644 --- a/wowViewerLib/src/engine/persistance/adtFile.h +++ b/wowViewerLib/src/engine/persistance/adtFile.h @@ -35,7 +35,8 @@ struct mcnkStruct_t { struct MCAL_Offsets_Runtime { int uncompressedIndex = 0; - std::array alphaOffsets = {nullptr,nullptr,nullptr}; + std::array alphaPtrs = {nullptr,nullptr,nullptr, nullptr}; + std::array alphaFlags = {0,0,0,0}; }; class AdtFile: public PersistentFile { diff --git a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h index 8345f38e1..6770a666c 100644 --- a/wowViewerLib/src/engine/persistance/header/adtFileHeader.h +++ b/wowViewerLib/src/engine/persistance/header/adtFileHeader.h @@ -127,18 +127,18 @@ struct SMChunk { struct { - uint32_t has_mcsh : 1; - uint32_t impass : 1; - uint32_t lq_river : 1; - uint32_t lq_ocean : 1; - uint32_t lq_magma : 1; - uint32_t lq_slime : 1; - uint32_t has_mccv : 1; - uint32_t unknown_0x80 : 1; - uint32_t unused1: 7; // not set in 6.2.0.20338 - uint32_t do_not_fix_alpha_map : 1; // "fix" alpha maps in MCAL (4 bit alpha maps are 63*63 instead of 64*64). + uint32_t has_mcsh : 1; //0x1 + uint32_t impass : 1; //0x2 + uint32_t lq_river : 1; //0x4 + uint32_t lq_ocean : 1; //0x8 + uint32_t lq_magma : 1; //0x10 + uint32_t lq_slime : 1; //0x20 + uint32_t has_mccv : 1; //0x40 + uint32_t unknown_0x80 : 1; //0x80 + uint32_t unused1: 7; //0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, // not set in 6.2.0.20338 + uint32_t do_not_fix_alpha_map : 1; //0x8000 // "fix" alpha maps in MCAL (4 bit alpha maps are 63*63 instead of 64*64). // Note that this also means that it *has* to be 4 bit alpha maps, otherwise UnpackAlphaShadowBits will assert. - uint32_t high_res_holes : 1; // Since ~5.3 WoW uses full 64-bit to store holes for each tile if this flag is set. + uint32_t high_res_holes : 1; //0x10000 // Since ~5.3 WoW uses full 64-bit to store holes for each tile if this flag is set. uint32_t unused2: 15; // not set in 6.2.0.20338 } flags; @@ -250,7 +250,7 @@ struct SMNormal { struct SMLayer { uint32_t textureId; - struct + struct MCAL_FLAG { uint32_t animation_rotation : 3; // each tick is 45° uint32_t animation_speed : 3; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 7ebdc473e..024ba00da 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -16,6 +16,7 @@ struct MapRecord { int WdtFileID; int MapType; int overrideTime; + uint32_t flags0; }; struct LightResult { From 304611ca68ecfbf7c153646c0fdb25bae06c9f7b Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 29 Jun 2024 22:41:31 +0300 Subject: [PATCH 198/212] some changes here and there --- src/database/CSqliteDB.cpp | 2 +- src/ui/FrontendUI.cpp | 7 ++ wowViewerLib/CMakeLists.txt | 3 + wowViewerLib/shaders/CMakeLists.txt | 3 +- .../glsl/common/commonADTMaterial.glsl | 8 +- .../src/engine/managers/animationManager.cpp | 10 +- .../managers/particles/particleEmitter.cpp | 35 +++--- .../src/engine/objects/ViewsObjects.cpp | 12 -- .../src/engine/objects/ViewsObjects.h | 4 - .../src/engine/objects/adt/adtObject.cpp | 18 +-- .../src/engine/objects/adt/adtObject.h | 4 +- .../engine/objects/liquid/LiquidInstance.h | 2 +- .../m2/m2Helpers/M2MeshBufferUpdater.cpp | 25 ---- .../m2/m2Helpers/M2MeshBufferUpdater.h | 2 - .../src/engine/objects/m2/m2Object.cpp | 53 ++++---- wowViewerLib/src/engine/objects/m2/m2Object.h | 23 +++- .../objects/scenes/EntityActorsFactory.h | 16 +-- .../src/engine/objects/scenes/map.cpp | 115 ++++++++++-------- .../src/engine/objects/wdl/wdlObject.cpp | 23 ++-- .../src/engine/objects/wmo/wmoObject.h | 2 +- .../src/engine/persistance/header/wdlHeader.h | 12 ++ .../src/engine/persistance/wdlFile.cpp | 37 +++++- wowViewerLib/src/engine/persistance/wdlFile.h | 8 ++ .../src/gapi/interface/meshes/IMesh.h | 3 +- .../renderer/mapScene/MapSceneRenderer.cpp | 7 ++ .../vulkan/MapSceneRenderBindlessVLK.cpp | 27 ++-- 26 files changed, 266 insertions(+), 195 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index e0070577f..5a3c816a6 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -51,7 +51,7 @@ const std::string getMapByIDSQL = "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.ID = ?"; const std::string getMapByIDSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.ID = ?"; const std::string getWmoAreaAreaNameSQL = R"===( select wat.AreaName_lang as wmoAreaName, at.AreaName_lang as areaName, at.ID as ID, at.ParentAreaID as ParentAreaID, at.Ambient_multiplier as Ambient_multiplier from WMOAreaTable wat diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 0125c7fcc..0ecf13264 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -1431,6 +1431,13 @@ void FrontendUI::showSettingsDialog() { m_api->getConfig()->renderM2 = renderM2; } + { + bool renderParticles = m_api->getConfig()->maxParticle >= 0; + if (ImGui::Checkbox("Render Particles", &renderParticles)) { + m_api->getConfig()->maxParticle = renderParticles ? 9999 : -1; + } + } + bool renderWMO = m_api->getConfig()->renderWMO; if (ImGui::Checkbox("Render WMO", &renderWMO)) { m_api->getConfig()->renderWMO = renderWMO; diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 04e90d2d5..872d19a2b 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -610,6 +610,9 @@ if (LINK_VULKAN) IF (Vulkan_LIBRARY) set(Vulkan_FOUND ON PARENT_SCOPE) MESSAGE("Using Vulkan library, Vulkan_LIBRARY= ${Vulkan_LIBRARY}") + if (NOT SPIRV_OPT_APP AND Vulkan_INCLUDE_DIR) + set(SPIRV_OPT_APP ${Vulkan_INCLUDE_DIR}/../Bin/spirv-opt) + endif() ELSE() MESSAGE("Vulkan Lib was not found. Disabling vulkan build") diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index e044fa129..cf8286c4c 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -4,6 +4,7 @@ else() set(GLSL_TARGET_FOLDER ${CMAKE_BINARY_DIR}) endif() +message( Shader SPIRV_OPT_APP = ${SPIRV_OPT_APP}) if (COMPILE_SHADER_WITH_DEBUG) set(SHADER_DEBUG_FLAG "-g") @@ -140,7 +141,7 @@ macro(configure_filesVLK rootDir srcCommonDirs shaderDirs destDir destDirGL20 de if(SPIRV_OPT_APP) add_custom_command( OUTPUT ${SPIRVOpt} - COMMAND ${SPIRV_OPT_APP} -O -o ${SPIRVOpt} ${SPIRV_NonOpt} + COMMAND ${SPIRV_OPT_APP} -O -Os -o ${SPIRVOpt} ${SPIRV_NonOpt} DEPENDS ${srcTemplatePath} ${SPIRV_NonOpt}) endif() diff --git a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl index 91eb76c47..1ad764ca2 100644 --- a/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl +++ b/wowViewerLib/shaders/glsl/common/commonADTMaterial.glsl @@ -111,10 +111,10 @@ void calcADTOrigFragMaterial( vec4 weights = vec4(minusAlphaBlendSum, alphaBlend); matDiffuse = - (tex1 * weights.r) + - (tex2 * weights.g) + - (tex3 * weights.b) + - (tex4 * weights.a); + (tex1 * weights.r) + + (tex2 * weights.g) + + (tex3 * weights.b) + + (tex4 * weights.a); } } diff --git a/wowViewerLib/src/engine/managers/animationManager.cpp b/wowViewerLib/src/engine/managers/animationManager.cpp index e512c2e62..a3239d6d5 100644 --- a/wowViewerLib/src/engine/managers/animationManager.cpp +++ b/wowViewerLib/src/engine/managers/animationManager.cpp @@ -741,11 +741,13 @@ void AnimationManager::update( std::vector> &particleEmitters, std::vector> &ribbonEmitters) { - auto &global_loops = *boneMasterData->getSkelData()->m_globalSequences; - auto &bones = *boneMasterData->getSkelData()->m_m2CompBones; + auto skelData = boneMasterData->getSkelData(); + + auto &global_loops = *skelData->m_globalSequences; + auto &bones = *skelData->m_m2CompBones; { - auto sequences = *boneMasterData->getSkelData()->m_sequences; + auto sequences = *skelData->m_sequences; if (sequences.size <= 0) return; } @@ -850,7 +852,7 @@ void AnimationManager::update( this->animationInfo.currentAnimation.repeatTimes--; if (this->animationInfo.nextSubAnimation.animationIndex > -1) { - M2Array * sequences = boneMasterData->getSkelData()->m_sequences; + M2Array * sequences = skelData->m_sequences; if (this->animationInfo.nextSubAnimation.animationFoundInParent) { sequences = boneMasterData->getParentSkelData()->m_sequences;; } diff --git a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp index d4dede234..0934e048f 100644 --- a/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp +++ b/wowViewerLib/src/engine/managers/particles/particleEmitter.cpp @@ -474,8 +474,6 @@ void ParticleEmitter::StepUpdate(animTime_t delta) { int i = 0; - std::list listForDeletion; - int numThreads = 10; #pragma omp parallel for schedule(dynamic, 200) default(none) shared(delta, forces) num_threads(numThreads) for (int i = 0; i < this->particles.size(); i++) { @@ -608,11 +606,7 @@ void ParticleEmitter::KillParticle(int index) { particles.erase(particles.begin()+index); } CParticle2& ParticleEmitter::BirthParticle() { - CParticle2 p1; - particles.push_back(p1); - - - CParticle2 &p = particles[particles.size() - 1]; + CParticle2 &p = particles.emplace_back(); return p; } @@ -673,7 +667,7 @@ void ParticleEmitter::fitBuffersToSize(const HMapSceneBufferCreate &sceneRendere } int ParticleEmitter::buildVertex1(CParticle2 &p, ParticlePreRenderData &particlePreRenderData) { - int coefXInt = (particlePreRenderData.m_ageDependentValues.timedHeadCell & this->textureColMask); + int coefXInt = (particlePreRenderData.m_ageDependentValues.timedHeadCell & this->textureColMask); float coefXf; if (coefXInt < 0) { coefXf = (float)((coefXInt & 1) | ((unsigned int)coefXInt >> 1)) + (float)((coefXInt & 1) | ((unsigned int)coefXInt >> 1)); @@ -1073,27 +1067,27 @@ ParticleEmitter::BuildQuadT3( mathfu::mat4 &inverseLookAt = this->inverseViewMatrix; for (int i = 0; i < 4; i++) { - - record.particle[i].position = ( inverseLookAt * mathfu::vec4( + auto &particleData = record.particle[i]; + particleData.position = ( inverseLookAt * mathfu::vec4( m0 * vxs[i] + m1 * vys[i] + viewPos, 1.0 )).xyz(); - record.particle[i].color = mathfu::vec4_packed(mathfu::vec4(color, alpha)); + particleData.color = mathfu::vec4_packed(mathfu::vec4(color, alpha)); - record.particle[i].textCoord0 = + particleData.textCoord0 = mathfu::vec2(txs[i] * this->texScaleX + texStartX, tys[i] * this->texScaleY + texStartY); - record.particle[i].textCoord1 = + particleData.textCoord1 = mathfu::vec2( txs[i] * paramXTransform(this->m_data->old.multiTextureParamX[0]) + texPos[0].x, tys[i] * paramXTransform(this->m_data->old.multiTextureParamX[0]) + texPos[0].y); - record.particle[i].textCoord2 = + particleData.textCoord2 = mathfu::vec2( txs[i] * paramXTransform(this->m_data->old.multiTextureParamX[1]) + texPos[1].x, tys[i] * paramXTransform(this->m_data->old.multiTextureParamX[1]) + texPos[1].y); - record.particle[i].alphaCutoff = alphaCutoff; + particleData.alphaCutoff = alphaCutoff; } } @@ -1124,10 +1118,21 @@ void ParticleEmitter::updateBuffers() { if (!currentFrame.active) return; +// +// if (szVertexCnt * sizeof(ParticleBuffStructQuad) > currentFrame.m_bufferVBO->getSize()) { +// std::cout << "Buffer miss match " << +// szVertexCnt * sizeof(ParticleBuffStructQuad) << +// " < " << +// currentFrame.m_bufferVBO->getSize() +// << std::endl; +// } // currentFrame.m_indexVBO->uploadData((void *) szIndexBuff.data(), (int) (szIndexBuff.size() * sizeof(uint16_t))); currentFrame.m_bufferVBO->save(szVertexCnt * sizeof(ParticleBuffStructQuad)); + + + currentFrame.m_mesh->setEnd(szVertexCnt * 6); currentFrame.m_mesh->setSortDistance(m_currentBonePos); } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.cpp b/wowViewerLib/src/engine/objects/ViewsObjects.cpp index eac41b354..35d0ff402 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.cpp +++ b/wowViewerLib/src/engine/objects/ViewsObjects.cpp @@ -12,18 +12,6 @@ #include "../algorithms/mathHelper_culling.h" void ExteriorView::collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) { - if (renderADT) { - for (auto const &adtMesh : this->m_adtOpaqueMeshes ) { - opaqueMeshCollector.addADTMesh(adtMesh); - } - } - - if (renderAdtLiquid) { - for (auto const &liquidMesh : this->liquidMeshes ) { - opaqueMeshCollector.addWaterMesh(liquidMesh); - } - } - GeneralView::collectMeshes(renderADT, renderAdtLiquid, renderWMO, opaqueMeshCollector, transparentMeshes); } diff --git a/wowViewerLib/src/engine/objects/ViewsObjects.h b/wowViewerLib/src/engine/objects/ViewsObjects.h index 49c6464d2..afd363f3c 100644 --- a/wowViewerLib/src/engine/objects/ViewsObjects.h +++ b/wowViewerLib/src/engine/objects/ViewsObjects.h @@ -53,8 +53,6 @@ class GeneralView { std::vector portals; - framebased::vector liquidMeshes = {}; - virtual void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); virtual void collectLights(std::vector &pointLights, std::vector &spotLights, std::vector> &newWmoLights); void collectPortalMeshes(framebased::vector &transparentMeshes); @@ -73,8 +71,6 @@ class InteriorView : public GeneralView { }; class ExteriorView : public GeneralView { -public: - std::vector m_adtOpaqueMeshes = {}; public: void collectMeshes(bool renderADT, bool renderAdtLiquid, bool renderWMO, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) override; }; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 771e35810..9e304a845 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -566,11 +566,12 @@ void AdtObject::loadAlphaTextures() { if (chunkMcalRuntime.uncompressedIndex) { _alpha[chunkMcalRuntime.uncompressedIndex] = - vec255 - - _alpha[0] - - _alpha[1] - - _alpha[2] - - _alpha[3]; + _mm_sub_epi8(_mm_sub_epi8( + _mm_sub_epi8( + _mm_sub_epi8(vec255,_alpha[0]), + _alpha[1]), + _alpha[2]), + _alpha[3]); } __m128i a_b_low = _mm_unpacklo_epi8(_alpha[0], _alpha[1]); //a_1 b_1 a_2 b_2 a_3 b_3 a_4 b_4 a_5 b_5 a_6 b_6 a_7 b_7 @@ -605,21 +606,20 @@ void AdtObject::loadAlphaTextures() { -void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, framebased::vector &transparentMeshes, int renderOrder) { +void AdtObject::collectMeshes(ADTObjRenderRes &adtRes, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes) { if (m_freeStrategy != nullptr) m_freeStrategy(false, true, m_mapApi->getCurrentSceneTime()); if (!m_loaded) return; size_t meshCount = adtMeshes.size(); - opaqueMeshes.reserve(opaqueMeshes.size() + adtMeshes.size()); transparentMeshes.reserve(transparentMeshes.size() + m_liquidInstancesPerChunk.size()); for (int i = 0; i < meshCount; i++) { if (adtRes.drawChunk[i] && (adtMeshes[i] != nullptr)) { - opaqueMeshes.emplace_back() = adtMeshes[i]; + opaqueMeshCollector.addADTMesh(adtMeshes[i]); } if (adtRes.drawWaterChunk[i]) { for (auto const &liquidInstance : m_liquidInstancesPerChunk[i]) { - liquidInstance->collectMeshes(transparentMeshes); + liquidInstance->collectMeshes(opaqueMeshCollector); } } } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.h b/wowViewerLib/src/engine/objects/adt/adtObject.h index c7039497f..34f656795 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.h +++ b/wowViewerLib/src/engine/objects/adt/adtObject.h @@ -26,7 +26,7 @@ class M2Object; typedef std::function FreeStrategy; class AdtObject; -enum class AdtObjectId : int; +enum class AdtObjectId : uintptr_t; extern EntityFactory<50, AdtObjectId, AdtObject> adtObjectFactory; class AdtObject : public ObjectWithId { public: @@ -47,7 +47,7 @@ class AdtObject : public ObjectWithId { FileStatus getLoadedStatus(); - void collectMeshes(ADTObjRenderRes &adtRes, std::vector &opaqueMeshes, framebased::vector &transparentMeshes, int renderOrder); + void collectMeshes(ADTObjRenderRes &adtRes, COpaqueMeshCollector &opaqueMeshCollector, framebased::vector &transparentMeshes); void collectMeshesLod(std::vector &renderedThisFrame); void update(animTime_t deltaTime); diff --git a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h index 27fee2d31..ae6a0de6e 100644 --- a/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h +++ b/wowViewerLib/src/engine/objects/liquid/LiquidInstance.h @@ -13,7 +13,7 @@ class IMapApi; class LiquidInstance; -enum class LiquidInstId : int; +enum class LiquidInstId : uintptr_t; extern EntityFactory<1000, LiquidInstId, LiquidInstance> liquidInstanceFactory; class LiquidInstance : public ObjectWithId { diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp index aa7d2daf2..258690a49 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.cpp @@ -93,31 +93,6 @@ void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Obje hmesh->setSortDistance(value); } -void M2MeshBufferUpdater::fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS) { - bool BCLoginScreenHack = m2Object.m_api->getConfig()->BCLightHack; -// int lightCount = (int) std::min(m2Object.lights.size(), (size_t) 4); -// for (int j = 0; j < lightCount; j++) { -// std::string uniformName; -// mathfu::vec4 attenVec; -// -// attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, m2Object.lights[j].diffuse_intensity, m2Object.lights[j].attenuation_end, m2Object.lights.size()); -// -// -// modelBlockPS.pc_lights[j].attenuation = attenVec;//;lights[i].diffuse_color); -// -// if (BCLoginScreenHack) { -// modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color ; -// } else { -// modelBlockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color * m2Object.lights[j].diffuse_intensity; -// } -// -//// mathfu::vec4 viewPos = modelView * m2Object.lights[j].position; -// modelBlockPS.pc_lights[j].position = m2Object.lights[j].position; -// } -// modelBlockPS.LightCount = lightCount; - modelBlockPS.bcHack = BCLoginScreenHack ? 1 : 0; -} - mathfu::mat4 M2MeshBufferUpdater::getTextureMatrix(const M2Object &m2Object, int textureMatIndex, M2Data *m2Data) { if (textureMatIndex < 0) return mathfu::mat4::Identity(); diff --git a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h index e30933f7b..642ed720a 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h +++ b/wowViewerLib/src/engine/objects/m2/m2Helpers/M2MeshBufferUpdater.h @@ -19,8 +19,6 @@ class M2MeshBufferUpdater { static void updateMaterialData(const std::shared_ptr &m2Material, M2Object *m2Object, M2Data * m2Data, M2SkinProfile * m2SkinProfile); - static void fillLights(const M2Object &m2Object, M2::modelWideBlockPS &modelBlockPS); - static mathfu::mat4 getTextureMatrix(const M2Object &m2Object, int textureMatIndex, M2Data *m2Data); static void getTextureMatrixIndexes(const M2Object &m2Object, int batchIndex, M2Data *m2Data, diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.cpp b/wowViewerLib/src/engine/objects/m2/m2Object.cpp index 2d39e7f4c..74f589806 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.cpp +++ b/wowViewerLib/src/engine/objects/m2/m2Object.cpp @@ -6,18 +6,9 @@ #include #include #include "m2Object.h" -#include "../../algorithms/mathHelper.h" -#include "../../managers/animationManager.h" #include "mathfu/matrix.h" -#include "../../persistance/header/M2FileHeader.h" -#include "../../../gapi/UniformBufferStructures.h" #include "m2Helpers/M2MeshBufferUpdater.h" -#include "../../../gapi/interface/IOcclusionQuery.h" -#include "../../../gapi/interface/IDevice.h" -#include "../../../gapi/interface/meshes/IM2Mesh.h" -#include "../../../gapi/interface/materials/IMaterial.h" - //Shader stuff enum class M2PixelShader : int { //Wotlk deprecated shaders @@ -730,8 +721,10 @@ uint8_t miniLogic(const CImVector *a2) { } void M2Object::setDiffuseColor(CImVector& value, float intensity) { + if (ImVectorToVec4(value) * intensity != this->m_localDiffuseColorV) { + m_modelWideDataChanged = true; + } this->m_localDiffuseColor = value; - this->m_localDiffuseColorV = ImVectorToVec4(value) * intensity; if (value.a != 255) { @@ -919,7 +912,6 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ this->initParticleEmitters(sceneRenderer); this->initRibbonEmitters(sceneRenderer); - this->status->m_loaded = true; this->status->m_geomLoaded = true; this->status->m_loading = false; @@ -932,20 +924,20 @@ void M2Object::doLoadGeom(const HMapSceneBufferCreate &sceneRenderer){ return; } +static const mathfu::mat4 particleCoordinatesFix = + mathfu::mat4( + 0,1,0,0, + -1,0,0,0, + 0,0,1,0, + 0,0,0,1 + ); + //deltaTime = miliseconds void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat) { if (!this->status->m_loaded) return; m_postLoadEvents.clear(); - static const mathfu::mat4 particleCoordinatesFix = - mathfu::mat4( - 0,1,0,0, - -1,0,0,0, - 0,0,1,0, - 0,0,0,1 - ); - if (m_boolSkybox && m_overrideSkyModelMat) { m_placementMatrix.GetColumn(3) = mathfu::vec4(cameraPos, 1.0); m_placementMatrixChanged = true; @@ -989,7 +981,6 @@ void M2Object::update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &v mathfu::vec4(mathfu::vec3(bounds.extent.max), 1.0f)); *this->aabb = worldAABB; - } @@ -1077,7 +1068,7 @@ void M2Object::fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sc } } -void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { +void M2Object::uploadBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { if (!this->status->m_loaded) return; // mathfu::mat4 modelViewMat = viewMat * m_placementMatrix; @@ -1094,14 +1085,14 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_placementMatrix->save(); m_placementMatrixChanged = false; } - if (bonesMatrices.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::bonesMatrices)]) { + if (!bonesMatrices.empty() && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::bonesMatrices)]) { auto &bonesData = m_modelWideDataBuff->m_bonesData->getObject(); int interCount = (int) std::min(bonesMatrices.size(), (size_t) MAX_MATRIX_NUM); std::copy(bonesMatrices.data(), bonesMatrices.data() + interCount, bonesData.uBoneMatrixes); m_modelWideDataBuff->m_bonesData->save(); } - if (subMeshColors.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::subMeshColors)]) { + if (!subMeshColors.empty() && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::subMeshColors)]) { auto &m2Colors = m_modelWideDataBuff->m_colors->getObject(); int m2ColorsCnt = (int) std::min(subMeshColors.size(), (size_t) MAX_M2COLORS_NUM); @@ -1109,7 +1100,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_colors->save(); } - if (transparencies.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::transparencies)]) { + if (!transparencies.empty() && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::transparencies)]) { auto &textureWeights = m_modelWideDataBuff->m_textureWeights->getObject(); int textureWeightsCnt = (int) std::min(transparencies.size(), (size_t) MAX_TEXTURE_WEIGHT_NUM); @@ -1117,7 +1108,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_textureWeights->save(); } - if (textAnimMatrices.size() > 0 && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::textAnimMatrices)]) { + if (!textAnimMatrices.empty() && dataIsChanged[EAnimDataTypeToInt(EAnimDataType::textAnimMatrices)]) { auto &textureMatrices = m_modelWideDataBuff->m_textureMatrices->getObject(); int textureMatricesCnt = (int) std::min(textAnimMatrices.size(), (size_t) MAX_TEXTURE_MATRIX_NUM); @@ -1125,6 +1116,7 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa m_modelWideDataBuff->m_textureMatrices->save(); } + if (m_modelWideDataChanged) { auto &modelFragmentData = m_modelWideDataBuff->m_modelFragmentData->getObject(); static mathfu::vec4 diffuseNon(0.0, 0.0, 0.0, 0.0); @@ -1148,13 +1140,18 @@ void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependa 0,0,0)); //Lights - M2MeshBufferUpdater::fillLights(*this, modelFragmentData); + + bool BCLoginScreenHack = m_api->getConfig()->BCLightHack; + modelFragmentData.bcHack = BCLoginScreenHack ? 1 : 0; + m_modelWideDataBuff->m_modelFragmentData->save(); + m_modelWideDataChanged = false; } //Manually update vertices for dynamics updateDynamicMeshes(); - +} +void M2Object::uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData) { int minParticle = m_api->getConfig()->minParticle; int maxParticle = std::min(m_api->getConfig()->maxParticle, (const int &) particleEmitters.size()); @@ -2051,6 +2048,8 @@ void M2Object::createVertexBindings(const HMapSceneBufferCreate &sceneRenderer) } void M2Object::updateDynamicMeshes() { + if (dynamicMeshes.empty()) return; + auto rootMatInverse = bonesMatrices[0].Inverse(); auto frameNum = m_api->hDevice->getCurrentProcessingFrameNumber() % IDevice::MAX_FRAMES_IN_FLIGHT; diff --git a/wowViewerLib/src/engine/objects/m2/m2Object.h b/wowViewerLib/src/engine/objects/m2/m2Object.h index e34ce069a..1da90b3eb 100644 --- a/wowViewerLib/src/engine/objects/m2/m2Object.h +++ b/wowViewerLib/src/engine/objects/m2/m2Object.h @@ -29,7 +29,7 @@ class M2ObjectListContainer; #include "../scenes/EntityActorsFactory.h" -enum class M2ObjId : int; +enum class M2ObjId : uintptr_t; struct M2LoadedStatus { bool m_loading = false; @@ -80,6 +80,7 @@ class M2Object : public ObjectWithId { private: mathfu::mat4 m_placementMatrix = mathfu::mat4::Identity(); bool m_placementMatrixChanged = false; + bool m_modelWideDataChanged = false; mathfu::mat4 m_placementInvertMatrix; mathfu::vec3 m_worldPosition; mathfu::vec3 m_localPosition; @@ -109,6 +110,7 @@ class M2Object : public ObjectWithId { float m_alpha = 1.0f; + bool m_animationRequired = false; bool animationOverrideActive = false; float animationOverridePercent = 0; @@ -260,9 +262,11 @@ class M2Object : public ObjectWithId { bool setUseLocalLighting(bool value) { if (m_useLocalDiffuseColor == -1) { m_useLocalDiffuseColor = value ? 1 : 0; + m_modelWideDataChanged = true; } if (value && m_useLocalDiffuseColor == 0) { m_useLocalDiffuseColor = 1; + m_modelWideDataChanged = true; } return m_useLocalDiffuseColor == 1; @@ -279,6 +283,7 @@ class M2Object : public ObjectWithId { void update(double deltaTime, mathfu::vec3 &cameraPos, mathfu::mat4 &viewMat); void collectLights(std::vector &pointLights); void fitParticleAndRibbonBuffersToSize(const HMapSceneBufferCreate &sceneRenderer); + void uploadBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); void uploadGeneratorBuffers(mathfu::mat4 &viewMat, const HFrameDependantData &frameDependantData); M2CameraResult updateCamera(double deltaTime, int cameraViewId); void drawDebugLight(); @@ -296,8 +301,11 @@ class M2Object : public ObjectWithId { mathfu::vec4 getM2SceneAmbientLight(); void setAmbientColorOverride(mathfu::vec4 &ambientColor, bool override) { - m_setAmbientColor = override; - m_ambientColorOverride = ambientColor; + if (m_setAmbientColor != override && m_ambientColorOverride != ambientColor) { + m_setAmbientColor = override; + m_ambientColorOverride = ambientColor; + m_modelWideDataChanged = true; + } } void drawParticles(COpaqueMeshCollector &opaqueMeshCollector, transp_vec &transparentMeshes, int renderOrder); @@ -332,9 +340,16 @@ inline const CAaBox &retrieveAABB<>(const std::shared_ptr &object) { return object->getAABB(); } +//TODO: In retrieveAABB, AABB can be null +static const CAaBox nonexitsting = CAaBox( + mathfu::vec3_packed(mathfu::vec3(999999, 999999, 999999)), + mathfu::vec3_packed(mathfu::vec3(-999999, -999999, -999999)) +); + template<> inline const CAaBox &retrieveAABB<>(const M2ObjId &objectId) { - return *m2Factory.getObjectById<1>(objectId); + auto * ptr = m2Factory.getObjectById<1>(objectId); + return ptr ? *ptr : nonexitsting; } diff --git a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h index 4655d6375..1da1529f4 100644 --- a/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h +++ b/wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h @@ -62,7 +62,7 @@ namespace EntityMemoryPool { template class EntityFactory { - + static_assert(sizeof(ObjIdType) == sizeof(uintptr_t)); static constexpr int ComponentAmount = sizeof...(Types); @@ -73,7 +73,7 @@ class EntityFactory { struct EttMemoryPoolGetter { using return_type = typename EttMemoryPoolGetter::return_type; - static const return_type &get(const EntityMemoryPool::EttMemoryPool &t) + static inline const return_type &get(const EntityMemoryPool::EttMemoryPool &t) { return EttMemoryPoolGetter::get(t); } @@ -82,7 +82,7 @@ class EntityFactory { struct EttMemoryPoolGetter<0, Head, Args...> { using return_type = EntityMemoryPool::EttMemoryPool; - static const return_type &get(const EntityMemoryPool::EttMemoryPool &t) + static const inline return_type &get(const EntityMemoryPool::EttMemoryPool &t) { return t; } @@ -91,7 +91,7 @@ class EntityFactory { EntityMemoryPool::EttMemoryPool m_combinedMemoryPool; template - const typename EttMemoryPoolGetter::return_type & + const inline typename EttMemoryPoolGetter::return_type & getMemoryPool() { return EttMemoryPoolGetter::get(m_combinedMemoryPool); @@ -103,13 +103,14 @@ class EntityFactory { m_combinedMemoryPool.expand(); }; - +private: template - typename EttMemoryPoolGetter::return_type::value_type * + inline typename EttMemoryPoolGetter::return_type::value_type * getPtrFromOffset(int offset) { return getMemoryPool().getPtrFromOffset(offset); } +public: // inline T * getPtrFromOffset(int offset) { // auto blockIndex = offset / BlockSize; @@ -146,7 +147,7 @@ class EntityFactory { }); } template - typename EttMemoryPoolGetter::return_type::value_type * + inline typename EttMemoryPoolGetter::return_type::value_type * getObjectById(ObjIdType id) { int index = (int)id; if ((index < 0)) @@ -155,6 +156,7 @@ class EntityFactory { return getPtrFromOffset((int)id); } +private: void deallocate(const OffsetAllocator::Allocation &alloc) { std::unique_lock lock(m_mutex); diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 24f9646bf..f36f5682d 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -522,15 +522,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams ZoneScopedN("collect m2 from groups"); exteriorView->addM2FromGroups(frustumData, cameraPos); } - - { - ZoneScopedN("adt mesh collect"); - for (auto &adtRes: mapRenderPlan->adtArray) { - adtRes.adtObject->collectMeshes(adtRes, exteriorView->m_adtOpaqueMeshes, - exteriorView->liquidMeshes, - exteriorView->renderOrder); - } - } { ZoneScopedN("m2AndWMOArr merge"); mapRenderPlan->m2Array.addDrawnAndToLoad(exteriorView->m2List); @@ -1532,22 +1523,23 @@ void Map::update(const HMapRenderPlan &renderPlan) { arena.execute([&] { tbb::affinity_partitioner ap; tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); - if (m2Object == nullptr) continue; - m2Object->update(deltaTime, cameraVec3, lookAtMat);\ - - std::vector localLights; - m2Object->collectLights(localLights); - if (!localLights.empty()) { - std::unique_lock lock(fillLights); - renderPlan->pointLights.insert( - renderPlan->pointLights.end(), - localLights.begin(),localLights.end()); - } - } - }, ap); + [&](tbb::blocked_range r) { + std::vector localLights; + + for (size_t i = r.begin(); i != r.end(); ++i) { + auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); + if (m2Object == nullptr) continue; + m2Object->update(deltaTime, cameraVec3, lookAtMat);\ + + m2Object->collectLights(localLights); + } + if (!localLights.empty()) { + std::unique_lock lock(fillLights); + renderPlan->pointLights.insert( + renderPlan->pointLights.end(), + localLights.begin(),localLights.end()); + } + }, ap); }); } @@ -1675,38 +1667,61 @@ void Map::updateBuffers(const HMapSceneBufferCreate &sceneRenderer, const HMapRe if (granSize == 0) granSize = m2ToDraw.size(); //Can't be paralleled? - auto &drawnM2s = renderPlan->m2Array.getDrawn(); - for (auto &m2ObjectId: drawnM2s) { - auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); - if (m2Object != nullptr) { - m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); + { + ZoneScopedN("fitParticleAndRibbonBuffersToSize"); + auto &drawnM2s = renderPlan->m2Array.getDrawn(); + for (auto &m2ObjectId: drawnM2s) { + auto m2Object = m2Factory.getObjectById<0>(m2ObjectId); + if (m2Object != nullptr) { + m2Object->fitParticleAndRibbonBuffersToSize(sceneRenderer); + } } } + auto updateLambda = [&](const std::function &callback) { + if (granSize > 0) { + auto l_device = m_api->hDevice; + auto oldProcessingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); + auto processingFrame = oldProcessingFrame; + oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); + arena.execute([&] { + tbb::affinity_partitioner ap; + tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), + [&](tbb::blocked_range r) { + l_device->setCurrentProcessingFrameNumber(processingFrame); + for (size_t i = r.begin(); i != r.end(); ++i) { + auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); + if (m2Object != nullptr) { + callback(m2Object); + } + } + }, ap); + }); + //Restore processing frame + l_device->setCurrentProcessingFrameNumber(oldProcessingFrame); + } + }; - if (granSize > 0) { - auto l_device = m_api->hDevice; - auto oldProcessingFrame = m_api->hDevice->getCurrentProcessingFrameNumber(); - auto processingFrame = oldProcessingFrame; - oneapi::tbb::task_arena arena(m_api->getConfig()->hardwareThreadCount(), 1); - arena.execute([&] { - tbb::affinity_partitioner ap; - tbb::parallel_for(tbb::blocked_range(0, m2ToDraw.size(), granSize), - [&](tbb::blocked_range r) { - l_device->setCurrentProcessingFrameNumber(processingFrame); - for (size_t i = r.begin(); i != r.end(); ++i) { - auto m2Object = m2Factory.getObjectById<0>(m2ToDraw[i]); - if (m2Object != nullptr) { - m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, - renderPlan->frameDependentData); - } - } - }, ap); + { + ZoneScopedN("upload Model buffers"); + + updateLambda([&renderPlan](M2Object *m2Object) { + m2Object->uploadBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); }); - //Restore processing frame - l_device->setCurrentProcessingFrameNumber(oldProcessingFrame); } + { + ZoneScopedN("upload generators buffers"); + + updateLambda([&renderPlan](M2Object *m2Object) { + m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, + renderPlan->frameDependentData); + }); + } + + + // for (auto &m2Object: renderPlan->m2Array.getDrawn()) { // if (m2Object != nullptr) { // m2Object->uploadGeneratorBuffers(renderPlan->renderingMatrices->lookAtMat, diff --git a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp index c782b564a..4d67d64da 100644 --- a/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp +++ b/wowViewerLib/src/engine/objects/wdl/wdlObject.cpp @@ -60,18 +60,22 @@ void WdlObject::loadM2s() { for (int l = mssn_rec.mssoIndex; l < mssn_rec.mssoIndex+mssn_rec.mssoRecordsNum; l++) { auto &msso_rec = m_wdlFile->m_msso[l]; + uint64_t mssf_val = 0; + if (msso_rec.flags.unk_0x1) { + mssf_val = m_wdlFile->m_mssf[msso_rec.mssf_index]; + } + + if (m_wdlFile->m_msli) { + auto msliIndex = m_wdlFile->m_msli[l]; + if (msliIndex != -1) { + auto &msld = m_wdlFile->m_msld[msliIndex]; + //std::cout << msld.timeEnd0 << " " << mssf_val; + } + } auto m2Object = m2Factory.createObject(m_api, false, false); m2Object->setLoadParams(0, {}, {}); m2Object->setModelFileId(msso_rec.fileDataID); -// std::cout << "fileDataID = " << msso_rec.fileDataID << std::endl; -// std::cout << "translateVec.x = " << msso_rec.translateVec.x << std::endl; -// std::cout << "translateVec.y = " << msso_rec.translateVec.y << std::endl; -// std::cout << "translateVec.z = " << msso_rec.translateVec.z << std::endl; -// std::cout << "rotationInRads.x = " << msso_rec.rotationInRads.x << std::endl; -// std::cout << "rotationInRads.y = " << msso_rec.rotationInRads.y << std::endl; -// std::cout << "rotationInRads.z = " << msso_rec.rotationInRads.z << std::endl; -// std::cout << "scale = " << msso_rec.scale << std::endl; constexpr float degreeToRad = M_PI/180.0f; @@ -79,9 +83,6 @@ void WdlObject::loadM2s() { rotationMatrix *= MathHelper::RotationY(msso_rec.rotationInDegree.x*degreeToRad); rotationMatrix *= MathHelper::RotationX(msso_rec.rotationInDegree.y*degreeToRad); -// auto quat = mathfu::quat::FromMatrix(rotationMatrix); -// auto rotationMatrix1 = quat.ToMatrix4(); - m2Object->createPlacementMatrix( mathfu::vec3(msso_rec.translateVec.x, msso_rec.translateVec.y, msso_rec.translateVec.z), 0, diff --git a/wowViewerLib/src/engine/objects/wmo/wmoObject.h b/wowViewerLib/src/engine/objects/wmo/wmoObject.h index 4d3c1fe13..6a9d99159 100644 --- a/wowViewerLib/src/engine/objects/wmo/wmoObject.h +++ b/wowViewerLib/src/engine/objects/wmo/wmoObject.h @@ -25,7 +25,7 @@ class WmoGroupObject; #include "../SceneObjectWithID.h" #include "../lights/CWmoNewLight.h" -enum class WMOObjId : int; +enum class WMOObjId : uintptr_t; constexpr WMOObjId emptyWMO = static_cast(0xFFFFFFF); class WmoObject : public IWmoApi, public ObjectWithId{ diff --git a/wowViewerLib/src/engine/persistance/header/wdlHeader.h b/wowViewerLib/src/engine/persistance/header/wdlHeader.h index 932f09b17..f199f3da2 100644 --- a/wowViewerLib/src/engine/persistance/header/wdlHeader.h +++ b/wowViewerLib/src/engine/persistance/header/wdlHeader.h @@ -53,6 +53,18 @@ struct mssc_t uint32_t conditionValue; }; +struct msld_t +{ + uint32_t unk_0; + uint32_t unk_1; + uint32_t unk_2; + uint32_t unk_3; + uint32_t timeStart0; + uint32_t timeStart1; + uint32_t timeEnd0; + uint32_t timeEnd1; +}; + #endif //AWEBWOWVIEWERCPP_WDLHEADER_H diff --git a/wowViewerLib/src/engine/persistance/wdlFile.cpp b/wowViewerLib/src/engine/persistance/wdlFile.cpp index fbca5e306..842167ddd 100644 --- a/wowViewerLib/src/engine/persistance/wdlFile.cpp +++ b/wowViewerLib/src/engine/persistance/wdlFile.cpp @@ -52,7 +52,8 @@ chunkDef WdlFile::wdlFileTable = { chunkData.readValues(file.m_mssn, file.m_mssn_len); } } - }, { + }, + { 'MSSC', { [](WdlFile& file, ChunkData& chunkData){ @@ -63,6 +64,40 @@ chunkDef WdlFile::wdlFileTable = { chunkData.readValues(file.m_mssc, file.m_mssc_len); } } + }, + { + 'MSLI', + { + [](WdlFile& file, ChunkData& chunkData){ + debuglog("Entered MSLI"); + + file.m_msli_len = chunkData.chunkLen / sizeof(uint32_t); + + chunkData.readValues(file.m_msli, file.m_msli_len); + } + } + }, + { + 'MSLD', + { + [](WdlFile& file, ChunkData& chunkData){ + debuglog("Entered MSLD"); + + file.m_msld_len = chunkData.chunkLen / sizeof(msld_t); + + chunkData.readValues(file.m_msld, file.m_msld_len); + } + } + }, + { + 'MSSF', + { + [](WdlFile& file, ChunkData& chunkData){ + debuglog("Entered MSSF"); + + chunkData.readValues(file.m_mssf, chunkData.chunkLen/8); + } + } } } }; diff --git a/wowViewerLib/src/engine/persistance/wdlFile.h b/wowViewerLib/src/engine/persistance/wdlFile.h index 7862648e7..04bfaa2f8 100644 --- a/wowViewerLib/src/engine/persistance/wdlFile.h +++ b/wowViewerLib/src/engine/persistance/wdlFile.h @@ -37,6 +37,14 @@ class WdlFile : public PersistentFile { mssc_t *m_mssc = nullptr; int m_mssc_len = -1; + uint32_t *m_msli = nullptr; + int m_msli_len = -1; + + msld_t *m_msld = nullptr; + int m_msld_len = -1; + + uint64_t *m_mssf = nullptr; + private: HFileContent m_wdlFile; diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index 7e566ba27..af619dbd8 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -66,7 +66,8 @@ class gMeshTemplate { std::array scissorSize = {0,0}; }; -enum class GMeshId : int; +enum class GMeshId : uintptr_t; + class IMesh : public ObjectWithId { friend class IDevice; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 9cee0b8b0..da266895c 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -53,6 +53,13 @@ void MapSceneRenderer::collectMeshes(const std::shared_ptr &rende if (exteriorView != nullptr) { ZoneScopedN("Collect Exterior"); exteriorView->collectMeshes(renderADT, true, renderWMO, opaqueMeshCollector, transparentMeshes); + + { + ZoneScopedN("adt mesh collect"); + for (auto &adtRes: renderPlan->adtArray) { + adtRes.adtObject->collectMeshes(adtRes, opaqueMeshCollector, transparentMeshes); + } + } } } diff --git a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp index 45e0b0315..79661ab1a 100644 --- a/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp +++ b/wowViewerLib/src/renderer/mapScene/vulkan/MapSceneRenderBindlessVLK.cpp @@ -362,8 +362,8 @@ void MapSceneRenderBindlessVLK::createWaterGlobalMaterialData() { pipelineTemplate.element = DrawElementMode::TRIANGLES; pipelineTemplate.depthWrite = true; pipelineTemplate.depthCulling = true; - pipelineTemplate.backFaceCulling = true; - pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Opaque; + pipelineTemplate.backFaceCulling = false; + pipelineTemplate.blendMode = EGxBlendEnum::GxBlend_Alpha; //Create global water descriptor for bindless textures g_waterMaterial = MaterialBuilderVLK::fromShader(m_device, {"waterShader", "waterShader"}, waterBindlessShaderConfig, {{0, sceneWideDS}}) @@ -1097,7 +1097,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ framebased::vector m2DrawVec; framebased::vector wmoDrawVec; - MeshMap waterMeshMap; + framebased::vector waterMeshVec; framebased::vector adtDrawVec; framebased::vector commonMeshes; @@ -1119,7 +1119,9 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ } inline static void fillMapWithMesh(MeshMap &meshMap, const HGMesh &mesh) { - const auto &meshVlk = (GMeshVLK*) mesh.get(); + auto meshId = mesh->getObjectId(); + const auto meshVlk = bindlessMeshFactoryVlk.getObjectById<0>(meshId); +// const auto &meshVlk = (GMeshVLK*) mesh.get(); auto const &pipeline = meshVlk->material()->getPipeline(); auto &vec = meshMap[pipeline]; @@ -1153,7 +1155,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ addDrawCommand(wmoDrawVec, mesh); } ; void addWaterMesh(const HGMesh &mesh) override { - fillMapWithMesh(waterMeshMap, mesh); + addDrawCommand(waterMeshVec, mesh); } ; void addADTMesh(const HGMesh &mesh) override { addDrawCommand(adtDrawVec, mesh); @@ -1174,7 +1176,7 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ wmoDrawVec.insert(wmoDrawVec.end(), l_collector.wmoDrawVec.begin(), l_collector.wmoDrawVec.end()); adtDrawVec.insert(adtDrawVec.end(), l_collector.adtDrawVec.begin(), l_collector.adtDrawVec.end()); commonMeshes.insert(commonMeshes.end(), l_collector.commonMeshes.begin(), l_collector.commonMeshes.end()); - waterMeshMap.insert(l_collector.waterMeshMap.begin(), l_collector.waterMeshMap.end()); + waterMeshVec.insert(waterMeshVec.end(), l_collector.waterMeshVec.begin(), l_collector.waterMeshVec.end()); } void render(CmdBufRecorder &cmdBuf, CmdBufRecorder::ViewportType viewPortType) { @@ -1250,18 +1252,17 @@ class COpaqueMeshCollectorBindlessVLK : public COpaqueMeshCollector{ cmdBuf.setDefaultScissors(); cmdBuf.setViewPort(viewPortType); - if (!waterMeshMap.empty()) + if (!waterMeshVec.empty()) { //4. Render water cmdBuf.bindVertexBindings(m_renderer.getDefaultWaterVao()); - cmdBuf.bindMaterial(m_renderer.getGlobalWaterMaterial()); + auto const &gWaterMat = m_renderer.getGlobalWaterMaterial(); - for (auto const &record : waterMeshMap) { - cmdBuf.bindPipeline(record.first); + cmdBuf.bindMaterial(gWaterMat); + cmdBuf.bindPipeline(gWaterMat->getPipeline()); - for (auto const & drawCmd : record.second) { - cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); - } + for (auto const &drawCmd : waterMeshVec) { + cmdBuf.drawIndexed(drawCmd.indexCount, drawCmd.instanceCount, drawCmd.firstIndex, drawCmd.firstInstance, drawCmd.vertexOffset); } } } From a61065c1ee8c0197d12db662157eba1e091a5886 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 29 Jun 2024 23:23:21 +0300 Subject: [PATCH 199/212] fix --- .../src/engine/shader/ShaderDefinitions.h | 1091 ----------------- 1 file changed, 1091 deletions(-) delete mode 100644 wowViewerLib/src/engine/shader/ShaderDefinitions.h diff --git a/wowViewerLib/src/engine/shader/ShaderDefinitions.h b/wowViewerLib/src/engine/shader/ShaderDefinitions.h deleted file mode 100644 index bdaea4dc3..000000000 --- a/wowViewerLib/src/engine/shader/ShaderDefinitions.h +++ /dev/null @@ -1,1091 +0,0 @@ -#ifndef WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H -#define WOWMAPVIEWERREVIVED_SHADERDEFINITIONS_H - -#include -#include -#include -#include -#include - -template -inline constexpr const uint32_t operator+ (T const val) { return static_cast(val); }; -struct fieldDefine { - std::string name; - bool isFloat ; - int offset; - int columns; - int vecSize; - int arraySize; -}; -struct attributeDefine { - std::string name; - int location; -}; -struct uboBindingData { - int set; - int binding; - int size; -}; - -struct shaderMetaData { - std::vector uboBindings; -}; - -//Per file -extern const std::unordered_map shaderMetaInfo; -extern const std::unordered_map> attributesPerShaderName; -extern const std::unordered_map>> fieldDefMapPerShaderNameVert; -extern const std::unordered_map>> fieldDefMapPerShaderNameFrag; -struct waterfallShader { - enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, waterfallShaderAttributeEnd - }; -}; - -struct adtLodShader { - enum class Attribute { - aHeight = 0, aIndex = 1, adtLodShaderAttributeEnd - }; -}; - -struct adtShader { - enum class Attribute { - aHeight = 0, aColor = 1, aVertexLighting = 2, aNormal = 3, aIndex = 4, adtShaderAttributeEnd - }; -}; - -struct drawBBShader { - enum class Attribute { - aPosition = 0, drawBBShaderAttributeEnd - }; -}; - -struct waterShader { - enum class Attribute { - aPositionTransp = 0, aTexCoord = 1, waterShaderAttributeEnd - }; -}; - -struct m2ParticleShader { - enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, aTexcoord1 = 3, aTexcoord2 = 4, aAlphaCutoff = 5, m2ParticleShaderAttributeEnd - }; -}; - -struct drawFrustumShader { - enum class Attribute { - aPosition = 0, drawFrustumShaderAttributeEnd - }; -}; - -struct drawPoints { - enum class Attribute { - aPosition = 0, drawPointsAttributeEnd - }; -}; - -struct drawQuad { - enum class Attribute { - position = 0, drawQuadAttributeEnd - }; -}; - -struct skyConus { - enum class Attribute { - aPosition = 0, skyConusAttributeEnd - }; -}; - -struct m2Shader { - enum class Attribute { - aPosition = 0, aNormal = 1, bones = 2, boneWeights = 3, aTexCoord = 4, aTexCoord2 = 5, m2ShaderAttributeEnd - }; -}; - -struct drawPortalShader { - enum class Attribute { - aPosition = 0, drawPortalShaderAttributeEnd - }; -}; - -struct renderFrameBufferShader { - enum class Attribute { - a_position = 0, renderFrameBufferShaderAttributeEnd - }; -}; - -struct wmoShader { - enum class Attribute { - aPosition = 0, aNormal = 1, aTexCoord = 2, aTexCoord2 = 3, aTexCoord3 = 4, aTexCoord4 = 5, aColor = 6, aColor2 = 7, aColorSecond = 8, wmoShaderAttributeEnd - }; -}; - -struct imguiShader { - enum class Attribute { - Position = 0, UV = 1, Color = 2, imguiShaderAttributeEnd - }; -}; - -struct drawLinesShader { - enum class Attribute { - aPosition = 0, drawLinesShaderAttributeEnd - }; -}; - -struct ribbonShader { - enum class Attribute { - aPosition = 0, aColor = 1, aTexcoord0 = 2, ribbonShaderAttributeEnd - }; -}; - -std::string loadShader(std::string shaderName); -#ifdef SHADERDATACPP -const std::unordered_map> attributesPerShaderName = { -{"waterfallShader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"bones", 2}, -{"boneWeights", 3}, -{"aTexCoord", 4}, -{"aTexCoord2", 5}, -}},{"adtLodShader", { -{"aHeight", 0}, -{"aIndex", 1}, -}},{"adtShader", { -{"aHeight", 0}, -{"aColor", 1}, -{"aVertexLighting", 2}, -{"aNormal", 3}, -{"aIndex", 4}, -}},{"drawBBShader", { -{"aPosition", 0}, -}},{"waterShader", { -{"aPositionTransp", 0}, -{"aTexCoord", 1}, -}},{"m2ParticleShader", { -{"aPosition", 0}, -{"aColor", 1}, -{"aTexcoord0", 2}, -{"aTexcoord1", 3}, -{"aTexcoord2", 4}, -{"aAlphaCutoff", 5}, -}},{"drawFrustumShader", { -{"aPosition", 0}, -}},{"drawPoints", { -{"aPosition", 0}, -}},{"drawQuad", { -{"position", 0}, -}},{"skyConus", { -{"aPosition", 0}, -}},{"m2Shader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"bones", 2}, -{"boneWeights", 3}, -{"aTexCoord", 4}, -{"aTexCoord2", 5}, -}},{"drawPortalShader", { -{"aPosition", 0}, -}},{"renderFrameBufferShader", { -{"a_position", 0}, -}},{"wmoShader", { -{"aPosition", 0}, -{"aNormal", 1}, -{"aTexCoord", 2}, -{"aTexCoord2", 3}, -{"aTexCoord3", 4}, -{"aTexCoord4", 5}, -{"aColor", 6}, -{"aColor2", 7}, -{"aColorSecond", 8}, -}},{"imguiShader", { -{"Position", 0}, -{"UV", 1}, -{"Color", 2}, -}},{"drawLinesShader", { -{"aPosition", 0}, -}},{"ribbonShader", { -{"aPosition", 0}, -{"aColor", 1}, -{"aTexcoord0", 2}, -}},}; - -const std::unordered_map shaderMetaInfo = {{ "wmoShader.vert.spv", { -{ -{0,1,64}, -{0,0,368}, -{0,2,16}, -} -} -},{ "wmoShader.frag.spv", { -{ -{0,3,32}, -{0,0,368}, -{0,4,32}, -} -} -},{ "waterShader.frag.spv", { -{ -{0,4,16}, -{0,0,368}, -} -} -},{ "waterfallShader.frag.spv", { -{ -{0,4,96}, -{0,0,368}, -{0,1,14144}, -} -} -},{ "adtShader.vert.spv", { -{ -{0,0,368}, -{0,2,16}, -} -} -},{ "adtLodShader.vert.spv", { -{ -{0,0,144}, -} -} -},{ "waterfallShader.vert.spv", { -{ -{0,2,144}, -{0,1,14144}, -{0,0,368}, -} -} -},{ "drawPoints.vert.spv", { -{ -{0,0,128}, -{0,1,64}, -} -} -},{ "drawFrustumShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ffxglow.frag.spv", { -{ -{0,4,16}, -} -} -},{ "adtShader.frag.spv", { -{ -{0,4,288}, -{0,3,16}, -{0,0,368}, -} -} -},{ "drawBBShader.vert.spv", { -{ -{0,1,112}, -{0,0,368}, -} -} -},{ "drawFrustumShader.frag.spv", { -{ -{0,2,12}, -} -} -},{ "drawDepthShader.frag.spv", { -{ -{0,2,12}, -} -} -},{ "adtLodShader.frag.spv", { -{ -{0,0,84}, -} -} -},{ "drawPoints.frag.spv", { -{ -{0,1,12}, -} -} -},{ "drawBBShader.frag.spv", { -{ -{0,1,112}, -} -} -},{ "drawLinesShader.frag.spv", { -{ -{0,1,12}, -} -} -},{ "skyConus.frag.spv", { -{ -} -} -},{ "drawPortalShader.frag.spv", { -{ -{0,4,16}, -} -} -},{ "drawLinesShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ffxgauss4.frag.spv", { -{ -{0,4,32}, -} -} -},{ "imguiShader.frag.spv", { -{ -} -} -},{ "m2ParticleShader.vert.spv", { -{ -{0,0,368}, -} -} -},{ "drawQuad.vert.spv", { -{ -{0,2,16}, -} -} -},{ "imguiShader.vert.spv", { -{ -{0,1,80}, -} -} -},{ "m2Shader.frag.spv", { -{ -{0,4,64}, -{0,3,256}, -{0,0,368}, -{0,1,14144}, -} -} -},{ "waterShader.vert.spv", { -{ -{0,0,368}, -{0,1,64}, -} -} -},{ "drawPortalShader.vert.spv", { -{ -{0,0,128}, -} -} -},{ "ribbonShader.vert.spv", { -{ -{0,0,368}, -} -} -},{ "skyConus.vert.spv", { -{ -{0,0,368}, -{0,2,96}, -} -} -},{ "renderFrameBufferShader.frag.spv", { -{ -{0,2,168}, -} -} -},{ "renderFrameBufferShader.vert.spv", { -{ -} -} -},{ "m2ParticleShader.frag.spv", { -{ -{0,4,48}, -{0,0,368}, -} -} -},{ "m2Shader.vert.spv", { -{ -{0,1,14144}, -{0,2,160}, -{0,0,368}, -} -} -},{ "ribbonShader.frag.spv", { -{ -{0,4,48}, -{0,0,368}, -} -} -},}; - -const std::unordered_map>> fieldDefMapPerShaderNameVert = { - {"waterfallShader", { - { - 0, { - {"_199_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_199_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_199_scene_uViewUp", true, 128, 1, 4, 0}, - {"_199_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_199_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_199_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_199_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_199_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_199_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_199_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_199_fogData_densityParams", true, 256, 1, 4, 0}, - {"_199_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_199_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_199_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_199_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_199_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_199_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 1, { - {"_104_uPlacementMat", true, 0, 4, 4, 0}, - {"_104_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - { - 2, { - {"_55_bumpScale", true, 0, 1, 4, 0}, - {"_55_uTextMat[0]", true, 16, 4, 4, 2}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_55_uPos", true, 0, 1, 3, 0}, - {"_55_uLookAtMat", true, 16, 4, 4, 0}, - {"_55_uPMatrix", true, 80, 4, 4, 0}, - } - }, - }}, - {"adtShader", { - { - 2, { - {"_139_uPos", true, 0, 1, 4, 0}, - } - }, - { - 0, { - {"_91_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_91_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_91_scene_uViewUp", true, 128, 1, 4, 0}, - {"_91_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_91_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_91_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_91_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_91_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_91_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_91_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_91_fogData_densityParams", true, 256, 1, 4, 0}, - {"_91_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_91_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_91_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_91_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_91_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_91_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - }}, - {"drawBBShader", { - { - 0, { - {"_62_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_62_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_62_scene_uViewUp", true, 128, 1, 4, 0}, - {"_62_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_62_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_62_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_62_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_62_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_62_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_62_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_62_fogData_densityParams", true, 256, 1, 4, 0}, - {"_62_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_62_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_62_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_62_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_62_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_62_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 1, { - {"_21_uPlacementMat", true, 0, 4, 4, 0}, - {"_21_uBBScale", true, 64, 1, 4, 0}, - {"_21_uBBCenter", true, 80, 1, 4, 0}, - {"_21_uColor", true, 96, 1, 4, 0}, - } - }, - }}, - {"waterShader", { - { - 1, { - {"_36_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - { - 0, { - {"_28_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_28_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_28_scene_uViewUp", true, 128, 1, 4, 0}, - {"_28_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_28_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_28_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_28_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_28_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_28_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_28_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_28_fogData_densityParams", true, 256, 1, 4, 0}, - {"_28_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_28_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_28_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_28_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_28_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_28_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - }}, - {"m2ParticleShader", { - { - 0, { - {"_43_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_43_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_43_scene_uViewUp", true, 128, 1, 4, 0}, - {"_43_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_43_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_43_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_43_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_43_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_43_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_43_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_43_fogData_densityParams", true, 256, 1, 4, 0}, - {"_43_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_43_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_43_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_43_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_43_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_43_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - }}, - {"drawFrustumShader", { - { - 0, { - {"_13_uLookAtMat", true, 0, 4, 4, 0}, - {"_13_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawPoints", { - { - 1, { - {"_29_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - { - 0, { - {"_19_uLookAtMat", true, 0, 4, 4, 0}, - {"_19_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"drawQuad", { - { - 2, { - {"_12_uWidth_uHeight_uX_uY", true, 0, 1, 4, 0}, - } - }, - }}, - {"skyConus", { - { - 2, { - {"_67_skyColor[0]", true, 0, 1, 4, 6}, - } - }, - { - 0, { - {"_26_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_26_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_26_scene_uViewUp", true, 128, 1, 4, 0}, - {"_26_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_26_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_26_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_26_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_26_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_26_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_26_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_26_fogData_densityParams", true, 256, 1, 4, 0}, - {"_26_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_26_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_26_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_26_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_26_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_26_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - }}, - {"m2Shader", { - { - 0, { - {"_203_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_203_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_203_scene_uViewUp", true, 128, 1, 4, 0}, - {"_203_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_203_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_203_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_203_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_203_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_203_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_203_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_203_fogData_densityParams", true, 256, 1, 4, 0}, - {"_203_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_203_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_203_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_203_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_203_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_203_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 2, { - {"_193_vertexShader_IsAffectedByLight", false, 0, 1, 4, 0}, - {"_193_color_Transparency", true, 16, 1, 4, 0}, - {"_193_uTextMat[0]", true, 32, 4, 4, 2}, - } - }, - { - 1, { - {"_93_uPlacementMat", true, 0, 4, 4, 0}, - {"_93_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - }}, - {"drawPortalShader", { - { - 0, { - {"_30_uLookAtMat", true, 0, 4, 4, 0}, - {"_30_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"renderFrameBufferShader", { - }}, - {"wmoShader", { - { - 2, { - {"_139_VertexShader_UseLitColor", false, 0, 1, 4, 0}, - } - }, - { - 0, { - {"_71_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_71_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_71_scene_uViewUp", true, 128, 1, 4, 0}, - {"_71_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_71_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_71_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_71_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_71_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_71_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_71_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_71_fogData_densityParams", true, 256, 1, 4, 0}, - {"_71_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_71_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_71_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_71_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_71_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_71_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 1, { - {"_51_uPlacementMat", true, 0, 4, 4, 0}, - } - }, - }}, - {"imguiShader", { - { - 1, { - {"_30_ProjMtx", true, 0, 4, 4, 0}, - {"_30_uiScale", true, 64, 1, 4, 0}, - } - }, - }}, - {"drawLinesShader", { - { - 0, { - {"_19_uLookAtMat", true, 0, 4, 4, 0}, - {"_19_uPMatrix", true, 64, 4, 4, 0}, - } - }, - }}, - {"ribbonShader", { - { - 0, { - {"_37_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_37_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_37_scene_uViewUp", true, 128, 1, 4, 0}, - {"_37_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_37_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_37_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_37_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_37_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_37_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_37_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_37_fogData_densityParams", true, 256, 1, 4, 0}, - {"_37_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_37_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_37_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_37_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_37_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_37_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - }}, -}; -const std::unordered_map>> fieldDefMapPerShaderNameFrag = { - {"waterfallShader", { - { - 1, { - {"_818_uPlacementMat", true, 0, 4, 4, 0}, - {"_818_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - { - 0, { - {"_709_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_709_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_709_scene_uViewUp", true, 128, 1, 4, 0}, - {"_709_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_709_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_709_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_709_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_709_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_709_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_709_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_709_fogData_densityParams", true, 256, 1, 4, 0}, - {"_709_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_709_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_709_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_709_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_709_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_709_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 4, { - {"_445_values0", true, 0, 1, 4, 0}, - {"_445_values1", true, 16, 1, 4, 0}, - {"_445_values2", true, 32, 1, 4, 0}, - {"_445_values3", true, 48, 1, 4, 0}, - {"_445_values4", true, 64, 1, 4, 0}, - {"_445_baseColor", true, 80, 1, 4, 0}, - } - }, - }}, - {"adtLodShader", { - { - 0, { - {"_65_uViewUp", true, 0, 1, 4, 0}, - {"_65_uSunDir_FogStart", true, 16, 1, 4, 0}, - {"_65_uSunColor_uFogEnd", true, 32, 1, 4, 0}, - {"_65_uAmbientLight", true, 48, 1, 4, 0}, - {"_65_FogColor", true, 64, 1, 4, 0}, - {"_65_uNewFormula", false, 80, 1, 1, 0}, - } - }, - }}, - {"renderFrameBufferShader", { - { - 2, { - {"_34_gauss_offsets[0]", true, 0, 1, 1, 5}, - {"_34_gauss_weights[0]", true, 80, 1, 1, 5}, - {"_34_uResolution", true, 160, 1, 2, 0}, - } - }, - }}, - {"drawPortalShader", { - { - 4, { - {"_12_uColor", true, 0, 1, 4, 0}, - } - }, - }}, - {"adtShader", { - { - 0, { - {"_748_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_748_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_748_scene_uViewUp", true, 128, 1, 4, 0}, - {"_748_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_748_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_748_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_748_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_748_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_748_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_748_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_748_fogData_densityParams", true, 256, 1, 4, 0}, - {"_748_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_748_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_748_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_748_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_748_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_748_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 3, { - {"_506_uUseHeightMixFormula", false, 0, 1, 4, 0}, - } - }, - { - 4, { - {"_466_uHeightScale", true, 0, 1, 4, 0}, - {"_466_uHeightOffset", true, 16, 1, 4, 0}, - {"_466_animationMat[0]", true, 32, 4, 4, 4}, - } - }, - }}, - {"drawBBShader", { - { - 1, { - {"_13_uPlacementMat", true, 0, 4, 4, 0}, - {"_13_uBBScale", true, 64, 1, 4, 0}, - {"_13_uBBCenter", true, 80, 1, 4, 0}, - {"_13_uColor", true, 96, 1, 4, 0}, - } - }, - }}, - {"ribbonShader", { - { - 0, { - {"_304_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_304_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_304_scene_uViewUp", true, 128, 1, 4, 0}, - {"_304_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_304_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_304_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_304_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_304_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_304_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_304_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_304_fogData_densityParams", true, 256, 1, 4, 0}, - {"_304_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_304_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_304_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_304_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_304_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_304_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 4, { - {"_256_uAlphaTestScalev", true, 0, 1, 4, 0}, - {"_256_uPixelShaderv", false, 16, 1, 4, 0}, - {"_256_uTextureTranslate", true, 32, 1, 4, 0}, - } - }, - }}, - {"drawLinesShader", { - { - 1, { - {"_19_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"waterShader", { - { - 0, { - {"_277_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_277_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_277_scene_uViewUp", true, 128, 1, 4, 0}, - {"_277_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_277_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_277_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_277_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_277_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_277_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_277_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_277_fogData_densityParams", true, 256, 1, 4, 0}, - {"_277_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_277_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_277_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_277_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_277_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_277_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 4, { - {"_253_color", true, 0, 1, 4, 0}, - } - }, - }}, - {"m2ParticleShader", { - { - 0, { - {"_493_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_493_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_493_scene_uViewUp", true, 128, 1, 4, 0}, - {"_493_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_493_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_493_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_493_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_493_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_493_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_493_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_493_fogData_densityParams", true, 256, 1, 4, 0}, - {"_493_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_493_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_493_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_493_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_493_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_493_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 4, { - {"_277_uAlphaTestv", true, 0, 1, 4, 0}, - {"_277_uPixelShaderBlendModev", false, 16, 1, 4, 0}, - {"_277_uTextureTranslate", true, 32, 1, 4, 0}, - } - }, - }}, - {"drawDepthShader", { - { - 2, { - {"_10_drawDepth", false, 0, 1, 1, 0}, - {"_10_uFarPlane", true, 4, 1, 1, 0}, - {"_10_uNearPlane", true, 8, 1, 1, 0}, - } - }, - }}, - {"drawPoints", { - { - 1, { - {"_13_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"drawFrustumShader", { - { - 2, { - {"_22_uColor", true, 0, 1, 3, 0}, - } - }, - }}, - {"ffxgauss4", { - { - 4, { - {"_36_texOffsetX", true, 0, 1, 4, 0}, - {"_36_texOffsetY", true, 16, 1, 4, 0}, - } - }, - }}, - {"skyConus", { - }}, - {"m2Shader", { - { - 1, { - {"_543_uPlacementMat", true, 0, 4, 4, 0}, - {"_543_uBoneMatrixes[0]", true, 64, 4, 4, 220}, - } - }, - { - 0, { - {"_535_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_535_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_535_scene_uViewUp", true, 128, 1, 4, 0}, - {"_535_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_535_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_535_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_535_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_535_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_535_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_535_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_535_fogData_densityParams", true, 256, 1, 4, 0}, - {"_535_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_535_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_535_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_535_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_535_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_535_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 3, { - {"_496_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_496_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - {"_496_pc_lights[0].color", true, 32, 1, 4, 0}, - {"_496_pc_lights[0].position", true, 48, 1, 4, 0}, - {"_496_pc_lights[0].attenuation", true, 64, 1, 4, 0}, - {"_496_pc_lights[1].color", true, 80, 1, 4, 0}, - {"_496_pc_lights[1].position", true, 96, 1, 4, 0}, - {"_496_pc_lights[1].attenuation", true, 112, 1, 4, 0}, - {"_496_pc_lights[2].color", true, 128, 1, 4, 0}, - {"_496_pc_lights[2].position", true, 144, 1, 4, 0}, - {"_496_pc_lights[2].attenuation", true, 160, 1, 4, 0}, - {"_496_pc_lights[3].color", true, 176, 1, 4, 0}, - {"_496_pc_lights[3].position", true, 192, 1, 4, 0}, - {"_496_pc_lights[3].attenuation", true, 208, 1, 4, 0}, - {"_496_lightCountAndBcHack", false, 224, 1, 4, 0}, - {"_496_interiorExteriorBlend", true, 240, 1, 4, 0}, - } - }, - { - 4, { - {"_473_PixelShader_UnFogged_IsAffectedByLight_blendMode", false, 0, 1, 4, 0}, - {"_473_uFogColorAndAlphaTest", true, 16, 1, 4, 0}, - {"_473_uTexSampleAlpha", true, 32, 1, 4, 0}, - {"_473_uPcColor", true, 48, 1, 4, 0}, - } - }, - }}, - {"ffxglow", { - { - 4, { - {"_34_blurAmount", true, 0, 1, 4, 0}, - } - }, - }}, - {"wmoShader", { - { - 4, { - {"_729_UseLitColor_EnableAlpha_PixelShader_BlendMode", false, 0, 1, 4, 0}, - {"_729_FogColor_AlphaTest", true, 16, 1, 4, 0}, - } - }, - { - 0, { - {"_609_scene_uLookAtMat", true, 0, 4, 4, 0}, - {"_609_scene_uPMatrix", true, 64, 4, 4, 0}, - {"_609_scene_uViewUp", true, 128, 1, 4, 0}, - {"_609_scene_uInteriorSunDir", true, 144, 1, 4, 0}, - {"_609_scene_extLight_uExteriorAmbientColor", true, 160, 1, 4, 0}, - {"_609_scene_extLight_uExteriorHorizontAmbientColor", true, 176, 1, 4, 0}, - {"_609_scene_extLight_uExteriorGroundAmbientColor", true, 192, 1, 4, 0}, - {"_609_scene_extLight_uExteriorDirectColor", true, 208, 1, 4, 0}, - {"_609_scene_extLight_uExteriorDirectColorDir", true, 224, 1, 4, 0}, - {"_609_scene_extLight_adtSpecMult", true, 240, 1, 4, 0}, - {"_609_fogData_densityParams", true, 256, 1, 4, 0}, - {"_609_fogData_heightPlane", true, 272, 1, 4, 0}, - {"_609_fogData_color_and_heightRate", true, 288, 1, 4, 0}, - {"_609_fogData_heightDensity_and_endColor", true, 304, 1, 4, 0}, - {"_609_fogData_sunAngle_and_sunColor", true, 320, 1, 4, 0}, - {"_609_fogData_heightColor_and_endFogDistance", true, 336, 1, 4, 0}, - {"_609_fogData_sunPercentage", true, 352, 1, 4, 0}, - } - }, - { - 3, { - {"_597_intLight_uInteriorAmbientColorAndApplyInteriorLight", true, 0, 1, 4, 0}, - {"_597_intLight_uInteriorDirectColorAndApplyExteriorLight", true, 16, 1, 4, 0}, - } - }, - }}, - {"imguiShader", { - }}, -}; -#endif - - -#endif From 78ae4cb09852ec1d84277b6f9ff4a80e7513f313 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Jun 2024 19:52:37 +0300 Subject: [PATCH 200/212] small fixes here and there --- CMakeLists.txt | 45 +++++++++++-------- src/main.cpp | 10 ++--- wowViewerLib/CMakeLists.txt | 2 +- wowViewerLib/shaders/CMakeLists.txt | 4 +- .../shaders/src/spirv/dumpShaderFields.h | 12 ++--- .../src/engine/objects/adt/adtObject.cpp | 5 +-- .../vulkan/shaders/GShaderPermutationVLK.cpp | 10 +++-- 7 files changed, 49 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9c484cf4..02af441fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,9 +87,8 @@ set(BUILD_SHARED_LIBS OFF CACHE BOOL "") if (TRUE) set(ZLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/3rdparty/zlib ${CMAKE_BINARY_DIR}/3rdparty/zlib) - message("CMAKE_BINARY_DIR = ${CMAKE_BINARY_DIR}") + message("CMAKE_BINARY_DIR = ${CMAKE_BINARY_DIR}") message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") - endif() @@ -112,21 +111,25 @@ add_compile_definitions(HAVE_LIMITS_H) SET(CMAKE_USE_LIBSSH2 0) SET(CPR_BUILD_TESTS 0) SET(CURL_ZLIB OFF CACHE STRING "" FORCE) # disable this lib to download the zlib as external project -FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git GIT_TAG 2553fc41450301cd09a9271c8d2c3e0cf3546b73) # the commit hash for 1.8.3 - -FetchContent_MakeAvailable(cpr) -#FetchContent_GetProperties(cpr) -#message("cpr_POPULATED = ${cpr_POPULATED}") -#if(NOT cpr_POPULATED) - # Fetch the content using previously declared details - #FetchContent_Populate(cpr) - #message("cpr_BINARY_DIR = ${cpr_BINARY_DIR}") - #message("cpr_SOURCE_DIR = ${cpr_SOURCE_DIR}") - # Bring the populated content into the build - #set(BUILD_SHARED_LIBS ON CACHE BOOL "") - #add_subdirectory(${cpr_SOURCE_DIR} ${cpr_BINARY_DIR} EXCLUDE_FROM_ALL) - #set(BUILD_SHARED_LIBS OFF CACHE BOOL "") -#endif() +FetchContent_Declare(cpr + GIT_REPOSITORY https://github.com/libcpr/cpr.git + GIT_TAG 2553fc41450301cd09a9271c8d2c3e0cf3546b73 # the commit hash for 1.8.3 + EXCLUDE_FROM_ALL +) + +#FetchContent_MakeAvailable(cpr) +FetchContent_GetProperties(cpr) +message("cpr_POPULATED = ${cpr_POPULATED}") +if(NOT cpr_POPULATED) +# Fetch the content using previously declared details + FetchContent_Populate(cpr) + message("cpr_BINARY_DIR = ${cpr_BINARY_DIR}") + message("cpr_SOURCE_DIR = ${cpr_SOURCE_DIR}") +# Bring the populated content into the build + set(BUILD_SHARED_LIBS ON CACHE BOOL "") + add_subdirectory(${cpr_SOURCE_DIR} ${cpr_BINARY_DIR} EXCLUDE_FROM_ALL) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "") +endif() #StormLib #add_subdirectory(3rdparty/stormlib) @@ -144,6 +147,7 @@ if (WIN32) endif() set(CASC_BUILD_STATIC_LIB 1) + set(CASC_BUILD_STATIC_LIB ON CACHE BOOL "Set static lib from main project") set(CASC_BUILD_SHARED_LIB true CACHE BOOL "Turn off shared lib ") add_subdirectory(3rdparty/casclib EXCLUDE_FROM_ALL) @@ -428,7 +432,12 @@ INSTALL(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION bin COMPONENT Lib if( MINGW ) message( STATUS " Installing system-libraries: MinGW DLLs." ) get_filename_component( Mingw_Path ${CMAKE_CXX_COMPILER} PATH ) - set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${Mingw_Path}/libgcc_s_seh-1.dll ${Mingw_Path}/libstdc++-6.dll ${Mingw_Path}/libwinpthread-1.dll) + set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} + ${Mingw_Path}/libgcc_s_seh-1.dll + ${Mingw_Path}/libstdc++-6.dll + ${Mingw_Path}/libwinpthread-1.dll + ${Mingw_Path}/zlib1.dll + ) endif( MINGW ) include( InstallRequiredSystemLibraries ) diff --git a/src/main.cpp b/src/main.cpp index e354192df..f652a8c07 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -355,12 +355,12 @@ int main(int argc, char *argv[]) { #endif // std::string rendererName = "ogl2"; - std::string rendererName = "ogl3"; -// std::string rendererName = "vulkan"; +// std::string rendererName = "ogl3"; + std::string rendererName = "vulkan"; - if (argc > 1 && std::string(argv[1]) == "-vulkan") { - rendererName = "vulkan"; - } +// if (argc > 1 && std::string(argv[1]) == "-vulkan") { +// rendererName = "vulkan"; +// } //FOR OGL diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index 872d19a2b..b15bb00c1 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -134,7 +134,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/3rdparty/mathfu EXCLUDE_FROM_ALL) if (LINK_TRACY) option( TRACY_ENABLE "" ON) option( TRACY_ON_DEMAND "" ON) - add_subdirectory (${PROJECT_SOURCE_DIR}/3rdparty/tracy) + add_subdirectory (${PROJECT_SOURCE_DIR}/3rdparty/tracy EXCLUDE_FROM_ALL) add_definitions(-DTRACY_ENABLE) set(TRACY_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/3rdparty/tracy/public/tracy") diff --git a/wowViewerLib/shaders/CMakeLists.txt b/wowViewerLib/shaders/CMakeLists.txt index cf8286c4c..cea7f4268 100644 --- a/wowViewerLib/shaders/CMakeLists.txt +++ b/wowViewerLib/shaders/CMakeLists.txt @@ -258,11 +258,11 @@ if (NOT EMSCRIPTEN) endif() if(LINK_VULKAN) if(SPIRV_OPT_APP) - install(FILES ${SPIRV_BINARY_FILES_OPT} + install(DIRECTORY ${CMAKE_BINARY_DIR}/spirv/ DESTINATION ${CMAKE_INSTALL_BINDIR}/spirv ) else() - install(FILES ${SPIRV_BINARY_FILES_NON_OPT} + install(DIRECTORY ${CMAKE_BINARY_DIR}/spriv_raw/ DESTINATION ${CMAKE_INSTALL_BINDIR}/spirv ) endif() diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index 0586955a0..d156ad694 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -72,8 +72,8 @@ struct bindingAmountData { struct shaderMetaData { ShaderStage stage; - std::vector uboBindings; - std::vector ssboBindingData; + std::vector m_uboBindings; + std::vector m_ssboBindingData; std::array uboBindingAmountsPerSet; std::vector imageBindings; @@ -338,7 +338,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vector= 0) { metaInfo.uboBindingAmountsPerSet[set].start = @@ -383,7 +383,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vector= 0) { // metaInfo.uboBindingAmountsPerSet[set].start = @@ -499,7 +499,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vectorsecond.stage) << "," << std::endl; //Dump UBO Bindings per shader std::cout << " {\n"; - for (auto subIt = it->second.uboBindings.begin(); subIt != it->second.uboBindings.end(); subIt++) { + for (auto subIt = it->second.m_uboBindings.begin(); subIt != it->second.m_uboBindings.end(); subIt++) { std::cout << " {" << subIt->set << "," << subIt->binding << "," << subIt->size << "}," << std::endl; } std::cout << " },\n"; @@ -520,7 +520,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vectorsecond.ssboBindingData.begin(); subIt != it->second.ssboBindingData.end(); subIt++) { + for (auto subIt = it->second.m_ssboBindingData.begin(); subIt != it->second.m_ssboBindingData.end(); subIt++) { std::cout << " {" << subIt->set << "," << subIt->binding << "," << subIt->size << "}," << std::endl; } std::cout << " },\n"; diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 9e304a845..72150492e 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "adtObject.h" #include #include "../../algorithms/mathHelper.h" @@ -562,7 +563,7 @@ void AdtObject::loadAlphaTextures() { _alpha[0] = _mm_load_si128(alpha[0]++); //a_1 a_2 a_3 a_4 a_5 a_6 a_7 a_8 a_9 a_10 a_11 a_12 a_13 a_14 a_15 a_16 _alpha[1] = _mm_load_si128(alpha[1]++); //b_1 b_2 b_3 b_4 b_5 b_6 b_7 b_8 b_9 b_10 b_11 b_12 b_13 b_14 b_15 b_16 _alpha[2] = _mm_load_si128(alpha[2]++); //c_1 c_2 c_3 c_4 c_5 c_6 c_7 c_8 c_9 c_10 c_11 c_12 c_13 c_14 c_15 c_16 - _alpha[3]= _mm_load_si128(alpha[3]++); //d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10 d_11 d_12 d_13 d_14 d_15 d_16 + _alpha[3] = _mm_load_si128(alpha[3]++); //d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10 d_11 d_12 d_13 d_14 d_15 d_16 if (chunkMcalRuntime.uncompressedIndex) { _alpha[chunkMcalRuntime.uncompressedIndex] = @@ -586,8 +587,6 @@ void AdtObject::loadAlphaTextures() { __m128i a_b_c_d_high_low = _mm_unpacklo_epi16(a_b_high, c_d_high);//a_8 b_8 c_8 d_8 a_9 b_9 c_9 d_9... __m128i a_b_c_d_high_high = _mm_unpackhi_epi16(a_b_high, c_d_high);//a_11 b_11 c_11 d_11 a_12 b_12 c_12 d_12... - - _mm_store_si128(texturePtr++, a_b_c_d_low_low); _mm_store_si128(texturePtr++, a_b_c_d_low_high); _mm_store_si128(texturePtr++, a_b_c_d_high_low); diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 1c3bca7d6..32e512241 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -117,10 +117,12 @@ void GShaderPermutationVLK::createShaderLayout() { auto it = setLayout.uboSizesPerBinding.find(uboBinding.binding); if (it != std::end(setLayout.uboSizesPerBinding)) { if (it->second != uboBinding.size) { - std::cerr << "UBO sizes mismatch for set = " << uboBinding.set - << " binding = " << uboBinding.binding - << " between " << m_shaderNameVert << " and " << m_shaderNameFrag - << std::endl; + +// std::cerr << "UBO sizes mismatch for set = " << uboBinding.set +// << " binding = " << uboBinding.binding +// << " between " << m_shaderNameVert << " and " << m_shaderNameFrag +// << std::endl; + makeMax(it->second, uboBinding.size); } } else { setLayout.uboSizesPerBinding[uboBinding.binding] = uboBinding.size; From f6526bd1cfe2890fa63e4a70ef0951d035a05850 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sun, 30 Jun 2024 23:04:29 +0300 Subject: [PATCH 201/212] test --- wowViewerLib/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index b15bb00c1..c913f7e38 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -611,7 +611,7 @@ if (LINK_VULKAN) set(Vulkan_FOUND ON PARENT_SCOPE) MESSAGE("Using Vulkan library, Vulkan_LIBRARY= ${Vulkan_LIBRARY}") if (NOT SPIRV_OPT_APP AND Vulkan_INCLUDE_DIR) - set(SPIRV_OPT_APP ${Vulkan_INCLUDE_DIR}/../Bin/spirv-opt) + set(SPIRV_OPT_APP ${Vulkan_INCLUDE_DIR}/../bin/spirv-opt) endif() ELSE() MESSAGE("Vulkan Lib was not found. Disabling vulkan build") From 417dd7daa8d6ca4aed9b1248d4f10c6730b47a43 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Tue, 2 Jul 2024 20:55:25 +0300 Subject: [PATCH 202/212] temp --- src/database/CSqliteDB.cpp | 40 ++++++++++++++----- src/database/CSqliteDB.h | 2 +- .../shaders/src/spirv/dumpShaderFields.h | 2 +- .../descriptorSets/GDescriptorSetLayout.cpp | 4 +- .../vulkan/shaders/GShaderPermutationVLK.cpp | 4 +- wowViewerLib/src/include/database/dbStructs.h | 2 +- 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 5a3c816a6..36166c7a3 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -61,9 +61,13 @@ const std::string getWmoAreaAreaNameSQL = R"===( const std::string getLightByIdSQL = R"===( select - l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, l.LightParamsID_0, - IFNULL(ls.SkyboxFileDataID, 0) as SkyboxFileDataID, IFNULL(lp.LightSkyboxID, 0) as LightSkyboxID, - lp.Glow, IFNULL(ls.Flags, 0) as SkyboxFlags + l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, + l.LightParamsID_0, l.LightParamsID_1, l.LightParamsID_2, l.LightParamsID_3, l.LightParamsID_4, + l.LightParamsID_5, l.LightParamsID_6, l.LightParamsID_7, + IFNULL(ls.SkyboxFileDataID, 0) as SkyboxFileDataID, + IFNULL(ls.Flags, 0) as SkyboxFlags, + IFNULL(lp.LightSkyboxID, 0) as LightSkyboxID, + lp.Glow from Light l left join LightParams lp on lp.ID = l.LightParamsID_0 left join LightSkybox ls on ls.ID = lp.LightSkyboxID @@ -72,15 +76,17 @@ const std::string getLightByIdSQL = R"===( const std::string getLightSQL = R"===( select - l.id as LightId, l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, l.GameFalloffStart, l.GameFalloffEnd, l.LightParamsID_0, - IFNULL(ls.SkyboxFileDataID, 0) as SkyboxFileDataID, IFNULL(lp.LightSkyboxID, 0) as LightSkyboxID, - lp.Glow, IFNULL(ls.Flags, 0) as SkyboxFlags, l.ContinentID, + l.id as LightId, l.GameCoords_0, l.GameCoords_1, l.GameCoords_2, + l.GameFalloffStart, l.GameFalloffEnd, + l.ContinentID, + + l.LightParamsID_0, l.LightParamsID_1, l.LightParamsID_2, l.LightParamsID_3, l.LightParamsID_4, + l.LightParamsID_5, l.LightParamsID_6, l.LightParamsID_7, + (abs(l.GameCoords_0 - ?1) * abs(l.GameCoords_0 - ?1) + abs(l.GameCoords_1 - ?2) * abs(l.GameCoords_1 - ?2) + abs(l.GameCoords_2 - ?3) * abs(l.GameCoords_2 - ?3)) as lightDistSQR from Light l - left join LightParams lp on lp.ID = l.LightParamsID_0 - left join LightSkybox ls on ls.ID = lp.LightSkyboxID where ((l.ContinentID = ?4) and ( @@ -336,7 +342,14 @@ void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, fl ilr.pos[2] = getLightByIdStatement.getField("GameCoords_2").getDouble(); ilr.fallbackStart = getLightByIdStatement.getField("GameFalloffStart").getDouble(); ilr.fallbackEnd = getLightByIdStatement.getField("GameFalloffEnd").getDouble(); - ilr.paramId = getLightByIdStatement.getField("LightParamsID_0").getInt(); + ilr.paramId[0] = getLightByIdStatement.getField("LightParamsID_0").getInt(); + ilr.paramId[1] = getLightByIdStatement.getField("LightParamsID_1").getInt(); + ilr.paramId[2] = getLightByIdStatement.getField("LightParamsID_2").getInt(); + ilr.paramId[3] = getLightByIdStatement.getField("LightParamsID_3").getInt(); + ilr.paramId[4] = getLightByIdStatement.getField("LightParamsID_4").getInt(); + ilr.paramId[5] = getLightByIdStatement.getField("LightParamsID_5").getInt(); + ilr.paramId[6] = getLightByIdStatement.getField("LightParamsID_6").getInt(); + ilr.paramId[7] = getLightByIdStatement.getField("LightParamsID_7").getInt(); ilr.skyBoxFileId = getLightByIdStatement.getField("SkyboxFileDataID").getInt(); ilr.lightSkyboxId = getLightByIdStatement.getField("LightSkyboxID").getInt(); ilr.glow = getLightByIdStatement.getField("Glow").getDouble(); @@ -366,7 +379,14 @@ void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std: ilr.pos[2] = getLightStatement.getField("GameCoords_2").getDouble(); ilr.fallbackStart = getLightStatement.getField("GameFalloffStart").getDouble(); ilr.fallbackEnd = getLightStatement.getField("GameFalloffEnd").getDouble(); - ilr.paramId = getLightStatement.getField("LightParamsID_0").getInt(); + ilr.paramId[0] = getLightStatement.getField("LightParamsID_0").getInt(); + ilr.paramId[1] = getLightStatement.getField("LightParamsID_1").getInt(); + ilr.paramId[2] = getLightStatement.getField("LightParamsID_2").getInt(); + ilr.paramId[3] = getLightStatement.getField("LightParamsID_3").getInt(); + ilr.paramId[4] = getLightStatement.getField("LightParamsID_4").getInt(); + ilr.paramId[5] = getLightStatement.getField("LightParamsID_5").getInt(); + ilr.paramId[6] = getLightStatement.getField("LightParamsID_6").getInt(); + ilr.paramId[7] = getLightStatement.getField("LightParamsID_7").getInt(); ilr.skyBoxFileId = getLightStatement.getField("SkyboxFileDataID").getInt(); ilr.lightSkyboxId = getLightStatement.getField("LightSkyboxID").getInt(); ilr.glow = getLightStatement.getField("Glow").getDouble(); diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index b3c2892ad..836387113 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -135,7 +135,7 @@ class CSqliteDB : public IClientDatabase { float fallbackEnd; float lightDistSQR = 0; float blendAlpha = 0; - int paramId; + int paramId[8]; int skyBoxFileId; int lightSkyboxId; float glow; diff --git a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h index d156ad694..b87600f5d 100644 --- a/wowViewerLib/shaders/src/spirv/dumpShaderFields.h +++ b/wowViewerLib/shaders/src/spirv/dumpShaderFields.h @@ -209,7 +209,7 @@ void dumpShaderUniformOffsets(const std::string &basePath, const std::vector uboBindings; std::array uboBindingAmountsPerSet; - std::vector ssboBindingData; + std::vector m_ssboBindings; std::vector imageBindings; std::array imageBindingAmountsPerSet; diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 599a8f79e..96c9143cc 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -202,8 +202,8 @@ void GDescriptorSetLayout::fillUbo(int setIndex, const DescTypeOverride &typeOve void GDescriptorSetLayout::fillSSBO(int setIndex, const DescTypeOverride &typeOverrides, std::unordered_map &shaderLayoutBindings, const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag) { - for (int i = 0; i < p_metaData->ssboBindingData.size(); i++) { - auto &ssboBinding = p_metaData->ssboBindingData[i]; + for (int i = 0; i < p_metaData->ssboBindings.size(); i++) { + auto &ssboBinding = p_metaData->ssboBindings[i]; if (ssboBinding.set != setIndex) continue; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 32e512241..5cf2511ad 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -132,8 +132,8 @@ void GShaderPermutationVLK::createShaderLayout() { } } - for (int i = 0; i < shaderMeta->ssboBindingData.size(); i++) { - auto &ssboBinding = shaderMeta->ssboBindingData[i]; + for (int i = 0; i < shaderMeta->ssboBindings.size(); i++) { + auto &ssboBinding = shaderMeta->ssboBindings[i]; auto &setLayout = combinedShaderLayout.setLayouts[ssboBinding.set]; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 024ba00da..d64c99896 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -30,6 +30,7 @@ struct LightResult { float closeOceanColor[3]; float farOceanColor[3]; + //Sky std::array SkyTopColor; float SkyMiddleColor[3]; float SkyBand1Color[3]; @@ -64,7 +65,6 @@ struct LightResult { std::array HeightEndFogColor; float FogStartOffset = 0; - std::string skyBoxName; int skyBoxFdid; int skyBoxFlags; From 5fcfea9d43c35deca535ffc22b20455f0495fdf4 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 3 Jul 2024 00:56:25 +0300 Subject: [PATCH 203/212] temp commit --- src/database/CEmptySqliteDB.h | 6 +- src/database/CSqliteDB.cpp | 599 ++++-------------- src/database/CSqliteDB.h | 78 +-- src/ui/renderer/uiScene/FrontendUIRenderer.h | 8 +- .../uiScene/FrontendUIRendererFactory.cpp | 6 + .../src/engine/objects/adt/adtObject.cpp | 14 +- wowViewerLib/src/engine/objects/iMapApi.h | 8 - .../src/engine/objects/scenes/map.cpp | 64 +- .../src/gapi/interface/meshes/IMesh.h | 6 +- wowViewerLib/src/include/database/dbStructs.h | 70 ++ wowViewerLib/src/include/databaseHandler.h | 7 +- .../renderer/mapScene/FrameDependentData.h | 13 +- .../mapScene/MapSceneRendererFactory.cpp | 9 +- 13 files changed, 283 insertions(+), 605 deletions(-) diff --git a/src/database/CEmptySqliteDB.h b/src/database/CEmptySqliteDB.h index df3c341d0..1e99d65fe 100644 --- a/src/database/CEmptySqliteDB.h +++ b/src/database/CEmptySqliteDB.h @@ -14,8 +14,10 @@ class CEmptySqliteDB : public IClientDatabase { bool getMapById(int mapId, MapRecord &mapRecord) override {return false;}; AreaRecord getArea(int areaId) override { return {}; }; bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) override {return false;}; - void getLightById(int lightId, int time, LightResult &lightResult, float zFar) override {}; - void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float zFar) override {}; + void getLightById(int lightId, int time, LightResult &lightResult) override {}; + void getEnvInfo(int mapId, float x, float y, float z, std::vector &lightResults) override {}; + + bool getLightParamData(int lightParamId, int time, LightParamData &lightParamData) override {return false;}; void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override {}; void getZoneLightsForMap(int mapId, std::vector &zoneLights) override {}; diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index 36166c7a3..d0b1a13d1 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -96,17 +96,6 @@ const std::string getLightSQL = R"===( ORDER BY l.ID desc )==="; -const std::string lightDataSQL = R"===( - select ld.AmbientColor, ld.HorizonAmbientColor, ld.GroundAmbientColor, ld.DirectColor, - ld.RiverCloseColor, ld.RiverFarColor, ld.OceanCloseColor, ld.OceanFarColor, - ld.SkyTopColor, ld.SkyMiddleColor, ld.SkyBand1Color, ld.SkyBand2Color, ld.SkySmogColor, ld.SkyFogColor, - ld.FogEnd, ld.FogScaler, ld.FogDensity, ld.FogHeight, ld.FogHeightScaler, ld.FogHeightDensity, ld.SunFogAngle, - ld.EndFogColor, ld.EndFogColorDistance, ld.SunFogColor, ld.SunFogStrength, ld.FogHeightColor, - ld.FogHeightCoefficients_0, ld.FogHeightCoefficients_1, ld.FogHeightCoefficients_2, ld.FogHeightCoefficients_3, - ld.Time from LightData ld - where ld.LightParamID = ? ORDER BY Time ASC - )==="; - const std::string liquidObjectInfoSQL = R"===( select lo.LiquidTypeID, lo.FlowDirection, lo.FlowSpeed, lo.Reflection from LiquidObject lo where lo.ID = ?; @@ -148,10 +137,12 @@ CSqliteDB::CSqliteDB(std::string dbFileName) : getLightStatement(m_sqliteDatabase, getLightSQL), getLightByIdStatement(m_sqliteDatabase, getLightByIdSQL), -// getLightData(m_sqliteDatabase, lightDataSQL), getLightData(m_sqliteDatabase, generateSimpleSelectSQL("LightData", {"LightParamID", "ID"}, " where LightParamID = ? ORDER BY Time ASC")), + getLightParamDataStatement(m_sqliteDatabase, generateSimpleSelectSQL("LightParams", + {}, + "where ID = ?")), getLiquidObjectInfo(m_sqliteDatabase,liquidObjectInfoSQL), getLiquidTypeInfo(m_sqliteDatabase, liquidTypeSQL), getLiquidTextureFileDataIds(m_sqliteDatabase, getHasLiquidTypeXTexture(m_sqliteDatabase) ? liquidTextureFileDataIdsSQL : "select 1 from Map;"), @@ -331,66 +322,53 @@ inline void addOnlyOne(std::array &colorF, int currLdRes) { inline void addOnlyOne(float &colorF, float currLdRes) { colorF = currLdRes; } -void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult, float farClip) { +void CSqliteDB::getLightById(int lightId, int time, LightResult &lightResult) { getLightByIdStatement.setInputs( lightId ); - std::vector innerResults; while (getLightByIdStatement.execute()) { - InnerLightResult &ilr = innerResults.emplace_back(); + auto &ilr = lightResult; + ilr.pos[0] = getLightByIdStatement.getField("GameCoords_0").getDouble(); ilr.pos[1] = getLightByIdStatement.getField("GameCoords_1").getDouble(); ilr.pos[2] = getLightByIdStatement.getField("GameCoords_2").getDouble(); ilr.fallbackStart = getLightByIdStatement.getField("GameFalloffStart").getDouble(); ilr.fallbackEnd = getLightByIdStatement.getField("GameFalloffEnd").getDouble(); - ilr.paramId[0] = getLightByIdStatement.getField("LightParamsID_0").getInt(); - ilr.paramId[1] = getLightByIdStatement.getField("LightParamsID_1").getInt(); - ilr.paramId[2] = getLightByIdStatement.getField("LightParamsID_2").getInt(); - ilr.paramId[3] = getLightByIdStatement.getField("LightParamsID_3").getInt(); - ilr.paramId[4] = getLightByIdStatement.getField("LightParamsID_4").getInt(); - ilr.paramId[5] = getLightByIdStatement.getField("LightParamsID_5").getInt(); - ilr.paramId[6] = getLightByIdStatement.getField("LightParamsID_6").getInt(); - ilr.paramId[7] = getLightByIdStatement.getField("LightParamsID_7").getInt(); - ilr.skyBoxFileId = getLightByIdStatement.getField("SkyboxFileDataID").getInt(); - ilr.lightSkyboxId = getLightByIdStatement.getField("LightSkyboxID").getInt(); - ilr.glow = getLightByIdStatement.getField("Glow").getDouble(); - ilr.skyBoxFlags = getLightByIdStatement.getField("SkyboxFlags").getInt(); + ilr.lightParamId[0] = getLightByIdStatement.getField("LightParamsID_0").getInt(); + ilr.lightParamId[1] = getLightByIdStatement.getField("LightParamsID_1").getInt(); + ilr.lightParamId[2] = getLightByIdStatement.getField("LightParamsID_2").getInt(); + ilr.lightParamId[3] = getLightByIdStatement.getField("LightParamsID_3").getInt(); + ilr.lightParamId[4] = getLightByIdStatement.getField("LightParamsID_4").getInt(); + ilr.lightParamId[5] = getLightByIdStatement.getField("LightParamsID_5").getInt(); + ilr.lightParamId[6] = getLightByIdStatement.getField("LightParamsID_6").getInt(); + ilr.lightParamId[7] = getLightByIdStatement.getField("LightParamsID_7").getInt(); + ilr.id = lightId; - } - std::vector lightResults; - convertInnerResultsToPublic(time, lightResults, innerResults, farClip); - if (lightResults.size() > 0) { - lightResult = lightResults[0]; - } + return; + } }; -void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std::vector &lightResults, float farClip) { +void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, std::vector &lightResults) { getLightStatement.setInputs(x, y, z, mapId ); - std::vector innerResults; bool defaultRecordSet = false; - InnerLightResult defaultRecord; - float totalBlend = 0; while (getLightStatement.execute()) { - InnerLightResult &ilr = innerResults.emplace_back(); + auto &ilr = lightResults.emplace_back(); ilr.id = getLightStatement.getField("LightId").getInt(); ilr.pos[0] = getLightStatement.getField("GameCoords_0").getDouble(); ilr.pos[1] = getLightStatement.getField("GameCoords_1").getDouble(); ilr.pos[2] = getLightStatement.getField("GameCoords_2").getDouble(); ilr.fallbackStart = getLightStatement.getField("GameFalloffStart").getDouble(); ilr.fallbackEnd = getLightStatement.getField("GameFalloffEnd").getDouble(); - ilr.paramId[0] = getLightStatement.getField("LightParamsID_0").getInt(); - ilr.paramId[1] = getLightStatement.getField("LightParamsID_1").getInt(); - ilr.paramId[2] = getLightStatement.getField("LightParamsID_2").getInt(); - ilr.paramId[3] = getLightStatement.getField("LightParamsID_3").getInt(); - ilr.paramId[4] = getLightStatement.getField("LightParamsID_4").getInt(); - ilr.paramId[5] = getLightStatement.getField("LightParamsID_5").getInt(); - ilr.paramId[6] = getLightStatement.getField("LightParamsID_6").getInt(); - ilr.paramId[7] = getLightStatement.getField("LightParamsID_7").getInt(); - ilr.skyBoxFileId = getLightStatement.getField("SkyboxFileDataID").getInt(); - ilr.lightSkyboxId = getLightStatement.getField("LightSkyboxID").getInt(); - ilr.glow = getLightStatement.getField("Glow").getDouble(); - ilr.skyBoxFlags = getLightStatement.getField("SkyboxFlags").getInt(); + ilr.lightParamId[0] = getLightStatement.getField("LightParamsID_0").getInt(); + ilr.lightParamId[1] = getLightStatement.getField("LightParamsID_1").getInt(); + ilr.lightParamId[2] = getLightStatement.getField("LightParamsID_2").getInt(); + ilr.lightParamId[3] = getLightStatement.getField("LightParamsID_3").getInt(); + ilr.lightParamId[4] = getLightStatement.getField("LightParamsID_4").getInt(); + ilr.lightParamId[5] = getLightStatement.getField("LightParamsID_5").getInt(); + ilr.lightParamId[6] = getLightStatement.getField("LightParamsID_6").getInt(); + ilr.lightParamId[7] = getLightStatement.getField("LightParamsID_7").getInt(); + ilr.lightDistSQR = getLightStatement.getField("lightDistSQR").getDouble(); @@ -398,434 +376,123 @@ void CSqliteDB::getEnvInfo(int mapId, float x, float y, float z, int ptime, std: sqrtf(ilr.lightDistSQR) > ilr.fallbackStart ? std::max( ((ilr.fallbackStart - sqrtf(ilr.lightDistSQR)) / (ilr.fallbackEnd - ilr.fallbackStart)) + 1.0f, 0.0f) : 1.0f; - - if (ilr.pos[0] == 0 && ilr.pos[1] == 0 && ilr.pos[2] == 0 ) { - if (!defaultRecordSet || mapId == getLightStatement.getField("ContinentID").getInt()){ - defaultRecord = ilr; - defaultRecord.isDefault = true; - defaultRecord.blendAlpha = 1.0f; - defaultRecordSet = true; - } - innerResults.resize(std::max(innerResults.size() - 1, 0)); - } } - if (defaultRecordSet) innerResults.push_back(defaultRecord); - - convertInnerResultsToPublic(ptime, lightResults, innerResults, farClip); -} -void CSqliteDB::addOnlyOne(LightResult &lightResult, - const CSqliteDB::InnerLightDataRes &currLdRes) const {//Set as is - ::addOnlyOne(lightResult.ambientColor, currLdRes.ambientLight); - ::addOnlyOne(lightResult.horizontAmbientColor, currLdRes.horizontAmbientColor); - ::addOnlyOne(lightResult.groundAmbientColor, currLdRes.groundAmbientColor); - - ::addOnlyOne(lightResult.directColor, currLdRes.directLight); - - ::addOnlyOne(lightResult.closeRiverColor, currLdRes.closeRiverColor); - ::addOnlyOne(lightResult.farRiverColor, currLdRes.farRiverColor); - ::addOnlyOne(lightResult.closeOceanColor, currLdRes.closeOceanColor); - ::addOnlyOne(lightResult.farOceanColor, currLdRes.farOceanColor); - - ::addOnlyOne(lightResult.SkyTopColor, currLdRes.SkyTopColor); - ::addOnlyOne(lightResult.SkyMiddleColor, currLdRes.SkyMiddleColor); - ::addOnlyOne(lightResult.SkyBand1Color, currLdRes.SkyBand1Color); - ::addOnlyOne(lightResult.SkyBand2Color, currLdRes.SkyBand2Color); - ::addOnlyOne(lightResult.SkySmogColor, currLdRes.SkySmogColor); - ::addOnlyOne(lightResult.SkyFogColor, currLdRes.SkyFogColor); - - ::addOnlyOne(lightResult.FogEnd, currLdRes.FogEnd); - ::addOnlyOne(lightResult.FogScaler, currLdRes.FogScaler); - ::addOnlyOne(lightResult.FogDensity, currLdRes.FogDensity); - ::addOnlyOne(lightResult.FogHeight, currLdRes.FogHeight); - ::addOnlyOne(lightResult.FogHeightScaler, currLdRes.FogHeightScaler); - ::addOnlyOne(lightResult.FogHeightDensity, currLdRes.FogHeightDensity); - - ::addOnlyOne(lightResult.EndFogColor, currLdRes.EndFogColor); - ::addOnlyOne(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance); - ::addOnlyOne(lightResult.SunFogColor, currLdRes.SunFogColor); - - ::addOnlyOne(lightResult.FogHeightColor, currLdRes.FogHeightColor); - ::addOnlyOne(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0]); - ::addOnlyOne(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1]); - ::addOnlyOne(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2]); - ::addOnlyOne(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3]); - - ::addOnlyOne(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0]); - ::addOnlyOne(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1]); - ::addOnlyOne(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2]); - ::addOnlyOne(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3]); - - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0]); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1]); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2]); - ::addOnlyOne(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3]); - - ::addOnlyOne(lightResult.FogZScalar, currLdRes.FogZScalar); - ::addOnlyOne(lightResult.MainFogStartDist, currLdRes.MainFogStartDist); - ::addOnlyOne(lightResult.MainFogEndDist, currLdRes.MainFogEndDist); - ::addOnlyOne(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor); - ::addOnlyOne(lightResult.FogStartOffset, currLdRes.FogStartOffset); } +bool CSqliteDB::getLightParamData(int lightParamId, int time, LightParamData &lightParamData) { + + getLightParamDataStatement.setInputs(lightParamId); + + if (getLightParamDataStatement.execute()) { + lightParamData.glow = getLightParamDataStatement.getField("Glow").getDouble(); + lightParamData.lightSkyBoxId = getLightParamDataStatement.getField("LightSkyboxID").getInt(); + lightParamData.waterShallowAlpha = getLightParamDataStatement.getField("WaterShallowAlpha").getDouble(); + lightParamData.waterDeepAlpha = getLightParamDataStatement.getField("WaterDeepAlpha").getDouble(); + lightParamData.oceanShallowAlpha = getLightParamDataStatement.getField("OceanShallowAlpha").getDouble(); + lightParamData.oceanDeepAlpha = getLightParamDataStatement.getField("OceanDeepAlpha").getDouble(); + lightParamData.lightParamFlags = getLightParamDataStatement.getField("Flags").getInt(); + } else { + //Record not found + return false; + } -void CSqliteDB::blendTwoAndAdd(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &lastLdRes, - const CSqliteDB::InnerLightDataRes &currLdRes, float timeAlphaBlend) const { - ::blendTwoAndAdd(lightResult.ambientColor, - currLdRes.ambientLight, lastLdRes.ambientLight, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.horizontAmbientColor, - currLdRes.horizontAmbientColor, lastLdRes.horizontAmbientColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.groundAmbientColor, - currLdRes.groundAmbientColor, lastLdRes.groundAmbientColor, - timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.directColor, - currLdRes.directLight, lastLdRes.directLight, - timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.closeRiverColor, - currLdRes.closeRiverColor, lastLdRes.closeRiverColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.farRiverColor, - currLdRes.farRiverColor, lastLdRes.farRiverColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.closeOceanColor, - currLdRes.closeOceanColor, lastLdRes.closeOceanColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.farOceanColor, - currLdRes.farOceanColor, lastLdRes.farOceanColor, - timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.SkyTopColor, - currLdRes.SkyTopColor, lastLdRes.SkyTopColor, - timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.SkyMiddleColor, - currLdRes.SkyMiddleColor, lastLdRes.SkyMiddleColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SkyBand1Color, - currLdRes.SkyBand1Color, lastLdRes.SkyBand1Color, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SkyBand2Color, - currLdRes.SkyBand2Color, lastLdRes.SkyBand2Color, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SkySmogColor, - currLdRes.SkySmogColor, lastLdRes.SkySmogColor, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SkyFogColor, - currLdRes.SkyFogColor, lastLdRes.SkyFogColor, - timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.FogEnd, currLdRes.FogEnd, lastLdRes.FogEnd, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogScaler, currLdRes.FogScaler, lastLdRes.FogScaler, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogDensity, currLdRes.FogDensity, lastLdRes.FogDensity, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeight, currLdRes.FogHeight, lastLdRes.FogHeight, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightScaler, currLdRes.FogHeightScaler, lastLdRes.FogHeightScaler, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightDensity, currLdRes.FogHeightDensity, lastLdRes.FogHeightDensity, timeAlphaBlend); -// ::blendTwoAndAdd(lightResult.SunFogAngle, currLdRes.SunFogAngle, lastLdRes.SunFogAngle, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.EndFogColor, currLdRes.EndFogColor, lastLdRes.EndFogColor, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.EndFogColorDistance, currLdRes.EndFogColorDistance, lastLdRes.EndFogColorDistance, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SunFogColor, currLdRes.SunFogColor, lastLdRes.SunFogColor, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SunFogStrength, currLdRes.SunFogStrength, lastLdRes.SunFogStrength, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightColor, currLdRes.FogHeightColor, lastLdRes.FogHeightColor, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[0], currLdRes.FogHeightCoefficients[0], lastLdRes.FogHeightCoefficients[0], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[1], currLdRes.FogHeightCoefficients[1], lastLdRes.FogHeightCoefficients[1], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[2], currLdRes.FogHeightCoefficients[2], lastLdRes.FogHeightCoefficients[2], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogHeightCoefficients[3], currLdRes.FogHeightCoefficients[3], lastLdRes.FogHeightCoefficients[3], timeAlphaBlend); - - - ::blendTwoAndAdd(lightResult.MainFogCoefficients[0], currLdRes.MainFogCoefficients[0], lastLdRes.MainFogCoefficients[0], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[1], currLdRes.MainFogCoefficients[1], lastLdRes.MainFogCoefficients[1], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[2], currLdRes.MainFogCoefficients[2], lastLdRes.MainFogCoefficients[2], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.MainFogCoefficients[3], currLdRes.MainFogCoefficients[3], lastLdRes.MainFogCoefficients[3], timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[0], currLdRes.HeightDensityFogCoeff[0], lastLdRes.HeightDensityFogCoeff[0], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[1], currLdRes.HeightDensityFogCoeff[1], lastLdRes.HeightDensityFogCoeff[1], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[2], currLdRes.HeightDensityFogCoeff[2], lastLdRes.HeightDensityFogCoeff[2], timeAlphaBlend); - ::blendTwoAndAdd(lightResult.HeightDensityFogCoefficients[3], currLdRes.HeightDensityFogCoeff[3], lastLdRes.HeightDensityFogCoeff[3], timeAlphaBlend); - - ::blendTwoAndAdd(lightResult.FogZScalar, currLdRes.FogZScalar, lastLdRes.FogZScalar, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.MainFogStartDist, currLdRes.MainFogStartDist, lastLdRes.MainFogStartDist, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.MainFogEndDist, currLdRes.MainFogEndDist, lastLdRes.MainFogEndDist, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.HeightEndFogColor, currLdRes.EndFogHeightColor,lastLdRes.EndFogHeightColor, timeAlphaBlend); - ::blendTwoAndAdd(lightResult.FogStartOffset, currLdRes.FogStartOffset, lastLdRes.FogStartOffset, timeAlphaBlend); -} + getTimedLightParamData(lightParamId, time, lightParamData); -float arr4SqrLength(const std::array &arr) { - return - arr[0] * arr[0] + - arr[1] * arr[1] + - arr[2] * arr[2] + - arr[3] * arr[3]; + return true; } -void CSqliteDB::convertInnerResultsToPublic(int ptime, std::vector &lightResults, - std::vector &innerResults, - float farClip) { - - //From lowest to highest - std::sort(innerResults.begin(), innerResults.end(), +[](const InnerLightResult &a, const InnerLightResult &b) -> bool { - if (a.isDefault) return true; - if (b.isDefault) return false; - - float distanceSqr = - (a.pos[0] - b.pos[0]) * (a.pos[0] - b.pos[0]) + - (a.pos[1] - b.pos[1]) * (a.pos[1] - b.pos[1]) + - (a.pos[2] - b.pos[2]) * (a.pos[2] - b.pos[2]); - - static const float tolerance = 0.33333334f; - if (sqrtf(distanceSqr) < tolerance) { - return a.fallbackStart < b.fallbackStart; - } else { - return a.lightDistSQR < b.lightDistSQR; +void CSqliteDB::getTimedLightParamData(int lightParamId, int time, LightParamData &lightParamData) { + getLightData.setInputs(lightParamId ); + + bool hasHorizonAmbientColor = getLightData.getFieldIndex("HorizonAmbientColor") >= 0; + bool hasGroundAmbientColor = getLightData.getFieldIndex("GroundAmbientColor") >= 0; + bool hasFogDensity = getLightData.getFieldIndex("FogDensity") >= 0; + bool hasFogHeight = getLightData.getFieldIndex("FogHeight") >= 0; + bool hasFogHeightScaler = getLightData.getFieldIndex("FogHeightScaler") >= 0; + bool hasFogHeightDensity = getLightData.getFieldIndex("FogHeightDensity") >= 0; + bool hasSunFogAngle = getLightData.getFieldIndex("SunFogAngle") >= 0; + bool hasEndFogColor = getLightData.getFieldIndex("EndFogColor") >= 0; + bool hasEndFogColorDistance = getLightData.getFieldIndex("EndFogColorDistance") >= 0; + bool hasSunFogColor = getLightData.getFieldIndex("SunFogColor") >= 0; + bool hasSunFogStrength = getLightData.getFieldIndex("SunFogStrength") >= 0; + bool hasFogHeightColor = getLightData.getFieldIndex("FogHeightColor") >= 0; + bool hasFogHeightCoefficients = getLightData.getFieldIndex("FogHeightCoefficients_0") >= 0; + bool hasFogZScalar = getLightData.getFieldIndex("FogZScalar") >= 0; + bool hasMainFogStartDist = getLightData.getFieldIndex("MainFogStartDist") >= 0; + bool hasMainFogEndDist = getLightData.getFieldIndex("MainFogEndDist") >= 0; + bool hasFogStartOffset = getLightData.getFieldIndex("FogStartOffset") >= 0; + bool hasEndFogHeightColor = getLightData.getFieldIndex("EndFogHeightColor") >= 0; + bool hasMainFogCoefficients = getLightData.getFieldIndex("MainFogCoefficients_0") >= 0; + bool hasHeightDensityFogCoeff = getLightData.getFieldIndex("HeightDensityFogCoeff_0") >= 0; + + int timeIndex = 0; + while (getLightData.execute()) { + int thisTime = getLightData.getField("Time").getInt(); + if (thisTime > time) { + //Increase timeIndex if the time of current record is bigger than time + timeIndex++; } - return false; - }); - - for (int i = 0; i < innerResults.size(); i++) { - LightResult lightResult; - initWithZeros(lightResult.ambientColor); - initWithZeros(lightResult.horizontAmbientColor); - initWithZeros(lightResult.groundAmbientColor); - initWithZeros(lightResult.directColor); - initWithZeros(lightResult.closeRiverColor); - initWithZeros(lightResult.farRiverColor); - initWithZeros(lightResult.closeOceanColor); - initWithZeros(lightResult.farOceanColor); - - initWithZeros(lightResult.SkyTopColor); - initWithZeros(lightResult.SkyMiddleColor); - initWithZeros(lightResult.SkyBand1Color); - initWithZeros(lightResult.SkyBand2Color); - initWithZeros(lightResult.SkySmogColor); - initWithZeros(lightResult.SkyFogColor); - - initWithZeros(lightResult.EndFogColor); - initWithZeros(lightResult.SunFogColor); - initWithZeros(lightResult.FogHeightColor); - initWithZeros(lightResult.FogHeightCoefficients); - initWithZeros(lightResult.MainFogCoefficients); - initWithZeros(lightResult.HeightDensityFogCoefficients); - initWithZeros(lightResult.HeightEndFogColor); - - - lightResult.skyBoxFdid = 0; - lightResult.lightSkyboxId = 0; - lightResult.lightParamId = 0; - - lightResult.FogEnd = 0.0; - lightResult.FogScaler = 0.0; - lightResult.FogDensity = 0.0; - lightResult.FogHeight = 0.0; - lightResult.FogHeightScaler = 0.0; - lightResult.FogHeightDensity = 0.0; - lightResult.SunFogAngle = 0.0; - lightResult.EndFogColorDistance = 0.0; - lightResult.SunFogStrength = 0.0; - lightResult.FogZScalar = 0.0; - lightResult.LegacyFogScalar = 0.0; - lightResult.MainFogStartDist = 0.0; - lightResult.MainFogEndDist = 0.0; - lightResult.FogBlendAlpha = 0.0; - lightResult.FogStartOffset = 0.0; - - - - auto &innerResult = innerResults[i]; - lightResult.isDefault = innerResult.isDefault; - lightResult.lightParamId = innerResult.paramId; - lightResult.id = innerResult.id; - - getLightData.setInputs( innerResult.paramId ); - -// std::cout << "innerResult.paramId = " << innerResult.paramId << std::endl; - - InnerLightDataRes lastLdRes = {0, 0, -1}; - bool assigned = false; - - lightResult.blendCoef = innerResult.blendAlpha; - - - lightResult.skyBoxFdid = innerResult.skyBoxFileId; - lightResult.skyBoxFlags = innerResult.skyBoxFlags; - lightResult.lightSkyboxId = innerResult.lightSkyboxId; - lightResult.glow = innerResult.glow; - - bool hasHorizonAmbientColor = getLightData.getFieldIndex("HorizonAmbientColor") >= 0; - bool hasGroundAmbientColor = getLightData.getFieldIndex("GroundAmbientColor") >= 0; - bool hasFogDensity = getLightData.getFieldIndex("FogDensity") >= 0; - bool hasFogHeight = getLightData.getFieldIndex("FogHeight") >= 0; - bool hasFogHeightScaler = getLightData.getFieldIndex("FogHeightScaler") >= 0; - bool hasFogHeightDensity = getLightData.getFieldIndex("FogHeightDensity") >= 0; - bool hasSunFogAngle = getLightData.getFieldIndex("SunFogAngle") >= 0; - bool hasEndFogColor = getLightData.getFieldIndex("EndFogColor") >= 0; - bool hasEndFogColorDistance = getLightData.getFieldIndex("EndFogColorDistance") >= 0; - bool hasSunFogColor = getLightData.getFieldIndex("SunFogColor") >= 0; - bool hasSunFogStrength = getLightData.getFieldIndex("SunFogStrength") >= 0; - bool hasFogHeightColor = getLightData.getFieldIndex("FogHeightColor") >= 0; - bool hasFogHeightCoefficients = getLightData.getFieldIndex("FogHeightCoefficients_0") >= 0; - bool hasFogZScalar = getLightData.getFieldIndex("FogZScalar") >= 0; - bool hasMainFogStartDist = getLightData.getFieldIndex("MainFogStartDist") >= 0; - bool hasMainFogEndDist = getLightData.getFieldIndex("MainFogEndDist") >= 0; - bool hasFogStartOffset = getLightData.getFieldIndex("FogStartOffset") >= 0; - bool hasEndFogHeightColor = getLightData.getFieldIndex("EndFogHeightColor") >= 0; - bool hasMainFogCoefficients = getLightData.getFieldIndex("MainFogCoefficients_0") >= 0; - bool hasHeightDensityFogCoeff = getLightData.getFieldIndex("HeightDensityFogCoeff_0") >= 0; - - while (getLightData.execute()) { - InnerLightDataRes currLdRes; - currLdRes.ambientLight = getLightData.getField("AmbientColor"); - currLdRes.horizontAmbientColor = hasHorizonAmbientColor ? getLightData.getField("HorizonAmbientColor") : 0; - - if (currLdRes.horizontAmbientColor == 0) { - currLdRes.horizontAmbientColor = currLdRes.ambientLight; - } - currLdRes.groundAmbientColor = hasGroundAmbientColor ? getLightData.getField("GroundAmbientColor") : 0; - if (currLdRes.groundAmbientColor == 0) { - currLdRes.groundAmbientColor = currLdRes.ambientLight; - } - - currLdRes.directLight = getLightData.getField("DirectColor"); - - currLdRes.closeRiverColor = getLightData.getField("RiverCloseColor"); - currLdRes.farRiverColor = getLightData.getField("RiverFarColor"); - currLdRes.closeOceanColor = getLightData.getField("OceanCloseColor"); - currLdRes.farOceanColor = getLightData.getField("OceanFarColor"); - - currLdRes.SkyTopColor = getLightData.getField("SkyTopColor"); - currLdRes.SkyMiddleColor = getLightData.getField("SkyMiddleColor"); - currLdRes.SkyBand1Color = getLightData.getField("SkyBand1Color"); - currLdRes.SkyBand2Color = getLightData.getField("SkyBand2Color"); - currLdRes.SkySmogColor = getLightData.getField("SkySmogColor"); - currLdRes.SkyFogColor = getLightData.getField("SkyFogColor"); - - currLdRes.FogEnd = getLightData.getField("FogEnd").getDouble(); - currLdRes.FogScaler = getLightData.getField("FogScaler").getDouble(); - currLdRes.FogDensity = hasFogDensity ? getLightData.getField("FogDensity").getDouble() : 0.000001f; - currLdRes.FogHeight = hasFogHeight ? getLightData.getField("FogHeight").getDouble() : -10000.0; - currLdRes.FogHeightScaler = hasFogHeightScaler ? getLightData.getField("FogHeightScaler").getDouble() : -1.0f; - currLdRes.FogHeightDensity = hasFogHeightDensity ? getLightData.getField("FogHeightDensity").getDouble() : 0.0f; - currLdRes.FogZScalar = hasFogZScalar ? getLightData.getField("FogZScalar").getDouble() : 0.0f; - currLdRes.MainFogStartDist = hasMainFogStartDist ? getLightData.getField("MainFogStartDist").getDouble() : 0.0f; - currLdRes.MainFogEndDist = hasMainFogEndDist ? getLightData.getField("MainFogEndDist").getDouble() : 0.0f; - currLdRes.SunFogAngle = hasSunFogAngle ? getLightData.getField("SunFogAngle").getDouble() : 0.f; - currLdRes.EndFogColor = hasEndFogColor ? getLightData.getField("EndFogColor").getInt() : 0; - currLdRes.EndFogColorDistance = hasEndFogColorDistance ? getLightData.getField("EndFogColorDistance").getDouble() : 0; - currLdRes.FogStartOffset = hasFogStartOffset ? getLightData.getField("FogStartOffset").getDouble() : 0; - currLdRes.SunFogColor = hasSunFogColor ? getLightData.getField("SunFogColor").getInt() : 0; - currLdRes.SunFogStrength = hasSunFogStrength ? getLightData.getField("SunFogStrength").getDouble() : 0.0f; - currLdRes.FogHeightColor = hasFogHeightColor ? getLightData.getField("FogHeightColor").getInt() : 0.0f; - currLdRes.EndFogHeightColor = hasEndFogHeightColor ? getLightData.getField("EndFogHeightColor").getInt() : 0; - currLdRes.FogHeightCoefficients[0] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_0").getDouble() : 0.0f; - currLdRes.FogHeightCoefficients[1] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_1").getDouble(): 0.0f; - currLdRes.FogHeightCoefficients[2] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_2").getDouble(): 0.0f; - currLdRes.FogHeightCoefficients[3] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_3").getDouble(): 0.0f; - currLdRes.MainFogCoefficients[0] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_0").getDouble() : 0.0f; - currLdRes.MainFogCoefficients[1] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_1").getDouble(): 0.0f; - currLdRes.MainFogCoefficients[2] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_2").getDouble(): 0.0f; - currLdRes.MainFogCoefficients[3] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_3").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[0] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_0").getDouble() : 0.0f; - currLdRes.HeightDensityFogCoeff[1] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_1").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[2] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_2").getDouble(): 0.0f; - currLdRes.HeightDensityFogCoeff[3] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_3").getDouble(): 0.0f; - - currLdRes.time = getLightData.getField("Time").getInt(); - - //Hacks for loading of fog information - if (!currLdRes.EndFogColor) { - currLdRes.EndFogColor = currLdRes.SkyFogColor; - } - if (!currLdRes.FogHeightColor) { - currLdRes.FogHeightColor = currLdRes.SkyFogColor; - } - if (!currLdRes.EndFogHeightColor) { - currLdRes.EndFogHeightColor = currLdRes.EndFogColor; - } - currLdRes.FogScaler = std::clamp(currLdRes.FogScaler, -1.0f, 1.0f); - currLdRes.FogEnd = std::max(currLdRes.FogEnd, 10.0f); - currLdRes.FogHeight = std::max(currLdRes.FogHeight, -10000.0f); - currLdRes.FogHeightScaler = std::clamp(currLdRes.FogHeightScaler, -1.0f, 1.0f); - if (!currLdRes.SunFogColor) - currLdRes.SunFogAngle = 1.0f; - - if (currLdRes.FogHeight > 10000.0f) - currLdRes.FogHeight = 0.0f; - - if (currLdRes.FogDensity <= 0.0f) { - float a = std::min(farClip, 700.0) - 200.0; - float b = currLdRes.FogEnd - (float)(currLdRes.FogEnd * lastLdRes.FogScaler); - if ( b > a || a <= 0.0 ) - currLdRes.FogDensity = 1.5; - else - currLdRes.FogDensity = (float)((float)(1.0f - (float)(b / a)) * 5.5f) + 1.5f; - } - -// if (currLdRes.FogHeightScaler == 0.0) { -// currLdRes.FogHeightDensity = currLdRes.FogDensity; -// } - - if (currLdRes.time > ptime) { - assigned = true; - //Blend using time as alpha - float timeAlphaBlend = 1.0f - (((float) currLdRes.time - (float) ptime) / - ((float) currLdRes.time - (float) lastLdRes.time)); - - //Hack for SunFogAngle - { - auto SunFogAngle2 = currLdRes.SunFogAngle; - auto SunFogAngle1 = lastLdRes.SunFogAngle; - if (SunFogAngle2 >= 1.0f && SunFogAngle1 >= 1.0f) { - lightResult.SunAngleBlend = 0.0f; - lightResult.SunFogStrength = 0.0f; - lightResult.SunFogAngle = 1.0f; - } else - if (SunFogAngle1 < 1.0 && SunFogAngle2 < 1.0) { - lightResult.SunAngleBlend = 1.0f; - ::blendTwoAndAdd(lightResult.SunFogStrength, - currLdRes.SunFogStrength, lastLdRes.SunFogStrength, - timeAlphaBlend); - ::blendTwoAndAdd(lightResult.SunFogAngle, - currLdRes.SunFogAngle, lastLdRes.SunFogAngle, - timeAlphaBlend); - lightResult.SunFogAngle = 1.0f; - } else - if ((SunFogAngle2 >= 1.0f && SunFogAngle2 >= 1.0) || (SunFogAngle1 < 1.0 && SunFogAngle2 >= 1.0)) - { - lightResult.SunAngleBlend = 1.0f - timeAlphaBlend; - lightResult.SunFogStrength = lastLdRes.SunFogStrength; - lightResult.SunFogAngle = lastLdRes.SunFogAngle; - } else { - lightResult.SunAngleBlend = timeAlphaBlend; - lightResult.SunFogAngle = SunFogAngle2; - lightResult.SunFogStrength = currLdRes.SunFogStrength; - } - } - blendTwoAndAdd(lightResult, lastLdRes, currLdRes, timeAlphaBlend); - - break; - } - lastLdRes = currLdRes; - } - - if (!assigned) { - addOnlyOne(lightResult, lastLdRes); - } - - //Hack for LegacyFogScaler - if ( - arr4SqrLength(lightResult.MainFogCoefficients) > 0.00000011920929f || - arr4SqrLength(lightResult.MainFogCoefficients) > 0.00000011920929f - ) { - lightResult.LegacyFogScalar = 0.0f; - } else { - lightResult.LegacyFogScalar = 1.0f; - } + if (timeIndex > 1) return; + + auto currLdRes = lightParamData.lightTimedData[timeIndex]; + currLdRes.time = thisTime; + + currLdRes.ambientLight = getLightData.getField("AmbientColor"); + currLdRes.horizontAmbientColor = hasHorizonAmbientColor ? getLightData.getField("HorizonAmbientColor") : 0; + currLdRes.groundAmbientColor = hasGroundAmbientColor ? getLightData.getField("GroundAmbientColor") : 0; + + currLdRes.directColor = getLightData.getField("DirectColor"); + + currLdRes.closeRiverColor = getLightData.getField("RiverCloseColor"); + currLdRes.farRiverColor = getLightData.getField("RiverFarColor"); + currLdRes.closeOceanColor = getLightData.getField("OceanCloseColor"); + currLdRes.farOceanColor = getLightData.getField("OceanFarColor"); + + currLdRes.SkyTopColor = getLightData.getField("SkyTopColor"); + currLdRes.SkyMiddleColor = getLightData.getField("SkyMiddleColor"); + currLdRes.SkyBand1Color = getLightData.getField("SkyBand1Color"); + currLdRes.SkyBand2Color = getLightData.getField("SkyBand2Color"); + currLdRes.SkySmogColor = getLightData.getField("SkySmogColor"); + currLdRes.SkyFogColor = getLightData.getField("SkyFogColor"); + + currLdRes.FogEnd = getLightData.getField("FogEnd").getDouble(); + currLdRes.FogScaler = getLightData.getField("FogScaler").getDouble(); + currLdRes.FogDensity = hasFogDensity ? getLightData.getField("FogDensity").getDouble() : 0.000001f; + currLdRes.FogHeight = hasFogHeight ? getLightData.getField("FogHeight").getDouble() : -10000.0; + currLdRes.FogHeightScaler = hasFogHeightScaler ? getLightData.getField("FogHeightScaler").getDouble() : -1.0f; + currLdRes.FogHeightDensity = hasFogHeightDensity ? getLightData.getField("FogHeightDensity").getDouble() : 0.0f; + currLdRes.FogZScalar = hasFogZScalar ? getLightData.getField("FogZScalar").getDouble() : 0.0f; + currLdRes.MainFogStartDist = hasMainFogStartDist ? getLightData.getField("MainFogStartDist").getDouble() : 0.0f; + currLdRes.MainFogEndDist = hasMainFogEndDist ? getLightData.getField("MainFogEndDist").getDouble() : 0.0f; + currLdRes.SunFogAngle = hasSunFogAngle ? getLightData.getField("SunFogAngle").getDouble() : 0.f; + currLdRes.EndFogColor = hasEndFogColor ? getLightData.getField("EndFogColor").getInt() : 0; + currLdRes.EndFogColorDistance = hasEndFogColorDistance ? getLightData.getField("EndFogColorDistance").getDouble() : 0; + currLdRes.FogStartOffset = hasFogStartOffset ? getLightData.getField("FogStartOffset").getDouble() : 0; + currLdRes.SunFogColor = hasSunFogColor ? getLightData.getField("SunFogColor").getInt() : 0; + currLdRes.SunFogStrength = hasSunFogStrength ? getLightData.getField("SunFogStrength").getDouble() : 0.0f; + currLdRes.FogHeightColor = hasFogHeightColor ? getLightData.getField("FogHeightColor").getInt() : 0.0f; + currLdRes.EndFogHeightColor = hasEndFogHeightColor ? getLightData.getField("EndFogHeightColor").getInt() : 0; + currLdRes.FogHeightCoefficients[0] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_0").getDouble() : 0.0f; + currLdRes.FogHeightCoefficients[1] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_1").getDouble() : 0.0f; + currLdRes.FogHeightCoefficients[2] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_2").getDouble() : 0.0f; + currLdRes.FogHeightCoefficients[3] = hasFogHeightCoefficients ? getLightData.getField("FogHeightCoefficients_3").getDouble() : 0.0f; + currLdRes.MainFogCoefficients[0] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_0").getDouble() : 0.0f; + currLdRes.MainFogCoefficients[1] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_1").getDouble() : 0.0f; + currLdRes.MainFogCoefficients[2] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_2").getDouble() : 0.0f; + currLdRes.MainFogCoefficients[3] = hasMainFogCoefficients ? getLightData.getField("MainFogCoefficients_3").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[0] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_0").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[1] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_1").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[2] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_2").getDouble() : 0.0f; + currLdRes.HeightDensityFogCoeff[3] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_3").getDouble() : 0.0f; + } - lightResults.push_back(lightResult); + if (timeIndex == 0) { + //Found only one result. Let's copy it to the second slot + lightParamData.lightTimedData[1] = lightParamData.lightTimedData[0]; } } + void CSqliteDB::getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) { getLiquidObjectInfo.setInputs( liquidObjectId ); diff --git a/src/database/CSqliteDB.h b/src/database/CSqliteDB.h index 836387113..7b9920181 100644 --- a/src/database/CSqliteDB.h +++ b/src/database/CSqliteDB.h @@ -21,8 +21,12 @@ class CSqliteDB : public IClientDatabase { AreaRecord getArea(int areaId) override; bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) override; - void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) override; - void getLightById(int lightId, int time, LightResult &lightResult, float farClip) override; + void getLightById(int lightId, int time, LightResult &lightResult) override; + void getEnvInfo(int mapId, float x, float y, float z, std::vector &lightResults) override; + + bool getLightParamData(int lightParamId, int time, LightParamData &lightParamData) override; + + void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) override; void getLiquidTexture(int liquidTypeId, std::vector &textures); @@ -86,6 +90,7 @@ class CSqliteDB : public IClientDatabase { StatementFieldHolder getAreaNameStatement; StatementFieldHolder getLightStatement; StatementFieldHolder getLightByIdStatement; + StatementFieldHolder getLightParamDataStatement; StatementFieldHolder getLightData; StatementFieldHolder getLiquidObjectInfo; StatementFieldHolder getLiquidTypeInfo; @@ -128,74 +133,7 @@ class CSqliteDB : public IClientDatabase { return result; } - struct InnerLightResult { - int id; - float pos[3]; - float fallbackStart; - float fallbackEnd; - float lightDistSQR = 0; - float blendAlpha = 0; - int paramId[8]; - int skyBoxFileId; - int lightSkyboxId; - float glow; - int skyBoxFlags ; - bool isDefault = false; - }; - - struct InnerLightDataRes { - int ambientLight; - int horizontAmbientColor = 0; - int groundAmbientColor = 0; - - int directLight; - int closeRiverColor; - int farRiverColor; - int closeOceanColor; - int farOceanColor; - - int SkyTopColor; - int SkyMiddleColor; - int SkyBand1Color; - int SkyBand2Color; - int SkySmogColor; - int SkyFogColor; - - float FogEnd; - float FogScaler; - float FogDensity; - float FogHeight; - float FogHeightScaler; - float FogHeightDensity; - float FogZScalar; - float MainFogStartDist; - float MainFogEndDist; - float SunFogAngle; - int EndFogColor; - float EndFogColorDistance; - float FogStartOffset; - int SunFogColor; - float SunFogStrength; - int FogHeightColor; - int EndFogHeightColor; - float FogHeightCoefficients[4]; - float MainFogCoefficients[4]; - float HeightDensityFogCoeff[4]; - - int time; - }; - - void convertInnerResultsToPublic(int ptime, std::vector &lightResults, - std::vector &innerResults, float farClip); - - void - addOnlyOne(LightResult &lightResult, const CSqliteDB::InnerLightDataRes &currLdRes) const; - - void - blendTwoAndAdd(LightResult &lightResult, const InnerLightDataRes &lastLdRes, - const InnerLightDataRes &currLdRes, - float timeAlphaBlend) const; - + void getTimedLightParamData(int lightParamId, int time, LightParamData &lightParamData); }; #endif //AWEBWOWVIEWERCPP_CSQLITEDB_H diff --git a/src/ui/renderer/uiScene/FrontendUIRenderer.h b/src/ui/renderer/uiScene/FrontendUIRenderer.h index 8da8c0f46..ef1313dbc 100644 --- a/src/ui/renderer/uiScene/FrontendUIRenderer.h +++ b/src/ui/renderer/uiScene/FrontendUIRenderer.h @@ -8,12 +8,12 @@ #include "../../../../wowViewerLib/src/renderer/IRenderParameters.h" #include "ImGUIPlan.h" #include "IFrontendUIBufferCreate.h" -#include "../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" +#include "ShaderDefinitions.h" static const std::array imguiBindings = {{ {+imguiShader::Attribute::Position, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, pos)}, - {+imguiShader::Attribute::UV, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, uv)}, - {+imguiShader::Attribute::Color, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, col)}, + {+imguiShader::Attribute::UV, 2, GBindingType::GFLOAT, false, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, uv)}, + {+imguiShader::Attribute::Color, 4, GBindingType::GUNSIGNED_BYTE, true, sizeof(ImDrawVert), IM_OFFSETOF(ImDrawVert, col)}, }}; static const PipelineTemplate s_imguiPipelineTemplate = { @@ -47,7 +47,7 @@ class FrontendUIRenderer : public IRendererParameters> m_imguiUbo = nullptr; + std::shared_ptr> m_imguiUbo = nullptr; void consumeFrameInput(const std::shared_ptr> &frameInputParams, std::vector &meshes); diff --git a/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp b/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp index 15406d8ad..18b0f4678 100644 --- a/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp +++ b/src/ui/renderer/uiScene/FrontendUIRendererFactory.cpp @@ -3,12 +3,18 @@ // #include "FrontendUIRendererFactory.h" +#ifdef LINK_VULKAN #include "vulkan/FrontendUIRenderForwardVLK.h" +#endif std::shared_ptr FrontendUIRendererFactory::createForwardRenderer(HGDevice &device) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: +#ifdef LINK_VULKAN return std::make_shared(std::dynamic_pointer_cast(device)); +#else + return nullptr; +#endif default: return nullptr; } diff --git a/wowViewerLib/src/engine/objects/adt/adtObject.cpp b/wowViewerLib/src/engine/objects/adt/adtObject.cpp index 72150492e..23f0f642d 100644 --- a/wowViewerLib/src/engine/objects/adt/adtObject.cpp +++ b/wowViewerLib/src/engine/objects/adt/adtObject.cpp @@ -255,7 +255,7 @@ void AdtObject::createVBO(const HMapSceneBufferCreate &sceneRenderer) { for (int k = 0; k < 3; k++) { adtVertex.normal[k] = m_adtFile->mcnkStructs[i].mcnr->entries[j].normal[k]; } - adtVertex.normal[4] = 0; + adtVertex.normal[3] = 0; } else { *(uint32_t*)&adtVertex.normal = 0x00FF0000; } @@ -1290,11 +1290,13 @@ bool AdtObject::getWaterColorFromDB(mathfu::vec4 cameraPos, mathfu::vec3 &closeR mathfu::vec3 waterPos = (mathfu::vec3(waterAaBB.max) + mathfu::vec3(waterAaBB.min)) / 2.0f; std::vector lightResults = {}; closeRiverColor = {0,0,0}; - this->m_mapApi->getLightResultsFromDB(waterPos, m_api->getConfig(), lightResults, nullptr); - for (auto &_light : lightResults) { - closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; - } - closeRiverColor = mathfu::vec3(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0]); +//TODO: Restore this for futere minimap creator + +// this->m_mapApi->getLightResultsFromDB(waterPos, m_api->getConfig(), lightResults, nullptr); +// for (auto &_light : lightResults) { +// closeRiverColor += mathfu::vec3(_light.closeRiverColor) * _light.blendCoef; +// } +// closeRiverColor = mathfu::vec3(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0]); return true; } diff --git a/wowViewerLib/src/engine/objects/iMapApi.h b/wowViewerLib/src/engine/objects/iMapApi.h index 0b36d93c3..b84ad4f48 100644 --- a/wowViewerLib/src/engine/objects/iMapApi.h +++ b/wowViewerLib/src/engine/objects/iMapApi.h @@ -11,14 +11,6 @@ class IMapApi; #include "../../include/database/dbStructs.h" #include "../../include/config.h" -struct StateForConditions { - int currentAreaId = 0; - int currentParentAreaId = 0; - std::vector currentSkyboxIds = {}; - std::vector currentLightParams = {}; - std::vector currentZoneLights = {}; -}; - class IMapApi { public: virtual std::shared_ptr getM2Object(std::string fileName, SMDoodadDef &doodadDef) = 0; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index f36f5682d..bf9ccd42c 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -414,8 +414,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams //7. Get AreaId and Area Name - StateForConditions stateForConditions; - AreaRecord wmoAreaRecord; bool wmoAreaFound = false; if (mapRenderPlan->m_currentWMO != emptyWMO) { @@ -445,6 +443,9 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->wmoAreaName = wmoAreaRecord.areaName; mapRenderPlan->areaName = areaRecord.areaName; + + auto &stateForConditions = mapRenderPlan->frameDependentData->stateForConditions; + stateForConditions.currentAreaId = areaRecord.areaId; stateForConditions.currentParentAreaId = areaRecord.parentAreaId; @@ -488,8 +489,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams checkExterior(cameraPos, exteriorView->frustumData, m_viewRenderOrder, mapRenderPlan); } - - if ((mapRenderPlan->viewsHolder.getExterior() != nullptr || mapRenderPlan->currentWmoGroupIsExtLit || mapRenderPlan->currentWmoGroupShowExtSkybox)) { ZoneScopedN("Skybox"); auto exteriorView = mapRenderPlan->viewsHolder.getOrCreateExterior(frustumData); @@ -602,21 +601,12 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp l_currentWmoObject->checkFog(frustumData.cameraPos, wmoFogData); } } - std::vector lightResults; + std::vector lightResults; if ((m_api->databaseHandler != nullptr)) { //Check zoneLight getLightResultsFromDB(frustumData.cameraPos, config, lightResults, &stateForConditions); - { - auto &fdd = mapRenderPlan->frameDependentData; - //Fill current light ids - for (auto &light : lightResults) { - fdd->currentLightIds.push_back(light.id); - fdd->currentLightParamIds.push_back(light.lightParamId); - } - } - bool drawDefaultSkybox = true; for (auto &_light : lightResults) { if (!_light.isDefault && _light.blendCoef > 0.99999f) { @@ -1007,49 +997,47 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } } + uint8_t currentLightParamId = 0; + if (zoneLightFound) { - m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult, config->farPlane); + m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult); if (stateForConditions != nullptr) { - stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId); + stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId[currentLightParamId]); } } + //Get light from DB m_api->databaseHandler->getEnvInfo(m_mapId, cameraVec3.x, cameraVec3.y, cameraVec3.z, - config->currentTime, - lightResults, - config->farPlane + lightResults ); + std::sort(lightResults.begin(), lightResults.end(), [](const LightResult &a, const LightResult &b) -> bool { + return a.blendAlpha > b.blendAlpha; + }); + int selectedLightParam = 0; + for (auto it = lightResults.begin(); it != lightResults.end(); it++) { + if (feq(it->pos[0], 0.0) && feq(it->pos[1], 0.0) && feq(it->pos[2], 0.0)) { + //This is default record. If zoneLight was selected -> skip it. + if (!zoneLightFound) { - if (stateForConditions != nullptr) { - for (auto &_light : lightResults) { - stateForConditions->currentZoneLights.push_back(_light.lightParamId); + } } + selectedLightParam = it->lightParamId[currentLightParamId]; } - //Calc final blendcoef for zoneLight; - if (zoneLightFound) { - float blendCoef = 1.0; + config->currentTime, + - //Replace default light with ZoneLight - //TODO: make a blend coef to zonelight border based on the least distance to border and replace default only if that coef is 1.0 - bool hasDefault = false; - zoneLightResult.blendCoef = 1.0f; + if (stateForConditions != nullptr) { for (auto &_light : lightResults) { - if (_light.isDefault) { - hasDefault = true; - _light = zoneLightResult; - } - } - if (!hasDefault) { - lightResults.push_back(zoneLightResult); + stateForConditions->currentZoneLights.push_back(_light.lightParamId[currentLightParamId]); + stateForConditions->currentLightIds.push_back(_light.id); } - std::sort(lightResults.begin(), lightResults.end(), [](auto const &a, auto const &b) {return a.blendCoef > b.blendCoef; }); - } + } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, diff --git a/wowViewerLib/src/gapi/interface/meshes/IMesh.h b/wowViewerLib/src/gapi/interface/meshes/IMesh.h index af619dbd8..3c958afc9 100644 --- a/wowViewerLib/src/gapi/interface/meshes/IMesh.h +++ b/wowViewerLib/src/gapi/interface/meshes/IMesh.h @@ -86,12 +86,8 @@ class IMesh : public ObjectWithId { uint32_t m_start; uint32_t m_end; - - public: - ~IMesh() override { - 1 + 1; - }; + ~IMesh() override = default ; virtual bool getIsTransparent() = 0; virtual MeshType getMeshType() = 0; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index d64c99896..3a39aa0b8 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -19,6 +19,73 @@ struct MapRecord { uint32_t flags0; }; +struct LightResult { + int id; + float pos[3]; + int continentId; + float fallbackStart; + float fallbackEnd; + float lightDistSQR = 0; + float blendAlpha = 0; + int lightParamId[8]; +}; + +struct LightTimedData { + int time; + + int ambientLight = 0 ; + int horizontAmbientColor = 0; + int groundAmbientColor = 0; + + int directColor; + + int closeRiverColor; + int farRiverColor; + int closeOceanColor; + int farOceanColor; + + int SkyTopColor; + int SkyMiddleColor; + int SkyBand1Color; + int SkyBand2Color; + int SkySmogColor; + int SkyFogColor; + + float FogEnd; + float FogScaler; + float FogDensity; + float FogHeight; + float FogHeightScaler; + float FogHeightDensity; + float FogZScalar; + float MainFogStartDist; + float MainFogEndDist; + float SunFogAngle; + int EndFogColor; + float EndFogColorDistance; + float FogStartOffset; + int SunFogColor; + float SunFogStrength; + int FogHeightColor; + int EndFogHeightColor; + float FogHeightCoefficients[4]; + float MainFogCoefficients[4]; + float HeightDensityFogCoeff[4]; +}; + +struct LightParamData { + int lightSkyBoxId = 0; + float glow = 1.0f; + float waterShallowAlpha; + float waterDeepAlpha; + float oceanShallowAlpha; + float oceanDeepAlpha; + int lightParamFlags = 0; + + std::array lightTimedData; +}; + +/* struct LightResult { int id; float ambientColor[3]; @@ -74,6 +141,7 @@ struct LightResult { float blendCoef; bool isDefault = false; }; + */ struct LiquidTextureData { int fileDataId; @@ -126,6 +194,8 @@ struct ZoneLight { std::vector points; }; + + struct AreaRecord { std::string areaName = ""; int areaId = 0; diff --git a/wowViewerLib/src/include/databaseHandler.h b/wowViewerLib/src/include/databaseHandler.h index 802a76a0d..889b376ca 100644 --- a/wowViewerLib/src/include/databaseHandler.h +++ b/wowViewerLib/src/include/databaseHandler.h @@ -15,8 +15,11 @@ class IClientDatabase { virtual bool getMapById(int mapId, MapRecord &mapRecord) = 0; virtual AreaRecord getArea(int areaId) = 0; virtual bool getWmoArea(int wmoId, int nameId, int groupId, AreaRecord &result) = 0; - virtual void getLightById(int lightId, int time, LightResult &lightResult, float farClip) = 0; - virtual void getEnvInfo(int mapId, float x, float y, float z, int time, std::vector &lightResults, float farClip) = 0; + virtual void getLightById(int lightId, int time, LightResult &lightResult) = 0; + virtual void getEnvInfo(int mapId, float x, float y, float z, std::vector &lightResults) = 0; + + virtual bool getLightParamData(int lightParamId, int time, LightParamData &lightParamData) = 0; + virtual void getLiquidObjectData(int liquidObjectId, int fallbackliquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; virtual void getLiquidTypeData(int liquidTypeId, LiquidTypeAndMat &loData, std::vector &textures) = 0; virtual void getZoneLightsForMap(int mapId, std::vector &zoneLights) = 0; diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 3dab76531..7d933961e 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -53,6 +53,16 @@ struct ExteriorColors { mathfu::vec4 exteriorDirectColor = {0.3,0.3,0.3, 0.3}; }; +struct StateForConditions { + int currentAreaId = 0; + int currentParentAreaId = 0; + std::vector currentSkyboxIds = {}; + std::vector currentLightIds = {}; + std::vector currentLightParams = {}; + std::vector currentZoneLights = {}; +}; + + struct FrameDependantData { //Glow float currentGlow; @@ -61,8 +71,7 @@ struct FrameDependantData { ExteriorColors colors; mathfu::vec3 exteriorDirectColorDir; - std::vector currentLightIds; - std::vector currentLightParamIds; + StateForConditions stateForConditions; //Sky params bool overrideValuesWithFinalFog = false; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp index 077328f02..dbfcc2462 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRendererFactory.cpp @@ -3,22 +3,27 @@ // #include "MapSceneRendererFactory.h" +#ifdef LINK_VULKAN #include "vulkan/MapSceneRenderForwardVLK.h" #include "vulkan/MapSceneRenderBindlessVLK.h" - +#endif std::shared_ptr MapSceneRendererFactory::createForwardRenderer(const HGDevice &device, Config * config) { switch (device->getDeviceType()) { case GDeviceType::GVulkan: +#ifdef LINK_VULKAN if (!device->supportsBindless()) { return std::make_shared(std::dynamic_pointer_cast(device), config); } else { return std::make_shared(std::dynamic_pointer_cast(device), config); } +#else + return nullptr; +#endif default: - return std::make_shared(std::dynamic_pointer_cast(device), config); + return nullptr; } return nullptr; From cb34cfbaedaeee7aebe137582be15cf7c5827577 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 3 Jul 2024 12:48:45 +0300 Subject: [PATCH 204/212] temp commit --- .../vulkan/FrontendUIRenderForwardVLK.cpp | 7 ++-- .../vulkan/FrontendUIRenderForwardVLK.h | 4 ++- .../src/engine/objects/scenes/map.cpp | 33 ++++++++++++------- .../descriptorSets/GDescriptorSetLayout.cpp | 4 +-- .../vulkan/shaders/GShaderPermutationVLK.cpp | 4 +-- wowViewerLib/src/include/database/dbStructs.h | 2 ++ 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp index f956bb723..4799eb9b2 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.cpp @@ -26,7 +26,8 @@ void FrontendUIRenderForwardVLK::createBuffers() { vboBuffer = m_device->createVertexBuffer("UI_Vbo_Buffer", 1024*1024); uboBuffer = m_device->createUniformBuffer("UI_UBO", sizeof(ImgUI::modelWideBlockVS)*IDevice::MAX_FRAMES_IN_FLIGHT); - m_imguiUbo = std::make_shared>(uboBuffer); + m_imguiUboVLK = std::make_shared>(uboBuffer); + m_imguiUbo = m_imguiUboVLK; } HGVertexBuffer FrontendUIRenderForwardVLK::createVertexBuffer(int sizeInBytes) { @@ -58,7 +59,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterial(const } } - auto &l_imguiUbo = m_imguiUbo; + auto &l_imguiUbo = m_imguiUboVLK; auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", !opaque?"imguiShader":"imguiShader_opaque"}, {"forwardRendering","forwardRendering"}, {}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { @@ -92,7 +93,7 @@ std::shared_ptr FrontendUIRenderForwardVLK::createUIMaterialDepth(c } } - auto &l_imguiUbo = m_imguiUbo; + auto &l_imguiUbo = m_imguiUboVLK; auto material = MaterialBuilderVLK::fromShader(m_device, {"imguiShader", "imguiShaderDepth"}, {"forwardRendering", "forwardRendering"}, {}) .createPipeline(m_emptyImguiVAO, m_lastRenderPass, s_imguiPipelineTemplate) .createDescriptorSet(0, [&l_imguiUbo](std::shared_ptr &ds) { diff --git a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h index 67c0c671e..cd521ea19 100644 --- a/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h +++ b/src/ui/renderer/uiScene/vulkan/FrontendUIRenderForwardVLK.h @@ -5,7 +5,6 @@ #ifndef AWEBWOWVIEWERCPP_FRONTENDUIRENDERFORWARDVLK_H #define AWEBWOWVIEWERCPP_FRONTENDUIRENDERFORWARDVLK_H - #include #include #include "../FrontendUIRenderer.h" @@ -16,6 +15,7 @@ #include "../../../../../wowViewerLib/src/renderer/vulkan/IRenderFunctionVLK.h" #include "../../../../../wowViewerLib/src/gapi/vulkan/meshes/GMeshVLK.h" #include "../../../../../wowViewerLib/src/engine/objects/scenes/EntityActorsFactory.h" +#include "../../../../../wowViewerLib/src/gapi/vulkan/buffers/CBufferChunkVLK.h" class FrontendUIRenderForwardVLK : public FrontendUIRenderer { public: @@ -54,6 +54,8 @@ class FrontendUIRenderForwardVLK : public FrontendUIRenderer { std::shared_ptr m_lastRenderPass; std::shared_ptr> m_previousMeshes = nullptr; + std::shared_ptr> m_imguiUboVLK = nullptr; + HGVertexBufferBindings m_emptyImguiVAO = nullptr; }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index bf9ccd42c..5ad5d0e02 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -997,12 +997,17 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } } - uint8_t currentLightParamId = 0; + uint8_t currentLightParamIdIndex = 0; + + int selectedLightParam = 0; + int selectedLightId = 0; if (zoneLightFound) { + selectedLightId = LightId; m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult); if (stateForConditions != nullptr) { - stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId[currentLightParamId]); + selectedLightParam = zoneLightResult.lightParamId[currentLightParamIdIndex]; + stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId[currentLightParamIdIndex]); } } @@ -1017,27 +1022,31 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, return a.blendAlpha > b.blendAlpha; }); - int selectedLightParam = 0; + for (auto it = lightResults.begin(); it != lightResults.end(); it++) { if (feq(it->pos[0], 0.0) && feq(it->pos[1], 0.0) && feq(it->pos[2], 0.0)) { //This is default record. If zoneLight was selected -> skip it. if (!zoneLightFound) { - + selectedLightParam = it->lightParamId[currentLightParamIdIndex]; + selectedLightId = it->id; } + } else { + selectedLightParam = it->lightParamId[currentLightParamIdIndex]; + selectedLightId = it->id; + break; } - selectedLightParam = it->lightParamId[currentLightParamId]; } - config->currentTime, - - if (stateForConditions != nullptr) { - for (auto &_light : lightResults) { - stateForConditions->currentZoneLights.push_back(_light.lightParamId[currentLightParamId]); - stateForConditions->currentLightIds.push_back(_light.id); - } + stateForConditions->currentZoneLights.push_back(selectedLightParam); + stateForConditions->currentLightIds.push_back(selectedLightId); } + LightParamData lightParamData; + if (m_api->databaseHandler->getLightParamData(selectedLightParam, config->currentTime, lightParamData)) { + //Blend two times using certain rules + + } } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, diff --git a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp index 96c9143cc..22f7e8623 100644 --- a/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp +++ b/wowViewerLib/src/gapi/vulkan/descriptorSets/GDescriptorSetLayout.cpp @@ -202,8 +202,8 @@ void GDescriptorSetLayout::fillUbo(int setIndex, const DescTypeOverride &typeOve void GDescriptorSetLayout::fillSSBO(int setIndex, const DescTypeOverride &typeOverrides, std::unordered_map &shaderLayoutBindings, const shaderMetaData *p_metaData, const VkShaderStageFlagBits &vkStageFlag) { - for (int i = 0; i < p_metaData->ssboBindings.size(); i++) { - auto &ssboBinding = p_metaData->ssboBindings[i]; + for (int i = 0; i < p_metaData->m_ssboBindings.size(); i++) { + auto &ssboBinding = p_metaData->m_ssboBindings[i]; if (ssboBinding.set != setIndex) continue; diff --git a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp index 5cf2511ad..2cf9cc79d 100644 --- a/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp +++ b/wowViewerLib/src/gapi/vulkan/shaders/GShaderPermutationVLK.cpp @@ -132,8 +132,8 @@ void GShaderPermutationVLK::createShaderLayout() { } } - for (int i = 0; i < shaderMeta->ssboBindings.size(); i++) { - auto &ssboBinding = shaderMeta->ssboBindings[i]; + for (int i = 0; i < shaderMeta->m_ssboBindings.size(); i++) { + auto &ssboBinding = shaderMeta->m_ssboBindings[i]; auto &setLayout = combinedShaderLayout.setLayouts[ssboBinding.set]; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 3a39aa0b8..555d45315 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -82,6 +82,8 @@ struct LightParamData { float oceanDeepAlpha; int lightParamFlags = 0; + + std::array lightTimedData; }; From 15c05ea6ab405dce4f5d4166a78171bb14e1cc9c Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 3 Jul 2024 21:35:49 +0300 Subject: [PATCH 205/212] temp commit --- src/ui/FrontendUI.cpp | 4 +- wowViewerLib/src/engine/objects/iMapApi.h | 5 +- .../src/engine/objects/scenes/map.cpp | 102 +++++++++++++++++- wowViewerLib/src/engine/objects/scenes/map.h | 5 +- wowViewerLib/src/include/database/dbStructs.h | 6 +- 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/ui/FrontendUI.cpp b/src/ui/FrontendUI.cpp index 0ecf13264..ff755cb05 100644 --- a/src/ui/FrontendUI.cpp +++ b/src/ui/FrontendUI.cpp @@ -321,14 +321,14 @@ void FrontendUI::showCurrentStatsDialog() { if (cullStageData != nullptr && cullStageData->frameDependentData != nullptr ) { ImGui::Text("List of current Light.db2 ids:"); - for (auto lightId : cullStageData->frameDependentData->currentLightIds) { + for (auto lightId : cullStageData->frameDependentData->stateForConditions.currentLightIds) { ImGui::Text("%d", lightId); } ImGui::Separator(); ImGui::Text("List of current LightParams.db2 ids:"); - for (auto lightParamId : cullStageData->frameDependentData->currentLightParamIds) { + for (auto lightParamId : cullStageData->frameDependentData->stateForConditions.currentLightParams) { ImGui::Text("%d", lightParamId); } } diff --git a/wowViewerLib/src/engine/objects/iMapApi.h b/wowViewerLib/src/engine/objects/iMapApi.h index b84ad4f48..a23671735 100644 --- a/wowViewerLib/src/engine/objects/iMapApi.h +++ b/wowViewerLib/src/engine/objects/iMapApi.h @@ -19,7 +19,10 @@ class IMapApi { virtual std::shared_ptr getWmoObject(int fileDataId, SMMapObjDef &mapObjDef) = 0; virtual std::shared_ptr getWmoObject(std::string fileName, SMMapObjDefObj1 &mapObjDef) = 0; virtual std::shared_ptr getWmoObject(int fileDataId, SMMapObjDefObj1 &mapObjDef) = 0; - virtual void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults,StateForConditions *stateForConditions) = 0; + virtual void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, + SkyColors &skyColors, + ExteriorColors &exteriorColors, + FogResult &fogResult, StateForConditions *stateForConditions) = 0; virtual animTime_t getCurrentSceneTime() = 0; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 5ad5d0e02..a86c761e1 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -973,7 +973,68 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp } } -void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) { +template +inline float getFloatFromInt(int value) { + if constexpr (T == 0) { + return (value & 0xFF) / 255.0f; + } + if constexpr (T == 1) { + return ((value >> 8) & 0xFF) / 255.0f; + } + if constexpr (T == 2) { + return ((value >> 16) & 0xFF) / 255.0f; + } +} + +inline mathfu::vec3 intToColor3(int a) { + //BGR + return mathfu::vec3( + getFloatFromInt<2>(a), + getFloatFromInt<1>(a), + getFloatFromInt<0>(a) + ); +} +inline mathfu::vec4 intToColor4(int a) { + //BGRA + return mathfu::vec4( + getFloatFromInt<2>(a), + getFloatFromInt<1>(a), + getFloatFromInt<0>(a), + getFloatFromInt<3>(a) + ); +} +inline mathfu::vec4 floatArr(std::array a) { + //BGRA + return mathfu::vec4( + a[3], + a[2], + a[1], + a[0] + ); +} + +template +decltype(auto) mixMembers(LightParamData& data, T LightTimedData::*member, float blendTimeCoeff) { + if constexpr (C == 3) { + static_assert(std::is_same::value, "the type must be int for vector component"); + return mix(intToColor3(data.lightTimedData[0].*member), intToColor3(data.lightTimedData[0].*member), blendTimeCoeff); + } + if constexpr (C == 4 && std::is_same>::value) { + return mix(floatArr(data.lightTimedData[0].*member), floatArr(data.lightTimedData[1].*member), blendTimeCoeff); + } else if constexpr (C == 4) { + static_assert(std::is_same::value, "the type must be int for vector component"); + return mix(intToColor4(data.lightTimedData[0].*member), intToColor4(data.lightTimedData[0].*member), blendTimeCoeff); + } + if constexpr (C == 1) { + static_assert(std::is_same::value, "the type must be float for one component"); + return mix(data.lightTimedData[0].*member, data.lightTimedData[0].*member, blendTimeCoeff); + } +} + +void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, + SkyColors &skyColors, + ExteriorColors &exteriorColors, + FogResult &fogResult, StateForConditions *stateForConditions) { if (m_api->databaseHandler == nullptr) return ; @@ -1044,8 +1105,47 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, LightParamData lightParamData; if (m_api->databaseHandler->getLightParamData(selectedLightParam, config->currentTime, lightParamData)) { + + float blendTimeCoeff = (config->currentTime - lightParamData.lightTimedData[0].time) / (float)(lightParamData.lightTimedData[1].time - lightParamData.lightTimedData[0].time); + + auto &dataA = lightParamData.lightTimedData[0]; + auto &dataB = lightParamData.lightTimedData[1]; //Blend two times using certain rules + //Ambient lights + + //Fog! + fogResult.FogEnd = mixMembers<1>(lightParamData, &LightTimedData::FogEnd, blendTimeCoeff); + fogResult.FogScaler = mixMembers<1>(lightParamData, &LightTimedData::FogScaler, blendTimeCoeff); + fogResult.FogDensity = mixMembers<1>(lightParamData, &LightTimedData::FogDensity, blendTimeCoeff); + fogResult.FogHeight = mixMembers<1>(lightParamData, &LightTimedData::FogHeight, blendTimeCoeff); + fogResult.FogHeightScaler = mixMembers<1>(lightParamData, &LightTimedData::FogHeightScaler, blendTimeCoeff); + fogResult.FogHeightDensity = mixMembers<1>(lightParamData, &LightTimedData::FogHeightDensity, blendTimeCoeff); + fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff); + + if (false) {//fdd->overrideValuesWithFinalFog) { + fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); + } else { + fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); + } + + fogResult.EndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); + fogResult.EndFogColorDistance = mixMembers<1>(lightParamData, &LightTimedData::EndFogColorDistance, blendTimeCoeff); + fogResult.SunFogColor = mixMembers<3>(lightParamData, &LightTimedData::SunFogColor, blendTimeCoeff); + fogResult.SunFogStrength = mixMembers<1>(lightParamData, &LightTimedData::SunFogStrength, blendTimeCoeff); + fogResult.FogHeightColor = mixMembers<3>(lightParamData, &LightTimedData::FogHeightColor, blendTimeCoeff); + fogResult.FogHeightCoefficients = mixMembers<4>(lightParamData, &LightTimedData::FogHeightCoefficients, blendTimeCoeff); + fogResult.MainFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); + fogResult.HeightDensityFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); + + fogResult.FogZScalar = mixMembers<1>(lightParamData, &LightTimedData::FogZScalar, blendTimeCoeff); +// fogResult.LegacyFogScalar = mixMembers<1>(lightParamData, &LightTimedData::LegacyFogScalar, blendTimeCoeff); + fogResult.MainFogStartDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogStartDist, blendTimeCoeff); + fogResult.MainFogEndDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogEndDist, blendTimeCoeff); +// fogResult.FogBlendAlpha = mixMembers<1>(lightParamData, &LightTimedData::FogBlendAlpha, blendTimeCoeff); + fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); + fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); + } } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 0a2cecd35..17210d937 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -207,7 +207,10 @@ class Map : public IScene, public IMapApi { // HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; - void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, std::vector &lightResults, StateForConditions *stateForConditions) override; + void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, + SkyColors &skyColors, + ExteriorColors &exteriorColors, + FogResult &fogResult, StateForConditions *stateForConditions) override; void createAdtFreeLamdas(); }; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 555d45315..7b33567c1 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -68,9 +68,9 @@ struct LightTimedData { float SunFogStrength; int FogHeightColor; int EndFogHeightColor; - float FogHeightCoefficients[4]; - float MainFogCoefficients[4]; - float HeightDensityFogCoeff[4]; + std::array FogHeightCoefficients; + std::array MainFogCoefficients; + std::array HeightDensityFogCoeff; }; struct LightParamData { From abe54269ec779cc5ef46b16de9d1ba9ea92d41dc Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Thu, 4 Jul 2024 00:29:13 +0300 Subject: [PATCH 206/212] temp commit --- .../glsl/bindless/water/waterShader.frag | 6 +- .../glsl/common/commonLightFunctions.glsl | 8 +- .../glsl/forwardRendering/waterShader.frag | 4 +- wowViewerLib/src/engine/objects/iMapApi.h | 4 +- .../src/engine/objects/scenes/map.cpp | 167 +++++------------- wowViewerLib/src/engine/objects/scenes/map.h | 5 +- wowViewerLib/src/include/database/dbStructs.h | 4 +- .../renderer/mapScene/FrameDependentData.h | 12 +- 8 files changed, 72 insertions(+), 138 deletions(-) diff --git a/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag index 660525fc2..3d6d9a719 100644 --- a/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag +++ b/wowViewerLib/shaders/glsl/bindless/water/waterShader.frag @@ -87,10 +87,10 @@ void main() { int materialId = waterData.materialId_liquidFlags.x; if ((liquidFlags & 1024) > 0) {// Ocean - color = scene.closeOceanColor; + color = scene.closeOceanColor_shallowAlpha; } else if (liquidFlags == 15) { //River/Lake //Query river color - color = vec4(scene.closeRiverColor.xyz, 0.7); + color = scene.closeRiverColor_shallowAlpha; } else { color = vec4(waterData.matColor.xyz, 0.7); } @@ -125,7 +125,7 @@ void main() { 0, scene, intLight, - vec3(0.0) /*accumLight*/, + vec3(0.0) /* accumLight */, vec3(0.0), vec3(0.0), /* specular */ vec3(0.0), diff --git a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl index c603ab3bf..85db197a8 100644 --- a/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl +++ b/wowViewerLib/shaders/glsl/common/commonLightFunctions.glsl @@ -39,10 +39,10 @@ struct SceneWideParams { vec4 uInteriorSunDir; vec4 uSceneSize_DisableLightBuffer; - vec4 closeRiverColor; - vec4 farRiverColor; - vec4 closeOceanColor; - vec4 farOceanColor; + vec4 closeRiverColor_shallowAlpha; + vec4 farRiverColor_deepAlpha; + vec4 closeOceanColor_shallowAlpha; + vec4 farOceanColor_deepAlpha; SceneExteriorLight extLight; }; diff --git a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag index 23ca678e8..e07b5b91e 100644 --- a/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag +++ b/wowViewerLib/shaders/glsl/forwardRendering/waterShader.frag @@ -79,10 +79,10 @@ void main() { vec4 color = vec4(0.0); int liquidFlags = materialId_liquidFlags.y; if ((materialId_liquidFlags.y & 1024) > 0) {// Ocean - color = scene.closeOceanColor; + color = scene.closeRiverColor_shallowAlpha; } else if (liquidFlags == 15) { //River/Lake //Query river color - color = vec4(scene.closeRiverColor.xyz, 0.7); + color = vec4(scene.closeRiverColor_shallowAlpha.xyz, 0.7); } else { color = vec4(matColor.xyz, 0.7); } diff --git a/wowViewerLib/src/engine/objects/iMapApi.h b/wowViewerLib/src/engine/objects/iMapApi.h index a23671735..616842fa6 100644 --- a/wowViewerLib/src/engine/objects/iMapApi.h +++ b/wowViewerLib/src/engine/objects/iMapApi.h @@ -22,7 +22,9 @@ class IMapApi { virtual void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, SkyColors &skyColors, ExteriorColors &exteriorColors, - FogResult &fogResult, StateForConditions *stateForConditions) = 0; + FogResult &fogResult, + LiquidColors &liquidColors, + StateForConditions *stateForConditions) = 0; virtual animTime_t getCurrentSceneTime() = 0; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index a86c761e1..e69fbcc87 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -311,7 +311,6 @@ std::tuple> createSkyMesh(const HMapSc pipelineTemplate.element = DrawElementMode::TRIANGLE_STRIP; auto material = sceneRenderer->createSkyMeshMaterial(pipelineTemplate); - //TODO: Pass m_skyConeAlpha to fragment shader gMeshTemplate meshTemplate(skyBindings); @@ -556,9 +555,9 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams mapRenderPlan->renderSky = m_api->getConfig()->renderSkyDom && (!m_suppressDrawingSky && (mapRenderPlan->viewsHolder.getExterior() || mapRenderPlan->currentWmoGroupIsExtLit)); - if (m_skyConeAlpha > 0) { +// if (m_skyConeAlpha > 0) { mapRenderPlan->skyMesh = skyMesh; - } +// } if (mapRenderPlan->frameDependentData->overrideValuesWithFinalFog) { mapRenderPlan->skyMesh0x4 = skyMesh0x4Sky; } @@ -605,16 +604,15 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp std::vector lightResults; if ((m_api->databaseHandler != nullptr)) { //Check zoneLight - getLightResultsFromDB(frustumData.cameraPos, config, lightResults, &stateForConditions); - - bool drawDefaultSkybox = true; - for (auto &_light : lightResults) { - if (!_light.isDefault && _light.blendCoef > 0.99999f) { - drawDefaultSkybox = false; - } - } + SkyColors skyColors; + ExteriorColors exteriorColors; + FogResult fogResult; + LiquidColors liquidColors; + getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, fogResult, liquidColors, &stateForConditions); + //TODO: restore skyboxes + /* //Delete skyboxes that are not in light array std::unordered_map> perFdidMap; auto modelIt = m_exteriorSkyBoxes.begin(); @@ -675,51 +673,9 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp skyBox->setOverrideAnimationPerc(config->currentTime / 2880.0, true); } } + */ - //Blend glow and ambient - mathfu::vec3 ambientColor = {0, 0, 0}; - mathfu::vec3 horizontAmbientColor = {0, 0, 0}; - mathfu::vec3 groundAmbientColor = {0, 0, 0}; - mathfu::vec3 directColor = {0, 0, 0}; - mathfu::vec3 closeRiverColor = {0, 0, 0}; - mathfu::vec3 farRiverColor = {0, 0, 0}; - mathfu::vec3 closeOceanColor = {0, 0, 0}; - mathfu::vec3 farOceanColor = {0, 0, 0}; - - mathfu::vec3 SkyTopColor = {0, 0, 0}; - mathfu::vec3 SkyMiddleColor = {0, 0, 0}; - mathfu::vec3 SkyBand1Color = {0, 0, 0}; - mathfu::vec3 SkyBand2Color = {0, 0, 0}; - mathfu::vec3 SkySmogColor = {0, 0, 0}; - mathfu::vec3 SkyFogColor = {0, 0, 0}; - float currentGlow = 0; - - for (auto &_light : lightResults) { - currentGlow = mix(currentGlow, _light.glow, _light.blendCoef); - - ambientColor = mix(ambientColor, mathfu::vec3(_light.ambientColor), _light.blendCoef); - horizontAmbientColor = mix(horizontAmbientColor, mathfu::vec3(_light.horizontAmbientColor), _light.blendCoef); - groundAmbientColor = mix(groundAmbientColor, mathfu::vec3(_light.groundAmbientColor), _light.blendCoef); - directColor = mix(directColor, mathfu::vec3(_light.directColor), _light.blendCoef); - - closeRiverColor = mix(closeRiverColor, mathfu::vec3(_light.closeRiverColor), _light.blendCoef); - farRiverColor = mix(farRiverColor, mathfu::vec3(_light.farRiverColor), _light.blendCoef); - closeOceanColor = mix(closeOceanColor, mathfu::vec3(_light.closeOceanColor), _light.blendCoef); - farOceanColor = mix(farOceanColor, mathfu::vec3(_light.farOceanColor), _light.blendCoef); - - SkyTopColor = mix(SkyTopColor, mathfu::vec3(_light.SkyTopColor.data()), _light.blendCoef); - SkyMiddleColor = mix(SkyMiddleColor, mathfu::vec3(_light.SkyMiddleColor), _light.blendCoef); - SkyBand1Color = mix(SkyBand1Color, mathfu::vec3(_light.SkyBand1Color), _light.blendCoef); - SkyBand2Color = mix(SkyBand2Color, mathfu::vec3(_light.SkyBand2Color), _light.blendCoef); - SkySmogColor = mix(SkySmogColor, mathfu::vec3(_light.SkySmogColor), _light.blendCoef); - SkyFogColor = mix(SkyFogColor, mathfu::vec3(_light.SkyFogColor.data()), _light.blendCoef); - } - - //Database is in BGRA float ambientMult = areaRecord.ambientMultiplier * 2.0f + 1; -// ambientColor *= ambientMult; -// groundAmbientColor *= ambientMult; -// horizontAmbientColor *= ambientMult; if (config->glowSource == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; @@ -733,12 +689,8 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp if (config->globalLighting == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->colors.exteriorAmbientColor = mathfu::vec4(ambientColor[2], ambientColor[1], ambientColor[0], 0); - fdd->colors.exteriorGroundAmbientColor = mathfu::vec4(groundAmbientColor[2], groundAmbientColor[1], groundAmbientColor[0], - 0); - fdd->colors.exteriorHorizontAmbientColor = mathfu::vec4(horizontAmbientColor[2], horizontAmbientColor[1], - horizontAmbientColor[0], 0); - fdd->colors.exteriorDirectColor = mathfu::vec4(directColor[2], directColor[1], directColor[0], 0); + fdd->colors = exteriorColors; + auto extDir = MathHelper::calcExteriorColorDir( frustumData.viewMat, m_api->getConfig()->currentTime @@ -766,53 +718,22 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp if (config->waterColorParams == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->closeRiverColor = mathfu::vec4(closeRiverColor[2], closeRiverColor[1], closeRiverColor[0], 0); - fdd->farRiverColor = mathfu::vec4(farRiverColor[2], farRiverColor[1], farRiverColor[0], 0); - fdd->closeOceanColor = mathfu::vec4(closeOceanColor[2], closeOceanColor[1], closeOceanColor[0], 0); - fdd->farOceanColor = mathfu::vec4(farOceanColor[2], farOceanColor[1], farOceanColor[0], 0); + fdd->liquidColors = liquidColors; } else if (config->waterColorParams == EParameterSource::eConfig) { auto fdd = mapRenderPlan->frameDependentData; - fdd->closeRiverColor = config->closeRiverColor; - fdd->farRiverColor = config->farRiverColor; - fdd->closeOceanColor = config->closeOceanColor; - fdd->farOceanColor = config->farOceanColor; + fdd->liquidColors.closeRiverColor_shallowAlpha = config->closeRiverColor; + fdd->liquidColors.farRiverColor_deepAlpha = config->farRiverColor; + fdd->liquidColors.closeOceanColor_shallowAlpha = config->closeOceanColor; + fdd->liquidColors.farOceanColor_deepAlpha = config->farOceanColor; } if (config->skyParams == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->skyColors.SkyTopColor = mathfu::vec4(SkyTopColor[2], SkyTopColor[1], SkyTopColor[0], 1.0); - fdd->skyColors.SkyMiddleColor = mathfu::vec4(SkyMiddleColor[2], SkyMiddleColor[1], SkyMiddleColor[0], 1.0); - fdd->skyColors.SkyBand1Color = mathfu::vec4(SkyBand1Color[2], SkyBand1Color[1], SkyBand1Color[0], 1.0); - fdd->skyColors.SkyBand2Color = mathfu::vec4(SkyBand2Color[2], SkyBand2Color[1], SkyBand2Color[0], 1.0); - fdd->skyColors.SkySmogColor = mathfu::vec4(SkySmogColor[2], SkySmogColor[1], SkySmogColor[0], 1.0); - fdd->skyColors.SkyFogColor = mathfu::vec4(SkyFogColor[2], SkyFogColor[1], SkyFogColor[0], 1.0); + fdd->skyColors = skyColors; } } //Handle fog { - float FogEnd = 0; - float FogScaler = 0; - float FogDensity = 0; - float FogHeight = 0; - float FogHeightScaler = 0; - float FogHeightDensity = 0; - float SunFogAngle = 0; - mathfu::vec3 EndFogColor = mathfu::vec3(0,0,0); - float EndFogColorDistance = 0; - mathfu::vec3 SunFogColor = mathfu::vec3(0,0,0); - float SunFogStrength = 0; - mathfu::vec3 FogHeightColor = mathfu::vec3(0,0,0); - mathfu::vec4 FogHeightCoefficients = mathfu::vec4(0,0,0,0); - mathfu::vec4 MainFogCoefficients = mathfu::vec4(0,0,0,0); - mathfu::vec4 HeightDensityFogCoefficients = mathfu::vec4(0,0,0,0); - float FogZScalar = 0; - float LegacyFogScalar = 0; - float MainFogStartDist = 0; - float MainFogEndDist = 0; - float FogBlendAlpha = 0; - mathfu::vec3 HeightEndFogColor = mathfu::vec3(0,0,0); - float FogStartOffset = 0; - std::vector combinedResults = {}; float totalSummator = 0.0; @@ -866,29 +787,7 @@ void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelp //Apply fogs from lights if (totalSummator < 1.0) { if (config->globalFog == EParameterSource::eDatabase) { - bool fogDefaultExist = false; - int fogDefaultIndex = -1; - - for (int i = 0; i < lightResults.size() && totalSummator < 1.0f; i++) { - auto &fogRec = lightResults[i]; - if (fogRec.isDefault) { - fogDefaultExist = true; - fogDefaultIndex = i; - continue; - } - if (totalSummator + fogRec.blendCoef > 1.0f) { - fogRec.blendCoef = 1.0f - totalSummator; - totalSummator = 1.0f; - } else { - totalSummator += fogRec.blendCoef; - } - combinedResults.push_back(fogRec); - } - if (fogDefaultExist && totalSummator < 1.0f) { - lightResults[fogDefaultIndex].blendCoef = 1.0f - totalSummator; - totalSummator = 1.0f; - combinedResults.push_back(lightResults[fogDefaultIndex]); - } + } else if (config->globalFog == EParameterSource::eConfig) { LightResult globalFog; globalFog.FogScaler = config->fogResult.FogScaler; @@ -1034,7 +933,9 @@ decltype(auto) mixMembers(LightParamData& data, T LightTimedData::*member, float void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, SkyColors &skyColors, ExteriorColors &exteriorColors, - FogResult &fogResult, StateForConditions *stateForConditions) { + FogResult &fogResult, + LiquidColors &liquidColors, + StateForConditions *stateForConditions) { if (m_api->databaseHandler == nullptr) return ; @@ -1073,6 +974,7 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, } //Get light from DB + std::vector lightResults; m_api->databaseHandler->getEnvInfo(m_mapId, cameraVec3.x, cameraVec3.y, @@ -1113,6 +1015,29 @@ void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, //Blend two times using certain rules //Ambient lights + exteriorColors.exteriorAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::ambientLight, blendTimeCoeff); + exteriorColors.exteriorGroundAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::groundAmbientColor, blendTimeCoeff); + exteriorColors.exteriorHorizontAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::horizontAmbientColor, blendTimeCoeff); + exteriorColors.exteriorDirectColor = mixMembers<4>(lightParamData, &LightTimedData::directColor, blendTimeCoeff); + + //Liquid colors + liquidColors.closeOceanColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeOceanColor, blendTimeCoeff); + liquidColors.farOceanColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farOceanColor, blendTimeCoeff); + liquidColors.closeRiverColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeRiverColor, blendTimeCoeff); + liquidColors.farRiverColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farRiverColor, blendTimeCoeff); + + liquidColors.closeOceanColor_shallowAlpha.w = lightParamData.oceanShallowAlpha; + liquidColors.farOceanColor_deepAlpha.w = lightParamData.oceanDeepAlpha; + liquidColors.closeRiverColor_shallowAlpha.w = lightParamData.waterShallowAlpha; + liquidColors.farRiverColor_deepAlpha.w = lightParamData.waterDeepAlpha; + + //SkyColors + skyColors.SkyTopColor = mixMembers<4>(lightParamData, &LightTimedData::SkyTopColor, blendTimeCoeff); + skyColors.SkyMiddleColor = mixMembers<4>(lightParamData, &LightTimedData::SkyMiddleColor, blendTimeCoeff); + skyColors.SkyBand1Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand1Color, blendTimeCoeff); + skyColors.SkyBand2Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand2Color, blendTimeCoeff); + skyColors.SkySmogColor = mixMembers<4>(lightParamData, &LightTimedData::SkySmogColor, blendTimeCoeff); + skyColors.SkyFogColor = mixMembers<4>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); //Fog! fogResult.FogEnd = mixMembers<1>(lightParamData, &LightTimedData::FogEnd, blendTimeCoeff); diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 17210d937..89137eb8a 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -63,7 +63,6 @@ class Map : public IScene, public IMapApi { int m_viewRenderOrder = 0; - float m_skyConeAlpha = 0.0; HGMesh skyMesh = nullptr; std::shared_ptr skyMeshMat = nullptr; @@ -210,7 +209,9 @@ class Map : public IScene, public IMapApi { void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, SkyColors &skyColors, ExteriorColors &exteriorColors, - FogResult &fogResult, StateForConditions *stateForConditions) override; + FogResult &fogResult, + LiquidColors &liquidColors, + StateForConditions *stateForConditions) override; void createAdtFreeLamdas(); }; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 7b33567c1..af023ac75 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -82,7 +82,9 @@ struct LightParamData { float oceanDeepAlpha; int lightParamFlags = 0; - + std::string skyBoxName; + int skyBoxFdid; + int skyBoxFlags; std::array lightTimedData; }; diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 7d933961e..2d79f8179 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -46,6 +46,13 @@ struct SkyColors { mathfu::vec4 SkyFogColor; }; +struct LiquidColors { + mathfu::vec4 closeRiverColor_shallowAlpha = mathfu::vec4(0,0,0,0); + mathfu::vec4 farRiverColor_deepAlpha = mathfu::vec4(0,0,0,0); + + mathfu::vec4 closeOceanColor_shallowAlpha = mathfu::vec4(0,0,0,0); + mathfu::vec4 farOceanColor_deepAlpha = mathfu::vec4(0,0,0,0); +}; struct ExteriorColors { mathfu::vec4 exteriorAmbientColor = {1, 1, 1, 1}; mathfu::vec4 exteriorHorizontAmbientColor = {1, 1, 1, 1}; @@ -85,11 +92,8 @@ struct FrameDependantData { //Water params bool useMinimapWaterColor; bool useCloseRiverColorForDB; - mathfu::vec4 closeRiverColor = mathfu::vec4(0,0,0,0); - mathfu::vec4 farRiverColor = mathfu::vec4(0,0,0,0); - mathfu::vec4 closeOceanColor = mathfu::vec4(0,0,0,0); - mathfu::vec4 farOceanColor = mathfu::vec4(0,0,0,0); + LiquidColors liquidColors; }; typedef std::shared_ptr HFrameDependantData; From 444198f0320a6b5dadba4c70d4d5a50671da9f16 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Fri, 5 Jul 2024 02:44:26 +0300 Subject: [PATCH 207/212] temp commit --- wowViewerLib/CMakeLists.txt | 2 + wowViewerLib/src/engine/objects/iMapApi.h | 7 - .../DayNightLightHolder.cpp | 601 ++++++++++++++++++ .../dayNightDataHolder/DayNightLightHolder.h | 44 ++ .../src/engine/objects/scenes/map.cpp | 533 +--------------- wowViewerLib/src/engine/objects/scenes/map.h | 30 +- .../renderer/mapScene/MapSceneRenderer.cpp | 8 +- 7 files changed, 663 insertions(+), 562 deletions(-) create mode 100644 wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp create mode 100644 wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h diff --git a/wowViewerLib/CMakeLists.txt b/wowViewerLib/CMakeLists.txt index c913f7e38..00b2dce65 100644 --- a/wowViewerLib/CMakeLists.txt +++ b/wowViewerLib/CMakeLists.txt @@ -378,6 +378,8 @@ set(SOURCE_FILES src/engine/objects/lights/CSpotLight.h src/engine/objects/lights/CWmoNewLight.cpp src/engine/objects/lights/CWmoNewLight.h + src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp + src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h ) if (LINK_OGL2) diff --git a/wowViewerLib/src/engine/objects/iMapApi.h b/wowViewerLib/src/engine/objects/iMapApi.h index 616842fa6..3d7f4e355 100644 --- a/wowViewerLib/src/engine/objects/iMapApi.h +++ b/wowViewerLib/src/engine/objects/iMapApi.h @@ -19,13 +19,6 @@ class IMapApi { virtual std::shared_ptr getWmoObject(int fileDataId, SMMapObjDef &mapObjDef) = 0; virtual std::shared_ptr getWmoObject(std::string fileName, SMMapObjDefObj1 &mapObjDef) = 0; virtual std::shared_ptr getWmoObject(int fileDataId, SMMapObjDefObj1 &mapObjDef) = 0; - virtual void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, - SkyColors &skyColors, - ExteriorColors &exteriorColors, - FogResult &fogResult, - LiquidColors &liquidColors, - StateForConditions *stateForConditions) = 0; - virtual animTime_t getCurrentSceneTime() = 0; }; diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp new file mode 100644 index 000000000..f4a0f56fb --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -0,0 +1,601 @@ +// +// Created by Deamon on 7/5/2024. +// + +#include "DayNightLightHolder.h" +#include "../../../../include/database/dbStructs.h" +#include "../../../algorithms/mathHelper.h" + +DayNightLightHolder::DayNightLightHolder(const HApiContainer &api, int mapId) : m_api(api), m_mapId(mapId) { + +} + +void DayNightLightHolder::loadZoneLights() { + if (m_api->databaseHandler != nullptr) { + std::vector zoneLights; + m_api->databaseHandler->getZoneLightsForMap(m_mapId, zoneLights); + + for (const auto &zoneLight : zoneLights) { + mapInnerZoneLightRecord innerZoneLightRecord; + innerZoneLightRecord.ID = zoneLight.ID; + innerZoneLightRecord.name = zoneLight.name; + innerZoneLightRecord.LightID = zoneLight.LightID; +// innerZoneLightRecord.Zmin = zoneLight.Zmin; +// innerZoneLightRecord.Zmax = zoneLight.Zmax; + + float minX = 9999; float maxX = -9999; + float minY = 9999; float maxY = -9999; + + auto &points = innerZoneLightRecord.points; + for (auto &zonePoint : zoneLight.points) { + minX = std::min(zonePoint.x, minX); minY = std::min(zonePoint.y, minY); + maxX = std::max(zonePoint.x, maxX); maxY = std::max(zonePoint.y, maxY); + + points.push_back(mathfu::vec2(zonePoint.x, zonePoint.y)); + } + + innerZoneLightRecord.aabb = CAaBox( + C3Vector(mathfu::vec3(minX, minY, zoneLight.Zmin)), + C3Vector(mathfu::vec3(maxX, maxY, zoneLight.Zmax)) + ); + + auto &lines = innerZoneLightRecord.lines; + for (int i = 0; i < (points.size() - 1); i++) { + lines.push_back(points[i + 1] - points[i]); + } + lines.push_back( points[0] - points[points.size() - 1]); + + m_zoneLights.push_back(innerZoneLightRecord); + } + } +} + +void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, + MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, + const AreaRecord &areaRecord) { + + ZoneScoped ; + + Config* config = this->m_api->getConfig(); + + bool fogRecordWasFound = false; + mathfu::vec3 endFogColor = mathfu::vec3(0.0, 0.0, 0.0); + + std::vector wmoFogData = {}; + if (mapRenderPlan->m_currentWMO != emptyWMO) { + auto l_currentWmoObject = wmoFactory.getObjectById<0>(mapRenderPlan->m_currentWMO); + if (l_currentWmoObject != nullptr) { + l_currentWmoObject->checkFog(frustumData.cameraPos, wmoFogData); + } + } + + std::vector lightResults; + if ((m_api->databaseHandler != nullptr)) { + //Check zoneLight + SkyColors skyColors; + ExteriorColors exteriorColors; + FogResult fogResult; + LiquidColors liquidColors; + + getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, fogResult, liquidColors, &stateForConditions); + + //TODO: restore skyboxes + /* + //Delete skyboxes that are not in light array + std::unordered_map> perFdidMap; + auto modelIt = m_exteriorSkyBoxes.begin(); + while (modelIt != m_exteriorSkyBoxes.end()) { + bool found = false; + for (auto &_light : lightResults) { + if (_light.skyBoxFdid == (*modelIt)->getModelFileId()) { + if (!drawDefaultSkybox && _light.isDefault) continue; + + found = true; + break; + } + } + + if (found) { + perFdidMap[(*modelIt)->getModelFileId()] = *modelIt; + modelIt++; + } else { + modelIt = m_exteriorSkyBoxes.erase(modelIt); + } + } + + m_skyConeAlpha = 1.0; + + + + for (auto &_light : lightResults) { + if (_light.skyBoxFdid == 0 || _light.lightSkyboxId == 0) continue; + + stateForConditions.currentSkyboxIds.push_back(_light.lightSkyboxId); + std::shared_ptr skyBox = nullptr; + if (perFdidMap[_light.skyBoxFdid] == nullptr) { + skyBox = m2Factory.createObject(m_api, true); + skyBox->setLoadParams(0, {}, {}); + + skyBox->setModelFileId(_light.skyBoxFdid); + + skyBox->createPlacementMatrix(mathfu::vec3(0, 0, 0), 0, mathfu::vec3(1, 1, 1), nullptr); + skyBox->calcWorldPosition(); + m_exteriorSkyBoxes.push_back(skyBox); + } else { + skyBox = perFdidMap[_light.skyBoxFdid]; + } + + skyBox->setAlpha(_light.blendCoef); + if ((_light.skyBoxFlags & 4) > 0 ) { + //In this case conus is still rendered been, but all values are final fog values. + auto fdd = mapRenderPlan->frameDependentData; + fdd->overrideValuesWithFinalFog = true; + } + + if ((_light.skyBoxFlags & 2) == 0) { +// m_skyConeAlpha -= _light.blendCoef; + m_skyConeAlpha -= _light.blendCoef; + } + + if (_light.skyBoxFlags & 1) { + skyBox->setOverrideAnimationPerc(config->currentTime / 2880.0, true); + } + } + */ + + float ambientMult = areaRecord.ambientMultiplier * 2.0f + 1; + + if (config->glowSource == EParameterSource::eDatabase) { + auto fdd = mapRenderPlan->frameDependentData; + fdd->currentGlow = currentGlow; + } else if (config->glowSource == EParameterSource::eConfig) { + auto fdd = mapRenderPlan->frameDependentData; + fdd->currentGlow = config->currentGlow; + } + + + if (config->globalLighting == EParameterSource::eDatabase) { + auto fdd = mapRenderPlan->frameDependentData; + + fdd->colors = exteriorColors; + + auto extDir = MathHelper::calcExteriorColorDir( + frustumData.viewMat, + m_api->getConfig()->currentTime + ); + fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; + } else if (config->globalLighting == EParameterSource::eConfig) { + auto fdd = mapRenderPlan->frameDependentData; + + fdd->colors.exteriorAmbientColor = config->exteriorColors.exteriorAmbientColor; + fdd->colors.exteriorGroundAmbientColor = config->exteriorColors.exteriorGroundAmbientColor; + fdd->colors.exteriorHorizontAmbientColor = config->exteriorColors.exteriorHorizontAmbientColor; + fdd->colors.exteriorDirectColor = config->exteriorColors.exteriorDirectColor; + auto extDir = MathHelper::calcExteriorColorDir( + frustumData.viewMat, + m_api->getConfig()->currentTime + ); + fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; + } + + { + auto fdd = mapRenderPlan->frameDependentData; + fdd->useMinimapWaterColor = config->useMinimapWaterColor; + fdd->useCloseRiverColorForDB = config->useCloseRiverColorForDB; + } + if (config->waterColorParams == EParameterSource::eDatabase) + { + auto fdd = mapRenderPlan->frameDependentData; + fdd->liquidColors = liquidColors; + } else if (config->waterColorParams == EParameterSource::eConfig) { + auto fdd = mapRenderPlan->frameDependentData; + fdd->liquidColors.closeRiverColor_shallowAlpha = config->closeRiverColor; + fdd->liquidColors.farRiverColor_deepAlpha = config->farRiverColor; + fdd->liquidColors.closeOceanColor_shallowAlpha = config->closeOceanColor; + fdd->liquidColors.farOceanColor_deepAlpha = config->farOceanColor; + } + if (config->skyParams == EParameterSource::eDatabase) { + auto fdd = mapRenderPlan->frameDependentData; + fdd->skyColors = skyColors; + } + } + + //Handle fog + { + std::vector combinedResults = {}; + float totalSummator = 0.0; + + //Apply fog from WMO + { + for (auto &wmoFog : wmoFogData) { + auto &lightResult = combinedResults.emplace_back(); + auto farPlaneClamped = std::min(config->farPlane, wmoFog.end); + + std::array colorConverted; + ImVectorToArrBGR(colorConverted, wmoFog.color); + + lightResult.FogEnd = farPlaneClamped; + lightResult.FogStart = farPlaneClamped * wmoFog.start_scalar; + lightResult.SkyFogColor = colorConverted; + lightResult.FogDensity = 1.0; + lightResult.FogHeightColor = colorConverted; + lightResult.EndFogColor = colorConverted; + lightResult.SunFogColor = colorConverted; + lightResult.HeightEndFogColor = colorConverted; + + if (farPlaneClamped < 30.f) { + lightResult.FogEnd = farPlaneClamped; + farPlaneClamped = 30.f; + } + + bool mapHasWeightedBlendFlag = false; + if (!mapHasWeightedBlendFlag) { + float difference = farPlaneClamped - lightResult.FogStart; + float farPlaneClamped2 = std::min(config->farPlane, 700.0f) - 200.0f; + if ((difference > farPlaneClamped2) || (farPlaneClamped2 <= 0.0f)) { + lightResult.FogDensity = 1.5; + } else { + lightResult.FogDensity = ((1.0 - (difference / farPlaneClamped2)) * 5.5) + 1.5; + } + lightResult.FogEnd = config->farPlane; + if (lightResult.FogStart < 0.0f) + lightResult.FogStart = 0.0; + } + + lightResult.FogHeightDensity = lightResult.FogDensity; + lightResult.FogStartOffset = 0; + lightResult.FogHeightScaler = 1.0; + lightResult.FogZScalar = 0; + lightResult.FogHeight = -10000.0; + lightResult.LegacyFogScalar = 1.0; + lightResult.EndFogColorDistance = 10000.0; + } + } + + //Apply fogs from lights + if (totalSummator < 1.0) { + if (config->globalFog == EParameterSource::eDatabase) { + + } else if (config->globalFog == EParameterSource::eConfig) { + LightResult globalFog; + globalFog.FogScaler = config->fogResult.FogScaler; + globalFog.FogEnd = config->fogResult.FogEnd; + globalFog.FogDensity = config->fogResult.FogDensity; + + globalFog.FogHeightScaler = config->fogResult.FogHeightScaler; + globalFog.FogHeightDensity = config->fogResult.FogHeightDensity; + globalFog.SunFogAngle = config->fogResult.SunFogAngle; + globalFog.EndFogColorDistance = config->fogResult.EndFogColorDistance; + globalFog.SunFogStrength = config->fogResult.SunFogStrength; + + globalFog.blendCoef = 1.0 - totalSummator; + globalFog.isDefault = true; + + globalFog.EndFogColor = {config->fogResult.EndFogColor.z, config->fogResult.EndFogColor.y, config->fogResult.EndFogColor.x}; + globalFog.SunFogColor = {config->fogResult.SunFogColor.z, config->fogResult.SunFogColor.y, config->fogResult.SunFogColor.x}; + globalFog.FogHeightColor = {config->fogResult.FogHeightColor.z, config->fogResult.FogHeightColor.y, config->fogResult.FogHeightColor.x}; + + combinedResults = {globalFog}; + } + } + std::sort(combinedResults.begin(), combinedResults.end(), [](const LightResult &a, const LightResult &b) -> bool { + return a.blendCoef > b.blendCoef; + }); + + //Rebalance blendCoefs + if (totalSummator < 1.0f && totalSummator > 0.0f) { + for (auto &_light : combinedResults) { + _light.blendCoef = _light.blendCoef / totalSummator; + } + } + + //In case of no data -> disable the fog + { + auto fdd = mapRenderPlan->frameDependentData; + fdd->FogDataFound = !combinedResults.empty(); + + auto &fogResult = fdd->fogResults.emplace_back(); + for (auto &_light : lightResults) { + fogResult.FogEnd = mix(fogResult.FogEnd, _light.FogEnd, _light.blendCoef); + fogResult.FogScaler = mix(fogResult.FogScaler, _light.FogScaler, _light.blendCoef); + fogResult.FogDensity = mix(fogResult.FogDensity, _light.FogDensity, _light.blendCoef); + fogResult.FogHeight = mix(fogResult.FogHeight, _light.FogHeight, _light.blendCoef); + fogResult.FogHeightScaler = mix(fogResult.FogHeightScaler, _light.FogHeightScaler, _light.blendCoef); + fogResult.FogHeightDensity = mix(fogResult.FogHeightDensity, _light.FogHeightDensity, _light.blendCoef); + fogResult.SunFogAngle = mix(fogResult.SunFogAngle, _light.SunFogAngle, _light.blendCoef); + if (fdd->overrideValuesWithFinalFog) { + fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); + } else { + fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]), _light.blendCoef); + } + fogResult.EndFogColor = mix(fogResult.EndFogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); + fogResult.EndFogColorDistance = mix(fogResult.EndFogColorDistance, _light.EndFogColorDistance, _light.blendCoef); + fogResult.SunFogColor = mix(fogResult.SunFogColor, mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]), _light.blendCoef); + fogResult.SunFogStrength = mix(fogResult.SunFogStrength, _light.SunFogStrength, _light.blendCoef); + fogResult.FogHeightColor = mix(fogResult.FogHeightColor, mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]), _light.blendCoef); + fogResult.FogHeightCoefficients = mix( + fogResult.FogHeightCoefficients, + mathfu::vec4(_light.FogHeightCoefficients[3], _light.FogHeightCoefficients[2], + _light.FogHeightCoefficients[1], _light.FogHeightCoefficients[0]), _light.blendCoef); + fogResult.MainFogCoefficients = mix( + fogResult.MainFogCoefficients, + mathfu::vec4(_light.MainFogCoefficients[3], _light.MainFogCoefficients[2], + _light.MainFogCoefficients[1], _light.MainFogCoefficients[0]), _light.blendCoef); + fogResult.HeightDensityFogCoefficients = mix( + fogResult.HeightDensityFogCoefficients, + mathfu::vec4(_light.HeightDensityFogCoefficients[3], + _light.HeightDensityFogCoefficients[2], + _light.HeightDensityFogCoefficients[1], + _light.HeightDensityFogCoefficients[0]), _light.blendCoef); + + fogResult.FogZScalar = mix(fogResult.FogZScalar, _light.FogZScalar, _light.blendCoef); + fogResult.LegacyFogScalar = mix(fogResult.LegacyFogScalar, _light.LegacyFogScalar, _light.blendCoef); + fogResult.MainFogStartDist = mix(fogResult.MainFogStartDist, _light.MainFogStartDist, _light.blendCoef); + fogResult.MainFogEndDist = mix(fogResult.MainFogEndDist, _light.MainFogEndDist, _light.blendCoef); + fogResult.FogBlendAlpha = mix(fogResult.FogBlendAlpha, _light.blendCoef, _light.blendCoef); + fogResult.HeightEndFogColor = mix(fogResult.HeightEndFogColor, mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]), _light.blendCoef); + fogResult.FogStartOffset = mix(fogResult.FogStartOffset, _light.FogStartOffset, _light.blendCoef); + } + } + } +} + + +template +inline float getFloatFromInt(int value) { + if constexpr (T == 0) { + return (value & 0xFF) / 255.0f; + } + if constexpr (T == 1) { + return ((value >> 8) & 0xFF) / 255.0f; + } + if constexpr (T == 2) { + return ((value >> 16) & 0xFF) / 255.0f; + } +} + +inline mathfu::vec3 intToColor3(int a) { + //BGR + return mathfu::vec3( + getFloatFromInt<2>(a), + getFloatFromInt<1>(a), + getFloatFromInt<0>(a) + ); +} +inline mathfu::vec4 intToColor4(int a) { + //BGRA + return mathfu::vec4( + getFloatFromInt<2>(a), + getFloatFromInt<1>(a), + getFloatFromInt<0>(a), + getFloatFromInt<3>(a) + ); +} +inline mathfu::vec4 floatArr(std::array a) { + //BGRA + return mathfu::vec4( + a[3], + a[2], + a[1], + a[0] + ); +} + +template +decltype(auto) mixMembers(LightParamData& data, T LightTimedData::*member, float blendTimeCoeff) { + if constexpr (C == 3) { + static_assert(std::is_same::value, "the type must be int for vector component"); + return mix(intToColor3(data.lightTimedData[0].*member), intToColor3(data.lightTimedData[1].*member), blendTimeCoeff); + } + if constexpr (C == 4 && std::is_same>::value) { + return mix(floatArr(data.lightTimedData[0].*member), floatArr(data.lightTimedData[1].*member), blendTimeCoeff); + } else if constexpr (C == 4) { + static_assert(std::is_same::value, "the type must be int for vector component"); + return mix(intToColor4(data.lightTimedData[0].*member), intToColor4(data.lightTimedData[1].*member), blendTimeCoeff); + } + if constexpr (C == 1) { + static_assert(std::is_same::value, "the type must be float for one component"); + return mix(data.lightTimedData[0].*member, data.lightTimedData[1].*member, blendTimeCoeff); + } +} + +bool vec3EqZero(const mathfu::vec3 &a) { + return feq(a.x, 0.0f) && feq(a.y, 0.0f) && feq(a.z, 0.0f); +} + +float maxFarClip(float farClip) { + + return std::max(std::min(farClip, 50000.0), 1000.0); +} + +float getClampedFarClip(float farClip) { + int someflag = 0; + float multiplier = 1.0f; + + if ((map_has0x10000Flag) != 0 && farClip >= 4400.0f) + farClip = 4400.0; + farClip = farClip * multiplier; + + return maxFarClip( + + ); +} + +void fixLightTimedData(LightTimedData &data, float farClip) { + if (data.EndFogColor == 0) { + data.EndFogColor = data.SkyFogColor; + } + + if (data.FogHeightColor == 0) { + data.FogHeightColor = data.SkyFogColor; + } + + if (data.EndFogHeightColor == 0) { + data.EndFogHeightColor = data.EndFogColor; + } + + //Clamp into (-1.0f, 1.0f) + data.FogScaler = std::max(std::min(data.FogScaler, 1.0f), -1.0f); + data.FogEnd = std::max(data.FogEnd, 10.0f); + data.FogHeight = std::max(data.FogHeight, -10000.0f); + data.FogHeightScaler = std::max(std::min(data.FogScaler, 1.0f), -1.0f); + + if (data.SunFogColor == 0) + data.SunFogAngle = 1.0f; + + if (data.EndFogColorDistance <= 0.0f) + data.EndFogColorDistance = getClampedFarClip(farClip); +} + +void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, + SkyColors &skyColors, + ExteriorColors &exteriorColors, + FogResult &fogResult, + LiquidColors &liquidColors, + StateForConditions *stateForConditions) { + if (m_api->databaseHandler == nullptr) + return ; + + LightResult zoneLightResult; + + bool zoneLightFound = false; + int LightId; + for (const auto &zoneLight : m_zoneLights) { + CAaBox laabb = zoneLight.aabb; + auto const vec50 = mathfu::vec3(50.0f,50.0f,0); + laabb.min = (mathfu::vec3(laabb.min) - vec50); + laabb.max = (mathfu::vec3(laabb.max) + vec50); + if (MathHelper::isPointInsideNonConvex(cameraVec3, zoneLight.aabb, zoneLight.points)) { + zoneLightFound = true; + + if (stateForConditions != nullptr) { + stateForConditions->currentZoneLights.push_back(zoneLight.ID); + } + LightId = zoneLight.LightID; + break; + } + } + + uint8_t currentLightParamIdIndex = 0; + + int selectedLightParam = 0; + int selectedLightId = 0; + + if (zoneLightFound) { + selectedLightId = LightId; + m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult); + if (stateForConditions != nullptr) { + selectedLightParam = zoneLightResult.lightParamId[currentLightParamIdIndex]; + stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId[currentLightParamIdIndex]); + } + } + + //Get light from DB + std::vector lightResults; + m_api->databaseHandler->getEnvInfo(m_mapId, + cameraVec3.x, + cameraVec3.y, + cameraVec3.z, + lightResults + ); + std::sort(lightResults.begin(), lightResults.end(), [](const LightResult &a, const LightResult &b) -> bool { + return a.blendAlpha > b.blendAlpha; + }); + + + for (auto it = lightResults.begin(); it != lightResults.end(); it++) { + if (feq(it->pos[0], 0.0) && feq(it->pos[1], 0.0) && feq(it->pos[2], 0.0)) { + //This is default record. If zoneLight was selected -> skip it. + if (!zoneLightFound) { + selectedLightParam = it->lightParamId[currentLightParamIdIndex]; + selectedLightId = it->id; + } + } else { + selectedLightParam = it->lightParamId[currentLightParamIdIndex]; + selectedLightId = it->id; + break; + } + } + + if (stateForConditions != nullptr) { + stateForConditions->currentZoneLights.push_back(selectedLightParam); + stateForConditions->currentLightIds.push_back(selectedLightId); + } + + LightParamData lightParamData; + if (m_api->databaseHandler->getLightParamData(selectedLightParam, config->currentTime, lightParamData)) { + + float blendTimeCoeff = (config->currentTime - lightParamData.lightTimedData[0].time) / (float)(lightParamData.lightTimedData[1].time - lightParamData.lightTimedData[0].time); + + auto &dataA = lightParamData.lightTimedData[0]; + auto &dataB = lightParamData.lightTimedData[1]; + //Blend two times using certain rules + fixLightTimedData(dataA, config->farPlane); + fixLightTimedData(dataB, config->farPlane); + + //Ambient lights + exteriorColors.exteriorAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::ambientLight, blendTimeCoeff); + exteriorColors.exteriorGroundAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::groundAmbientColor, blendTimeCoeff); + if (vec3EqZero(exteriorColors.exteriorGroundAmbientColor.xyz())) + exteriorColors.exteriorGroundAmbientColor = exteriorColors.exteriorAmbientColor; + + exteriorColors.exteriorHorizontAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::horizontAmbientColor, blendTimeCoeff); + if (vec3EqZero(exteriorColors.exteriorHorizontAmbientColor.xyz())) + exteriorColors.exteriorHorizontAmbientColor = exteriorColors.exteriorAmbientColor; + + exteriorColors.exteriorDirectColor = mixMembers<4>(lightParamData, &LightTimedData::directColor, blendTimeCoeff); + + //Liquid colors + liquidColors.closeOceanColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeOceanColor, blendTimeCoeff); + liquidColors.farOceanColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farOceanColor, blendTimeCoeff); + liquidColors.closeRiverColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeRiverColor, blendTimeCoeff); + liquidColors.farRiverColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farRiverColor, blendTimeCoeff); + + liquidColors.closeOceanColor_shallowAlpha.w = lightParamData.oceanShallowAlpha; + liquidColors.farOceanColor_deepAlpha.w = lightParamData.oceanDeepAlpha; + liquidColors.closeRiverColor_shallowAlpha.w = lightParamData.waterShallowAlpha; + liquidColors.farRiverColor_deepAlpha.w = lightParamData.waterDeepAlpha; + + //SkyColors + skyColors.SkyTopColor = mixMembers<4>(lightParamData, &LightTimedData::SkyTopColor, blendTimeCoeff); + skyColors.SkyMiddleColor = mixMembers<4>(lightParamData, &LightTimedData::SkyMiddleColor, blendTimeCoeff); + skyColors.SkyBand1Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand1Color, blendTimeCoeff); + skyColors.SkyBand2Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand2Color, blendTimeCoeff); + skyColors.SkySmogColor = mixMembers<4>(lightParamData, &LightTimedData::SkySmogColor, blendTimeCoeff); + skyColors.SkyFogColor = mixMembers<4>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); + + //Fog! + fogResult.FogEnd = mixMembers<1>(lightParamData, &LightTimedData::FogEnd, blendTimeCoeff); + fogResult.FogScaler = mixMembers<1>(lightParamData, &LightTimedData::FogScaler, blendTimeCoeff); + fogResult.FogDensity = mixMembers<1>(lightParamData, &LightTimedData::FogDensity, blendTimeCoeff); + fogResult.FogHeight = mixMembers<1>(lightParamData, &LightTimedData::FogHeight, blendTimeCoeff); + fogResult.FogHeightScaler = mixMembers<1>(lightParamData, &LightTimedData::FogHeightScaler, blendTimeCoeff); + fogResult.FogHeightDensity = mixMembers<1>(lightParamData, &LightTimedData::FogHeightDensity, blendTimeCoeff); + fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff); + + if (false) {//fdd->overrideValuesWithFinalFog) { + fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); + } else { + fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); + } + + fogResult.EndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); + fogResult.EndFogColorDistance = mixMembers<1>(lightParamData, &LightTimedData::EndFogColorDistance, blendTimeCoeff); + fogResult.SunFogColor = mixMembers<3>(lightParamData, &LightTimedData::SunFogColor, blendTimeCoeff); + fogResult.SunFogStrength = mixMembers<1>(lightParamData, &LightTimedData::SunFogStrength, blendTimeCoeff); + fogResult.FogHeightColor = mixMembers<3>(lightParamData, &LightTimedData::FogHeightColor, blendTimeCoeff); + fogResult.FogHeightCoefficients = mixMembers<4>(lightParamData, &LightTimedData::FogHeightCoefficients, blendTimeCoeff); + fogResult.MainFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); + fogResult.HeightDensityFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); + + fogResult.FogZScalar = mixMembers<1>(lightParamData, &LightTimedData::FogZScalar, blendTimeCoeff); +// fogResult.LegacyFogScalar = mixMembers<1>(lightParamData, &LightTimedData::LegacyFogScalar, blendTimeCoeff); + fogResult.MainFogStartDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogStartDist, blendTimeCoeff); + fogResult.MainFogEndDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogEndDist, blendTimeCoeff); +// fogResult.FogBlendAlpha = mixMembers<1>(lightParamData, &LightTimedData::FogBlendAlpha, blendTimeCoeff); + fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); + fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); + + } +} \ No newline at end of file diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h new file mode 100644 index 000000000..e4e4372d9 --- /dev/null +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h @@ -0,0 +1,44 @@ +// +// Created by Deamon on 7/5/2024. +// + +#ifndef AWEBWOWVIEWERCPP_DAYNIGHTLIGHTHOLDER_H +#define AWEBWOWVIEWERCPP_DAYNIGHTLIGHTHOLDER_H + +#include +#include +#include "../../../persistance/header/commonFileStructs.h" +#include "../../../ApiContainer.h" + +class DayNightLightHolder { +public: + DayNightLightHolder(const HApiContainer &api, int mapId); + +private: + struct mapInnerZoneLightRecord { + int ID; + std::string name; + int LightID; + CAaBox aabb; + std::vector points; + std::vector lines; + }; + std::vector m_zoneLights; + + HApiContainer m_api; + int m_mapId = -1; +public: + void loadZoneLights(); + void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, + StateForConditions &stateForConditions, const AreaRecord &areaRecord); + + void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, + SkyColors &skyColors, + ExteriorColors &exteriorColors, + FogResult &fogResult, + LiquidColors &liquidColors, + StateForConditions *stateForConditions); +}; + + +#endif //AWEBWOWVIEWERCPP_DAYNIGHTLIGHTHOLDER_H diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index e69fbcc87..4085faff2 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -272,7 +272,7 @@ HGVertexBufferBindings createSkyBindings(const HMapSceneBufferCreate &sceneRende return skyBindings; } -Map::Map(HApiContainer api, int mapId, const std::string &mapName) { +Map::Map(HApiContainer api, int mapId, const std::string &mapName) : dayNightLightHolder(api, mapId) { initMapTiles(); m_mapId = mapId; m_api = api; this->mapName = mapName; @@ -282,6 +282,7 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) { MapRecord mapRecord; api->databaseHandler->getMapById(mapId, mapRecord); useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + has0x200000Flag = (mapRecord.flags0 & 0x200000) > 0; std::string wdtFileName = "world/maps/"+mapName+"/"+mapName+".wdt"; @@ -294,8 +295,7 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) { m_wdlObject = std::make_shared(api, wdlFileName); m_wdlObject->setMapApi(this); - - loadZoneLights(); + dayNightLightHolder.loadZoneLights(); m_sceneWideBlockVSPSChunk = nullptr; } @@ -586,493 +586,10 @@ static inline float mix(const float &a, const float &b, float alpha) { void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) { - ZoneScoped ; - - Config* config = this->m_api->getConfig(); - - bool fogRecordWasFound = false; - mathfu::vec3 endFogColor = mathfu::vec3(0.0, 0.0, 0.0); - - std::vector wmoFogData = {}; - if (mapRenderPlan->m_currentWMO != emptyWMO) { - auto l_currentWmoObject = wmoFactory.getObjectById<0>(mapRenderPlan->m_currentWMO); - if (l_currentWmoObject != nullptr) { - l_currentWmoObject->checkFog(frustumData.cameraPos, wmoFogData); - } - } - - std::vector lightResults; - if ((m_api->databaseHandler != nullptr)) { - //Check zoneLight - SkyColors skyColors; - ExteriorColors exteriorColors; - FogResult fogResult; - LiquidColors liquidColors; - - getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, fogResult, liquidColors, &stateForConditions); - - //TODO: restore skyboxes - /* - //Delete skyboxes that are not in light array - std::unordered_map> perFdidMap; - auto modelIt = m_exteriorSkyBoxes.begin(); - while (modelIt != m_exteriorSkyBoxes.end()) { - bool found = false; - for (auto &_light : lightResults) { - if (_light.skyBoxFdid == (*modelIt)->getModelFileId()) { - if (!drawDefaultSkybox && _light.isDefault) continue; - - found = true; - break; - } - } - - if (found) { - perFdidMap[(*modelIt)->getModelFileId()] = *modelIt; - modelIt++; - } else { - modelIt = m_exteriorSkyBoxes.erase(modelIt); - } - } - - m_skyConeAlpha = 1.0; - - - - for (auto &_light : lightResults) { - if (_light.skyBoxFdid == 0 || _light.lightSkyboxId == 0) continue; - - stateForConditions.currentSkyboxIds.push_back(_light.lightSkyboxId); - std::shared_ptr skyBox = nullptr; - if (perFdidMap[_light.skyBoxFdid] == nullptr) { - skyBox = m2Factory.createObject(m_api, true); - skyBox->setLoadParams(0, {}, {}); - - skyBox->setModelFileId(_light.skyBoxFdid); - - skyBox->createPlacementMatrix(mathfu::vec3(0, 0, 0), 0, mathfu::vec3(1, 1, 1), nullptr); - skyBox->calcWorldPosition(); - m_exteriorSkyBoxes.push_back(skyBox); - } else { - skyBox = perFdidMap[_light.skyBoxFdid]; - } - - skyBox->setAlpha(_light.blendCoef); - if ((_light.skyBoxFlags & 4) > 0 ) { - //In this case conus is still rendered been, but all values are final fog values. - auto fdd = mapRenderPlan->frameDependentData; - fdd->overrideValuesWithFinalFog = true; - } - - if ((_light.skyBoxFlags & 2) == 0) { -// m_skyConeAlpha -= _light.blendCoef; - m_skyConeAlpha -= _light.blendCoef; - } - - if (_light.skyBoxFlags & 1) { - skyBox->setOverrideAnimationPerc(config->currentTime / 2880.0, true); - } - } - */ - float ambientMult = areaRecord.ambientMultiplier * 2.0f + 1; - - if (config->glowSource == EParameterSource::eDatabase) { - auto fdd = mapRenderPlan->frameDependentData; - fdd->currentGlow = currentGlow; - } else if (config->glowSource == EParameterSource::eConfig) { - auto fdd = mapRenderPlan->frameDependentData; - fdd->currentGlow = config->currentGlow; - } - - - if (config->globalLighting == EParameterSource::eDatabase) { - auto fdd = mapRenderPlan->frameDependentData; - - fdd->colors = exteriorColors; - - auto extDir = MathHelper::calcExteriorColorDir( - frustumData.viewMat, - m_api->getConfig()->currentTime - ); - fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; - } else if (config->globalLighting == EParameterSource::eConfig) { - auto fdd = mapRenderPlan->frameDependentData; - - fdd->colors.exteriorAmbientColor = config->exteriorColors.exteriorAmbientColor; - fdd->colors.exteriorGroundAmbientColor = config->exteriorColors.exteriorGroundAmbientColor; - fdd->colors.exteriorHorizontAmbientColor = config->exteriorColors.exteriorHorizontAmbientColor; - fdd->colors.exteriorDirectColor = config->exteriorColors.exteriorDirectColor; - auto extDir = MathHelper::calcExteriorColorDir( - frustumData.viewMat, - m_api->getConfig()->currentTime - ); - fdd->exteriorDirectColorDir = { extDir.x, extDir.y, extDir.z }; - } - - { - auto fdd = mapRenderPlan->frameDependentData; - fdd->useMinimapWaterColor = config->useMinimapWaterColor; - fdd->useCloseRiverColorForDB = config->useCloseRiverColorForDB; - } - if (config->waterColorParams == EParameterSource::eDatabase) - { - auto fdd = mapRenderPlan->frameDependentData; - fdd->liquidColors = liquidColors; - } else if (config->waterColorParams == EParameterSource::eConfig) { - auto fdd = mapRenderPlan->frameDependentData; - fdd->liquidColors.closeRiverColor_shallowAlpha = config->closeRiverColor; - fdd->liquidColors.farRiverColor_deepAlpha = config->farRiverColor; - fdd->liquidColors.closeOceanColor_shallowAlpha = config->closeOceanColor; - fdd->liquidColors.farOceanColor_deepAlpha = config->farOceanColor; - } - if (config->skyParams == EParameterSource::eDatabase) { - auto fdd = mapRenderPlan->frameDependentData; - fdd->skyColors = skyColors; - } - } - - //Handle fog - { - std::vector combinedResults = {}; - float totalSummator = 0.0; - - //Apply fog from WMO - { - for (auto &wmoFog : wmoFogData) { - auto &lightResult = combinedResults.emplace_back(); - auto farPlaneClamped = std::min(config->farPlane, wmoFog.end); - - std::array colorConverted; - ImVectorToArrBGR(colorConverted, wmoFog.color); - - lightResult.FogEnd = farPlaneClamped; - lightResult.FogStart = farPlaneClamped * wmoFog.start_scalar; - lightResult.SkyFogColor = colorConverted; - lightResult.FogDensity = 1.0; - lightResult.FogHeightColor = colorConverted; - lightResult.EndFogColor = colorConverted; - lightResult.SunFogColor = colorConverted; - lightResult.HeightEndFogColor = colorConverted; - - if (farPlaneClamped < 30.f) { - lightResult.FogEnd = farPlaneClamped; - farPlaneClamped = 30.f; - } - - bool mapHasWeightedBlendFlag = false; - if (!mapHasWeightedBlendFlag) { - float difference = farPlaneClamped - lightResult.FogStart; - float farPlaneClamped2 = std::min(config->farPlane, 700.0f) - 200.0f; - if ((difference > farPlaneClamped2) || (farPlaneClamped2 <= 0.0f)) { - lightResult.FogDensity = 1.5; - } else { - lightResult.FogDensity = ((1.0 - (difference / farPlaneClamped2)) * 5.5) + 1.5; - } - lightResult.FogEnd = config->farPlane; - if (lightResult.FogStart < 0.0f) - lightResult.FogStart = 0.0; - } - - lightResult.FogHeightDensity = lightResult.FogDensity; - lightResult.FogStartOffset = 0; - lightResult.FogHeightScaler = 1.0; - lightResult.FogZScalar = 0; - lightResult.FogHeight = -10000.0; - lightResult.LegacyFogScalar = 1.0; - lightResult.EndFogColorDistance = 10000.0; - } - } - - //Apply fogs from lights - if (totalSummator < 1.0) { - if (config->globalFog == EParameterSource::eDatabase) { - - } else if (config->globalFog == EParameterSource::eConfig) { - LightResult globalFog; - globalFog.FogScaler = config->fogResult.FogScaler; - globalFog.FogEnd = config->fogResult.FogEnd; - globalFog.FogDensity = config->fogResult.FogDensity; - - globalFog.FogHeightScaler = config->fogResult.FogHeightScaler; - globalFog.FogHeightDensity = config->fogResult.FogHeightDensity; - globalFog.SunFogAngle = config->fogResult.SunFogAngle; - globalFog.EndFogColorDistance = config->fogResult.EndFogColorDistance; - globalFog.SunFogStrength = config->fogResult.SunFogStrength; - - globalFog.blendCoef = 1.0 - totalSummator; - globalFog.isDefault = true; - - globalFog.EndFogColor = {config->fogResult.EndFogColor.z, config->fogResult.EndFogColor.y, config->fogResult.EndFogColor.x}; - globalFog.SunFogColor = {config->fogResult.SunFogColor.z, config->fogResult.SunFogColor.y, config->fogResult.SunFogColor.x}; - globalFog.FogHeightColor = {config->fogResult.FogHeightColor.z, config->fogResult.FogHeightColor.y, config->fogResult.FogHeightColor.x}; - - combinedResults = {globalFog}; - } - } - std::sort(combinedResults.begin(), combinedResults.end(), [](const LightResult &a, const LightResult &b) -> bool { - return a.blendCoef > b.blendCoef; - }); - - //Rebalance blendCoefs - if (totalSummator < 1.0f && totalSummator > 0.0f) { - for (auto &_light : combinedResults) { - _light.blendCoef = _light.blendCoef / totalSummator; - } - } - - //In case of no data -> disable the fog - { - auto fdd = mapRenderPlan->frameDependentData; - fdd->FogDataFound = !combinedResults.empty(); - - auto &fogResult = fdd->fogResults.emplace_back(); - for (auto &_light : lightResults) { - fogResult.FogEnd = mix(fogResult.FogEnd, _light.FogEnd, _light.blendCoef); - fogResult.FogScaler = mix(fogResult.FogScaler, _light.FogScaler, _light.blendCoef); - fogResult.FogDensity = mix(fogResult.FogDensity, _light.FogDensity, _light.blendCoef); - fogResult.FogHeight = mix(fogResult.FogHeight, _light.FogHeight, _light.blendCoef); - fogResult.FogHeightScaler = mix(fogResult.FogHeightScaler, _light.FogHeightScaler, _light.blendCoef); - fogResult.FogHeightDensity = mix(fogResult.FogHeightDensity, _light.FogHeightDensity, _light.blendCoef); - fogResult.SunFogAngle = mix(fogResult.SunFogAngle, _light.SunFogAngle, _light.blendCoef); - if (fdd->overrideValuesWithFinalFog) { - fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); - } else { - fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]), _light.blendCoef); - } - fogResult.EndFogColor = mix(fogResult.EndFogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); - fogResult.EndFogColorDistance = mix(fogResult.EndFogColorDistance, _light.EndFogColorDistance, _light.blendCoef); - fogResult.SunFogColor = mix(fogResult.SunFogColor, mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]), _light.blendCoef); - fogResult.SunFogStrength = mix(fogResult.SunFogStrength, _light.SunFogStrength, _light.blendCoef); - fogResult.FogHeightColor = mix(fogResult.FogHeightColor, mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]), _light.blendCoef); - fogResult.FogHeightCoefficients = mix( - fogResult.FogHeightCoefficients, - mathfu::vec4(_light.FogHeightCoefficients[3], _light.FogHeightCoefficients[2], - _light.FogHeightCoefficients[1], _light.FogHeightCoefficients[0]), _light.blendCoef); - fogResult.MainFogCoefficients = mix( - fogResult.MainFogCoefficients, - mathfu::vec4(_light.MainFogCoefficients[3], _light.MainFogCoefficients[2], - _light.MainFogCoefficients[1], _light.MainFogCoefficients[0]), _light.blendCoef); - fogResult.HeightDensityFogCoefficients = mix( - fogResult.HeightDensityFogCoefficients, - mathfu::vec4(_light.HeightDensityFogCoefficients[3], - _light.HeightDensityFogCoefficients[2], - _light.HeightDensityFogCoefficients[1], - _light.HeightDensityFogCoefficients[0]), _light.blendCoef); - - fogResult.FogZScalar = mix(fogResult.FogZScalar, _light.FogZScalar, _light.blendCoef); - fogResult.LegacyFogScalar = mix(fogResult.LegacyFogScalar, _light.LegacyFogScalar, _light.blendCoef); - fogResult.MainFogStartDist = mix(fogResult.MainFogStartDist, _light.MainFogStartDist, _light.blendCoef); - fogResult.MainFogEndDist = mix(fogResult.MainFogEndDist, _light.MainFogEndDist, _light.blendCoef); - fogResult.FogBlendAlpha = mix(fogResult.FogBlendAlpha, _light.blendCoef, _light.blendCoef); - fogResult.HeightEndFogColor = mix(fogResult.HeightEndFogColor, mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]), _light.blendCoef); - fogResult.FogStartOffset = mix(fogResult.FogStartOffset, _light.FogStartOffset, _light.blendCoef); - } - } - } + dayNightLightHolder.updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); } -template -inline float getFloatFromInt(int value) { - if constexpr (T == 0) { - return (value & 0xFF) / 255.0f; - } - if constexpr (T == 1) { - return ((value >> 8) & 0xFF) / 255.0f; - } - if constexpr (T == 2) { - return ((value >> 16) & 0xFF) / 255.0f; - } -} - -inline mathfu::vec3 intToColor3(int a) { - //BGR - return mathfu::vec3( - getFloatFromInt<2>(a), - getFloatFromInt<1>(a), - getFloatFromInt<0>(a) - ); -} -inline mathfu::vec4 intToColor4(int a) { - //BGRA - return mathfu::vec4( - getFloatFromInt<2>(a), - getFloatFromInt<1>(a), - getFloatFromInt<0>(a), - getFloatFromInt<3>(a) - ); -} -inline mathfu::vec4 floatArr(std::array a) { - //BGRA - return mathfu::vec4( - a[3], - a[2], - a[1], - a[0] - ); -} - -template -decltype(auto) mixMembers(LightParamData& data, T LightTimedData::*member, float blendTimeCoeff) { - if constexpr (C == 3) { - static_assert(std::is_same::value, "the type must be int for vector component"); - return mix(intToColor3(data.lightTimedData[0].*member), intToColor3(data.lightTimedData[0].*member), blendTimeCoeff); - } - if constexpr (C == 4 && std::is_same>::value) { - return mix(floatArr(data.lightTimedData[0].*member), floatArr(data.lightTimedData[1].*member), blendTimeCoeff); - } else if constexpr (C == 4) { - static_assert(std::is_same::value, "the type must be int for vector component"); - return mix(intToColor4(data.lightTimedData[0].*member), intToColor4(data.lightTimedData[0].*member), blendTimeCoeff); - } - if constexpr (C == 1) { - static_assert(std::is_same::value, "the type must be float for one component"); - return mix(data.lightTimedData[0].*member, data.lightTimedData[0].*member, blendTimeCoeff); - } -} - -void Map::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, - SkyColors &skyColors, - ExteriorColors &exteriorColors, - FogResult &fogResult, - LiquidColors &liquidColors, - StateForConditions *stateForConditions) { - if (m_api->databaseHandler == nullptr) - return ; - - LightResult zoneLightResult; - - bool zoneLightFound = false; - int LightId; - for (const auto &zoneLight : m_zoneLights) { - CAaBox laabb = zoneLight.aabb; - auto const vec50 = mathfu::vec3(50.0f,50.0f,0); - laabb.min = (mathfu::vec3(laabb.min) - vec50); - laabb.max = (mathfu::vec3(laabb.max) + vec50); - if (MathHelper::isPointInsideNonConvex(cameraVec3, zoneLight.aabb, zoneLight.points)) { - zoneLightFound = true; - - if (stateForConditions != nullptr) { - stateForConditions->currentZoneLights.push_back(zoneLight.ID); - } - LightId = zoneLight.LightID; - break; - } - } - - uint8_t currentLightParamIdIndex = 0; - - int selectedLightParam = 0; - int selectedLightId = 0; - - if (zoneLightFound) { - selectedLightId = LightId; - m_api->databaseHandler->getLightById(LightId, config->currentTime, zoneLightResult); - if (stateForConditions != nullptr) { - selectedLightParam = zoneLightResult.lightParamId[currentLightParamIdIndex]; - stateForConditions->currentZoneLights.push_back(zoneLightResult.lightParamId[currentLightParamIdIndex]); - } - } - - //Get light from DB - std::vector lightResults; - m_api->databaseHandler->getEnvInfo(m_mapId, - cameraVec3.x, - cameraVec3.y, - cameraVec3.z, - lightResults - ); - std::sort(lightResults.begin(), lightResults.end(), [](const LightResult &a, const LightResult &b) -> bool { - return a.blendAlpha > b.blendAlpha; - }); - - - for (auto it = lightResults.begin(); it != lightResults.end(); it++) { - if (feq(it->pos[0], 0.0) && feq(it->pos[1], 0.0) && feq(it->pos[2], 0.0)) { - //This is default record. If zoneLight was selected -> skip it. - if (!zoneLightFound) { - selectedLightParam = it->lightParamId[currentLightParamIdIndex]; - selectedLightId = it->id; - } - } else { - selectedLightParam = it->lightParamId[currentLightParamIdIndex]; - selectedLightId = it->id; - break; - } - } - - if (stateForConditions != nullptr) { - stateForConditions->currentZoneLights.push_back(selectedLightParam); - stateForConditions->currentLightIds.push_back(selectedLightId); - } - - LightParamData lightParamData; - if (m_api->databaseHandler->getLightParamData(selectedLightParam, config->currentTime, lightParamData)) { - - float blendTimeCoeff = (config->currentTime - lightParamData.lightTimedData[0].time) / (float)(lightParamData.lightTimedData[1].time - lightParamData.lightTimedData[0].time); - - auto &dataA = lightParamData.lightTimedData[0]; - auto &dataB = lightParamData.lightTimedData[1]; - //Blend two times using certain rules - - //Ambient lights - exteriorColors.exteriorAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::ambientLight, blendTimeCoeff); - exteriorColors.exteriorGroundAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::groundAmbientColor, blendTimeCoeff); - exteriorColors.exteriorHorizontAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::horizontAmbientColor, blendTimeCoeff); - exteriorColors.exteriorDirectColor = mixMembers<4>(lightParamData, &LightTimedData::directColor, blendTimeCoeff); - - //Liquid colors - liquidColors.closeOceanColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeOceanColor, blendTimeCoeff); - liquidColors.farOceanColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farOceanColor, blendTimeCoeff); - liquidColors.closeRiverColor_shallowAlpha = mixMembers<4>(lightParamData, &LightTimedData::closeRiverColor, blendTimeCoeff); - liquidColors.farRiverColor_deepAlpha = mixMembers<4>(lightParamData, &LightTimedData::farRiverColor, blendTimeCoeff); - - liquidColors.closeOceanColor_shallowAlpha.w = lightParamData.oceanShallowAlpha; - liquidColors.farOceanColor_deepAlpha.w = lightParamData.oceanDeepAlpha; - liquidColors.closeRiverColor_shallowAlpha.w = lightParamData.waterShallowAlpha; - liquidColors.farRiverColor_deepAlpha.w = lightParamData.waterDeepAlpha; - - //SkyColors - skyColors.SkyTopColor = mixMembers<4>(lightParamData, &LightTimedData::SkyTopColor, blendTimeCoeff); - skyColors.SkyMiddleColor = mixMembers<4>(lightParamData, &LightTimedData::SkyMiddleColor, blendTimeCoeff); - skyColors.SkyBand1Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand1Color, blendTimeCoeff); - skyColors.SkyBand2Color = mixMembers<4>(lightParamData, &LightTimedData::SkyBand2Color, blendTimeCoeff); - skyColors.SkySmogColor = mixMembers<4>(lightParamData, &LightTimedData::SkySmogColor, blendTimeCoeff); - skyColors.SkyFogColor = mixMembers<4>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); - - //Fog! - fogResult.FogEnd = mixMembers<1>(lightParamData, &LightTimedData::FogEnd, blendTimeCoeff); - fogResult.FogScaler = mixMembers<1>(lightParamData, &LightTimedData::FogScaler, blendTimeCoeff); - fogResult.FogDensity = mixMembers<1>(lightParamData, &LightTimedData::FogDensity, blendTimeCoeff); - fogResult.FogHeight = mixMembers<1>(lightParamData, &LightTimedData::FogHeight, blendTimeCoeff); - fogResult.FogHeightScaler = mixMembers<1>(lightParamData, &LightTimedData::FogHeightScaler, blendTimeCoeff); - fogResult.FogHeightDensity = mixMembers<1>(lightParamData, &LightTimedData::FogHeightDensity, blendTimeCoeff); - fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff); - - if (false) {//fdd->overrideValuesWithFinalFog) { - fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); - } else { - fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::SkyFogColor, blendTimeCoeff); - } - - fogResult.EndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); - fogResult.EndFogColorDistance = mixMembers<1>(lightParamData, &LightTimedData::EndFogColorDistance, blendTimeCoeff); - fogResult.SunFogColor = mixMembers<3>(lightParamData, &LightTimedData::SunFogColor, blendTimeCoeff); - fogResult.SunFogStrength = mixMembers<1>(lightParamData, &LightTimedData::SunFogStrength, blendTimeCoeff); - fogResult.FogHeightColor = mixMembers<3>(lightParamData, &LightTimedData::FogHeightColor, blendTimeCoeff); - fogResult.FogHeightCoefficients = mixMembers<4>(lightParamData, &LightTimedData::FogHeightCoefficients, blendTimeCoeff); - fogResult.MainFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); - fogResult.HeightDensityFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); - - fogResult.FogZScalar = mixMembers<1>(lightParamData, &LightTimedData::FogZScalar, blendTimeCoeff); -// fogResult.LegacyFogScalar = mixMembers<1>(lightParamData, &LightTimedData::LegacyFogScalar, blendTimeCoeff); - fogResult.MainFogStartDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogStartDist, blendTimeCoeff); - fogResult.MainFogEndDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogEndDist, blendTimeCoeff); -// fogResult.FogBlendAlpha = mixMembers<1>(lightParamData, &LightTimedData::FogBlendAlpha, blendTimeCoeff); - fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); - fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); - - } -} void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, const mathfu::vec4 &cameraPos, const HMapRenderPlan &mapRenderPlan, @@ -1878,45 +1395,3 @@ std::shared_ptr Map::getWmoObject(int fileDataId, SMMapObjDefObj1 &ma animTime_t Map::getCurrentSceneTime() { return m_currentTime; } - -void Map::loadZoneLights() { - if (m_api->databaseHandler != nullptr) { - std::vector zoneLights; - m_api->databaseHandler->getZoneLightsForMap(m_mapId, zoneLights); - - for (const auto &zoneLight : zoneLights) { - mapInnerZoneLightRecord innerZoneLightRecord; - innerZoneLightRecord.ID = zoneLight.ID; - innerZoneLightRecord.name = zoneLight.name; - innerZoneLightRecord.LightID = zoneLight.LightID; -// innerZoneLightRecord.Zmin = zoneLight.Zmin; -// innerZoneLightRecord.Zmax = zoneLight.Zmax; - - float minX = 9999; float maxX = -9999; - float minY = 9999; float maxY = -9999; - - auto &points = innerZoneLightRecord.points; - for (auto &zonePoint : zoneLight.points) { - minX = std::min(zonePoint.x, minX); minY = std::min(zonePoint.y, minY); - maxX = std::max(zonePoint.x, maxX); maxY = std::max(zonePoint.y, maxY); - - points.push_back(mathfu::vec2(zonePoint.x, zonePoint.y)); - } - - innerZoneLightRecord.aabb = CAaBox( - C3Vector(mathfu::vec3(minX, minY, zoneLight.Zmin)), - C3Vector(mathfu::vec3(maxX, maxY, zoneLight.Zmax)) - ); - - auto &lines = innerZoneLightRecord.lines; - for (int i = 0; i < (points.size() - 1); i++) { - lines.push_back(points[i + 1] - points[i]); - } - lines.push_back( points[0] - points[points.size() - 1]); - - m_zoneLights.push_back(innerZoneLightRecord); - } - - } -} - diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 89137eb8a..183e02141 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -20,6 +20,7 @@ #include "../../../renderer/mapScene/MapScenePlan.h" #include "../../../renderer/mapScene/MapSceneParams.h" #include "../wdt/wdtLightsObject.h" +#include "dayNightDataHolder/DayNightLightHolder.h" enum class SceneMode { smMap, @@ -55,6 +56,7 @@ class Map : public IScene, public IMapApi { std::shared_ptr wmoMap = nullptr; bool useWeightedBlend = false; + bool has0x200000Flag = false; std::vector> m_exteriorSkyBoxes; @@ -115,16 +117,7 @@ class Map : public IScene, public IMapApi { virtual void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord); - struct mapInnerZoneLightRecord { - int ID; - std::string name; - int LightID; - CAaBox aabb; - std::vector points; - std::vector lines; - }; - std::vector m_zoneLights; - void loadZoneLights(); + DayNightLightHolder dayNightLightHolder; FreeStrategy adtFreeLambda; FreeStrategy zeroStateLambda; @@ -132,12 +125,12 @@ class Map : public IScene, public IMapApi { HADTRenderConfigDataHolder m_adtConfigHolder = nullptr; protected: - explicit Map() { + explicit Map() : dayNightLightHolder(nullptr, -1) { } public: explicit Map(HApiContainer api, int mapId, const std::string &mapName); - explicit Map(HApiContainer api, int mapId, int wdtFileDataId) { + explicit Map(HApiContainer api, int mapId, int wdtFileDataId) : dayNightLightHolder(api, mapId) { initMapTiles(); m_mapId = mapId; m_api = api; mapName = ""; @@ -146,15 +139,16 @@ class Map : public IScene, public IMapApi { MapRecord mapRecord; api->databaseHandler->getMapById(mapId, mapRecord); useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + has0x200000Flag = (mapRecord.flags0 & 0x200000) > 0; createAdtFreeLamdas(); m_wdtfile = api->cacheStorage->getWdtFileCache()->getFileId(wdtFileDataId); - loadZoneLights(); + dayNightLightHolder.loadZoneLights(); }; - explicit Map(HApiContainer api, std::string adtFileName, int i, int j, std::string mapName) { + explicit Map(HApiContainer api, std::string adtFileName, int i, int j, std::string mapName) : dayNightLightHolder(api, 0) { initMapTiles(); m_mapId = 0; m_api = api; this->mapName = mapName; @@ -205,14 +199,6 @@ class Map : public IScene, public IMapApi { // HDrawStage doGaussBlur(const HDrawStage &parentDrawStage, std::vector &uniformBufferChunks) const; - - void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, - SkyColors &skyColors, - ExteriorColors &exteriorColors, - FogResult &fogResult, - LiquidColors &liquidColors, - StateForConditions *stateForConditions) override; - void createAdtFreeLamdas(); }; typedef std::shared_ptr HMapScene; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index da266895c..a24ae3bde 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -176,10 +176,10 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrviewUp.xyz(), sceneTime); - blockPSVS.closeOceanColor = fdd->closeOceanColor; - blockPSVS.farOceanColor = fdd->farOceanColor; - blockPSVS.closeRiverColor = fdd->closeRiverColor; - blockPSVS.farRiverColor = fdd->farRiverColor; + blockPSVS.closeOceanColor = fdd->liquidColors.closeOceanColor_shallowAlpha; + blockPSVS.farOceanColor = fdd->liquidColors.farOceanColor_deepAlpha; + blockPSVS.closeRiverColor = fdd->liquidColors.closeRiverColor_shallowAlpha; + blockPSVS.farRiverColor = fdd->liquidColors.farRiverColor_deepAlpha; blockPSVS.extLight.uExteriorAmbientColor = fdd->colors.exteriorAmbientColor; blockPSVS.extLight.uExteriorHorizontAmbientColor = fdd->colors.exteriorHorizontAmbientColor; From 5686fb8051e794dccbf3811f92ffb67015f701fe Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 6 Jul 2024 00:39:35 +0300 Subject: [PATCH 208/212] data correction logic --- .../DayNightLightHolder.cpp | 122 ++++++++++++++++-- .../dayNightDataHolder/DayNightLightHolder.h | 14 ++ .../src/engine/objects/scenes/map.cpp | 11 -- .../renderer/mapScene/FrameDependentData.h | 6 + 4 files changed, 129 insertions(+), 24 deletions(-) diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp index f4a0f56fb..86baf17dd 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -6,8 +6,14 @@ #include "../../../../include/database/dbStructs.h" #include "../../../algorithms/mathHelper.h" + DayNightLightHolder::DayNightLightHolder(const HApiContainer &api, int mapId) : m_api(api), m_mapId(mapId) { + MapRecord mapRecord; + api->databaseHandler->getMapById(mapId, mapRecord); + m_useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + m_mapHasFlag_0x200000 = (mapRecord.flags0 & 0x200000) > 0; + m_mapHasFlag_0x10000 = (mapRecord.flags0 & 0x10000) > 0; } void DayNightLightHolder::loadZoneLights() { @@ -55,7 +61,7 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend StateForConditions &stateForConditions, const AreaRecord &areaRecord) { - ZoneScoped ; + ZoneScoped ; Config* config = this->m_api->getConfig(); @@ -342,6 +348,16 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend } +static inline mathfu::vec4 mix(const mathfu::vec4 &a, const mathfu::vec4 &b, float alpha) { + return (b - a) * alpha + a; +} +static inline mathfu::vec3 mix(const mathfu::vec3 &a, const mathfu::vec3 &b, float alpha) { + return (b - a) * alpha + a; +} +static inline float mix(const float &a, const float &b, float alpha) { + return (b - a) * alpha + a; +} + template inline float getFloatFromInt(int value) { if constexpr (T == 0) { @@ -405,24 +421,20 @@ bool vec3EqZero(const mathfu::vec3 &a) { } float maxFarClip(float farClip) { - return std::max(std::min(farClip, 50000.0), 1000.0); } -float getClampedFarClip(float farClip) { +float DayNightLightHolder::getClampedFarClip(float farClip) { int someflag = 0; float multiplier = 1.0f; - if ((map_has0x10000Flag) != 0 && farClip >= 4400.0f) + if ((m_mapHasFlag_0x10000) != 0 && farClip >= 4400.0f) farClip = 4400.0; - farClip = farClip * multiplier; - - return maxFarClip( - ); + return maxFarClip(fmaxf(fmaxf(fmaxf(m_minFogDist1, farClip), m_minFogDist3), m_minFogDist2)); } -void fixLightTimedData(LightTimedData &data, float farClip) { +void DayNightLightHolder::fixLightTimedData(LightTimedData &data, float farClip, float &fogScalarOverride) { if (data.EndFogColor == 0) { data.EndFogColor = data.SkyFogColor; } @@ -446,6 +458,25 @@ void fixLightTimedData(LightTimedData &data, float farClip) { if (data.EndFogColorDistance <= 0.0f) data.EndFogColorDistance = getClampedFarClip(farClip); + + if (data.FogHeight > 10000.0) + data.FogHeight = 0.0; + + if (data.FogDensity <= 0.0f) { + float farPlaneClamped = std::min(farClip, 700.0f) - 200.0f; + + float difference = data.FogEnd - (float)(data.FogEnd * data.FogScaler); + if (difference > farPlaneClamped || difference <= 0.0f) { + data.FogDensity = 1.5f; + } else { + data.FogDensity = ((1.0f - (difference / farPlaneClamped)) * 5.5f) + 1.5f; + } + } else { + fogScalarOverride = std::min(fogScalarOverride, -0.2f); + } + + if ( data.FogHeightScaler == 0.0f ) + data.FogHeightDensity = data.FogDensity; } void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, @@ -530,9 +561,11 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const auto &dataA = lightParamData.lightTimedData[0]; auto &dataB = lightParamData.lightTimedData[1]; + //Blend two times using certain rules - fixLightTimedData(dataA, config->farPlane); - fixLightTimedData(dataB, config->farPlane); + float fogScalarOverride = 0.0f; + fixLightTimedData(dataA, config->farPlane, fogScalarOverride); + fixLightTimedData(dataB, config->farPlane, fogScalarOverride); //Ambient lights exteriorColors.exteriorAmbientColor = mixMembers<4>(lightParamData, &LightTimedData::ambientLight, blendTimeCoeff); @@ -572,7 +605,26 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.FogHeight = mixMembers<1>(lightParamData, &LightTimedData::FogHeight, blendTimeCoeff); fogResult.FogHeightScaler = mixMembers<1>(lightParamData, &LightTimedData::FogHeightScaler, blendTimeCoeff); fogResult.FogHeightDensity = mixMembers<1>(lightParamData, &LightTimedData::FogHeightDensity, blendTimeCoeff); - fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff); + //Custom blend for Sun + if ( lightParamData.lightTimedData[1].SunFogAngle >= 1.0 && + lightParamData.lightTimedData[0].SunFogAngle >= 1.0) + { + fogResult.SunAngleBlend = 0.0; + fogResult.SunFogStrength = 0.0; + fogResult.SunAngleBlend = 1.0; + } else if ( lightParamData.lightTimedData[1].SunFogAngle >= 1.0 || lightParamData.lightTimedData[0].SunFogAngle < 1.0) { + if ( lightParamData.lightTimedData[1].SunFogAngle < 1.0 ) + { + fogResult.SunAngleBlend = 1.0; + fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff);; + } + else + { + fogResult.SunFogStrength = lightParamData.lightTimedData[0].SunFogStrength; + fogResult.SunFogAngle = lightParamData.lightTimedData[0].SunFogAngle; + fogResult.SunAngleBlend = 1.0f - blendTimeCoeff; + } + } if (false) {//fdd->overrideValuesWithFinalFog) { fogResult.FogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); @@ -597,5 +649,49 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); + if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ + //TODO: + } + + if ( + (fogResult.MainFogCoefficients.LengthSquared()) > 0.00000011920929f || + (fogResult.HeightDensityFogCoefficients.LengthSquared()) > 0.00000011920929f + ) { + fogResult.LegacyFogScalar = 0.0f; + } else { + fogResult.LegacyFogScalar = 1.0f; + } + + fogResult.FogDensity = fmaxf(fogResult.FogDensity, 0.89999998f); + if ( m_useWeightedBlend ) + { + fogResult.FogDensity = 1.0; + } + else if ( fogScalarOverride > fogResult.FogScaler ) + { + fogResult.FogScaler = fogScalarOverride; + } + } +} + +void DayNightLightHolder::createMinFogDistances() { + m_minFogDist1 = maxFarClip(0.0f); + m_minFogDist2 = maxFarClip(0.0f); + + switch ( m_mapId ) + { + case 1492: + m_minFogDist1 = maxFarClip(7000.0); + break; + case 1718: + m_minFogDist1 = maxFarClip(7000.0); + break; + case 571: + m_minFogDist1 = maxFarClip(30000.0); + break; } -} \ No newline at end of file + + if (m_mapHasFlag_0x200000) { + m_minFogDist2 = maxFarClip(30000.0f); + } +} diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h index e4e4372d9..25d8e5150 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h @@ -9,6 +9,7 @@ #include #include "../../../persistance/header/commonFileStructs.h" #include "../../../ApiContainer.h" +#include "../../../../renderer/mapScene/MapScenePlan.h" class DayNightLightHolder { public: @@ -38,6 +39,19 @@ class DayNightLightHolder { FogResult &fogResult, LiquidColors &liquidColors, StateForConditions *stateForConditions); + +private: + bool m_useWeightedBlend = false; + bool m_mapHasFlag_0x200000 = false; + bool m_mapHasFlag_0x10000 = false; + + float m_minFogDist1 = 0.0; + float m_minFogDist2 = 0.0; + float m_minFogDist3 = 0.0; + + void fixLightTimedData(LightTimedData &data, float farClip, float &fogScalarOverride); + float getClampedFarClip(float farClip); + void createMinFogDistances(); }; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 4085faff2..49eb0471b 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -573,17 +573,6 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams // } } -static inline mathfu::vec4 mix(const mathfu::vec4 &a, const mathfu::vec4 &b, float alpha) { - return (b - a) * alpha + a; -} -static inline mathfu::vec3 mix(const mathfu::vec3 &a, const mathfu::vec3 &b, float alpha) { - return (b - a) * alpha + a; -} -static inline float mix(const float &a, const float &b, float alpha) { - return (b - a) * alpha + a; -} - - void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) { diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 2d79f8179..7dadc71e8 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -35,6 +35,12 @@ struct FogResult { float FogBlendAlpha = 0.00001; mathfu::vec3 HeightEndFogColor = mathfu::vec3(0, 0, 0); float FogStartOffset = 0.00001; + + float SunAngleBlend = 1.0f; + + inline void addMix(FogResult &b, float blendAlpha) { + + } }; struct SkyColors { From 5b843e479f07683db54c42f7a546620292f3b1b3 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 6 Jul 2024 01:27:49 +0300 Subject: [PATCH 209/212] More correction logic --- .../DayNightLightHolder.cpp | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp index 86baf17dd..8b7c89f7c 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -459,8 +459,8 @@ void DayNightLightHolder::fixLightTimedData(LightTimedData &data, float farClip, if (data.EndFogColorDistance <= 0.0f) data.EndFogColorDistance = getClampedFarClip(farClip); - if (data.FogHeight > 10000.0) - data.FogHeight = 0.0; + if (data.FogHeight > 10000.0f) + data.FogHeight = 0.0f; if (data.FogDensity <= 0.0f) { float farPlaneClamped = std::min(farClip, 700.0f) - 200.0f; @@ -606,23 +606,29 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.FogHeightScaler = mixMembers<1>(lightParamData, &LightTimedData::FogHeightScaler, blendTimeCoeff); fogResult.FogHeightDensity = mixMembers<1>(lightParamData, &LightTimedData::FogHeightDensity, blendTimeCoeff); //Custom blend for Sun - if ( lightParamData.lightTimedData[1].SunFogAngle >= 1.0 && - lightParamData.lightTimedData[0].SunFogAngle >= 1.0) { - fogResult.SunAngleBlend = 0.0; - fogResult.SunFogStrength = 0.0; - fogResult.SunAngleBlend = 1.0; - } else if ( lightParamData.lightTimedData[1].SunFogAngle >= 1.0 || lightParamData.lightTimedData[0].SunFogAngle < 1.0) { - if ( lightParamData.lightTimedData[1].SunFogAngle < 1.0 ) - { - fogResult.SunAngleBlend = 1.0; - fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff);; - } - else - { - fogResult.SunFogStrength = lightParamData.lightTimedData[0].SunFogStrength; - fogResult.SunFogAngle = lightParamData.lightTimedData[0].SunFogAngle; - fogResult.SunAngleBlend = 1.0f - blendTimeCoeff; + float SunFogAngle1 = lightParamData.lightTimedData[0].SunFogAngle; + float SunFogAngle2 = lightParamData.lightTimedData[1].SunFogAngle; + if (SunFogAngle1 >= 1.0f) { + if (SunFogAngle2 >= 1.0f) { + fogResult.SunAngleBlend = 0.0f; + fogResult.SunFogStrength = 0.0f; + fogResult.SunAngleBlend = 1.0f; + } else if (SunFogAngle2 < 1.0f) { + fogResult.SunAngleBlend = blendTimeCoeff; + fogResult.SunFogAngle = SunFogAngle2; + fogResult.SunFogStrength = lightParamData.lightTimedData[1].SunFogStrength; + } + } else if (SunFogAngle1 < 1.0f) { + if (SunFogAngle2 < 1.0f) { + fogResult.SunAngleBlend = 1.0f; + fogResult.SunFogAngle = mixMembers<1>(lightParamData, &LightTimedData::SunFogAngle, blendTimeCoeff); + fogResult.SunFogStrength = mixMembers<1>(lightParamData, &LightTimedData::SunFogStrength, blendTimeCoeff); + } else if (SunFogAngle2 >= 1.0f) { + fogResult.SunFogStrength = lightParamData.lightTimedData[0].SunFogStrength; + fogResult.SunFogAngle = SunFogAngle1; + fogResult.SunAngleBlend = 1.0f - blendTimeCoeff; + } } } @@ -635,17 +641,14 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.EndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); fogResult.EndFogColorDistance = mixMembers<1>(lightParamData, &LightTimedData::EndFogColorDistance, blendTimeCoeff); fogResult.SunFogColor = mixMembers<3>(lightParamData, &LightTimedData::SunFogColor, blendTimeCoeff); - fogResult.SunFogStrength = mixMembers<1>(lightParamData, &LightTimedData::SunFogStrength, blendTimeCoeff); fogResult.FogHeightColor = mixMembers<3>(lightParamData, &LightTimedData::FogHeightColor, blendTimeCoeff); fogResult.FogHeightCoefficients = mixMembers<4>(lightParamData, &LightTimedData::FogHeightCoefficients, blendTimeCoeff); fogResult.MainFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); fogResult.HeightDensityFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); fogResult.FogZScalar = mixMembers<1>(lightParamData, &LightTimedData::FogZScalar, blendTimeCoeff); -// fogResult.LegacyFogScalar = mixMembers<1>(lightParamData, &LightTimedData::LegacyFogScalar, blendTimeCoeff); fogResult.MainFogStartDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogStartDist, blendTimeCoeff); fogResult.MainFogEndDist = mixMembers<1>(lightParamData, &LightTimedData::MainFogEndDist, blendTimeCoeff); -// fogResult.FogBlendAlpha = mixMembers<1>(lightParamData, &LightTimedData::FogBlendAlpha, blendTimeCoeff); fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); @@ -665,7 +668,7 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.FogDensity = fmaxf(fogResult.FogDensity, 0.89999998f); if ( m_useWeightedBlend ) { - fogResult.FogDensity = 1.0; + fogResult.FogDensity = 1.0f; } else if ( fogScalarOverride > fogResult.FogScaler ) { From 85b62d6f03639ac8dd28f8b121f3bafa9a4c86c8 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 6 Jul 2024 04:25:11 +0300 Subject: [PATCH 210/212] fix --- src/database/CSqliteDB.cpp | 12 +++++--- .../DayNightLightHolder.cpp | 29 ++++++++++--------- .../dayNightDataHolder/DayNightLightHolder.h | 1 + wowViewerLib/src/include/database/dbStructs.h | 2 ++ .../renderer/mapScene/MapSceneRenderer.cpp | 2 +- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index d0b1a13d1..b18091aca 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -42,16 +42,16 @@ SQLite::Column CSqliteDB::StatementFieldHolder::getField(const HashedString fiel const std::string getMapListSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.WdtFileDataID > 0"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0, m.Flags_1, m.Flags_2 from Map m where m.WdtFileDataID > 0"; const std::string getMapListSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0, m.Flags_1, m.Flags_2 from Map m"; const std::string getMapByIDSQL = - "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.ID = ?"; + "select m.ID, m.Directory, m.MapName_lang, m.WdtFileDataID, m.MapType, m.TimeOfDayOverride, m.Flags_0, m.Flags_1, m.Flags_2 from Map m where m.ID = ?"; const std::string getMapByIDSQL_classic = - "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0 from Map m where m.ID = ?"; + "select m.ID, m.Directory, m.MapName_lang, m.MapType, m.TimeOfDayOverride, m.Flags_0, m.Flags_1, m.Flags_2 from Map m where m.ID = ?"; const std::string getWmoAreaAreaNameSQL = R"===( select wat.AreaName_lang as wmoAreaName, at.AreaName_lang as areaName, at.ID as ID, at.ParentAreaID as ParentAreaID, at.Ambient_multiplier as Ambient_multiplier from WMOAreaTable wat @@ -182,6 +182,8 @@ void CSqliteDB::getMapArray(std::vector &mapRecords) { mapRecord.MapType = getMapList.getField("MapType").getInt(); mapRecord.overrideTime = getMapList.getField("TimeOfDayOverride").getInt(); mapRecord.flags0 = getMapList.getField("Flags_0").getInt(); + mapRecord.flags1 = getMapList.getField("Flags_1").getInt(); + mapRecord.flags2 = getMapList.getField("Flags_2").getInt(); } } @@ -205,6 +207,8 @@ bool CSqliteDB::getMapById(int mapId, MapRecord &mapRecord) { mapRecord.MapType = getMapByIdStatement.getField("MapType").getInt(); mapRecord.overrideTime = getMapByIdStatement.getField("TimeOfDayOverride").getInt(); mapRecord.flags0 = getMapByIdStatement.getField("Flags_0").getInt(); + mapRecord.flags1 = getMapByIdStatement.getField("Flags_1").getInt(); + mapRecord.flags2 = getMapByIdStatement.getField("Flags_2").getInt(); return true; } diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp index 8b7c89f7c..672bd3214 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -11,6 +11,7 @@ DayNightLightHolder::DayNightLightHolder(const HApiContainer &api, int mapId) : MapRecord mapRecord; api->databaseHandler->getMapById(mapId, mapRecord); + m_mapFlag2_0x2 = (mapRecord.flags2 & 0x2) > 0; m_useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; m_mapHasFlag_0x200000 = (mapRecord.flags0 & 0x200000) > 0; m_mapHasFlag_0x10000 = (mapRecord.flags0 & 0x10000) > 0; @@ -56,6 +57,19 @@ void DayNightLightHolder::loadZoneLights() { } } + +static inline mathfu::vec4 mix(const mathfu::vec4 &a, const mathfu::vec4 &b, float alpha) { + return (b - a) * alpha + a; +} +static inline mathfu::vec3 mix(const mathfu::vec3 &a, const mathfu::vec3 &b, float alpha) { + return (b - a) * alpha + a; +} +static inline float mix(const float &a, const float &b, float alpha) { + return (b - a) * alpha + a; +} + + + void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, @@ -347,17 +361,6 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend } } - -static inline mathfu::vec4 mix(const mathfu::vec4 &a, const mathfu::vec4 &b, float alpha) { - return (b - a) * alpha + a; -} -static inline mathfu::vec3 mix(const mathfu::vec3 &a, const mathfu::vec3 &b, float alpha) { - return (b - a) * alpha + a; -} -static inline float mix(const float &a, const float &b, float alpha) { - return (b - a) * alpha + a; -} - template inline float getFloatFromInt(int value) { if constexpr (T == 0) { @@ -653,7 +656,7 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ - //TODO: + fogResult.FogHeightCoefficients = mathfu::vec4(0,0,1,0); } if ( @@ -666,7 +669,7 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const } fogResult.FogDensity = fmaxf(fogResult.FogDensity, 0.89999998f); - if ( m_useWeightedBlend ) + if ( m_mapFlag2_0x2 ) { fogResult.FogDensity = 1.0f; } diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h index 25d8e5150..771d5375f 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h @@ -41,6 +41,7 @@ class DayNightLightHolder { StateForConditions *stateForConditions); private: + bool m_mapFlag2_0x2 = false; bool m_useWeightedBlend = false; bool m_mapHasFlag_0x200000 = false; bool m_mapHasFlag_0x10000 = false; diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index af023ac75..2e2d9dfc3 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -17,6 +17,8 @@ struct MapRecord { int MapType; int overrideTime; uint32_t flags0; + uint32_t flags1; + uint32_t flags2; }; struct LightResult { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index a24ae3bde..c9e0d4f87 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -242,7 +242,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorDirectColorDir, //TODO: for fog this is calculated from SUN position From 0c134ec3697b16bbf751b141bdb2b47c997e3129 Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Sat, 6 Jul 2024 21:51:37 +0300 Subject: [PATCH 211/212] FOG! --- src/database/CSqliteDB.cpp | 13 +- .../DayNightLightHolder.cpp | 245 ++++++++---------- .../src/engine/objects/scenes/m2Scene.cpp | 2 +- .../src/engine/objects/scenes/map.cpp | 6 +- wowViewerLib/src/engine/objects/scenes/map.h | 11 +- .../renderer/mapScene/FrameDependentData.h | 4 - .../renderer/mapScene/MapSceneRenderer.cpp | 8 +- 7 files changed, 128 insertions(+), 161 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index b18091aca..a23d2e55e 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -429,6 +429,7 @@ void CSqliteDB::getTimedLightParamData(int lightParamId, int time, LightParamDat bool hasHeightDensityFogCoeff = getLightData.getFieldIndex("HeightDensityFogCoeff_0") >= 0; int timeIndex = 0; + std::array slotWritten = {false, false}; while (getLightData.execute()) { int thisTime = getLightData.getField("Time").getInt(); if (thisTime > time) { @@ -438,7 +439,7 @@ void CSqliteDB::getTimedLightParamData(int lightParamId, int time, LightParamDat if (timeIndex > 1) return; - auto currLdRes = lightParamData.lightTimedData[timeIndex]; + auto &currLdRes = lightParamData.lightTimedData[timeIndex]; currLdRes.time = thisTime; currLdRes.ambientLight = getLightData.getField("AmbientColor"); @@ -488,12 +489,14 @@ void CSqliteDB::getTimedLightParamData(int lightParamId, int time, LightParamDat currLdRes.HeightDensityFogCoeff[1] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_1").getDouble() : 0.0f; currLdRes.HeightDensityFogCoeff[2] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_2").getDouble() : 0.0f; currLdRes.HeightDensityFogCoeff[3] = hasHeightDensityFogCoeff ? getLightData.getField("HeightDensityFogCoeff_3").getDouble() : 0.0f; - } - if (timeIndex == 0) { - //Found only one result. Let's copy it to the second slot - lightParamData.lightTimedData[1] = lightParamData.lightTimedData[0]; + slotWritten[timeIndex] = true; } + + //Found only one result. Let's copy it to the second slot + if (slotWritten[0] && !slotWritten[1]) lightParamData.lightTimedData[1] = lightParamData.lightTimedData[0]; + if (slotWritten[1] && !slotWritten[0]) lightParamData.lightTimedData[0] = lightParamData.lightTimedData[1]; + } diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp index 672bd3214..8794b2ee8 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -10,15 +10,17 @@ DayNightLightHolder::DayNightLightHolder(const HApiContainer &api, int mapId) : m_api(api), m_mapId(mapId) { MapRecord mapRecord; - api->databaseHandler->getMapById(mapId, mapRecord); - m_mapFlag2_0x2 = (mapRecord.flags2 & 0x2) > 0; - m_useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; - m_mapHasFlag_0x200000 = (mapRecord.flags0 & 0x200000) > 0; - m_mapHasFlag_0x10000 = (mapRecord.flags0 & 0x10000) > 0; + if (m_api) { + api->databaseHandler->getMapById(mapId, mapRecord); + m_mapFlag2_0x2 = (mapRecord.flags2 & 0x2) > 0; + m_useWeightedBlend = (mapRecord.flags0 & 0x4) > 0; + m_mapHasFlag_0x200000 = (mapRecord.flags0 & 0x200000) > 0; + m_mapHasFlag_0x10000 = (mapRecord.flags0 & 0x10000) > 0; + } } void DayNightLightHolder::loadZoneLights() { - if (m_api->databaseHandler != nullptr) { + if (m_api && m_api->databaseHandler != nullptr) { std::vector zoneLights; m_api->databaseHandler->getZoneLightsForMap(m_mapId, zoneLights); @@ -68,6 +70,37 @@ static inline float mix(const float &a, const float &b, float alpha) { return (b - a) * alpha + a; } +template +void mixFogMember(FogResult& a, FogResult& b, T FogResult::*member, float blendTimeCoeff) { + a.*member = mix(a.*member, b.*member, blendTimeCoeff); +} + +void fogMixAndSet(FogResult& a, FogResult& b, float blendCoeff) { + mixFogMember(a, b, &FogResult::FogEnd , blendCoeff); + mixFogMember(a, b, &FogResult::FogScaler , blendCoeff); + mixFogMember(a, b, &FogResult::FogDensity , blendCoeff); + mixFogMember(a, b, &FogResult::FogHeight , blendCoeff); + mixFogMember(a, b, &FogResult::FogHeightScaler , blendCoeff); + mixFogMember(a, b, &FogResult::FogHeightDensity , blendCoeff); + mixFogMember(a, b, &FogResult::SunFogAngle , blendCoeff); + mixFogMember(a, b, &FogResult::FogColor , blendCoeff); + mixFogMember(a, b, &FogResult::EndFogColor , blendCoeff); + mixFogMember(a, b, &FogResult::EndFogColorDistance , blendCoeff); + mixFogMember(a, b, &FogResult::SunFogColor , blendCoeff); + mixFogMember(a, b, &FogResult::SunFogStrength , blendCoeff); + mixFogMember(a, b, &FogResult::FogHeightColor , blendCoeff); + mixFogMember(a, b, &FogResult::FogHeightCoefficients , blendCoeff); + mixFogMember(a, b, &FogResult::MainFogCoefficients , blendCoeff); + mixFogMember(a, b, &FogResult::HeightDensityFogCoefficients , blendCoeff); + mixFogMember(a, b, &FogResult::FogZScalar , blendCoeff); + mixFogMember(a, b, &FogResult::LegacyFogScalar , blendCoeff); + mixFogMember(a, b, &FogResult::MainFogStartDist , blendCoeff); + mixFogMember(a, b, &FogResult::MainFogEndDist , blendCoeff); + mixFogMember(a, b, &FogResult::FogBlendAlpha , blendCoeff); + mixFogMember(a, b, &FogResult::HeightEndFogColor , blendCoeff); + mixFogMember(a, b, &FogResult::FogStartOffset , blendCoeff); + mixFogMember(a, b, &FogResult::SunAngleBlend , blendCoeff); +} void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, @@ -76,6 +109,7 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend const AreaRecord &areaRecord) { ZoneScoped ; + if(!m_api) return; Config* config = this->m_api->getConfig(); @@ -90,15 +124,17 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend } } + FogResult exteriorFogResult; + std::vector lightResults; if ((m_api->databaseHandler != nullptr)) { //Check zoneLight SkyColors skyColors; ExteriorColors exteriorColors; - FogResult fogResult; + LiquidColors liquidColors; - getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, fogResult, liquidColors, &stateForConditions); + getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, exteriorFogResult, liquidColors, &stateForConditions); //TODO: restore skyboxes /* @@ -168,7 +204,7 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend if (config->glowSource == EParameterSource::eDatabase) { auto fdd = mapRenderPlan->frameDependentData; - fdd->currentGlow = currentGlow; + fdd->currentGlow = 1.0;//currentGlow; } else if (config->glowSource == EParameterSource::eConfig) { auto fdd = mapRenderPlan->frameDependentData; fdd->currentGlow = config->currentGlow; @@ -227,88 +263,51 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend float totalSummator = 0.0; //Apply fog from WMO - { - for (auto &wmoFog : wmoFogData) { - auto &lightResult = combinedResults.emplace_back(); - auto farPlaneClamped = std::min(config->farPlane, wmoFog.end); - - std::array colorConverted; - ImVectorToArrBGR(colorConverted, wmoFog.color); - - lightResult.FogEnd = farPlaneClamped; - lightResult.FogStart = farPlaneClamped * wmoFog.start_scalar; - lightResult.SkyFogColor = colorConverted; - lightResult.FogDensity = 1.0; - lightResult.FogHeightColor = colorConverted; - lightResult.EndFogColor = colorConverted; - lightResult.SunFogColor = colorConverted; - lightResult.HeightEndFogColor = colorConverted; - - if (farPlaneClamped < 30.f) { - lightResult.FogEnd = farPlaneClamped; - farPlaneClamped = 30.f; - } - - bool mapHasWeightedBlendFlag = false; - if (!mapHasWeightedBlendFlag) { - float difference = farPlaneClamped - lightResult.FogStart; - float farPlaneClamped2 = std::min(config->farPlane, 700.0f) - 200.0f; - if ((difference > farPlaneClamped2) || (farPlaneClamped2 <= 0.0f)) { - lightResult.FogDensity = 1.5; - } else { - lightResult.FogDensity = ((1.0 - (difference / farPlaneClamped2)) * 5.5) + 1.5; - } - lightResult.FogEnd = config->farPlane; - if (lightResult.FogStart < 0.0f) - lightResult.FogStart = 0.0; - } - - lightResult.FogHeightDensity = lightResult.FogDensity; - lightResult.FogStartOffset = 0; - lightResult.FogHeightScaler = 1.0; - lightResult.FogZScalar = 0; - lightResult.FogHeight = -10000.0; - lightResult.LegacyFogScalar = 1.0; - lightResult.EndFogColorDistance = 10000.0; - } - } - - //Apply fogs from lights - if (totalSummator < 1.0) { - if (config->globalFog == EParameterSource::eDatabase) { - - } else if (config->globalFog == EParameterSource::eConfig) { - LightResult globalFog; - globalFog.FogScaler = config->fogResult.FogScaler; - globalFog.FogEnd = config->fogResult.FogEnd; - globalFog.FogDensity = config->fogResult.FogDensity; - - globalFog.FogHeightScaler = config->fogResult.FogHeightScaler; - globalFog.FogHeightDensity = config->fogResult.FogHeightDensity; - globalFog.SunFogAngle = config->fogResult.SunFogAngle; - globalFog.EndFogColorDistance = config->fogResult.EndFogColorDistance; - globalFog.SunFogStrength = config->fogResult.SunFogStrength; - - globalFog.blendCoef = 1.0 - totalSummator; - globalFog.isDefault = true; - - globalFog.EndFogColor = {config->fogResult.EndFogColor.z, config->fogResult.EndFogColor.y, config->fogResult.EndFogColor.x}; - globalFog.SunFogColor = {config->fogResult.SunFogColor.z, config->fogResult.SunFogColor.y, config->fogResult.SunFogColor.x}; - globalFog.FogHeightColor = {config->fogResult.FogHeightColor.z, config->fogResult.FogHeightColor.y, config->fogResult.FogHeightColor.x}; - - combinedResults = {globalFog}; - } - } - std::sort(combinedResults.begin(), combinedResults.end(), [](const LightResult &a, const LightResult &b) -> bool { - return a.blendCoef > b.blendCoef; - }); - - //Rebalance blendCoefs - if (totalSummator < 1.0f && totalSummator > 0.0f) { - for (auto &_light : combinedResults) { - _light.blendCoef = _light.blendCoef / totalSummator; - } - } +// { +// for (auto &wmoFog : wmoFogData) { +// auto &lightResult = combinedResults.emplace_back(); +// auto farPlaneClamped = std::min(config->farPlane, wmoFog.end); +// +// std::array colorConverted; +// ImVectorToArrBGR(colorConverted, wmoFog.color); +// +// lightResult.FogEnd = farPlaneClamped; +// lightResult.FogStart = farPlaneClamped * wmoFog.start_scalar; +// lightResult.SkyFogColor = colorConverted; +// lightResult.FogDensity = 1.0; +// lightResult.FogHeightColor = colorConverted; +// lightResult.EndFogColor = colorConverted; +// lightResult.SunFogColor = colorConverted; +// lightResult.HeightEndFogColor = colorConverted; +// +// if (farPlaneClamped < 30.f) { +// lightResult.FogEnd = farPlaneClamped; +// farPlaneClamped = 30.f; +// } +// +// bool mapHasWeightedBlendFlag = false; +// if (!mapHasWeightedBlendFlag) { +// float difference = farPlaneClamped - lightResult.FogStart; +// float farPlaneClamped2 = std::min(config->farPlane, 700.0f) - 200.0f; +// if ((difference > farPlaneClamped2) || (farPlaneClamped2 <= 0.0f)) { +// lightResult.FogDensity = 1.5; +// } else { +// lightResult.FogDensity = ((1.0 - (difference / farPlaneClamped2)) * 5.5) + 1.5; +// } +// lightResult.FogEnd = config->farPlane; +// if (lightResult.FogStart < 0.0f) +// lightResult.FogStart = 0.0; +// } +// +// lightResult.FogHeightDensity = lightResult.FogDensity; +// lightResult.FogStartOffset = 0; +// lightResult.FogHeightScaler = 1.0; +// lightResult.FogZScalar = 0; +// lightResult.FogHeight = -10000.0; +// lightResult.LegacyFogScalar = 1.0; +// lightResult.EndFogColorDistance = 10000.0; +// } +// } //In case of no data -> disable the fog { @@ -316,47 +315,10 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend fdd->FogDataFound = !combinedResults.empty(); auto &fogResult = fdd->fogResults.emplace_back(); - for (auto &_light : lightResults) { - fogResult.FogEnd = mix(fogResult.FogEnd, _light.FogEnd, _light.blendCoef); - fogResult.FogScaler = mix(fogResult.FogScaler, _light.FogScaler, _light.blendCoef); - fogResult.FogDensity = mix(fogResult.FogDensity, _light.FogDensity, _light.blendCoef); - fogResult.FogHeight = mix(fogResult.FogHeight, _light.FogHeight, _light.blendCoef); - fogResult.FogHeightScaler = mix(fogResult.FogHeightScaler, _light.FogHeightScaler, _light.blendCoef); - fogResult.FogHeightDensity = mix(fogResult.FogHeightDensity, _light.FogHeightDensity, _light.blendCoef); - fogResult.SunFogAngle = mix(fogResult.SunFogAngle, _light.SunFogAngle, _light.blendCoef); - if (fdd->overrideValuesWithFinalFog) { - fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); - } else { - fogResult.FogColor = mix(fogResult.FogColor, mathfu::vec3(_light.SkyFogColor[2], _light.SkyFogColor[1], _light.SkyFogColor[0]), _light.blendCoef); - } - fogResult.EndFogColor = mix(fogResult.EndFogColor, mathfu::vec3(_light.EndFogColor[2], _light.EndFogColor[1], _light.EndFogColor[0]), _light.blendCoef); - fogResult.EndFogColorDistance = mix(fogResult.EndFogColorDistance, _light.EndFogColorDistance, _light.blendCoef); - fogResult.SunFogColor = mix(fogResult.SunFogColor, mathfu::vec3(_light.SunFogColor[2], _light.SunFogColor[1], _light.SunFogColor[0]), _light.blendCoef); - fogResult.SunFogStrength = mix(fogResult.SunFogStrength, _light.SunFogStrength, _light.blendCoef); - fogResult.FogHeightColor = mix(fogResult.FogHeightColor, mathfu::vec3(_light.FogHeightColor[2], _light.FogHeightColor[1], _light.FogHeightColor[0]), _light.blendCoef); - fogResult.FogHeightCoefficients = mix( - fogResult.FogHeightCoefficients, - mathfu::vec4(_light.FogHeightCoefficients[3], _light.FogHeightCoefficients[2], - _light.FogHeightCoefficients[1], _light.FogHeightCoefficients[0]), _light.blendCoef); - fogResult.MainFogCoefficients = mix( - fogResult.MainFogCoefficients, - mathfu::vec4(_light.MainFogCoefficients[3], _light.MainFogCoefficients[2], - _light.MainFogCoefficients[1], _light.MainFogCoefficients[0]), _light.blendCoef); - fogResult.HeightDensityFogCoefficients = mix( - fogResult.HeightDensityFogCoefficients, - mathfu::vec4(_light.HeightDensityFogCoefficients[3], - _light.HeightDensityFogCoefficients[2], - _light.HeightDensityFogCoefficients[1], - _light.HeightDensityFogCoefficients[0]), _light.blendCoef); - - fogResult.FogZScalar = mix(fogResult.FogZScalar, _light.FogZScalar, _light.blendCoef); - fogResult.LegacyFogScalar = mix(fogResult.LegacyFogScalar, _light.LegacyFogScalar, _light.blendCoef); - fogResult.MainFogStartDist = mix(fogResult.MainFogStartDist, _light.MainFogStartDist, _light.blendCoef); - fogResult.MainFogEndDist = mix(fogResult.MainFogEndDist, _light.MainFogEndDist, _light.blendCoef); - fogResult.FogBlendAlpha = mix(fogResult.FogBlendAlpha, _light.blendCoef, _light.blendCoef); - fogResult.HeightEndFogColor = mix(fogResult.HeightEndFogColor, mathfu::vec3(_light.HeightEndFogColor[2], _light.HeightEndFogColor[1], _light.HeightEndFogColor[0]), _light.blendCoef); - fogResult.FogStartOffset = mix(fogResult.FogStartOffset, _light.FogStartOffset, _light.blendCoef); - } + fogResult = exteriorFogResult; + + fdd->FogDataFound = true; + } } } @@ -372,6 +334,8 @@ inline float getFloatFromInt(int value) { if constexpr (T == 2) { return ((value >> 16) & 0xFF) / 255.0f; } + + return 0.0f; } inline mathfu::vec3 intToColor3(int a) { @@ -454,7 +418,7 @@ void DayNightLightHolder::fixLightTimedData(LightTimedData &data, float farClip, data.FogScaler = std::max(std::min(data.FogScaler, 1.0f), -1.0f); data.FogEnd = std::max(data.FogEnd, 10.0f); data.FogHeight = std::max(data.FogHeight, -10000.0f); - data.FogHeightScaler = std::max(std::min(data.FogScaler, 1.0f), -1.0f); + data.FogHeightScaler = std::max(std::min(data.FogHeightScaler, 1.0f), -1.0f); if (data.SunFogColor == 0) data.SunFogAngle = 1.0f; @@ -478,8 +442,8 @@ void DayNightLightHolder::fixLightTimedData(LightTimedData &data, float farClip, fogScalarOverride = std::min(fogScalarOverride, -0.2f); } - if ( data.FogHeightScaler == 0.0f ) - data.FogHeightDensity = data.FogDensity; +// if ( data.FogHeightScaler == 0.0f ) +// data.FogHeightDensity = data.FogDensity; } void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, @@ -488,7 +452,7 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const FogResult &fogResult, LiquidColors &liquidColors, StateForConditions *stateForConditions) { - if (m_api->databaseHandler == nullptr) + if (!m_api || !m_api->databaseHandler) return ; LightResult zoneLightResult; @@ -561,6 +525,8 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const if (m_api->databaseHandler->getLightParamData(selectedLightParam, config->currentTime, lightParamData)) { float blendTimeCoeff = (config->currentTime - lightParamData.lightTimedData[0].time) / (float)(lightParamData.lightTimedData[1].time - lightParamData.lightTimedData[0].time); + blendTimeCoeff = std::min(std::max(blendTimeCoeff, 0.0f), 1.0f); + auto &dataA = lightParamData.lightTimedData[0]; auto &dataB = lightParamData.lightTimedData[1]; @@ -644,6 +610,7 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.EndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogColor, blendTimeCoeff); fogResult.EndFogColorDistance = mixMembers<1>(lightParamData, &LightTimedData::EndFogColorDistance, blendTimeCoeff); fogResult.SunFogColor = mixMembers<3>(lightParamData, &LightTimedData::SunFogColor, blendTimeCoeff); +// fogResult.SunFogColor = mathfu::vec3(0,0,0); fogResult.FogHeightColor = mixMembers<3>(lightParamData, &LightTimedData::FogHeightColor, blendTimeCoeff); fogResult.FogHeightCoefficients = mixMembers<4>(lightParamData, &LightTimedData::FogHeightCoefficients, blendTimeCoeff); fogResult.MainFogCoefficients = mixMembers<4>(lightParamData, &LightTimedData::MainFogCoefficients, blendTimeCoeff); @@ -655,9 +622,9 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); - if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ - fogResult.FogHeightCoefficients = mathfu::vec4(0,0,1,0); - } +// if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ +// fogResult.FogHeightCoefficients = mathfu::vec4(0,0,1,0); +// } if ( (fogResult.MainFogCoefficients.LengthSquared()) > 0.00000011920929f || diff --git a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp index 9a2cdec8e..5e04485ee 100644 --- a/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp +++ b/wowViewerLib/src/engine/objects/scenes/m2Scene.cpp @@ -118,7 +118,7 @@ M2Scene::M2Scene(const HApiContainer &api, const std::string &m2Model) { api->getConfig()->globalFog = EParameterSource::eConfig; } -M2Scene::M2Scene(const HApiContainer &api, int fileDataId) { +M2Scene::M2Scene(const HApiContainer &api, int fileDataId) { m_api = api; m_sceneMode = SceneMode::smM2; m_suppressDrawingSky = true; diff --git a/wowViewerLib/src/engine/objects/scenes/map.cpp b/wowViewerLib/src/engine/objects/scenes/map.cpp index 49eb0471b..903637b46 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.cpp +++ b/wowViewerLib/src/engine/objects/scenes/map.cpp @@ -272,7 +272,7 @@ HGVertexBufferBindings createSkyBindings(const HMapSceneBufferCreate &sceneRende return skyBindings; } -Map::Map(HApiContainer api, int mapId, const std::string &mapName) : dayNightLightHolder(api, mapId) { +Map::Map(HApiContainer api, int mapId, const std::string &mapName) : m_dayNightLightHolder(api, mapId) { initMapTiles(); m_mapId = mapId; m_api = api; this->mapName = mapName; @@ -295,7 +295,7 @@ Map::Map(HApiContainer api, int mapId, const std::string &mapName) : dayNightLig m_wdlObject = std::make_shared(api, wdlFileName); m_wdlObject->setMapApi(this); - dayNightLightHolder.loadZoneLights(); + m_dayNightLightHolder.loadZoneLights(); m_sceneWideBlockVSPSChunk = nullptr; } @@ -576,7 +576,7 @@ void Map::makeFramePlan(const FrameInputParams &frameInputParams void Map::updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord) { - dayNightLightHolder.updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); + m_dayNightLightHolder.updateLightAndSkyboxData(mapRenderPlan, frustumData, stateForConditions, areaRecord); } void Map::getPotentialEntities(const MathHelper::FrustumCullingData &frustumData, diff --git a/wowViewerLib/src/engine/objects/scenes/map.h b/wowViewerLib/src/engine/objects/scenes/map.h index 183e02141..7817022e9 100644 --- a/wowViewerLib/src/engine/objects/scenes/map.h +++ b/wowViewerLib/src/engine/objects/scenes/map.h @@ -117,20 +117,19 @@ class Map : public IScene, public IMapApi { virtual void updateLightAndSkyboxData(const HMapRenderPlan &mapRenderPlan, MathHelper::FrustumCullingData &frustumData, StateForConditions &stateForConditions, const AreaRecord &areaRecord); - DayNightLightHolder dayNightLightHolder; - FreeStrategy adtFreeLambda; FreeStrategy zeroStateLambda; HADTRenderConfigDataHolder m_adtConfigHolder = nullptr; protected: - explicit Map() : dayNightLightHolder(nullptr, -1) { + explicit Map() : m_dayNightLightHolder(nullptr, -1) { } + DayNightLightHolder m_dayNightLightHolder; public: explicit Map(HApiContainer api, int mapId, const std::string &mapName); - explicit Map(HApiContainer api, int mapId, int wdtFileDataId) : dayNightLightHolder(api, mapId) { + explicit Map(HApiContainer api, int mapId, int wdtFileDataId) : m_dayNightLightHolder(api, mapId) { initMapTiles(); m_mapId = mapId; m_api = api; mapName = ""; @@ -145,10 +144,10 @@ class Map : public IScene, public IMapApi { m_wdtfile = api->cacheStorage->getWdtFileCache()->getFileId(wdtFileDataId); - dayNightLightHolder.loadZoneLights(); + m_dayNightLightHolder.loadZoneLights(); }; - explicit Map(HApiContainer api, std::string adtFileName, int i, int j, std::string mapName) : dayNightLightHolder(api, 0) { + explicit Map(HApiContainer api, std::string adtFileName, int i, int j, std::string mapName) : m_dayNightLightHolder(api, 0) { initMapTiles(); m_mapId = 0; m_api = api; this->mapName = mapName; diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 7dadc71e8..81c0af69e 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -37,10 +37,6 @@ struct FogResult { float FogStartOffset = 0.00001; float SunAngleBlend = 1.0f; - - inline void addMix(FogResult &b, float blendAlpha) { - - } }; struct SkyColors { diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index c9e0d4f87..0568ce3e8 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -153,6 +153,8 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrfogResults.empty()) fdd->fogResults.emplace_back(); + for (int i = 0; i < renderingMatricesAndSizes.size(); i++) { auto const &matAndSceneSize = renderingMatricesAndSizes[i]; auto const &renderingMatrices = matAndSceneSize.renderingMat; @@ -230,7 +232,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorDirectColorDir, //TODO: for fog this is calculated from SUN position @@ -257,7 +259,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptr= 0.0 ? fogResult.MainFogStartDist : 0.0f, fogResult.LegacyFogScalar, - fogResult.FogBlendAlpha + 1.0f//fogResult.FogBlendAlpha ); fogData.heightFogEndColor_fogStartOffset = mathfu::vec4( fogResult.HeightEndFogColor, From 3141d45516c2918732f6d39071b49eaa4fc70a3a Mon Sep 17 00:00:00 2001 From: Deamon87 Date: Wed, 10 Jul 2024 17:13:31 +0300 Subject: [PATCH 212/212] temp commit --- src/database/CSqliteDB.cpp | 8 +++ .../src/engine/algorithms/mathHelper.cpp | 68 +++++++++++-------- .../src/engine/algorithms/mathHelper.h | 1 + .../DayNightLightHolder.cpp | 40 +++++++++-- .../dayNightDataHolder/DayNightLightHolder.h | 1 + wowViewerLib/src/include/database/dbStructs.h | 3 + .../renderer/mapScene/FrameDependentData.h | 8 +++ .../renderer/mapScene/MapSceneRenderer.cpp | 6 +- 8 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/database/CSqliteDB.cpp b/src/database/CSqliteDB.cpp index a23d2e55e..b47eec076 100644 --- a/src/database/CSqliteDB.cpp +++ b/src/database/CSqliteDB.cpp @@ -386,6 +386,8 @@ bool CSqliteDB::getLightParamData(int lightParamId, int time, LightParamData &li getLightParamDataStatement.setInputs(lightParamId); + bool hasSecondOverrideSphere = getLightParamDataStatement.getFieldIndex("Field_11_0_0_54210_001_0"); + if (getLightParamDataStatement.execute()) { lightParamData.glow = getLightParamDataStatement.getField("Glow").getDouble(); lightParamData.lightSkyBoxId = getLightParamDataStatement.getField("LightSkyboxID").getInt(); @@ -394,6 +396,12 @@ bool CSqliteDB::getLightParamData(int lightParamId, int time, LightParamData &li lightParamData.oceanShallowAlpha = getLightParamDataStatement.getField("OceanShallowAlpha").getDouble(); lightParamData.oceanDeepAlpha = getLightParamDataStatement.getField("OceanDeepAlpha").getDouble(); lightParamData.lightParamFlags = getLightParamDataStatement.getField("Flags").getInt(); + + if (hasSecondOverrideSphere) { + lightParamData.celestialBodyOverride2[0] = getLightParamDataStatement.getField("Field_11_0_0_54210_001_0").getDouble(); + lightParamData.celestialBodyOverride2[1] = getLightParamDataStatement.getField("Field_11_0_0_54210_001_1").getDouble(); + lightParamData.celestialBodyOverride2[2] = getLightParamDataStatement.getField("Field_11_0_0_54210_001_2").getDouble(); + } } else { //Record not found return false; diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.cpp b/wowViewerLib/src/engine/algorithms/mathHelper.cpp index b962a1764..c684ae9dd 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.cpp +++ b/wowViewerLib/src/engine/algorithms/mathHelper.cpp @@ -806,9 +806,8 @@ float doSomeConvert(float a) { return res; } -mathfu::vec3 MathHelper::calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int time) { - // Phi Table - static constexpr std::array, 5> sunPhiTable = { +namespace SkyConstantsAndFunctions { + static constexpr std::array, 5> sunPhiTable = { { { 0.25f, 1.7453293f }, { 0.49652779f, 0.08726646f}, @@ -862,44 +861,55 @@ mathfu::vec3 MathHelper::calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int } }; + enum class SkyDataType : int { SK_SUN, SK_MOON, SK_DIR_LIGHT }; + template + mathfu::vec3 getVector(int time) { + float timeF = time / 2880.0f; - float phi = sunPhiTable[0][1]; - float theta = sunThetaTable[0][1]; - - //Find Index - float timeF = time / 2880.0f; + float phi = 0.0f; + float theta = 0.0f; + if constexpr (T == SkyDataType::SK_DIR_LIGHT) { + phi = InterpTable<4>(directionalLightPhiTable, timeF); + theta = InterpTable<4>(directionalLightThetaTable, timeF); + } + if constexpr (T == SkyDataType::SK_SUN) { + phi = InterpTable<5>(sunPhiTable, timeF); + theta = InterpTable<3>(sunThetaTable, timeF); + } + if constexpr (T == SkyDataType::SK_MOON) { + phi = InterpTable<5>(moonPhiTable, timeF); + theta = InterpTable<3>(moonThetaTable, timeF); + } - phi = InterpTable<4>(directionalLightPhiTable, timeF); - theta = InterpTable<4>(directionalLightThetaTable, timeF); + constexpr float INV_PI = 1.0f / M_PI; -// if ( timeF >= 0.22222222f && timeF <= 0.81944448f ) -// { -// phi = InterpTable<5>(sunPhiTable, timeF); -// theta = InterpTable<3>(sunThetaTable, timeF); -// } -// else -// { -// phi = InterpTable<5>(moonPhiTable, timeF); -// theta = InterpTable<3>(moonThetaTable, timeF); -// } - constexpr float INV_PI = 1.0f / M_PI; + float sinPhi = doSomeConvert(phi * INV_PI - 0.5f); + float cosPhi = doSomeConvert(phi * INV_PI); - float sinPhi = doSomeConvert(phi * INV_PI - 0.5f); - float cosPhi = doSomeConvert(phi * INV_PI); + float sinTheta = doSomeConvert(theta * INV_PI + -0.5f); + float cosTheta = doSomeConvert(theta * INV_PI); - float sinTheta = doSomeConvert(theta * INV_PI + -0.5f); - float cosTheta = doSomeConvert(theta * INV_PI); + mathfu::vec3 vec = mathfu::vec3(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi); + return vec; + } +} +mathfu::vec3 MathHelper::calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int time) { + using namespace SkyConstantsAndFunctions; - mathfu::vec4 sunDirWorld = mathfu::vec4(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi, 0); -// sunDirWorld = mathfu::vec4(sunDirWorld.x, sunDirWorld.x, sunDirWorld.x, 0); + mathfu::vec4 sunDirWorld = mathfu::vec4(getVector(time), 0.0f); sunDirWorld = mathfu::vec4(sunDirWorld.xyz().Normalized(), 0.0f); -// mathfu::vec4 sunDirWorld = mathfu::vec4(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi, 0); -// mathfu::vec4 sunDirWorld = mathfu::vec4(-0.30822, -0.30822, -0.89999998, 0); + return (lookAtMat.Inverse().Transpose() * sunDirWorld).xyz().Normalized(); } +mathfu::vec3 MathHelper::calcSunPlanetPos(const mathfu::mat4 &lookAtMat, int time) { + using namespace SkyConstantsAndFunctions; + + mathfu::vec4 sunPlanetPos = mathfu::vec4(getVector(time), 0.0f); + return sunPlanetPos.xyz(); +} mathfu::vec3 MathHelper::hsv2rgb(const MathHelper::hsv &in) { double hh, p, q, t, ff; diff --git a/wowViewerLib/src/engine/algorithms/mathHelper.h b/wowViewerLib/src/engine/algorithms/mathHelper.h index 82e7b6b5d..4246837d9 100644 --- a/wowViewerLib/src/engine/algorithms/mathHelper.h +++ b/wowViewerLib/src/engine/algorithms/mathHelper.h @@ -134,6 +134,7 @@ class MathHelper { static float distanceFromAABBToPoint2DSquared(const mathfu::vec2 aabb[2], mathfu::vec2 &p); static mathfu::vec3 calcExteriorColorDir(const mathfu::mat4 &lookAtMat, int time); + static mathfu::vec3 calcSunPlanetPos(const mathfu::mat4 &lookAtMat, int time); }; const float ROUNDING_ERROR_f32 = 0.001f; diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp index 8794b2ee8..37d823322 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.cpp @@ -126,6 +126,8 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend FogResult exteriorFogResult; + auto fdd = mapRenderPlan->frameDependentData; + std::vector lightResults; if ((m_api->databaseHandler != nullptr)) { //Check zoneLight @@ -133,8 +135,9 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend ExteriorColors exteriorColors; LiquidColors liquidColors; + SkyBodyData skyBodyData; - getLightResultsFromDB(frustumData.cameraPos, config, skyColors, exteriorColors, exteriorFogResult, liquidColors, &stateForConditions); + getLightResultsFromDB(frustumData.cameraPos, config, skyColors, skyBodyData, exteriorColors, exteriorFogResult, liquidColors, &stateForConditions); //TODO: restore skyboxes /* @@ -200,6 +203,22 @@ void DayNightLightHolder::updateLightAndSkyboxData(const HMapRenderPlan &mapRend } */ + { + mathfu::vec3 sunPlanetPosVec3 = MathHelper::calcSunPlanetPos( + mapRenderPlan->renderingMatrices->lookAtMat, + m_api->getConfig()->currentTime + ) + frustumData.cameraPos; + + if (skyBodyData.celestialBodyOverride2.LengthSquared() > 0.0f) { + sunPlanetPosVec3 = mathfu::vec3( + skyBodyData.celestialBodyOverride2[0], + skyBodyData.celestialBodyOverride2[1], + skyBodyData.celestialBodyOverride2[2]); + } + mathfu::vec4 sunPlanetPos = mathfu::vec4((sunPlanetPosVec3 - frustumData.cameraPos).Normalized(), 0.0f); + fdd->sunDirection = (frustumData.viewMat.Inverse().Transpose() * sunPlanetPos).xyz().Normalized(); + } + float ambientMult = areaRecord.ambientMultiplier * 2.0f + 1; if (config->glowSource == EParameterSource::eDatabase) { @@ -442,12 +461,13 @@ void DayNightLightHolder::fixLightTimedData(LightTimedData &data, float farClip, fogScalarOverride = std::min(fogScalarOverride, -0.2f); } -// if ( data.FogHeightScaler == 0.0f ) -// data.FogHeightDensity = data.FogDensity; + if ( data.FogHeightScaler == 0.0f ) + data.FogHeightDensity = data.FogDensity; } void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, SkyColors &skyColors, + SkyBodyData &skyBodyData, ExteriorColors &exteriorColors, FogResult &fogResult, LiquidColors &liquidColors, @@ -527,6 +547,11 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const float blendTimeCoeff = (config->currentTime - lightParamData.lightTimedData[0].time) / (float)(lightParamData.lightTimedData[1].time - lightParamData.lightTimedData[0].time); blendTimeCoeff = std::min(std::max(blendTimeCoeff, 0.0f), 1.0f); + skyBodyData.celestialBodyOverride2 = mathfu::vec3( + lightParamData.celestialBodyOverride2[0], + lightParamData.celestialBodyOverride2[1], + lightParamData.celestialBodyOverride2[2] + ); auto &dataA = lightParamData.lightTimedData[0]; auto &dataB = lightParamData.lightTimedData[1]; @@ -622,9 +647,9 @@ void DayNightLightHolder::getLightResultsFromDB(mathfu::vec3 &cameraVec3, const fogResult.HeightEndFogColor = mixMembers<3>(lightParamData, &LightTimedData::EndFogHeightColor, blendTimeCoeff); fogResult.FogStartOffset = mixMembers<1>(lightParamData, &LightTimedData::FogStartOffset, blendTimeCoeff); -// if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ -// fogResult.FogHeightCoefficients = mathfu::vec4(0,0,1,0); -// } + if (fogResult.FogHeightCoefficients.LengthSquared() <= 0.00000011920929f ){ + fogResult.FogHeightCoefficients = mathfu::vec4(0,0,1,0); + } if ( (fogResult.MainFogCoefficients.LengthSquared()) > 0.00000011920929f || @@ -653,6 +678,9 @@ void DayNightLightHolder::createMinFogDistances() { switch ( m_mapId ) { + case 2695: + m_minFogDist1 = maxFarClip(7000.0); + break; case 1492: m_minFogDist1 = maxFarClip(7000.0); break; diff --git a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h index 771d5375f..88359144d 100644 --- a/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h +++ b/wowViewerLib/src/engine/objects/scenes/dayNightDataHolder/DayNightLightHolder.h @@ -35,6 +35,7 @@ class DayNightLightHolder { void getLightResultsFromDB(mathfu::vec3 &cameraVec3, const Config *config, SkyColors &skyColors, + SkyBodyData &skyBodyData, ExteriorColors &exteriorColors, FogResult &fogResult, LiquidColors &liquidColors, diff --git a/wowViewerLib/src/include/database/dbStructs.h b/wowViewerLib/src/include/database/dbStructs.h index 2e2d9dfc3..0adddf8ad 100644 --- a/wowViewerLib/src/include/database/dbStructs.h +++ b/wowViewerLib/src/include/database/dbStructs.h @@ -84,6 +84,9 @@ struct LightParamData { float oceanDeepAlpha; int lightParamFlags = 0; + std::array celestialBodyOverride; + std::array celestialBodyOverride2; + std::string skyBoxName; int skyBoxFdid; int skyBoxFlags; diff --git a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h index 81c0af69e..d64e9d4d2 100644 --- a/wowViewerLib/src/renderer/mapScene/FrameDependentData.h +++ b/wowViewerLib/src/renderer/mapScene/FrameDependentData.h @@ -48,6 +48,11 @@ struct SkyColors { mathfu::vec4 SkyFogColor; }; +struct SkyBodyData { + mathfu::vec3 celestialBodyOverride; + mathfu::vec3 celestialBodyOverride2; +}; + struct LiquidColors { mathfu::vec4 closeRiverColor_shallowAlpha = mathfu::vec4(0,0,0,0); mathfu::vec4 farRiverColor_deepAlpha = mathfu::vec4(0,0,0,0); @@ -86,6 +91,9 @@ struct FrameDependantData { bool overrideValuesWithFinalFog = false; SkyColors skyColors; +//Planet data + mathfu::vec3 sunDirection; + //Fog params bool FogDataFound = false; diff --git a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp index 0568ce3e8..11e6ebc24 100644 --- a/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp +++ b/wowViewerLib/src/renderer/mapScene/MapSceneRenderer.cpp @@ -232,7 +232,7 @@ void MapSceneRenderer::updateSceneWideChunk(const std::shared_ptrexteriorDirectColorDir, //TODO: for fog this is calculated from SUN position + fdd->sunDirection, fogResult.FogZScalar ); fogData.heightFogCoeff = fogResult.FogHeightCoefficients;